From e81881ad78fc44a67eac8931bf96d8e6a2783382 Mon Sep 17 00:00:00 2001 From: "JSD\\13999" <1399945104@qq.com> Date: Tue, 26 May 2026 16:46:26 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCatanBuilding=E5=A4=87?= =?UTF-8?q?=E4=BB=BD=E5=B7=A5=E7=A8=8B=E6=89=93=E5=BC=80=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../ABPackage/pkgDownloads/HexBuilding.meta | 8 + Assets/ABPackage/pkgFirstPackage/Fonts.meta | 8 + .../art/terrainbuilding/test01.meta | 8 + Assets/CoreLib.meta | 8 + Assets/CoreLib/DebugLib.meta | 8 + Assets/CoreLib/DebugLib/asap.core.dll | Bin 0 -> 117760 bytes Assets/CoreLib/DebugLib/asap.core.dll.meta | 77 + Assets/CoreLib/Plugins.meta | 8 + Assets/CoreLib/Plugins/LitJSON.dll | Bin 0 -> 52224 bytes Assets/CoreLib/Plugins/LitJSON.dll.meta | 33 + Assets/CoreLib/ReleaseLib.meta | 8 + Assets/CoreLib/ReleaseLib/asap.core.dll | Bin 0 -> 104960 bytes Assets/CoreLib/ReleaseLib/asap.core.dll.meta | 77 + Assets/Plugins.meta | 8 + Assets/Plugins/CodeStage.meta | 2 + .../Plugins/CodeStage/AntiCheatToolkit.meta | 7 + .../CodeStage/AntiCheatToolkit/API.txt | 2 + .../CodeStage/AntiCheatToolkit/API.txt.meta | 6 + .../CodeStage/AntiCheatToolkit/CHANGELOG.md | 1191 +++++++ .../AntiCheatToolkit/CHANGELOG.md.meta | 6 + .../CodeStage/AntiCheatToolkit/Editor.meta | 7 + .../Editor/ACTk.Editor.asmdef | 23 + .../Editor/ACTk.Editor.asmdef.meta | 9 + .../AntiCheatToolkit/Editor/Scripts.meta | 7 + .../Editor/Scripts/ACTkEditorConstants.cs | 48 + .../Scripts/ACTkEditorConstants.cs.meta | 3 + .../Editor/Scripts/ACTkMarker.cs | 41 + .../Editor/Scripts/ACTkMarker.cs.meta | 13 + .../Editor/Scripts/ACTkMenuItems.cs | 134 + .../Editor/Scripts/ACTkMenuItems.cs.meta | 11 + .../Editor/Scripts/AssemblyInfo.cs | 10 + .../Editor/Scripts/AssemblyInfo.cs.meta | 3 + .../Editor/Scripts/Common.meta | 8 + .../Editor/Scripts/Common/Tools.meta | 8 + .../Scripts/Common/Tools/CSColorTools.cs | 198 ++ .../Scripts/Common/Tools/CSColorTools.cs.meta | 11 + .../Scripts/Common/Tools/CSEditorIcons.cs | 35 + .../Common/Tools/CSEditorIcons.cs.meta | 11 + .../Scripts/Common/Tools/CSFileTools.cs | 27 + .../Scripts/Common/Tools/CSFileTools.cs.meta | 11 + .../Scripts/Common/Tools/CSTextureLoader.cs | 114 + .../Common/Tools/CSTextureLoader.cs.meta | 11 + .../Editor/Scripts/Editors.meta | 7 + .../Editors/InjectionDetectorEditor.cs | 64 + .../Editors/InjectionDetectorEditor.cs.meta | 10 + .../Editors/KeepAliveBehaviourEditor.cs | 94 + .../Editors/KeepAliveBehaviourEditor.cs.meta | 10 + .../Editors/ObscuredCheatingDetectorEditor.cs | 45 + .../ObscuredCheatingDetectorEditor.cs.meta | 10 + .../Editors/SpeedHackDetectorEditor.cs | 70 + .../Editors/SpeedHackDetectorEditor.cs.meta | 10 + .../Editors/TimeCheatingDetectorEditor.cs | 74 + .../TimeCheatingDetectorEditor.cs.meta | 8 + .../Scripts/Editors/WallHackDetectorEditor.cs | 139 + .../Editors/WallHackDetectorEditor.cs.meta | 10 + .../Editor/Scripts/Genuine.meta | 8 + .../Editor/Scripts/Genuine/CodeHash.meta | 8 + .../Scripts/Genuine/CodeHash/PostProcess.meta | 8 + .../CodeHashGeneratorPostprocessor.cs | 203 ++ .../CodeHashGeneratorPostprocessor.cs.meta | 11 + .../CodeHash/PostProcess/Platforms.meta | 3 + .../Platforms/AndroidBuildHashGenerator.cs | 184 + .../AndroidBuildHashGenerator.cs.meta | 3 + .../Platforms/WindowsBuildHashGenerator.cs | 49 + .../WindowsBuildHashGenerator.cs.meta | 3 + .../Editor/Scripts/Injection.meta | 3 + .../Scripts/Injection/AllowedAssembly.cs | 70 + .../Scripts/Injection/AllowedAssembly.cs.meta | 10 + .../Scripts/Injection/InjectionConstants.cs | 23 + .../Injection/InjectionConstants.cs.meta | 3 + .../Scripts/Injection/InjectionRoutines.cs | 229 ++ .../Injection/InjectionRoutines.cs.meta | 3 + .../Injection/InjectionWhitelistBuilder.cs | 234 ++ .../InjectionWhitelistBuilder.cs.meta | 3 + .../Editor/Scripts/Injection/PostProcess.meta | 9 + .../PostProcess/BuildPostProcessor.cs | 93 + .../PostProcess/BuildPostProcessor.cs.meta | 12 + .../Scripts/Injection/UserWhitelistEditor.cs | 276 ++ .../Injection/UserWhitelistEditor.cs.meta | 10 + .../Editor/Scripts/ObscuredTypes.meta | 8 + .../ObscuredTypes/MigrateUtils.Routines.cs | 253 ++ .../MigrateUtils.Routines.cs.meta | 3 + .../Scripts/ObscuredTypes/MigrateUtils.cs | 160 + .../ObscuredTypes/MigrateUtils.cs.meta | 8 + .../ObscuredTypes/PropertyDrawers.meta | 7 + .../ObscuredBigIntegerDrawer.cs | 122 + .../ObscuredBigIntegerDrawer.cs.meta | 3 + .../PropertyDrawers/ObscuredBoolDrawer.cs | 54 + .../ObscuredBoolDrawer.cs.meta | 10 + .../PropertyDrawers/ObscuredDateTimeDrawer.cs | 74 + .../ObscuredDateTimeDrawer.cs.meta | 3 + .../PropertyDrawers/ObscuredDecimalDrawer.cs | 143 + .../ObscuredDecimalDrawer.cs.meta | 12 + .../PropertyDrawers/ObscuredDoubleDrawer.cs | 59 + .../ObscuredDoubleDrawer.cs.meta | 10 + .../PropertyDrawers/ObscuredFloatDrawer.cs | 59 + .../ObscuredFloatDrawer.cs.meta | 10 + .../PropertyDrawers/ObscuredIntDrawer.cs | 57 + .../PropertyDrawers/ObscuredIntDrawer.cs.meta | 10 + .../PropertyDrawers/ObscuredLongDrawer.cs | 53 + .../ObscuredLongDrawer.cs.meta | 10 + .../ObscuredQuaternionDrawer.cs | 90 + .../ObscuredQuaternionDrawer.cs.meta | 3 + .../PropertyDrawers/ObscuredShortDrawer.cs | 57 + .../ObscuredShortDrawer.cs.meta | 8 + .../PropertyDrawers/ObscuredStringDrawer.cs | 137 + .../ObscuredStringDrawer.cs.meta | 10 + .../PropertyDrawers/ObscuredUIntDrawer.cs | 57 + .../ObscuredUIntDrawer.cs.meta | 8 + .../PropertyDrawers/ObscuredULongDrawer.cs | 53 + .../ObscuredULongDrawer.cs.meta | 12 + .../PropertyDrawers/ObscuredVector2Drawer.cs | 71 + .../ObscuredVector2Drawer.cs.meta | 10 + .../ObscuredVector2IntDrawer.cs | 71 + .../ObscuredVector2IntDrawer.cs.meta | 10 + .../PropertyDrawers/ObscuredVector3Drawer.cs | 77 + .../ObscuredVector3Drawer.cs.meta | 10 + .../ObscuredVector3IntDrawer.cs | 77 + .../ObscuredVector3IntDrawer.cs.meta | 13 + .../Scripts/ObscuredTypes/Validator.meta | 3 + .../Validator/ObscuredTypesValidator.cs | 87 + .../Validator/ObscuredTypesValidator.cs.meta | 3 + .../Editor/Scripts/PrefsEditor.meta | 8 + .../Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs | 447 +++ .../PrefsEditor/ACTkPrefsEditor.UI.cs.meta | 3 + .../Scripts/PrefsEditor/ACTkPrefsEditor.cs | 398 +++ .../PrefsEditor/ACTkPrefsEditor.cs.meta | 10 + .../Editor/Scripts/PrefsEditor/Plist.cs | 960 +++++ .../Editor/Scripts/PrefsEditor/Plist.cs.meta | 10 + .../Editor/Scripts/PrefsEditor/PrefsRecord.cs | 491 +++ .../Scripts/PrefsEditor/PrefsRecord.cs.meta | 3 + .../Editor/Scripts/Processors.meta | 3 + .../Scripts/Processors/BuildPreProcessor.cs | 151 + .../Processors/BuildPreProcessor.cs.meta | 3 + .../WallHackDetectorLinkerProcessor.cs | 80 + .../WallHackDetectorLinkerProcessor.cs.meta | 3 + .../Editor/Scripts/Settings.meta | 10 + .../Settings/ACTkEditorPrefsSettings.cs | 131 + .../Settings/ACTkEditorPrefsSettings.cs.meta | 3 + .../Editor/Scripts/Settings/ACTkSettings.cs | 230 ++ .../Scripts/Settings/ACTkSettings.cs.meta | 3 + .../Scripts/Settings/ACTkUserSettings.cs | 124 + .../Scripts/Settings/ACTkUserSettings.cs.meta | 3 + .../Editor/Scripts/Settings/SettingsGUI.cs | 583 ++++ .../Scripts/Settings/SettingsGUI.cs.meta | 3 + .../Settings/SettingsProviderWrapper.cs | 31 + .../Settings/SettingsProviderWrapper.cs.meta | 3 + .../Editor/Scripts/Settings/SettingsUtils.cs | 248 ++ .../Scripts/Settings/SettingsUtils.cs.meta | 3 + .../Scripts/Settings/SettingsValidator.cs | 138 + .../Settings/SettingsValidator.cs.meta | 3 + .../Editor/Scripts/Settings/SymbolsData.cs | 27 + .../Scripts/Settings/SymbolsData.cs.meta | 3 + .../Editor/Scripts/Tools.meta | 7 + .../Editor/Scripts/Tools/AsyncHelpers.cs | 129 + .../Editor/Scripts/Tools/AsyncHelpers.cs.meta | 3 + .../Editor/Scripts/Tools/DetectorTools.cs | 90 + .../Scripts/Tools/DetectorTools.cs.meta | 11 + .../Editor/Scripts/Tools/EditorTools.cs | 447 +++ .../Editor/Scripts/Tools/EditorTools.cs.meta | 10 + .../Editor/Scripts/Tools/GUITools.cs | 442 +++ .../Editor/Scripts/Tools/GUITools.cs.meta | 10 + .../Editor/Scripts/Tools/ReflectionTools.cs | 92 + .../Scripts/Tools/ReflectionTools.cs.meta | 3 + .../Tools/SerializedPropertyExtensions.cs | 77 + .../SerializedPropertyExtensions.cs.meta | 3 + .../Editor/Scripts/Tools/TextureTools.cs | 42 + .../Editor/Scripts/Tools/TextureTools.cs.meta | 3 + .../AntiCheatToolkit/Editor/SharpZip.meta | 8 + .../Editor/SharpZip/ACTkSharpZipLib.dll | Bin 0 -> 196608 bytes .../Editor/SharpZip/ACTkSharpZipLib.dll.meta | 33 + .../Editor/SharpZip/LICENSE.txt | 17 + .../Editor/SharpZip/LICENSE.txt.meta | 7 + .../AntiCheatToolkit/Editor/Textures.meta | 8 + .../Editor/Textures/Icons.meta | 8 + .../Editor/Textures/Icons/API.png | Bin 0 -> 253 bytes .../Editor/Textures/Icons/API.png.meta | 154 + .../Editor/Textures/Icons/Discord.png | Bin 0 -> 598 bytes .../Editor/Textures/Icons/Discord.png.meta | 132 + .../Editor/Textures/Icons/Forum.png | Bin 0 -> 245 bytes .../Editor/Textures/Icons/Forum.png.meta | 154 + .../Editor/Textures/Icons/Home.png | Bin 0 -> 249 bytes .../Editor/Textures/Icons/Home.png.meta | 154 + .../Editor/Textures/Icons/Manual.png | Bin 0 -> 281 bytes .../Editor/Textures/Icons/Manual.png.meta | 154 + .../Editor/Textures/Icons/Support.png | Bin 0 -> 284 bytes .../Editor/Textures/Icons/Support.png.meta | 154 + .../Editor/Textures/Icons/d_API.png | Bin 0 -> 263 bytes .../Editor/Textures/Icons/d_API.png.meta | 154 + .../Editor/Textures/Icons/d_Discord.png | Bin 0 -> 583 bytes .../Editor/Textures/Icons/d_Discord.png.meta | 132 + .../Editor/Textures/Icons/d_Forum.png | Bin 0 -> 244 bytes .../Editor/Textures/Icons/d_Forum.png.meta | 154 + .../Editor/Textures/Icons/d_Home.png | Bin 0 -> 268 bytes .../Editor/Textures/Icons/d_Home.png.meta | 154 + .../Editor/Textures/Icons/d_Manual.png | Bin 0 -> 280 bytes .../Editor/Textures/Icons/d_Manual.png.meta | 154 + .../Editor/Textures/Icons/d_Support.png | Bin 0 -> 282 bytes .../Editor/Textures/Icons/d_Support.png.meta | 154 + .../AntiCheatToolkit/Editor/Textures/Logo.png | Bin 0 -> 1459 bytes .../Editor/Textures/Logo.png.meta | 136 + .../Editor/Textures/d_Logo.png | Bin 0 -> 1436 bytes .../Editor/Textures/d_Logo.png.meta | 136 + .../AntiCheatToolkit/Integration.meta | 7 + .../AntiCheatToolkit/Integration/readme.txt | 1 + .../Integration/readme.txt.meta | 6 + .../CodeStage/AntiCheatToolkit/Readme.pdf | Bin 0 -> 822337 bytes .../AntiCheatToolkit/Readme.pdf.meta | 30 + .../CodeStage/AntiCheatToolkit/Runtime.meta | 8 + .../Runtime/ACTk.Runtime.asmdef | 24 + .../Runtime/ACTk.Runtime.asmdef.meta | 9 + .../AntiCheatToolkit/Runtime/Plugins.meta | 9 + .../Runtime/Plugins/Android.meta | 9 + .../Runtime/Plugins/Android/AndroidNative.aar | Bin 0 -> 16442 bytes .../Plugins/Android/AndroidNative.aar.meta | 32 + .../Runtime/Plugins/WebGL.meta | 3 + .../Runtime/Plugins/WebGL/WebGLNative.jslib | 15 + .../Plugins/WebGL/WebGLNative.jslib.meta | 32 + .../AntiCheatToolkit/Runtime/Scripts.meta | 7 + .../Runtime/Scripts/AssemblyInfo.cs | 12 + .../Runtime/Scripts/AssemblyInfo.cs.meta | 3 + .../Runtime/Scripts/Common.meta | 7 + .../Runtime/Scripts/Common/ACTk.cs | 93 + .../Runtime/Scripts/Common/ACTk.cs.meta | 3 + .../Runtime/Scripts/Common/ACTkByte16.cs | 65 + .../Runtime/Scripts/Common/ACTkByte16.cs.meta | 12 + .../Runtime/Scripts/Common/ACTkByte4.cs | 33 + .../Runtime/Scripts/Common/ACTkByte4.cs.meta | 8 + .../Runtime/Scripts/Common/ACTkByte8.cs | 47 + .../Runtime/Scripts/Common/ACTkByte8.cs.meta | 12 + .../Common/BackgroundThreadAccessException.cs | 21 + .../BackgroundThreadAccessException.cs.meta | 3 + .../Runtime/Scripts/Common/ContainerHolder.cs | 63 + .../Scripts/Common/ContainerHolder.cs.meta | 3 + .../Scripts/Common/KeepAliveBehaviour.cs | 155 + .../Scripts/Common/KeepAliveBehaviour.cs.meta | 3 + .../Scripts/Common/UnityApiResultsHolder.cs | 126 + .../Common/UnityApiResultsHolder.cs.meta | 3 + .../Runtime/Scripts/Detectors.meta | 7 + .../Runtime/Scripts/Detectors/Abstract.meta | 8 + .../Detectors/Abstract/ACTkDetectorBase.cs | 173 + .../Abstract/ACTkDetectorBase.cs.meta | 10 + .../Scripts/Detectors/InjectionDetector.cs | 564 +++ .../Detectors/InjectionDetector.cs.meta | 10 + .../Detectors/ObscuredCheatingDetector.cs | 244 ++ .../ObscuredCheatingDetector.cs.meta | 10 + .../Scripts/Detectors/SpeedHackDetector.cs | 387 +++ .../Detectors/SpeedHackDetector.cs.meta | 10 + .../Scripts/Detectors/TimeCheatingDetector.cs | 1224 +++++++ .../Detectors/TimeCheatingDetector.cs.meta | 8 + .../Scripts/Detectors/WallHackDetector.cs | 1162 +++++++ .../Detectors/WallHackDetector.cs.meta | 11 + .../Runtime/Scripts/Genuine.meta | 8 + .../Runtime/Scripts/Genuine/Android.meta | 3 + .../Genuine/Android/AndroidAppSource.cs | 31 + .../Genuine/Android/AndroidAppSource.cs.meta | 3 + .../Genuine/Android/AppInstallationSource.cs | 53 + .../Android/AppInstallationSource.cs.meta | 3 + .../Android/AppInstallationSourceValidator.cs | 53 + .../AppInstallationSourceValidator.cs.meta | 3 + .../Runtime/Scripts/Genuine/CodeHash.meta | 8 + .../Scripts/Genuine/CodeHash/BuildHashes.cs | 151 + .../Genuine/CodeHash/BuildHashes.cs.meta | 3 + .../Genuine/CodeHash/CodeHashGenerator.cs | 172 + .../CodeHash/CodeHashGenerator.cs.meta | 11 + .../Scripts/Genuine/CodeHash/FileHash.cs | 47 + .../Scripts/Genuine/CodeHash/FileHash.cs.meta | 3 + .../Scripts/Genuine/CodeHash/FilesProgress.cs | 43 + .../Genuine/CodeHash/FilesProgress.cs.meta | 3 + .../Scripts/Genuine/CodeHash/Filtering.meta | 3 + .../Genuine/CodeHash/Filtering/FileFilter.cs | 114 + .../CodeHash/Filtering/FileFilter.cs.meta | 3 + .../Genuine/CodeHash/Filtering/FilterGroup.cs | 15 + .../CodeHash/Filtering/FilterGroup.cs.meta | 3 + .../CodeHash/Filtering/FilteringData.cs | 65 + .../CodeHash/Filtering/FilteringData.cs.meta | 3 + .../CodeHash/Filtering/FilteringSettings.cs | 20 + .../Filtering/FilteringSettings.cs.meta | 3 + .../CodeHash/Filtering/FiltersProducer.cs | 186 + .../Filtering/FiltersProducer.cs.meta | 3 + .../Genuine/CodeHash/HashGeneratorResult.cs | 95 + .../CodeHash/HashGeneratorResult.cs.meta | 11 + .../Genuine/CodeHash/ICodeHashGenerator.cs | 42 + .../CodeHash/ICodeHashGenerator.cs.meta | 11 + .../Scripts/Genuine/CodeHash/SHA1Wrapper.cs | 42 + .../Genuine/CodeHash/SHA1Wrapper.cs.meta | 11 + .../Scripts/Genuine/CodeHash/Workers.meta | 8 + .../Genuine/CodeHash/Workers/AndroidWorker.cs | 121 + .../CodeHash/Workers/AndroidWorker.cs.meta | 11 + .../Genuine/CodeHash/Workers/BaseWorker.cs | 32 + .../CodeHash/Workers/BaseWorker.cs.meta | 11 + .../Workers/StandaloneWindowsWorker.cs | 135 + .../Workers/StandaloneWindowsWorker.cs.meta | 11 + .../Runtime/Scripts/ObscuredTypes.meta | 7 + .../Scripts/ObscuredTypes/Converters.meta | 8 + .../ObscuredTypes/Converters/Newtonsoft.meta | 8 + .../ObscuredTypesNewtonsoftConverter.cs | 293 ++ .../ObscuredTypesNewtonsoftConverter.cs.meta | 11 + .../Scripts/ObscuredTypes/Interfaces.meta | 3 + .../ObscuredTypes/Interfaces/IObscuredType.cs | 21 + .../Interfaces/IObscuredType.cs.meta | 3 + .../ObscuredTypes/ObscuredBigInteger.API.cs | 433 +++ .../ObscuredBigInteger.API.cs.meta | 3 + .../ObscuredBigInteger.Editor.cs | 22 + .../ObscuredBigInteger.Editor.cs.meta | 3 + .../ObscuredTypes/ObscuredBigInteger.Raw.cs | 87 + .../ObscuredBigInteger.Raw.cs.meta | 3 + .../ObscuredTypes/ObscuredBigInteger.cs | 192 + .../ObscuredTypes/ObscuredBigInteger.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredBool.API.cs | 65 + .../ObscuredTypes/ObscuredBool.API.cs.meta | 3 + .../ObscuredTypes/ObscuredBool.Editor.cs | 22 + .../ObscuredTypes/ObscuredBool.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredBool.cs | 212 ++ .../ObscuredTypes/ObscuredBool.cs.meta | 10 + .../Scripts/ObscuredTypes/ObscuredByte.API.cs | 109 + .../ObscuredTypes/ObscuredByte.API.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredByte.cs | 253 ++ .../ObscuredTypes/ObscuredByte.cs.meta | 10 + .../Scripts/ObscuredTypes/ObscuredChar.API.cs | 99 + .../ObscuredTypes/ObscuredChar.API.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredChar.cs | 212 ++ .../ObscuredTypes/ObscuredChar.cs.meta | 10 + .../ObscuredTypes/ObscuredDateTime.API.cs | 194 ++ .../ObscuredDateTime.API.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredDateTime.cs | 190 + .../ObscuredTypes/ObscuredDateTime.cs.meta | 3 + .../ObscuredTypes/ObscuredDecimal.API.cs | 114 + .../ObscuredTypes/ObscuredDecimal.API.cs.meta | 3 + .../ObscuredTypes/ObscuredDecimal.Editor.cs | 23 + .../ObscuredDecimal.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredDecimal.cs | 274 ++ .../ObscuredTypes/ObscuredDecimal.cs.meta | 10 + .../ObscuredTypes/ObscuredDouble.API.cs | 114 + .../ObscuredTypes/ObscuredDouble.API.cs.meta | 3 + .../ObscuredTypes/ObscuredDouble.Editor.cs | 22 + .../ObscuredDouble.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredDouble.cs | 337 ++ .../ObscuredTypes/ObscuredDouble.cs.meta | 10 + .../ObscuredTypes/ObscuredFloat.API.cs | 109 + .../ObscuredTypes/ObscuredFloat.API.cs.meta | 3 + .../ObscuredTypes/ObscuredFloat.Editor.cs | 22 + .../ObscuredFloat.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredFloat.cs | 317 ++ .../ObscuredTypes/ObscuredFloat.cs.meta | 10 + .../Scripts/ObscuredTypes/ObscuredInt.API.cs | 124 + .../ObscuredTypes/ObscuredInt.API.cs.meta | 3 + .../ObscuredTypes/ObscuredInt.Editor.cs | 22 + .../ObscuredTypes/ObscuredInt.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredInt.cs | 209 ++ .../Scripts/ObscuredTypes/ObscuredInt.cs.meta | 10 + .../Scripts/ObscuredTypes/ObscuredLong.API.cs | 109 + .../ObscuredTypes/ObscuredLong.API.cs.meta | 3 + .../ObscuredTypes/ObscuredLong.Editor.cs | 22 + .../ObscuredTypes/ObscuredLong.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredLong.cs | 209 ++ .../ObscuredTypes/ObscuredLong.cs.meta | 10 + .../ObscuredTypes/ObscuredQuaternion.API.cs | 65 + .../ObscuredQuaternion.API.cs.meta | 3 + .../ObscuredQuaternion.Editor.cs | 22 + .../ObscuredQuaternion.Editor.cs.meta | 3 + .../ObscuredTypes/ObscuredQuaternion.Raw.cs | 62 + .../ObscuredQuaternion.Raw.cs.meta | 3 + .../ObscuredTypes/ObscuredQuaternion.cs | 277 ++ .../ObscuredTypes/ObscuredQuaternion.cs.meta | 10 + .../ObscuredTypes/ObscuredSByte.API.cs | 109 + .../ObscuredTypes/ObscuredSByte.API.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredSByte.cs | 214 ++ .../ObscuredTypes/ObscuredSByte.cs.meta | 10 + .../ObscuredTypes/ObscuredShort.API.cs | 109 + .../ObscuredTypes/ObscuredShort.API.cs.meta | 3 + .../ObscuredTypes/ObscuredShort.Editor.cs | 22 + .../ObscuredShort.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredShort.cs | 213 ++ .../ObscuredTypes/ObscuredShort.cs.meta | 10 + .../ObscuredTypes/ObscuredString.API.cs | 159 + .../ObscuredTypes/ObscuredString.API.cs.meta | 3 + .../ObscuredTypes/ObscuredString.Editor.cs | 22 + .../ObscuredString.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredString.cs | 430 +++ .../ObscuredTypes/ObscuredString.cs.meta | 10 + .../Scripts/ObscuredTypes/ObscuredUInt.API.cs | 114 + .../ObscuredTypes/ObscuredUInt.API.cs.meta | 3 + .../ObscuredTypes/ObscuredUInt.Editor.cs | 22 + .../ObscuredTypes/ObscuredUInt.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredUInt.cs | 209 ++ .../ObscuredTypes/ObscuredUInt.cs.meta | 10 + .../ObscuredTypes/ObscuredULong.API.cs | 109 + .../ObscuredTypes/ObscuredULong.API.cs.meta | 3 + .../ObscuredTypes/ObscuredULong.Editor.cs | 22 + .../ObscuredULong.Editor.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredULong.cs | 209 ++ .../ObscuredTypes/ObscuredULong.cs.meta | 10 + .../ObscuredTypes/ObscuredUShort.API.cs | 109 + .../ObscuredTypes/ObscuredUShort.API.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredUShort.cs | 212 ++ .../ObscuredTypes/ObscuredUShort.cs.meta | 10 + .../ObscuredTypes/ObscuredVector2.API.cs | 71 + .../ObscuredTypes/ObscuredVector2.API.cs.meta | 3 + .../ObscuredTypes/ObscuredVector2.Editor.cs | 22 + .../ObscuredVector2.Editor.cs.meta | 3 + .../ObscuredTypes/ObscuredVector2.Raw.cs | 48 + .../ObscuredTypes/ObscuredVector2.Raw.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredVector2.cs | 376 ++ .../ObscuredTypes/ObscuredVector2.cs.meta | 10 + .../ObscuredTypes/ObscuredVector2Int.API.cs | 56 + .../ObscuredVector2Int.API.cs.meta | 3 + .../ObscuredVector2Int.Editor.cs | 22 + .../ObscuredVector2Int.Editor.cs.meta | 3 + .../ObscuredTypes/ObscuredVector2Int.Raw.cs | 48 + .../ObscuredVector2Int.Raw.cs.meta | 3 + .../ObscuredTypes/ObscuredVector2Int.cs | 351 ++ .../ObscuredTypes/ObscuredVector2Int.cs.meta | 10 + .../ObscuredTypes/ObscuredVector3.API.cs | 145 + .../ObscuredTypes/ObscuredVector3.API.cs.meta | 3 + .../ObscuredTypes/ObscuredVector3.Editor.cs | 22 + .../ObscuredVector3.Editor.cs.meta | 3 + .../ObscuredTypes/ObscuredVector3.Raw.cs | 54 + .../ObscuredTypes/ObscuredVector3.Raw.cs.meta | 3 + .../Scripts/ObscuredTypes/ObscuredVector3.cs | 424 +++ .../ObscuredTypes/ObscuredVector3.cs.meta | 10 + .../ObscuredTypes/ObscuredVector3Int.API.cs | 126 + .../ObscuredVector3Int.API.cs.meta | 3 + .../ObscuredVector3Int.Editor.cs | 22 + .../ObscuredVector3Int.Editor.cs.meta | 3 + .../ObscuredTypes/ObscuredVector3Int.Raw.cs | 56 + .../ObscuredVector3Int.Raw.cs.meta | 3 + .../ObscuredTypes/ObscuredVector3Int.cs | 401 +++ .../ObscuredTypes/ObscuredVector3Int.cs.meta | 13 + .../Runtime/Scripts/Storage.meta | 3 + .../Runtime/Scripts/Storage/Data.meta | 3 + .../Runtime/Scripts/Storage/Data/Enums.meta | 3 + .../Storage/Data/Enums/StorageDataType.cs | 110 + .../Data/Enums/StorageDataType.cs.meta | 3 + .../Scripts/Storage/Data/ObscuredPrefsData.cs | 23 + .../Storage/Data/ObscuredPrefsData.cs.meta | 3 + .../Storage/Data/StorageDataConverter.cs | 251 ++ .../Storage/Data/StorageDataConverter.cs.meta | 3 + .../Storage/Data/StorageDataTypeClassifier.cs | 86 + .../Data/StorageDataTypeClassifier.cs.meta | 3 + .../Data/UnsupportedDataTypeException.cs | 16 + .../Data/UnsupportedDataTypeException.cs.meta | 3 + .../Runtime/Scripts/Storage/DeviceLock.meta | 3 + .../Storage/DeviceLock/DeviceIdHolder.cs | 136 + .../Storage/DeviceLock/DeviceIdHolder.cs.meta | 3 + .../Storage/DeviceLock/DeviceLockLevel.cs | 40 + .../DeviceLock/DeviceLockLevel.cs.meta | 3 + .../Storage/DeviceLock/DeviceLockSettings.cs | 37 + .../DeviceLock/DeviceLockSettings.cs.meta | 3 + .../DeviceLockTamperingSensitivity.cs | 31 + .../DeviceLockTamperingSensitivity.cs.meta | 3 + .../Runtime/Scripts/Storage/Exceptions.meta | 3 + .../DeviceUniqueIdentifierException.cs | 19 + .../DeviceUniqueIdentifierException.cs.meta | 3 + .../Exceptions/PersistentDataPathException.cs | 19 + .../PersistentDataPathException.cs.meta | 3 + .../Exceptions/VendorIdentifierException.cs | 24 + .../VendorIdentifierException.cs.meta | 3 + .../Runtime/Scripts/Storage/File.meta | 8 + .../Scripts/Storage/File/ObscuredFile.cs | 425 +++ .../Scripts/Storage/File/ObscuredFile.cs.meta | 11 + .../Storage/File/ObscuredFileCrypto.cs | 118 + .../Storage/File/ObscuredFileCrypto.cs.meta | 3 + .../Storage/File/ObscuredFileHeader.cs | 56 + .../Storage/File/ObscuredFileHeader.cs.meta | 3 + .../Storage/File/OperationResults.meta | 3 + .../OperationResults/ObscuredFileError.cs | 72 + .../ObscuredFileError.cs.meta | 3 + .../ObscuredFileReadResult.cs | 95 + .../ObscuredFileReadResult.cs.meta | 3 + .../ObscuredFileWriteResult.cs | 57 + .../ObscuredFileWriteResult.cs.meta | 3 + .../Runtime/Scripts/Storage/File/Prefs.meta | 3 + .../Prefs/ObscuredFilePrefs.ObscuredTypes.cs | 60 + .../ObscuredFilePrefs.ObscuredTypes.cs.meta | 3 + .../Storage/File/Prefs/ObscuredFilePrefs.cs | 511 +++ .../File/Prefs/ObscuredFilePrefs.cs.meta | 3 + .../File/Prefs/ObscuredFilePrefsAutoSaver.cs | 123 + .../Prefs/ObscuredFilePrefsAutoSaver.cs.meta | 3 + .../Storage/File/Prefs/Serialization.meta | 3 + .../Prefs/Serialization/PrefsSerialization.cs | 43 + .../Serialization/PrefsSerialization.cs.meta | 3 + .../Serialization/SerializationSettings.cs | 23 + .../SerializationSettings.cs.meta | 3 + .../File/Prefs/Serialization/Serializers.meta | 3 + .../Serializers/BinarySerializer.cs | 107 + .../Serializers/BinarySerializer.cs.meta | 3 + .../IObscuredFilePrefsSerializer.cs | 19 + .../IObscuredFilePrefsSerializer.cs.meta | 3 + .../Serializers/JsonSerializer.cs | 42 + .../Serializers/JsonSerializer.cs.meta | 3 + .../Scripts/Storage/File/Settings.meta | 3 + .../File/Settings/EncryptionSettings.cs | 76 + .../File/Settings/EncryptionSettings.cs.meta | 3 + .../File/Settings/IObscuredFileSettings.cs | 45 + .../Settings/IObscuredFileSettings.cs.meta | 3 + .../File/Settings/ObscuredFileSettings.cs | 88 + .../Settings/ObscuredFileSettings.cs.meta | 3 + .../Runtime/Scripts/Storage/Prefs.meta | 3 + .../Storage/Prefs/ObscuredPrefs.LegacyApi.cs | 274 ++ .../Prefs/ObscuredPrefs.LegacyApi.cs.meta | 3 + .../Prefs/ObscuredPrefs.ObscuredTypes.cs | 61 + .../Prefs/ObscuredPrefs.ObscuredTypes.cs.meta | 11 + .../Storage/Prefs/ObscuredPrefs.Routines.cs | 481 +++ .../Prefs/ObscuredPrefs.Routines.cs.meta | 3 + .../Scripts/Storage/Prefs/ObscuredPrefs.cs | 356 ++ .../Storage/Prefs/ObscuredPrefs.cs.meta | 10 + .../Runtime/Scripts/Time.meta | 10 + .../Scripts/Time/SpeedHackProofTime.cs | 260 ++ .../Scripts/Time/SpeedHackProofTime.cs.meta | 13 + .../Runtime/Scripts/Utils.meta | 7 + .../Runtime/Scripts/Utils/AndroidRoutines.cs | 47 + .../Scripts/Utils/AndroidRoutines.cs.meta | 3 + .../Scripts/Utils/AppEventsDispatcher.cs | 49 + .../Scripts/Utils/AppEventsDispatcher.cs.meta | 3 + .../Runtime/Scripts/Utils/Base64Utils.cs | 40 + .../Runtime/Scripts/Utils/Base64Utils.cs.meta | 3 + .../Runtime/Scripts/Utils/CryptoUtils.cs | 98 + .../Runtime/Scripts/Utils/CryptoUtils.cs.meta | 3 + .../Utils/NonValidatingCertificateHandler.cs | 19 + .../NonValidatingCertificateHandler.cs.meta | 3 + .../Runtime/Scripts/Utils/NumUtils.cs | 18 + .../Runtime/Scripts/Utils/NumUtils.cs.meta | 3 + .../Scripts/Utils/ProgressExtensionMethods.cs | 28 + .../Utils/ProgressExtensionMethods.cs.meta | 3 + .../Runtime/Scripts/Utils/RandomUtils.cs | 82 + .../Runtime/Scripts/Utils/RandomUtils.cs.meta | 3 + .../Runtime/Scripts/Utils/StringUtils.cs | 58 + .../Runtime/Scripts/Utils/StringUtils.cs.meta | 3 + .../Utils/ThreadSafeDisposablesPool.cs | 41 + .../Utils/ThreadSafeDisposablesPool.cs.meta | 3 + .../Runtime/Scripts/Utils/ThreadSafeRandom.cs | 148 + .../Scripts/Utils/ThreadSafeRandom.cs.meta | 3 + .../Runtime/Scripts/Utils/TimeUtils.cs | 92 + .../Runtime/Scripts/Utils/TimeUtils.cs.meta | 13 + .../Runtime/Scripts/Utils/xxHash.cs | 195 ++ .../Runtime/Scripts/Utils/xxHash.cs.meta | 10 + .../AntiCheatToolkit/Runtime/Shaders.meta | 7 + .../Runtime/Shaders/WallHackTexture.shader | 45 + .../Shaders/WallHackTexture.shader.meta | 7 + .../AntiCheatToolkit/Third-Party Notices.txt | 5 + .../Third-Party Notices.txt.meta | 7 + Assets/Plugins/Demigiant.meta | 8 + Assets/Plugins/Demigiant/DOTween.meta | 21 + Assets/Plugins/Demigiant/DOTween/DOTween.XML | 3077 +++++++++++++++++ .../Demigiant/DOTween/DOTween.XML.meta | 4 + Assets/Plugins/Demigiant/DOTween/DOTween.dll | Bin 0 -> 175104 bytes .../Demigiant/DOTween/DOTween.dll.meta | 22 + Assets/Plugins/Demigiant/DOTween/Editor.meta | 5 + .../DOTween/Editor/DOTweenEditor.XML | 124 + .../DOTween/Editor/DOTweenEditor.XML.meta | 4 + .../DOTween/Editor/DOTweenEditor.dll | Bin 0 -> 69632 bytes .../DOTween/Editor/DOTweenEditor.dll.meta | 22 + .../Demigiant/DOTween/Editor/Imgs.meta | 5 + .../DOTween/Editor/Imgs/DOTweenIcon.png | Bin 0 -> 1565 bytes .../DOTween/Editor/Imgs/DOTweenIcon.png.meta | 47 + .../DOTween/Editor/Imgs/DOTweenMiniIcon.png | Bin 0 -> 319 bytes .../Editor/Imgs/DOTweenMiniIcon.png.meta | 68 + .../Demigiant/DOTween/Editor/Imgs/Footer.png | Bin 0 -> 4409 bytes .../DOTween/Editor/Imgs/Footer.png.meta | 47 + .../DOTween/Editor/Imgs/Footer_dark.png | Bin 0 -> 4429 bytes .../DOTween/Editor/Imgs/Footer_dark.png.meta | 47 + .../Demigiant/DOTween/Editor/Imgs/Header.jpg | Bin 0 -> 22787 bytes .../DOTween/Editor/Imgs/Header.jpg.meta | 47 + Assets/Plugins/Demigiant/DOTween/Modules.meta | 5 + .../DOTween/Modules/DOTween.Modules.asmdef | 3 + .../Modules/DOTween.Modules.asmdef.meta | 7 + .../DOTween/Modules/DOTweenModuleAudio.cs | 202 ++ .../Modules/DOTweenModuleAudio.cs.meta | 8 + .../Modules/DOTweenModuleEPOOutline.cs | 146 + .../Modules/DOTweenModuleEPOOutline.cs.meta | 12 + .../DOTween/Modules/DOTweenModulePhysics.cs | 216 ++ .../Modules/DOTweenModulePhysics.cs.meta | 8 + .../DOTween/Modules/DOTweenModulePhysics2D.cs | 193 ++ .../Modules/DOTweenModulePhysics2D.cs.meta | 8 + .../DOTween/Modules/DOTweenModuleSprite.cs | 93 + .../Modules/DOTweenModuleSprite.cs.meta | 8 + .../DOTween/Modules/DOTweenModuleUI.cs | 662 ++++ .../DOTween/Modules/DOTweenModuleUI.cs.meta | 8 + .../Modules/DOTweenModuleUnityVersion.cs | 403 +++ .../Modules/DOTweenModuleUnityVersion.cs.meta | 8 + .../DOTween/Modules/DOTweenModuleUtils.cs | 167 + .../Modules/DOTweenModuleUtils.cs.meta | 8 + Assets/Plugins/Demigiant/DOTween/readme.txt | 29 + .../Plugins/Demigiant/DOTween/readme.txt.meta | 4 + Assets/Plugins/Demigiant/DOTweenPro.meta | 23 + .../Demigiant/DOTweenPro/DOTweenAnimation.cs | 917 +++++ .../DOTweenPro/DOTweenAnimation.cs.meta | 8 + .../Demigiant/DOTweenPro/DOTweenDeAudio.cs | 9 + .../DOTweenPro/DOTweenDeAudio.cs.meta | 12 + .../DOTweenPro/DOTweenDeUnityExtended.cs | 9 + .../DOTweenPro/DOTweenDeUnityExtended.cs.meta | 12 + .../DOTweenPro/DOTweenPro.Scripts.asmdef | 6 + .../DOTweenPro/DOTweenPro.Scripts.asmdef.meta | 7 + .../Demigiant/DOTweenPro/DOTweenPro.XML | 80 + .../Demigiant/DOTweenPro/DOTweenPro.XML.meta | 4 + .../Demigiant/DOTweenPro/DOTweenPro.dll | Bin 0 -> 16384 bytes .../Demigiant/DOTweenPro/DOTweenPro.dll.meta | 22 + .../DOTweenPro/DOTweenProShortcuts.cs | 90 + .../DOTweenPro/DOTweenProShortcuts.cs.meta | 8 + .../DOTweenPro/DOTweenTextMeshPro.cs | 1037 ++++++ .../DOTweenPro/DOTweenTextMeshPro.cs.meta | 8 + .../Demigiant/DOTweenPro/DOTweenTk2d.cs | 247 ++ .../Demigiant/DOTweenPro/DOTweenTk2d.cs.meta | 8 + .../Plugins/Demigiant/DOTweenPro/Editor.meta | 5 + .../Editor/DOTweenAnimationInspector.cs | 764 ++++ .../Editor/DOTweenAnimationInspector.cs.meta | 8 + .../Editor/DOTweenPreviewManager.cs | 265 ++ .../Editor/DOTweenPreviewManager.cs.meta | 8 + .../Editor/DOTweenPro.EditorScripts.asmdef | 11 + .../DOTweenPro.EditorScripts.asmdef.meta | 7 + .../DOTweenPro/Editor/DOTweenProEditor.XML | 18 + .../Editor/DOTweenProEditor.XML.meta | 4 + .../DOTweenPro/Editor/DOTweenProEditor.dll | Bin 0 -> 35840 bytes .../Editor/DOTweenProEditor.dll.meta | 22 + .../Plugins/Demigiant/DOTweenPro/readme.txt | 35 + .../Demigiant/DOTweenPro/readme.txt.meta | 4 + Assets/Plugins/Demigiant/DemiLib.meta | 21 + Assets/Plugins/Demigiant/DemiLib/Core.meta | 5 + .../Demigiant/DemiLib/Core/DemiLib.dll | Bin 0 -> 14848 bytes .../Demigiant/DemiLib/Core/DemiLib.dll.meta | 22 + .../Demigiant/DemiLib/Core/DemiLib.xml | 231 ++ .../Demigiant/DemiLib/Core/DemiLib.xml.meta | 4 + .../Demigiant/DemiLib/Core/Editor.meta | 5 + .../DemiLib/Core/Editor/DemiEditor.dll | Bin 0 -> 193536 bytes .../DemiLib/Core/Editor/DemiEditor.dll.meta | 22 + .../DemiLib/Core/Editor/DemiEditor.xml | 2370 +++++++++++++ .../DemiLib/Core/Editor/DemiEditor.xml.meta | 4 + .../Demigiant/DemiLib/Core/Editor/Imgs.meta | 5 + .../DemiLib/Core/Editor/Imgs/blackSquare.png | Bin 0 -> 109 bytes .../Core/Editor/Imgs/blackSquare.png.meta | 47 + .../Core/Editor/Imgs/blackSquareAlpha10.png | Bin 0 -> 109 bytes .../Editor/Imgs/blackSquareAlpha10.png.meta | 47 + .../Core/Editor/Imgs/blackSquareAlpha15.png | Bin 0 -> 109 bytes .../Editor/Imgs/blackSquareAlpha15.png.meta | 47 + .../Core/Editor/Imgs/blackSquareAlpha25.png | Bin 0 -> 109 bytes .../Editor/Imgs/blackSquareAlpha25.png.meta | 47 + .../Core/Editor/Imgs/blackSquareAlpha50.png | Bin 0 -> 109 bytes .../Editor/Imgs/blackSquareAlpha50.png.meta | 47 + .../Core/Editor/Imgs/blackSquareAlpha80.png | Bin 0 -> 109 bytes .../Editor/Imgs/blackSquareAlpha80.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/blueSquare.png | Bin 0 -> 106 bytes .../Core/Editor/Imgs/blueSquare.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/circle.png | Bin 0 -> 455 bytes .../DemiLib/Core/Editor/Imgs/circle.png.meta | 47 + .../Editor/Imgs/circle_dashedBorderEmpty.png | Bin 0 -> 673 bytes .../Imgs/circle_dashedBorderEmpty.png.meta | 68 + .../DemiLib/Core/Editor/Imgs/greenSquare.png | Bin 0 -> 106 bytes .../Core/Editor/Imgs/greenSquare.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/grid_bright.png | Bin 0 -> 222 bytes .../Core/Editor/Imgs/grid_bright.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/grid_dark.png | Bin 0 -> 216 bytes .../Core/Editor/Imgs/grid_dark.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alert.png | Bin 0 -> 540 bytes .../Core/Editor/Imgs/ico_alert.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignB.png | Bin 0 -> 131 bytes .../Core/Editor/Imgs/ico_alignB.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignBC.png | Bin 0 -> 158 bytes .../Core/Editor/Imgs/ico_alignBC.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignBL.png | Bin 0 -> 152 bytes .../Core/Editor/Imgs/ico_alignBL.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignBR.png | Bin 0 -> 150 bytes .../Core/Editor/Imgs/ico_alignBR.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignCC.png | Bin 0 -> 152 bytes .../Core/Editor/Imgs/ico_alignCC.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignCL.png | Bin 0 -> 158 bytes .../Core/Editor/Imgs/ico_alignCL.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignCR.png | Bin 0 -> 153 bytes .../Core/Editor/Imgs/ico_alignCR.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignHC.png | Bin 0 -> 147 bytes .../Core/Editor/Imgs/ico_alignHC.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignL.png | Bin 0 -> 136 bytes .../Core/Editor/Imgs/ico_alignL.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignR.png | Bin 0 -> 145 bytes .../Core/Editor/Imgs/ico_alignR.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignT.png | Bin 0 -> 129 bytes .../Core/Editor/Imgs/ico_alignT.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignTC.png | Bin 0 -> 164 bytes .../Core/Editor/Imgs/ico_alignTC.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignTL.png | Bin 0 -> 153 bytes .../Core/Editor/Imgs/ico_alignTL.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignTR.png | Bin 0 -> 155 bytes .../Core/Editor/Imgs/ico_alignTR.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_alignVC.png | Bin 0 -> 135 bytes .../Core/Editor/Imgs/ico_alignVC.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_camera.png | Bin 0 -> 206 bytes .../Core/Editor/Imgs/ico_camera.png.meta | 47 + .../Core/Editor/Imgs/ico_camera_border.png | Bin 0 -> 347 bytes .../Editor/Imgs/ico_camera_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_cog.png | Bin 0 -> 197 bytes .../DemiLib/Core/Editor/Imgs/ico_cog.png.meta | 47 + .../Core/Editor/Imgs/ico_cog_border.png | Bin 0 -> 376 bytes .../Core/Editor/Imgs/ico_cog_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_comment.png | Bin 0 -> 176 bytes .../Core/Editor/Imgs/ico_comment.png.meta | 47 + .../Core/Editor/Imgs/ico_comment_border.png | Bin 0 -> 426 bytes .../Editor/Imgs/ico_comment_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_delete.png | Bin 0 -> 145 bytes .../Core/Editor/Imgs/ico_delete.png.meta | 47 + .../Core/Editor/Imgs/ico_demigiant.png | Bin 0 -> 605 bytes .../Core/Editor/Imgs/ico_demigiant.png.meta | 47 + .../Editor/Imgs/ico_distributeHAlignT.png | Bin 0 -> 174 bytes .../Imgs/ico_distributeHAlignT.png.meta | 47 + .../Editor/Imgs/ico_distributeVAlignL.png | Bin 0 -> 197 bytes .../Imgs/ico_distributeVAlignL.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_doing.png | Bin 0 -> 838 bytes .../Core/Editor/Imgs/ico_doing.png.meta | 68 + .../DemiLib/Core/Editor/Imgs/ico_end.png | Bin 0 -> 475 bytes .../DemiLib/Core/Editor/Imgs/ico_end.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_flipV.png | Bin 0 -> 167 bytes .../Core/Editor/Imgs/ico_flipV.png.meta | 47 + .../Core/Editor/Imgs/ico_foldout_closed.png | Bin 0 -> 158 bytes .../Editor/Imgs/ico_foldout_closed.png.meta | 47 + .../Core/Editor/Imgs/ico_foldout_open.png | Bin 0 -> 170 bytes .../Editor/Imgs/ico_foldout_open.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_heart.png | Bin 0 -> 210 bytes .../Core/Editor/Imgs/ico_heart.png.meta | 47 + .../Core/Editor/Imgs/ico_heart_border.png | Bin 0 -> 307 bytes .../Editor/Imgs/ico_heart_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_light.png | Bin 0 -> 190 bytes .../Core/Editor/Imgs/ico_light.png.meta | 47 + .../Core/Editor/Imgs/ico_light_border.png | Bin 0 -> 292 bytes .../Editor/Imgs/ico_light_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_lock.png | Bin 0 -> 300 bytes .../Core/Editor/Imgs/ico_lock.png.meta | 47 + .../Core/Editor/Imgs/ico_lock_open.png | Bin 0 -> 293 bytes .../Core/Editor/Imgs/ico_lock_open.png.meta | 47 + .../Core/Editor/Imgs/ico_nodeArrow.png | Bin 0 -> 168 bytes .../Core/Editor/Imgs/ico_nodeArrow.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_ok.png | Bin 0 -> 715 bytes .../DemiLib/Core/Editor/Imgs/ico_ok.png.meta | 47 + .../Core/Editor/Imgs/ico_optionsDropdown.png | Bin 0 -> 135 bytes .../Editor/Imgs/ico_optionsDropdown.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_play.png | Bin 0 -> 256 bytes .../Core/Editor/Imgs/ico_play.png.meta | 47 + .../Core/Editor/Imgs/ico_play_border.png | Bin 0 -> 386 bytes .../Core/Editor/Imgs/ico_play_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_skull.png | Bin 0 -> 227 bytes .../Core/Editor/Imgs/ico_skull.png.meta | 47 + .../Core/Editor/Imgs/ico_skull_border.png | Bin 0 -> 332 bytes .../Editor/Imgs/ico_skull_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_star.png | Bin 0 -> 203 bytes .../Core/Editor/Imgs/ico_star.png.meta | 47 + .../Core/Editor/Imgs/ico_star_border.png | Bin 0 -> 323 bytes .../Core/Editor/Imgs/ico_star_border.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/ico_todo.png | Bin 0 -> 674 bytes .../Core/Editor/Imgs/ico_todo.png.meta | 68 + .../DemiLib/Core/Editor/Imgs/ico_ui.png | Bin 0 -> 223 bytes .../DemiLib/Core/Editor/Imgs/ico_ui.png.meta | 47 + .../Core/Editor/Imgs/ico_ui_border.png | Bin 0 -> 259 bytes .../Core/Editor/Imgs/ico_ui_border.png.meta | 47 + .../Core/Editor/Imgs/ico_visibility.png | Bin 0 -> 298 bytes .../Core/Editor/Imgs/ico_visibility.png.meta | 47 + .../Core/Editor/Imgs/ico_visibility_off.png | Bin 0 -> 367 bytes .../Editor/Imgs/ico_visibility_off.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/orangeSquare.png | Bin 0 -> 104 bytes .../Core/Editor/Imgs/orangeSquare.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/project.meta | 5 + .../Core/Editor/Imgs/project/ico_atlas.png | Bin 0 -> 218 bytes .../Editor/Imgs/project/ico_atlas.png.meta | 47 + .../Core/Editor/Imgs/project/ico_audio.png | Bin 0 -> 338 bytes .../Editor/Imgs/project/ico_audio.png.meta | 47 + .../Core/Editor/Imgs/project/ico_bundle.png | Bin 0 -> 522 bytes .../Editor/Imgs/project/ico_bundle.png.meta | 47 + .../Core/Editor/Imgs/project/ico_cog.png | Bin 0 -> 406 bytes .../Core/Editor/Imgs/project/ico_cog.png.meta | 47 + .../Core/Editor/Imgs/project/ico_cross.png | Bin 0 -> 210 bytes .../Editor/Imgs/project/ico_cross.png.meta | 47 + .../Editor/Imgs/project/ico_demigiant.png | Bin 0 -> 388 bytes .../Imgs/project/ico_demigiant.png.meta | 47 + .../Core/Editor/Imgs/project/ico_folder.png | Bin 0 -> 150 bytes .../Editor/Imgs/project/ico_folder.png.meta | 47 + .../Core/Editor/Imgs/project/ico_fonts.png | Bin 0 -> 465 bytes .../Editor/Imgs/project/ico_fonts.png.meta | 47 + .../Core/Editor/Imgs/project/ico_heart.png | Bin 0 -> 334 bytes .../Editor/Imgs/project/ico_heart.png.meta | 47 + .../Editor/Imgs/project/ico_materials.png | Bin 0 -> 355 bytes .../Imgs/project/ico_materials.png.meta | 47 + .../Core/Editor/Imgs/project/ico_models.png | Bin 0 -> 380 bytes .../Editor/Imgs/project/ico_models.png.meta | 47 + .../Editor/Imgs/project/ico_particles.png | Bin 0 -> 493 bytes .../Imgs/project/ico_particles.png.meta | 47 + .../Core/Editor/Imgs/project/ico_play.png | Bin 0 -> 217 bytes .../Editor/Imgs/project/ico_play.png.meta | 47 + .../Core/Editor/Imgs/project/ico_prefab.png | Bin 0 -> 343 bytes .../Editor/Imgs/project/ico_prefab.png.meta | 47 + .../Core/Editor/Imgs/project/ico_scripts.png | Bin 0 -> 208 bytes .../Editor/Imgs/project/ico_scripts.png.meta | 47 + .../Core/Editor/Imgs/project/ico_shaders.png | Bin 0 -> 379 bytes .../Editor/Imgs/project/ico_shaders.png.meta | 47 + .../Core/Editor/Imgs/project/ico_skull.png | Bin 0 -> 368 bytes .../Editor/Imgs/project/ico_skull.png.meta | 47 + .../Core/Editor/Imgs/project/ico_star.png | Bin 0 -> 289 bytes .../Editor/Imgs/project/ico_star.png.meta | 47 + .../Core/Editor/Imgs/project/ico_terrains.png | Bin 0 -> 309 bytes .../Editor/Imgs/project/ico_terrains.png.meta | 47 + .../Core/Editor/Imgs/project/ico_textures.png | Bin 0 -> 278 bytes .../Editor/Imgs/project/ico_textures.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/purpleSquare.png | Bin 0 -> 106 bytes .../Core/Editor/Imgs/purpleSquare.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/redSquare.png | Bin 0 -> 106 bytes .../Core/Editor/Imgs/redSquare.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/squareBorder.png | Bin 0 -> 122 bytes .../Core/Editor/Imgs/squareBorder.png.meta | 47 + .../Core/Editor/Imgs/squareBorderAlpha15.png | Bin 0 -> 116 bytes .../Editor/Imgs/squareBorderAlpha15.png.meta | 47 + .../Core/Editor/Imgs/squareBorderCurved.png | Bin 0 -> 196 bytes .../Editor/Imgs/squareBorderCurved.png.meta | 47 + .../Core/Editor/Imgs/squareBorderCurved02.png | Bin 0 -> 281 bytes .../Editor/Imgs/squareBorderCurved02.png.meta | 47 + .../Imgs/squareBorderCurved02_darkBorders.png | Bin 0 -> 336 bytes .../squareBorderCurved02_darkBorders.png.meta | 47 + .../Editor/Imgs/squareBorderCurvedAlpha.png | Bin 0 -> 197 bytes .../Imgs/squareBorderCurvedAlpha.png.meta | 47 + .../Editor/Imgs/squareBorderCurvedEmpty.png | Bin 0 -> 180 bytes .../Imgs/squareBorderCurvedEmpty.png.meta | 47 + .../Editor/Imgs/squareBorderCurvedEmpty02.png | Bin 0 -> 217 bytes .../Imgs/squareBorderCurvedEmpty02.png.meta | 47 + .../Imgs/squareBorderCurvedEmptyThick.png | Bin 0 -> 233 bytes .../squareBorderCurvedEmptyThick.png.meta | 47 + .../Imgs/squareBorderCurved_darkBorders.png | Bin 0 -> 216 bytes .../squareBorderCurved_darkBorders.png.meta | 47 + .../squareBorderCurved_darkBordersAlpha.png | Bin 0 -> 200 bytes ...uareBorderCurved_darkBordersAlpha.png.meta | 47 + .../Core/Editor/Imgs/squareBorderEmpty.png | Bin 0 -> 114 bytes .../Editor/Imgs/squareBorderEmpty.png.meta | 47 + .../Core/Editor/Imgs/squareBorderEmpty01.png | Bin 0 -> 114 bytes .../Editor/Imgs/squareBorderEmpty01.png.meta | 47 + .../Core/Editor/Imgs/squareBorderEmpty02.png | Bin 0 -> 121 bytes .../Editor/Imgs/squareBorderEmpty02.png.meta | 47 + .../Core/Editor/Imgs/squareBorderEmpty03.png | Bin 0 -> 122 bytes .../Editor/Imgs/squareBorderEmpty03.png.meta | 47 + .../Editor/Imgs/squareBorderThickEmpty.png | Bin 0 -> 121 bytes .../Imgs/squareBorderThickEmpty.png.meta | 47 + .../Editor/Imgs/squareBorderThickerEmpty.png | Bin 0 -> 122 bytes .../Imgs/squareBorderThickerEmpty.png.meta | 47 + .../Core/Editor/Imgs/squareCorners03.png | Bin 0 -> 133 bytes .../Core/Editor/Imgs/squareCorners03.png.meta | 47 + .../Core/Editor/Imgs/squareCornersEmpty02.png | Bin 0 -> 131 bytes .../Editor/Imgs/squareCornersEmpty02.png.meta | 47 + .../Core/Editor/Imgs/tileBars_empty.png | Bin 0 -> 236 bytes .../Core/Editor/Imgs/tileBars_empty.png.meta | 47 + .../Core/Editor/Imgs/tileBars_slanted.png | Bin 0 -> 285 bytes .../Editor/Imgs/tileBars_slanted.png.meta | 47 + .../Editor/Imgs/tileBars_slanted_alpha.png | Bin 0 -> 266 bytes .../Imgs/tileBars_slanted_alpha.png.meta | 47 + .../Core/Editor/Imgs/tileCheckerboard.png | Bin 0 -> 397 bytes .../Editor/Imgs/tileCheckerboard.png.meta | 92 + .../Core/Editor/Imgs/transparentSquare.png | Bin 0 -> 97 bytes .../Editor/Imgs/transparentSquare.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/whiteDot.png | Bin 0 -> 148 bytes .../Core/Editor/Imgs/whiteDot.png.meta | 47 + .../Core/Editor/Imgs/whiteDot_darkBorder.png | Bin 0 -> 219 bytes .../Editor/Imgs/whiteDot_darkBorder.png.meta | 47 + .../Editor/Imgs/whiteDot_whiteBorderAlpha.png | Bin 0 -> 176 bytes .../Imgs/whiteDot_whiteBorderAlpha.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/whiteSquare.png | Bin 0 -> 103 bytes .../Core/Editor/Imgs/whiteSquare.png.meta | 47 + .../Core/Editor/Imgs/whiteSquareAlpha10.png | Bin 0 -> 107 bytes .../Editor/Imgs/whiteSquareAlpha10.png.meta | 47 + .../Core/Editor/Imgs/whiteSquareAlpha15.png | Bin 0 -> 109 bytes .../Editor/Imgs/whiteSquareAlpha15.png.meta | 47 + .../Core/Editor/Imgs/whiteSquareAlpha25.png | Bin 0 -> 107 bytes .../Editor/Imgs/whiteSquareAlpha25.png.meta | 47 + .../Core/Editor/Imgs/whiteSquareAlpha50.png | Bin 0 -> 107 bytes .../Editor/Imgs/whiteSquareAlpha50.png.meta | 47 + .../Core/Editor/Imgs/whiteSquareAlpha80.png | Bin 0 -> 110 bytes .../Editor/Imgs/whiteSquareAlpha80.png.meta | 47 + .../Core/Editor/Imgs/whiteSquareCurved.png | Bin 0 -> 144 bytes .../Editor/Imgs/whiteSquareCurved.png.meta | 68 + .../Core/Editor/Imgs/whiteSquareCurved02.png | Bin 0 -> 190 bytes .../Editor/Imgs/whiteSquareCurved02.png.meta | 68 + .../Editor/Imgs/whiteSquare_fadeOut_bt.png | Bin 0 -> 131 bytes .../Imgs/whiteSquare_fadeOut_bt.png.meta | 47 + .../DemiLib/Core/Editor/Imgs/yellowSquare.png | Bin 0 -> 106 bytes .../Core/Editor/Imgs/yellowSquare.png.meta | 47 + Assets/Plugins/LubanLib.meta | 2 + Assets/Plugins/LubanLib/BeanBase.cs | 9 + Assets/Plugins/LubanLib/BeanBase.cs.meta | 11 + Assets/Plugins/LubanLib/ByteBuf.cs | 1568 +++++++++ Assets/Plugins/LubanLib/ByteBuf.cs.meta | 11 + Assets/Plugins/LubanLib/ITypeId.cs | 7 + Assets/Plugins/LubanLib/ITypeId.cs.meta | 11 + Assets/Plugins/LubanLib/LubanLib.asmdef | 14 + Assets/Plugins/LubanLib/LubanLib.asmdef.meta | 7 + Assets/Plugins/LubanLib/SimpleJSON.meta | 8 + .../Plugins/LubanLib/SimpleJSON/Changelog.txt | 111 + .../LubanLib/SimpleJSON/Changelog.txt.meta | 7 + Assets/Plugins/LubanLib/SimpleJSON/LICENSE | 21 + .../Plugins/LubanLib/SimpleJSON/LICENSE.meta | 7 + Assets/Plugins/LubanLib/SimpleJSON/README | 0 .../Plugins/LubanLib/SimpleJSON/README.meta | 7 + .../Plugins/LubanLib/SimpleJSON/SimpleJSON.cs | 1434 ++++++++ .../LubanLib/SimpleJSON/SimpleJSON.cs.meta | 11 + .../LubanLib/SimpleJSON/SimpleJSONBinary.cs | 301 ++ .../SimpleJSON/SimpleJSONBinary.cs.meta | 11 + .../SimpleJSON/SimpleJSONDotNetTypes.cs | 516 +++ .../SimpleJSON/SimpleJSONDotNetTypes.cs.meta | 11 + .../LubanLib/SimpleJSON/SimpleJSONUnity.cs | 462 +++ .../SimpleJSON/SimpleJSONUnity.cs.meta | 11 + Assets/Plugins/LubanLib/StringUtil.cs | 52 + Assets/Plugins/LubanLib/StringUtil.cs.meta | 11 + Assets/Plugins/SignalR.meta | 8 + ...ft.AspNetCore.Connections.Abstractions.dll | Bin 0 -> 42144 bytes ...pNetCore.Connections.Abstractions.dll.meta | 33 + ...oft.AspNetCore.Http.Connections.Client.dll | Bin 0 -> 122120 bytes ...spNetCore.Http.Connections.Client.dll.meta | 33 + ...oft.AspNetCore.Http.Connections.Common.dll | Bin 0 -> 31496 bytes ...spNetCore.Http.Connections.Common.dll.meta | 33 + ...crosoft.AspNetCore.SignalR.Client.Core.dll | Bin 0 -> 200464 bytes ...ft.AspNetCore.SignalR.Client.Core.dll.meta | 33 + .../Microsoft.AspNetCore.SignalR.Client.dll | Bin 0 -> 24336 bytes ...crosoft.AspNetCore.SignalR.Client.dll.meta | 33 + .../Microsoft.AspNetCore.SignalR.Common.dll | Bin 0 -> 44720 bytes ...crosoft.AspNetCore.SignalR.Common.dll.meta | 33 + ...soft.AspNetCore.SignalR.Protocols.Json.dll | Bin 0 -> 39584 bytes ...AspNetCore.SignalR.Protocols.Json.dll.meta | 33 + .../SignalR/Microsoft.Bcl.AsyncInterfaces.dll | Bin 0 -> 26904 bytes .../Microsoft.Bcl.AsyncInterfaces.dll.meta | 33 + .../SignalR/Microsoft.Bcl.TimeProvider.dll | Bin 0 -> 32520 bytes .../Microsoft.Bcl.TimeProvider.dll.meta | 33 + ...sions.DependencyInjection.Abstractions.dll | Bin 0 -> 64160 bytes ....DependencyInjection.Abstractions.dll.meta | 33 + ...crosoft.Extensions.DependencyInjection.dll | Bin 0 -> 96928 bytes ...ft.Extensions.DependencyInjection.dll.meta | 33 + .../SignalR/Microsoft.Extensions.Features.dll | Bin 0 -> 29872 bytes .../Microsoft.Extensions.Features.dll.meta | 33 + ...rosoft.Extensions.Logging.Abstractions.dll | Bin 0 -> 67848 bytes ...t.Extensions.Logging.Abstractions.dll.meta | 33 + .../SignalR/Microsoft.Extensions.Logging.dll | Bin 0 -> 54032 bytes .../Microsoft.Extensions.Logging.dll.meta | 33 + .../SignalR/Microsoft.Extensions.Options.dll | Bin 0 -> 68768 bytes .../Microsoft.Extensions.Options.dll.meta | 33 + .../Microsoft.Extensions.Primitives.dll | Bin 0 -> 49936 bytes .../Microsoft.Extensions.Primitives.dll.meta | 33 + Assets/Plugins/SignalR/System.Buffers.dll | Bin 0 -> 20856 bytes .../Plugins/SignalR/System.Buffers.dll.meta | 33 + .../System.Diagnostics.DiagnosticSource.dll | Bin 0 -> 189088 bytes ...stem.Diagnostics.DiagnosticSource.dll.meta | 33 + .../Plugins/SignalR/System.IO.Pipelines.dll | Bin 0 -> 84744 bytes .../SignalR/System.IO.Pipelines.dll.meta | 33 + Assets/Plugins/SignalR/System.Memory.dll | Bin 0 -> 142240 bytes Assets/Plugins/SignalR/System.Memory.dll.meta | 33 + ...System.Runtime.CompilerServices.Unsafe.dll | Bin 0 -> 18024 bytes ...m.Runtime.CompilerServices.Unsafe.dll.meta | 33 + .../SignalR/System.Text.Encodings.Web.dll | Bin 0 -> 79024 bytes .../System.Text.Encodings.Web.dll.meta | 33 + Assets/Plugins/SignalR/System.Text.Json.dll | Bin 0 -> 643864 bytes .../Plugins/SignalR/System.Text.Json.dll.meta | 33 + .../SignalR/System.Threading.Channels.dll | Bin 0 -> 74000 bytes .../System.Threading.Channels.dll.meta | 33 + .../System.Threading.Tasks.Extensions.dll | Bin 0 -> 25984 bytes ...System.Threading.Tasks.Extensions.dll.meta | 33 + Assets/Plugins/SignalR/link.xml | 28 + Assets/Plugins/SignalR/link.xml.meta | 7 + BACKUP_MANIFEST.md | 3 +- DEPENDENCY_REPORT.md | 21 +- Packages/tysdk/Runtime/TYSdkFacade.cs | 2 + 959 files changed, 58811 insertions(+), 9 deletions(-) create mode 100644 Assets/ABPackage/pkgDownloads/HexBuilding.meta create mode 100644 Assets/ABPackage/pkgFirstPackage/Fonts.meta create mode 100644 Assets/AssetsPackage/art/terrainbuilding/test01.meta create mode 100644 Assets/CoreLib.meta create mode 100644 Assets/CoreLib/DebugLib.meta create mode 100644 Assets/CoreLib/DebugLib/asap.core.dll create mode 100644 Assets/CoreLib/DebugLib/asap.core.dll.meta create mode 100644 Assets/CoreLib/Plugins.meta create mode 100644 Assets/CoreLib/Plugins/LitJSON.dll create mode 100644 Assets/CoreLib/Plugins/LitJSON.dll.meta create mode 100644 Assets/CoreLib/ReleaseLib.meta create mode 100644 Assets/CoreLib/ReleaseLib/asap.core.dll create mode 100644 Assets/CoreLib/ReleaseLib/asap.core.dll.meta create mode 100644 Assets/Plugins.meta create mode 100644 Assets/Plugins/CodeStage.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Integration.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader.meta create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt create mode 100644 Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt.meta create mode 100644 Assets/Plugins/Demigiant.meta create mode 100644 Assets/Plugins/Demigiant/DOTween.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/DOTween.XML create mode 100644 Assets/Plugins/Demigiant/DOTween/DOTween.XML.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/DOTween.dll create mode 100644 Assets/Plugins/Demigiant/DOTween/DOTween.dll.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg create mode 100644 Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs create mode 100644 Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTween/readme.txt create mode 100644 Assets/Plugins/Demigiant/DOTween/readme.txt.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll.meta create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/readme.txt create mode 100644 Assets/Plugins/Demigiant/DOTweenPro/readme.txt.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png.meta create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png create mode 100644 Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png.meta create mode 100644 Assets/Plugins/LubanLib.meta create mode 100644 Assets/Plugins/LubanLib/BeanBase.cs create mode 100644 Assets/Plugins/LubanLib/BeanBase.cs.meta create mode 100644 Assets/Plugins/LubanLib/ByteBuf.cs create mode 100644 Assets/Plugins/LubanLib/ByteBuf.cs.meta create mode 100644 Assets/Plugins/LubanLib/ITypeId.cs create mode 100644 Assets/Plugins/LubanLib/ITypeId.cs.meta create mode 100644 Assets/Plugins/LubanLib/LubanLib.asmdef create mode 100644 Assets/Plugins/LubanLib/LubanLib.asmdef.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/LICENSE create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/LICENSE.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/README create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/README.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs.meta create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs create mode 100644 Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs.meta create mode 100644 Assets/Plugins/LubanLib/StringUtil.cs create mode 100644 Assets/Plugins/LubanLib/StringUtil.cs.meta create mode 100644 Assets/Plugins/SignalR.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll.meta create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll create mode 100644 Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Buffers.dll create mode 100644 Assets/Plugins/SignalR/System.Buffers.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll create mode 100644 Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll.meta create mode 100644 Assets/Plugins/SignalR/System.IO.Pipelines.dll create mode 100644 Assets/Plugins/SignalR/System.IO.Pipelines.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Memory.dll create mode 100644 Assets/Plugins/SignalR/System.Memory.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll create mode 100644 Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Text.Encodings.Web.dll create mode 100644 Assets/Plugins/SignalR/System.Text.Encodings.Web.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Text.Json.dll create mode 100644 Assets/Plugins/SignalR/System.Text.Json.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Threading.Channels.dll create mode 100644 Assets/Plugins/SignalR/System.Threading.Channels.dll.meta create mode 100644 Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll create mode 100644 Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll.meta create mode 100644 Assets/Plugins/SignalR/link.xml create mode 100644 Assets/Plugins/SignalR/link.xml.meta diff --git a/.gitignore b/.gitignore index d46fc89..d0d829a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ Obj/ Logs/ UserSettings/ .vs/ +.idea/ *.csproj *.sln *.user diff --git a/Assets/ABPackage/pkgDownloads/HexBuilding.meta b/Assets/ABPackage/pkgDownloads/HexBuilding.meta new file mode 100644 index 0000000..3bf9030 --- /dev/null +++ b/Assets/ABPackage/pkgDownloads/HexBuilding.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 316f4406db119b84ea347a6ed2430678 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ABPackage/pkgFirstPackage/Fonts.meta b/Assets/ABPackage/pkgFirstPackage/Fonts.meta new file mode 100644 index 0000000..d1a3cf0 --- /dev/null +++ b/Assets/ABPackage/pkgFirstPackage/Fonts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50f3702f55cd42144863f5ffeaf8de61 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AssetsPackage/art/terrainbuilding/test01.meta b/Assets/AssetsPackage/art/terrainbuilding/test01.meta new file mode 100644 index 0000000..71af338 --- /dev/null +++ b/Assets/AssetsPackage/art/terrainbuilding/test01.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e324649d839d02c488dee086fc7ee2cb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib.meta b/Assets/CoreLib.meta new file mode 100644 index 0000000..86d409d --- /dev/null +++ b/Assets/CoreLib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 374495418f507124e80cfe5137776bf6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib/DebugLib.meta b/Assets/CoreLib/DebugLib.meta new file mode 100644 index 0000000..5f038a7 --- /dev/null +++ b/Assets/CoreLib/DebugLib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0579fd5f5ba2e146908c139c7324d32 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib/DebugLib/asap.core.dll b/Assets/CoreLib/DebugLib/asap.core.dll new file mode 100644 index 0000000000000000000000000000000000000000..1ac63655545b71d5621e58438e3b6581f9376120 GIT binary patch literal 117760 zcmd44d4OD1ng4z2R`spws_rD!OLfv&It%Gsy1ElcSemdUK|m2fWDAJwpajX)t^_cZ z3Q=4D0l|$iq9Q0Rql^nGZn)vbh@#>S(Q#Zx$88)(9mi>YpYL;SRo&_|%I|&uc;7(Z zvpwh8&NmR(RAajs|?gh%mRK7Q%Uc&dxwm(7gN`}pO}_+7On)UDlOu(pE8-D0V>pL}9s ztp9+lt3!t}EZ5$gabYnG8gCOnVQnQ)jl1xNb;S(DqeM6#2&coh09{)}R2;SA?{rR9~Fy75<3tdWof9$bX37D>;IrKohgRn zJ#LC>^n%*aKnji@y5M$w$$VjN)ph%}^(=4=2$x|&@BtT{K<4P_ z`d}PG^tY~s4>BD9KkxuZ($4gV#f|N9L%Y8SxnSxUC^DG3gl}|W3+vb>SMljtPsZ~@ z**F?%!VlznTmbg3fwQN&vc*Slcard^C3v83n_pJLmnqfEQLb&-inOkW0V-9OwJ@26 zg6J`e7QlDRr^X{2C|tBE>IGb^p@P9uh3fS=B+G{N&*MbMhqdZ*1Kwn{^3DG{`A*s= zU*Il--U7=vVD+#x^&(Y6y6EDLAbute^%EZEOvUq^)A>WY?({kd|E zdJsfEvIP0QXFk;e=N3|@R^bjC-3Tw0D6CO6ilx2%SmuH0ESU3Qd@50HdKlegY)nyb zRN{W}Wfsye(Mh?59tW0RIAVqj;3$R4jQJ?KN0Yn(Jqvl&RT_ONzgwidwbPX)h=idB zL+HqPhH|<>d?xP7BHZ+LPyF2NEx}Wvi8kI$Vt=mc$~nm-{sK40jZAnNYB$pD;{Uh0 z{l*jN_J=LqemA9C)gjesdfRqAq`GEv(Ki7rrRp>)_6d6}!TY~ue$_@_r?KPGGxc#m z{h;sAEG>()&9rPK8gD0xhYLts+Ty{ttE@FE3`4u7Bs@fFRwPhUvXPnt4F16y35GJ<#^H+HuLHga)Ng5k*o;1}2gvmxrWP-Fy(y?a{OK zcTv7wV~4n@uZfA;*^u60_M4jNmW$r598J=`TuK}w)8>p#O8O%=>W42oWO(+yG z=%x-+8qwA0>moxt?)G@vW01ArUt##WTKE^bsaKNIZ}IWMC*)(Wl^>z^;iIXGH|(1~(Z$pU z(>(kw93OuYI6C{=!0q4UY3e)VHoZsZqkM{~+a<*yyGbuhqiwcF-%pRKOy*lZOKD0@*s>HfPDR&hq4Z0{~9^QxEo`G1t?`#xyVyY1eq4XNo*ks}rV^CM9gxnF)6X zld-3u+R)p5EbWFakW%Nbk3YI;nMkbM)ZDCex^!xRx$~!1m^*K3e{%~{Ys>{%VsJhE zzonN$_GS6+>XPx*ujkhQ|h%d(}hVk=p)N&TOun=ECfY!4WCmYdmh0R7l6F_SdKcG$-53j+UNO*{W zo+xCk1ywUcbXoKfba%CZqNh^I8N?5g%UwoCZ7P0&QL;9gFXzWgjyO>-Ru4#g z*@#|@>9v=&zfdlydG^uI4Q*CqEx=lLxqIRr%^sF^@Io+nxv?FNaR741d5X3e-iWhs zAQI11jBer!ir4Vj&!@BQz2sTr^O%mZH(yrD-$d__>8bQq5bSCfmUCVP7%&<7!wSaX zD3>kg_w*MEd_9fvQaLOa%m`61VsyOEkxVv;d1v>~=HBW6Mg?I|0HhG7ST0U{s5_4_ zDwRu;c9>Bc0F;0)FJOAgJ?pnW{`ljCekLpBUSBR*$Kb;qAl|`L3~yp+m7#Dez10`E zpxd(y7SD25r9Z452Fu}|{(PQqi{-9zzQwW>-b;x>dCO3!mE<$tWe%u;-d z+W{x3x&te8SVf457w7v?aJi>hf0#4Cq{_vYtFN+^XtUKhKeu2^=ngcP>~u&^?4^H6)qJlBn^Q$h19Yb6vNI9vlTN$o%pbb>Dg0e?a&x-W@=`#ZI2gTd z=}11KQu{MwHfF@Xz+|q>Hhw89drzhIGavhikNuXMT;tnvx*Fe+Gbh*hF76l@e&u0* zsOW6tM@j7Oee6$s>`#-}X&?I=ANyOyTDz6rvC-(gP8V7X>R0luUDZ;i~g}b~YF$v>KODA0rG+7{n}^6{DR((`VM!H5vq%Jnq6VQqutq zbJ)hY*9dsGJ}>4Izl2X>&z=rmthv=6wPos0zneN3yX*(54@1mVtCbRMC&*jH?@^+G`Lc}Sw)#Ieb4Ks0^S+*5*v}^vAPy$zB?1fCIT<@>{)%(SkmxhTlJfvd$tn4 z%z%RE<+$-H6bPd0HFdtOl)`7EO-l}h0Jh2Be3-)Ki!hsxA27xY%o3@l`N&t-e7$5WNW@5q{D$g0S-ow69qveV;5rm5np zw>meN`Zg4@w$fy!CjI5yv4L~zjkh+Pc~jp9bn1`d=oE4%3oNx;@fRzlaAZyVYP_SB z9i#ERQ9y+Vn75c-;cV$$BVfX6cfS%vWwt7y> z?+a9Yhh6Gfx$$wDveDtAS_DZZXb*>1E^`eWW3OVdc~NMHZ}XPl{(&u9}qvZ+2<-3&!Xlgh4I~uh7R=Fq39i zs84?FG#FXFdSx(j#OkHN$Wf~o1|vIHSAvnHYsoC_QOOTzDi|DZ!80RWmrgNB(($p7}_f6p2(WN+R z$B(q)a@qLJq?x{=w}`5b=rSARV{%=a_kn_eIi3$@C%K@jb_aPI^V&Qe4^Q+n*prA3 z19P)ei4k^G6InQ090YZVV)TQ$u$|S$l7M59lMMv*1;gNE(AdUVH{w38sqx$vIgc^B zxgikKQ-+Mnto)wxU10axmmc>`f7^_7+Of~?*Y(Xdy`8wDJWq5T$eD=iDUixAMl9I$ z2j%yB+CH)p-wnWMN;g>4gJ92e>oq17Z0_~&U0XI&waw19RfmKUSSoml!&@Bpx)K@f$rnqBY~Qj&Y)wH8(v-h9Dcn?-6UNL1zv7#w_D= zVlIf80~Q;i*7S=)M}}NoQCp{T>Y>S1!D3ice2?;qvR_)XdM{o#d7fxuo~KQ)&`>Cd zu;*cGZz~16ume`1Cx%_r0jtm~u*Y~F7B^vK+g=QBPqFw)V}Y{m6jNqLs1$RlW{O?1 z`Rhrl*sxS8$-b!~Y^msF-&7Hf{s{#!j%ub3Czw^<3t7j#0ryzrr}jP|=>r$I0_|>& zHm~=fDO+J+y1(~g#}Hn|wJ*^4hBjF4n)oI=ANlcoKH2%uK$OB@Ai7hGPY+@w7ZQ++ zt$>(r1;pd@AT@bmb4h`*9=Wt9v+nTrp3Jhqx#Ps=oGwpdPFIQqfi?*OZ4w09B<8w^ zu}(;zPu&;am7YnR%NQs+l3qnp?fnQ?3{4lk#Lwv>;bs!7I9QL!+HfjgRuT2*Y^`#< z8S2uAsTG=&^Mj>w4xP)!&FQkTHR3jGg8XAohkVv1^L=x=y5kQ(zIF#6tE)DhAD@vR z#dc|AG&4a$LsX+7%kn|tx>vZQ0jNtw{c|f@`sek{jXp#|dERsm?_2SnX9J|t)Q{Db z(ouvv$RJWroI%5+($sKQDuY;f;tU!rm8MQgXAo!o1C{>4zJch&;%E?#2CUMa*RN4j zY3jNb{7}!{k?!$)cT(AG>!QC>uC#Uo-J`bOy73^@ALpLW-)qsY0*t2YpW@HtkD~*w zL;$m6|70Iez(*MSJUuu>t|0yhEG>QJ(?gbrytS0^i7-t{Xe@i zILR@-q5o_Oob~-XRwZBQoqRFriTPIhPg(Mj%9hP6I#IbX%e~cS`y^t0H_2>PLXbmF zX?7gp*3J2?!lKOpVHxyrVSaNH&5)lwEj*yhJ%uuRYEnkj=XM!o0^hK-E>@`YmnIhi zi55Sq(mB{mZ+Ny1AcK zKt=AGG*sI~i|+4X1m3`i=E^kXvVDcosdK-j|L6NwFH_w>FMQV3{ku$n*T2j9-f9?9!<=ZN~Mvevi%d?n;uCM`UtEe#_E&tO~{u5LFXL!Gr{YfeR$@r7T zk_|#%1)fRVkY6bmZ#mm@g-Dqp4Q7ZTW0vy>8Xxx*up;WHYo8#rBVX8D3JYi1KDmvq zCmyl&t=A(PjFnx5{3Ar94|6 zzVmZK{W(`<3w#I~OlH^80m6XR+_iQ05DVxNVRsTkmpE~!rCWCxIu_=u^IQTzFYE7}-$b&*Z4&XVXMj*kWqfGM$x? zn)saQ;Yw&w5VCg~jMp^L16rd|egQgUS@A zK}i&dK!w$;(CYa<|KRGmJ~gpTECs3>9M+XVq#zubx8Gz=#{f9ljyJ-$ zMns5CiY*9D9TGN2CgoCH zePJ4-mV;P*NrOzx0MRm0Y3lW95Mcosbv03xmX10Um5@5U3y%<<&hgk2{kWN#u7*sU z=4<10dzbe2xv9@Wq}*4dHikR;SzEVozYmW&jc4>v3gvu;`z3!2k=>y_sulm2B%UJA zXgqTOFqAO+(x<_R-*BRiSKQRMCDf;=cu_ZNS-X|&fovOjidp|w5=V}VKds8?L(ymC z*M9tG&2wdP((xXccG2gEiyz<<(FHNR8s3HExv?d|ZgYososk3+SEtpAAj>w)vm~g0 zp&4Nw+2Z}-A0t=}>R%*{ef@kk`VzivS=vfZuv4*xd_+rPuQ9*whZKw1@Y(V`_$2Z% zu291(ySbSl`e!oS*bkxUioWqz2&2598U;QvdWaazLiAO0gXn9xJ}G`!QDbK_sTYqc zC$gheCROp*ExNUuj?mvA#!F=5t%oPd*P(}Rf&2;e zpv36ge58l(m>Wdj#SJ1Q#otqu=|Qyi)q}4|vU|^=?w+Euj*e9x$AaAV@lZd0AgA^y z-^OEnvhln5jvNy2#VJm4IQ0e55Am||I{AAFke&5C@sEhe$N$2&w;N0Cmru1g-!+K> z`1kM-Wg20Cirtkx(ZAxpT`}})d-J32F&ZLeCvxRnUswDSJoG>|y<6sLKP9-boNN3H zx4)|i$1d~FiQstn&>k5xb$3%av3C*C6H5rqYlW5*8g7L~tA~`k;5!?YsLR^6ELQhR z$NW+;eMwA@VE$b($$^2exskp8aaMjun|@oE}u;8T0k{xzKr* zNO_g9X2k>}sGi}2**<5AW*jr0L#-0o`s|=uU=y98V~bp_FJq848kz6%bt%k-9)b-M z*s=8(uKyqQ$j*bfuruvP)J^vsSWh`Y1#AB4#76&??s z)xz^|zFCv9LG)h$Y*)nF^=Te}u(gIEHx*Iffz?ghAgcWl=pCuE5U9zY!^z%EZNu20 zQ(Ma`RR?yRkNxzaZ1g8GCI^0G=PA3S{45V+3QST6qr~ex?R;GSk5-Bu3!^`qAbYz; zo!jed9IURS+~>OBoAa|-?OW@P4QF8g8(4pgE6H7&dI^H$!{{%h^ti$dY#^{Yw#=2r zoA_qq;eY-P53}Vt>+j^r=uE9Y!4up2v)<40#?`*Ybf2cb~6b>bM~K ztHC2M7L48u!+e2K)L)rrvBY6{eQ{3a$@diP@9&o*ieMuNFBvaTF}O! zmym}xsP^zUAhsDu!865REnG1@)#HPRf+;?{il%1fYADVSj(V{H+ZD-K9UVdD0cng>*-U7f>4u2vve%$uPf23Jfk z#?ap*4&!c8QM?R`M-awEMTIfl8`EeGA6<%ygiqU|O_s`qW>)wJw~e51&PSBU$sQ;> zpv^i&UiWM-o1Lo>qEbF38*8#NWEcJ3=X(Z|k?0v}XyI;g zSHoV1yT#JjrA*%ITk$1>#$`y~P&l3PAjP$qR+@D*#JIBI-@46=7`-2|;ZE ztTtj{ksiA2Sk1YTVa#OcYM|U4(>m_=REeq0C0B$n;n-2cc16^;(1*RZxj> zq>SSqL92FYbFCJ2q%SYI~YESquG`ziy7Ld?D z#9W~e593EA2ZE-y5Pt+$RaNNX&`nqg=oi=6fMGvTfA8T`W$oS30cXOw;p zf+w1OxwZ^Wid2y0xUBC&zp$!9V@meKT@lUbv(gL-c8wMt)<#M4(`vJWvNa5yEn7C`ri!08EJW|S zpu5HB)P-jjG;MP#G#*LJ9axSfEXRQFkB{bNxoK)p_kJ%N$JnAVASS-GcP<-=m2s6I z{R$VgQbN$CHFgWAwQDY7+m3&$YgMxCmY^D`)#R%8GS8OgNG)g=TQpxvwDAPvFL$}g zG%^s6gJu_LG&1f?ViLGBdAJ(;1PLp5DSBu%KiOMK?TWSZv)(N|+i!cdMrx~T2Z3a_$d7GpR*;}}Fp-VzM541Rl?GwiD%l0! zK6QQ-n|la=RN6j@&?0j2p~N68>$%OCNsBSvV)`7$9=UxYHlN!~{(7iy8oH^-IF(L< z@`|V^I$~_JkH)1}m?bX*yY1Ie31~AYuG3$xrs~>6R63uCXlVLx8 znq{b+fYT7op!Rfmg&?S%hNC2q{AY^Gb|VU^hwA>!O5LB?(;o(0+sMV6fnjy&ESyA*&1*6K+M0H{ zzS^tNHZXP+1%R|9bX{Slg~G}4|T$6_AEF>#}^vhQw;95PB@*95uBpqiwtg& z!F{+BPWNC0r|9@%gZo1u{yx$Pr&+e(6dhk;a9=SvYqu(NFNY2V2u{&n8Ix}_xcfTs z=?akG6dhk`_;woHM?2x{^bK%|j-P9Ary1OPI^par4seQ&pJ#B)^N>Rwm{m&8pLV0x z>Uv+MU%O644xF2|t3xh3eRDA zDn7o#Lo%?UMQkOYGtQPC#e{qnag%?hfphgs={oLns>^MsPt5cWb;U1KeTv%Q>@dG#c2GHlW)5B%@7nK)b z+xi!m7mx3N^ucG|n@ndL?CcJZ(zTVCRM@cAoy`bR4L z%eeCgJB!N8;w#0@NYjKYgP&#PW#uLCv%I`~;(N?Lfn=$Gp$82UgQ9W3E3qf^Xf1m( z9;&u5X^=e|C{12LdfWW9P0e}xni|Z>Q#ls>UZm*9N?(oe<=otCd=-3Y6rs)EQ2?%% zG_>sKMR?|ArpT?DNWuwo5@jA1#BnCZUXZ;;5wp_CaBj)hSILGn>It zLj?>wQoK<{r!?v9(hPf}b_!TSM3q#U{4Z}Z`<@o}8vA~ps z{02sqN*k92@e)RkAz zvR9N>l$X)6_bcx=@%{2hY4Y=GGcq++50W;svb^%Jn@C7ooc+uDGa5}>oL#iP)Cg;! zRIOW&F;*T+vuSp0v}Jo%C5%Ru{wnwL%A?|Rm2n!s3_eF)xeBAza=^cpo!*yMDiSq>-dyR(-4rP}Z(BubtCuzaWBpY%t;;}JK zATTpEg`Bq#+1%e6s@Vd4u8X-%t~p%OCE!s;Xu1SkE_6w*f*+k}92vh{h0wa}>xXDq zq=|<>!W?Z=Fybcz$vk+ByB667qUbWpPB~q=Etwm;o1;i|#ruH`0j0JAg7JZ|Jzy|{ z z%RVLq>ogLA0r?yKf zd$FhX5>M?~IozXtDK1?XxN`PB0;Gh?fa?ZZH_*BOYp-lc+=PcI!QV(iP`}B(H{17B zd^L$mR_U7XApRTpZy}S{XcIocf2-kqwS8Y>U&cWx{C5VG2Ga{R171fwU0o0{nF<>( zS6mP=aS9u+kf_qxk;sc^;zQ|vG|!^P>&eRapL=4Q0lCfaFtD5Y0`1wuME@Y7Z{U;M z)$seTC`h=3Upqg0JR0tyW#c#E@8M#;N0Q2~1JIHYl{r+)9PoBPi{Zn^G;PkVh0VpQ zVLa2}(OSHE6F@6>D0Ye60n)q!WHq z8(t|*cqY`|X6_p4gg>SYuaqV{6W|1XX(v17+scm?rG~wH2 z!#c2Exb$WJv^Km_n(*ziVR1MOe?l8xDNXox*{te>e|j5UDNXox*|6l7#(!cPUMUHD zTX%sy9#U?%v21*&RH%KR;*kDl{g(lcU;i}^5v&vW2=fqeLo>oWl!<>ck49UrJp&fl zi@Xc8jWKv&FS06Uu)*pzdy$G`p?c790@ec2+X1EhdmJ>@a_yNO$KArQ+T&n^AsiGv zI1~qtis4WodS?^IGHeKZ)9#0&i?A+sw|gUoheg-ME8#oT!;0*y0wHa0XLwW`JT4%!wu(OsoSlQ9L-)!w56Zk% z5xB3G+tMYhmTQ-%^l*u%ajB=>>9>*zH(0HnxY=f>$sE(DhQ%Rs&WT+H~{!ztZG6~ns z!o{Ofsvma?7jsnMVh$=?%uj`DtDK!m0@q^0rGRIvh3i$qbzTbB$;uWqPLY#su%ahi zC&}5VBycS;Tnfy<#j0Dmc3}z^3wgrDcucrhffFwJDsU+YTqA}{ffTOekde|X*Dgun zV!2DW&XJRCoGmBUc($Cu1}kEq6a*-j8cGEclqRciQZvf6=cRC-r+h)`MsQ!E$yg31rI+nF2G) z^|ivqWT{oI8=5xER{N zU90BNeqpyf1!W&)@7@4UwH>~E&E7FTQ~AD3&S2wOIXe|c!D3gd-nM3Sf7R`2%cC<3?}z?q zGW}__0}T;qmIff=~oBwVjf)$7kIThREToNVI@at0d@$l0kRaG@^vQXpj) z)ZX4KT-#E7ZCAFSag`jl4do0rw#nJ4Bygc>a4C@DOZI@uQLbH|!gYtT1r7RK;bM>@ zdqBr7ly8xpNna%1?-0GKQhK~Q2hhF^+@Qy7frTgqs}$? zQhXETJ@`F+$)-?RHY%`WTHl$s&B9PaxDZAegF3662{H+zP+AzD+7d=N+nBNqCAWpS zvwiyDb4V#8gtqj}##kSAR&%mXMLlngxzh92UsBM{GuPpl>c;%(%f#u4j|Xu})wNWl zf5yjFzCA}%v6HcShh>z$FnPy?hxaa_B_ttoe1#knpZ7cYC$zhiFn)-H(WwK->K|OO zKC=1BP;(#h=#%{ZzS_*Y;fs0?UtcAw4w_*l;A?w6#%jP;AqJ#4wH1^j2gP3}uD5$2 z`Ub8oZ*ffXgzkdvGpg6q0-09RiC)JEcxCPH3L~sUb$l*&0iuKPMc*Q~x=C%Bu{6Lf zgl`iACwYH52n7 zEQ$Rt*eILt$;mdpkJB#WD{KrWj zOU|PN+V^&dgFRF{_OQU5b7*z0s{a;O#)3i1pyv}fpZW<=7_yk5RuWc+==fiuM#CuO zC%%=$plR({>mZ~-pz>n6nN~Et63VgRs@P(9Y?g?CzZ`!d zf7Oux_Nz9GZNa$e5^j3@9G}0i0q=@7-Yq?-{~O^H?++(2Dc%iYChr`+u=rn)y&(d@ z{7%#+oD!PCtqtl5+AWl^)ioM)xcf5_zSW1x_RAJ({Jcu-ZPyn`pUB&b^3^W?#JrXS zNS8jCMR?n2aFm@k*dpp1x~S?{T=aYJT#%1urhD0LZ-9 z2oHZHPXqoE<&K=gdt(1C&zksGIJ>_j1#6#iVaB+xz(+@*_vOmej_|Z%kQUbru}3hC|K&c z-b;lhqdwI_Uox#1$?b;#qCY^=^Qk%6;pCzB?#QF9ndU3zKF@!VhttoDreUFXZ;5S{ z=KK0w%vK+v7spGhU1^wc*4oNV*Wv6|h45`A>%I#FT|9Jle}!m!Ilox@qwogNpKzvb zK>5~%azj~aVH>*N6%4u%=4FJ{9C>$G`CAcT{AXY%7FeNby7=G1b)RsZPi>%P*#wbC zraYAgn^aT*jE;4!{XAi7r06%BwA|EQfQ_8->Z|5;*cZXF}z z`(`b3K?l+Q0IfIExs6&$o+|3C9=%KX!@HQ+1*L3W){vnMQTVZQIo*GiA2XY4JRrYu z0z3h4%Z6wr_jXE&495#8%e!=+K1q`pB>aZ_xm>hH1tf0pIoY$T=0MVnk`&o*H|-2 z@+p_~=QuA{&e>B8rRr+e&A~Z%Wh7EmnM#2=*AdnNl(B=fZoMa+D|eq|N17`j)yu_S zm4sl^pHFN&pt$)FDI`GJ6 zJmcAXbrgN|R5$x7o!jHHwBIGw5j=x9r1gGvLVV4Hn# zVYk)Vn$LMmF2hFA>(=R~ayUoe`0A%Rmgf}NpGkL74ss+vh2*#kzbchIu4>)6)vftL zqx@9vFCN38EsRZEzAqoK02j)Htp6%^yvt$1Ybkjm3!MJZF1L4H{{Uy0MP$Ig zAHm~VRZh&62jimnsf6Wvr}cKpr`hHB%963E_gbF30N7JOQ7SZHc8m%mXw2lH1FApaC! z;BP%1c7QG)W%F%`UUti&Nbb{)uWT$agbg59NqPc)?Zpf=g*qgEcL9r&W9xloLHQ*Q$ z_`cbXr!sEYa=kY1GO20YH-NKAr|jEH(GjQ2m~$#RHRsG%^OFSM;f~`mcZ+QZN}6 zV|lzPg8H|KFr7E=;qN`7Cn)GifSj9pGnx+S^0zgggr7+Lp2T#>#4@bSL+Lfh6&v3K z2eVWOZ?jZ+V25GoY}6lB>eL^Ny8LPC7JdTin#)VV%2;NR6!UIZ`LsJ?m@>mAWhzHy z%+Ksx>@+8^&0wlnA5*f;M^&!O>ymO+e5zcvmT-s_suB?AM>xC62yO4QuTV8pl>G!_ zV=q2bAW&0*{ugcSXh%oa?^ z{9`32G6(is3BE2XepZ>40QWz|nIW^HYD-n@bjOlepeD2Bk<33Krc-8KQ7!0+4rIQ? zWR~A#_M`odRz6ck-o$qqWE8!Wj22AE_;V$<%9Xj9ezTSKs`wc)PFT4r!BzK%;a}n_ z1^J<~?B@xnXa7b7q6xx8Gf)r5@TjLS@u1}V1<9Rq9?=_g>p2kQ{JzO4f4Xcf{P)ZD zELVwJWh-VN%KtY?(AUw8Zr&-bS$?9DlEZ?nUPEh0d3e82eMZnc9~LuidIByx^WH-+%GF~1uHn>a@Y=jV)uPq%fLm+D zPtDQ?n$8}FMb_x3j@IFcp&tI|#pqb4y_rgVGHDSiR$PwgQxIuW0r@9w&soKyEHay=9ie7hCvQCrsNGh|58 z;y*&ywt%?o>bHQ7u`M7;LYoVq7xV`H*1m>PlpLNKR@ONIAh}yFjyZ z{pU`uha!rS@#Q4D$CzR&j}2j1|2d3?)l`vbWuT(V;KduyK=HbnX%E-N6{04N4Tji) zGPcWIjcl6lF8Dse_h#b)-@+`=4UxfEmgR)|w4A^*4@EsOz>bsh`ro{vNn$5FU@qo;(bk#L+0r>c zpGsc{o=+%0*SZ!frAaUroL}S?Nvh-;CU(W>Qe!(Qn#3Mk&O9fV4 z5XSRps-^t){gFIT=^QoQ(C-KRuw!KIxrmpM*S`Z4VEI-~`l0qoL2Wq+4QZyie@vg) zMUch#Y{NXC4I)~m_M!*R;N#84Oya0Yt?o{BIzo@1_H`QWa`sY4U=NRQqK46}e#f@U z?mheGFIt(&r#l9xYiohkI%XeOwDPx(unEkMo~?pzga&x`4QY9h;~lF16<*Q@ z_|AyuSy)X}#<(g-uHpGr@)ofvbka(<7c=~e5X^Z~ia0K)^V~`?Ud_jEQE}?OUI8!n z^6P`RL4AO4J8!%OP&amSsz?RSRROA4v0+(q4dr3Ci>Yq7dr1BkUngWAUQ6qW80vC` zmA6NVV<%*@(NXjpdbK31O^U(QwWE}ExFf6SFVNd3?z7T=Zu>DPWxO}{cDcnN#tJM< zqW!$9p-a{x;)BF&cIrlKcFbHHe`r5Ur6&iJa7#MjMX;14#D^-~?>{n1a-Z|`fG~P; zpCmo@HjthukO02NGVV_B*TW*QZiaoRH^+c1lw#;^lSl@_En8wuBeCPm-6= zE?>-A?i{viDJ#WESid=y@DFKay{etiIFrks`3VBKJx2cxxMRXSuyPmC(T> zXRun#ckuYycEY|qe$n%|BjHi*-{SH1wD3G3(xP}rI^l>^f_{st)#8p!CFpmnS_w4r zCaQgT{F3Lfp71F5N%P1pkYc=n4{f}I$Bn6k4jx&NYvt(R@tAf(Cy&Qd)?XHn*_cZh z#nEhhERH4-$KhVi(Vy9(OG$K?x1Y|tQKqZCFLo?AAMC)%oe9JFaoT4aWjZ#6@u>jc zDC6WY`mx>x;QZ$foZ_>W@$f8swxXL@y;QB}o)-HByJU5v%u@3dk*9Yq^uE$TPuvQ_ zzA`jp+tkvqX=1OSI^QVU(;}uZFy_oX)Im$K_2>F>vkBLZZ`139Z&LJ9x8Zx+Vt3p1 zt{Y`~T0h}xuoY4x*yUj9$$hecA>aQ3GwWi3PJ9*=a<(~=V528`9N zr{hj+v}vyZnf8v$;X<{)Arhd_qcyeLdr?qV5|dsz(}PIuk3K3Nb)O3-npsx~>B#~8 zFd4I-F3o-nv*BYe`y|2b9qf$HM<*+~xksOOS6}0X{hX&QnARKq5xH33MXm`5C2}3% zXExekVx1qW zPRtuxy8=_rMW>ihHl=IFN6+e%Y5UIEW%@QUJ!~=^2$e)89bD_9LCGB3{ROJ45b<8yt+|NwWoUiB(=^>(*H7s4C;ph zI8YgiPDR6w!w3XB^^Hy=9G}idb>R%$3BRNx#7NHagh_q~u1UU0l0Wt!ScAF}5nj&p zAhv9w9qd(3aBT+HXpm5038>guPXe6CiLvF?#^H*n>lk%qog z?)2dK9h&Qk&Na=MiZB&xo@|bMbiOi- zrPolj+Q`O_y#Y3xJ^39He8cMA(Qu!%y;GY-v5~mwWhiGfsLQWsYkbRUof`M`OPR4T zPmx0%+JI}P#u+M595iX*7km{8A zuVqZ&_Kw&wb0a^KlpRS6y0t_T+EyOj4QLpPd&!?IC^i)q!SEAMC9^^4dRc7TZ__~~4J)L-6P=6{(cAJkS zZf)!zwiTX0r1(^7MbBXPLhTRvtIoM* z32W`t%ldEVE|HbB)7fNA)=s@<2O6(dRcR{wc$5*>Tco@Dx|=c&w`A__B;DO2eMOse z_w1y*J7qR%*NEDM*n|FJUopA}4<>D4i(0Yq40vi4Y7uHrw?ci~>WC8gRgRrT()SlYhWRC55dh(?U}TiqNwPiT+Fc(1#WLreINvtx~5FN=+r~ zy*yDq24ptnmzo+7k<#8}{rp1ew69D9o;hn&<(|Z*E}AvDX+Tjy+J?T5_V*F~mJvUj zt@tqUkC?4E3F?UrolNy!ENfX~_oEO2VJn{{2U~eEuGz{HrT@KgP*;kz^b#sHFtv1L z%lnqz#~D?+SoUOs`ZI}c+(c#Tj-Fu%lHr+AG31@Yvvz!Qc-9)9?0&^;d?z*KQ%Xxd1CxBpmXeQ-+~hl*=ms4K@|~QPfn*iQM{ z@&8xyecR;Q46(l}pMa2$uF&K=3)kdhIp3F`Qd;sEnB-Holza>zOg@G|xyGwZzEjfj z85O&e+bLf={{Kooj*-xpoeQzQE1!Un?;<(W&+~9iK1NbrKBcteGcd`gY$^HZ`At5C z@43b;Cf})P`HYGo@070{|D@$(S6k)G0Tr2O>O~g}p z=$n{Uc^jC@TiKHGPA>czBD=`n9D><|upK>v|BEkg-uLUA<2LBzzi<3+g+^*mJw5i~ zp`#bsC5FkX=pQG4!G~gfAsLb}kIry*J;nxL5}iuq@pItX;~tgyeGEX8(U_=G<~2E# zd5mji&PbiX?2oNGRwBhNCpG9%PH;5`vn_7ys&`|GRL@0ecZouc^gBa$Y0&x&bbSF1+b5=#{p>*ZYN8FA9bJw1noo?C=&RjR&8IILB~EZivmWpeg`6Wo`RjCA8jEqzMK!dwqtCH@qA)U zHZH3Pc6#t4jWFASMpszAx=Fqje?o;<4gvRMqT5t`ViNl`hj;-VMANjziEW5&7E?m2QO(3aV<0Wroh)=$S%t*r|}~B2P~>xj`Q~|M-{4I8*fS# zs>NtrYE{x`40w#DcdBF!dTy_cOZQ36N86M-2H)v%De89|8F+#^nRV(HAGJD38*lal z7xLPFGuq~1;S=)E>=%ui5$Ws~+wn8{l_%;KSp;y8nLe(C zlcZl{?oNTdj0peO#e3-o>{W}#%ZX#@Q47ZxP2Qk76YNx+y>!udg;IS+p7tW3cU8mq z4NaRiV}V2z>13~yL%;D-TeRwI?j{6hjycdd2{2Q)YLl)m#P9cyp?S`b>sdTE0Peh8iMj z#~M9#Pi_a~%oMNRf$r_%tH4v|6D`;p)M(uv`P>gp##;bQ>fRL;!D|Ux&Ew@Iyur@b z@wN9!Y`n@4=9Od(>WU8PuTdi1sh`@<7^@01&GPkfXqLC)+PLK$YnB%Vb)``GWxmW?YOwQ?PoqBk$n=2u z?kwwPOg@05h`NWApiWE5>B&8B<0Yz@c)#AL%!v9XIfzOx=S6*vHK(5&8YLpFoRodH zoFFs%e!KDqbvcbU%0JMssJa4r$T%6Fv_@u|tb;Ke^qp^3mL_?P%+57UGs;nlhGlY7 zZCM!^P5)n^(f*6+|1I!h z^{{L552p8E=Ua)2>S|1H!-q27?wz}FWF-~bc!%ODjd$WyPa@L7bp`h{-o;mda^v$* zhR0ABo`LAOtlDzcmUj?F)x-n@ta1)*HhezdQQmyn+B*UA*xUIT|9nE+Rxk5=UbbMb zO)uNBv|TShzL9tu-~5wYtxw*8hw)7qoo{vI3n+=lFNjn*$xZEjDKq6{dtX3_e9YRe zolVtw&1>P?A}^4P?EPaLXo)#A8&u~^{TY%d&^+YCv;F&lu@o8AXOX0fZ>FU2%vE}KHw?eeA&@g zW6uB=AK(?|x&x|Z_q*^XW=e#7V$4iU6B~~NFScf| z4k>sGgGlU{oRqavR*)suN@U`=WfEJHML*^?G913{q|?=+^UtWv)6raGHbTj4G1&wZ zHJzc-&XZ~E4x3*X6PJsLT~s|YBZ^A20u#mc-{W3gb37zn%@_|^l#Pd?Yd~S6TRY@! zym^whKsbJLu*>4>*yEkA>`JghO?hBcP1nymFO=3|1xD<-1R zVlCgCwx!f6n!!%d@0_-^V(g^3P1`;!(1c;{H-_n-lF67hHKAvF%UcDraEiO3_k0usfX$>I$SfYwdSf131q1J3Ir$88x%m zs+k8G1FDhQ@R+S;7JUl6s`@2pQn1a_rjpA6b6WLQdUpdnrnE?;jp0^&_iA@ zBSf9U;eC=@!{OF=_;t6>J|6xQ?e!<7g9kwS#A}^9CYi~*Nt&6P>?04-e~}D{mcC$& zeTi>}mX0!Gpy*WpFk`V(WYN-ta?sM}aZO8?S?gS37?g;j#w1QRm{xP@fS#8sgpR7!vK=VV#E8&X>s(znDbZ z3unhnBo#Rny+pBEM7kDF{8ELq6aF$h$vF_uf7tkE;9F|aPWTp6(_aml5;fA4J3UA> z^CxIbPhs?Ou-YQRg)aBuh zHsAOaD7rcMKSDWMu?F5Y;~rN)8IEXm9JqHxS== zr4osjYj=WRrg5VpAA1cMbZz#g1f-QSx|x{9tN5_q!Pj1)<4udhQK11*2k9F9>tSUy zs>lTN7Rx1+wfl8u{#JZcJ#I74o>hyNdCviKcC|*oGwn3EjxIHYnO9>#VtGq|Eb%iF5CLtnjmtYa_((&i97vN_fFc(JmOXy zfBMq^bN3N`gay|Xo1U)~0sDuU&7Ap`4_CXF5d2GKoh}}Vy4GWvb~re5_W^V!e-{x( z0Cy7Z4&s@T$p)D#|7!lu=5Hr|VurrW)_8?aN8UJ}VDoA^95=|Hb4RXHn$B*nSvqo1 z=x(v^BlbOf=??|K*`@zI5`ob)kD;(H~cZ?hPY~`39InxBuu@4-VafOB8c$m;CQNSTNazih09< z`feXr%=R_%4=ufIUD17Je_?)6c*va4mDhD28oJ}g1oNpe!Th94@%I{)I}PTpHG>;p zy`K2gLmy8x=SMIiurA~Vm2*#|7hs8jOg1l@;Ywe?J>HyN22whQGdE| zRb3*jo@}~(-o|rR6y2u`^G}xu&#L+2_UlL;x^oNq-c*pT)|oc0Fg<^Isp5ZY7*1Rx z|I)Sk{>9=y2;GW%MR@zhqPu_1pE%wA<@E!Hh3*u?c7lDcHf+}xes~n6W_4!C{&yV` zx>N1D#ZrGaDV!@t^u66;&Rx27?9_}eqix330|!3TyTn~{@SXhF+rJ-p=XmHwHVOXA z8@dlIy1Aye&ljbo2hrye_fcS$xP@!R{FC^Gu)T zfwSmNrd1+!MHn6%dTb(eo2?WMUo6OD&Hv{}rL*Wz;kn0hWmYKH^Y&BB^GknRwZz@L zLR$SD-_X64HnqgPWrO_JS_u|RmQ#%LtAG#P`l7yT?0YpeA6h2kT^r=zJ*GBWT_?;Z zjtkFG6Vq_`Ba`vd`>9sH;TU~CIbYw62P)Tb)|TI8_58&v1~-OoEjk}{-#te4@Pn0s z!;0>v4M%|auhz!bnsnXvJ>Zb7W5e$5g9P&*YbK8@y6;u=J^G+O(c$ybQLnzT`7dTL zkeSqR;AZGGhbWZ8dMfR@Bvi7{2}x)H(DU4DF!X|4XrV{gmHZ^3#RmB_`VOUyxVJ*- zo=Eg^ZmmH+%1B6QlNNe9b#5{BbEAd617`|7)nzc#pJf~F*Mv^Cv}@KXtwczieG8n6 zInun@(xx^!_uqt`ZE3$q($0bEJoizmgdn$D+D}H;9;VP$mUiE&wTFF%P{S3#Iof~g zvWGY#eUpWL*Qd}Bze}OCkE~T_39pkYv};hI74CKm-MLz!)$UCe`jCaz@ov2!A6==m zI%Pw=Lxwjc-j~}eG(|E^O+FgF&uSdHwr}3JumC>qS zk1pmm^1Dr++q)iJME}UEmoEl#E1|`N?zPaZ;iHSXGG|j3!t&gL(w@UTM`6kDr_lM_ z_)@7%uMw6D=ywI#Gw;zwS7a`5-?6k6VA1O&Kd{jE*80$+2Du+;i%HvSq3@Hn*j-Go zEM5-TDC(EGUm>A$&pbf+u5f=b$UhQVOz5x1%UOpg^g`F25ijpqD99JOeoB3wyPlBJ z`l$r--20Y_vzi++$Uh7Ta+@2rv`y;-xy>!Iw3AjSZM$1)X(tm}OlUt#yTD|)%8gs- zt?LDOm0O#UUal}+u5t%iz6(vFtK6ZP?q&1b&$=I7^bo%@x5+|}TWFU%-a-!*mG)wH zg5~?!fsZcwOy*_oWTWt>!$jdacVE(_gANSat@ z^4*lA^;_CaZpt9nScsQ5EVR@@uS!BkS?Cr*qBjnfuFS0pLGPmdrHR+NYmLH4MV!6X zU7vw%w{Xd$i+)Y$7Q>k{EN>(v%`XLVF*WxV83%WiwavG>H)pco)MR%t@AUi7XIL{^ z%**I^WCHR%%UayK++7yBn*L`ougAVKlO+wqN9cX-y_svl^20+F`ha`C;bbe+Libwe zal?79`>=)nU}+zA_gQFlmmojFTW;dzf8lO1?*M(mLce3YxR}>A?zhmf26?}GAd_7- z&#j%Kw9mK)GrionxT~-46`s2aT79+`n4r zLRDtvlacbT-5&`_yY&ME`9De{^bEF*7Q4qCKSD^p(8}m>R|xI|`;`m% zxLl@Wq33zpkh2*oC6<{8fCllJLMS7yjU=UOPA;fE%H{61I~ z(`r{5y`pKpC&MclP`|)Jy_s%&bDS=XrUo1v2B@c7Wy}99lJ7DS?GO6{o2e9 z3o-Qu=k=L}g%(-bEtzXA^hx98w#>^d#4-VpZ^>M5p{tCu_hoLh&`&Mj{h3!;=o^;y zK<3pJ`n7TPQ08@k?C?*)`H=f&=8YD59gsexlKvKxtHqY4&^N55en0b8!}4q^&Apj- zSm=k=8h@O5Z=ibp8f$Ss%Y4w%{>^I0FOtx2O}<}dKIHS64F8__NN}M0@!~BD4s@Sh zyp``?7fdZEyRpNs}zxNK8&)9w8!uoui(2o8km=H<&`%q$hdc{dNtn#)mJPyW%oB%50^9UX)A6c=G)8l9h6*qZ5Chvj<8s8VmYZ|xZQZ{T~z?#CAizo&A@2FZSk zeSZY!KAw@}F#`k4O!wC}!Hh(qn;g{lgtDj{me+S+`78KdVBeqZr_^uR_i_7X7(%}F00f&M5$fH&t;e01p^;Nw}0+`6MfR$0ezo;^yYB3m;={- zmH5*l!F>JjABSak`I`Gxf&;%J=Dmx4pU=2~dGdeZ(9aQn^t`V@<>mp^gxB{E%qzR& z2EM;w!2NRV58>^;F7op69Hy-nG_Vd!IcI=brq& zv~OQU@pHUyH{S))O{`4ym>izb2|8Z!m--Z2+}z8b?h^H!M)tB-$I zFtt@OeXHzU8%vnlDw&=u*(x?4mnOzK>6hgVNYDE6rSMsg*x@$Qoj#5EO4%t7mfC}_O&yNCweReX)-0xxaZLXzlB-0L0!aw%NN0Kw9R^_CD_8VG(Qae+^WqP*UNsr{!DJR`DpcqfOC+`jTd2Hw#A&bji7|6_xmPee~JBEoy|}B zS7|TH(36DFc(kKr`Zzf;HktaDa_Og(ccWH3Q^d5c_!z>n94oj1GvMKo-dry03%Fz- z?aOpm$R}r|L~FI>%mEy)4qFCZ(d~A&FADn-^p0@Or5k!N^`)GjWsQVlKZ@4d|2OSi z3A=DG=S=K5VQ)+O8u`rrwdW9uLJx_$D)gg5F4M<^y36sTrhmRL`+L-%UZqUWjAwe& z!0+K_OZxeEx)HjJgbo?XxfEPCx{6MsW$C(65%xxildkX0|1RSG#8}V;!w2_s(luz0 zK0YmV7$p14M}mG=enGzw`o4T7XjjpDNaxGY_T+!ax&)HH4!S}t<1nfDQy*?eFQ?YS z|E^*4`*9s;?w5>}#g(ATY%4^v4*Wf81L*xWrb|PaP77yR+KcHwg|3WXzABRGL3Ib{ zD>kNghB9prXX@_7v|q#>NQ3X$cS<^UBMqnRdxGS@{Rug@qpl)t{|b1YpQmB}PidiD zMK8eHIQuK0--R9qeKnk0{b~EV;5ly<{Vn{%v*OZyg$`R}=TKZ0KkffoJNqmN)1KL9 zMHsj1zlEPX%X4t5PTRTO`qIqL7##0UX)hejtx2ctTpR8GzuV}rJ=1)4I)BQ4uxGoS z>rBs_`8%FM_l;deXOM5%c9p8=a47fBzYY%p|7E z_?hJTC1Kh! z7AfJf4tQq!1AP_J5d16+_H0-V3gdRYJ)FZn+lwWo5uEZzBe;$&jO4m{GLq%FnB(yx zl;w6C%X_v6jwSdRFR~9ssP0hC;itkm&v!~bmqu`2-50?zZiv)r=9=lN`N8=g$P=A! zzT60YI zJSOVi{?=Z*APM%iC+`B}@MA+~z)w%PZyY>Z9vCan9?L@T8-E_H-YA<5pWjRWd2`>( zQm1ENN=}=@V*1WSEDH>}JIxK$VbJ@176NV2h+Zvd1$xAwU-ey*YSBvuB@Oyns*So0 zI-GJ{s+~>?+L$t?;O0~Zr8o(Ho9X_%+kmziG;Gw}NYxR)Zbxb;eeFjNrG`;trZ3!M zso|9EM^9tPRN_YmQzNL>k6ulUq-H;QJ2i^d_|f~R(R7y|eViIY-F|dBHI}loIKGYa zV!SOajuse{oYgBWo^~7b>*2lA63CvdEpIA4W>2Jnf;Ll3L3&ye75UMCv}CFjv=+~P zRQ0CoHA*QeP}q;$Bf zy4s+N3&*6T(0YR&C>~_%OYa!;7*Ib-9jL=S6vkW!tNPU{V7iJg&_L3Zqt zaET2oyEx5B6Af~fy>8E>H3q#{SeKSXCk!enS{;{7a|i2i&lX-5H-L8gQC-?#ddZL6 zX+!9kppA6nu;#S$sCEd4+ekN+ElC?j`wZ%rG$Kv55THBccs!=T!WN1A9di6};4wK5 zWO&HobgoDX=%Q1P5w=$3?~r5rs0J&5HVNv|F@zG6~~ZI(+%Pn@@auV z976%EFo~+Y*_No(+cRQpiX(d0y?cNX$*dXTtKl>glmb@ zQb3gkaaszf-5^d&0X<+)bZUcDDF3JxPeh!SLb_avcP(*R3h5R>o5>lsKCO_t44P5C zDQyHLN?~uNeWUM68%2)^(y1Oz&lp|n*k7iNrmqZoebmEgV`w*aH@VKojCeY2EY;$S zg3*h~FQ$#BWd=Q;{6<6g>J29@Mn+#e%cuD#K`plp;xsN0|~Vt<*|MmacDBJ5RvIA%-wm2?LqQzNgW zoq{&gclq}~*JaSCQLo!QG!c8pl1tgE?Or-&(CX|R=}TzTXsw%`cTf6NIGNVy*|J^f z%jh*hT(*y-FDLsL)-ie_{b#gA(4nwbvb*i8=re=fAId1cge?z+ofvw^v5ImGnio5m zI%u*%KMY{hY|!u08Fgqx8)ADoI;e20c;UCi9jobigTBc=TDsI8Ra+e~*3IFWt}rIaz+h%XdQO5;7G_e1Dlsb{oZIoX$y#G$R+@RyB zqx=7gs9Nhn&nxf0iy8!Nq$#nJ`aeX+1#z8-#eaD^2JlWhuz>kL~7-P05)=y*8C@C;QN#4-GiR%oO+hG*#y zg1S^*+$|x`(Z_<;NI!pozB1uB_5*ZUkdFNTsi_>_@oQ9} z)_nrqYcy9-Cw-E(1Ly%k8|idfLFnsrM$l$@y?9ms-&5gC4!4<(X0Gl3Ce<4Beb$El zhv|BQjwfyC|0jCKpnIWvhaziqxV!T=^nZ^^4f;#c&8bIdg&;jMKEh`BI}~*WV`Bh? z#p1MCtDw6%KgIDEx?aNRn*0~qs!>?v@CNIzbe}=}hR5P8_aVO}Rx3U)j#=5OtN=PZ z{`UUeLAvezKcFX!m)0>ig&n024eA)PtN&5@OwjRgPUkV2Q_De*hjTiQ(E@`wogdK} zjTFcC5&cGxZaK&435~*bkKEh;IDKf)lOqoReP&Qv?C<-3Ov$r2hP7e2vF`(A2s*Af z)hFnTL9?>A_diK3v&B+s+qr4OSKc{<4xahnufF95~dTsnS{lB0W44Rc4m-Gew(V&fEDC0}|Opxw1 zPI0pE*X2l!nG}7B23#aaU5hvLPSN>-bWJ`*qXg+X;R|=jabS2@MgaX8=TB~4WdS{qi|r@=~7lLd8#&FK>h%UN0npRts#I25<(pT`ZR{(iJM?k%7; zvAm52rS@@VsKbIb6W1Q6y7&qXr^_!(xdiFhvwU70$HxqG2GECNa-0Kvx~OA=R-_H` zA;If`qJD2g8S6$SHRg`O&`23!EeT=-&XIof zT;?q2Xg~6%Uf~?;NBc4xoa6lHxy(h*@oLjtj$<>aF&<~B>N4oL%noOTI&IL~IX5{c zs2mqt9#`zMT6G!3>71mp=V=|M^Fmc=5T|ppy2~I==M>d#5T|pxDy-*lYw6VJJDfG@ zB|)9EFY^xPY?ZQrb)EEF<__m2>XBw`smA=;dAVA=SdjEtb?O>FdfZv3Hfsbg4bFLL zzd`)8_3DJ6&0+VIJnL*wi7o7f(Th&Esu0Ar=Y*|MUGCTY!P%s)_oH{63)LRK<-({% z>abt;p|e%lTYWx1b+)NOKl<8vrE2h_e>*+uHbJ_!det+64$;#&A(>tk*2Z2A(W5zW znM>6~L7miVRC?ys>e!X6>!kT3^MEqE+HzCre^&(6Ekm!r(x-FGih?|3-Juu@Gnh+|l( zW*NjWT%+a~#4%i>8hw_CVU=nTv?gpV#+6lSnV>_8QL6(Iv&6%C*K8a7~%eCr3ow6{_muuByM#u53R!QIKI_ti$NUU8voOljP_(+r;drPOZ`69letz6U&>y(RA}6?%%7_j z2E7~Gk$JuPgFy*#>oRXp*;i@H3dFEpwHY)sW?AM<{unqvH>jsYr}J}z>Jr3b)h(GD z)Mp0u9=$d57L~Y+eQu_t{GFM%s#1f#&HGK}CbhtzslA`b+^lZ#TRxw;#h>#{yPL;yZ)e`=N525N%a4{sdou6#qcg?TIGy6Sk%JEV=vcg+Wl+>6)Vl5J8Hw+BxJJ{L zvsRB|+ZBJBo)O2sT|HtD$9|tWV-Ux_LruI|TXO6>)h0n*YAtm4t8PJ^bXo7eW&Tp- z|BNj=>F)7gWImv#3+hr2Al!rMPNREt{F%&$)Lucy6+gpnb;clmhTo`?73@X#ArGs| zdY}eDtLYKT%6eF>4ASjU*9-bUIm#5?H!EGqUOrIC{rUk_3R)W$fqZ#XU9J&*RFV(0 z&7i&Mze{;keQv_tALpdKD(RX)TK1_7jl|17HA*9R!D>*o8?-k)BzB*AO3(+2z5G^v zsCCk_KdwIYqt9a>SBa}621*_FUF?%8TTmzd@%*DHPpW4GZKR0gEh$f_H63iZncj>K z&w5&IHRzGj_^jWlM-0ly%FKFB9TKE-@PPWgpw*OVDLSA&@1gsr(Jd5RVkhCx7cNcE zYT9h&WgSrG1?iqwg+})X!ac7p>YZf;NZs!ybH>sugq__Ta~)b*VK5U61|iL+TNO zc%S_xb;KavOMh8~t>M^jBi~e!h3q6Gq3Wen;K)^MKFyRLb=lvCkuFvOygCUsT}@ zff%|~&W##z3?Hal1Z||KTLB=O^m=O#z>us9Q7=pP#5-7#;ikMBOV$`}{;b zY%JO5r)sZ3?DJDK{q}&*Pu0a5iO)|}ozbz+Pt|-u?32B;2|BJ`DW013saj*u>&3NM zpQ*QlEWcDodY}`6bbtM&y7&%>UHa=U74tl*@e1=RKl&~Qt7Jdg(JvT%nKLIVpxe@K zPS!uv<>GSMq_>ZoqESuj!xc^bw<%vj(sgnNS=}L zgUS|kNY;O3-6BZO3&`53EyLa{e*`}|-7Tmyth@YWpnY10TsoSitP_Itn%QRcy^~`& zt~k|pYk)zV>JaOEL7lWLIm#JkjTUqW`@)LCt;+>*&Qo@{wcdo|T#B#`8pJ*$t+xzf zpV8J|1ZkhK)(Jt{XPnjRE_qt`?3Ep7jSzHPab71{(+%RhPP7&Z>ZB=ZSazayjX_rd zC0Vx$(sd%)x>L|bYYmDwL`>^c3)}2ARe%4N-J7A5(&)?Z2*Q||WCS~`tek;1;icy;N z7k{{!+5Ihb4_oRU(`iKs($D9#k_D}%A?ng>r!~Z&PMa$`(<%uHmt{>13YTTo8p~g) zh1pqFmqEX=EzBNZjk=fPTTQD%7iJH#_8W9@_`>WV*5qwkSKVu2_IcJ<2K@ju%-XbF z>()jr%s$^5b)QC4BNt}pSw{?dO?k2ltl>Mf?robVyUobG0BRtuotR?rePUl3i)gef?;$my^FIlH&UB%W^LE3V(b+OU${A{$9 zfh~HUG6iYN5-Z2(*s{dB>%o9!iFJ=4Z8_F@!06a= zthM){faO^0w}Q0gIBUPrvE?|c`{97)IO{_}+H$=0nbEQ3cx(S70n72$^MbTxsr8!C zv1O^XZBM|m)VfcQwk)%D8y#DgSsjlCEX%BG1!>E2YrWC2Ww|x?v4CZ{HBXSXtgxDm zjx8&!w!Hz%3dOCumX%h%AZ=M?l^7jcR$0d$4_H=N#|3H23D#Fe z$CeYUWlsexCsAcWdzdvAkp|wGfww!EjF*>%KY^^^Su$*jd5Tq@qSX+#aEvHy1 zF9$5ASbYU)%c)kj(Xr)JEA^Ft<Go15th7~PH`6~TVYjm8>S=KL&j(yIuej|u|vhHy~tLYEc?6_Ih%R#!?)>}sRsC{vl zr-(l?!zINuH=08Y2SuH9a;Q-v*EWeLYef$YV)?a_dk+m_`(-F!{EuxsuiePkNZB1e zKcM~Rcn-^!7X3=X{*=vIS!`J)VaFs`@O(6pCE7liUL$>i8$LG3gJ{vEV3m+h+) zIIbVlqIS}+rPQj<=lc0esa=|%ljMt?)4z{OzK>5!Ax(PX0H` zJmiCg-v)80U=JhvvSbpT&Z2Lm&Saw|Tl9Dl%el9)h$S{73D*AK@H+if!vm>RWwEh} zk|b}Lw+tWrqzW}ZkPrW7dmUDX%9XbHr1YW*Qu^o8SLJ#Cgx}1lptMJxBl#q$GJn%r&GSqTGdHQ*|3JT_ z=pvatvcxj8$DiU)$+O=hV}YhU=Yc%N?UIqb=bVsZVM)(9UeB;+YxR8Zr@ZwH`(yF; zjO*O=@I2O{XVLa;bRY7Nf3fl3Xou9&!;;%SU|wO9x1AN~Jl8#;?y+?b|Kq%kZbm6{ zPtIu$^zA))_7JdSdtK+hgxta}@U#aX3_2jOYo9u`n(ERYB6F%O z@)Uo?>_wR;;$EG5Czb^BT!Oyw=rySun(F>xpGf{+@Vejr?^KuF|2wK{)c=kD|6cdF zXT~qggr34TptA8@o@{(QE}Jqbp0aQarY$rS-_RY3`+0byD;KAwxpY6@@r#K2@tcMH zxbCMB`2Ngjyti12@4`%^NHqojgm4Pv)5(SJlU5{%Wt{ZUO zh-*Ern{aJF8a5ye8{qS1;9GEQ#C0pK+i-2dbvtZsht2J<*#dqG_$}b?0DlMgJHT%R zzZLve@OOg06a1av!-?1Uai9+BBfJx|7xJ3lGsFAG1xX0cHoJr#Al}nCKzt7Vfk?vD z4{=WFqu8=qPBp%T&0v)7A)JzaOZ{-3{Vn*BlqixstEixyib1QX2^8OF0-a4yg2FRs zES&;%kkeLFu!^cducu2u@$D%)+sr_`JLnRjF3?9&3QWsDvDOh+2ZHWPDYh;_T(JoCO7=0@gPg3!S3r=%R;QGX%l=(rgSA5ZuOM68 zD$8Ymzb{KpmtAKy+3(JOz`7D1s%g3Sd0AZ^{k*l#_HD)Qt(Vn|=;KzWedutG_u+~& z)|={hL0{XO>V}*KNOp+i*Q1=aVtJ3R%zmn3kZmI@%WNO0Q2YYz1NDOQEzpVi4$!p0 z7uim#kH;UwY30epIks=rhoc){zXSFg?Jwgk$WxL7AE?f;KZl2Q&~U4u->WvK#a}sa zTKvU>K6u6>pe*TQ@s|*skeq<$?DPH!e#+1@pj!TAa+uv|{W6~Ae;O8P-(~x9NWA@| ziXNJ7-)LV`o-4Enk_}_W!tyt;IjO!GS_R8v6_dfA8Ilh9{C+HdzIT;t zGjbW|-xF8b_t^OzMlP4t_8~~W1Lr#Sq&?udM4lAwB}ic`c*p__rkQ!UKQ7jeikROq)|v93Mz2?@?O^4Rq{L3nFqr@!JQ-dhxjj z@y@npAf4+WAJMDZzDHdgdJH|2j`vBt?XsSj?om@hZ-vcyy*7hJJD*34{HvGsk}7^u zMNN`suKC|MK7eQRE%t_@0U;ahzl+Vahl|ZA`$MrgA*bxCVveC-<1ct@k}r5{k}r6C zYyYxueTZ@_>)jgit^GY`eaI%_-vkuX>7pCK^KT9|5&tS-6Y=i>HsQVeTS8K4SMMz$ zJH^{h@wQXE?Ub;1a~SqJCDcv{wNpavmal^BCjLUmUTG=23APL(1$_{-2OI z2fw9TX8%ozEp#1SnGzNHuDUKQDReKjI#WZtBvhAtuV61)*_M#q^7en1e7m5F%JJ=j zF5+(&AQt?7;5FF)8UJgFf31*1{40gM6q>8Z=_u&C88-Yof*eWnVLZ_)>s$NjwBLqu z>*kjJdhzq2P4@4z9UZ}p=Z!mB-AF@7e(9!`|60Ds<=F#cBTeNuI8KfJG=kf&qAOv;ZTWN=MRux&H2gB$p~m!zTt_=9&If&}U}R*O@;J*t zPxec3tfQxs24g;Q>FB|j&+s#@qej&BD{Wor?U77lAwM=~x$qrAuM_G(TwUom2!FHC zLk^Z~5`Kqh-x7LkF%F&c;kJ_W`&R(G2h-lCUQ^L@X zwIh~2sxT!UlBnEd&^aUfM!l=Xjmd~wXZx9RP}D}7EpAv;nfjTtD(Vj8-VD(D%8t<; zwhx8=P;rd5L%uL-yN$=4?KU1?w%d3-+HT|T?d%fmF4681?Jm*o5^X26_&$N8{0Q2} z7W68w7ymNqTeM&N-bLh}LB2flu$1x<&_BbTYuYi9d?u1(A~`H&^tC#bHaPlg#j}^M z70+tEwVg^E7yYe`CEwZx44f2wMr_WA%^9(=Tbz@2Yg*CyF_BhUK~+p5<}Gs~5-qN! zc8gnCs>PmDE%uXYv1hx~t8Ag$F?aeR=4IlyA>XB=asL3%Z!x}0b8|vs-=)8U&$0Mx zJUNzpr6;5y%^9mgHe)84WAV3oaxDICPoa1#vH1Huh1MMWwx`76FZNVI?!fsmf8T(| zQ$Eq;wp@#J=Hmp6(>X*P>)ReXSv*`0?f1PJM7xd-Bt8^drgl{9i_LRfQ~n(2L+EGL z(Zi_ulPzvdldT)kBAO+ZW{c-|%@)t)+J$cyeuc$f1X>}I5?Fp7TVnA$mTQDxBm8#B zf$ek=zb#7_ofjFm-r}z-the48cQ?ML#xuQ5)_WK+<3hG)>rsAG9M2iX#q|k!2Jgp} z*|P@B2G4KDmDyj)a)b7TWS#9u=E69q*f>M@eLQDKOYG*jyX1M}LhkJIx_t$4ImU%_ zfWHeZ{W@z%$b_^P5H>FR)wtpi&bKoA=b7R0I}z&7;7?{If#22p1U)Ia%A*NvLSBw+ zj4um$Hmf;)1;u51;;Ruh7H=!AEnO9Vm!;{kL2JQ(K8Ph8@0;}R*e2fYSf#e5jwVCu|ws5AH`D01c*3DsqN6kCwc zC3UaMqPU8LY-tN!)}K)uyHHo_5?+&1?y|U_?~;_KicKNtDytSWA7c%-mv8N#j2TJA zj`PQEPWaY7Ea~oqV#n}7I}(a*F7z$Mjvb|sB^A*q(qk&QTxt zdO~N2J>zf!w@thYY`Xv_rh9C=@vEFYwz19~pts`ZBri+|?j_!|-GJ{Yy=jZd zW;#5YX)frykS8XxWk=+@&?Y9n3oX-J&?jvhFpGQAHa;aQ@tDQ)x+iT5L&qn+j2>fR z;&%E=;@ZRyZ1?A_PdsVk7WcK{7I)IdE$(Z@E$(ae_Y%wyY%KrQ#*%Ms+y>Wio+s{= z_WPN|>z%JH_Haf#d~I?5@0I%L3Yj@5F6oToaycWGc8SZ5Sn^@dKF>%j>q0J1i%W_` zdVZipu}Ku0Z*3fQW61hGHzyCVKZjV>g?tdbIXTs0d8&<{Lle5KJj(AJ8_$hM4XR5{Vrds@T8$-T|{w}#tYzjq-e?E$ukZRkN9%fIq zP40(2!Ty&~H~0Ql)(-gkCF07q-gBP7H=0#(cW=A!*;2>W!Q14NRP>NvP>IA|DV{6E z^GVu2D$IV8E`rZWY0-t&cLVal^S4$iE&kR@rN!S`DY5w7>Pm~hxKd*ATh}=jzXx7u zy)-PJ3Z8>vT94yg3(*>Pc% zO5db}Q3ibnnoU1|qId2ShLvkL=;ffHG?$|LgyS2w-=&1pGKzzI1tmkWQY7oCU!Mr< zAY?%D1PuXwhH_!Ep9(;`XcXv6G#2vLs2qHf`T>4Y)dk=))Z{)E6|4F_@ibO_ml989 zpy5=hz5!naK9nY^8L*tJYC$hS*m%6h&X&Iewdh@hwXn`(`YmV}dTxG}i!FYZ%PoGE zxz;714HiGq0_zII)oEi7>x6C>x=ZK*&@eh8wA;oWj@j753EL$I)yK}EoI-~QEfQKL zbc)bfLgxrw4jM`K3w;^XqBrgQq#ud)6lf@YV|POm?qJVJLY<(YG{E7;6Af`l&WOBP z=q#Zwp^Jqs2err%vHDineA)nHVIR}Mig|a*=oaw=E zj^(IOTQBCf8~PZ{$=MLU@;=1fT=ux4z7`Dt3 zx?1QCp$CN?6>5tW8=)0K>xHfsx4_(@@D<;mZtVNrmwBLRSmj zA@rcoqe5-*?9&?2ZbILTAIi?S(@}T z+Rof04%H!ao6!A2Gm=?eDzroBHlh24b_=E6Y?C2$o6!A2yMj3C-@u_6i%k(78f8gl-eMU+4kn`_!1zEj(pPJrr6hv^$gi zP!`jUfvnvobibzOvAkO-8onJsN4x;l}o&o;UpbX*Xf=?SfSNIO_m4iEk-v)m1 z;BCV12fumne&M^p9~j&%JPj|P&j-_R_BnSrKV65=Z9?}8?G{RTk~8@Q)OScmzSx7W z95Pq<4)9BcbO^r<`~yR_3BMow`$P5%-wi%`Xt(fGu!zPF%_u0Kt3cUXDI~jx&V}S8 zC`&rPC!W`#wS|{KvcG5%m7SL{Vi8?)UMc9o^X7sk=jX`wa|A%ZDE;VgTkuA7KHsG?9s4i!tCLR;YHzN!!Hb<7Tz8H&+s3@ z`}Z2$E5Fx-UQ2tu(kn5dUqoia!ictr4H36T{4U}j5st{j$n?kwkB!nbJ zCH77%NSvB@S>l4krHOYYK9=}mVsX;Uq#a2IlKz(T@1%ao#mQ5Xo030HPU=0lcV6#l zy_fgCzjs7R|CF`(+@iwit%Vt@4JF+?9xqA;Q488oyde{YcMyBwyfGSFB2F8Vz$N3n zu|K#Ba862rm%i|lN(1r#QU*af6w>ps#>s&spN8NIZbPXEk`a)M!~a|yk8kpoLQ?_h zMEqZvNi>G0PzlZj$Kw2V9L{~m(`7gfyaE>WINxia2{_xGh%?twDX9g>%u1a2|RIo*|*{a=cmbQrb13_P(n@yR-O9*v} zpuGm%2^xDI)5ch~v<+l>Af4&?S@(iIlF4*H^bSy0<^!OKLT8jP-pEdSle4nSzlQp8`!L#r`W{PltuEDy{!kYkTpc~-BLJ#T$-G~;W@D>1m7>M@(27uoLYN1XK0>2s5LT@_+ z^jBy(7CnS^qi8p%g`W3(@V^1I@IQg_Kp#OHv+$-x5#;+oE&45u1phdwh5rpy4E|YA zi=IPUQ|Pzx?=Re*)CPSCXcH{~Xk!FOWluz67=CE3{SoJ`>c!fA*;Xp8{%8Uo{JS zKTwM@)kUC#)Fq&^)McQv)f~`^R2^(C2DPv+;R1gts705ldeAGB8p?C2cb!F`&1x~|V$}-jQCC9i1+}PMc|n(`C7?H}t3Yp2%RzUjpMgH0R)QW- zt3VH`PS6+CYS5R}b)c`SpM#!M>p(wMH-dhtZUQ}}ZU+4Z-#Nrvs_Hh-@73*~|5m>M zRn{G#HtSB%-qzhnNeU=xk##TVwbpjfEm+fAv=#p&#iDzxUx9A3c7g81Dj)B8TfYW< z(0Ukjx3vfK5$iF~N3DH$m!{m709t8FLVi!S^+B&X8}w4T#+C-!Ve1cit<4F##)cgW zT5B7C9`^=lFQfI)UPc>igFtVA_A3dUXdCE5Xx(%iS~vD~`h$J~t(!iB)=ghP+em+hwvoPuwvlkI4|*EfM*0rg z`Sc%X=c6m{4{F(+pmuu}Xb8HxW{S5bfF|0L=o-2U{55nB_*HZt_*JwMdvzn1obzm|Rrelel`3Vt1RgTH}}fxm%{gTIkJ0e>TX27Wz#1%5sK9sEu7Pw+S4 z+tEqr9nRR(K>vd$-GEpB@joZXa%6$p9Rtv7ggFvGdpVM@0~ihd7K#PGkrKggq-5~7 zQeW`5QY!e{CD_soj zopd?0chVKm-br(zy_4oadnYwOn}hyn4$8EZuA=L(dwH5JP#39ob-Q{>EwfJAr#bRN zt`FH3(iQS%NUzWVp{~$}Lq7@qK6G5z6=BzfJs9><*q_2a59<}47Ctb1efXL1@Lqj- zjq0_a*NwgQ_4=^a-+S33A|uKoW<~6X*cX>G5|2 zZ*%e(>lR%2b|_lf6tu7@XjxOxex_j5o{BMhDq0KANo%Hup!&{kP`+q`4n9{tg>_(%k=U?!%Q%U!mOX^b2)T()*;+@jh+tZ=3rc z&HW=2?qhRLu(Y2f>)s@;?Mc=j@M{yy!;QR;x%b1J_5F-K&B*(kyVKk&%zcWv*PDBj zxi2#J#pd2>?(=OQN7Z4Tk%RvV_9VTGubckK`W=0V>$LR|-DLY%u8fe|)QXTd)!5KC z)x=PT^(X5Ib(8HWTy^w(Se|uNc(L_Z_#EruUd7gdUe&hz=xMgf=;LY@E?0CNEe2kW z>$>P!wyn7T64#@+p2hVFu0KKkA?{z`EdJ~03|#5BQmv4f3|#5B>c|x{-?j?ZjWN?~ zzrcM5u7|-t4c&{l-j4Cw{uA>n+pDp=a5dVxai1CYk?l*I7=CFDu^*22+TM#l-~Ju0 zkOa5=F9~-i?PcEOE%oCXv}C4xev`M|?SW>#+b67> z>R#49!Q)!&msGmF?Vi@-0fvo zxtid9+&m*XJA~Nf*0;BcNnW0WKilh%O7nkI`s2d#NaqaRpH>X}~%DgrBr{K-*_SP1b75=E(B9=}^me#lGpdvW?!ShD=Vi)ED zcZ=KOYIjfawzgd4;VkoV41S}LY#nSg)9q?7Mxs00|BnibwU_n^SN#HagA@vT^_9|0 zcl#1g%k0)BpUPJ|s$0D6u9kYq2&7|ziwkUdaP~;*ditqxH#eFn>MGq_MO@9zMlf?p z%e0nRElusqYd9rKnoSi6PL0ph)X+d`Cp0y?C3g^MP?AxjAt>`!SG6oz%$bQgrDZOp z9<`er0sgN*P-3_dKvL7*+9q`$d}Zt8R#!t!J<8*vruGF@OWiH)KHb@QjOvOIXG>8r zS&Bwbz|8-#UK!&N+W04`fiW6+wo#92z(!}a9SMNqs&0_SrxKkFR1(M%!^tBsyv=nGzcy(E@7{`y?jYaL$kZW<3^jA>ArFa`X{3v=M}4QOZ4rm{NNsD zE}Wd5Pv{|jOgu`9>-Y^>{^RCA;(AEL4eHB)e_*0%{uTIzvnUEW0%t&7{xZJ=wZ zXv@na*%bdS5CsU8mxzNXz( zzX*4Z2sd=numn?G(c0XsJ2Vz^x6dY1-0cfm8_Jh7HKPMzGpXZKTrFrLj4N6_txMXQ zQ2&whh**1C+~)EKU(>{o;x{rKJdD_P0QsH?tq{7JCG)sz1;<&$xzXB!hQ+QYWBkFr zq9(h9t3`8by{p-qN4j&6%<^@64P5ez=QS^%(%RBmQ}1bNYvQ zgv+NAZqCS(9x_-3kAtu}t5d*Mt*5>qpX!AoA6q>@+}LJSx3n8pbG5Aj3F?VxrS*@f zgI{0T&*|5p<1S+4*+xAYG>p956Z!jJG(ML3x-;+#q(*SN0%-D9B3}*AjTqAUB_0nl zd%CB!-n2>xgBvN^w6?Tk&^JN3ARy$X#5Xjhe3IInPqSUkOWd_fPzC1Z`>Gn0HB)re z^gw!{d%0LmcQrArXl*emsBDs|>GCXxxVCjRYDB9ipO%`t^uvL2Dxi{CEzM__9;AV? zLS{ABHkoOP-(Kp#kM!ULG-|@gks~LJ$Qv=Dyt2HixDs^2@Zlp0@+K5c7&*LP)TrXZ zkwrx#szwwQp6r`z9IMmhz6m>6enwIGTLpyj^g-zv zNp*EFYHzA9^LSj#t1+wMZn386YWLW@Q6ooEQT~L2;=;U<>WpwTU!^E zwdYq-voOH9ztEN>{Vyx%&#I#0K?nOMS{AmqRsb)ErYKwELr_od-WT|_4^OE^ZE!ER%uqiT|mU7QrS4Wdwi{~}CB*Q9Q z?JklrQaGMgO?R~~@Cpiyq5|t0*mxfDpxzfzVE*9Em6C6&C+nX-= zbUQ&67lSF!(_n1IW;(li&^g05G8f}^V5%oAK!m*P;3o-4q?6RpM9qVy7U-d~y$SJa z0Z;Y~hvkl8B{DNfFv<5-A(MDNJZmY;voAB3;Msy?dvyb$0@UHgwN}rp8fq6H6B>+6 zW;cEb8~2nTYb)JLo9f-{N-9DFEp{#AqJ*Sf-`Kg1o#*##hlB{rbw)=nb30bT*2mYm zc~N5w%)HNAzT8;#5Y#Q!(?YGTal03lW3G9X%hTX3YiZ!VQXa9w)gnCRshXLG@yJ`- zDndMF>s8f_uxS^}L(zm*4?CKVnP!X08SO|>o?mmiw7DWq z^OQ9-Fyo(FYDukUIV=3(+=ka7foib&#jIp0YR6Q!XpyDu?g|XW^8wkTESAx%yzS^0 zni`uRM*r^iV5+)^d2gk=5z}S%%$2JRoOxz5nCVQa#^jJkKB%R31fXfx7}eV`naSlx zK>haAU=@HW;LWX`+S=aKxID0k$eq?=0G!F3dsd6r)#yG)94z4KQtb_do7TcZ1srIF z0luV(#?{bJSGCMMB&9lv60EHk)zxu*#^#Wb^=QuLs<|$3w*HvL zWXicJD6orhPE=EQpY9wfjN5-i%(eI@RMlLFT)jQ#dgJAR3w8WQRC=L?wI!N)OViad zLSo7QS|}bwZQJYebib0x3p8!>(chmb57Gro~k) zs6>dWww1XuG)dgNP4in^*x+)r4`6AdJdmJuP2he=_tvsH#-e3$8}DJrW+1PZX|Yzc zxZAzh3u{0ZNLTv?_?hndR$!iTO>3-O(Bw4&T^m~(FrXuEJ+9`;CXXz3mK%dw=|~ze z6{e}~_N%bN5)jOn_8P!V+~sR`(Y*eeh%XooV}H3TBcuL z*W{0w2mP7uMmH9%cu3hgoY>UhmgI5&Q_%{*!-1p#eX<)xyh!f+$ctU`(YBVD08>zi zctq3>y|Whd^gh*MV^SuWVe&*`(*o|jG&j@jZEaqvCo;&CpsjPRf5w_~RO*k*>9C`2~#=Z z@FVW^WsvYo>Uh(zr9FU~eIdb!2QwM0K?mB>fNs;(EMiWl133; z>EDG#yph`j2GTTSvYi5h_V76n+Bf&Qya6l_b-~y5`HqUnv|DZ96*Dsv;>m)Za&WiD?Te~? z-4B{FW6m*YnSy+ssQ|rY$3}?N3^Ssr!xTggxLDy&;8}-XGy$uLpwk{q@+4}v#~<%> z^hX#Tjl`EQQ8)6ePI?5wxWwa*Nr&%Vr5Dx$^}G$mMml z<)V1FJcAY{wXHS2k)C*Eixq_I6}Nfq08&lN14>27xOy`mW#R^(fp2Rhx}#U1ksy>)NOY?-@ZRvQ-Ix^qK& zozN5z`Py)>%(NL3$Y)`o9*0fUL!)-jXV09SQsbr1(p(j8^W8Fza`i_?J8#K+908PL zx#s0j!I(8Pq4>`dPW4UJwT-VmNj&~3roT##P(LIHc}T4Y}{ATz}+odISnP0ct)4rqP7 zMnJ*?h3t^a9D}#YrJhQ+$UPs{2hDtzrsw*uO7t08Clyb#?qxWp!t%}^sHWYcd9Juv z7;B)Ho0>R*F9h|hkvqXrs;Ve;Iea}$*K(kuT5_*43 z$j;8Oti!2iPlvi^k`(EFLsbB|HXaWca~Wayz<4VV`9dzw zd|K?qGa*uG^Hh#O%(J}4?LuusokaHFKCx;30`6dW?o@+*dI4eFu6JYIh{n}2UyE?$ zywq@54m81N`Vx={%}hC)B|!~nJ-o+^YV2wd#y?hYgO_bkVAZVv0gbWGv=w zZmyx2{>jNb7QaS-;R@439|~5_WBVFxHB9qNZ}p0eh%moy7N)LEAHkwyhb5kT61rvC zBaoSh-cQi1G;mjg2JY5+!$DlLsHshh5mILRXYVa&?Q}FNDG`jI+{A*~4?i~d^d252 z+O!p~2dSNj@34aRF))J(2&%A!(d70{YxyZnH8k$CQxk07+K%b>{F*j*J!Z51h>YLb z)^-R@lR}~CR|K%;ayN5J=7C1~(`L>&y(*lHo$O{zui6*P!qKLl^~=C2D_)V+U}p-g zmbaq>b7PT%Q0jRmN`ZwAatejqj1On}CYZSmK-FG;WrJ_6?ZP4J_+W_i$S*8TguHI9 zjb4F>)NC4}8KYVgs|?GPy&Tg=0~gn!f5OtyK(u%65T>;>FEUY$nTVufbm6%$hHYL?bB~GTxyRMw<$1XTL;?*m!|HT2Qqdxp{X9p3JtwVb z^e)EaxS?r@iQ3Ei5Y)(PfI8+l;pMHZm>jndH#gT(Hy;deXU;DX$~GOAg=i}7MbkV@ zSh-WHzEuaGYZ2DF(p|_Y7hzq^H5P-k^k#Yog=?|QSImmf5A`8f)iU2E9umyEc-(G- zg#Lv~kPMXtrQgyXB%12JDhSQu4m1dJ?Q)^x)bCL06!8=a$JQR%KXf&?%a==~Z#2^k zUb6b89KITlg;}nD50DE$CM5c`9b_M7gzU4n=TRgz^*EWt_|v**CfbqM@^~OSM?EAS zpPC0T3>3&#cB}_!o^Sx5MY=sc9y@M^ZEdSVy+n=CR=$~*f92?V6pX#*y`$iFko2n~ zfip$YlTz8C;uhywqTTY^)yJQ6@`3)?%y6alqMw!Nu2lUVKpxyLDQj5D?=RN2`X!6& z+I(T9a{GWD8K>4eO*AcD}CUC)Xv30amXmI1cXhC%HV>qCgJF z!{T7mUd#{?PY?8TL6RimAQ^_d zhO=e7-1oEx8KJsP=6C+MSxl7L#fNxj&mw}fyhNDRXiPN_2S(zXW%}O22-fKw(sh`) z))=-H1GQoG{Mdj6Iz1kJtDYdeGKy^}jw3ugM@A>@hdjH}3YmiNYt&{7Nxy3O6K`Om zM0wJ0-p9o27wvU*^Gpb{zOGv4uE!ghtu5GtLcH^2rKCr^TojAEBx#QAu_cS;ix2d8 zwNr{HaLA`;3;r`d(Kg6lJ2p@8LT!*Gp4OZUQZ+AOX0@Qtk)I8qACnV9T5_%kCEspN z1w1709>}r>58$8UHMlEV7yHkGG`Av*f)MzdJq32X9qWxjTcxR4Kcqn20h@@9A7Ae9>{x=eG7|6>QIJ_}v7%gpeHAo5a65XMfu@36JT zjlvVZJznJId=LCqKwf6W%U*CLzefS(-W!Vn-nIr4JU7)-e#xaKuL0h65Ai!y2#vo*!Z%<64f~srUL?KxGroDzQ{-f~XxACXZ&l;N`^0nB*m1vLMsU83~F4 zRk%S6bpIl3S#z_0_K0$9#QCs48Z)!c^$%w#EqSxVmkyr+S95g3h|1`Fy^9xPVr** z1B);2?@b;s!~HRykk5F$ROhR``sl-i;9Ab zvZ>d5vXv)HtY=1SR$IROAjuT(0ajw?yos+NKgJHC+4u=>rYFm6s=~1ts>TD7|DHj7 zC_P%xczfHSw|E}})1=gX@D(ST+cQ-b$sWT?k2<_^61yXH{JJT5Tf-*JzVtxutbaO; zg(&k5#fC-}ie8uaMlzLwpvhjffl;1=Eo}EMoz!d^!Y>k#Om5css!d@{BCVOdwM&cs zQLJA-{On#NIFQDid z|C&`ARXH}8v@Ly@++?#u&rl+kPcgqOxxfs5)L=69-L>+x<6w@;lMQ|e|0GRP%65tJ zk;P2I1j(KXDr5+cV;NJhsgyjNm(*2QEhZ@{P}Jo~a?fs4l6LS^5-_A~DU()0i-%76 zE~xc1NZmHB$qP@W8+sDFIRTp5AxWO()q64StPFSCd1Rx)r|5jvLdWflKTXW6YD;)< z8V=y6Zh59>8&|xaD))lOn<$83tsIhKg(Z?-H5uA-Q{nWZb5s2ulV5!$#h*EJ%ASGe zSm5l}Hf`h##X=kIR0w|dHn1rI$EK3@w2mJk%Ve?H7UFJGw0qAaiy)>55B}v*^_MQN zD=gR~r2X+Mf}LR5$$Lha2FaTwn-t6r{7rbV;fIDhmW7MjrLd%uYO%SBrDWkmyQWbv zvFDCuNbx)fz@+36a6>dJIa>myZ|G%D*cZoW>%n^`lDT=UC6bCgn=V+o$P1sc5zrF( zKV_*|sC_~WMf8fGTkqX?=ujf1`VmFq(u*^9&}JU;k$I%&9DEd6))VpKu_ur1Iz1w< zC4tXP6Atr0w5@AV`+7dygPpO}XrBzqYriIivnabCX}sUN#)-5xoQ?6!zBX+3p7hPZ zQa)g0;mK7$`8hp4!P%~&N9?KtJOAk3j#KCK#wallDy?Y(6KA%@`3pL6wv5NlXZCd0XLAjKeQoocJxG^{5@yqNFva<6|+ z)a0c$0i2$IJH#O*{bK!8I2?F1n{6g9SQa9C*ej6QVl8a9gb}stgC?|wX za5|@4QP@O*j*;d*;B0boq5NmHy@?|JI%s}fvOt@1d(YUT$Ff5ne$JYB4)OS$vNPRp zN7?RCM)U|z8tY983{zCFu8FFB$j%k4{Ds1L%pR6t5tZI$p!%>ngT~fNVi+#Gb;e^8 z7Ey-iKynsR8V}%0TFcHqtMJ$OA;NZRAAkp#&vU%N`5TQVOJJQ=iI+Gjx?tgLCoe#A zRItu{v~JVpu>iD}D(!_q&0&f=y~L zc^ZF1x*x~KPzzs1CoO)#3F-o|Bcz=p?F6}}@m+KTzeK!KM)?)EviVKIXZWh&QwA|j z=yv|O#VfcTPTIkuQQDA7pQAlDHi=K8(}XW1bz15TkK+O80PQ|OEiL?Bs?BLae8_s) z8txnp8m3QiKTqtaFc{C_=H|OCM}U?8q$g?n8Lp@J$HNeWc_@bTJ%-b9{3lK0SLg)w z9;4lp&NX&%WiN(&(O}xS{SOfKbT~&XE%zX)qTFY0RhJVwPMqYx4#_8FlCU?EZZwL8GQy+G@9Z+m;`fh`nrgnFi&)o(N z!b0UVYRBpEN&Gyi$A_s!X@_~$@GvmvNp;J%LCYQZ#oBAF93u7z{z`Y_?&+A7+GE%4 zR?kVo!giY89;BbA3Atq+ZWpm_q#w1OiBnx=5B#$Y2T2~{AzD2$2j--4oEw>>q-c4H z@;Di*h&p_nyKdIC{dt-RiPH2Kbwa}rXX;NLn6 zi`g|fPr{NaC6+tdQ~Lz|S`YJkk{=W7hT^mmhIx&yq4vc*o<$({UNQKyq-c83k{zJpUq^- z{RZ$;xXD#1U8iuz=}PL`N(9VV@DO{jkxm))LX+2xoTBZgC@+R|Bf?X3GC^{eM1p!N z=F)_}pEyrq0pTayX{*NzLEhCN_qTv|oBEd%%Sv3S?Kx$(^e?lUGMYFia9SpeHEw5M zv;xj|^e?Giibj}X;B^*O-2(+Ax>SR^S=b(UZU7PqwHy17H@{b_fkJXW7FKUJwTqr>D|+Y8Be@38#Ges#CB`@_t5ue z5}Y)i8Y#G79@yEK87_RlV2AZu+$ip#&uemZC3=WU&y%j%!{dR3Jq@5B?#$emVT+rkZRE6*8FX?J`t*!?DDMDYXM zMNL1S#m`b54|A776L%;j6}G+=VIf)L+w-A~q-mxOXcds@y3Q|(S)NP;WLkHC@ z98XZ9H3!38s3?!&R@@{~#}oZ~`hN(+2j`>Yr^NEX*|IgKN6Le_a`qBJCXVEau3uox zHTrJI%VOrlh?gKzvBZX2xLdv#dIk4rT*V2Z-rTv>LPF$R*qX)3Zg?dnrNt!ak?zA2 z$=o>X+-QN;Dx*Nh4g{uf+Qd-0BXxMyxWv( zr53HF=C$Tis-e6wTac@dKVC3D``J5(Ofq=0bi2{;1hzp@lBTKmlPg)b#-s%lSS*R7 z-sY0eJ^I<&^O98D-M=+==(E);ewXf-?AFZbUpsx_BO&=bxmG%f_Z%PT`1BUAI4;BWT~jm4dZ!o|Q> z#^UyG1DxCg-M>RzZH(8$)cmH89Y;29|XbZ zayL*_l4a~1s?cUf>?yZz6u+0Zp8u;1+i$ zX+EqEK;X?0*D$_2stne{D2nPsR1$Z0@qf575Vt>$DF3l&&J8js#UfXhRH||NisGPk z#h}8FPAqqzHn2Xxl`g!s+j!WjbW#V|IZlJ#1u*DyFOLp*yy|qUxbG6AfrG} zD^6^L+LQdnn}mNY5r<0Xax-W#ew zSNM~jR<4iRFEu*fjUon$1pU%KNf>fVG|erFe3YRf^+QIf4oj&zp;m8n57V!zcqbej zYjjowRSkZX;jS`()LR9|R#>ezI;$$JQZzmgF~0Cswafrc0#^|i4%i63NnI6C77*gV zs!IbA(@QA&R-zFY^|849UgKcccr3h?4t3Uu8{bnOlRsZUm6(O-EOk>ktqk!S20UC+krw zq}I{Jf%KSf4~ZNMjY^nMLDOVTr#y(PjjS(20U`=u-PHm9B|4B$jX@&M_jkM^`Ryys z0vg+ne#qq7l1jPI3+WqbO)4Ko9z)W}CRhw1yW`F@!i~X&^G%jFn_j7$hjf(GP2={* z+)X7V36?P=x%K-@Jx!W%Ivz4g2qNHL<|Z{ed7UY|{b4*Ax4%V&NvN6!mn0AfFAt!A zI=??us9722N-w|x$v{P#>}3CQq8_#7UOgL5aix-gexapxnWh62|^`pL9bieFIe{9i<` z#ja^qlm%oA%7TTn44AvP70aQdP9xHrFlmh8M1Q_d2Dcw@s}HMNq(}l)l02XGgDg#e zh!+W!GP4rBq*`l3mBAXeO%1KaWUH4N-S45EYIT&LSI_Yz^Py5^epIm15a$&T2CYgw zX*D&QO`kyAlks=y=$q=51-z_&)8F12Hks4?kwDPebp*y6HEQpy8HZ7SIF9CUT+ka$ zz(0A2~HLo#5}My>sdiO`_gysdI`-2REz9<#6L z{df}H6L)?@9g}EtX{!ndA|56515;mRg@$zDtMWlGtjmZl*n$HgRszBC610jSD~t(y zkH?dDS0?x%BBZLroJ9n@;)`TEcm#atN1$Q`#ehV;%ul*Q7^#OIE%O`XH^NU1qHVk? zpf%PLT3STSxKd4MLc^XamaB=;=)5gM3k9r5`y;#l%rf4ow92x;%pPn1+|u5ynb3R) z6yIxxUUP|2(Gg0~gzzCVk(#-<`Jfpliq60#WIix(AG#@%)>#e4Lxs9~Kzykj#K%D~ z?)-x+nqLIrkQ2-QLV`idqJOZ=t5^h$&OchpRX8c$Z`~@B(CCyc99dZ8h`UyltHLc6 z;;QgU3$L_rO)~cvNSLdZC~C#s)fQfD;ZX~ZT6l?tmsohIg_l~`6m!=kRaeNwTvd;d zNv`dyn8GNgtMGo^ixnBiXwq6kOOCNdw_!07WMG&Y>(n&M(@HCOu;V#8P}sj85vsxsZD6Lt0&SdnM~ zp4ItcS7R2(7n5F!UsW|Y!zm>h$D}+zpbnk@I2??GfNd5)4Xkbvg|&dLw#q1#5D4{B z9f43MNrHtRD@&z^tPD%z$o)q9M*@pvHU^_CPMHiP);W=1T~ndM>aQb}S=4G7&5w0f z+YHWV<%Hr)>rAMLjW;bHokA9f*&OVp~VlFU#%uWo93hK_@#7UyINb`kobdK#J_y8=9Dtx&e1}Xu9~rJ@#V?x? zu`}*mwiz@db1%0On~MHUW;QnYs*p67!I%Zm(p*^_AW53Gz-nsYE1qpOZNuq#?5RMc zeK{z|@Yj*yW)n0U(zidc`edbI*=hWr-_jIAb{<)TvH$!%SapQQxmB_9I^R}Y+>X&^ zyIHc?peE`pjLdwGyDv%-wEv^6`PmQ9V*IE6_O`#h<8SZ!+u!)x-!cLN!T4ewYmy{!dB1`~T5li_cS&OvzZgf6wbgrOF7+vX+ zD|DAM#)2!!b;_qOSL5Sp`c?K>Z2Y^9AvXcmWz(dBeR5TMc^c;~7S2vZ;G9ucPKUfH z27m)Js{unE8F&p&$O^K9q{UCd5#6%J?fYyfT5a&TueDoFq-qzgOpq|`(!R2SO&U-E zfw+sA*O>PId<$2_r)k}_q#!!aV{|pa=xT=1Rq7BOthUicXEZM@MMy%HyQI-slIKb_ zl91&tZFH9Axl)!SWVy{orQ%kX>^6t9WcxgS;MSHk$cfELykaUwJ2|CM6$98izwkYtjICg#5OO>s? zRN1-&#-^8Pue$eXyo;FJmyG#+V@NR|VGutJx;vP=$89CZ#-E=9UDNlS)<&_E(T?i6 zI~&sps&;GURLn9mymyvS4d;uU+gTvx&LU>a;@i)`1xTW^X87MT;a^ zw#R}LkeqB^f&(;^?MqU4PfHxS5(+Mie*BHazkK_)5B5jvzqj|V{_J1<>%T4kl0PWJ z_fG>|LR}OO16SVnB^G|8N+C2DrQdNRR*ATj%H_H;*&cRfef^9y&LZ}GX<)D%6Ah`k zrDXPS_{J!gfDa2g)-i)|livz{tF&eG)6!sLGm*Rbtql19rx&kP<-Lh0E)9+kBxzAN zI1~;JCnRVbq{Iwhoh`cj$uJ_yR=Dh#*tVPBaZx?5>GEAcT~z4u^&S){+`9v!?fAm> zi3Q3qM*dQ%&)&n87LB?me@8>?PT6WqF9A<$cr=enfU~n9JMA6^Y z9@5utt-qw^UIw{I1up6G zvkdZ5XuEkTr0ol3{@gPCk}re%plMvd8cZNC9s)y`e>7}tsicgSqTaG0iU=WU+6{aN zglYV0TFl7Z*(`F7C1oLT0%l}Smq5^u3WZRz-cgwZk^ucXPX)>3Q{&&$Y$O!gVj(6?Kuj1%@iyQ%$Thb()8J)6lZGVeDC=Up-%kMJLh34(teX&SZ;3t!`?CxmIs*HNVhsl{2ZBFWpcAE1X(zx;(9k#Q0R&_ zS#*zB=5XVGJ+bK8SJ+F}Snz+m?!zBr({P+-_+F`DDt4e23$QD-LZlOAks95)&M`Cs ztI;+EqXa=CX1U+Nb(1_GU&Xz{#gby&@>J~QN zh{yKhq@QU9c^*XFGmG#$&^h$yL!lA$Lv2x031^M$rf|m~Qi#oN-84%b5 z^ri;hV`A--Ga8McSIAPe)lrV0Ts#9~N8%bbl;Et+mO=W_l!`)tj>FO=&OXMQL<4Ta z>x~t)$6e<%+7>maJ+Y@Y?rYkFNG1M=Pfs@FZGXb{D%#&l&KtZoFgAP56aKX-r=-+i zTkmQy?z}qctI4;}M_RDbYwVF}Xq(kE#`#DZqy{hXSka;Qy-I1aF#a&b#t^05?7Cq!zvt+uP|g8N8at6LuwLJ)>dq|a|RDAfm@CXGhu zwR(DB^J*OnMV(FCf=SuR24s-lbFSU8+UBA`IkpIxbzc&Jg93Qp+8unQ3{DBw>bevODb~7yN{kqOV zV6@H;*$^Sb!sWd@M8(==ESJkR%idhH#+Ya z%)5n@cNtz9qlwOkwN{zi2X?mfVVrRqHPm+f21HVl5l zK53G$7XP-k!g^+1F+w93QybOrxyWXRX226(o^^IM7g4j{Bf^xFXcwRP1Zf6_8`FYq z=z7eg^_Hl=Vq?%ZhKb>?Yo~pBNh{3wKV$Uk8P1devqUr{xMdS(vtDFPmiUylN-7 zm^3=5XNWFY{zn9S{(G>lD)|83#W3KqLYGyg)h;YWJjOu;b;$K@lB)bF<<%TfM60#` zj37?~kzi&h5~&EL@M=AlwA$4PFlPWygr$X2@t8z(B1zFuMKO|BOAk|w{aCK;t5nlm zYM_0{83iuFs&|~kVcH)Iuaidu9JFVSPwd6JvjK1wtuEY>fTue%FON9=;Qf2IDsZh? zPAb;U`3$MMHE=ie`ovh<@8h#>P2g63BAmV_YVG>>j#D>=Yq#d!`t3t=ywW1<=0NR` zYnkmhH#DgE>gt8s$g{YCTRneWyb@Uax}x=D4s_;EGi!Y_>Qv;{Uo~(8J0|ac zeLL`q0mJ-4s^CUowoK2wvt=JTUYmbe)$It}7Z)hp$MX)Q^AD)Q8jQiifqUrFR$`t` z`n&>fy>jk>z-{}qRpwsKRmnyv8$`7KyUzB&T!dE^`xZ!9uhtv)Y%pOzk$)#LaUpc- zOd(A#v}ftRw0i%N9Xt!Pt%V^r?#wH3(xChDM}PHW7d*62TYE3?d;jggz5k~vKH8My zEdhSF@;myMfjfFR&m+l=>QeZ7_`r?>zwy!^{$2cRb;l3>{y+bln-2ZYQ!26j3saBa zci`;QlYH=ZdP-l{;?46T(^Drm-A3fZ(W$58vshmcnL3X@vkN#HlCQU^-N&Ci!)xhN z_fJnx;jZEMQ-_b7J3F;u%aQf`?Zfr-jwg>z96fw&D(CpqN1t>Dc5d5v$DJ-grTlS% z3f`czBw~;6ro8EglqK&DL6z2Xk~w(S+3Fn9Pba9x>*O}mc9^c6Nnjn z>v+$)fZpgqCuVgFn8aB;FstW*nd^KV;5+*R7rxvvgSWlJ^%u;Zel3!s8?LD+-wN(2 zwf$O4E#xMX*6;tP)RTOtkZLwxQ#Ixus^F}bf?vF*g0tOXe3m-;`s46lLjaGp*Mvvn z_7(U$t_ePI0F|vUDR_%Qj2q;t7VS=TnFhlW$6=H`iyr4hi5(SaTu`rOt1HR zl9tRA{hTGP*hqJadomLLrKFGcr0c`da}x35DoI<=9=%S6$!lZ?&zPU0T}MBu#OLx7 zbNsqe;dOboRhaliB*!hAl~r&6OKzO!rt3=;%C*?ceEy7qDvU?s1P4F3{N>2vxj1ox zIg@Nu~-JNDYHZxRDiT#Dr|S*TcB-swVn z_N}=hRDs#DS`hhudC?E~nGCE~!57A?=eu^`yfo`M>aypncw`m^)MsWM9o5~jLQ$VB zw}Hwj47Ja|V=sS&(MXeL5`1#+=fJJZDxS#Tm|b#Hd%-6Ft_lmxoqi37)X}WC=%G&p z@pnU>IM+)u`8fx`K6AYw0+C}iGXM`#bt z&Eo2ntYYsitEV@Gj?ON(WJY?yGf2i3s<1XwbjC%(B0qjTK#t=lw_?hBKh0M(Q;ARL zDJ>2rj>u@26yLl6ptiCy>vk$#0_0_X?bDUbusrLl5S|ZQa~1R3^f^MiuD!OztuzJf zdqT-4LA}kMSGeQTS2)YA&+GcaHP_X<3dn2Ne$6$^vu4Pv+VW|u@+%BqfgZDb@LZ9qi%{d zpEvJvMDJdxOyL8_Q$0prUjE)|E#Jo?%xk&lv()0v$GnmShPvll&QnEHur>dQHDH+f z8pLi341r1c+)T_{T{VB_Q{&MC*J$AL^8@eNyPXkE3`1W+qHE2F`>Ld}s~{YlWK z>O8!j*;`;j8st<_HRioqfF|Y^f2xoE^rbZp8|FvSmo|E2+R7KC+^_!rpQS)xo25&g zYxkn)k1g4^pOY@Qo%|l-fzjRKisWy1C=2<^?f`CszU(G(c5(n`Ch{$Ki2EK~uIx3) zH_Ctazq|#Nmh|^8CQ;3uLbaB>yXk83FZZ!_*xpaD+8LdvG_-a(dJp~+30+`**nw18dD z!Fvw-WiXYSzZ_;gZprc=M>DPtyn5qZQ+Y>BdlF|ajyoU0pq&YG2O|eZ6F6^?n?$zl z46og!$pxF7(wqYFf?;+Hw=m~`5l%a-jlD^_T*C-D?T=z|EVFQ1o2_5_s6$TO&Vvn3 x#Ao#`@0a@M+}&0tbx0*Ae%=Y$CzYed8h@-uCA`GuIU-A7aezza0wyY_W!BS#LSJc?ky!f-TnRMV9B~@No=UUq_@AM?dWACTg>&*NNTEox)Qy(U5JI6OMLjr z>bI@lUKgb$$y${VkAY%H>XpC8wS>wVfpjkGQg0%V{`{GTdeG_P67$X?R{B42RVb10 zX@}gSxul6rWQg&f5>2FlcIQ4J8pqd7hL;H8b<}%-FL2R#6vM_NTebI;ttw!`a|2v-AlN(L$gUBP7qva3Yz66jbTr2n-um45$v` z^{DXc!(eus4Jap7^ANzwH(&L8Dh!V~2gobNAo|nF@P$!y zkta%;grBTx^@C}*`yUclL=nsl84VdLG1YeSa&yvYABKec0X9P8#4#R9l+n{ct zVYt3BtjlY*l3a{}hU79aT0az`abS2n4p}ubp}P^r{2FCnALDT@vkgrvQf1FB6T!@1 zmMO>P5~o8J!k0C+pm4dB7UaRIZEJRN`N4A79v*gz@+ViggJe%pbq4EPUgF7Fne0)H zI3El(kCvxM)G)D#F+>*b=Hcs^BXE2-k4+af&_~*umM9hyFV0$M?`M5FNqZ@4+zd$D zP#p5`c*eAchTPt59svR6bH_^1FpIQ2tfA8ia(Q?#YQ9wc7=_`gN0K(j$g5s7Lb~d% zkz`zKYN16%)JstFEo!QhT3}Jrh|0cq4aP$s*@tUr9=x+6)9&jA!exi9AvhD&Sv}rB z_y~9F8iHq0oz?FRgpY9Nt|2%Y)mgpYK==r&AXf_N@|0%0Iz|v9++{H=5w&_O3s_u| zp;(V2w$PG}BVzCsONFlp4}698Mp?g{=F`*WrPJe%vMx&h2!dYP`{Dw@*|nD zPynVsIt0*cvFb$;_PQ$}htqQDG`DisqOLR-E3aAxvZ$>LNgwi7q%;!6p*${`w z?Zo9aL*x$94`CeITLbpu?E?Dgz2r=udh(k&Pn~K3f{L9(XAv$ktNeRgfTCtAH0kf;`5xEixiNoIJQxcZHEC$-)*YAQ9M1R+-SF@>7o{|X$4-;Hs7x)j+*$;G z^zW8AhFq*UL?l^~7~5h`C-tifNaN3V?kvP6EJ|9X6>t!{m7XIbRD3CV9$_Wp%cw~D zsGhhjq>_B>TMqdN6|ogLJ|~<1ItWux-25rHoQs_(Ti*j zbqw<$Nkjr7iCAccStg0-+^A@AnGv8mFI|6mz%Z9%EUc?5+y@RrCWe1_HDC-O@My`2 z{Lp1qN=e8SjEZiTS;dm3K|o4*m6s*mfMBGhx`M9o3X)5Clvxcn5RMt!kym!~i&q2Q z{X06CIx5qUbm?N3D7sO=!c_jXm^($|vXzs;C;_az6QPo|WaNS|%$ewreg90fWj+}> z^)Tcb6-Q?xs*;n)5EvBZv1m|H=_Im4SL7;>mT6&}mWjENglCtJKTq|QObsp&kKPVBC!98bMgH(zHi~%_&0zYv|(E?G*^=@DqZ4b zYf&i5x`qjwYlz2XQbt};?cy!61d>KK*Q6=zi!Z)7ZF4p0b1Fr3N$m|E&%zanDkQ~a zQj%X$Eq7Z>l)`LLE^epxb4wKM3sQRc1SuTm1BGC?OH#1#Kp_}jOO$MEnQU5_V_gE( z=_6^bTCL2*)`KPBcS1lnff*82_#(j;t@vW;i1JnXgyE*VnKK?4Cd%s&|H)|O<$5;n zHRYvx_GaE*%5!zBAo=0lsoVn|(i2%Eg*d4n%^GYK(1+pv?h0hqbS;Z_V=R6no`(gK z?8!DWXi0i_CF_Q{4wal(D{jc3byI{ZOcrpNL9qK>s+kM`NKZ%zLKgFG#g%-~a;cnE z?c_{|_G}g;aiRp@3Vbv1C5J0-jm=3C1DJKTc8|0_&&7IK=1GsrGR<9h1C?W|xD|U> zS!_EYNHk7{Q|zXwBJEIu4iNL854v;noh{ve(e9&e!{QrBSO$Ubec^#nb36I6EX&V^-Yvap&bmPHlZlnZEz7%B-|00CYl30xrie;4+rPn;|{Is^5xgmt7!$a_?& z+%8q36k0!8Oazk}PN&iUl@QV0@sp?&rc#Vba8!3Z2Oc{LA9PbL<{w24?v4*qsl+Z# zrP2`5;7qE7h35|61_uk@4uJC%m)Hw^5eNf2s8`*D`}-@jvY_}p3$CpPg>J$j{o!-K zug4BI#DKXCcxHGzF?xd{C%lWQ%u|3TXQz}e_IR&M^_jy!V<&+>S zeL-(d?W}-1`$}^MD0^GT7ij+Egr)|C&peILvmn-+vogi&xuCb^mK|ixjHK)gBajp{ z!lU4j8XM+LlwX}P^VO7qQQ-+Bg--|m3h$*t+%3``5-!9rO&2$d{72<69F4nMK@mR_%;5{2!)`=-F@EG7B(qVCJSmVwBR?*XWR0A1 z1;@ze*(3iNB$rnQ-JfT9XbRlE5hQVLT-h)qIfRJt1>ll)4!BJi%WoO$@Ih=Ix_LH8 z83tygBVc&1%c@1_DEp3UW=Hd`7f4P=IRGN#YaYb|w>>%IPO*jYv%r$JS!y0qHc5g_$^%KTi4pWDn|K0-w24RB#K8FN z#x!#^Pw$`=o8isQ@CCdRo_MsRr0@-C=3|J8yL;5;M zWqRy>_;Swqm?dpSw(Hv_wtm0=0DZD3!@LwMuZCvsCoJ{Vltk}FnXe2k3?IcdIO||} zb}Gb~BJ-OfORl+7MfL5Ho>66poi6OL7_ZArM*N!TGCzk87u4b|LJxm~lrm;i>NE9Z zSrJOEovxdgfnMn|RKNji>=}$kZa8r)b>kGtT^u<`778OJvQQMsQG$GtR8{iN`!j6r zGQU7W^Kytz_4v$h;))v>CYJ4>80j;wAX=3|t_0#SuOd>>7}C`sDPd?}lEY`@lJ?0=k%P~l_d3R|hi`y9745$bri`RuQW(L)sLV$JYuKm^#J&bmP8(Y+xqA3J zXfue_s$uygg%Jvk3{Ux#`1K?T`v9c-Gq9XEy$^U?;hTxW8}L^8q#6Yg1Zu<;__%*& z`R|nEio?+)o!a^W6gzH2F$F=UywE#XfX>jw&&R>I+=RM-KW8OE5Q0$6tBts`6agcp zaT>0&lbm_jA%%y;7#!g}Cd}y1NcOP)u!zG0^X9y3I|bkJWTXU>Ilcx`OsMa#I4yzS zLSj+_slyaHE2g4A!FjM6I(mUnaF$~>Zv|)hWfnt(ES45XGjAh-1%b4&+?ghJWPjs& zgzhm?W;QMX3Ed;c7?oHupVBoW_5@8(ASHYUTB&6aMu$dYDcHS(&`Ar>D9!^-=~F@- zxTv}e!_BC2iz3(v+1|MI7=cUE!o>Qcm1$mwvPJUMX5d(!R*$^Z#cDQ;GRa?T*YP2& ziLAn|D@@e2KsB0ayRIlv*GhGWh<07bpQxNim1&O3{Ms2tt_fE(kS1bYa6^!AvJO1u zkuLUoI1=Xz0v){0;?YV9oJ}?)noy0S$x^!s!n?D{ z#zYgUaWq+GH$migHrbSDLN$&i%k3tJ=*}j+i6&IzXtKg?g5d9LvN_R&Y8*}K>?R2H z&L$@¬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 literal 0 HcmV?d00001 diff --git a/Assets/CoreLib/Plugins/LitJSON.dll.meta b/Assets/CoreLib/Plugins/LitJSON.dll.meta new file mode 100644 index 0000000..614464a --- /dev/null +++ b/Assets/CoreLib/Plugins/LitJSON.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: a6aee3e70b1022d4aa0dd15acad74351 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib/ReleaseLib.meta b/Assets/CoreLib/ReleaseLib.meta new file mode 100644 index 0000000..307ba1b --- /dev/null +++ b/Assets/CoreLib/ReleaseLib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6c176e912c23c742927770501978946 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib/ReleaseLib/asap.core.dll b/Assets/CoreLib/ReleaseLib/asap.core.dll new file mode 100644 index 0000000000000000000000000000000000000000..8f0984d137aaf0a6b500b97665846c77d63f0ce6 GIT binary patch literal 104960 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

SZ=ROm;U29~VZl$u! z53W@o??QH{?uVS)6S+^XCL4B^6oEOVaz&F`rGo2%+2LcE9DhtQo0A=eR2NuG*02vb z_dw+Ku7$Aj7#Y=*7FiF)H_31=w9I-azI}#KXrT3K!sa2{Lt{wR`ZUtRk$YgRnvB|* zW_YlU1Cjgens|Pv&v4;5N6sCN+{0@j7205U!<*&ESRNiyMm+1zFi#8=&N4hqhCzKk zj1>cB@T*XTU4|=pdgi4i?5uxw|7?CJnVXN?BkLfK*q9G?e%vNQgFbj7awk735!(no zVuzg7%DKlPcjTjz%$=Kx$OBqzw)rKn!nQ2)(OuGpI~z3njmPiH&ua>f1%CY-g*a_< z%i=#Yj{kQU=Pb}S)<20&&YTk38-GH2>DzzcqLZh!@DBLB@=D}h`5nJZ2t=VR{65X^ zp3D3V*ze|PL}5@IzMeQUf9Ax(!G}-nzIN=d-Yx%e=O4d)To}hb-~BS15nt>+$5D7o zT^(}4cC_c0y1(|hy}X=1+x=B}ERa>{aU?U0Uk0hx44a zm%Z5Cf9Ux+uG9O@{>oRo`3QgE>~rqS!jT6ae8{DRcrg@$idMh*!GHfled^tRdG6%j z|MSaHAW=*UT>ZOzm2vksL|SYYym9+NKHpf0G%o=q&dpx|owH{1hw2aOi_$==!{ zR*kcN?d0BQk4hg8O9h-=C$E(pLGZ=x+ABCnZv+z%ikGQuRWS_hmnt-HOC|niyQS6Sb}9onNfM+2>JkP6`RXu#CDDiHUNgqRHwJvQ2Ve|ms^%7gA(Q88eGM_6EH z)__^sY zM88HoU+W`fTW! z8Opppt2xW%&>=M>7CO`?X6~I--Cro6`egYKQc9t#eFA>^xC*_IM)yK_a-XNb?aT=8 z%ix$@a!$u_wV{wASQy-?%YR}U8M@j-=KyehGLKyC8O>%DfCBb zqY_o9{|IOeWVNG*&EOU?bLkXWchI5CaL!Y~6Pck;4|n37T_EUOZ|p6ETSkXUF< zi2B3=ZlNII1UGQLPssK6eFMc%K ztduW$5-R6o8z!-~OrIC%#Kx%wXObY;p#kB9E-$m^1m{0G!4-0SPV4gABTz; zA9Et>boJ2Dirr#SkTriw3J9j2f`;2VU0_^37ZdYbcdcFdRCx5jH8S|j+Q27H9ixYX zVCXT#x^}ORkxCsNLBnX@+6Z0@z(0I9$RHkT0<3jLe2!HVCZOW6#opJM=Q;Lj8Nd_Z zPbb{{>l9i(*}5#Kd0}Vn1Z_*5hu2@>turAFvRhml^IEObCgu#cJ7WFx*y@M27A+sZ*Ox{C*_WrM?^i6}A!@Gq4cK{y^v;lrbVsKMo;$a{Jc%p9Ig@*f{GTpf7T#(TH$z8oH>uJSeEc;Z5u zeD($J21|s_QbSqh_=pegB5?BJa^Cz1ynycnmF%l{S@=z0I{fA>k5eK39C-;kt&iUB zoYw)X*J)_TFU$o>gJ;eawae?JIy!gIa8jQZ@&n}knA`~u)Sq8Js}}g9$Z7q1 hashedBuilds +- Refactor BuildHashes.FileHashes property type from Array to IReadOnlyList +- Refactor HashGeneratorResult.FileHashes property type from Array to IReadOnlyList +- Improve CodeHashGeneratorPostprocessor progress reporting in Editor +- Improve CodeHashGenerator filtering to include all .dex and .so files on Android +- Prepare CodeHashGenerator filtering to include content files so whole build could be covered in future +- Introduce various minor improvements + +### Removed +- Remove static CodeHashGeneratorPostprocessor.Instance property + +### Fixed +- Fix InjectionDetector build processor could keep the service temp file if build fails +- Fix ObscuredBigInteger.Equals(ObscuredBigInteger) check didn't work properly +- Fix ObscuredBigInteger.GetHashCode() did return value affected by random crypto key +- Fix ObscuredFile could have inconsistent path delimiters in the FilePath +- Fix some critical errors didn't print to console +- Fix regression where ACTK_PREVENT_READ_PHONE_STATE didn't remove permissions caused by SystemInfo.deviceUniqueIdentifier + +## [2021.6.4] - 2023-03-09 +_I know it's 2023 already, fine? xD_ + +### Changed +- Improve Unity 2023 compatibility + +### Fixed +- Fix inspector fields regression introduced at v2021.2.1 for Unity versions below 2022.2 (thx mrm83) +- Fix possible SpeedHackDetector false positives regression introduced at v2021.3.0, now DSP module is optional and off by default with proper warning about its sensitivity (thx mrm83, Kazeon, gpedrani and others 🙏) +- Fix some buttons didn't open Project Settings in Unity 2019+ + +## [2021.6.3] - 2022-12-19 + +### Added +- Add few more operators to the ObscuredBigInteger to better match BigInteger API. + +### Changed +- Change CodeHashGenerator Editor warning to error to make it more visible and reduce possible confusion + +## [2021.6.2] - 2022-11-12 + +### Changed +- Make ObscuredCheatingDetector to print logs when ACTK_DETECTION_BACKLOGS is enabled +- Improve Obscured Types serialization Validation logs to include exact path and location + +## [2021.6.1] - 2022-11-10 + +### Fixed +- Fix rare SpeedHackDetector false positive + +## [2021.6.0] - 2022-11-09 + +### Added +- Add new WallHackDetector compatibility check and safety warning (thx naezith) +- Add serialization corruption detection for Obscured Types + +### Changed +- Improve ObscuredVector2Int and ObscuredVector3Int vector components access performance + +### Fixed +- Reduce rare SpeedHackDetector false positive possibility +- Fix few rare ObscuredCheatingDetector false positives (thx thiagolr) + +## [2021.5.1] - 2022-09-10 + +### Changed +- Improve ObscuredFilePrefsAutoSaver behavior in Editor (thx YeahBoi) + +### Fixed +- Fix ObscuredBigInteger corruption (thx jaeyoung) +- Fix ambiguous APIs at the ObscuredBigInteger + +## [2021.5.0] - 2022-07-31 + +### Added +- Add IDisposable implementation to the SHA1Wrapper class +- Add DurationSeconds property to the CodeHashGenerator results + +### Changed +- Improve CodeHashGenerator accuracy in Editor for IL2CPP platforms +- Deprecate few obsolete CodeHashGenerator APIs +- Improve Unity 2023 compatibility + +### Fixed +- Fix WebGL compilation regression + +## [2021.4.2] - 2022-07-25 + +### Fixed +- ObscuredCheatingDetector: fix possible rare false positive (thx tbiz5270) + +## [2021.4.1] - 2022-07-21 + +### Fixed +- SpeedHackDetector: fix possible rare false positive in Editor + +## [2021.4.0] - 2022-07-16 + +### Added +- Add LastOnlineTimeResult instance property to the TimeCheatingDetector +- Add automatic ProGuard configuration to prevent errors due to minification +- Add new menu item to configure proguard-user.txt on demand + +### Changed +- Make ProGuard configuration more granular to obfuscate more of the native code +- Expose internal TimeCheatingDetector.IsReadyForForceCheck() API + +### Fixed +- Fix possible TimeCheatingDetector error due to certificate validation (thx murat303) + +## [2021.3.0] - 2022-07-10 + +### Changed +- Improve Speed Hack Detector sensitivity in sandboxed environments +- Improve detectors' keepAlive logic when using additive scenes +- Improve WebGL file system compatibility at Obscured File and Obscured File Prefs + +### Fixed +- Fix possible undesired detector self-destroy on additive scene load + +## [2021.2.1] - 2022-07-04 + +### Changed +- Change some property drawers to use Delayed fields to reduce CPU overhead while editing obscured fields in inspector + +## [2021.2.0] - 2022-06-29 + +### Added +- Add ObscuredBigInteger type +- Add BigInteger type support to the ObscuredPrefs / ObscuredFilePrefs +- Add TriggerDetection() utility method to all detectors +- Add 'Trigger detection' context menu item to all detectors components + +## [2021.1.1] - 2022-05-04 + +### Added +- Add TimeCheatingDetector.GetOnlineTimeTask() overloads with CancellationToken argument + +## [2021.1.0] - 2022-04-11 + +### Added +- Add ObscuredFilePrefs Auto Save on mobile platforms (enabled by default) + - Automatically saves unsaved changes on app loose focus / pause +- Add API to disable ObscuredFilePrefs Auto Save (disables Auto Save on both mobile and non-mobile platforms) +- Introduce IObscuredFileSettings to improve API usage experience + +### Changed +- Add locks to the ObscuredFilePrefs sync operations to improve stability when accessing it from different threads +- Move ObscuredFilePrefs Save-On-Quit code to the Auto Save feature entity so it's disableable now + +### Fixed +- Prevent ObscuredFilePrefs Save-On-Quit while not initialized +- Fix ObscuredFilePrefs behavior with disabled Reload Domain +- Fix compilation error at Unity 2018 Android +- Fix compilation warnings for WebGL platform + +## [2021.0.10] - 2022-03-09 + +### Fixed +- Fix ObscuredString name in Inspector might render incorrect in arrays (thx Sungmin An) + +## [2021.0.9] - 2022-03-06 + +### Changed +- CodeHashGenerator's Summary Hash is no longer printed for AAB builds +- Skip Android Patch Packages hashing by CodeHashGenerator + +### Fixed +- Fix obsolete API usage leading to compilation error in Unity 2022.1 + +## [2021.0.8] - 2022-02-08 + +### Changed +- Minor Prefs Editor UI improvements + +### Fixed +- Fix Prefs Editor window didn't update properly under specific conditions (thx Todd Gillissie) + +## [2021.0.7] - 2021-11-18 + +### Fixed +- Fix iOS Conditional compilation constants settings could not apply in some Unity versions (thx Hesham) +- Fix empty ObscuredString fields automatic migration (thx thiagolr) + +## [2021.0.6] - 2021-11-18 + +### Changed +- Warn when trying to use ObscuredFile with StreamingAssets on Android and WebGL (thx Harama) + +### Fixed +- Fix automatic ObscuredString migration didn't happen properly in some cases (thx thiagolr) +- Fix exception in ObscuredFilePrefs on iOS could happen under rare conditions +- Fix ObscuredString example log + +## [2021.0.5] - 2021-10-26 + +### Changed +- Improve ObscuredPrefs and ObscuredFilePrefs compatibility with Obscured types + +### Fixed +- Fix TimeUtils could be disposed unexpectedly (thx Hesham) +- Fix TimeUtils might not reinitialize properly in rare case + +## [2021.0.4] - 2021-10-02 + +### Fixed +- Fix BehaviorDesigner integration package compilation errors (thx Levent) + +## [2021.0.3] - 2021-09-27 + +### Changed +- Improve TimeCheatingDetector performance a bit + +### Fixed +- Fix missing script at the example scene +- Fix CodeHashGeneratorListener example compilation errors + +## [2021.0.2] - 2021-09-17 + +### Fixed +- Fix empty string was read as null from ObscuredPrefs and ObscuredFilePrefs (thx C0dingschmuser) + +## [2021.0.1] - 2021-09-10 + +### Changed +- Improve exceptions logging a bit + +### Fixed +- Fix compilation exception for iOS platform (thx Vladnee) + +## [2021.0.0] - 2021-09-06 + +### Added +- Add new ObscuredFile and ObscuredFilePrefs tools to the ACTk 🧰 + - Encrypted and plain modes + - All modes have data consistency validation + - All modes have lock to device feature + - ObscuredFilePrefs has simple and easy to use PlayerPrefs-like APIs + - Async compatible + - Supports UWP starting from Unity 2019.1 + - BehaviorDesigner and PlayMaker Actions +- Add generic APIs to ObscuredPrefs +- Add new types support to ObscuredPrefs: + - rest of simple C# types (SByte, Byte, Int16, UInt16, Char) + - System.DateTime + - Color (it's possible to save HDR colors now) + - Matrix4x4, RangeInt, Ray, Ray2D, RectInt, Vector2Int, Vector3Int, Vector4 +- Add ObscuredQuaternion property drawer (now it's editable from inspector) +- Add automatic link.xml generation option to complement fix for WallHack Detector false positives due to stripping +- Add additional information to the important error logs +- Make ThreadSafeRandom utility public +- Add Copy Player Prefs path context menu item to the Prefs Editor tab +- Add ObscuredPrefs Vector2Int and Vector3Int support to BehaviorDesigner integration +- Add new support contact, let's chat at [Discord](https://discord.gg/Ppsb89naWf)! + +### Changed +- Swap Changelog to md version to better match Unity packages format ([Keep a Changelog](https://keepachangelog.com/en/1.0.0/)) +- Rename following ObscuredPrefs API in order to better suite coding style: + - OnAlterationDetected -> NotGenuineDataDetected + - OnPossibleForeignSavesDetected -> DataFromAnotherDeviceDetected + - lockToDevice -> DeviceLockLevel +- Move ObscuredPrefs.DeviceLockLevel enum out from the ObscuredPrefs type +- Introduce DeviceLockTamperingSensitivity instead of readForeignSaves and emergencyMode settings for additional clarity +- Decimal values processing at ObscuredPrefs are much faster now with much lesser GC-allocations footprint +- Improve exceptions handling across whole codebase +- Improve incorrect type usage handling at ObscuredPrefs (thx David E) +- Improve Settings UI a bit +- Improve detectors startup a bit +- Improve Prefs Editor error handling +- Minor code refactoring and cleanup +- Update some API docs + +### Deprecated +- Deprecate non-generic ObscuredPrefs APIs (to be removed in future versions) + +### Removed +- Remove .NET 3.5 scripting runtime version support + +### Fixed +- Fix possible data corruption at all Obscured types in super rare scenarios (only one rare case for ObscuredBool was found) +- Fix possible false positives from WallHackDetector on Unity 2019.3 or newer when IL2CPP "Strip Engine Code" setting is used (thx Hesham) +- Fix compilation warning on UWP platform +- Fix redundant injection detector support were added into IL2CPP builds in some conditions +- Fix exceptions in Unity 2021.2 and newer while browsing ACTk settings +- Fix code hash pre-generation was run redundantly when building with Create Visual Studio Solution option enabled +- Fix Behavior Tree at BehaviorDesigner's integration ObscuredPrefsExample scene +- Fix other minor stuff here and there + +2.3.4 +- backport from 3.0.0-beta.2: fix null reference exception in Unity 2021.2 and newer while browsing ACTk settings (IL2CPP section) +- want to participate in ACTk v3 Beta and get a chance to win v3 voucher or any other Code Stage plugin voucher of your choice? + reach out at https://codestage.net/contacts or https://discord.gg/Ppsb89naWf + +2.3.3 +- backport from 3.0.0-alpha: fix possible exception in Unity 2021.2 and newer while browsing ACTk settings + +2.3.2 +- prepare for legacy .NET 3.5 support deprecation in upcoming 3.0 major release +- fix inverted ACTK_US_EXPORT_COMPATIBLE logic +- improve minor stuff + +2.3.1 +- fix possible code corruption due to the obfuscation (thx firediver98) + +2.3.0 +- update minimum Unity version to 2018.4 +- remove legacy code +- add DateTime value to the TimeCheatingDetector's OnlineTimeResult + +2.2.4 +- fix compilation warnings for non-IL2CPP UWP platform +- fix build errors on non-IL2CPP UWP platform (thx Aymen) + +2.2.3 +- fix possible SharpZipLib.dll conflicts (thx Nathaniel) + +2.2.2 +- fix possible null reference exception when migrating from ACTkv1 (thx RonoVanBono) +- fix HasKey() did not checked ACTkv1 keys (thx Albert) + +2.2.1 +- fix compilation error in Unity 2018.1 - 2018.4 with .NET 3.5 scripting (thx Vladimir) + +2.2.0 +- add new APIs to CodeHashGenerator to return all files hashes for accurate checks + * allows to check split builds hashes (e.g. from aab) +- improve CodeHashGenerator performance +- improve CodeHashGenerator Android native part errors processing +- clean and refactor some code +- fix possible error in CodeHashGenerator example code + +2.1.3 +- fix Code Hashing example compilation error +- add ProGuard notice to the Readme (thx Vladimir) + +2.1.2 +- fix compilation warnings and errors with TimeCheatingDetector disabled (thx Gary) + +2.1.1 +- fix ObscuredString.GetDecrypted returning value (thx Jose) + +2.1.0 +- add ignoreSetCorrectTime option to TimeCheatingDetector +- add IsStarted property to all detectors +- fix possible wrong TimeCheatingDetector check result (thx esteban16108) + +2.0.6 +- add ACTK_US_EXPORT_COMPATIBLE symbol (see Readme for details) +- fix possible data loss after removing all obscured prefs (thx n0lex) + +2.0.5 +- fix incorrect CodeHashGenerator result Success calculation (thx murat303) +- ignore more standard prefs at the Prefs Editor (thx n0lex) + +2.0.4 +- remove few extra debug logs from Android native plugin +- add code obfuscation and overall code protection notes to the readme + +2.0.3 +- add few API proxies to the ObscuredString for better compatibility +- fix ObscuredString.GetHashCode returned incorrect values (thx quanbp) + +2.0.2 +- fix incorrect ObscuredString.Length property value (thx Davy) + +2.0.1 +- move settings from User to Project space + +2.0.0 +- add new feature: CodeHashGenerator (Unity 2018.1 and newer) + * generate hash for your code in Editor to save in resources or on your server + * generate hash for your code in Runtime for further validation + * hash generation performs on separate thread + * hash Mono, IL2CPP, Android App Bundle builds + * support for Standalone Windows and Android, more to come +- add new feature: SpeedHackProofTime class + * use speed-hack resistant timers to let you ignore speedhack + * proxy to Time.* until speed hack is detected to avoid extra resources waste + * mimic non-fixed Time.* APIs (e.g. time, deltaTime, unscaledTime, etc.) +- Obscured types update: + * make obscured types handle crypto keys fully automatically + * automatically randomize crypto key for each new instance + * close few key-related vulnerabilities + * refactor and update API and docs for consistency + * add GenerateKey() API + * improve ObscuredString performance + * reduce ObscuredString GC allocations by 24% + * fix overridden obscured types indication in Unity 2018.3+ +- Obscured Prefs update: + * make ObscuredPrefs handle crypto keys fully automatically + * change encryption bits with automatic migration from ACTk v1 + * make SetRawValue and GetRawValue to take encrypted key into account + * remove support for pre-1.4.0 prefs migration, use ACTk v1 to migrate + * remove unobscured mode, please use PrefsEditor to view obscured prefs + * refactor and cleanup +- Injection Detector update: + * add dynamic whitelist generation (no more default whitelist) + * dramatically improve injection check performance (Unity 2018.3 and newer) + * include only used assemblies in whitelist (Unity 2018.3 and newer) + * enable Injection Detector feature from the detector's inspector + * fix lots false positives with old default whitelist + * fix detector didn't disable for IL2CPP builds in some cases + * add detection event delegate for addition argument clarity +- Speed Hack Detector update: + * add Threshold property to allow tiny clocks speed difference on different HW + * slightly improve and refactor internals +- Wall Hack Detector update: + * improve warnings and errors UI in inspector + * fix false positive for volumetric fog (volumetric atmospheric scattering in HDRP) + * fix rare false positive for Linear color space in 2017.4.1 and newer + * fix rare false positive for Post-processing stack + * fix rare false positives due to Unity rendering glitches +- Settings update: + * move Settings window to the Unity Editor Preferences section + * add new buttons-icons for quick access to the important related resources + * add IL2CPP section with "Switch to IL2CPP" button for supported platforms + * add "add support to build" toggle in Injection Detector section + * add validation for Injection Detector to have support toggle enabled + * add validation for Wallhack Detector wireframe shader to be always included + * add custom whitelist entries count to the button which opens whitelist editor + * make all ACTk settings to be per-project + * update and refactor UI a bit + * prevent compilation conditional changes while editor is compiling anything + * fix ACTK_IS_HERE state check missed +- add StringToBytes() and BytesToString() helper methods to ObscuredString +- add IsCheatDetected property to all detectors +- add Assembly Definitions +- make all detectors return their instances from StartDetection methods +- make PrefsEditor aware of TimeCheatingDetector service pref +- make PrefsEditor aware of more standard Unity prefs to hide them +- fix and improve lots of other stuff across codebase +- fix various compilation warnings in newest Unity versions +- remove deprecated components from example scenes preventing warnings in 2019.3 +- fix possible data corruption while incrementing ObscuredShort +- fix compilation errors regression in PlayMaker integration package +- update project to Unity 2017.4.1 +- refactor all detectors code to have nicer inheritance +- refactor menu-related code a bit for better readability and clarity +- refactor other minor parts of code base +- remove legacy code + +1.6.7 [Maintenance Update before big 2.0 release!] +- update to Unity 5.6.1 +- improve random key generation performance in some cases +- add few missing assemblies to the default InjectionDetector whitelist +- prevent detectors duplicates on same Game Object +- workaround for Android 4.2.* HEAD request bug +- fix RandomRangeInt can only be called from the main thread in some cases +- fix possible null ref exception in ObscuredPrefs.SetString +- other minor changes + +1.6.6 +- update to Unity 5.6 +- fix Unity 2018.3 project settings open code didn't compiled +- fix ObscuredQuaternion was shown in inspector +- fix ObscuredVector3 and ObscuredQuaternion migration (thx friuns3) +- fix migration of prefab instances in scene after prefabs migration + +1.6.5 +- ObscuredPrefs actions refactored to events to properly allow multiple listeners +- example code refactored and updated +- add support for dynamic assemblies to InjectionDetector (thx Michal) +- fix InjectionDetector whitelist had no some .NET Core assemblies (thx Michal) +- fix InjectionDetector crash when user whitelist has incorrect chars (thx Michal) + +1.6.4 +- celebrating 5 years of free updates! \o/ +- file names and structure refactored - please remove previous version completely! +- TimeCheatingDetector got more attention again (breaks existing APIs): + * core rewritten and now works with WebGL and UWP .NET (thank you Vincent!) + * logic to exclude false positives when user just has wrong time + * now detects both wrong time and actual time cheating with separate thresholds + * few old events deprecated in favor of new more generic CheatChecked event + * fixed possible Sockets errors + * fixed incorrect check interval calculation after resuming unity player +- add static method FromEncrypted() to all obscured variable types +- added new detectors prefab with another layout (each detector on separate object) +- improved UI of settings window +- added few new conditional symbols options for better debug and compatibility +- updated InjectionDetector whitelist to match Unity 2018.3.0b2 +- detectors inspector UI updated to make it easier to read settings +- fixed obscured values initialization in inspector was inconsistent in some cases +- fixed warnings when KeepAlive detectors were started from nested objects +- readme got list of contents with hyperlinks for quicker navigation +- some legacy redundant code removed +- other minor fixes and improvements + +1.6.3 +- SpeedHackDetector on Android improvements: + * now detects root level speed hack on Android 8.0 and newer (no root required) + * more accurate algorythm removing chance of false positives + * resources usage significantly improved +- fixed possible ObscuredCheatingDetector false positive on SetEncryptred() (thx Matt) +- fixed TimeCheatingDetector compilation for the UWP IL2CPP platform + +1.6.2 +- fixed 1.6.1 critical compilation error for Android platform (sorry!) +- fixed missing ObscuredVector2, ObscuredVector3 and ObscuredQuaternion migration +- fixed WallHackDetector false positive when Linear color space is used (thx Fiete) +- fixed wrong plugin path at Unity 2018 packages (thx Fiete) +- fixed compilation error when enabling WALLHACK_DEBUG flag (thx Fiete) +- fixed test scene null reference errors in some cases when cheats are detected +- fixed exception when removing entry at the user-defined Whitelist window (thx Matt) +- other minor fixes +- minor refactorings + +1.6.1 +- SpeedHackDetector now able to detect root-level speed hack on Android (beta) +- organized usings in all code to prevent ambiguity with third-party classes +- TimeCheatingDetector: + * ForceCheckEnumerator method execution slightly changed to improve stability + * added force check examples to the ActTesterGui +- removed some legacy code + +1.6.0 +- TimeCheatingDetector got some more love: + * enabled for Windows Universal Platform with IL2CPP + * stability improvements (thx Nilooo & off3nd) + * Error and CheckPassed events exposed in public API now + * new ErrorKind enum for error events + * added new callback for successful check passes + * interval 0 is now supported for the manual ForceCheck() execution only + * added ForceCheckEnumerator() for yielding from coroutine + * added awaitable ForceCheckTask() for async methods (.NET 4.6+, no WebGL) + * added LastResult and LastError properties +- all Detectors: + * added new AddToSceneOrGetExisting() API (execute from Start phase or later) + * exposed CheatDetected event for subscription + * now you may have multiple listeners for the detection event +- added IComparable implementations to all native obscured types + * now native obscured types are sortable and LINQ-friendly +- exposed double epsilon at the ObscuredCheatingDetector +- added Paste functionality to the prefs editor +- get rid of internals usage at editor scripts (allows asmdef usage) +- improved ObscuredDouble/Float security, migration required (thx off3nd) +- added ObscuredDouble/Float migration from 1.5.2.0 - 1.5.8.0 to 1.6.0+ : + * auto migration at runtime with ACTK_OBSCURED_AUTO_MIGRATION flag + * manual migration at all prefabs and opened scenes via menu commands + * runtime API to migrate values got with GetEncrypted() + * removed legacy pre-1.5.2.0 support for Obscured types migration +- now detector object is automatically selected in scene after creation +- BehaviorDesigner integration package updated: + * added TimeCheatingDetected conditional + * fixed compatibility issues +- PlayMaker integration package updated: + * added TimeCheatingDetected action + * fixed compatibility issues +- updated InjectionDetector whitelist to match Unity 2018.2.0b3 +- switched to X.X.X version tracking format +- fixed compiler errors on UWP platform (thx Wajdi) +- fixed possible incorrect readout of string pref at PrefsEditor +- fixed incorrect behavior when copying unobscured string pref +- fixed incorrect behavior of InjectionDetector in editor in debug mode +- fixed missing Reflection.Obfuscation attributes at TimeCheatingDetector +- fixed compilation flags set/get code to avoid obsolete platforms +- fixed duplicate flags setting for some platforms (cleanup needed) +- fixes and additions in API docs +- minor refactor +- other minor fixes + +1.5.8.0 +- TimeCheatingDetector got some love: + * added new ForceCheck method for manual execution + * added new IsCheckingForCheat property + * first check on Start now removed + * fixed callbacks could run not on the main thread + * improved overall stability of the TimeCheatingDetector (thx Nilo) + * reduced min range for the TimeCheatingDetector interval to 0.1 min +- updated default whitelist of InjectionDetector up to Unity 2018 beta + +1.5.7.0 +- added obscured versions of Vector2Int and Vector3Int from Unity 2017.2+ +- base Unity version increased to 5.1.0f3 +- InjectionDetector whitelist updated up to Unity 2017.3b6 +- added ObscuredDecimalDrawer (thx mcmorry) +- added IsRunning read-only property to all detectors +- added ObscuredByte.EncryptDecrypt(byte[] value) API variants +- added proper help urls for all detectors +- added error callback to the TimeCheatingDetector +- reduced GC allocations count at WallHackDetector for Unity 5.3+ +- removed urls-related code from the examples for better compatibility +- fixed non-blocking error while switching the condition compilation symbols +- minor refactorings +- minor improvements + +1.5.6.1 +- TimeCheatingDetector now uses async methods to reduce main thread locks +- disabled TimeCheatingDetector for Windows Universal Platform +- fixed initialization of Obscured types with SetEncrypted call (thx Keith) +- added version output at the Settings window +- added tooltips to the compilation symbols at the Settings window +- updated InjectionDetector whitelist to match Unity 2017.2.0b4 +- minor improvements +- minor fixes + +1.5.6.0 +- brand new TimeCheatingDetector (needs Internet connection) +- another kind of SpeedHack detection added (thx lol) +- third-party integration packages paths are match ACTk path now +- added switches for all important conditional compilation symbols + to the Settings window +- improved Unity 2017 compatibility + +1.5.5.0 +- menu items migrated to the "Tools > Code Stage > Anti-Cheat Toolkit" +- added new utility script to migrate ObscuredDouble and ObscuredFloat + instances on prefabs when updating from 1.5.1.0 and previous to the + 1.5.2.0 +; you can run it via menu Tools > Code Stage > ACTk > Migrate... +- improved compatibility with Unity 5.5+ +- fixed ObscuredCheatingDetector false positives (huge thx Fiete) +- fixed vulnerability of the obscured types +- fixed ObscuredShort inspector output in Unity 5.0+ +- fixed false cheating detections for obscured types which are able to + show up in the inspector in some cases (thx mrm83) + +1.5.4.0 +- added (x,y) constructor and same Encrypt API to the ObscuredVector2 +- added (x,y,z) constructor and same Encrypt API to the ObscuredVector3 +- added (x,y,z,w) constructor and same Encrypt API to the ObscuredQuaternion +- added new GetDecrypted API to all obscured memory types +- added ObscuredShort inspector output for Unity 5.0+ +- fixed incorrect InjectionDetector execution with argument in callback + +1.5.3.0 +- plugin moved to Plugins folder, please remove previous ACTk version! +- added ObscuredString.Length property for better compatibility +- added ULong support to the ObscuredPrefs +- added Decimal support to the ObscuredPrefs +- added ObscuredUInt inspector output for Unity 5.0+ +- added ObscuredULong inspector output for Unity 5.0+ + +1.5.2.3 +- improved Unity 5.6 compatibility +- added workaround for a Unity bug related to ObscuredDouble on prefabs + +1.5.2.2 +- updated InjectionDetector whitelist up to the Unity 5.5 +- fixed possible data corruption leading to false positives in Obscured types +- updated third-party integration packages to the new APIs +- improved compatibility with Unity 5.5 +- reduced chance of the wrong encrypted pref detection at the prefs editor + +1.5.2.1 +- added back classic parameterless callback support to the InjectionDetector + +1.5.2.0 +- InjectionDetector callbacks now should accept string with detection cause +- improved Window > CodeStage > Anti-Cheat Toolkit menu appearance +- added new Prefs Editor window mode: as an utility window (via new menu item) +- renamed DEBUG conditional symbols to the ACTK_DEBUG to avoid collisions +- added few more standard prefs to the Prefs Editor ignores +- ObscuredFloat GC allocations on initialization removed (thx pachash) +- ObscuredDecimal GC allocations on initialization removed (thx pachash) +- added proper reaction in case obscured data can't be decrypted in Prefs Editor +- fixed "E" button width when adding new pref +- fixed wrong prefs readout in rare cases in Prefs Editor (thx mcmorry) +- fixed "Cutting off characters" error by checking string length (thx mcmorry) +- fixed errors if working from the Plugins folder in Unity 5.3+ (thx demigiant) +- fixed pref deletion wasn't saved on Mac + +1.5.1.0 +- added ObscuredPrefs Editor! + * edit both PlayerPrefs and Obscured prefs in Unity Editor + * encrypt regular PlayerPrefs with configurable encryption key + * decrypt ObscuredPrefs to the regular PlayerPrefs + * search in prefs names + * sort prefs by name, type, or encrypted state + * smart prefs reading progress bar + * shows 50 prefs per page allowing to work with huge collections + * overwrite notice to prevent data loss + * coloration of obscured prefs for easier navigation + * copy prefs to clipboard + * copy raw obscured prefs to clipboard + * works on Win, Mac, Linux +- ObscuredFloat/Double now may be assigned to ObscuredInt +- changed the randomize crypto key logic for all obscured types +- added support for the Unity 5.4 SceneManager.sceneLoaded delegate +- more editor actions are undoable now +- minor ObscuredPrefs API changes + +1.5.0.6 +- SetRawValue and GetRawValue APIs added to the ObscuredPrefs +- fixed possible issues for the Unity 4.7 + +1.5.0.5 +- added warning when new detector self-destroying because of another instance +- added new item to the readme's troubleshooting section +- added explicit operator for the ObscuredFloat > ObscuredDecimal conversion +- fixed InjectionDetecor may not start in Editor in debug mode properly in some cases + +1.5.0.4 +- WallHackDetector: + * slightly decreased amount of the generated garbage + +1.5.0.3 +- WallHackDetector: + * fixed false positive when used in scenes with fog (thx Andrey Pakhomov!) + * minor resources usage optimizations + +1.5.0.2 +- WallHackDetector: + * added extra editor check for the proper Physics Layers settings + * additional debug output +- minor refactorings + +1.5.0.1 +- ObscuredLong can now be exposed to the inspector +- fixed wrong inspector height of the ObscuredVectors in not wide mode + +1.5.0.0 +- Project updated to the Unity 4.6 +- TestScene changed to better represent ACTk features +- Changes for all detectors: + * new Detection Event exposed to the inspector + * new Auto Start option (see readme for details) + * improvements in placement algorithm + * fixed incorrect behavior in rare cases after disabling and re-enabling + * fixed incorrect behavior on scenes switch in some cases + * inspector appearance improvements and fixes +- WallHackDetector changes: + * new "Raycast" option to detect shooting through the walls + * new "Wireframe" option to detect looking through the walls + * new option maxFalsePositives allows to set allowed detections in a row + * now you can separately control Rigidbody and Character Controller modules + * now you can enable and disable all detection modules at any time + * fixes and improvements + * ACTK_WALLHACK_DEBUG conditional introduced, see readme for details +- InjectionDetector changes: + * default whitelist updated (up to Unity 5.3 Beta 2) + * workaround for the IL2CPP bug (Issue ID 711312) + * debug conditionals renamed and their defines removed, use Player Settings + * iOS support removed since this target doesn't allow to inject Assemblies +- Obscured vars changes: + * RandomizeCryptoKey() API introduced to hide from 'unknown value' search + * vars with same value are treated as equal now even if crypto keys differ + * fixed bold texts in the inspectors of the prefabs with obscured vars +- ObscuredPrefs changes: + * API change: DeviceID -> DeviceId + * fixed incorrect Color storage in the unobscuredMode + * fixed DeleteKey removed PlayerPrefs value with enabled preservePlayerPrefs +- ObscuredVector2 now can be exposed to the inspector +- ObscuredVector3 now can be exposed to the inspector +- ObscuredDouble now can be exposed to the inspector in Unity 5 and higher +- ObscuredInt and ObscuredUInt are now able to explicitly cast to each other +- ObscuredVector2 now able to implicitly cast to the Vector3 +- ACTK_EXCLUDE_OBFUSCATION conditional introduced, see readme for details +- PREVENT_READ_PHONE_STATE is ACTK_PREVENT_READ_PHONE_STATE now +- BehaviorDesigner integration package changes: + * RandomizeCryptoKey API for all SharedObscured types + * WallHackDetector added to the example scene + * fixed absent crypto key in the ObscuredPrefs example scene + * fixes in comment docs + * other minor fixes +- PlayMaker integration package changes: + * added keepAlive and autoDispose options to detector actions + * fixes in comment docs +- all detectors are now more correctly placed in the Component menu +- you'll not see example scripts in the Component menu anymore +- fixed possible cs0241 error in xxHash.cs file +- fixed API compatibility issues +- removed obsolete editor code +- all editor code has proper Namespaces now +- all examples code has proper Namespaces now +- numerous optimizations and refactorings +- additions and fixes in readme +- additions and fixes in docs + +1.4.1.1 +- WallHackDetector: additional auto-correction for rigidbody module +- WallHackDetector: service sandbox now survive scene load if detector has Keep Alive enabled +- WallHackDetector: resources usage improvements +- WallHackDetector: initialization performance improvements +- all ACTk windows are moved to Window > Code Stage > Anti-Cheat Toolkit menu item +- fixes in readme + +1.4.1 +- added new WallHackDetector! Detects 2 native hacks: Rigidbody and CharacterController patches +- added new InjectionDetected and WallHackDetected Actions for the PlayMaker +- added new WallHackDetected task to the BehaviorDesigner +- InjectionDetector now detects case when there is 0 assemblies in current domain +- fixes in filenames: ObscuredUint.cs to ObscuredUInt.cs, ObscuredUshort.cs to ObscuredUShort.cs +- minor fixes and refactorings +- fixes in readme + +1.4.0.2 +- fixed ObscuredString editing in multiple objects (thanks VitaMin00) + +1.4.0.1 +- fixed ObscuredPrefs.SetColor for WebPlayer + +1.4.0 +- massive ObscuredPrefs update: + * uint support added + * Rect support added + * overall performance and memory usage improvements + * values are locked to keys now to prevent value swapping + * all service data in final values is hidden now + * hashing algorithm replaced with more secure keeping the same performance + * SetColor/GetColor optimizations + * Float accuracy increased + * Double accuracy increased + * ByteArray support fixed (no more extra length after load) + * PREVENT_READ_PHONE_STATE define introduced to let you remove Android permission if you don't use lockToDevice + * legacy ObscuredPlayerPrefs support removed (use previous ACTk version to read them) + * ForceDeviceID() method replaced with DeviceID property (now you can retrieve current device ID as well) + * format improvements allowing to easily change it with backwards compatibility + * refactorings +- ObscuredString.EncryptDecrypt() optimization (affects all Get/Set methods in ObscuredPrefs) +- disabling and enabling started detectors now should pause and resume them +- Anti-Cheat Toolkit Detectors object will self-destroy now ignoring attached scripts and nested objects +- fixed disabled detectors behavior on StartDetection() +- fixed issues with casting obscured vars from objects in the Behavior Designer package +- fixes in readme +- fixes in docs +- other minor fixes + +1.3.5 +- Anti-Cheat Toolkit now fully supports Opsive Behavior Designer, see readme for details (thanks Justin Mosiman!) +- added new ObscuredPrefsSetNewCryptoKey Action for PlayMaker +- added DetectorsExample scene into the PlayMaker package with SpeedHackDetector usage example +- added ObscuredPrefsExample scene into the PlayMaker package with simple ObscuredPrefs usage example +- fixed obscured vars initialization via SetEncrypted() +- serialization support added to: ObscuredQuaternion, ObscuredVector3 & ObscuredVector2 +- redundant alteration callback logic removed from ObscuredPrefs +- removed deprecated code from ObscuredQuaternion, ObscuredVector3 & ObscuredVector2 +- plugin abbreviation changed from ACT to ACTk +- minor fixes + +1.3.4 +- added ObscuredPrefs actions for PlayMaker (thanks kreischweide) +- added SpeedHackDetected action for PlayMaker (thanks kreischweide) +- added Vector2, Quaternion, Color support to the ObscuredPrefs +- detectors keepAlive behavior fixed and improved +- new detectors prefab +- increased detectors placement flexibility: you may put all detectors at one GameObject now +- all detectors will be added to the single Game Object when instantiating from code +- detectors Instance property reworked (can be null now) +- fixed ObscuredCheatingDetector values were not tunable in inspector +- fixed iPhone.vendorIdentifier error on Unity 5 iOS target platform (thanks Mike Messer) +- obscured types now implement IFormattable for better compatibility +- added more tool-tips for detectors +- added troubleshooting section to the readme +- few fixes and additions in readme & API docs +- minor refactoring in ObscuredPrefs + +1.3.3 +- Flash Player support deprecated, lot of ugly code removed +- Unity 5 fully supported +- plugin project updated to the Unity 4.5 (still can work in earlier Unity versions with few restrictions) +- obscured fields are now bold in inspector if values changed in prefab instance (mimics regular behavior) +- minor refactorings +- some fixes and additions in the readme + +1.3.2.1 +- optimized inspector exposition for supported obscured types +- fixed array elements names while exposing ObscuredString[] in inspector +- fixed ObscuredString truncation while being shown at inspector in some cases (thanks Stefan Laubenberger) + +1.3.2 +- ObscuredVector2, ObscuredVector3 and ObscuredQuaternion accuracy increased (consistent on all platforms now) +- added epsilons for ObscuredFloat, Obscured vectors and ObscuredQuaternion in ObscuredCheatDetector +- fixed cheating detection false positives for Obscured vectors and ObscuredQuaternion (thanks Capital j Media) +- fixed ObscuredInt returned 0 in case value matched crypto key regression +- minor optimizations and refactorings + +1.3.1 +- ObscuredBool inspector support added (requires Unity 4.5) +- new public API for all basic Obscured types: ApplyNewCryptoKey(), see docs for more details +- Significant changes in SpeedHackDetector: + * Cool Down system introduced. Read more in pdf and "coolDown" field API docs (thanks Cliff Cawley) + * detection checks period is not affected by speed hack anymore (now it uses system date timer) + * fixed speed hack wasn't detected in some cases + * fixed false positives in some cases + * fixed extra calculations on first detection check in the SpeedHackDetector + * fixed incorrect datetime change detection + * fixed continuous detects after first detect even if speed hack was removed (thanks Cliff Cawley) + * speed hack detection log message now appears in debug builds only + * application pause handled correctly now +- all basic Obscured types are serializable now (only binary serialization supported) +- ObscuredBool cheating detection is now supported in the Flash Player. +- fixed ObscuredInt default value issues +- fixed null reference error while using exposed ObscuredFloat fields to the inspector without default value +- fixed incorrectly decrypted ObscuredString values in inspector when used without default values +- fixed cheating detection false positives for Obscured variables while being exposed to the editor +- fixed possible cheating detection false positives for ObscuredVector2, ObscuredVector3 and ObscuredQuaternion +- fixed GetEncrypted() after SetNewCryptoKey() in ObscuredString didn't counted new crypto key +- removed redundant [InitializeOnLoad] attribute from ActPostprocessor +- minor refactorings in all Obscured types +- fixes and additions in the docs + +1.3.0 +- ObscuredString fields are now editable from inspector +- ObscuredInt and ObscuredFloat fields are now editable from inspector (Unity 4.5 or higher required) + * in case int->ObscuredInt \ float->ObscuredFloat replacement, old values set in inspector will be reset to defaults! + * experimental inspector support for the obscured structs instances, report any bugs please +- ObscuredCheatingDetector implemented + * central detector for all Obscured types (except ObscuredPrefs) cheating detection + * replacement for legacy onCheatingDetected Action callback +- Injection Detector user-defined Whitelist Editor implemented + * allows gather assembly data both from files and manually (for assemblies made in realtime) +- ObscuredPrefs.ForceDeviceID(string) method introduced + * useful if you have server-side authorization, especially on iOS (we have no reliable way to get device ID there) +- Injection Detector data file is restored now if it was accidentally removed +- public API StopMonitoring was renamed to the StopDetection for all detectors +- most of Vector3 operators are now supported by ObscuredVector3 +- fixed possible false positives in Speed Hack Detector caused by system time / date change +- fixed exception in ActPostprocessor while trying to write into the read-only file (thanks Sebastiano Mandalà) +- fixed possible false positives for ObscuredVector3, ObscuredVector2, ObscuredQuaternion cheating detection. +- added ability to force Injection Detector data collection for unsupported platforms for debugging +- Injection Detector will be re-enabled after switching from unsupported target if it was enabled previously +- significant refactorings in the detectors code +- service data cleanup code simplified +- improved removing of obsolete editor prefs used by ACT +- refactorings in the Editor scripts and file structure (remove prev version before updating to avoid collisions!) +- fixed possible name conflicts: MenuItem, Action +- minor fixes and optimizations +- minor fixes in documentation + +1.2.9 +- cheating detection added to the ObscuredQuaternion, ObscuredVector3, ObscuredVector2, ObscuredString +- fixed rare critical bug in ++ and -- operators of some obscured types leading to false detections (huge thanks redux!) +- fixed ObscuredPrefs.HasKey() and ObscuredPrefs.DeleteKey() were not count regular PlayerPrefs keys (thanks Sashko) +- fixed possible access issue while reading from AllowedAssemblies.bytes file in editor (thanks Sabastiano) +- fixed possible fndid file corruption leading to the false positives in Injection Detector (thanks Sabastiano) +- access to the x, y, z fields was added to the ObscuredVector3 (access by index was implemented as well) +- access to the x and y fields was added to the ObscuredVector2 (access by index was implemented as well) +- DetectorsUsageExample script was moved from Anti-Cheat Toolkit Detectors prefab to the separate GameObject +- minor fixes in the API docs + +1.2.8 +- New obscured types with cheating detection implemented + * ObscuredSByte + * ObscuredChar + * ObscuredDecimal (Flash Player is not supported, use ObscuredFloat instead) + * ObscuredULong +- cheating detection added to these existing obscured types + * ObscuredUInt + * ObscuredLong + * ObscuredDouble + * ObscuredBool (except Flash Player: bug in exported pool manager code doesn't allow to use nullables) +- minor public API changes for few obscured types +- fixed SpeedHackDetector error while playing test scene in editor with Flash Player target +- fixed possible false positives of SpeedHackDetector in Flash Player +- fixed Flash Player implementation of the ObscuredUShort.GetHashCode() +- another minor improvements in flash implementation of SpeedHackDetector +- other minor fixes and optimizations + +1.2.7 +- InjectionDetector introduced + * allows to detect if someone injects any managed dll into your app +- ObscuredShort and ObscuredUShort with cheating detection implemented +- IntegrityChecker removed +- significant changes and fixes in API documentation (should be prettier and more detailed now) +- DeviceLockLevel enum moved into the ObscuredPrefs class, thus now it should be reached as ObscuredPrefs.DeviceLockLevel +- SpeedHackDetector's StartMonitoring methods were renamed to StartDetection ones +- minor improvements in flash implementation of SpeedHackDetector +- ObscuredUint was renamed to ObscuredUInt +- minor files structure changes, please, make clean update (completely remove previous version before updating) +- minor fixes and optimizations + +1.2.6u2 +- fixed possible false positives of cheating detection in Obscured types +- minor API docs fixes + +1.2.6u1 +- extra traces in ActionScript code were commented out + +1.2.6 +- flash build support for SpeedHackDetector implemented +- ObscuredVector2 and ObscuredQuaternion implemented +- cheating detection added to the ObscuredByte +- SpeedHackDetector now awaits Action delegate instead of MonoBehaviour and method name. Please, read API docs for details +- ObscuredPrefs.readForeignSaves field introduced + * allows to read saves locked to other device and onPossibleForeignSavesDetected action still will be fired +- deprecated PlayerPrefsObscured was removed completely, use ObscuredPrefs instead +- ObscuredFloat slightly optimized +- ObscuredDouble slightly optimized +- all default arguments were replaced by methods overloading for additional compatibility with UnityScript (again) +- minor fixes in API docs + +1.2.5u1 +- SpeedHackDetector.Instance is now public and may be used to set interval, autoDispose, etc. from code. + +1.2.5 +- SpeedHackDetector introduced! Allows you to react on Cheat Engine's speed hack + * some other speed hack tools may be detected too + * use GameObject->Create Other->Code Stage->Speed Hack Detector menu item to add detector in scene + * use any public SpeedHackDetector API to automatically add it to scene +- added cheating detection to the ObscuredInt and ObscuredFloat (use Obscured*.onCheatingDetected) +- migration from PlayerPrefs to ObscuredPrefs became super easy: just replace PlayerPrefs with ObscuredPrefs + and read \ write any data as usual, no more manual PlayerPrefs to ObscuredPrefs conversion! + * all data saved with regular PlayerPrefs will be automatically encrypted with ObscuredPrefs on read and + original PlayerPrefs data will be deleted + * Set ObscuredPrefs.preservePlayerPrefs to true to prevent original PlayerPrefs data deletion +- migration from legacy PlayerPrefsObscured to ObscuredPrefs became smoother: data, written with PlayerPrefsObscured + now converts to the new format while readed with ObscuredPrefs (previously - old legacy keys were left untouched + after migration). +- ObscuredPrefs.unobscuredMode implemented + * allows to write all data unobscured, for testing purposes + * thus it works in Editor only + * breaks PlayerPrefs to ObscuredPrefs migration (reminder: in Editor) +- ObscuredVector3 and ObscuredBool implemented! +- data saved in TestScene now cleans up on application quit +- ObscuredPrefs overfill in Web Player no longer breaks entire game process (and logs error in such case) +- added selftests and performance tests code to the example scene (disabled by default) for debugging and + making wise choices ;) +- ObscuredString default crypto key was changed. Set new key to 4444 before using SetEncrypted() to set data got with + GetEncrypted in previous versions. +- fixed compilation error of WP8 build +- fixed initialization of some Obscured types +- fixed ObscuredString equality operator implementation +- minor fixes +- minor docs fixes + +1.2.0 +- project updated to Unity 4.2.2 +- new ObscuredPrefs introduced instead of old PlayerPrefsObscured + * PlayerPrefsObscured is no more supported, please, make sure to save all your new data using ObscuredPrefs + * all data saved with ObscuredPrefs will not be accessible using deprecated PlayerPrefsObscured! + * all data saved with deprecated PlayerPrefsObscured is accessible with ObscuredPrefs automatically as fallback + (will be removed in future) + * new flexible lock data to device feature introduced, read more in api docs and readme + * now saved data may be recovered in emergency cases (like device ID change after updating from iOS 6 to iOS 7) + * attempt to prevent device id change after iOS6 to iOS7 update (works in some cases only) + * key is now encrypted with common encryptionKey (previously default key for ObscuredString was used) + * accessing data saved with regular PlayerPrefs now generates warning with additional information + * saves alteration can be detected now, use ObscuredPrefs.onAlterationDetected (see ObscuredPrefsTest) + * foreign saves usage detection added, use ObscuredPrefs.onPossibleForeignSavesDetected (see ObscuredPrefsTest) + * added example of storing encryption key outside of the IL bytecode (increasing its security level) + (see ObscuredPrefsTest) + * added support of these types: long, bool, byte[], Vector3 +- ObscuredByte and ObscuredLong added +- equality operations (==, !=, .Equals()) are now supported in all simple Obscured types +- all default arguments were replaced by methods overloading for additional compatibility with UnityScript +- other minor fixes +- few fixes in docs + +1.1.0u1 +- fixed ObscuredDouble not worked correctly +- fixed link to ObscuredDouble missed in object Tester in the test scene + +1.1.0 +- no more dlls, plugin now comes with full source code included! +- Yey, Flash Player exporter support is back! :D IntegrityChecker, ObscuredDouble and + PlayerPrefsObscured.lockToDevice are not supported there though. +- added increment and decrement operators support to the numeric obscured types (thanks Yuri Saveliev) +- added ObscuredDouble! Not supported in FlashPlayer (use ObscuredFloat instead)! (thanks Andriy Pidvirnyy) +- added correct analogues of toString() methods to some of the Obscured types +- added PlayerPrefsObscured.ForceLockToDeviceInit() method to call device ID obtanation (noticably slow at first + call) process at desirable time (at splash screen time for example) +- added initial support for Windows Store (Metro) Apps (needs testing) +- added initial support for Windows Phone 8 (needs testing, thanks friuns3) + +- PlayerPrefsObscured.lockToDevice field is now property, so please use PlayerPrefsObscured.LockToDevice instead. + Sorry for inconvenience. +- removed unsafe code in ObscuredFloat +- fixed possible placement in memory not obscured float while using ObscuredFloat, oops :P +- fixed possible data loss when using values equal to the crypto keys +- attempt to fix "get_deviceUniqueIdentifier can only be called from the main thread" error (thanks ecc83) +- fixed issue with different line endings on different platforms in IntegrityChecker causing it to think + assemblies are not valid +- fixed incorrect line breaks in the xml docs +- assemblies signing now can't be enabled on known unsupported platforms +- assemblies signing will be disabled after switching to the known unsupported platform +- assemblies signing will be disabled if Stripping Level in Player Settings is not set to "Disabled" +- changed PlayerPrefsObscured default encryption key. Use SetNewCryptoKey(e806f69e7aea3ee30fe27a6abfae967f) to + read any data saved in previous ACT version with default key. +- docs were fixed a bit +- removed obsolete methods in PlayerPrefsObscured +- minor fixes + + +1.0.1.2 +- fixed .meta files handling +- moved Anti-Cheat Toolkit/Options menu item to the Window/Anti-Cheat Toolkit/Options +- moved plugin into CodeStage directory (to compact placing of any future plugins I'll release) +- reduced ObscuredInt default key length +- attempt to fix async assemblies reloading issue + + +1.0.1.1 +- Added assemblies signing process duration estimation +- Fixed issues with Anti-Cheat Toolkit .dll import in Unity 4.x + + +1.0.1.0 +- Added Assemblies signing functionality * EXPERIMENTAL * +- Fixed web player detection, now ObscuredFloat can be used in static conditions (thanks Andriy Pidvirnyy) + + +1.0.0.9 +- Fixed data loss in PlayerPrefsObscured (use Get*Deprecated to read data saved with ACT 1.0.0.8) + + +1.0.0.8 +- PlayerPrefsObscured now able to lock saved data to the current device. See PlayerPrefsObscured.lockToDevice + field description in API docs. +- Improved PlayerPrefsObscured stability and obscuration strength (use Get*Deprecated() methods to load data, + saved with ACT 1.0.0.6 or earlier) +- PlayerPrefsObscured now has own encryption key. Use PlayerPrefsObscured.SetNewCryptoKey() to change it from + default value. +- Created home page for ACT: https://codestage.net/uas/actk/ + + +1.0.0.7 +- Fixed error in ObscuredString (now it works in WebPlayer without errors). +- Fixed error in ObscuredFloat (now it works in WebPlayer without errors). +- ObscuredFloat is memory wiser now. +- ObscuredFloat.SetNewCryptoKey() accepts int now (was long). +- Added changelog :) \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md.meta new file mode 100644 index 0000000..ce7937c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md.meta @@ -0,0 +1,6 @@ +fileFormatVersion: 2 +guid: a707e4914fc9f014790c02a3cd0b455d +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor.meta new file mode 100644 index 0000000..c8042f7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ac5220baa6a51bb47a5c640ddf6c0ce8 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef new file mode 100644 index 0000000..77ab57b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef @@ -0,0 +1,23 @@ +{ + "name": "ACTk.Editor", + "references": [ + "ACTk.Runtime" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.modules.audio", + "expression": "", + "define": "UNITY_AUDIO_MODULE" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef.meta new file mode 100644 index 0000000..cea2982 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 8ef82b58ed1acc8419a02b8a05286620 +timeCreated: 1554196096 +licenseType: Store +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts.meta new file mode 100644 index 0000000..5f36054 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1ff6bc3cba85fba4e922af0d4a624023 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs new file mode 100644 index 0000000..0f47166 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs @@ -0,0 +1,48 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System.IO; + using System.Linq; + using UnityEngine; + + internal static class ACTkEditorConstants + { + internal static class Conditionals + { + public const string WallhackLinkXML = "ACTK_WALLHACK_LINK_XML"; + public const string ExcludeObfuscation = "ACTK_EXCLUDE_OBFUSCATION"; + public const string PreventReadPhoneState = "ACTK_PREVENT_READ_PHONE_STATE"; + public const string PreventInternetPermission = "ACTK_PREVENT_INTERNET_PERMISSION"; + public const string ObscuredAutoMigration = "ACTK_OBSCURED_AUTO_MIGRATION"; + public const string ThirdPartyIntegration = "ACTK_IS_HERE"; + public const string UsExportCompatible = "ACTK_US_EXPORT_COMPATIBLE"; + public const string NewtonsoftJson = "ACTK_NEWTONSOFT_JSON"; + + public const string InjectionDebug = "ACTK_INJECTION_DEBUG"; + public const string InjectionDebugVerbose = "ACTK_INJECTION_DEBUG_VERBOSE"; + public const string InjectionDebugParanoid = "ACTK_INJECTION_DEBUG_PARANOID"; + public const string WallhackDebug = "ACTK_WALLHACK_DEBUG"; + public const string DetectionBacklogs = "ACTK_DETECTION_BACKLOGS"; + public const string GenericDevLogs = "ACTK_DEV_LOGS"; + } + + public const string SettingsProviderPath = "Code Stage/Anti-Cheat Toolkit"; + public const string MenuPath = "Code Stage/🕵 Anti-Cheat Toolkit/"; + public const string ToolsMenuPath = "Tools/" + MenuPath; + public const string GameObjectMenuPath = "GameObject/Create Other/" + MenuPath; + + public static readonly string ProjectFolder = Path.GetFullPath(Path.Combine(Application.dataPath, "../")); + public static readonly string ProjectTempFolder = Path.Combine(ProjectFolder, "Temp"); + public static readonly string LinkXmlPath = Path.Combine(ProjectTempFolder, "actk-link.xml"); + public static readonly string ProjectLibraryFolder = Path.Combine(ProjectFolder, "Library"); + public static readonly string ProjectSettingsFolder = Path.Combine(ProjectFolder, "ProjectSettings"); + public static readonly string AssetsFolder = Path.Combine(ProjectFolder, "Assets"); + + public static readonly string[] HexTable = Enumerable.Range(0, 256).Select(v => v.ToString("x2")).ToArray(); + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs.meta new file mode 100644 index 0000000..da039ff --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a9ee7d4a58674ac69c27bc7c29417309 +timeCreated: 1552925230 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs new file mode 100644 index 0000000..77295cd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs @@ -0,0 +1,41 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using UnityEditor; + using UnityEngine; + + ///

+ /// Use it to guess current directory of the Anti-Cheat Toolkit. + /// + public class ACTkMarker : ScriptableObject + { + /// + /// Returns raw path of the ACTkMarker script for further reference. + /// + /// Path of the ACTkMarker ScriptableObject asset. + public static string GetAssetPath() + { + string result; + + var tempInstance = CreateInstance(); + var script = MonoScript.FromScriptableObject(tempInstance); + if (script != null) + { + result = AssetDatabase.GetAssetPath(script); + } + else + { + result = AssetDatabase.FindAssets("ACTkMarker")[0]; + result = AssetDatabase.GUIDToAssetPath(result); + } + + DestroyImmediate(tempInstance); + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs.meta new file mode 100644 index 0000000..f3981f5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 00b850c709170d1469bcd89e6f80b16c +timeCreated: 1557660868 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs new file mode 100644 index 0000000..0a2b69a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs @@ -0,0 +1,134 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using Detectors; + using UnityEditor; + + using Common; + using PostProcessors; + using UnityEngine; + using Processors; + + internal static class ACTkMenuItems + { + // --------------------------------------------------------------- + // Main menu items + // --------------------------------------------------------------- + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Settings...", false, 100)] + private static void ShowSettingsWindow() + { + ACTkSettings.Show(); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Injection Detector Whitelist Editor...", false, 1000)] + private static void ShowAssembliesWhitelistWindow() + { + UserWhitelistEditor.ShowWindow(); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Calculate external build hashes", false, 1200)] + private static async void HashExternalBuild() + { + var buildHashes = await CodeHashGeneratorPostprocessor.CalculateExternalBuildHashesAsync(null, true); + if (buildHashes == null || buildHashes.FileHashes.Count == 0) + { + Debug.LogError(ACTk.LogPrefix + "External build hashing was not successful. " + + "See previous log messages for possible details."); + } + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Configure proguard-user.txt", false, 1201)] + private static void CheckProGuard() + { + BuildPreProcessor.CheckProGuard(true); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types on prefabs...", false, 1500)] + private static void MigrateObscuredTypesOnPrefabs() + { + MigrateUtils.MigrateObscuredTypesOnPrefabs("ObscuredFloat", "ObscuredDouble", "ObscuredVector2", "ObscuredVector3", "ObscuredQuaternion"); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types in opened scene(s)...", false, 1501)] + private static void MigrateObscuredTypesInScene() + { + MigrateUtils.MigrateObscuredTypesInScene("ObscuredFloat", "ObscuredDouble", "ObscuredVector2", "ObscuredVector3", "ObscuredQuaternion"); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in assets...", false, 1500)] + private static void ValidateObscuredTypesInAssets() + { + ObscuredTypesValidator.ValidateProjectAssets(); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in opened scene(s)...", false, 1501)] + private static void ValidateObscuredTypesInOpenedScenes() + { + ObscuredTypesValidator.ValidateOpenedScenes(); + } + + /* will be needed when obsolete string internals will be deprecated along with automatic migration */ + + //[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate ObscuredString on prefabs...", false, 1600)] + private static void MigrateObscuredStringOnPrefabs() + { + MigrateUtils.MigrateObscuredTypesOnPrefabs("ObscuredString"); + } + + //[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate ObscuredString in opened scene(s)...", false, 1601)] + private static void MigrateObscuredStringInScene() + { + MigrateUtils.MigrateObscuredTypesInScene("ObscuredString"); + } + + // --------------------------------------------------------------- + // GameObject menu items + // --------------------------------------------------------------- + + [MenuItem(ACTkEditorConstants.GameObjectMenuPath + "All detectors", false, 0)] + private static void AddAllDetectorsToScene() + { + AddInjectionDetectorToScene(); + AddObscuredCheatingDetectorToScene(); + AddSpeedHackDetectorToScene(); + AddWallHackDetectorToScene(); + AddTimeCheatingDetectorToScene(); + } + + [MenuItem(ACTkEditorConstants.GameObjectMenuPath + InjectionDetector.ComponentName, false, 1)] + private static void AddInjectionDetectorToScene() + { + DetectorTools.SetupDetectorInScene(); + } + + [MenuItem(ACTkEditorConstants.GameObjectMenuPath + ObscuredCheatingDetector.ComponentName, false, 1)] + private static void AddObscuredCheatingDetectorToScene() + { + DetectorTools.SetupDetectorInScene(); + } + + [MenuItem(ACTkEditorConstants.GameObjectMenuPath + SpeedHackDetector.ComponentName, false, 1)] + private static void AddSpeedHackDetectorToScene() + { + DetectorTools.SetupDetectorInScene(); + } + + [MenuItem(ACTkEditorConstants.GameObjectMenuPath + WallHackDetector.ComponentName, false, 1)] + private static void AddWallHackDetectorToScene() + { + DetectorTools.SetupDetectorInScene(); + } + + [MenuItem(ACTkEditorConstants.GameObjectMenuPath + TimeCheatingDetector.ComponentName, false, 1)] + private static void AddTimeCheatingDetectorToScene() + { + DetectorTools.SetupDetectorInScene(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs.meta new file mode 100644 index 0000000..1b58284 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e10289b3bdb7db64c8f2c624b337d331 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs new file mode 100644 index 0000000..110c241 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs @@ -0,0 +1,10 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("CodeStage.ACTk.Service")] +[assembly: InternalsVisibleTo("CodeStage.ACTk.Tests.Editor")] \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs.meta new file mode 100644 index 0000000..ff505db --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1cc293465f841498ad940f7813ccedd +timeCreated: 1588809689 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common.meta new file mode 100644 index 0000000..3d9e444 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d9e6164ee563b444d87cbe3437d6012a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools.meta new file mode 100644 index 0000000..bc2a57b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 14398b80f1b8c7e4ea405ef47a17e38c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs new file mode 100644 index 0000000..a3bb867 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs @@ -0,0 +1,198 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.EditorCommon.Tools +{ + using System; + using UnityEditor; + using UnityEngine; + + internal static class CSColorTools + { + internal enum ColorKind + { + Green, + Red, + Purple + } + + public const string GreenHex = "02C85F"; + public const string GreenDarkHex = "02981F"; + public const string PurpleHex = "A76ED1"; + public const string PurpleDarkHex = "7030A0"; + public const string RedHex = "FF4040"; + public const string RedAltHex = "FF6060"; + public const string RedDarkHex = "FF1010"; + public const string BrightGreyHex = "E5E5E5"; + + public readonly static Color32 Green = new Color32(2, 200, 95, 255); + public readonly static Color32 GreenDark = new Color32(2, 152, 31, 255); + public readonly static Color32 Purple = new Color32(167, 110, 209, 255); + public readonly static Color32 PurpleDark = new Color32(112, 48, 160, 255); + public readonly static Color32 RedAlt = new Color32(255, 96, 96, 255); + public readonly static Color32 RedDark = new Color32(255, 16, 16, 255); + public readonly static Color32 BrightGrey = new Color32(229, 229, 229, 255); + + public static string EditorGreenHex + { + get + { + return EditorGUIUtility.isProSkin ? GreenHex : GreenDarkHex; + } + } + + public static string EditorPurpleHex + { + get + { + return EditorGUIUtility.isProSkin ? PurpleHex : PurpleDarkHex; + } + } + + public static string EditorRedHex + { + get + { + return EditorGUIUtility.isProSkin ? RedAltHex : RedDarkHex; + } + } + + public static Color EditorGreen + { + get + { + return EditorGUIUtility.isProSkin ? Green : GreenDark; + } + } + + public static Color EditorPurple + { + get + { + return EditorGUIUtility.isProSkin ? Purple : PurpleDark; + } + } + + public static Color EditorRed + { + get + { + return EditorGUIUtility.isProSkin ? RedAlt : RedDark; + } + } + + public static Color DimmedColor + { + get + { + return ChangeAlpha(GUI.skin.label.normal.textColor, 150); + } + } + + public static Color BrightGreyDimmed + { + get + { + return ChangeAlpha(BrightGrey, 150); + } + } + + public static Color GreenColor + { + get + { + return LerpToGreen(GUI.skin.label.normal.textColor, 0.3f); + } + } + + public static Color RedColor + { + get + { + return LerpToRed(GUI.skin.label.normal.textColor, 0.3f); + } + } + + public static Color BackgroundGreenTint + { + get + { + return EditorGUIUtility.isProSkin ? new Color32(0, 255, 0, 150) : new Color32(0, 255, 0, 30); + } + } + + public static Color BackgroundRedTint + { + get + { + return EditorGUIUtility.isProSkin ? new Color32(255, 0, 0, 150) : new Color32(255, 0, 0, 30); + } + } + + public static string WrapBool(bool value) + { + return WrapString(value.ToString(), value ? ColorKind.Green : ColorKind.Red); + } + + public static string WrapString(string inputGood, string inputBad, bool good) + { + return WrapString(good ? inputGood : inputBad, good ? ColorKind.Green : ColorKind.Red); + } + + public static string WrapString(string input, bool good) + { + return WrapString(input, good ? ColorKind.Green : ColorKind.Red); + } + + public static string WrapString(string input, ColorKind colorKind) + { + switch (colorKind) + { + case ColorKind.Green: + return WrapString(input, EditorGreenHex); + case ColorKind.Red: + return WrapString(input, EditorRedHex); + case ColorKind.Purple: + return WrapString(input, EditorPurpleHex); + default: + throw new ArgumentOutOfRangeException("colorKind", colorKind, null); + } + } + + public static string WrapString(string input, Color color) + { + var colorString = ColorUtility.ToHtmlStringRGBA(color); + return WrapString(input, colorString); + } + + // color argument should be in rrggbbaa format or match standard html color name, without '#' + public static string WrapString(string input, string color) + { + return "" + input + ""; + } + + public static Color32 LerpToRed(Color32 inValue, float greenAmountPercent) + { + return Color.Lerp(inValue, Color.red, greenAmountPercent); + } + + public static Color32 LerpToGreen(Color32 inValue, float greenAmountPercent) + { + return Color.Lerp(inValue, Color.green, greenAmountPercent); + } + + public static Color32 LerpToYellow(Color32 inValue, float greenAmountPercent) + { + return Color.Lerp(inValue, Color.yellow, greenAmountPercent); + } + + private static Color32 ChangeAlpha(Color32 inValue, byte alphaValue) + { + inValue.a = alphaValue; + return inValue; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs.meta new file mode 100644 index 0000000..c2e8cd7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b18cacce4700f664e8a56903e2090843 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs new file mode 100644 index 0000000..545a28b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs @@ -0,0 +1,35 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.EditorCommon.Tools +{ + using UnityEngine; + + internal static class CSEditorIcons + { + public static Texture AssetStore { get { return CSTextureLoader.GetIconTexture("Asset Store", ImageKind.InternalIcon); } } + public static Texture Error { get { return CSTextureLoader.GetIconTexture("console.erroricon", ImageKind.InternalIcon); } } + public static Texture ErrorSmall { get { return CSTextureLoader.GetIconTexture("console.erroricon.sml", ImageKind.InternalIcon); } } + public static Texture Favorite { get { return CSTextureLoader.GetIconTexture("Favorite", ImageKind.InternalIcon); } } + public static Texture FavoriteIcon { get { return CSTextureLoader.GetIconTexture("Favorite Icon", ImageKind.InternalIcon); } } + public static Texture FilterByType { get { return CSTextureLoader.GetIconTexture("FilterByType", ImageKind.InternalIcon); } } + public static Texture Folder { get { return CSTextureLoader.GetIconTexture("Folder Icon", ImageKind.InternalIcon); } } + public static Texture GameObject { get { return CSTextureLoader.GetTypeImage(typeof(GameObject)); } } + public static Texture Help { get { return CSTextureLoader.GetIconTexture("_Help", ImageKind.InternalIcon); } } + public static Texture HierarchyView { get { return CSTextureLoader.GetIconTexture("UnityEditor.SceneHierarchyWindow", ImageKind.InternalIcon); } } + public static Texture Info { get { return CSTextureLoader.GetIconTexture("console.infoicon", ImageKind.InternalIcon); } } + public static Texture InfoSmall { get { return CSTextureLoader.GetIconTexture("console.infoicon.sml", ImageKind.InternalIcon); } } + public static Texture Inspector { get { return CSTextureLoader.GetIconTexture("UnityEditor.InspectorWindow", ImageKind.InternalIcon); } } + public static Texture Prefab { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.prefab"); } } + public static Texture ProjectView { get { return CSTextureLoader.GetIconTexture("Project", ImageKind.InternalIcon); } } + public static Texture Scene { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.unity"); } } + public static Texture Script { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.cs"); } } + public static Texture Search { get { return CSTextureLoader.GetIconTexture("Search Icon", ImageKind.InternalIcon); } } + public static Texture Settings { get { return CSTextureLoader.GetIconTexture("Settings", ImageKind.InternalIcon); } } + public static Texture Warn { get { return CSTextureLoader.GetIconTexture("console.warnicon", ImageKind.InternalIcon); } } + public static Texture WarnSmall { get { return CSTextureLoader.GetIconTexture("console.warnicon.sml", ImageKind.InternalIcon); } } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs.meta new file mode 100644 index 0000000..6354517 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0262830fc851659438acad57bb020619 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs new file mode 100644 index 0000000..8d9de40 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs @@ -0,0 +1,27 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.EditorCommon.Tools +{ + using System.IO; + + internal static class CSFileTools + { + public static void DeleteFile(string path) + { + if (!File.Exists(path)) return; + RemoveReadOnlyAttribute(path); + File.Delete(path); + } + + private static void RemoveReadOnlyAttribute(string filePath) + { + var attributes = File.GetAttributes(filePath); + if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) + File.SetAttributes(filePath, attributes & ~FileAttributes.ReadOnly); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs.meta new file mode 100644 index 0000000..438b4a3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47e5a8270a3c78c4191b11b026ac7c2d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs new file mode 100644 index 0000000..097ef93 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs @@ -0,0 +1,114 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.EditorCommon.Tools +{ + using System; + using System.Collections.Generic; + using System.IO; + using UnityEditor; + using UnityEngine; + + internal enum ImageKind + { + External, + InternalTexture, + InternalIcon + } + + internal static class CSTextureLoader + { + public static string ExternalTexturesFolder { get; set; } + public static string LogPrefix { get; set; } + + private static readonly Dictionary CachedTextures = new Dictionary(); + + public static Texture GetTexture(string fileName) + { + return GetTexture(fileName, false); + } + + public static Texture GetIconTexture(string fileName, ImageKind kind = ImageKind.External) + { + return GetTexture(fileName, true, kind); + } + + private static Texture GetTexture(string fileName, bool icon, ImageKind kind = ImageKind.External) + { + Texture result; + var isDark = EditorGUIUtility.isProSkin; + + var textureName = fileName; + if (isDark) + textureName = "d_" + textureName; + + if (CachedTextures.ContainsKey(textureName)) + { + result = CachedTextures[textureName]; + } + else + { + var path = fileName; + + if (kind == ImageKind.External) + { + fileName = textureName; + path = Path.Combine(ExternalTexturesFolder, "Textures"); + + if (icon) + path = Path.Combine(path, "Icons"); + + path = Path.Combine(path, fileName); + if (!File.Exists(Path.GetFullPath(path)) && !Path.HasExtension(path)) + { + path = Path.ChangeExtension(path, "png"); + } + + if (!File.Exists(Path.GetFullPath(path))) + { + Debug.LogWarning("Couldn't find icon " + fileName + " at path " + path); + return null; + } + } + + switch (kind) + { + case ImageKind.External: + result = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D; + break; + case ImageKind.InternalTexture: + result = EditorGUIUtility.FindTexture(path); + break; + case ImageKind.InternalIcon: + result = EditorGUIUtility.IconContent(path).image; + break; + default: + throw new ArgumentOutOfRangeException("kind", kind, null); + } + + if (result == null) + Debug.LogError(LogPrefix + "Some error occurred while looking for image\n" + path); + else + CachedTextures[textureName] = result; + } + return result; + } + + public static Texture GetTypeImage(Type type) + { + var key = type.ToString(); + if (CachedTextures.ContainsKey(key)) + { + return CachedTextures[key]; + } + + var texture = EditorGUIUtility.ObjectContent(null, type).image; + CachedTextures.Add(key, texture); + + return texture; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs.meta new file mode 100644 index 0000000..4ca3e36 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e42f0f68a093d74ea97ddfbd9a5ef4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors.meta new file mode 100644 index 0000000..10cdcd4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f0c63cf6cabe3a547a0b46de95bff055 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs new file mode 100644 index 0000000..dc29499 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs @@ -0,0 +1,64 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Editors +{ + using Detectors; + + using UnityEditor; + using UnityEngine; + + [CustomEditor(typeof (InjectionDetector))] + internal class InjectionDetectorEditor : KeepAliveBehaviourEditor + { + protected override bool DrawUniqueDetectorProperties() + { + if (!ACTkSettings.Instance.InjectionDetectorEnabled) + { + using (GUITools.Vertical(GUITools.PanelWithBackground)) + { + EditorGUILayout.Separator(); + EditorGUILayout.HelpBox("Injection Detector support is not enabled! Injection Detector will not work properly", + MessageType.Error, true); + + using (new GUILayout.HorizontalScope()) + { + if (GUILayout.Button("Enable Now")) + { + ACTkSettings.Instance.InjectionDetectorEnabled = true; + } + if (GUILayout.Button("Enable In settings...")) + { + ACTkSettings.Show(); + } + } + + EditorGUILayout.Separator(); + } + + return true; + } + + if (SettingsUtils.IsIL2CPPEnabled()) + { + EditorGUILayout.HelpBox("Mono Injections are not possible in IL2CPP, this detector is not needed in IL2CPP builds", + MessageType.Info, true); + + return true; + } + + if (!InjectionRoutines.IsTargetPlatformCompatible()) + { + EditorGUILayout.HelpBox("Injection Detection is only supported in Standalone and Android builds", + MessageType.Warning, true); + + return true; + } + + return false; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs.meta new file mode 100644 index 0000000..7de88c1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6025f911d895a7e43a5d5c6229254129 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs new file mode 100644 index 0000000..a835851 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs @@ -0,0 +1,94 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Editors +{ + using Common; + using UnityEditor; + using UnityEngine; + + internal class KeepAliveBehaviourEditor : Editor where T: KeepAliveBehaviour + { + protected T self; + + private SerializedProperty autoStart; + private SerializedProperty autoDispose; + private SerializedProperty keepAlive; + private SerializedProperty detectionEvent; + private SerializedProperty detectionEventHasListener; + + public virtual void OnEnable() + { + autoStart = serializedObject.FindProperty("autoStart"); + autoDispose = serializedObject.FindProperty("autoDispose"); + keepAlive = serializedObject.FindProperty("keepAlive"); + detectionEvent = serializedObject.FindProperty("detectionEvent"); + detectionEventHasListener = serializedObject.FindProperty("detectionEventHasListener"); + + self = (T)target; + + FindUniqueDetectorProperties(); + } + + public override void OnInspectorGUI() + { + if (self == null) return; + + serializedObject.Update(); + + EditorGUIUtility.labelWidth = 140; + EditorGUILayout.Space(); + DrawHeader("Base settings"); + + EditorGUILayout.PropertyField(autoStart); + detectionEventHasListener.boolValue = EditorTools.CheckUnityEventHasActivePersistentListener(detectionEvent); + + CheckAdditionalEventsForListeners(); + + if (autoStart.boolValue && !detectionEventHasListener.boolValue && !AdditionalEventsHasListeners()) + { + EditorGUILayout.LabelField(new GUIContent("You need to add at least one active item to the Events in order to use Auto Start feature!"), GUITools.BoldLabel); + } + else if (!autoStart.boolValue) + { + EditorGUILayout.LabelField(new GUIContent("Don't forget to start detection!", "You should start detector from code using ObscuredCheatingDetector.StartDetection() method. See readme for details."), GUITools.BoldLabel); + EditorGUILayout.Separator(); + } + EditorGUILayout.PropertyField(autoDispose); + EditorGUILayout.PropertyField(keepAlive); + + EditorGUILayout.Separator(); + + if (DrawUniqueDetectorProperties()) + { + EditorGUILayout.Separator(); + } + + //DrawHeader("Events"); + + EditorGUILayout.PropertyField(detectionEvent); + DrawAdditionalEvents(); + serializedObject.ApplyModifiedProperties(); + + EditorGUIUtility.labelWidth = 0; + } + + protected virtual void DrawHeader(string text) + { + GUITools.DrawHeader(text); + } + + protected virtual bool AdditionalEventsHasListeners() + { + return true; + } + + protected virtual void FindUniqueDetectorProperties() {} + protected virtual bool DrawUniqueDetectorProperties() { return false; } + protected virtual void CheckAdditionalEventsForListeners() {} + protected virtual void DrawAdditionalEvents() {} + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs.meta new file mode 100644 index 0000000..cd250e7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6b59c308aff5e054991de809a3b5985b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs new file mode 100644 index 0000000..63709ed --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs @@ -0,0 +1,45 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Editors +{ + using Detectors; + + using UnityEditor; + using UnityEngine; + + [CustomEditor(typeof (ObscuredCheatingDetector))] + internal class ObscuredCheatingDetectorEditor : KeepAliveBehaviourEditor + { + private SerializedProperty doubleEpsilon; + private SerializedProperty floatEpsilon; + private SerializedProperty vector2Epsilon; + private SerializedProperty vector3Epsilon; + private SerializedProperty quaternionEpsilon; + + protected override void FindUniqueDetectorProperties() + { + doubleEpsilon = serializedObject.FindProperty("doubleEpsilon"); + floatEpsilon = serializedObject.FindProperty("floatEpsilon"); + vector2Epsilon = serializedObject.FindProperty("vector2Epsilon"); + vector3Epsilon = serializedObject.FindProperty("vector3Epsilon"); + quaternionEpsilon = serializedObject.FindProperty("quaternionEpsilon"); + } + + protected override bool DrawUniqueDetectorProperties() + { + DrawHeader("Specific settings"); + + EditorGUILayout.PropertyField(doubleEpsilon); + EditorGUILayout.PropertyField(floatEpsilon); + EditorGUILayout.PropertyField(vector2Epsilon, new GUIContent("Vector2 Epsilon")); + EditorGUILayout.PropertyField(vector3Epsilon, new GUIContent("Vector3 Epsilon")); + EditorGUILayout.PropertyField(quaternionEpsilon); + + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs.meta new file mode 100644 index 0000000..78cf6cb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8df36b70906d65d43bcb3ddce3fe36ba +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs new file mode 100644 index 0000000..ac1caac --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs @@ -0,0 +1,70 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Editors +{ + using Detectors; + + using UnityEditor; + using UnityEditor.EditorTools; + using UnityEngine; + using EditorTools = EditorCode.EditorTools; + + [CustomEditor(typeof (SpeedHackDetector))] + internal class SpeedHackDetectorEditor : KeepAliveBehaviourEditor + { + private SerializedProperty interval; + private SerializedProperty threshold; + private SerializedProperty maxFalsePositives; + private SerializedProperty coolDown; + private SerializedProperty useDsp; + + protected override void FindUniqueDetectorProperties() + { + interval = serializedObject.FindProperty("interval"); + threshold = serializedObject.FindProperty("threshold"); + maxFalsePositives = serializedObject.FindProperty("maxFalsePositives"); + coolDown = serializedObject.FindProperty("coolDown"); + + useDsp = serializedObject.GetProperty(nameof(SpeedHackDetector.UseDsp)); + } + + protected override bool DrawUniqueDetectorProperties() + { + DrawHeader("Specific settings"); + + EditorGUILayout.PropertyField(interval); + EditorGUILayout.PropertyField(threshold); + EditorGUILayout.PropertyField(maxFalsePositives); + EditorGUILayout.PropertyField(coolDown); + +#if UNITY_2020_1_OR_NEWER + EditorGUILayout.PropertyField(useDsp); +#else + EditorGUILayout.PropertyField(useDsp, new GUIContent( ObjectNames.NicifyVariableName(nameof(SpeedHackDetector.UseDsp)), useDsp.tooltip)); +#endif + if (useDsp.boolValue) + EditorGUILayout.HelpBox("Dsp timers may cause false positives on some hardware.\nMake sure to test on target devices before using this in production.", MessageType.Warning); + +#if UNITY_AUDIO_MODULE + if (!EditorTools.IsAudioManagerEnabled()) + { + EditorGUILayout.HelpBox("Dsp option is not available since Disable Unity Audio option is enabled.", MessageType.Error); + if (GUILayout.Button("Open Audio Settings")) + { + SettingsService.OpenProjectSettings("Project/Audio"); +#if UNITY_2021_3_OR_NEWER + Highlighter.Highlight("Project Settings", EditorTools.GetAudioManagerEnabledPropertyPath(), HighlightSearchMode.Identifier); +#endif + } + } +#else + EditorGUILayout.HelpBox("Dsp option is not available since built-in Audio module is disabled.", MessageType.Error); +#endif + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs.meta new file mode 100644 index 0000000..92b69d3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 199f39969debe8f46afc5f32b333be3b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs new file mode 100644 index 0000000..1d14df5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs @@ -0,0 +1,74 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Editors +{ + using Detectors; + + using UnityEditor; + using UnityEngine; + + [CustomEditor(typeof(TimeCheatingDetector))] + internal class TimeCheatingDetectorEditor : KeepAliveBehaviourEditor + { +#if !ACTK_PREVENT_INTERNET_PERMISSION + private SerializedProperty requestUrl; + private SerializedProperty requestMethod; + private SerializedProperty timeoutSeconds; + private SerializedProperty interval; + private SerializedProperty realCheatThreshold; + private SerializedProperty wrongTimeThreshold; + private SerializedProperty ignoreSetCorrectTime; + + protected override void FindUniqueDetectorProperties() + { + requestUrl = serializedObject.FindProperty("requestUrl"); + requestMethod = serializedObject.FindProperty("requestMethod"); + timeoutSeconds = serializedObject.FindProperty("timeoutSeconds"); + interval = serializedObject.FindProperty("interval"); + realCheatThreshold = serializedObject.FindProperty("realCheatThreshold"); + wrongTimeThreshold = serializedObject.FindProperty("wrongTimeThreshold"); + ignoreSetCorrectTime = serializedObject.FindProperty("ignoreSetCorrectTime"); + } + + protected override bool DrawUniqueDetectorProperties() + { + DrawHeader("Specific settings"); + + EditorGUIUtility.labelWidth += 10; + EditorGUILayout.PropertyField(ignoreSetCorrectTime); + EditorGUIUtility.labelWidth -= 10; + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(requestUrl, new GUIContent("URL", requestUrl.tooltip)); + if (EditorGUI.EndChangeCheck()) + { + self.RequestUrl = requestUrl.stringValue; + } + +#if UNITY_WEBGL + GUILayout.Label("To avoid CORS limitations while running in WebGL, URL will be changed to the current domain, if it does points to any other domain", GUITools.RichMiniLabel); + EditorGUILayout.Space(); +#endif + + EditorGUILayout.PropertyField(requestMethod, new GUIContent("Method", requestMethod.tooltip)); + + EditorGUILayout.PropertyField(timeoutSeconds); + EditorGUILayout.PropertyField(interval); + EditorGUILayout.PropertyField(realCheatThreshold); + EditorGUILayout.PropertyField(wrongTimeThreshold); + + return true; + } +#else + protected override bool DrawUniqueDetectorProperties() + { + GUILayout.Label("Detector disabled with ACTK_PREVENT_INTERNET_PERMISSION conditional symbol", GUITools.RichLabel); + return true; + } +#endif + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs.meta new file mode 100644 index 0000000..6d0c898 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2fb4c7beaf58d554ab0f85d86b53726e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs new file mode 100644 index 0000000..13023c3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs @@ -0,0 +1,139 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Editors +{ + using Detectors; + using UnityEditor; + using UnityEngine; + + [CustomEditor(typeof (WallHackDetector))] + internal class WallHackDetectorEditor : KeepAliveBehaviourEditor + { + private SerializedProperty wireframeDelay; + private SerializedProperty raycastDelay; + private SerializedProperty spawnPosition; + private SerializedProperty maxFalsePositives; + + private SerializedProperty checkRigidbody; + private SerializedProperty checkController; + private SerializedProperty checkWireframe; + private SerializedProperty checkRaycast; + + protected override void FindUniqueDetectorProperties() + { + raycastDelay = serializedObject.FindProperty("raycastDelay"); + wireframeDelay = serializedObject.FindProperty("wireframeDelay"); + spawnPosition = serializedObject.FindProperty("spawnPosition"); + maxFalsePositives = serializedObject.FindProperty("maxFalsePositives"); + + checkRigidbody = serializedObject.FindProperty("checkRigidbody"); + checkController = serializedObject.FindProperty("checkController"); + checkWireframe = serializedObject.FindProperty("checkWireframe"); + checkRaycast = serializedObject.FindProperty("checkRaycast"); + } + + protected override bool DrawUniqueDetectorProperties() + { + var detector = self; + if (detector == null) return false; + + DrawHeader("Specific settings"); + + if (PropertyFieldChanged(checkRigidbody, new GUIContent("Rigidbody"))) + { + detector.CheckRigidbody = checkRigidbody.boolValue; + } + + if (PropertyFieldChanged(checkController, new GUIContent("Character Controller"))) + { + detector.CheckController = checkController.boolValue; + } + + if (PropertyFieldChanged(checkWireframe, new GUIContent("Wireframe"))) + { + detector.CheckWireframe = checkWireframe.boolValue; + } + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(wireframeDelay, new GUIContent("Delay")); + EditorGUI.indentLevel--; + + if (PropertyFieldChanged(checkRaycast, new GUIContent("Raycast"))) + { + detector.CheckRaycast = checkRaycast.boolValue; + } + EditorGUI.indentLevel++; + EditorGUILayout.PropertyField(raycastDelay, new GUIContent("Delay")); + EditorGUI.indentLevel--; + + EditorGUILayout.Separator(); + + EditorGUILayout.PropertyField(spawnPosition); + if (Vector3.Distance(spawnPosition.vector3Value, Vector3.zero) <= 0.001f) + { + EditorGUILayout.HelpBox("Please consider placing spawn position as far from your moving objects as possible to avoid false positives", MessageType.Warning); + EditorGUILayout.Space(); + } + EditorGUILayout.PropertyField(maxFalsePositives); + + EditorGUILayout.Separator(); + + if (checkWireframe.boolValue && !SettingsGUI.IsWallhackDetectorShaderIncluded()) + { + using (GUITools.Vertical(GUITools.PanelWithBackground)) + { + EditorGUILayout.Separator(); + EditorGUILayout.HelpBox("Wallhack Detector shader for Wireframe checks is not included into the build! Detector may work incorrectly", + MessageType.Error, true); + + if (GUILayout.Button("Include in Settings...")) + { + ACTkSettings.Show(); + } + + EditorGUILayout.Separator(); + } + } + + if (checkRaycast.boolValue || checkController.boolValue || checkRigidbody.boolValue) + { + var layerId = LayerMask.NameToLayer("Ignore Raycast"); + if (Physics.GetIgnoreLayerCollision(layerId, layerId)) + { + EditorGUILayout.LabelField("IgnoreRaycast physics layer should collide with itself to avoid false positives! See readme's troubleshooting section for details.", EditorStyles.wordWrappedLabel); + if (GUILayout.Button("Edit in Physics settings")) + { + SettingsService.OpenProjectSettings("Project/Physics"); + } + } + } + + return true; + } + + private static bool PropertyFieldChanged(SerializedProperty property, GUIContent content, params GUILayoutOption[] options) + { + var result = false; + + EditorGUI.BeginChangeCheck(); + + if (content == null) + { + EditorGUILayout.PropertyField(property, options); + } + else + { + EditorGUILayout.PropertyField(property, content, options); + } + + if (EditorGUI.EndChangeCheck()) + { + result = true; + } + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs.meta new file mode 100644 index 0000000..a1c53ed --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2f88f8bd1134b464fa26c27d9979e6db +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine.meta new file mode 100644 index 0000000..8ea9da3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b60780b31b4fac0448812d7db515e8a7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash.meta new file mode 100644 index 0000000..b7e865c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0eab0a2d46900f5498873b929a503bad +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess.meta new file mode 100644 index 0000000..4b6f214 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7ae78be353f2d8243b15efd15919c5f5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs new file mode 100644 index 0000000..f23e7b6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs @@ -0,0 +1,203 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System.Linq; +using System.Threading.Tasks; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using CodeStage.AntiCheat.Common; +using CodeStage.AntiCheat.Genuine.CodeHash; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using Debug = UnityEngine.Debug; + +namespace CodeStage.AntiCheat.EditorCode.PostProcessors +{ + /// + /// Does calculates code hash after build if you use option "Generate code hash". + /// Listen to HashesGenerated or look for hash for each build in the Editor Console. + /// + /// Resulting hash in most cases should match value you get from the \ref CodeStage.AntiCheat.Genuine.CodeHash.CodeHashGenerator "CodeHashGenerator" + public class CodeHashGeneratorPostprocessor : IPostprocessBuildWithReport + { + /// + /// Equals int.MaxValue to make sure this postprocessor will run as late as possible + /// so you could run own postprocessors before and subscribe to HashesGenerated event. + /// + /// Used at CodeHashGeneratorListener example. + public const int CallbackOrder = int.MaxValue; + + /// + /// HashesGenerated event delegate. + /// + /// Standard post-build report from Unity. + /// Build hashing results array. + /// + /// You may generate multiple actual builds within single build operation, + /// like multiple APKs when you use "Split APKs by target architecture" option, + /// so you may have more than one valid hashed builds for one actual build procedure. + public delegate void OnHashesGenerated(BuildReport report, IReadOnlyList hashedBuilds); + + /// + /// You may listen to this event if you wish to post-process resulting code hash, + /// e.g. upload it to the server for the later runtime check with CodeHashGenerator. + /// + /// Make sure to enable "Generate code hash on build completion" option in the ACTk settings to make this event work. + public static event OnHashesGenerated HashesGenerated; + + int IOrderedCallback.callbackOrder => CallbackOrder; + async void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report) + { + if (!ACTkSettings.Instance.PreGenerateBuildHash || !CodeHashGenerator.IsTargetPlatformCompatible()) + return; + + await CalculateBuildReportHashesAsync(report, true, true); + } + + /// + /// Calls selection dialog and calculates hashes for the selected build. + /// + /// Path to the .apk / .aab or .exe file. Pass null to show file selection dialog. + /// Path to the .apk / .aab or .exe file. Pass null to show file selection dialog. + /// Valid BuildHashes instance or null in case of error / user cancellation. + public static BuildHashes CalculateExternalBuildHashes(string buildPath, bool printToConsole) + { + return AsyncHelpers.RunSync(() => CalculateExternalBuildHashesAsync(buildPath, printToConsole)); + } + + /// + /// Calls selection dialog and calculates hashes for the selected build. + /// + /// Path to the .apk / .aab or .exe file. Pass null to show file selection dialog. + /// Path to the .apk / .aab or .exe file. Pass null to show file selection dialog. + /// Task with Valid BuildHashes instance or null in case of error / user cancellation. + public static async Task CalculateExternalBuildHashesAsync(string buildPath, bool printToConsole) + { + if (buildPath == null) + { + buildPath = EditorUtility.OpenFilePanel( + "Select Standalone Windows build exe or Android build apk / aab", "", "exe,apk,aab"); + if (string.IsNullOrEmpty(buildPath)) + { + Debug.Log(ACTk.LogPrefix + "Hashing cancelled by user."); + return null; + } + } + + var extension = Path.GetExtension(buildPath); + if (string.IsNullOrEmpty(extension)) + return null; + + extension = extension.ToLower(CultureInfo.InvariantCulture); + + try + { + EditorUtility.DisplayProgressBar("ACTk: Generating code hash", "Preparing...", 0); + BuildHashes hashes; + + if (extension == ".apk" || extension == ".aab") + hashes = (await AndroidBuildHashGenerator.GetBuildHashes(new[] { buildPath })).FirstOrDefault(); + else + hashes = (await WindowsBuildHashGenerator.GetBuildHashes(buildPath)).FirstOrDefault(); + + if (printToConsole) + hashes?.PrintToConsole(); + + return hashes; + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Error while trying to hash build!", e); + } + finally + { + EditorUtility.ClearProgressBar(); + } + + return null; + } + + /// + /// Calculates hashes for the given build report. Can be useful if you wish to hash build you just made with BuildPipeline. + /// + /// Will not trigger the HashesGenerated event. + /// BuildReport you wish to calculates hashes for + /// Specifies if calculated hashes should be printed to Unity Console + /// Readonly List of the BuildHashes, one per each resulting build from the BuildReport. + public static Task> CalculateBuildReportHashesAsync(BuildReport report, + bool printToConsole) + { + return CalculateBuildReportHashesAsync(report, false, printToConsole); + } + + private static async Task> CalculateBuildReportHashesAsync(BuildReport report, + bool triggerEvent, bool printLogs) + { + if (EditorUserBuildSettings.GetPlatformSettings(report.summary.platformGroup.ToString(), + "CreateSolution") == "true") + { + Debug.Log( + ACTk.LogPrefix + "Build hashing is skipped due to the 'Create Visual Studio Solution' option."); + return null; + } + + try + { + EditorUtility.DisplayProgressBar("ACTk: Generating code hash", "Preparing...", 0); + + var hashedBuilds = await GetHashedBuilds(report); + + if (hashedBuilds == null || hashedBuilds.Count == 0) + { + Debug.Log(ACTk.LogPrefix + "Couldn't pre-generate code hash. " + + "Please run your build and generate hash with CodeHashGenerator."); + return null; + } + + if (printLogs) + { + foreach (var hashedBuild in hashedBuilds) + { + hashedBuild.PrintToConsole(); + } + } + + if (triggerEvent) + HashesGenerated?.Invoke(report, hashedBuilds); + + return hashedBuilds; + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Error while trying to hash build!", e); + } + finally + { + EditorUtility.ClearProgressBar(); + } + + return null; + } + + private static async Task> GetHashedBuilds(BuildReport report) + { + var platform = report.summary.platform; + switch (platform) + { + case BuildTarget.StandaloneWindows64: + case BuildTarget.StandaloneWindows: + return await WindowsBuildHashGenerator.GetBuildHashes(report.summary.outputPath); + case BuildTarget.Android: + return await AndroidBuildHashGenerator.GetBuildHashes(report); + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs.meta new file mode 100644 index 0000000..317770c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c82c021ded9a49b44b3701f1859341cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms.meta new file mode 100644 index 0000000..50759b5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 881ba0c65bee45139ca757895221c6ab +timeCreated: 1680806941 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs new file mode 100644 index 0000000..44ab0c1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs @@ -0,0 +1,184 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using CodeStage.AntiCheat.Common; +using CodeStage.AntiCheat.EditorCode.ICSharpCode.SharpZipLib.Zip; +using CodeStage.AntiCheat.Genuine.CodeHash; +using CodeStage.AntiCheat.Utils; +using UnityEditor; +using UnityEditor.Build.Reporting; +using Debug = UnityEngine.Debug; + +namespace CodeStage.AntiCheat.EditorCode.PostProcessors +{ + internal static class AndroidBuildHashGenerator + { + private static readonly object ProgressLock = new object(); + + public static async Task GetBuildHashes(BuildReport report) + { + if ((report.summary.options & BuildOptions.PatchPackage) != 0) + { + Debug.Log(ACTk.LogPrefix + "Patch hashing is skipped, only full build hashing is supported."); + return Array.Empty(); + } + +#if UNITY_2022_1_OR_NEWER + var files = report.GetFiles(); +#else + var files = report.files; +#endif + var filePaths = new string[files.Length]; + for (var i = 0; i < filePaths.Length; i++) + { + filePaths[i] = files[i].path; + } + + return await GetBuildHashes(filePaths); + } + + public static async Task GetBuildHashes(string[] files) + { + var result = new List(); + + foreach (var path in files) + { + var extension = Path.GetExtension(path); + if (!string.IsNullOrEmpty(extension)) + extension = extension.ToLower(CultureInfo.InvariantCulture); + + if (extension != ".apk" && extension != ".aab") + continue; + + var progress = FilesProgress.CreateNew("ACTk: Generating code hash"); + var filters = GetFilters(); + var buildHashes = await Task.Run(() => HashSuitableFilesInZipFile(path, filters, + progress)); + if (buildHashes != null) + result.Add(buildHashes); + } + + if (result.Count == 0) + { + if (!EditorUserBuildSettings.exportAsGoogleAndroidProject) + ACTk.PrintExceptionForSupport("Couldn't find compiled APK or AAB build!"); + else + Debug.LogWarning("Couldn't find compiled APK or AAB build! " + + "This is fine if you use Export Project feature."); + } + + return result.ToArray(); + } + + private static BuildHashes HashSuitableFilesInZipFile(string path, FilteringData filters, + IProgress progress) + { + ZipFile zf = null; + + try + { + var sw = Stopwatch.StartNew(); + + var latestPercent = 0; + var filesChecked = 0; + var fileHashes = new ConcurrentBag(); + var fs = File.OpenRead(path); + zf = new ZipFile(fs); + var count = zf.Count; + + var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount }; + var sha1Pool = new ThreadSafeDisposablesPool(() => new SHA1Wrapper()); + + Parallel.ForEach(zf.Cast(), options, zipEntry => + { + string entryFileName = null; + var skipped = true; + try + { + // skip folders since we can't hash them + if (!zipEntry.IsFile) + return; + + entryFileName = zipEntry.Name; + if (filters.IsIgnored(entryFileName)) + return; + + if (!filters.IsIncluded(entryFileName)) + return; + + using (var zipStream = zf.GetInputStream(zipEntry)) + { + fileHashes.Add(new FileHash(entryFileName, zipStream, sha1Pool)); + } + + skipped = false; + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + finally + { + lock (ProgressLock) + { + filesChecked++; + if (!skipped) + progress?.ReportPercent(ref latestPercent, filesChecked, count, Path.GetFileName(entryFileName)); + } + } + }); + + sha1Pool.Dispose(); + progress?.Report(FilesProgress.None()); + sw.Stop(); + + if (fileHashes.Count == 0) + return null; + + var result = new BuildHashes(path, fileHashes.ToArray()) + { + DurationSeconds = sw.Elapsed.TotalSeconds + }; + + return result; + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Error while calculating code hash!", e); + } + finally + { + if (zf != null) + { + zf.IsStreamOwner = true; + zf.Close(); + } + } + + return null; + } + + private static FilteringData GetFilters() + { + var il2Cpp = false; +#if UNITY_EDITOR + il2Cpp = SettingsUtils.IsIL2CPPEnabled(); +#elif ENABLE_IL2CPP + il2Cpp = true; +#endif + return FiltersProducer.GetFileFiltersAndroid(il2Cpp); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs.meta new file mode 100644 index 0000000..2f38cc8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9717d52c2bf842caaa8575f8f2947afa +timeCreated: 1680806503 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs new file mode 100644 index 0000000..a4b342d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs @@ -0,0 +1,49 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; +using CodeStage.AntiCheat.Common; +using CodeStage.AntiCheat.Genuine.CodeHash; + +namespace CodeStage.AntiCheat.EditorCode.PostProcessors +{ + internal static class WindowsBuildHashGenerator + { + public static async Task> GetBuildHashes(string buildPath) + { + var folder = Path.GetDirectoryName(buildPath); + if (folder == null) + { + ACTk.PrintExceptionForSupport("Could not found build folder for this file: " + buildPath); + return Array.Empty(); + } + + var progress = FilesProgress.CreateNew("ACTk: Generating code hash"); + var filters = GetFilters(); + var buildHashes = await Task.Run(()=> StandaloneWindowsWorker.GetBuildHashes(folder, filters, Environment.ProcessorCount, + progress)); + + if (buildHashes == null) + return Array.Empty(); + + return new [] { buildHashes }; + } + + private static FilteringData GetFilters() + { + var il2Cpp = false; +#if UNITY_EDITOR + il2Cpp = SettingsUtils.IsIL2CPPEnabled(); +#elif ENABLE_IL2CPP + il2Cpp = true; +#endif + return FiltersProducer.GetFileFiltersStandaloneWindows(il2Cpp); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs.meta new file mode 100644 index 0000000..bc28d90 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 02b38fd3639d4fd7a1a6732fadbeebc8 +timeCreated: 1680806778 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection.meta new file mode 100644 index 0000000..9fb3da5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 59e19c7338f04be697d7788c76f0cde6 +timeCreated: 1552927805 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs new file mode 100644 index 0000000..4c89286 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs @@ -0,0 +1,70 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + + /// + /// Describes assembly which is added to the InjectionDetector "white list". + /// + [Serializable] + public class AllowedAssembly + { + [Obsolete("Please use Name property instead.", false)] + public string name => Name; + + [Obsolete("Please use Hashes property instead.", false)] + public int[] hashes => Hashes; + + /// + /// Assembly name, i.e.: ACTk.Runtime. + /// + public string Name { get; } + + /// + /// Array of whitelisted hashes for the assembly with given Name. + /// + public int[] Hashes { get; private set; } + + /// + /// Constructs new instance. + /// + /// Sets Name property. + /// Sets Hashes property. + public AllowedAssembly(string name, int[] hashes) + { + Name = name; + Hashes = hashes; + } + + /// + /// Allows adding new hash to the Hashes collection. + /// + /// New whitelisted hash for the assembly with specified Name. + /// True if hash was added and false otherwise (i.e. when hash already existed in the collection). + public bool AddHash(int hash) + { + if (Array.IndexOf(Hashes, hash) != -1) return false; + + var oldLen = Hashes.Length; + var newLen = oldLen + 1; + + var newHashesArray = new int[newLen]; + Array.Copy(Hashes, newHashesArray, oldLen); + + Hashes = newHashesArray; + Hashes[oldLen] = hash; + + return true; + } + + public override string ToString() + { + return Name + " (hashes: " + Hashes.Length + ")"; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs.meta new file mode 100644 index 0000000..02fdd25 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 99e59ee643091664d874b8418be8b78e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs new file mode 100644 index 0000000..ada09dd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs @@ -0,0 +1,23 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System.IO; + + internal static class InjectionConstants + { + public const string LegacyWhitelistRelativePath = "InjectionDetectorData/UserWhitelist.bytes"; + + public const string PrefsKey = "ACTDIDEnabledGlobal"; + public const string DataSeparator = ":"; + + public static readonly string ResourcesFolder = Path.Combine(ACTkEditorConstants.AssetsFolder, "Resources"); + public static readonly string DataFilePath = Path.Combine(ResourcesFolder, DataFileName); + + private const string DataFileName = "fndid.bytes"; + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs.meta new file mode 100644 index 0000000..ab868be --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fdb8abbb3fde4da3aa210fccf74e9524 +timeCreated: 1552925592 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs new file mode 100644 index 0000000..7c7e04a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs @@ -0,0 +1,229 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if (UNITY_STANDALONE || UNITY_ANDROID) +#define UNITY_SUPPORTED_PLATFORM +#endif + +#define ACTK_DEBUG +#undef ACTK_DEBUG + +#define ACTK_DEBUG_VERBOSE +#undef ACTK_DEBUG_VERBOSE + +#define ACTK_DEBUG_PARANIOD +#undef ACTK_DEBUG_PARANIOD + +#if ACTK_DEBUG_PARANIOD +#define ACTK_DEBUG +#define ACTK_DEBUG_VERBOSE +#endif + +#if ACTK_DEBUG_VERBOSE +#define ACTK_DEBUG +#endif + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Reflection; + using Common; + using ObscuredTypes; + using UnityEditor; + using UnityEngine; + + internal static class InjectionRoutines + { + private static bool cleanupDone; + + public static bool IsInjectionPossible() + { + return IsTargetPlatformCompatible() && !SettingsUtils.IsIL2CPPEnabled(); + } + + public static bool IsTargetPlatformCompatible() + { +#if UNITY_SUPPORTED_PLATFORM + return true; +#else + return false; +#endif + } + + public static int GetAssemblyHash(AssemblyName ass) + { + var hashInfo = ass.Name; + + var bytes = ass.GetPublicKeyToken(); + if (bytes != null && bytes.Length == 8) + { + hashInfo += PublicKeyTokenToString(bytes); + } + + // Jenkins hash function (http://en.wikipedia.org/wiki/Jenkins_hash_function) + var result = 0; + var len = hashInfo.Length; + + for (var i = 0; i < len; ++i) + { + result += hashInfo[i]; + result += (result << 10); + result ^= (result >> 6); + } + result += (result << 3); + result ^= (result >> 11); + result += (result << 15); + + return result; + } + + public static List MergeAllowedAssemblies(IEnumerable collection1, IEnumerable collection2) + { + var result = new List(collection1); + + foreach (var whiteListedAssembly in collection2) + { + var exists = false; + foreach (var assembly in result) + { + if (assembly.Name != whiteListedAssembly.Name) continue; + + exists = true; + foreach (var hash in whiteListedAssembly.Hashes) + { + if (Array.IndexOf(assembly.Hashes, hash) == -1) + { + assembly.AddHash(hash); + } + } + + break; + } + + if (!exists) + { + result.Add(whiteListedAssembly); + } + } + + return result; + } + + public static void InitCleanup() + { + cleanupDone = false; + } + + public static void Cleanup() + { + if (cleanupDone) return; + cleanupDone = true; + + TryMigrateSettings(); + TryMigrateLegacyInjectionWhitelist(); + + if (File.Exists(InjectionConstants.DataFilePath)) + { +#if ACTK_DEBUG + Debug.Log(ACTk.LogPrefix + "Data file found and going to be removed: " + InjectionConstants.DataFilePath); +#endif + EditorTools.DeleteFile(InjectionConstants.DataFilePath); + EditorTools.DeleteFile(AssetDatabase.GetTextMetaFilePathFromAssetPath(InjectionConstants.DataFilePath)); + EditorTools.RemoveDirectoryIfEmpty(InjectionConstants.ResourcesFolder); + + AssetDatabase.Refresh(); + } + } + + private static string PublicKeyTokenToString(byte[] bytes) + { + var result = ""; + + // AssemblyName.GetPublicKeyToken() returns 8 bytes + for (var i = 0; i < 8; i++) + { + result += ACTkEditorConstants.HexTable[bytes[i]]; + } + + return result; + } + + private static void TryMigrateSettings() + { + if (!EditorPrefs.HasKey(InjectionConstants.PrefsKey)) return; + + ACTkSettings.Instance.InjectionDetectorEnabled = EditorPrefs.GetBool(InjectionConstants.PrefsKey); + EditorPrefs.DeleteKey(InjectionConstants.PrefsKey); + } + + private static void TryMigrateLegacyInjectionWhitelist() + { + if (!File.Exists(InjectionConstants.LegacyWhitelistRelativePath)) return; + var whitelistedAssemblies = LoadAndParseLegacyWhitelist(); + ACTkSettings.Instance.InjectionDetectorWhiteList = MergeAllowedAssemblies(ACTkSettings.Instance.InjectionDetectorWhiteList, whitelistedAssemblies); + } + + private static IEnumerable LoadAndParseLegacyWhitelist() + { + var result = new List(); + string[] separator = { InjectionConstants.DataSeparator }; + + var fs = new FileStream(InjectionConstants.LegacyWhitelistRelativePath, FileMode.Open, FileAccess.Read, FileShare.Read); + var br = new BinaryReader(fs); + + try + { + var count = br.ReadInt32(); + + for (var i = 0; i < count; i++) + { + var line = br.ReadString(); + line = new string(ObscuredString.Encrypt(line, ACTk.StringKey)); + var strArr = line.Split(separator, StringSplitOptions.RemoveEmptyEntries); + var stringsCount = strArr.Length; + if (stringsCount > 1) + { + var assemblyName = strArr[0]; + + var hashes = new int[stringsCount - 1]; + for (var j = 1; j < stringsCount; j++) + { + var success = int.TryParse(strArr[j], out var parseResult); + if (success) + { + hashes[j - 1] = parseResult; + } + else + { + Debug.LogError(ACTk.LogPrefix + "Could not parse value: " + strArr[j] + + ", line:\n" + line); + } + } + + result.Add(new AllowedAssembly(assemblyName, hashes)); + } + else + { + throw new Exception("Error parsing whitelist file line!"); + } + } + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Error while reading legacy whitelist!", e); + } + finally + { + br.Close(); + fs.Close(); + } + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs.meta new file mode 100644 index 0000000..6ec742d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 682e4f8bd25b4b3f9ab90c2c080decf5 +timeCreated: 1552927820 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs new file mode 100644 index 0000000..7ba9c6f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs @@ -0,0 +1,234 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#define ACTK_DEBUG +#undef ACTK_DEBUG + +#define ACTK_DEBUG_VERBOSE +#undef ACTK_DEBUG_VERBOSE + +#define ACTK_DEBUG_PARANIOD +#undef ACTK_DEBUG_PARANIOD + +#if ACTK_DEBUG_PARANIOD +#define ACTK_DEBUG +#define ACTK_DEBUG_VERBOSE +#endif + +#if ACTK_DEBUG_VERBOSE +#define ACTK_DEBUG +#endif + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Text; + using Common; + using Detectors; + using ObscuredTypes; + using PostProcessors; + using UnityEditor; + using Debug = UnityEngine.Debug; + +#if ACTK_DEBUG + using System.Diagnostics; +#endif + + internal static class InjectionWhitelistBuilder + { + private const string ProgressCaption = "ACTk: Building InjectionDetector Whitelist"; + +#if ACTK_DEBUG + private static Stopwatch sw; +#endif + + public static void GenerateWhitelist() + { + try + { + GenerateWhitelistInternal(); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport($"Something went wrong while building {nameof(InjectionDetector)} whitelist!", e); + } + finally + { + EditorUtility.ClearProgressBar(); + } + } + + private static void GenerateWhitelistInternal() + { +#if ACTK_DEBUG + sw = Stopwatch.StartNew(); + sw.Stop(); + Debug.Log("=== Injection Detector Whitelist Build Start ==="); + sw.Start(); +#endif + EditorUtility.DisplayProgressBar(ProgressCaption, "Gathering assemblies", 0); + + var assembliesInBuild = GetAssembliesInBuild(); + if (assembliesInBuild.Length == 0) + ACTk.PrintExceptionForSupport("Can't find any assemblies in build!"); + + var assembliesAllowedByUser = GetUserWhiteListAssemblies(); + var allAllowedAssemblies = InjectionRoutines.MergeAllowedAssemblies(assembliesInBuild, assembliesAllowedByUser); + + EditorUtility.DisplayProgressBar(ProgressCaption, "Writing assemblies hashes", 0); + + WriteAllowedAssemblies(allAllowedAssemblies); + +#if ACTK_DEBUG + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "WhiteList build duration: " + sw.ElapsedMilliseconds + " ms."); +#endif + + AssetDatabase.Refresh(); + } + + private static AllowedAssembly[] GetAssembliesInBuild() + { +#if ACTK_DEBUG_VERBOSE + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Trying to guess which assemblies can get into the build..."); + sw.Start(); +#endif + var libraries = BuildPostProcessor.GetGuessedLibrariesForBuild(); + +#if ACTK_DEBUG_VERBOSE + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Total libraries candidates: " + libraries.Length); + sw.Start(); + + var invalidAssemblies = string.Empty; +#endif + + var result = new List(); + + foreach (var libraryPath in libraries) + { +#if ACTK_DEBUG_PARANIOD + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Checking library at the path: " + libraryPath); + sw.Start(); +#endif + try + { + var assName = AssemblyName.GetAssemblyName(libraryPath); + var name = assName.Name; + var hash = InjectionRoutines.GetAssemblyHash(assName); + + var allowed = result.FirstOrDefault(allowedAssembly => allowedAssembly.Name == name); + if (allowed != null) + { + allowed.AddHash(hash); + } + else + { + allowed = new AllowedAssembly(name, new[] { hash }); + result.Add(allowed); + } + } + catch + { + // not a valid IL assembly, skipping +#if ACTK_DEBUG_VERBOSE + invalidAssemblies += libraryPath + "\n"; +#endif + } + } + +#if ACTK_DEBUG_VERBOSE + if (!string.IsNullOrEmpty(invalidAssemblies)) + { + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Not valid assemblies:\n" + invalidAssemblies); + sw.Start(); + } +#endif + +#if ACTK_DEBUG + sw.Stop(); + var trace = ACTk.LogPrefix + "Found assemblies in build (" + result.Count + ", " + sw.ElapsedMilliseconds + " ms):\n"; + + foreach (var allowedAssembly in result) + { + trace += " Name: " + allowedAssembly.name + "\n"; + trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n")); + } + Debug.Log(trace); + sw.Start(); +#endif + return result.ToArray(); + } + + private static AllowedAssembly[] GetUserWhiteListAssemblies() + { + var userWhiteList = ACTkSettings.Instance.InjectionDetectorWhiteList; +#if ACTK_DEBUG + sw.Stop(); + var trace = ACTk.LogPrefix + "User White List assemblies (" + userWhiteList.Count + "):\n"; + + foreach (var allowedAssembly in userWhiteList) + { + trace += " Name: " + allowedAssembly.name + "\n"; + trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n")); + } + Debug.Log(trace); + sw.Start(); +#endif + return userWhiteList.ToArray(); + } + + private static void WriteAllowedAssemblies(List assemblies) + { + Directory.CreateDirectory(InjectionConstants.ResourcesFolder); + var bw = new BinaryWriter(new FileStream(InjectionConstants.DataFilePath, FileMode.Create, FileAccess.Write, FileShare.Read), Encoding.Unicode); + + bw.Write(assemblies.Count); + +#if ACTK_DEBUG_VERBOSE + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Writing assemblies data, count: " + assemblies.Count); + sw.Start(); +#endif + + foreach (var assembly in assemblies) + { + var name = assembly.Name; + var hashes = ""; + + for (var j = 0; j < assembly.Hashes.Length; j++) + { + hashes += assembly.Hashes[j].ToString(CultureInfo.InvariantCulture); + if (j < assembly.Hashes.Length - 1) + { + hashes += InjectionConstants.DataSeparator; + } + } + + var line = ObscuredString.Encrypt(name + InjectionConstants.DataSeparator + hashes, ACTk.StringKey); + +#if ACTK_DEBUG_PARANIOD + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Writing assembly:\n" + name + InjectionConstants.DataSeparator + hashes + "\n" + + new string(line) + ", length: " + line.Length); + sw.Start(); +#endif + bw.Write(line.Length); + bw.Write(line, 0, line.Length); + } + + bw.Close(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs.meta new file mode 100644 index 0000000..4dc6e88 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4ed4f862c6dc42a49c1f47d1e9ee2fb5 +timeCreated: 1552945114 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess.meta new file mode 100644 index 0000000..fd1618b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: bb730acf6c1569848b1187cd6c0e312c +folderAsset: yes +timeCreated: 1552913902 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs new file mode 100644 index 0000000..75b69dc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs @@ -0,0 +1,93 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PostProcessors +{ + using System; + using System.IO; + using System.Text; + using Common; + using UnityEditor; + using UnityEditor.Build; + using UnityEditor.Build.Reporting; + + internal class BuildPostProcessor : IPreprocessBuildWithReport, IPostBuildPlayerScriptDLLs, IPostprocessBuildWithReport + { + int IOrderedCallback.callbackOrder => int.MaxValue - 1; + + public void OnPreprocessBuild(BuildReport report) + { + if (!ACTkSettings.Instance.InjectionDetectorEnabled || + !InjectionRoutines.IsInjectionPossible()) + { + return; + } + + InjectionRoutines.InitCleanup(); + Prepare(); + } + + public void OnPostBuildPlayerScriptDLLs(BuildReport report) + { + if (!ACTkSettings.Instance.InjectionDetectorEnabled || + !InjectionRoutines.IsInjectionPossible()) + { + return; + } + + InjectionWhitelistBuilder.GenerateWhitelist(); + } + + public void OnPostprocessBuild(BuildReport report) + { + Cleanup(); + } + + public static string[] GetGuessedLibrariesForBuild() + { + var stagingAreaFolder = Path.Combine(ACTkEditorConstants.ProjectTempFolder, "StagingArea"); + return EditorTools.FindLibrariesAt(stagingAreaFolder); + } + + private void Prepare() + { + try + { + EditorApplication.LockReloadAssemblies(); + + if (!Directory.Exists(InjectionConstants.ResourcesFolder)) + { + Directory.CreateDirectory(InjectionConstants.ResourcesFolder); + } + + File.WriteAllText(InjectionConstants.DataFilePath, "please remove me", Encoding.Unicode); + AssetDatabase.Refresh(); + + EditorApplication.update += OnEditorUpdate; + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Injection Detector preparation failed!", e); + } + finally + { + EditorApplication.UnlockReloadAssemblies(); + } + } + + private void OnEditorUpdate() + { + if (!BuildPipeline.isBuildingPlayer) + Cleanup(); + } + + private void Cleanup() + { + InjectionRoutines.Cleanup(); + EditorApplication.update -= OnEditorUpdate; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs.meta new file mode 100644 index 0000000..d1fe4c7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e79f56c36f349f64995908c2bc571662 +timeCreated: 1552680217 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs new file mode 100644 index 0000000..c183a80 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs @@ -0,0 +1,276 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Reflection; + using UnityEditor; + using UnityEngine; + + internal class UserWhitelistEditor : EditorWindow + { + private const string InitialCustomName = "AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"; + private static List whitelist; + private static string whitelistPath; + + private Vector2 scrollPosition; + private bool manualAssemblyWhitelisting; + private string manualAssemblyWhitelistingName = InitialCustomName; + + internal static void ShowWindow() + { + EditorWindow myself = GetWindow(false, "Whitelist Editor", true); + myself.minSize = new Vector2(500, 200); + } + + private void OnLostFocus() + { + manualAssemblyWhitelisting = false; + manualAssemblyWhitelistingName = InitialCustomName; + } + + private void OnGUI() + { + if (whitelist == null) + { + whitelist = new List(); + LoadAndParseWhitelist(); + } + + var tmpStyle = new GUIStyle(EditorStyles.largeLabel) + { + alignment = TextAnchor.MiddleCenter, + fontStyle = FontStyle.Bold + }; + GUILayout.Label("User-defined Whitelist of Assemblies trusted by Injection Detector", tmpStyle); + + scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); + var whitelistUpdated = false; + + var count = whitelist.Count; + + if (count > 0) + { + for (var i = 0; i < count; i++) + { + var assembly = whitelist[i]; + using (GUITools.Horizontal()) + { + GUILayout.Label(assembly.ToString()); + if (GUILayout.Button(new GUIContent("-", "Remove Assembly from Whitelist"), GUILayout.Width(30))) + { + whitelist.Remove(assembly); + whitelistUpdated = true; + break; + } + } + } + } + else + { + tmpStyle = new GUIStyle(EditorStyles.largeLabel) + { + alignment = TextAnchor.MiddleCenter + }; + GUILayout.Label("- no Assemblies added so far (use buttons below to add) -", tmpStyle); + } + + if (manualAssemblyWhitelisting) + { + manualAssemblyWhitelistingName = EditorGUILayout.TextField(manualAssemblyWhitelistingName); + + using (GUITools.Horizontal()) + { + if (GUILayout.Button("Save")) + { + try + { + if (manualAssemblyWhitelistingName.StartsWith("Cause:")) + { + throw new Exception("Please remove Cause: from the assembly name!"); + } + + var assName = new AssemblyName(manualAssemblyWhitelistingName.Trim()); + + var res = TryWhitelistAssemblyName(assName, true); + if (res != WhitelistingResult.Exists) + { + whitelistUpdated = true; + } + manualAssemblyWhitelisting = false; + manualAssemblyWhitelistingName = InitialCustomName; + } + catch (Exception e) + { + ShowNotification(new GUIContent(e.Message)); + } + + GUI.FocusControl(""); + } + + if (GUILayout.Button("Cancel")) + { + manualAssemblyWhitelisting = false; + manualAssemblyWhitelistingName = InitialCustomName; + GUI.FocusControl(""); + } + } + } + + EditorGUILayout.EndScrollView(); + + using (GUITools.Horizontal()) + { + GUILayout.Space(20); + if (GUILayout.Button("Add Assembly")) + { + var assemblyPath = EditorUtility.OpenFilePanel("Choose an Assembly to add", "", "dll"); + if (!string.IsNullOrEmpty(assemblyPath)) + { + whitelistUpdated |= TryWhitelistAssemblies(new[] {assemblyPath}, true); + } + } + + if (GUILayout.Button("Add Assemblies from Folder")) + { + var selectedFolder = EditorUtility.OpenFolderPanel("Choose a Folder with Assemblies", "", ""); + if (!string.IsNullOrEmpty(selectedFolder)) + { + var libraries = EditorTools.FindLibrariesAt(selectedFolder); + whitelistUpdated |= TryWhitelistAssemblies(libraries); + } + } + + if (!manualAssemblyWhitelisting) + { + if (GUILayout.Button("Add Assembly manually")) + { + manualAssemblyWhitelisting = true; + } + } + + if (count > 0) + { + if (GUILayout.Button("Clear")) + { + if (EditorUtility.DisplayDialog("Please confirm", + "Are you sure you wish to completely clear your Injection Detector whitelist?", "Yes", "No")) + { + whitelist.Clear(); + whitelistUpdated = true; + } + } + } + GUILayout.Space(20); + } + + GUILayout.Space(20); + + if (whitelistUpdated) + { + WriteWhitelist(); + } + } + + private bool TryWhitelistAssemblies(IList libraries, bool singleFile = false) + { + var added = 0; + var updated = 0; + + var count = libraries.Count; + + for (var i = 0; i < count; i++) + { + var libraryPath = libraries[i]; + try + { + var assName = AssemblyName.GetAssemblyName(libraryPath); + var whitelistingResult = TryWhitelistAssemblyName(assName, singleFile); + switch (whitelistingResult) + { + case WhitelistingResult.Added: + added++; + break; + case WhitelistingResult.Updated: + updated++; + break; + case WhitelistingResult.Exists: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + catch + { + if (singleFile) + ShowNotification(new GUIContent("Selected file is not a valid .NET assembly!")); + } + } + + if (!singleFile) + { + ShowNotification(new GUIContent("Assemblies added: " + added + ", updated: " + updated)); + } + + return added > 0 || updated > 0; + } + + private WhitelistingResult TryWhitelistAssemblyName(AssemblyName assName, bool singleFile) + { + var result = WhitelistingResult.Exists; + + var assNameString = assName.Name; + var hash = InjectionRoutines.GetAssemblyHash(assName); + + var allowed = whitelist.FirstOrDefault(allowedAssembly => allowedAssembly.Name == assNameString); + + if (allowed != null) + { + if (allowed.AddHash(hash)) + { + if (singleFile) ShowNotification(new GUIContent("New hash added!")); + result = WhitelistingResult.Updated; + } + else + { + if (singleFile) ShowNotification(new GUIContent("Assembly already exists!")); + } + } + else + { + allowed = new AllowedAssembly(assNameString, new[] {hash}); + whitelist.Add(allowed); + + if (singleFile) ShowNotification(new GUIContent("Assembly added!")); + result = WhitelistingResult.Added; + } + + return result; + } + + private static void LoadAndParseWhitelist() + { + whitelist = ACTkSettings.Instance.InjectionDetectorWhiteList; + } + + private static void WriteWhitelist() + { + ACTkSettings.Instance.InjectionDetectorWhiteList = whitelist; + } + + ////////////////////////////////////// + + private enum WhitelistingResult : byte + { + Exists, + Added, + Updated + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs.meta new file mode 100644 index 0000000..0c8666a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: bd28be63d7a09224da0cac7e3178896d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes.meta new file mode 100644 index 0000000..41f398b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1140a4b6184eae45916fdae3da40a10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs new file mode 100644 index 0000000..9c25721 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs @@ -0,0 +1,253 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using Common; + using UnityEditor; + + public static partial class MigrateUtils + { + private static bool MigrateObscuredDouble(SerializedProperty sp) + { + var hiddenValue = sp.FindPropertyRelative("hiddenValue"); + if (hiddenValue == null) + return false; + + var fakeValue = sp.FindPropertyRelative("fakeValue"); + + var migratedVersion = sp.FindPropertyRelative("migratedVersion"); + if (migratedVersion != null) + { + if (migratedVersion.stringValue == MigrationVersion) + { + if (!fakeValue.prefabOverride) + return false; + } + + migratedVersion.stringValue = MigrationVersion; + } + + var hiddenValueOldProperty = sp.FindPropertyRelative("hiddenValueOldByte8"); + var hiddenValueOld = default(ACTkByte8); + var oldValueExists = false; + + if (hiddenValueOldProperty?.FindPropertyRelative("b1") != null) + { + hiddenValueOld.b1 = (byte)hiddenValueOldProperty.FindPropertyRelative("b1").intValue; + hiddenValueOld.b2 = (byte)hiddenValueOldProperty.FindPropertyRelative("b2").intValue; + hiddenValueOld.b3 = (byte)hiddenValueOldProperty.FindPropertyRelative("b3").intValue; + hiddenValueOld.b4 = (byte)hiddenValueOldProperty.FindPropertyRelative("b4").intValue; + hiddenValueOld.b5 = (byte)hiddenValueOldProperty.FindPropertyRelative("b5").intValue; + hiddenValueOld.b6 = (byte)hiddenValueOldProperty.FindPropertyRelative("b6").intValue; + hiddenValueOld.b7 = (byte)hiddenValueOldProperty.FindPropertyRelative("b7").intValue; + hiddenValueOld.b8 = (byte)hiddenValueOldProperty.FindPropertyRelative("b8").intValue; + + if (hiddenValueOld.b1 != 0 || + hiddenValueOld.b2 != 0 || + hiddenValueOld.b3 != 0 || + hiddenValueOld.b4 != 0 || + hiddenValueOld.b5 != 0 || + hiddenValueOld.b6 != 0 || + hiddenValueOld.b7 != 0 || + hiddenValueOld.b8 != 0) + { + oldValueExists = true; + } + } + + if (!oldValueExists) + return false; + + var union = new LongBytesUnion {b8 = hiddenValueOld}; + union.b8.Shuffle(); + hiddenValue.longValue = union.l; + + hiddenValueOldProperty.FindPropertyRelative("b1").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b2").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b3").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b4").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b5").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b6").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b7").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b8").intValue = 0; + + return true; + } + + private static bool MigrateObscuredFloat(SerializedProperty sp) + { + var hiddenValue = sp.FindPropertyRelative("hiddenValue"); + if (hiddenValue == null) + return false; + + var fakeValue = sp.FindPropertyRelative("fakeValue"); + + var migratedVersion = sp.FindPropertyRelative("migratedVersion"); + if (migratedVersion != null) + { + if (migratedVersion.stringValue == MigrationVersion) + { + if (!fakeValue.prefabOverride) + return false; + } + + migratedVersion.stringValue = MigrationVersion; + } + + var hiddenValueOldProperty = sp.FindPropertyRelative("hiddenValueOldByte4"); + var hiddenValueOld = default(ACTkByte4); + var oldValueExists = false; + + if (hiddenValueOldProperty?.FindPropertyRelative("b1") != null) + { + hiddenValueOld.b1 = (byte)hiddenValueOldProperty.FindPropertyRelative("b1").intValue; + hiddenValueOld.b2 = (byte)hiddenValueOldProperty.FindPropertyRelative("b2").intValue; + hiddenValueOld.b3 = (byte)hiddenValueOldProperty.FindPropertyRelative("b3").intValue; + hiddenValueOld.b4 = (byte)hiddenValueOldProperty.FindPropertyRelative("b4").intValue; + + if (hiddenValueOld.b1 != 0 || + hiddenValueOld.b2 != 0 || + hiddenValueOld.b3 != 0 || + hiddenValueOld.b4 != 0) + { + oldValueExists = true; + } + } + + if (!oldValueExists) + return false; + + var union = new FloatIntBytesUnion {b4 = hiddenValueOld}; + union.b4.Shuffle(); + hiddenValue.longValue = union.i; + + hiddenValueOldProperty.FindPropertyRelative("b1").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b2").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b3").intValue = 0; + hiddenValueOldProperty.FindPropertyRelative("b4").intValue = 0; + + return true; + } + + private static bool MigrateObscuredVector2(SerializedProperty sp) + { + var hiddenValue = sp.FindPropertyRelative("hiddenValue"); + if (hiddenValue == null) + return false; + + var fakeValue = sp.FindPropertyRelative("fakeValue"); + + var migratedVersion = sp.FindPropertyRelative("migratedVersion"); + if (migratedVersion != null) + { + if (migratedVersion.stringValue == MigrationVersion) + { + if (!fakeValue.prefabOverride) + return false; + } + + migratedVersion.stringValue = MigrationVersion; + } + + var hiddenValueX = hiddenValue.FindPropertyRelative("x"); + var hiddenValueY = hiddenValue.FindPropertyRelative("y"); + + var union = new FloatIntBytesUnion {i = hiddenValueX.intValue}; + union.b4.Shuffle(); + hiddenValueX.intValue = union.i; + + union.i = hiddenValueY.intValue; + union.b4.Shuffle(); + hiddenValueY.intValue = union.i; + + return true; + } + + private static bool MigrateObscuredVector3(SerializedProperty sp) + { + var hiddenValue = sp.FindPropertyRelative("hiddenValue"); + if (hiddenValue == null) + return false; + + var fakeValue = sp.FindPropertyRelative("fakeValue"); + + var migratedVersion = sp.FindPropertyRelative("migratedVersion"); + if (migratedVersion != null) + { + if (migratedVersion.stringValue == MigrationVersion) + { + if (!fakeValue.prefabOverride) + return false; + } + + migratedVersion.stringValue = MigrationVersion; + } + + var hiddenValueX = hiddenValue.FindPropertyRelative("x"); + var hiddenValueY = hiddenValue.FindPropertyRelative("y"); + var hiddenValueZ = hiddenValue.FindPropertyRelative("z"); + + var union = new FloatIntBytesUnion {i = hiddenValueX.intValue}; + union.b4.Shuffle(); + hiddenValueX.intValue = union.i; + + union.i = hiddenValueY.intValue; + union.b4.Shuffle(); + hiddenValueY.intValue = union.i; + + union.i = hiddenValueZ.intValue; + union.b4.Shuffle(); + hiddenValueZ.intValue = union.i; + + return true; + } + + private static bool MigrateObscuredQuaternion(SerializedProperty sp) + { + var hiddenValue = sp.FindPropertyRelative("hiddenValue"); + if (hiddenValue == null) + return false; + + var fakeValue = sp.FindPropertyRelative("fakeValue"); + + var migratedVersion = sp.FindPropertyRelative("migratedVersion"); + if (migratedVersion != null) + { + if (migratedVersion.stringValue == MigrationVersion) + { + if (!fakeValue.prefabOverride) + return false; + } + + migratedVersion.stringValue = MigrationVersion; + } + + var hiddenValueX = hiddenValue.FindPropertyRelative("x"); + var hiddenValueY = hiddenValue.FindPropertyRelative("y"); + var hiddenValueZ = hiddenValue.FindPropertyRelative("z"); + var hiddenValueW = hiddenValue.FindPropertyRelative("w"); + + var union = new FloatIntBytesUnion {i = hiddenValueX.intValue}; + union.b4.Shuffle(); + hiddenValueX.intValue = union.i; + + union.i = hiddenValueY.intValue; + union.b4.Shuffle(); + hiddenValueY.intValue = union.i; + + union.i = hiddenValueZ.intValue; + union.b4.Shuffle(); + hiddenValueZ.intValue = union.i; + + union.i = hiddenValueW.intValue; + union.b4.Shuffle(); + hiddenValueW.intValue = union.i; + + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs.meta new file mode 100644 index 0000000..93f08dd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.Routines.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7e1925e5a5f04349bee0d734c5705598 +timeCreated: 1621638102 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs new file mode 100644 index 0000000..5d5f03c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs @@ -0,0 +1,160 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using Common; + using System.Runtime.InteropServices; + using ObscuredTypes; + using PropertyDrawers; + using UnityEditor; + using UnityEngine; + using Object = UnityEngine.Object; + + /// + /// Class with utility functions to help with ACTk migrations after updates. + /// + public static partial class MigrateUtils + { + private const string MigrationVersion = "2"; + + /// + /// Checks all prefabs in project for old version of obscured types and tries to migrate values to the new version. + /// + public static void MigrateObscuredTypesOnPrefabs(params string[] typesToMigrate) + { + if (!EditorUtility.DisplayDialog("ACTk Obscured types migration", + "Are you sure you wish to scan all prefabs in your project and automatically migrate values to the new format?\n" + + GetWhatMigratesString(typesToMigrate), + "Yes", "No")) + { + Debug.Log(ACTk.LogPrefix + "Obscured types migration was canceled by user."); + return; + } + + EditorTools.TraverseSerializedScriptsAssets(ProcessProperty, typesToMigrate); + } + + /// + /// Checks all scenes in project for old version of obscured types and tries to migrate values to the new version. + /// + public static void MigrateObscuredTypesInScene(params string[] typesToMigrate) + { + if (!EditorUtility.DisplayDialog("ACTk Obscured types migration", + "Are you sure you wish to scan all opened scenes and automatically migrate values to the new format?\n" + + GetWhatMigratesString(typesToMigrate), + "Yes", "No")) + { + Debug.Log(ACTk.LogPrefix + "Obscured types migration was canceled by user."); + return; + } + + EditorTools.TraverseSerializedScriptsInScenes(ProcessProperty, typesToMigrate); + } + + private static bool ProcessProperty(Object target, SerializedProperty sp, string label, string type) + { + var modified = false; + + switch (type) + { + case "ObscuredDouble": + { + modified = MigrateObscuredDouble(sp); + break; + } + case "ObscuredFloat": + { + modified = MigrateObscuredFloat(sp); + break; + } + case "ObscuredVector2": + { + modified = MigrateObscuredVector2(sp); + break; + } + case "ObscuredVector3": + { + modified = MigrateObscuredVector3(sp); + break; + } + case "ObscuredQuaternion": + { + modified = MigrateObscuredQuaternion(sp); + break; + } + case "ObscuredString": + { + modified = MigrateObscuredStringIfNecessary(sp); + break; + } + } + + if (modified) + Debug.Log($"{ACTk.LogPrefix}Migrated property {sp.displayName}:{type} at the object {label}"); + + return modified; + } + + internal static bool MigrateObscuredStringIfNecessary(SerializedProperty sp) + { + var hiddenValueProperty = sp.FindPropertyRelative("hiddenValue"); + if (hiddenValueProperty == null) return false; + + var currentCryptoKeyOldProperty = sp.FindPropertyRelative("currentCryptoKey"); + if (currentCryptoKeyOldProperty == null) return false; + + var currentCryptoKeyOld = currentCryptoKeyOldProperty.stringValue; + if (string.IsNullOrEmpty(currentCryptoKeyOld)) return false; + + var hiddenCharsProperty = sp.FindPropertyRelative("hiddenChars"); + if (hiddenCharsProperty == null) return false; + + var hiddenValue = ObscuredStringDrawer.GetBytesObsolete(hiddenValueProperty); + + var decrypted = + ObscuredString.EncryptDecryptObsolete(ObscuredString.GetStringObsolete(hiddenValue), + currentCryptoKeyOld); + + var currentCryptoKey = ObscuredString.GenerateKey(); + var hiddenChars = ObscuredString.InternalEncryptDecrypt(decrypted.ToCharArray(), currentCryptoKey); + + ObscuredStringDrawer.SetChars(hiddenCharsProperty, hiddenChars); + var currentCryptoKeyProperty = sp.FindPropertyRelative("cryptoKey"); + ObscuredStringDrawer.SetChars(currentCryptoKeyProperty, currentCryptoKey); + + hiddenValueProperty.arraySize = 0; + currentCryptoKeyOldProperty.stringValue = null; + + return true; + } + + private static string GetWhatMigratesString(string[] typesToMigrate) + { + return string.Join(", ", typesToMigrate) + " will migrated."; + } + + [StructLayout(LayoutKind.Explicit)] + private struct LongBytesUnion + { + [FieldOffset(0)] + public readonly long l; + + [FieldOffset(0)] + public ACTkByte8 b8; + } + + [StructLayout(LayoutKind.Explicit)] + private struct FloatIntBytesUnion + { + [FieldOffset(0)] + public int i; + + [FieldOffset(0)] + public ACTkByte4 b4; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs.meta new file mode 100644 index 0000000..badd06f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/MigrateUtils.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1c7ff960ccd8a243ad385a3fe965e9e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers.meta new file mode 100644 index 0000000..8930a17 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: dfff86e18b5565b499779c37590c4d83 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs new file mode 100644 index 0000000..a9fe0fa --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs @@ -0,0 +1,122 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using System.Numerics; + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredBigInteger))] + internal class ObscuredBigIntegerDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label) + { + var hiddenValue = sp.FindPropertyRelative(nameof(ObscuredBigInteger.hiddenValue)); + var cryptoKey = sp.FindPropertyRelative(nameof(ObscuredBigInteger.currentCryptoKey)); + var inited = sp.FindPropertyRelative(nameof(ObscuredBigInteger.inited)); + var fakeValue = sp.FindPropertyRelative(nameof(ObscuredBigInteger.fakeValue)); + var fakeValueActive = sp.FindPropertyRelative(nameof(ObscuredBigInteger.fakeValueActive)); + + var currentCryptoKey = (uint)cryptoKey.intValue; + BigInteger val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + { + currentCryptoKey = ObscuredBigInteger.GenerateKey(); + cryptoKey.intValue = (int)currentCryptoKey; + } + + var encrypted = ObscuredBigInteger.Encrypt(0, currentCryptoKey); + SetBigInteger(hiddenValue, encrypted); + inited.boolValue = true; + SetBigInteger(fakeValue, 0); + } + else + { + val = ObscuredBigInteger.Decrypt(GetBigInteger(hiddenValue), currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, sp); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + var bigIntString = EditorGUI.DelayedTextField(position, label, val.ToString()); +#else + var bigIntString = EditorGUI.TextField(position, label, val.ToString()); +#endif + if (EditorGUI.EndChangeCheck()) + { + if (!BigInteger.TryParse(bigIntString, out var newValue)) + newValue = 0; + + var encrypted = ObscuredBigInteger.Encrypt(newValue, currentCryptoKey); + SetBigInteger(hiddenValue, encrypted); + SetBigInteger(fakeValue, newValue); + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + + private static BigInteger GetBigInteger(SerializedProperty serializableBigInteger) + { + var result = new SerializableBigInteger(); + var rawProperty = serializableBigInteger.FindPropertyRelative(nameof(SerializableBigInteger.raw)); + var signProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.sign)); + var bitsProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.bits)); + var bits = ReadBitsArray(bitsProperty); + + result.raw = new SerializableBigInteger.BigIntegerContents + { + sign = signProperty.intValue, + bits = bits + }; + + return result.value; + } + + private static void SetBigInteger(SerializedProperty serializableBigInteger, BigInteger value) + { + var explicitStruct = new SerializableBigInteger + { + value = value + }; + + var sign = explicitStruct.raw.sign; + var bits = explicitStruct.raw.bits; + + var rawProperty = serializableBigInteger.FindPropertyRelative(nameof(SerializableBigInteger.raw)); + var signProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.sign)); + var bitsProperty = rawProperty.FindPropertyRelative(nameof(SerializableBigInteger.BigIntegerContents.bits)); + + signProperty.intValue = sign; + WriteBitsArray(bitsProperty, bits); + } + + private static uint[] ReadBitsArray(SerializedProperty bits) + { + var count = bits.arraySize; + if (count == 0) + return null; + var result = new uint[count]; + for (var i = 0; i < count; i++) + result[i] = (uint)bits.GetArrayElementAtIndex(i).longValue; + + return result; + } + + private static void WriteBitsArray(SerializedProperty bitsProperty, uint[] bits) + { + bitsProperty.arraySize = bits?.Length ?? 0; + for (var i = 0; i < bits?.Length; i++) + bitsProperty.GetArrayElementAtIndex(i).longValue = bits[i]; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs.meta new file mode 100644 index 0000000..809b2bf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c48a363379404a3f8ffa0970bd1f7653 +timeCreated: 1653693062 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs new file mode 100644 index 0000000..0312bf7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs @@ -0,0 +1,54 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredBool))] + internal class ObscuredBoolDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label) + { + var hiddenValue = sp.FindPropertyRelative(nameof(ObscuredBool.hiddenValue)); + var cryptoKey = sp.FindPropertyRelative(nameof(ObscuredBool.currentCryptoKey)); + var inited = sp.FindPropertyRelative(nameof(ObscuredBool.inited)); + var fakeValue = sp.FindPropertyRelative(nameof(ObscuredBool.fakeValue)); + var fakeValueActive = sp.FindPropertyRelative(nameof(ObscuredBool.fakeValueActive)); + + var currentCryptoKey = cryptoKey.intValue; + var val = false; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredBool.GenerateKey(); + inited.boolValue = true; + hiddenValue.intValue = ObscuredBool.Encrypt(false, (byte)currentCryptoKey); + } + else + { + val = ObscuredBool.Decrypt(hiddenValue.intValue, (byte)currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, sp); + + EditorGUI.BeginChangeCheck(); + val = EditorGUI.Toggle(position, label, val); + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.intValue = ObscuredBool.Encrypt(val, (byte)currentCryptoKey); + + fakeValue.boolValue = val; + fakeValueActive.boolValue = true; + } + + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs.meta new file mode 100644 index 0000000..2e7aeaa --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2a0ae33a4804dd5468c37cee3d9e4a15 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs new file mode 100644 index 0000000..f75b85b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs @@ -0,0 +1,74 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Globalization; +using CodeStage.AntiCheat.ObscuredTypes; +using UnityEditor; +using UnityEngine; + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + [CustomPropertyDrawer(typeof(ObscuredDateTime))] + internal class ObscuredDateTimeDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredDateTime.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredDateTime.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredDateTime.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredDateTime.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredDateTime.fakeValueActive)); + + var currentCryptoKey = cryptoKey.longValue; + var val = new DateTime(0); + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.longValue = ObscuredDateTime.GenerateKey(); + hiddenValue.longValue = ObscuredDateTime.Encrypt(new DateTime(0), currentCryptoKey); + inited.boolValue = true; + } + else + { + val = ObscuredDateTime.Decrypt(hiddenValue.longValue, currentCryptoKey); + } + + var labelRect = position; + labelRect.width = position.width * 0.75f; + label = EditorGUI.BeginProperty(labelRect, label, prop); + EditorGUI.BeginChangeCheck(); + var dateString = val.ToString("o", DateTimeFormatInfo.InvariantInfo); + var input = EditorGUI.DelayedTextField(labelRect, label, dateString); + if (EditorGUI.EndChangeCheck()) + { + DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out val); + hiddenValue.longValue = ObscuredDateTime.Encrypt(val, currentCryptoKey); + fakeValue.longValue = val.ToBinary(); + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + + var kindRect = position; + kindRect.x = labelRect.xMax + 5; + kindRect.width = position.width * 0.25f - 5; + label = EditorGUI.BeginProperty(kindRect, GUIContent.none, prop); + + EditorGUI.BeginChangeCheck(); + var kind = val.Kind; + var kindInput = (DateTimeKind)EditorGUI.EnumPopup(kindRect, label, kind); + if (EditorGUI.EndChangeCheck()) + { + val = DateTime.SpecifyKind(val, kindInput); + hiddenValue.longValue = ObscuredDateTime.Encrypt(val, currentCryptoKey); + fakeValue.longValue = val.ToBinary(); + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs.meta new file mode 100644 index 0000000..27af3e4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d4822eb673254d3fa09b8add898e8445 +timeCreated: 1684493697 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs new file mode 100644 index 0000000..3895533 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs @@ -0,0 +1,143 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using Common; + using ObscuredTypes; + + using System.Globalization; + using System.Runtime.InteropServices; + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredDecimal))] + internal class ObscuredDecimalDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredDecimal.hiddenValue)); + var hiddenValue1 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b1)); + var hiddenValue2 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b2)); + var hiddenValue3 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b3)); + var hiddenValue4 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b4)); + var hiddenValue5 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b5)); + var hiddenValue6 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b6)); + var hiddenValue7 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b7)); + var hiddenValue8 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b8)); + var hiddenValue9 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b9)); + var hiddenValue10 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b10)); + var hiddenValue11 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b11)); + var hiddenValue12 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b12)); + var hiddenValue13 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b13)); + var hiddenValue14 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b14)); + var hiddenValue15 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b15)); + var hiddenValue16 = hiddenValue.FindPropertyRelative(nameof(ACTkByte16.b16)); + + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredDecimal.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredDecimal.inited)); + //SerializedProperty fakeValue = prop.FindPropertyRelative("fakeValue"); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredDecimal.fakeValueActive)); + + var currentCryptoKey = cryptoKey.longValue; + var union = new DecimalBytesUnion(); + decimal val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.longValue = ObscuredDecimal.GenerateKey(); + inited.boolValue = true; + + union.d = ObscuredDecimal.Encrypt(0, currentCryptoKey); + + hiddenValue1.intValue = union.b16.b1; + hiddenValue2.intValue = union.b16.b2; + hiddenValue3.intValue = union.b16.b3; + hiddenValue4.intValue = union.b16.b4; + hiddenValue5.intValue = union.b16.b5; + hiddenValue6.intValue = union.b16.b6; + hiddenValue7.intValue = union.b16.b7; + hiddenValue8.intValue = union.b16.b8; + hiddenValue9.intValue = union.b16.b9; + hiddenValue10.intValue = union.b16.b10; + hiddenValue11.intValue = union.b16.b11; + hiddenValue12.intValue = union.b16.b12; + hiddenValue13.intValue = union.b16.b13; + hiddenValue14.intValue = union.b16.b14; + hiddenValue15.intValue = union.b16.b15; + hiddenValue16.intValue = union.b16.b16; + } + else + { + union.b16.b1 = (byte)hiddenValue1.intValue; + union.b16.b2 = (byte)hiddenValue2.intValue; + union.b16.b3 = (byte)hiddenValue3.intValue; + union.b16.b4 = (byte)hiddenValue4.intValue; + union.b16.b5 = (byte)hiddenValue5.intValue; + union.b16.b6 = (byte)hiddenValue6.intValue; + union.b16.b7 = (byte)hiddenValue7.intValue; + union.b16.b8 = (byte)hiddenValue8.intValue; + union.b16.b9 = (byte)hiddenValue9.intValue; + union.b16.b10 = (byte)hiddenValue10.intValue; + union.b16.b11 = (byte)hiddenValue11.intValue; + union.b16.b12 = (byte)hiddenValue12.intValue; + union.b16.b13 = (byte)hiddenValue13.intValue; + union.b16.b14 = (byte)hiddenValue14.intValue; + union.b16.b15 = (byte)hiddenValue15.intValue; + union.b16.b16 = (byte)hiddenValue16.intValue; + + val = ObscuredDecimal.Decrypt(union.d, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + var input = EditorGUI.DelayedTextField(position, label, val.ToString(CultureInfo.InvariantCulture)); +#else + var input = EditorGUI.TextField(position, label, val.ToString(CultureInfo.InvariantCulture)); +#endif + decimal.TryParse(input, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out val); + if (EditorGUI.EndChangeCheck()) + { + union.d = ObscuredDecimal.Encrypt(val, currentCryptoKey); + + hiddenValue1.intValue = union.b16.b1; + hiddenValue2.intValue = union.b16.b2; + hiddenValue3.intValue = union.b16.b3; + hiddenValue4.intValue = union.b16.b4; + hiddenValue5.intValue = union.b16.b5; + hiddenValue6.intValue = union.b16.b6; + hiddenValue7.intValue = union.b16.b7; + hiddenValue8.intValue = union.b16.b8; + hiddenValue9.intValue = union.b16.b9; + hiddenValue10.intValue = union.b16.b10; + hiddenValue11.intValue = union.b16.b11; + hiddenValue12.intValue = union.b16.b12; + hiddenValue13.intValue = union.b16.b13; + hiddenValue14.intValue = union.b16.b14; + hiddenValue15.intValue = union.b16.b15; + hiddenValue16.intValue = union.b16.b16; + + //fakeValue.doubleValue = 0; + fakeValueActive.boolValue = false; + } + + EditorGUI.EndProperty(); + } + + [StructLayout(LayoutKind.Explicit)] + private struct DecimalBytesUnion + { + [FieldOffset(0)] + public decimal d; + + [FieldOffset(0)] + public ACTkByte16 b16; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs.meta new file mode 100644 index 0000000..6f3fbe7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDecimalDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b695953c62fb4e84aa3bcf20ed203871 +timeCreated: 1508363700 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs new file mode 100644 index 0000000..c11479b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs @@ -0,0 +1,59 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredDouble))] + internal class ObscuredDoubleDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredDouble.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredDouble.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredDouble.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredDouble.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredDouble.fakeValueActive)); + + var currentCryptoKey = cryptoKey.longValue; + + double val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.longValue = ObscuredDouble.GenerateKey(); + + inited.boolValue = true; + hiddenValue.longValue = ObscuredDouble.Encrypt(0, currentCryptoKey); + } + else + { + val = ObscuredDouble.Decrypt(hiddenValue.longValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + val = EditorGUI.DelayedDoubleField(position, label, val); +#else + val = EditorGUI.DoubleField(position, label, val); +#endif + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.longValue = ObscuredDouble.Encrypt(val, currentCryptoKey); + fakeValue.doubleValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs.meta new file mode 100644 index 0000000..82d9949 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDoubleDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 5f1f384feecf6f94e9229f7d2b8ea644 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs new file mode 100644 index 0000000..79e776e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs @@ -0,0 +1,59 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredFloat))] + internal class ObscuredFloatDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredFloat.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredFloat.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredFloat.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredFloat.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredFloat.fakeValueActive)); + + var currentCryptoKey = cryptoKey.intValue; + + float val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredFloat.GenerateKey(); + + inited.boolValue = true; + hiddenValue.intValue = ObscuredFloat.Encrypt(0, currentCryptoKey); + } + else + { + val = ObscuredFloat.Decrypt(hiddenValue.intValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + val = EditorGUI.DelayedFloatField(position, label, val); +#else + val = EditorGUI.FloatField(position, label, val); +#endif + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.intValue = ObscuredFloat.Encrypt(val, currentCryptoKey); + fakeValue.floatValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs.meta new file mode 100644 index 0000000..38c472d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredFloatDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 68a1078367903c94bb9914b21b55172d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs new file mode 100644 index 0000000..cd1d71c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs @@ -0,0 +1,57 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredInt))] + internal class ObscuredIntDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredInt.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredInt.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredInt.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredInt.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredInt.fakeValueActive)); + + var currentCryptoKey = cryptoKey.intValue; + var val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredInt.GenerateKey(); + hiddenValue.intValue = ObscuredInt.Encrypt(0, currentCryptoKey); + inited.boolValue = true; + } + else + { + val = ObscuredInt.Decrypt(hiddenValue.intValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + val = EditorGUI.DelayedIntField(position, label, val); +#else + val = EditorGUI.IntField(position, label, val); +#endif + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.intValue = ObscuredInt.Encrypt(val, currentCryptoKey); + fakeValue.intValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs.meta new file mode 100644 index 0000000..068d4e5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredIntDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0d720256b4500364ba597cd9f71f28e1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs new file mode 100644 index 0000000..1a6531c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs @@ -0,0 +1,53 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredLong))] + internal class ObscuredLongDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredLong.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredLong.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredLong.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredLong.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredLong.fakeValueActive)); + + var currentCryptoKey = cryptoKey.longValue; + long val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.longValue = ObscuredLong.GenerateKey(); + hiddenValue.longValue = ObscuredLong.Encrypt(0, currentCryptoKey); + inited.boolValue = true; + } + else + { + val = ObscuredLong.Decrypt(hiddenValue.longValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); + val = EditorGUI.LongField(position, label, val); + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.longValue = ObscuredLong.Encrypt(val, currentCryptoKey); + fakeValue.longValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs.meta new file mode 100644 index 0000000..3ae7e60 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredLongDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 98c9f8eb20d73134e96287318b713c39 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs new file mode 100644 index 0000000..31924c5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs @@ -0,0 +1,90 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredQuaternion))] + internal class ObscuredQuaternionDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredQuaternion.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredQuaternion.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredQuaternion.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredQuaternion.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredQuaternion.fakeValueActive)); + + var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.x)); + var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.y)); + var hiddenValueZ = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.z)); + var hiddenValueW = hiddenValue.FindPropertyRelative(nameof(ObscuredQuaternion.RawEncryptedQuaternion.w)); + + var currentCryptoKey = cryptoKey.intValue; + var val = Quaternion.identity; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredQuaternion.GenerateKey(); + var ev = ObscuredQuaternion.Encrypt(Quaternion.identity, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + hiddenValueZ.intValue = ev.z; + hiddenValueW.intValue = ev.w; + inited.boolValue = true; + + fakeValue.quaternionValue = Quaternion.identity; + } + else + { + var ev = new ObscuredQuaternion.RawEncryptedQuaternion + { + x = hiddenValueX.intValue, + y = hiddenValueY.intValue, + z = hiddenValueZ.intValue, + w = hiddenValueW.intValue + }; + val = ObscuredQuaternion.Decrypt(ev, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + EditorGUI.BeginChangeCheck(); + val = Vector4ToQuaternion(EditorGUI.Vector4Field(position, label, QuaternionToVector4(val))); + if (EditorGUI.EndChangeCheck()) + { + var ev = ObscuredQuaternion.Encrypt(val, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + hiddenValueZ.intValue = ev.z; + hiddenValueW.intValue = ev.w; + + fakeValue.quaternionValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f; + } + + private Vector4 QuaternionToVector4(Quaternion value) + { + return new Vector4(value.x, value.y, value.z, value.w); + } + + private Quaternion Vector4ToQuaternion(Vector4 value) + { + return new Quaternion(value.x, value.y, value.z, value.w); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs.meta new file mode 100644 index 0000000..22bae23 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredQuaternionDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1cd362a81eab4155a2f1585c5d7ba876 +timeCreated: 1544725257 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs new file mode 100644 index 0000000..e99035b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs @@ -0,0 +1,57 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredShort))] + internal class ObscuredShortDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredShort.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredShort.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredShort.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredShort.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredShort.fakeValueActive)); + + var currentCryptoKey = (short)cryptoKey.intValue; + short val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = (short)(cryptoKey.intValue = ObscuredShort.GenerateKey()); + hiddenValue.intValue = ObscuredShort.Encrypt(0, currentCryptoKey); + inited.boolValue = true; + } + else + { + val = ObscuredShort.Decrypt((short)hiddenValue.intValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + val = (short)EditorGUI.DelayedIntField(position, label, val); +#else + val = (short)EditorGUI.IntField(position, label, val); +#endif + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.intValue = ObscuredShort.Encrypt(val, currentCryptoKey); + fakeValue.intValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs.meta new file mode 100644 index 0000000..827ab60 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredShortDrawer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eaf7a22e1b4319f40b23596cea6556a4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs new file mode 100644 index 0000000..688bad4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs @@ -0,0 +1,137 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using System; + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredString))] + internal class ObscuredStringDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label) + { + MigrateUtils.MigrateObscuredStringIfNecessary(sp); + + var hiddenChars = sp.FindPropertyRelative(nameof(ObscuredString.hiddenChars)); + var cryptoKey = sp.FindPropertyRelative(nameof(ObscuredString.cryptoKey)); + var inited = sp.FindPropertyRelative(nameof(ObscuredString.inited)); + var fakeValue = sp.FindPropertyRelative(nameof(ObscuredString.fakeValue)); + var fakeValueActive = sp.FindPropertyRelative(nameof(ObscuredString.fakeValueActive)); + + var currentCryptoKey = GetChars(cryptoKey); + + var val = string.Empty; + + if (!inited.boolValue) + { + if (currentCryptoKey.Length == 0) + { + currentCryptoKey = ObscuredString.GenerateKey(); + SetChars(cryptoKey, currentCryptoKey); + } + inited.boolValue = true; + EncryptAndSetChars(val.ToCharArray(), hiddenChars, currentCryptoKey); + fakeValue.stringValue = val; + } + else + { + var size = hiddenChars.FindPropertyRelative("Array.size"); + var showMixed = size.hasMultipleDifferentValues; + + if (!showMixed) + { + for (var i = 0; i < hiddenChars.arraySize; i++) + { + showMixed |= hiddenChars.GetArrayElementAtIndex(i).hasMultipleDifferentValues; + if (showMixed) break; + } + } + + if (!showMixed) + val = Decrypt(hiddenChars, currentCryptoKey); + else + EditorGUI.showMixedValue = true; + } + + if (label.text.IndexOf('[') != -1) + { + var dataIndex = sp.propertyPath.IndexOf("Array.data[", StringComparison.Ordinal); + + if (dataIndex >= 0) + { + dataIndex += 11; + var index = "Element " + sp.propertyPath.Substring(dataIndex, sp.propertyPath.IndexOf("]", dataIndex, StringComparison.Ordinal) - dataIndex); + label.text = index; + } + } + + label = EditorGUI.BeginProperty(position, label, sp); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + val = EditorGUI.DelayedTextField(position, label, val); +#else + val = EditorGUI.TextField(position, label, val); +#endif + if (EditorGUI.EndChangeCheck()) + { + EncryptAndSetChars(val.ToCharArray(), hiddenChars, currentCryptoKey); + fakeValue.stringValue = val; + fakeValueActive.boolValue = true; + } + + EditorGUI.showMixedValue = false; + EditorGUI.EndProperty(); + } + + private static void EncryptAndSetChars(char[] val, SerializedProperty prop, char[] key) + { + var encrypted = ObscuredString.InternalEncryptDecrypt(val, key); + SetChars(prop, encrypted); + } + + private static string Decrypt(SerializedProperty hiddenChars, char[] currentCryptoKey) + { + var chars = new char[hiddenChars.arraySize]; + for (var i = 0; i < hiddenChars.arraySize; i++) + chars[i] = (char)hiddenChars.GetArrayElementAtIndex(i).intValue; + + return ObscuredString.Decrypt(chars, currentCryptoKey); + } + + public static byte[] GetBytesObsolete(SerializedProperty property) + { + var length = property.arraySize; + var result = new byte[length]; + for (var i = 0; i < length; i++) + result[i] = (byte)property.GetArrayElementAtIndex(i).intValue; + + return result; + } + + public static void SetChars(SerializedProperty property, char[] array) + { + property.ClearArray(); + property.arraySize = array.Length; + for (var i = 0; i < array.Length; i++) + property.GetArrayElementAtIndex(i).intValue = array[i]; + } + + private static char[] GetChars(SerializedProperty property) + { + var length = property.arraySize; + var result = new char[length]; + for (var i = 0; i < length; i++) + result[i] = (char)property.GetArrayElementAtIndex(i).intValue; + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs.meta new file mode 100644 index 0000000..ba004a1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredStringDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: db9197f5c028e5b4497f66a9b3217395 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs new file mode 100644 index 0000000..19fe011 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs @@ -0,0 +1,57 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredUInt))] + internal class ObscuredUIntDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredUInt.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredUInt.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredUInt.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredUInt.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredUInt.fakeValueActive)); + + var currentCryptoKey = (uint)cryptoKey.intValue; + uint val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + cryptoKey.intValue = (int)(currentCryptoKey = ObscuredUInt.GenerateKey()); + hiddenValue.intValue = (int)ObscuredUInt.Encrypt(0, currentCryptoKey); + inited.boolValue = true; + } + else + { + val = ObscuredUInt.Decrypt((uint)hiddenValue.intValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); +#if UNITY_2022_1_OR_NEWER + val = (uint)EditorGUI.DelayedIntField(position, label, (int)val); +#else + val = (uint)EditorGUI.IntField(position, label, (int)val); +#endif + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.intValue = (int)ObscuredUInt.Encrypt(val, currentCryptoKey); + fakeValue.intValue = (int)val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs.meta new file mode 100644 index 0000000..fe328a6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredUIntDrawer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 914802edc5dc95349a9903ac64be6343 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs new file mode 100644 index 0000000..665c357 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs @@ -0,0 +1,53 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredULong))] + internal class ObscuredULongDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredULong.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredULong.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredULong.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredULong.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredULong.fakeValueActive)); + + var currentCryptoKey = (ulong)cryptoKey.longValue; + ulong val = 0; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + cryptoKey.longValue = (long)(currentCryptoKey = ObscuredULong.GenerateKey()); + hiddenValue.longValue = (long)ObscuredULong.Encrypt(0, currentCryptoKey); + inited.boolValue = true; + } + else + { + val = ObscuredULong.Decrypt((ulong)hiddenValue.longValue, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); + val = (ulong)EditorGUI.LongField(position, label, (long)val); + if (EditorGUI.EndChangeCheck()) + { + hiddenValue.longValue = (long)ObscuredULong.Encrypt(val, currentCryptoKey); + fakeValue.longValue = (long)val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs.meta new file mode 100644 index 0000000..827a868 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredULongDrawer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: ae392b1c42e591945a2aa46d35119192 +timeCreated: 1484857585 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs new file mode 100644 index 0000000..0c8a584 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs @@ -0,0 +1,71 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredVector2))] + internal class ObscuredVector2Drawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredVector2.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredVector2.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredVector2.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredVector2.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredVector2.fakeValueActive)); + + var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredVector2.RawEncryptedVector2.x)); + var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredVector2.RawEncryptedVector2.y)); + + var currentCryptoKey = cryptoKey.intValue; + var val = Vector2.zero; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredVector2.GenerateKey(); + var ev = ObscuredVector2.Encrypt(Vector2.zero, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + inited.boolValue = true; + fakeValue.vector2Value = Vector2.zero; + } + else + { + var ev = new ObscuredVector2.RawEncryptedVector2 + { + x = hiddenValueX.intValue, + y = hiddenValueY.intValue + }; + val = ObscuredVector2.Decrypt(ev, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); + val = EditorGUI.Vector2Field(position, label, val); + if (EditorGUI.EndChangeCheck()) + { + var ev = ObscuredVector2.Encrypt(val, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + fakeValue.vector2Value = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs.meta new file mode 100644 index 0000000..8f15836 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2Drawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: bd9505d4322c45e4480aec264415f564 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs new file mode 100644 index 0000000..24b05de --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs @@ -0,0 +1,71 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredVector2Int))] + internal class ObscuredVector2IntDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredVector2Int.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredVector2Int.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredVector2Int.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredVector2Int.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredVector2Int.fakeValueActive)); + + var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredVector2Int.RawEncryptedVector2Int.x)); + var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredVector2Int.RawEncryptedVector2Int.y)); + + var currentCryptoKey = cryptoKey.intValue; + var val = Vector2Int.zero; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredVector2Int.GenerateKey(); + var ev = ObscuredVector2Int.Encrypt(Vector2Int.zero, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + inited.boolValue = true; + fakeValue.vector2IntValue = Vector2Int.zero; + } + else + { + var ev = new ObscuredVector2Int.RawEncryptedVector2Int + { + x = hiddenValueX.intValue, + y = hiddenValueY.intValue + }; + val = ObscuredVector2Int.Decrypt(ev, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); + val = EditorGUI.Vector2IntField(position, label, val); + if (EditorGUI.EndChangeCheck()) + { + var ev = ObscuredVector2Int.Encrypt(val, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + fakeValue.vector2IntValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs.meta new file mode 100644 index 0000000..2054d71 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector2IntDrawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 43349687f2537d343afec50a81e3e6a7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs new file mode 100644 index 0000000..bd6da5e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs @@ -0,0 +1,77 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredVector3))] + internal class ObscuredVector3Drawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredVector3.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredVector3.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredVector3.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredVector3.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredVector3.fakeValueActive)); + + var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredVector3.RawEncryptedVector3.x)); + var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredVector3.RawEncryptedVector3.y)); + var hiddenValueZ = hiddenValue.FindPropertyRelative(nameof(ObscuredVector3.RawEncryptedVector3.z)); + + var currentCryptoKey = cryptoKey.intValue; + var val = Vector3.zero; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredVector3.GenerateKey(); + var ev = ObscuredVector3.Encrypt(Vector3.zero, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + hiddenValueZ.intValue = ev.z; + inited.boolValue = true; + + fakeValue.vector3Value = Vector3.zero; + } + else + { + var ev = new ObscuredVector3.RawEncryptedVector3 + { + x = hiddenValueX.intValue, + y = hiddenValueY.intValue, + z = hiddenValueZ.intValue + }; + val = ObscuredVector3.Decrypt(ev, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); + val = EditorGUI.Vector3Field(position, label, val); + if (EditorGUI.EndChangeCheck()) + { + var ev = ObscuredVector3.Encrypt(val, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + hiddenValueZ.intValue = ev.z; + + fakeValue.vector3Value = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs.meta new file mode 100644 index 0000000..8bdcdf0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3Drawer.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ab13e15ddf3b1d24ea07503a57d84959 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs new file mode 100644 index 0000000..62d2613 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs @@ -0,0 +1,77 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers +{ + using ObscuredTypes; + + using UnityEditor; + using UnityEngine; + + [CustomPropertyDrawer(typeof(ObscuredVector3Int))] + internal class ObscuredVector3IntDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty prop, GUIContent label) + { + var hiddenValue = prop.FindPropertyRelative(nameof(ObscuredVector3Int.hiddenValue)); + var cryptoKey = prop.FindPropertyRelative(nameof(ObscuredVector3Int.currentCryptoKey)); + var inited = prop.FindPropertyRelative(nameof(ObscuredVector3Int.inited)); + var fakeValue = prop.FindPropertyRelative(nameof(ObscuredVector3Int.fakeValue)); + var fakeValueActive = prop.FindPropertyRelative(nameof(ObscuredVector3Int.fakeValueActive)); + + var hiddenValueX = hiddenValue.FindPropertyRelative(nameof(ObscuredVector3Int.RawEncryptedVector3Int.x)); + var hiddenValueY = hiddenValue.FindPropertyRelative(nameof(ObscuredVector3Int.RawEncryptedVector3Int.y)); + var hiddenValueZ = hiddenValue.FindPropertyRelative(nameof(ObscuredVector3Int.RawEncryptedVector3Int.z)); + + var currentCryptoKey = cryptoKey.intValue; + var val = Vector3Int.zero; + + if (!inited.boolValue) + { + if (currentCryptoKey == 0) + currentCryptoKey = cryptoKey.intValue = ObscuredVector3Int.GenerateKey(); + var ev = ObscuredVector3Int.Encrypt(Vector3Int.zero, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + hiddenValueZ.intValue = ev.z; + inited.boolValue = true; + + fakeValue.vector3IntValue = Vector3Int.zero; + } + else + { + var ev = new ObscuredVector3Int.RawEncryptedVector3Int + { + x = hiddenValueX.intValue, + y = hiddenValueY.intValue, + z = hiddenValueZ.intValue + }; + val = ObscuredVector3Int.Decrypt(ev, currentCryptoKey); + } + + label = EditorGUI.BeginProperty(position, label, prop); + + EditorGUI.BeginChangeCheck(); + val = EditorGUI.Vector3IntField(position, label, val); + if (EditorGUI.EndChangeCheck()) + { + var ev = ObscuredVector3Int.Encrypt(val, currentCryptoKey); + hiddenValueX.intValue = ev.x; + hiddenValueY.intValue = ev.y; + hiddenValueZ.intValue = ev.z; + + fakeValue.vector3IntValue = val; + fakeValueActive.boolValue = true; + } + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs.meta new file mode 100644 index 0000000..3c0e388 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredVector3IntDrawer.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 457d09d2ffa45754ea88b27085364169 +timeCreated: 1508447688 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator.meta new file mode 100644 index 0000000..e3a9905 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 071f007b436a44fc8f2b6425b606b621 +timeCreated: 1666516531 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs new file mode 100644 index 0000000..3723829 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs @@ -0,0 +1,87 @@ +namespace CodeStage.AntiCheat.EditorCode +{ + using System.Linq; + using Common; + using ObscuredTypes; + using UnityEditor; + using UnityEngine; + + public delegate void InvalidPropertyFound(Object target, SerializedProperty sp, string location, string type); + + public static class ObscuredTypesValidator + { + private static InvalidPropertyFound lastPassedCallback; + + /// + /// Traverses all prefabs and scriptable objects in the project and checks if they contain any Obscured types with anomalies. + /// + /// Pass callback if you wish to process invalid objects. + public static void ValidateProjectAssets(InvalidPropertyFound callback = null) + { + if (!EditorUtility.DisplayDialog("ACTk Obscured types validation", + "Are you sure you wish to scan all assets (except scenes) in your project and validate all found obscured types?\n" + + "This can take some time to complete.", + "Yes", "No")) + { + Debug.Log(ACTk.LogPrefix + "Obscured types validation was canceled by user."); + return; + } + + var types = TypeCache.GetTypesDerivedFrom().Where(t => !t.IsAbstract && !t.IsInterface) + .Select(type => type.Name).ToArray(); + lastPassedCallback = callback; + EditorTools.TraverseSerializedScriptsAssets(ValidateProperty, types); + lastPassedCallback = null; + } + + /// + /// Traverse all currently opened scenes and checks if they contain any Components with non-valid Obscured types. + /// + /// Pass callback if you wish to process invalid objects. + public static void ValidateOpenedScenes(InvalidPropertyFound callback = null) + { + if (!EditorUtility.DisplayDialog("ACTk Obscured types validation", + "Are you sure you wish to scan all opened Scenes and validate all found obscured types?\n" + + "This can take some time to complete.", + "Yes", "No")) + { + Debug.Log(ACTk.LogPrefix + "Obscured types validation was canceled by user."); + return; + } + + var types = TypeCache.GetTypesDerivedFrom().Where(t => !t.IsAbstract && !t.IsInterface) + .Select(type => type.Name).ToArray(); + lastPassedCallback = callback; + EditorTools.TraverseSerializedScriptsInScenes(ValidateProperty, types); + lastPassedCallback = null; + } + + private static bool ValidateProperty(Object target, SerializedProperty sp, string location, string type) + { + var obscured = sp.GetValue(); + if (obscured is ObscuredBigInteger obi && !obi.IsDataValid || + obscured is ObscuredBool ob && !ob.IsDataValid || + obscured is ObscuredDecimal ode && !ode.IsDataValid || + obscured is ObscuredDouble od && !od.IsDataValid || + obscured is ObscuredFloat of && !of.IsDataValid || + obscured is ObscuredInt oi && !oi.IsDataValid || + obscured is ObscuredLong ol && !ol.IsDataValid || + obscured is ObscuredQuaternion oq && !oq.IsDataValid || + obscured is ObscuredShort os && !os.IsDataValid || + obscured is ObscuredString ost && !ost.IsDataValid || + obscured is ObscuredUInt oui && !oui.IsDataValid || + obscured is ObscuredULong oul && !oul.IsDataValid || + obscured is ObscuredVector2 ov2 && !ov2.IsDataValid || + obscured is ObscuredVector2Int ov2Int && !ov2Int.IsDataValid || + obscured is ObscuredVector3 ov3 && !ov3.IsDataValid || + obscured is ObscuredVector3Int ov3Int && !ov3Int.IsDataValid) + { + lastPassedCallback?.Invoke(target, sp, location, type); + target = EditorTools.GetPingableObject(target); + Debug.LogError($"{ACTk.LogPrefix}Obscured Types Validator found invalid Property [{sp.displayName}] of type [{type}] at:\n{location}", target); + } + + return false; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs.meta new file mode 100644 index 0000000..7b6087f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Validator/ObscuredTypesValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7ec1712370d34ee1b38697a83d773c14 +timeCreated: 1666516545 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor.meta new file mode 100644 index 0000000..6c3fbac --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d318c64b7444f8543b210f1d70344386 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs new file mode 100644 index 0000000..4b49c6f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs @@ -0,0 +1,447 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections.Generic; + using Common; + using Storage; + using UnityEditor; + using UnityEngine; + + internal partial class ACTkPrefsEditor + { + // ------------------------------------------------------------------- + // UI + // ------------------------------------------------------------------- + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Prefs Editor as Tab...", false, 500)] + internal static void ShowWindow() + { + var myself = GetWindow(false, "Prefs Editor", true); + myself.minSize = new Vector2(500, 300); + myself.RefreshData(); + } + + [MenuItem(ACTkEditorConstants.ToolsMenuPath + "Prefs Editor as Utility...", false, 501)] + internal static void ShowWindowUtility() + { + var myself = GetWindow(true, "Prefs Editor", true); + myself.minSize = new Vector2(500, 300); + myself.RefreshData(); + } + + public void AddItemsToMenu(GenericMenu menu) + { + menu.AddItem(new GUIContent("Copy Player Prefs path"), false, OnCopyPrefsPath); + menu.AddSeparator(""); + } + + private void DrawGUI() + { + if (allRecords == null) allRecords = new List(); + if (filteredRecords == null) filteredRecords = new List(); + + DrawToolbar(); + + if (addingNewRecord) + { + DrawAddNewRecordPanel(); + } + + using (GUITools.Vertical(GUITools.PanelWithBackground)) + { + GUILayout.Space(5); + + DrawRecordsPages(); + + GUILayout.Space(5); + + DrawFooterButtons(); + } + } + + private void DrawToolbar() + { + using (GUITools.Horizontal(GUITools.Toolbar)) + { + if (GUILayout.Button(new GUIContent("+", "Create new prefs record."), EditorStyles.toolbarButton, GUILayout.Width(20))) + { + addingNewRecord = true; + } + + if (GUILayout.Button(new GUIContent("Refresh", "Re-read and re-parse all prefs."), EditorStyles.toolbarButton, GUILayout.Width(55))) + { + RefreshData(); + GUIUtility.keyboardControl = 0; + scrollPosition = Vector2.zero; + recordsCurrentPage = 0; + } + + EditorGUI.BeginChangeCheck(); + sortingType = (SortingType)EditorGUILayout.EnumPopup(sortingType, EditorStyles.toolbarDropDown, GUILayout.Width(110)); + if (EditorGUI.EndChangeCheck()) + { + ApplySorting(); + } + + GUILayout.Space(10); + + EditorGUI.BeginChangeCheck(); + searchPattern = GUITools.SearchToolbar(searchPattern); + if (EditorGUI.EndChangeCheck()) + { + ApplyFiltering(); + } + } + } + + private void DrawAddNewRecordPanel() + { + using (GUITools.Horizontal(GUITools.PanelWithBackground)) + { + string[] types = {"String", "Int", "Float"}; + newRecordType = EditorGUILayout.Popup(newRecordType, types, GUILayout.Width(55)); + + newRecordEncrypted = GUILayout.Toggle(newRecordEncrypted, + new GUIContent("E", "Create new pref as encrypted ObscuredPref?"), GUITools.CompactButton, + GUILayout.Width(25)); + + var guiColor = GUI.color; + if (newRecordEncrypted) + { + GUI.color = obscuredColor; + } + + GUILayout.Label("Key:", GUILayout.ExpandWidth(false)); + newRecordKey = EditorGUILayout.TextField(newRecordKey); + GUILayout.Label("Value:", GUILayout.ExpandWidth(false)); + + if (newRecordType == 0) + { + newRecordStringValue = EditorGUILayout.TextField(newRecordStringValue); + } + else if (newRecordType == 1) + { + newRecordIntValue = EditorGUILayout.IntField(newRecordIntValue); + } + else + { + newRecordFloatValue = EditorGUILayout.FloatField(newRecordFloatValue); + } + + GUI.color = guiColor; + + if (GUILayout.Button("OK", GUITools.CompactButton, GUILayout.Width(30))) + { + AddNewRecord(); + } + + if (GUILayout.Button("Cancel", GUITools.CompactButton, GUILayout.Width(60))) + { + CloseNewRecordPanel(); + } + } + } + + private void CloseNewRecordPanel() + { + addingNewRecord = false; + newRecordKey = string.Empty; + newRecordStringValue = string.Empty; + newRecordIntValue = 0; + newRecordFloatValue = 0; + GUIUtility.keyboardControl = 0; + } + + private void DrawFooterButtons() + { + GUI.enabled = filteredRecords.Count > 0; + using (GUITools.Horizontal()) + { + if (GUILayout.Button("Encrypt ALL", GUITools.CompactButton)) + { + PerformEncryptAll(); + } + + if (GUILayout.Button("Decrypt ALL", GUITools.CompactButton)) + { + PerformDecryptAll(); + } + + if (GUILayout.Button("Save ALL", GUITools.CompactButton)) + { + PerformSaveAll(); + } + + if (GUILayout.Button("Delete ALL", GUITools.CompactButton)) + { + PerformDeleteAll(); + } + } + GUI.enabled = true; + } + + private void DrawRecordsPages() + { + recordsTotalPages = Math.Max(1,(int)Math.Ceiling((double)filteredRecords.Count / RecordsPerPage)); + + if (recordsCurrentPage < 0) recordsCurrentPage = 0; + if (recordsCurrentPage + 1 > recordsTotalPages) recordsCurrentPage = recordsTotalPages - 1; + + var fromRecord = recordsCurrentPage * RecordsPerPage; + var toRecord = fromRecord + Math.Min(RecordsPerPage, filteredRecords.Count - fromRecord); + + if (recordsTotalPages > 1) + { + GUILayout.Label("Prefs " + fromRecord + " - " + toRecord + " from " + filteredRecords.Count); + } + + scrollPosition = GUILayout.BeginScrollView(scrollPosition); + for (var i = fromRecord; i < toRecord; i++) + { + DrawRecord(i, out var recordRemoved); + if (recordRemoved) + { + break; + } + } + GUILayout.EndScrollView(); + + if (recordsTotalPages <= 1) return; + + GUILayout.Space(5); + using (GUITools.Horizontal()) + { + GUILayout.FlexibleSpace(); + + GUI.enabled = recordsCurrentPage > 0; + if (GUILayout.Button("<<", GUILayout.Width(50))) + { + RemoveNotification(); + recordsCurrentPage = 0; + scrollPosition = Vector2.zero; + } + if (GUILayout.Button("<", GUILayout.Width(50))) + { + RemoveNotification(); + recordsCurrentPage--; + scrollPosition = Vector2.zero; + } + GUI.enabled = true; + GUILayout.Label(recordsCurrentPage + 1 + " of " + recordsTotalPages, GUITools.CenteredLabel, GUILayout.Width(100)); + GUI.enabled = recordsCurrentPage < recordsTotalPages - 1; + if (GUILayout.Button(">", GUILayout.Width(50))) + { + RemoveNotification(); + recordsCurrentPage++; + scrollPosition = Vector2.zero; + } + if (GUILayout.Button(">>", GUILayout.Width(50))) + { + RemoveNotification(); + recordsCurrentPage = recordsTotalPages - 1; + scrollPosition = Vector2.zero; + } + GUI.enabled = true; + + GUILayout.FlexibleSpace(); + } + } + + private void DrawRecord(int recordIndex, out bool recordRemoved) + { + recordRemoved = false; + var record = filteredRecords[recordIndex]; + var guiColor = GUI.color; + + using (GUITools.Horizontal()) + { + if (GUILayout.Button(new GUIContent("X", "Delete this pref."), GUITools.CompactButton, GUILayout.Width(20))) + { + DeleteRecord(); + recordRemoved = true; + return; + } + + GUI.enabled = (record.dirtyValue || record.dirtyKey) && record.prefType != PrefsRecord.PrefsType.Unknown; + if (GUILayout.Button(new GUIContent("S", "Save changes in this pref."), GUITools.CompactButton, GUILayout.Width(20))) + { + record.Save(); + GUIUtility.keyboardControl = 0; + } + + DrawEncryptDecryptButtons(); + + if (GUILayout.Button(new GUIContent("...", "Other operations"), GUITools.CompactButton, GUILayout.Width(25))) + ShowOtherMenu(record); + + if (record.Obscured) + GUI.color = obscuredColor; + + GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown; + + DrawKey(); + DrawValue(); + + GUI.color = guiColor; + GUI.enabled = true; + + EditorGUILayout.LabelField(record.DisplayType, GUILayout.Width(70)); + } + + void DeleteRecord() + { + record.Delete(); + allRecords.Remove(record); + filteredRecords.Remove(record); + } + + void DrawEncryptDecryptButtons() + { + GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown; + if (record.Obscured) + { + GUI.enabled &= record.obscuredType == StorageDataType.String || + record.obscuredType == StorageDataType.Int32 || + record.obscuredType == StorageDataType.Single; + if (GUILayout.Button(new GUIContent("D", "Decrypt this pref using ObscuredPrefs"), GUITools.CompactButton, GUILayout.Width(25))) + { + record.Decrypt(); + GUIUtility.keyboardControl = 0; + } + } + else + { + if (GUILayout.Button(new GUIContent("E", "Encrypt this pref using ObscuredPrefs"), GUITools.CompactButton, GUILayout.Width(25))) + { + record.Encrypt(); + GUIUtility.keyboardControl = 0; + } + } + GUI.enabled = true; + } + + void DrawKey() + { + if (record.Obscured && !(record.obscuredType == StorageDataType.String || + record.obscuredType == StorageDataType.Int32 || + record.obscuredType == StorageDataType.Single)) + { + GUI.enabled = false; + EditorGUILayout.TextField(record.Key, GUILayout.MaxWidth(200), GUILayout.MinWidth(50)); + GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown; + } + else + { + record.Key = EditorGUILayout.TextField(record.Key, GUILayout.MaxWidth(200), GUILayout.MinWidth(50)); + } + } + + void DrawValue() + { + if (record.prefType == PrefsRecord.PrefsType.String && !record.Obscured || record.Obscured && record.obscuredType == StorageDataType.String) + { + // to avoid TextMeshGenerator error because of too much characters + if (record.StringValue.Length > 16382) + { + GUI.enabled = false; + EditorGUILayout.TextField(StringTooLong, GUILayout.MinWidth(150)); + GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown; + } + else + { + record.StringValue = EditorGUILayout.TextField(record.StringValue, GUILayout.MinWidth(150)); + } + } + else if (record.prefType == PrefsRecord.PrefsType.Int || (record.Obscured && record.obscuredType == StorageDataType.Int32)) + { + record.IntValue = EditorGUILayout.IntField(record.IntValue, GUILayout.MinWidth(150)); + } + else if (record.prefType == PrefsRecord.PrefsType.Float || (record.Obscured && record.obscuredType == StorageDataType.Single)) + { + record.FloatValue = EditorGUILayout.FloatField(record.FloatValue, GUILayout.MinWidth(150)); + } + else if (record.Obscured) + { + GUI.enabled = false; + EditorGUILayout.TextField(UnsupportedValueDescription, GUILayout.MinWidth(150)); + GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown; + } + else + { + GUI.enabled = false; + EditorGUILayout.TextField(UnknownValueDescription, GUILayout.MinWidth(150)); + GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown; + } + } + } + + private static void ShowOtherMenu(PrefsRecord record) + { + var menu = new GenericMenu(); + menu.AddItem(new GUIContent("Copy to clipboard"), false, () => + { + EditorGUIUtility.systemCopyBuffer = record.ToString(); + }); + + if (record.Obscured) + { + menu.AddItem(new GUIContent("Copy obscured raw data to clipboard"), false, () => + { + EditorGUIUtility.systemCopyBuffer = record.ToString(true); + }); + } + + var valueToPaste = EditorGUIUtility.systemCopyBuffer; + switch (record.prefType) + { + case PrefsRecord.PrefsType.Unknown: + break; + case PrefsRecord.PrefsType.String: + if (!record.Obscured || record.IsEditableObscuredValue()) + { + menu.AddItem(new GUIContent("Paste string value from clipboard"), false, () => + { + record.StringValue = valueToPaste; + }); + } + break; + case PrefsRecord.PrefsType.Int: + menu.AddItem(new GUIContent("Paste int value from clipboard"), false, () => + { + if (int.TryParse(valueToPaste, out var pastedInt)) + { + record.IntValue = pastedInt; + } + else + { + Debug.LogWarning(ACTk.LogPrefix + "Can't paste this value to Int pref:\n" + valueToPaste); + } + }); + break; + case PrefsRecord.PrefsType.Float: + menu.AddItem(new GUIContent("Paste float value from clipboard"), false, () => + { + if (float.TryParse(valueToPaste, out var pastedFloat)) + { + record.FloatValue = pastedFloat; + } + else + { + Debug.LogWarning(ACTk.LogPrefix + "Can't paste this value to Float pref:\n" + valueToPaste); + } + }); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + menu.ShowAsContext(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs.meta new file mode 100644 index 0000000..73ee8ec --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.UI.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bb4576e186e147a4875e8c81476e9040 +timeCreated: 1621638706 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs new file mode 100644 index 0000000..1867112 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs @@ -0,0 +1,398 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using Common; + using Storage; + + using System; + using System.Collections.Generic; + using UnityEditor; + using UnityEditor.Callbacks; + using UnityEngine; +#if UNITY_EDITOR_WIN + using Microsoft.Win32; +#elif UNITY_EDITOR_OSX + using System.IO; +#else // LINUX + using System.IO; + using System.Xml; +#endif + + internal partial class ACTkPrefsEditor : EditorWindow, IHasCustomMenu + { + internal const string UnknownValueDescription = "Value corrupted / wrong Unity version"; + internal const string UnsupportedValueDescription = "Not editable value"; + + private const int RecordsPerPage = 50; + private const string StringTooLong = "String is too long"; + + internal static ACTkPrefsEditor instance; + + // 180, 255, 180, 255 + // note the 2 alpha - it's to make disabled components look as usual + private readonly Color obscuredColor = new Color(0.706f, 1f, 0.706f, 2f); + + [SerializeField] + private SortingType sortingType = SortingType.KeyAscending; + + [SerializeField] + private string searchPattern; + + [SerializeField] + private List allRecords; + + [SerializeField] + private List filteredRecords; + + [SerializeField] + private Vector2 scrollPosition; + + [SerializeField] + private int recordsCurrentPage; + + [SerializeField] + private int recordsTotalPages; + + [SerializeField] + private bool addingNewRecord; + + [SerializeField] + private int newRecordType; + + [SerializeField] + private bool newRecordEncrypted; + + [SerializeField] + private string newRecordKey; + + [SerializeField] + private string newRecordStringValue; + + [SerializeField] + private int newRecordIntValue; + + [SerializeField] + private float newRecordFloatValue; + + [DidReloadScripts] + private static void OnRecompile() + { + if (instance) instance.Repaint(); + } + + private void OnEnable() + { + instance = this; + RefreshData(); + } + + private void OnGUI() + { + DrawGUI(); + } + + private void AddNewRecord() + { + if (string.IsNullOrEmpty(newRecordKey) || + newRecordType == 0 && string.IsNullOrEmpty(newRecordStringValue) || + newRecordType == 1 && newRecordIntValue == 0 || + newRecordType == 2 && Math.Abs(newRecordFloatValue) < 0.00000001f) + { + ShowNotification(new GUIContent("Please fill in the pref first!")); + } + else + { + PrefsRecord newRecord; + + switch (newRecordType) + { + case 0: + newRecord = new PrefsRecord(newRecordKey, newRecordStringValue, newRecordEncrypted); + break; + case 1: + newRecord = new PrefsRecord(newRecordKey, newRecordIntValue, newRecordEncrypted); + break; + default: + newRecord = new PrefsRecord(newRecordKey, newRecordFloatValue, newRecordEncrypted); + break; + } + + if (newRecord.Save()) + { + allRecords.Add(newRecord); + ApplySorting(); + CloseNewRecordPanel(); + } + } + } + + private void PerformEncryptAll() + { + if (EditorUtility.DisplayDialog("Obscure ALL prefs in list?", "This will apply obscuration to ALL unobscured prefs in the list.\nAre you sure you wish to do this?", "Yep", "Oh, no!")) + { + foreach (var record in filteredRecords) + { + record.Encrypt(); + } + GUIUtility.keyboardControl = 0; + ApplySorting(); + } + } + + private void PerformDecryptAll() + { + if (EditorUtility.DisplayDialog("UnObscure ALL prefs in list?", "This will remove obscuration from ALL obscured prefs in the list if possible.\nAre you sure you wish to do this?", "Yep", "Oh, no!")) + { + foreach (var record in filteredRecords) + { + record.Decrypt(); + } + GUIUtility.keyboardControl = 0; + ApplySorting(); + } + } + + private void PerformSaveAll() + { + if (EditorUtility.DisplayDialog("Save changes to ALL prefs in list?", "Are you sure you wish to save changes to ALL prefs in the list? This can't be undone!", "Yep", "Oh, no!")) + { + foreach (var record in filteredRecords) + { + record.Save(); + } + GUIUtility.keyboardControl = 0; + ApplySorting(); + } + } + + private void PerformDeleteAll() + { + if (EditorUtility.DisplayDialog("Delete ALL prefs in list?", "Are you sure you wish to delete the ALL prefs in the list? This can't be undone!", "Yep", "Oh, no!")) + { + foreach (var record in filteredRecords) + { + record.Delete(); + } + + RefreshData(); + GUIUtility.keyboardControl = 0; + } + } + + private void RefreshData() + { + var keys = new List(); +#if UNITY_EDITOR_WIN + keys.AddRange(ReadKeysWin()); +#elif UNITY_EDITOR_OSX + keys.AddRange(ReadKeysOSX()); +#else // LINUX + keys.AddRange(ReadKeysLinux()); +#endif + keys.RemoveAll(IgnoredPrefsKeys); + + if (allRecords == null) allRecords = new List(); + if (filteredRecords == null) filteredRecords = new List(); + + allRecords.Clear(); + filteredRecords.Clear(); + + var keysCount = keys.Count; + var showProgress = keysCount >= 500; + + for (var i = 0; i < keysCount; i++) + { + var keyName = keys[i]; + if (showProgress) + { + if (EditorUtility.DisplayCancelableProgressBar("Reading PlayerPrefs [" + (i + 1) + " of " + keysCount + "]", "Reading " + keyName, (float)i/keysCount)) + { + break; + } + } + allRecords.Add(new PrefsRecord(keyName)); + } + + if (showProgress) EditorUtility.ClearProgressBar(); + + ApplySorting(); + } + + private void ApplyFiltering() + { + filteredRecords.Clear(); + if (string.IsNullOrEmpty(searchPattern)) + { + filteredRecords.AddRange(allRecords); + } + else + { + foreach (var record in allRecords) + { + if (record.Key.ToLowerInvariant().Contains(searchPattern.Trim().ToLowerInvariant())) + { + filteredRecords.Add(record); + } + } + } + } + + private void ApplySorting() + { + switch (sortingType) + { + case SortingType.KeyAscending: + allRecords.Sort(PrefsRecord.SortByNameAscending); + break; + case SortingType.KeyDescending: + allRecords.Sort(PrefsRecord.SortByNameDescending); + break; + case SortingType.Type: + allRecords.Sort(PrefsRecord.SortByType); + break; + case SortingType.Obscurance: + allRecords.Sort(PrefsRecord.SortByObscurance); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + ApplyFiltering(); + } + + private bool IgnoredPrefsKeys(string key) + { + return key == ObscuredPrefs.PrefsKey || + key == "OwsfBQ8qISsHHho6ACAJAiAAKRI2GjIDFh4EIQ0o" || + key == "UnityGraphicsQuality" || + key == "UnitySelectMonitor" || + key == "Screenmanager Resolution Width" || + key == "Screenmanager Resolution Height" || + key == "Screenmanager Is Fullscreen mode" || + key == "unity.cloud_userid" || + key == "unity.player_session_background_time" || + key == "unity.player_session_elapsed_time" || + key == "unity.player_sessionid" || + key == "unity.player_session_count" || + key == "UnityUdpSdkImported" || + key.StartsWith("PackageUpdaterLastChecked"); + } + + private void OnCopyPrefsPath() + { + EditorGUIUtility.systemCopyBuffer = GetPrefsPath(); + instance.ShowNotification(new GUIContent("Player Prefs path copied to clipboard")); + } + + private string GetPrefsPath() + { +#if UNITY_EDITOR_WIN + return "Software\\Unity\\UnityEditor\\" + PlayerSettings.companyName + "\\" + PlayerSettings.productName; +#elif UNITY_EDITOR_OSX + return Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "/Library/Preferences/unity." + + PlayerSettings.companyName + "." + PlayerSettings.productName + ".plist"; +#else // LINUX! + return Environment.GetFolderPath(Environment.SpecialFolder.Personal) + "/.config/unity3d/" + + PlayerSettings.companyName + "/" + PlayerSettings.productName + "/prefs"; +#endif + } + +#if UNITY_EDITOR_WIN + private string[] ReadKeysWin() + { + var prefsPath = GetPrefsPath(); + var registryLocation = Registry.CurrentUser.CreateSubKey(prefsPath); + if (registryLocation == null) + { + Debug.LogWarning($"{ACTk.LogPrefix}Couldn't locate / access Player Prefs at path {prefsPath}. " + + $"This message is harmless unless you already saved anything to the {nameof(PlayerPrefs)} or {nameof(ObscuredPrefs)}.\n" + + $"In such case, please report this problem to {ACTk.SupportContact} and include these data:\n" + + $"{ACTk.GenerateBugReport()}"); + return new string[0]; + } + + var names = registryLocation.GetValueNames(); + var result = new string[names.Length]; + + for (var i = 0; i < names.Length; i++) + { + var key = names[i]; + + if (key.IndexOf('_') > 0) + { + result[i] = key.Substring(0, key.LastIndexOf('_')); + } + else + { + result[i] = key; + } + } + + return result; + } + +#elif UNITY_EDITOR_OSX + + private string[] ReadKeysOSX() + { + var plistPath = GetPrefsPath(); + if (!File.Exists (plistPath)) + { + Debug.LogWarning($"{ACTk.LogPrefix}Couldn't locate / access Player Prefs at path {plistPath}. " + + $"This message is harmless unless you already saved anything to the {nameof(PlayerPrefs)} or {nameof(ObscuredPrefs)}.\n" + + $"In such case, please report this problem to {ACTk.SupportContact} and include these data:\n" + + $"{ACTk.GenerateBugReport()}"); + return new string[0]; + } + + var parsedPlist = (Dictionary)Plist.readPlist(plistPath); + + var keys = new string[parsedPlist.Keys.Count]; + parsedPlist.Keys.CopyTo (keys, 0); + + return keys; + } + +#else // LINUX! + + private string[] ReadKeysLinux() + { + var prefsPath = GetPrefsPath(); + if (!File.Exists(prefsPath)) + { + Debug.LogWarning($"{ACTk.LogPrefix}Couldn't locate / access Player Prefs at path {prefsPath}. " + + $"This message is harmless unless you already saved anything to the {nameof(PlayerPrefs)} or {nameof(ObscuredPrefs)}.\n" + + $"In such case, please report this problem to {ACTk.SupportContact} and include these data:\n" + + $"{ACTk.GenerateBugReport()}"); + return new string[0]; + } + + var prefsXML = new XmlDocument(); + prefsXML.Load(prefsPath); + var prefsList = prefsXML.SelectNodes("/unity_prefs/pref"); + + var keys = new string[prefsList.Count]; + + for (var i = 0; i < keys.Length; i++) + { + keys[i] = prefsList[i].Attributes["name"].Value; + } + + return keys; + } + +#endif + private enum SortingType : byte + { + KeyAscending = 0, + KeyDescending = 2, + Type = 5, + Obscurance = 10 + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs.meta new file mode 100644 index 0000000..206db1a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/ACTkPrefsEditor.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 996c620e94c266d47beedf3539748d9f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs new file mode 100644 index 0000000..e695850 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs @@ -0,0 +1,960 @@ +// +// PlistCS Property List (plist) serialization and parsing library. +// +// https://github.com/animetrics/PlistCS +// +// Copyright (c) 2011 Animetrics Inc. (marc@animetrics.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.IO; + using System.Text; + using System.Xml; + + internal static class Plist + { + private static List offsetTable = new List(); + private static List objectTable = new List(); + private static int refCount; + private static int objRefSize; + private static int offsetByteSize; + private static long offsetTableOffset; + + #region Public Functions + + public static object readPlist(string path) + { + using (FileStream f = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + return readPlist(f, plistType.Auto); + } + } + + public static object readPlistSource(string source) + { + return readPlist(Encoding.UTF8.GetBytes(source)); + } + + public static object readPlist(byte[] data) + { + return readPlist(new MemoryStream(data), plistType.Auto); + } + + public static plistType getPlistType(Stream stream) + { + byte[] magicHeader = new byte[8]; + stream.Read(magicHeader, 0, 8); + + if (BitConverter.ToInt64(magicHeader, 0) == 3472403351741427810) + { + return plistType.Binary; + } + else + { + return plistType.Xml; + } + } + + public static object readPlist(Stream stream, plistType type) + { + if (type == plistType.Auto) + { + type = getPlistType(stream); + stream.Seek(0, SeekOrigin.Begin); + } + + if (type == plistType.Binary) + { + using (BinaryReader reader = new BinaryReader(stream)) + { + byte[] data = reader.ReadBytes((int) reader.BaseStream.Length); + return readBinary(data); + } + } + else + { + XmlDocument xml = new XmlDocument(); + xml.XmlResolver = null; + xml.Load(stream); + return readXml(xml); + } + } + + public static void writeXml(object value, string path) + { + using (StreamWriter writer = new StreamWriter(path)) + { + writer.Write(writeXml(value)); + } + } + + public static void writeXml(object value, Stream stream) + { + using (StreamWriter writer = new StreamWriter(stream)) + { + writer.Write(writeXml(value)); + } + } + + public static string writeXml(object value) + { + using (MemoryStream ms = new MemoryStream()) + { + XmlWriterSettings xmlWriterSettings = new XmlWriterSettings(); + xmlWriterSettings.Encoding = new UTF8Encoding(false); + xmlWriterSettings.ConformanceLevel = ConformanceLevel.Document; + xmlWriterSettings.Indent = true; + + using (XmlWriter xmlWriter = XmlWriter.Create(ms, xmlWriterSettings)) + { + xmlWriter.WriteStartDocument(); + //xmlWriter.WriteComment("DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" " + "\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\""); + xmlWriter.WriteDocType("plist", "-//Apple Computer//DTD PLIST 1.0//EN", "http://www.apple.com/DTDs/PropertyList-1.0.dtd", null); + xmlWriter.WriteStartElement("plist"); + xmlWriter.WriteAttributeString("version", "1.0"); + compose(value, xmlWriter); + xmlWriter.WriteEndElement(); + xmlWriter.WriteEndDocument(); + xmlWriter.Flush(); + xmlWriter.Close(); + return System.Text.Encoding.UTF8.GetString(ms.ToArray()); + } + } + } + + public static void writeBinary(object value, string path) + { + using (BinaryWriter writer = new BinaryWriter(new FileStream(path, FileMode.Create))) + { + writer.Write(writeBinary(value)); + } + } + + public static void writeBinary(object value, Stream stream) + { + using (BinaryWriter writer = new BinaryWriter(stream)) + { + writer.Write(writeBinary(value)); + } + } + + public static byte[] writeBinary(object value) + { + offsetTable.Clear(); + objectTable.Clear(); + refCount = 0; + objRefSize = 0; + offsetByteSize = 0; + offsetTableOffset = 0; + + //Do not count the root node, subtract by 1 + int totalRefs = countObject(value) - 1; + + refCount = totalRefs; + + objRefSize = RegulateNullBytes(BitConverter.GetBytes(refCount)).Length; + + composeBinary(value); + + writeBinaryString("bplist00", false); + + offsetTableOffset = (long)objectTable.Count; + + offsetTable.Add(objectTable.Count - 8); + + offsetByteSize = RegulateNullBytes(BitConverter.GetBytes(offsetTable[offsetTable.Count-1])).Length; + + List offsetBytes = new List(); + + offsetTable.Reverse(); + + for (int i = 0; i < offsetTable.Count; i++) + { + offsetTable[i] = objectTable.Count - offsetTable[i]; + byte[] buffer = RegulateNullBytes(BitConverter.GetBytes(offsetTable[i]), offsetByteSize); + Array.Reverse(buffer); + offsetBytes.AddRange(buffer); + } + + objectTable.AddRange(offsetBytes); + + objectTable.AddRange(new byte[6]); + objectTable.Add(Convert.ToByte(offsetByteSize)); + objectTable.Add(Convert.ToByte(objRefSize)); + + var a = BitConverter.GetBytes((long) totalRefs + 1); + Array.Reverse(a); + objectTable.AddRange(a); + + objectTable.AddRange(BitConverter.GetBytes((long)0)); + a = BitConverter.GetBytes(offsetTableOffset); + Array.Reverse(a); + objectTable.AddRange(a); + + return objectTable.ToArray(); + } + + #endregion + + #region Private Functions + + private static object readXml(XmlDocument xml) + { + XmlNode rootNode = xml.DocumentElement.ChildNodes[0]; + return parse(rootNode); + } + + private static object readBinary(byte[] data) + { + offsetTable.Clear(); + List offsetTableBytes = new List(); + objectTable.Clear(); + refCount = 0; + objRefSize = 0; + offsetByteSize = 0; + offsetTableOffset = 0; + + List bList = new List(data); + + List trailer = bList.GetRange(bList.Count - 32, 32); + + parseTrailer(trailer); + + objectTable = bList.GetRange(0, (int)offsetTableOffset); + + offsetTableBytes = bList.GetRange((int)offsetTableOffset, bList.Count - (int)offsetTableOffset - 32); + + parseOffsetTable(offsetTableBytes); + + return parseBinary(0); + } + + private static Dictionary parseDictionary(XmlNode node) + { + XmlNodeList children = node.ChildNodes; + if (children.Count % 2 != 0) + { + throw new DataMisalignedException("Dictionary elements must have an even number of child nodes"); + } + + Dictionary dict = new Dictionary(); + + for (int i = 0; i < children.Count; i += 2) + { + XmlNode keynode = children[i]; + XmlNode valnode = children[i + 1]; + + if (keynode.Name != "key") + { + throw new ApplicationException("expected a key node"); + } + + object result = parse(valnode); + + if (result != null) + { + dict.Add(keynode.InnerText, result); + } + } + + return dict; + } + + private static List parseArray(XmlNode node) + { + List array = new List(); + + foreach (XmlNode child in node.ChildNodes) + { + object result = parse(child); + if (result != null) + { + array.Add(result); + } + } + + return array; + } + + private static void composeArray(List value, XmlWriter writer) + { + writer.WriteStartElement("array"); + foreach (object obj in value) + { + compose(obj, writer); + } + writer.WriteEndElement(); + } + + private static object parse(XmlNode node) + { + switch (node.Name) + { + case "dict": + return parseDictionary(node); + case "array": + return parseArray(node); + case "string": + return node.InnerText; + case "integer": + // int result; + //int.TryParse(node.InnerText, System.Globalization.NumberFormatInfo.InvariantInfo, out result); + return Convert.ToInt32(node.InnerText, System.Globalization.NumberFormatInfo.InvariantInfo); + case "real": + return Convert.ToDouble(node.InnerText,System.Globalization.NumberFormatInfo.InvariantInfo); + case "false": + return false; + case "true": + return true; + case "null": + return null; + case "date": + return XmlConvert.ToDateTime(node.InnerText, XmlDateTimeSerializationMode.Utc); + case "data": + return Convert.FromBase64String(node.InnerText); + } + + throw new ApplicationException(String.Format("Plist Node `{0}' is not supported", node.Name)); + } + + private static void compose(object value, XmlWriter writer) + { + + if (value == null || value is string) + { + writer.WriteElementString("string", value as string); + } + else if (value is int || value is long) + { + writer.WriteElementString("integer", ((int)value).ToString(System.Globalization.NumberFormatInfo.InvariantInfo)); + } + else if (value is System.Collections.Generic.Dictionary || + value.GetType().ToString().StartsWith("System.Collections.Generic.Dictionary`2[System.String")) + { + //Convert to Dictionary + Dictionary dic = value as Dictionary; + if (dic == null) + { + dic = new Dictionary(); + IDictionary idic = (IDictionary)value; + foreach (var key in idic.Keys) + { + dic.Add(key.ToString(), idic[key]); + } + } + writeDictionaryValues(dic, writer); + } + else if (value is List) + { + composeArray((List)value, writer); + } + else if (value is byte[]) + { + writer.WriteElementString("data", Convert.ToBase64String((Byte[])value)); + } + else if (value is float || value is double) + { + writer.WriteElementString("real", ((double)value).ToString(System.Globalization.NumberFormatInfo.InvariantInfo)); + } + else if (value is DateTime) + { + DateTime time = (DateTime)value; + string theString = XmlConvert.ToString(time, XmlDateTimeSerializationMode.Utc); + writer.WriteElementString("date", theString);//, "yyyy-MM-ddTHH:mm:ssZ")); + } + else if (value is bool) + { + writer.WriteElementString(value.ToString().ToLower(), ""); + } + else + { + throw new Exception(String.Format("Value type '{0}' is unhandled", value.GetType().ToString())); + } + } + + private static void writeDictionaryValues(Dictionary dictionary, XmlWriter writer) + { + writer.WriteStartElement("dict"); + foreach (string key in dictionary.Keys) + { + object value = dictionary[key]; + writer.WriteElementString("key", key); + compose(value, writer); + } + writer.WriteEndElement(); + } + + private static int countObject(object value) + { + int count = 0; + switch (value.GetType().ToString()) + { + case "System.Collections.Generic.Dictionary`2[System.String,System.Object]": + Dictionary dict = (Dictionary)value; + foreach (string key in dict.Keys) + { + count += countObject(dict[key]); + } + count += dict.Keys.Count; + count++; + break; + case "System.Collections.Generic.List`1[System.Object]": + List list = (List)value; + foreach (object obj in list) + { + count += countObject(obj); + } + count++; + break; + default: + count++; + break; + } + return count; + } + + private static byte[] writeBinaryDictionary(Dictionary dictionary) + { + List buffer = new List(); + List header = new List(); + List refs = new List(); + for (int i = dictionary.Count - 1; i >= 0; i--) + { + var o = new object[dictionary.Count]; + dictionary.Values.CopyTo(o, 0); + composeBinary(o[i]); + offsetTable.Add(objectTable.Count); + refs.Add(refCount); + refCount--; + } + for (int i = dictionary.Count - 1; i >= 0; i--) + { + var o = new string[dictionary.Count]; + dictionary.Keys.CopyTo(o, 0); + composeBinary(o[i]);//); + offsetTable.Add(objectTable.Count); + refs.Add(refCount); + refCount--; + } + + if (dictionary.Count < 15) + { + header.Add(Convert.ToByte(0xD0 | Convert.ToByte(dictionary.Count))); + } + else + { + header.Add(0xD0 | 0xf); + header.AddRange(writeBinaryInteger(dictionary.Count, false)); + } + + + foreach (int val in refs) + { + byte[] refBuffer = RegulateNullBytes(BitConverter.GetBytes(val), objRefSize); + Array.Reverse(refBuffer); + buffer.InsertRange(0, refBuffer); + } + + buffer.InsertRange(0, header); + + + objectTable.InsertRange(0, buffer); + + return buffer.ToArray(); + } + + private static byte[] composeBinaryArray(List objects) + { + List buffer = new List(); + List header = new List(); + List refs = new List(); + + for (int i = objects.Count - 1; i >= 0; i--) + { + composeBinary(objects[i]); + offsetTable.Add(objectTable.Count); + refs.Add(refCount); + refCount--; + } + + if (objects.Count < 15) + { + header.Add(Convert.ToByte(0xA0 | Convert.ToByte(objects.Count))); + } + else + { + header.Add(0xA0 | 0xf); + header.AddRange(writeBinaryInteger(objects.Count, false)); + } + + foreach (int val in refs) + { + byte[] refBuffer = RegulateNullBytes(BitConverter.GetBytes(val), objRefSize); + Array.Reverse(refBuffer); + buffer.InsertRange(0, refBuffer); + } + + buffer.InsertRange(0, header); + + objectTable.InsertRange(0, buffer); + + return buffer.ToArray(); + } + + private static byte[] composeBinary(object obj) + { + byte[] value; + switch (obj.GetType().ToString()) + { + case "System.Collections.Generic.Dictionary`2[System.String,System.Object]": + value = writeBinaryDictionary((Dictionary)obj); + return value; + + case "System.Collections.Generic.List`1[System.Object]": + value = composeBinaryArray((List)obj); + return value; + + case "System.Byte[]": + value = writeBinaryByteArray((byte[])obj); + return value; + + case "System.Double": + value = writeBinaryDouble((double)obj); + return value; + + case "System.Int32": + value = writeBinaryInteger((int)obj, true); + return value; + + case "System.String": + value = writeBinaryString((string)obj, true); + return value; + + case "System.DateTime": + value = writeBinaryDate((DateTime)obj); + return value; + + case "System.Boolean": + value = writeBinaryBool((bool)obj); + return value; + + default: + return new byte[0]; + } + } + + public static byte[] writeBinaryDate(DateTime obj) + { + List buffer =new List(RegulateNullBytes(BitConverter.GetBytes(PlistDateConverter.ConvertToAppleTimeStamp(obj)), 8)); + buffer.Reverse(); + buffer.Insert(0, 0x33); + objectTable.InsertRange(0, buffer); + return buffer.ToArray(); + } + + public static byte[] writeBinaryBool(bool obj) + { + List buffer = new List(new byte[1] { (bool)obj ? (byte)9 : (byte)8 }); + objectTable.InsertRange(0, buffer); + return buffer.ToArray(); + } + + private static byte[] writeBinaryInteger(int value, bool write) + { + List buffer = new List(BitConverter.GetBytes((long) value)); + buffer =new List(RegulateNullBytes(buffer.ToArray())); + while (buffer.Count != Math.Pow(2, Math.Log(buffer.Count) / Math.Log(2))) + buffer.Add(0); + int header = 0x10 | (int)(Math.Log(buffer.Count) / Math.Log(2)); + + buffer.Reverse(); + + buffer.Insert(0, Convert.ToByte(header)); + + if (write) + objectTable.InsertRange(0, buffer); + + return buffer.ToArray(); + } + + private static byte[] writeBinaryDouble(double value) + { + List buffer =new List(RegulateNullBytes(BitConverter.GetBytes(value), 4)); + while (buffer.Count != Math.Pow(2, Math.Log(buffer.Count) / Math.Log(2))) + buffer.Add(0); + int header = 0x20 | (int)(Math.Log(buffer.Count) / Math.Log(2)); + + buffer.Reverse(); + + buffer.Insert(0, Convert.ToByte(header)); + + objectTable.InsertRange(0, buffer); + + return buffer.ToArray(); + } + + private static byte[] writeBinaryByteArray(byte[] value) + { + List buffer = new List(value); + List header = new List(); + if (value.Length < 15) + { + header.Add(Convert.ToByte(0x40 | Convert.ToByte(value.Length))); + } + else + { + header.Add(0x40 | 0xf); + header.AddRange(writeBinaryInteger(buffer.Count, false)); + } + + buffer.InsertRange(0, header); + + objectTable.InsertRange(0, buffer); + + return buffer.ToArray(); + } + + private static byte[] writeBinaryString(string value, bool head) + { + List buffer = new List(); + List header = new List(); + foreach (char chr in value.ToCharArray()) + buffer.Add(Convert.ToByte(chr)); + + if (head) + { + if (value.Length < 15) + { + header.Add(Convert.ToByte(0x50 | Convert.ToByte(value.Length))); + } + else + { + header.Add(0x50 | 0xf); + header.AddRange(writeBinaryInteger(buffer.Count, false)); + } + } + + buffer.InsertRange(0, header); + + objectTable.InsertRange(0, buffer); + + return buffer.ToArray(); + } + + private static byte[] RegulateNullBytes(byte[] value) + { + return RegulateNullBytes(value, 1); + } + + private static byte[] RegulateNullBytes(byte[] value, int minBytes) + { + Array.Reverse(value); + List bytes = new List(value); + for (int i = 0; i < bytes.Count; i++) + { + if (bytes[i] == 0 && bytes.Count > minBytes) + { + bytes.Remove(bytes[i]); + i--; + } + else + break; + } + + if (bytes.Count < minBytes) + { + int dist = minBytes - bytes.Count; + for (int i = 0; i < dist; i++) + bytes.Insert(0, 0); + } + + value = bytes.ToArray(); + Array.Reverse(value); + return value; + } + + private static void parseTrailer(List trailer) + { + offsetByteSize = BitConverter.ToInt32(RegulateNullBytes(trailer.GetRange(6, 1).ToArray(), 4), 0); + objRefSize = BitConverter.ToInt32(RegulateNullBytes(trailer.GetRange(7, 1).ToArray(), 4), 0); + byte[] refCountBytes = trailer.GetRange(12, 4).ToArray(); + Array.Reverse(refCountBytes); + refCount = BitConverter.ToInt32(refCountBytes, 0); + byte[] offsetTableOffsetBytes = trailer.GetRange(24, 8).ToArray(); + Array.Reverse(offsetTableOffsetBytes); + offsetTableOffset = BitConverter.ToInt64(offsetTableOffsetBytes, 0); + } + + private static void parseOffsetTable(List offsetTableBytes) + { + for (int i = 0; i < offsetTableBytes.Count; i += offsetByteSize) + { + byte[] buffer = offsetTableBytes.GetRange(i, offsetByteSize).ToArray(); + Array.Reverse(buffer); + offsetTable.Add(BitConverter.ToInt32(RegulateNullBytes(buffer, 4), 0)); + } + } + + private static object parseBinaryDictionary(int objRef) + { + Dictionary buffer = new Dictionary(); + List refs = new List(); + int refCount = 0; + + int refStartPosition; + refCount = getCount(offsetTable[objRef], out refStartPosition); + + + if (refCount < 15) + refStartPosition = offsetTable[objRef] + 1; + else + refStartPosition = offsetTable[objRef] + 2 + RegulateNullBytes(BitConverter.GetBytes(refCount), 1).Length; + + for (int i = refStartPosition; i < refStartPosition + refCount * 2 * objRefSize; i += objRefSize) + { + byte[] refBuffer = objectTable.GetRange(i, objRefSize).ToArray(); + Array.Reverse(refBuffer); + refs.Add(BitConverter.ToInt32(RegulateNullBytes(refBuffer, 4), 0)); + } + + for (int i = 0; i < refCount; i++) + { + buffer.Add((string)parseBinary(refs[i]), parseBinary(refs[i + refCount])); + } + + return buffer; + } + + private static object parseBinaryArray(int objRef) + { + List buffer = new List(); + List refs = new List(); + int refCount = 0; + + int refStartPosition; + refCount = getCount(offsetTable[objRef], out refStartPosition); + + + if (refCount < 15) + refStartPosition = offsetTable[objRef] + 1; + else + //The following integer has a header aswell so we increase the refStartPosition by two to account for that. + refStartPosition = offsetTable[objRef] + 2 + RegulateNullBytes(BitConverter.GetBytes(refCount), 1).Length; + + for (int i = refStartPosition; i < refStartPosition + refCount * objRefSize; i += objRefSize) + { + byte[] refBuffer = objectTable.GetRange(i, objRefSize).ToArray(); + Array.Reverse(refBuffer); + refs.Add(BitConverter.ToInt32(RegulateNullBytes(refBuffer, 4), 0)); + } + + for (int i = 0; i < refCount; i++) + { + buffer.Add(parseBinary(refs[i])); + } + + return buffer; + } + + private static int getCount(int bytePosition, out int newBytePosition) + { + byte headerByte = objectTable[bytePosition]; + byte headerByteTrail = Convert.ToByte(headerByte & 0xf); + int count; + if (headerByteTrail < 15) + { + count = headerByteTrail; + newBytePosition = bytePosition + 1; + } + else + count = (int)parseBinaryInt(bytePosition + 1, out newBytePosition); + return count; + } + + private static object parseBinary(int objRef) + { + byte header = objectTable[offsetTable[objRef]]; + switch (header & 0xF0) + { + case 0: + { + //If the byte is + //0 return null + //9 return true + //8 return false + return (objectTable[offsetTable[objRef]] == 0) ? (object)null : ((objectTable[offsetTable[objRef]] == 9) ? true : false); + } + case 0x10: + { + return parseBinaryInt(offsetTable[objRef]); + } + case 0x20: + { + return parseBinaryReal(offsetTable[objRef]); + } + case 0x30: + { + return parseBinaryDate(offsetTable[objRef]); + } + case 0x40: + { + return parseBinaryByteArray(offsetTable[objRef]); + } + case 0x50://String ASCII + { + return parseBinaryAsciiString(offsetTable[objRef]); + } + case 0x60://String Unicode + { + return parseBinaryUnicodeString(offsetTable[objRef]); + } + case 0xD0: + { + return parseBinaryDictionary(objRef); + } + case 0xA0: + { + return parseBinaryArray(objRef); + } + } + throw new Exception("This type is not supported"); + } + + public static object parseBinaryDate(int headerPosition) + { + byte[] buffer = objectTable.GetRange(headerPosition + 1, 8).ToArray(); + Array.Reverse(buffer); + double appleTime = BitConverter.ToDouble(buffer, 0); + DateTime result = PlistDateConverter.ConvertFromAppleTimeStamp(appleTime); + return result; + } + + private static object parseBinaryInt(int headerPosition) + { + int output; + return parseBinaryInt(headerPosition, out output); + } + + private static object parseBinaryInt(int headerPosition, out int newHeaderPosition) + { + byte header = objectTable[headerPosition]; + int byteCount = (int)Math.Pow(2, header & 0xf); + byte[] buffer = objectTable.GetRange(headerPosition + 1, byteCount).ToArray(); + Array.Reverse(buffer); + //Add one to account for the header byte + newHeaderPosition = headerPosition + byteCount + 1; + return BitConverter.ToInt32(RegulateNullBytes(buffer, 4), 0); + } + + private static object parseBinaryReal(int headerPosition) + { + byte header = objectTable[headerPosition]; + int byteCount = (int)Math.Pow(2, header & 0xf); + byte[] buffer = objectTable.GetRange(headerPosition + 1, byteCount).ToArray(); + Array.Reverse(buffer); + + return BitConverter.ToDouble(RegulateNullBytes(buffer, 8), 0); + } + + private static object parseBinaryAsciiString(int headerPosition) + { + int charStartPosition; + int charCount = getCount(headerPosition, out charStartPosition); + + var buffer = objectTable.GetRange(charStartPosition, charCount); + return buffer.Count > 0 ? Encoding.ASCII.GetString(buffer.ToArray()) : string.Empty; + } + + private static object parseBinaryUnicodeString(int headerPosition) + { + int charStartPosition; + int charCount = getCount(headerPosition, out charStartPosition); + charCount = charCount * 2; + + byte[] buffer = new byte[charCount]; + byte one, two; + + for (int i = 0; i < charCount; i+=2) + { + one = objectTable.GetRange(charStartPosition+i,1)[0]; + two = objectTable.GetRange(charStartPosition + i+1, 1)[0]; + + if (BitConverter.IsLittleEndian) + { + buffer[i] = two; + buffer[i + 1] = one; + } + else + { + buffer[i] = one; + buffer[i + 1] = two; + } + } + + return Encoding.Unicode.GetString(buffer); + } + + private static object parseBinaryByteArray(int headerPosition) + { + int byteStartPosition; + int byteCount = getCount(headerPosition, out byteStartPosition); + return objectTable.GetRange(byteStartPosition, byteCount).ToArray(); + } + + #endregion + } + + internal enum plistType + { + Auto, Binary, Xml + } + + internal static class PlistDateConverter + { + public static long timeDifference = 978307200; + + public static long GetAppleTime(long unixTime) + { + return unixTime - timeDifference; + } + + public static long GetUnixTime(long appleTime) + { + return appleTime + timeDifference; + } + + public static DateTime ConvertFromAppleTimeStamp(double timestamp) + { + DateTime origin = new DateTime(2001, 1, 1, 0, 0, 0, 0); + return origin.AddSeconds(timestamp); + } + + public static double ConvertToAppleTimeStamp(DateTime date) + { + DateTime begin = new DateTime(2001, 1, 1, 0, 0, 0, 0); + TimeSpan diff = date - begin; + return Math.Floor(diff.TotalSeconds); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs.meta new file mode 100644 index 0000000..d0b5b53 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/Plist.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2672b3f40586e4d319dfce4c30e00913 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs new file mode 100644 index 0000000..d6b28df --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs @@ -0,0 +1,491 @@ +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Globalization; + using System.Text.RegularExpressions; + using Common; + using ObscuredTypes; + using Storage; + using UnityEditor; + using UnityEngine; + using Utils; + + [Serializable] + internal class PrefsRecord + { + protected const string DefaultString = "[^_; = ElinaKristinaMyGirlsLoveYou'16 = ;_^]"; + protected const float DefaultFloat = float.MinValue + 2016.0122f; + protected const int DefaultInt = int.MinValue + 20130524; + protected const string CantDecrypt = "Can't decrypt with specified key"; + + internal PrefsType prefType = PrefsType.Unknown; + internal StorageDataType obscuredType = StorageDataType.Unknown; + + internal bool dirtyKey; + internal bool dirtyValue; + + [SerializeField] + private string savedKey; + + [SerializeField] + private string key; + + internal string Key + { + get => key; + set + { + if (value == key) return; + key = value; + + dirtyKey = true; + } + } + + [SerializeField] + private string stringValue; + + internal string StringValue + { + get => stringValue; + set + { + if (value == stringValue) return; + + stringValue = value; + dirtyValue = true; + } + } + + [SerializeField] + private int intValue; + + internal int IntValue + { + get => intValue; + set + { + if (value == intValue) return; + + intValue = value; + dirtyValue = true; + } + } + + [SerializeField] + private float floatValue; + + internal float FloatValue + { + get => floatValue; + set + { + if (Math.Abs(value - floatValue) < 0.0000001f) return; + + floatValue = value; + dirtyValue = true; + } + } + + internal string DisplayValue + { + get + { + switch (prefType) + { + case PrefsType.Unknown: + return ACTkPrefsEditor.UnknownValueDescription; + case PrefsType.String: + return IsEditableObscuredValue() || !Obscured ? stringValue : ACTkPrefsEditor.UnsupportedValueDescription; + case PrefsType.Int: + return intValue.ToString(); + case PrefsType.Float: + return floatValue.ToString(CultureInfo.InvariantCulture); + default: + throw new ArgumentOutOfRangeException(); + } + } + } + + internal string DisplayType => Obscured ? obscuredType.ToString() : prefType.ToString(); + + internal static int SortByNameAscending(PrefsRecord n1, PrefsRecord n2) + { + return string.CompareOrdinal(n1.key, n2.key); + } + + internal static int SortByNameDescending(PrefsRecord n1, PrefsRecord n2) + { + var result = string.CompareOrdinal(n2.key, n1.key); + return result; + } + + internal static int SortByType(PrefsRecord n1, PrefsRecord n2) + { + var result = string.CompareOrdinal(n1.DisplayType, n2.DisplayType); + return result == 0 ? SortByNameAscending(n1, n2) : result; + } + + internal static int SortByObscurance(PrefsRecord n1, PrefsRecord n2) + { + var result = n1.Obscured.CompareTo(n2.Obscured); + return result == 0 ? SortByNameAscending(n1, n2) : result; + } + + internal bool Obscured { get; set; } + + internal PrefsRecord(string newKey, string value, bool encrypted) + { + key = savedKey = newKey; + stringValue = value; + + prefType = PrefsType.String; + + if (encrypted) + { + obscuredType = StorageDataType.String; + Obscured = true; + } + } + + internal PrefsRecord(string newKey, int value, bool encrypted) + { + key = savedKey = newKey; + intValue = value; + + if (encrypted) + { + prefType = PrefsType.String; + obscuredType = StorageDataType.Int32; + Obscured = true; + } + else + { + prefType = PrefsType.Int; + } + } + + internal PrefsRecord(string newKey, float value, bool encrypted) + { + key = savedKey = newKey; + floatValue = value; + + if (encrypted) + { + prefType = PrefsType.String; + obscuredType = StorageDataType.Single; + Obscured = true; + } + else + { + prefType = PrefsType.Float; + } + } + + internal PrefsRecord(string originalKey) + { + key = savedKey = originalKey; + + ReadValue(); + + // only string prefs may be obscured + if (prefType == PrefsType.String) + { + Obscured = IsValueObscured(stringValue); + + if (Obscured) + { + key = DecryptKey(key); + + if (obscuredType == StorageDataType.String) + { + stringValue = ObscuredPrefs.DecryptValue(key, null, DefaultString, stringValue); + if (stringValue == DefaultString) stringValue = CantDecrypt; + } + else if (obscuredType == StorageDataType.Int32) + { + intValue = ObscuredPrefs.DecryptValue(key, null, DefaultInt, stringValue); + if (intValue == DefaultInt) + { + obscuredType = StorageDataType.String; + stringValue = CantDecrypt; + } + } + else if (obscuredType == StorageDataType.Single) + { + floatValue = ObscuredPrefs.DecryptValue(key, null, DefaultFloat, stringValue); + if (Math.Abs(floatValue - DefaultFloat) < 0.00001f) + { + obscuredType = StorageDataType.String; + stringValue = CantDecrypt; + } + } + } + } + } + + internal bool Save(bool newRecord = false) + { + var savedString = stringValue; + string newSavedKey; + + if (Obscured) + { + savedString = GetEncryptedValue(); + newSavedKey = GetEncryptedKey(); + } + else + { + newSavedKey = key; + } + + if (newSavedKey != savedKey && PlayerPrefs.HasKey(newSavedKey)) + { + if (!EditorUtility.DisplayDialog("Pref overwrite", + "Pref with name " + key + " already exists!\n" + "Are you sure you wish to overwrite it?", "Yes", + "No")) + { + return false; + } + } + + if (dirtyKey) + { + PlayerPrefs.DeleteKey(savedKey); + } + + switch (prefType) + { + case PrefsType.Unknown: + Debug.LogError(ACTk.LogPrefix + "Can't save Pref of unknown type!"); + break; + case PrefsType.String: + PlayerPrefs.SetString(newSavedKey, savedString); + break; + case PrefsType.Int: + PlayerPrefs.SetInt(newSavedKey, intValue); + break; + case PrefsType.Float: + PlayerPrefs.SetFloat(newSavedKey, floatValue); + break; + default: + throw new ArgumentOutOfRangeException(); + } + + savedKey = newSavedKey; + + dirtyKey = false; + dirtyValue = false; + + PlayerPrefs.Save(); + + return true; + } + + internal void Delete() + { + PlayerPrefs.DeleteKey(savedKey); + PlayerPrefs.Save(); + } + + internal void Encrypt() + { + if (Obscured) return; + + var success = true; + + switch (prefType) + { + case PrefsType.Unknown: + success = false; + Debug.LogError(ACTk.LogPrefix + "Can't encrypt pref of unknown type!"); + break; + case PrefsType.String: + obscuredType = StorageDataType.String; + break; + case PrefsType.Int: + obscuredType = StorageDataType.Int32; + break; + case PrefsType.Float: + obscuredType = StorageDataType.Single; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (success) + { + prefType = PrefsType.String; + Obscured = true; + dirtyValue = dirtyKey = true; + } + } + + internal void Decrypt() + { + if (!Obscured) return; + if (!IsEditableObscuredValue()) return; + + var success = true; + + switch (obscuredType) + { + case StorageDataType.Int32: + prefType = PrefsType.Int; + break; + case StorageDataType.String: + prefType = PrefsType.String; + break; + case StorageDataType.Single: + prefType = PrefsType.Float; + break; + case StorageDataType.UInt32: + case StorageDataType.Double: + case StorageDataType.Int64: + case StorageDataType.Boolean: + case StorageDataType.ByteArray: + case StorageDataType.Vector2: + case StorageDataType.Vector3: + case StorageDataType.Quaternion: + case StorageDataType.Color: + case StorageDataType.Color32: + case StorageDataType.Rect: + ACTkPrefsEditor.instance.ShowNotification(new GUIContent("Type " + obscuredType + " isn't supported")); + success = false; + break; + case StorageDataType.Unknown: + ACTkPrefsEditor.instance.ShowNotification(new GUIContent("Can't decrypt " + key)); + success = false; + break; + default: + throw new ArgumentOutOfRangeException(); + } + + if (success) + { + Obscured = false; + obscuredType = StorageDataType.Unknown; + dirtyValue = dirtyKey = true; + } + } + + internal string GetEncryptedKey() + { + return ObscuredPrefs.EncryptKey(key); + } + + internal string GetEncryptedValue() + { + string savedString; + + switch (obscuredType) + { + case StorageDataType.Int32: + savedString = ObscuredPrefs.EncryptValue(key, intValue); + break; + case StorageDataType.String: + savedString = ObscuredPrefs.EncryptValue(key, stringValue); + break; + case StorageDataType.Single: + savedString = ObscuredPrefs.EncryptValue(key, floatValue); + break; + default: + savedString = stringValue; + break;; + } + + return savedString; + } + + internal bool IsEditableObscuredValue() + { + return obscuredType == StorageDataType.Int32 || + obscuredType == StorageDataType.String || + obscuredType == StorageDataType.Single; + } + + internal string ToString(bool raw = false) + { + string result; + + if (raw) + { + result = "Key: " + GetEncryptedKey() + Environment.NewLine + "Value: " + GetEncryptedValue(); + } + else + { + result = "Key: " + key + Environment.NewLine + "Value: " + DisplayValue; + } + + return result; + } + + private void ReadValue() + { + var stringTry = PlayerPrefs.GetString(key, DefaultString); + if (stringTry != DefaultString) + { + prefType = PrefsType.String; + stringValue = stringTry; + return; + } + + var floatTry = PlayerPrefs.GetFloat(key, DefaultFloat); + if (Math.Abs(floatTry - DefaultFloat) > 0.0000001f) + { + prefType = PrefsType.Float; + floatValue = floatTry; + return; + } + + var intTry = PlayerPrefs.GetInt(key, DefaultInt); + if (intTry != DefaultInt) + { + prefType = PrefsType.Int; + intValue = intTry; + } + } + + private string DecryptKey(string encryptedKey) + { + string decryptedKey; + + try + { + var decryptedKeyChars = Base64Utils.FromBase64ToChars(encryptedKey); + decryptedKey = ObscuredString.Decrypt(decryptedKeyChars, ObscuredPrefs.GetCryptoKey()); + } + catch + { + decryptedKey = string.Empty; + } + + return decryptedKey; + } + + private bool IsValueObscured(string value) + { + var validBase64String = (value.Length % 4 == 0) && + Regex.IsMatch(value, @"^[a-zA-Z0-9\+/]*={0,3}$", RegexOptions.None); + if (!validBase64String) return false; + + var dataType = ObscuredPrefs.GetRawValueType(value); + if (!Enum.IsDefined(typeof(StorageDataType), dataType) || dataType == StorageDataType.Unknown) + { + return false; + } + + obscuredType = dataType; + + return true; + } + + internal enum PrefsType : byte + { + Unknown, + String, + Int, + Float + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs.meta new file mode 100644 index 0000000..44cd80e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/PrefsEditor/PrefsRecord.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bbfdc316834441f8a9b90c8d264eee2d +timeCreated: 1557960764 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors.meta new file mode 100644 index 0000000..fd06c40 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b75fb59d188745fba898daee356c6042 +timeCreated: 1621962890 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs new file mode 100644 index 0000000..c0a276e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs @@ -0,0 +1,151 @@ +// #region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +// #endregion + +namespace CodeStage.AntiCheat.EditorCode.Processors +{ + using System.IO; + using UnityEditor; + using UnityEditor.Build; + using UnityEditor.Build.Reporting; + using UnityEngine; + + public class BuildPreProcessor : IPreprocessBuildWithReport + { + private const string ProGuardExclusion = "-keep class net.codestage.actk.androidnative.ACTkAndroidRoutines { *; }\n" + + "-keep class net.codestage.actk.androidnative.CodeHashGenerator {public void GetCodeHash(...);}\n" + + "-keep class net.codestage.actk.androidnative.CodeHashCallback { *; }"; + + #region Implementation of IOrderedCallback + + public int callbackOrder => int.MinValue; + + public void OnPreprocessBuild(BuildReport report) + { + if (report.summary.platform == BuildTarget.Android) + CheckProGuard(); + } + + internal static void CheckProGuard(bool calledFromMenu = false) + { + if (!calledFromMenu && ACTkUserSettings.Instance.SkipProGuardNotice) + return; + + if (!calledFromMenu) + { + var devBuild = EditorUserBuildSettings.development; + var minifyEnabled = +#if UNITY_2020_1_OR_NEWER + (PlayerSettings.Android.minifyRelease && !devBuild) || + (PlayerSettings.Android.minifyDebug && devBuild); +#else + (EditorUserBuildSettings.androidReleaseMinification != AndroidMinification.None && !devBuild) || + (EditorUserBuildSettings.androidDebugMinification != AndroidMinification.None && devBuild); +#endif + if (!minifyEnabled) + return; + } + + ApplyProGuardConfiguration(calledFromMenu); + } + + private static void ApplyProGuardConfiguration(bool calledFromMenu) + { + var proguardFilePath = "Assets/Plugins/Android/proguard-user.txt"; + var disabledProguardFilePath = "Assets/Plugins/Android/proguard-user.txt.DISABLED"; + var needsConfiguration = false; + var activeConfigExists = false; + + if (!File.Exists(proguardFilePath)) + { + needsConfiguration = true; + } + else if (!FileHasACTkAdded(proguardFilePath)) + { + activeConfigExists = true; + needsConfiguration = true; + } + + if (!needsConfiguration) + { + if (calledFromMenu) + EditorUtility.DisplayDialog("Anti-Cheat Toolkit", + "ProGuard user file configuration is already applied, no action needed.", "OK"); + return; + } + + if (!calledFromMenu) + { + var choice = EditorUtility.DisplayDialogComplex("Anti-Cheat Toolkit", + "You're about to make a build with minification, but there is no active ProGuard User file configured to exclude ACTk which can cause runtime exceptions.\n\n" + + "Would you like to apply Anti-Cheat Toolkit rules to the ProGuard User file?", "Yes", "No", + "No and don't ask again"); + + if (choice != 0) + { + if (choice == 2) + ACTkUserSettings.Instance.SkipProGuardNotice = true; + return; + } + } + + var fileNeedsUpdate = true; + if (!activeConfigExists && File.Exists(disabledProguardFilePath)) + { + FileUtil.MoveFileOrDirectory(disabledProguardFilePath, proguardFilePath); + if (FileHasACTkAdded(proguardFilePath)) + fileNeedsUpdate = false; + } + + if (fileNeedsUpdate) + AddACTkToFile(proguardFilePath); + + AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); + + if (calledFromMenu) + EditorUtility.DisplayDialog("Anti-Cheat Toolkit", + $"ProGuard user file configuration at {proguardFilePath} updated.", "OK"); + } + + private static void AddACTkToFile(string path) + { + var folderPath = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(folderPath) && !Directory.Exists(folderPath)) + Directory.CreateDirectory(folderPath); + + var file = string.Empty; + + if (File.Exists(path)) + file = File.ReadAllText(path); + + if (!string.IsNullOrEmpty(file)) + file += "\n"; + + file += ProGuardExclusion; + + File.WriteAllText(path, file); + } + + private static bool FileHasACTkAdded(string path) + { + var file = File.ReadAllText(path); + if (file.Contains("-keep class net.codestage.actk")) + { + // migrating old version of the config + if (file.Contains("-keep class net.codestage.actk.** { *; }")) + { + file = file.Replace("-keep class net.codestage.actk.** { *; }",ProGuardExclusion); + File.WriteAllText(path, file); + } + + return true; + } + + return false; + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs.meta new file mode 100644 index 0000000..1cebb29 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/BuildPreProcessor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 206d36528cc940b3a156974ba2580c85 +timeCreated: 1657673033 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs new file mode 100644 index 0000000..d93e870 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs @@ -0,0 +1,80 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if ACTK_WALLHACK_LINK_XML + +namespace CodeStage.AntiCheat.EditorCode.Processors +{ + using System; + using System.IO; + using Common; + using Detectors; + using UnityEditor.Build; + using UnityEditor.Build.Reporting; + using UnityEditor.UnityLinker; + using UnityEngine; + + internal class WallHackDetectorLinkerProcessor : IUnityLinkerProcessor + { + private static string linkData; + + public int callbackOrder { get; } + + private readonly string path; + + public WallHackDetectorLinkerProcessor() + { + path = ACTkEditorConstants.LinkXmlPath; + } + + public string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data) + { + try + { + if (linkData == null) + linkData = ConstructLinkData(); + + File.WriteAllText(path, linkData); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Couldn't write link.xml!", e); + } + + Debug.Log($"{ACTk.LogPrefix}Additional link.xml generated for {WallHackDetector.ComponentName}:\n{path}"); + return path; + } + +#if !UNITY_2021_2_OR_NEWER + public void OnBeforeRun(BuildReport report, UnityLinkerBuildPipelineData data) + { + // ignoring since it was deprecated in Unity 2021.2 + } + + public void OnAfterRun(BuildReport report, UnityLinkerBuildPipelineData data) + { + // ignoring since it was deprecated in Unity 2021.2 + } +#endif + + private string ConstructLinkData() + { + return "\n" + + $"\t\n" + + $"\t\t\n" + + $"\t\t\n" + + $"\t\t\n" + + $"\t\t\n" + + $"\t\t\n" + + $"\t\t\n" + + $"\t\t\n" + + "\t\n" + + ""; + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs.meta new file mode 100644 index 0000000..d26d864 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Processors/WallHackDetectorLinkerProcessor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d740469e3e0430495570572d8084080 +timeCreated: 1621962902 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings.meta new file mode 100644 index 0000000..768892a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2a3f8c04015e4bf4faa5e7b926ff757a +folderAsset: yes +timeCreated: 1557585973 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs new file mode 100644 index 0000000..9af2a6f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs @@ -0,0 +1,131 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using UnityEditor; + + internal static class ACTkEditorPrefsSettings + { + private class FoldoutStorage + { + private bool il2cpp; + public bool Il2cpp + { + get => il2cpp; + set + { + il2cpp = value; + EditorPrefs.SetBool(IL2CPPFoldoutPref, value); + } + } + + private bool injection; + public bool Injection + { + get => injection; + set + { + injection = value; + EditorPrefs.SetBool(InjectionFoldoutPref, value); + } + } + + private bool hash; + public bool Hash + { + get => hash; + set + { + hash = value; + EditorPrefs.SetBool(HashFoldoutPref, value); + } + } + + private bool wallHack; + public bool WallHack + { + get => wallHack; + set + { + wallHack = value; + EditorPrefs.SetBool(WallHackFoldoutPref, value); + } + } + + private bool conditional; + public bool Conditional + { + get => conditional; + set + { + conditional = value; + EditorPrefs.SetBool(ConditionalFoldoutPref, value); + } + } + + public FoldoutStorage() + { + il2cpp = EditorPrefs.GetBool(IL2CPPFoldoutPref); + injection = EditorPrefs.GetBool(InjectionFoldoutPref); + hash = EditorPrefs.GetBool(HashFoldoutPref); + wallHack = EditorPrefs.GetBool(WallHackFoldoutPref); + conditional = EditorPrefs.GetBool(ConditionalFoldoutPref); + } + } + + private const string PrefsPrefix = "ACTkSettings_"; + + private const string IL2CPPFoldoutPref = PrefsPrefix + "IL2CPPFoldout"; + private const string InjectionFoldoutPref = PrefsPrefix + "injectionFoldout"; + private const string HashFoldoutPref = PrefsPrefix + "hashFoldout"; + private const string WallHackFoldoutPref = PrefsPrefix + "wallHackFoldout"; + private const string ConditionalFoldoutPref = PrefsPrefix + "conditionalFoldout"; + + private static readonly Lazy Storage = new Lazy(() => new FoldoutStorage()); + + public static bool IL2CPPFoldout + { + get => Storage.Value.Il2cpp; + set => Storage.Value.Il2cpp = value; + } + + public static bool InjectionFoldout + { + get => Storage.Value.Injection; + set => Storage.Value.Injection = value; + } + + public static bool HashFoldout + { + get => Storage.Value.Hash; + set => Storage.Value.Hash = value; + } + + public static bool WallHackFoldout + { + get => Storage.Value.WallHack; + set => Storage.Value.WallHack = value; + } + + public static bool ConditionalFoldout + { + get => Storage.Value.Conditional; + set => Storage.Value.Conditional = value; + } + + public static void FocusWallhackFoldout() + { + ConditionalFoldout = false; + HashFoldout = false; + InjectionFoldout = false; + IL2CPPFoldout = false; + + WallHackFoldout = true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs.meta new file mode 100644 index 0000000..37cb82b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkEditorPrefsSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3371576aaf6a4dddb491b60c74360fb8 +timeCreated: 1558287287 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs new file mode 100644 index 0000000..773d25e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs @@ -0,0 +1,230 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using UnityEngine.Serialization; + +namespace CodeStage.AntiCheat.EditorCode +{ + using Common; + using System; + using System.Collections.Generic; + using System.IO; + + using UnityEditor; + using UnityEngine; + using Object = UnityEngine.Object; + + /// + /// Represents settings scriptable object. Used mostly internally. + /// + /// Not intended for usage from user code, + /// touch at your peril since API can change and break backwards compatibility! + [Serializable] + public class ACTkSettings : ScriptableObject + { + private const string Directory = "ProjectSettings"; + private const string Path = Directory + "/ACTkSettings.asset"; + + [SerializeField] + private bool injectionDetectorEnabled; + + [SerializeField] + private bool preGenerateBuildHash; + + [SerializeField] + private bool disableInjectionDetectorValidation; + + [FormerlySerializedAs("disableWallhackDetectorValidation")] + [SerializeField] + private bool disableWallhackDetectorShaderValidation; + + [SerializeField] + private bool disableWallhackDetectorPhysicsValidation; + + [SerializeField] + private bool disableWallhackDetectorLinkXmlValidation; + + [SerializeField] + private List injectionDetectorWhiteList = new List(); + + [SerializeField] + private string version = ACTk.Version; + + private static ACTkSettings instance; + public static ACTkSettings Instance + { + get + { + if (instance != null) return instance; + instance = LoadOrCreate(); + return instance; + } + } + + public static void Show() + { + SettingsService.OpenProjectSettings(ACTkEditorConstants.SettingsProviderPath); + } + + public bool InjectionDetectorEnabled + { + get => injectionDetectorEnabled; + set + { + injectionDetectorEnabled = value; + Save(); + } + } + + public bool PreGenerateBuildHash + { + get => preGenerateBuildHash; + set + { + preGenerateBuildHash = value; + Save(); + } + } + + public bool DisableInjectionDetectorValidation + { + get => disableInjectionDetectorValidation; + set + { + disableInjectionDetectorValidation = value; + Save(); + } + } + + public bool DisableWallhackDetectorShaderValidation + { + get => disableWallhackDetectorShaderValidation; + set + { + disableWallhackDetectorShaderValidation = value; + Save(); + } + } + + public bool DisableWallhackDetectorPhysicsValidation + { + get => disableWallhackDetectorPhysicsValidation; + set + { + disableWallhackDetectorPhysicsValidation = value; + Save(); + } + } + + public bool DisableWallhackDetectorLinkXmlValidation + { + get => disableWallhackDetectorLinkXmlValidation; + set + { + disableWallhackDetectorLinkXmlValidation = value; + Save(); + } + } + + public List InjectionDetectorWhiteList + { + get => injectionDetectorWhiteList; + set + { + injectionDetectorWhiteList = value; + Save(); + } + } + + public static void Delete() + { + instance = null; + EditorTools.DeleteFile(Path); + } + + public static void Save() + { + SaveInstance(Instance); + } + + private static ACTkSettings LoadOrCreate() + { + ACTkSettings settings; + + if (!File.Exists(Path)) + { + settings = CreateNewSettingsFile(); + } + else + { + settings = LoadInstance(); + + if (settings == null) + { + EditorTools.DeleteFile(Path); + settings = CreateNewSettingsFile(); + } + + if (settings.version != ACTk.Version) + { + // for future migration reference + } + } + + settings.hideFlags = HideFlags.HideAndDontSave; + settings.version = ACTk.Version; + + return settings; + } + + private static ACTkSettings CreateNewSettingsFile() + { + var settingsInstance = CreateInstance(); + SaveInstance(settingsInstance); + return settingsInstance; + } + + private static void SaveInstance(ACTkSettings settingsInstance) + { + if (!System.IO.Directory.Exists(Directory)) + System.IO.Directory.CreateDirectory(Directory); + + try + { + UnityEditorInternal.InternalEditorUtility.SaveToSerializedFileAndForget(new Object[] { settingsInstance }, Path, true); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Can't save settings!", e); + } + } + + private static ACTkSettings LoadInstance() + { + ACTkSettings settingsInstance; + + try + { + settingsInstance = (ACTkSettings)UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(Path)[0]; + } + catch (Exception e) + { + Debug.Log($"{ACTk.LogPrefix}Can't read settings, resetting them to defaults.\n" + + "This message is harmless in most cases and can be ignored if not repeating.\n" + + $"Exception: {e}"); + settingsInstance = null; + } + + return settingsInstance; + } + + private static ACTkSettings CreateInstance() + { + var newInstance = CreateInstance(); + return newInstance; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs.meta new file mode 100644 index 0000000..592ab6b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 22111be9689046e1bd7b8b1fae4d0b3c +timeCreated: 1552937993 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs new file mode 100644 index 0000000..19430ef --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs @@ -0,0 +1,124 @@ +using System; +using System.IO; +using CodeStage.AntiCheat.Common; +using CodeStage.EditorCommon.Tools; +using UnityEngine; + +namespace CodeStage.AntiCheat.EditorCode +{ + internal class ACTkUserSettings : ScriptableObject + { +#if UNITY_2020_1_OR_NEWER + private const string Folder = "UserSettings"; +#else + private const string Folder = "Library"; +#endif + private const string Path = Folder + "/ACTkSettings.asset"; + + private static ACTkUserSettings instance; + + [SerializeField] + private bool skipProGuardNotice; + + internal bool SkipProGuardNotice + { + get => skipProGuardNotice; + set + { + skipProGuardNotice = value; + Save(); + } + } + + [field: SerializeField] + private string Version { get; set; } = ACTk.Version; // for backward compatibility in future versions + + public static ACTkUserSettings Instance + { + get + { + if (instance != null) return instance; + instance = LoadOrCreate(); + return instance; + } + } + + public static void Delete() + { + instance = null; + CSFileTools.DeleteFile(Path); + } + + public static void Save() + { + SaveInstance(Instance); + } + + private static ACTkUserSettings LoadOrCreate() + { + ACTkUserSettings settings; + + if (!File.Exists(Path)) + { + settings = CreateNewSettingsFile(); + } + else + { + settings = LoadInstance(); + + if (settings == null) + { + CSFileTools.DeleteFile(Path); + settings = CreateNewSettingsFile(); + } + } + + settings.Version = ACTk.Version; + return settings; + } + + private static ACTkUserSettings CreateNewSettingsFile() + { + var settingsInstance = CreateInstance(); + SaveInstance(settingsInstance); + return settingsInstance; + } + + private static void SaveInstance(ACTkUserSettings settingsInstance) + { + if (!Directory.Exists(Folder)) + Directory.CreateDirectory(Folder); + + try + { + UnityEditorInternal.InternalEditorUtility.SaveToSerializedFileAndForget(new[] { settingsInstance }, Path, true); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Can't save user settings!", e); + } + } + + private static ACTkUserSettings LoadInstance() + { + ACTkUserSettings settingsInstance; + + try + { + settingsInstance = (ACTkUserSettings)UnityEditorInternal.InternalEditorUtility.LoadSerializedFileAndForget(Path)[0]; + } + catch (Exception) + { + settingsInstance = null; + } + + return settingsInstance; + } + + private static ACTkUserSettings CreateInstance() + { + var newInstance = CreateInstance(); + return newInstance; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs.meta new file mode 100644 index 0000000..6a806dd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/ACTkUserSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 04905b38ab174522a78ec941de8ba4ec +timeCreated: 1657739749 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs new file mode 100644 index 0000000..177a134 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs @@ -0,0 +1,583 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using Common; + using Detectors; + using EditorCommon.Tools; + using Genuine.CodeHash; + using UnityEditor; + using UnityEditorInternal; + using UnityEngine; +#if UNITY_2021_2_OR_NEWER + using UnityEditor.Build; +#endif + + internal static class SettingsGUI + { + private const string Homepage = "https://codestage.net/uas/actk"; + private const string APILink = "https://codestage.net/uas_files/actk/api/"; + private const string DiscordLink = "https://discord.gg/Ppsb89naWf"; + private const string ForumLink = "https://forum.unity.com/threads/anti-cheat-toolkit-stop-cheaters-easily.196578/"; + private const string ReviewURL = "https://assetstore.unity.com/packages/slug/202695?aid=1011lGBp&pubref=actk#reviews"; + + private static SerializedObject graphicsSettingsAsset; + private static SerializedProperty includedShaders; + + public static void OnGUI() + { + GUITools.Separator(); + DrawSettingsHeader(); + + GUILayout.Space(5f); + DrawIL2CPPSection(); + + EditorGUILayout.Space(); + DrawInjectionSection(); + + EditorGUILayout.Space(); + DrawHashSection(); + + EditorGUILayout.Space(); + DrawWallHackSection(); + + EditorGUILayout.Space(); + DrawConditionalSection(); + + GUILayout.Space(5f); + } + + private static void DrawSettingsHeader() + { + using (new GUILayout.HorizontalScope()) + { + GUILayout.Space(5f); + using (new GUILayout.VerticalScope()) + { + GUILayout.Label("Version: " + ACTk.Version); + + using (new GUILayout.HorizontalScope()) + { + if (GUITools.ImageButton("", "Homepage", Icons.Home)) + Application.OpenURL(Homepage); + + if (GUITools.ImageButton("", "Live Support at Discord", Icons.Discord)) + Application.OpenURL(DiscordLink); + + if (GUITools.ImageButton("", "Forums Support thread", Icons.Forum)) + Application.OpenURL(ForumLink); + + if (GUITools.ImageButton("", "Other Support contacts", Icons.Support)) + Application.OpenURL(ACTk.SupportContact); + + if (GUITools.ImageButton("", "Write a Review at the Asset Store, it will help a lot!", CSEditorIcons.FavoriteIcon)) + { + if (!Event.current.control) + Application.OpenURL(ReviewURL); + else + AssetStore.Open(ReviewURL); + } + + GUILayout.Space(10f); + + if (GUITools.ImageButton("", "Anti-Cheat Toolkit Manual (Readme.pdf)", Icons.Manual)) + EditorTools.OpenReadme(); + + if (GUITools.ImageButton("", "API reference", Icons.API)) + Application.OpenURL(APILink); + + GUILayout.Space(10f); + + if (GUITools.ImageButton("", "About", CSEditorIcons.Help)) + { + EditorUtility.DisplayDialog("About Anti-Cheat Toolkit v" + ACTk.Version, + "Developer: Dmitriy Yukhanov\n" + + "Logo: Daniele Giardini \\m/\n" + + "Icons: Google, Discord\n" + + "Support: my lovely wife, daughters and you! <3\n\n" + + @"¯\_(ツ)_/¯", "Fine!"); + } + } + GUILayout.Space(1f); + } + + GUILayout.FlexibleSpace(); + + var logo = Images.Logo; + if (logo != null) + { + logo.wrapMode = TextureWrapMode.Clamp; + var logoRect = EditorGUILayout.GetControlRect(GUILayout.Width(logo.width), GUILayout.Height(logo.height)); + logoRect.y += 13; + GUI.DrawTexture(logoRect, logo); + } + } + } + + private static void DrawIL2CPPSection() + { + DrawSettingSection("IL2CPP is your friend", + ACTkEditorPrefsSettings.IL2CPPFoldout, + foldout => ACTkEditorPrefsSettings.IL2CPPFoldout = foldout, DrawContent); + + void DrawContent() + { + GUILayout.Label("IL2CPP prevents Mono injections and easy code decompilation. " + + "Also consider obfuscating your metadata to make cheaters cry, see readme for details.", + GUITools.RichLabel); + + GUILayout.Label("Note: IL2CPP is AOT and does not support JIT!", GUITools.RichMiniLabel); + + GUILayout.Space(5f); + + var supported = SettingsUtils.IsIL2CPPSupported(); + GUILayout.Label($"IL2CPP Supported: {CSColorTools.WrapBool(supported)}", + GUITools.RichLabel); + + var enabled = SettingsUtils.IsIL2CPPEnabled(); + GUILayout.Label($"IL2CPP Enabled: {CSColorTools.WrapBool(enabled)}", + GUITools.RichLabel); + + if (SettingsUtils.IsIL2CPPEnabled() || !SettingsUtils.IsIL2CPPSupported()) + return; + + GUILayout.Space(5f); + EditorGUILayout.HelpBox("Use IL2CPP to stop injections & easy code decompilation", + MessageType.Warning, true); + GUILayout.Space(5f); + if (GUILayout.Button(new GUIContent("Switch to IL2CPP"))) + { +#if UNITY_2021_2_OR_NEWER + var namedTarget = NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + PlayerSettings.SetScriptingBackend(namedTarget, + ScriptingImplementation.IL2CPP); +#else + PlayerSettings.SetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup, + ScriptingImplementation.IL2CPP); +#endif + } + } + } + + private static void DrawInjectionSection() + { + DrawSettingSection("Injection Detector", + ACTkEditorPrefsSettings.InjectionFoldout, + foldout => ACTkEditorPrefsSettings.InjectionFoldout = foldout, DrawContent); + + void DrawContent() + { + var enableInjectionDetector = ACTkSettings.Instance.InjectionDetectorEnabled; + + if (SettingsUtils.IsIL2CPPEnabled()) + { + EditorGUILayout.HelpBox("Injection is not possible in IL2CPP,\n" + + "this detector is not needed in IL2CPP builds", MessageType.Info, true); + GUILayout.Space(5f); + } + else if (!InjectionRoutines.IsTargetPlatformCompatible()) + { + EditorGUILayout.HelpBox( + "Injection Detection is only supported in non-IL2CPP Standalone and Android builds", + MessageType.Warning, true); + GUILayout.Space(5f); + } + + using (new GUILayout.HorizontalScope()) + { + EditorGUI.BeginChangeCheck(); + enableInjectionDetector = EditorGUILayout.ToggleLeft(new GUIContent( + "Add mono injection detection support to build", + "Injection Detector checks assemblies against whitelist. " + + "Please enable this option if you're using Injection Detector " + + "and default whitelist will be generated while Unity builds resulting build.\n" + + "Has no effect for IL2CPP or unsupported platforms."), enableInjectionDetector + ); + if (EditorGUI.EndChangeCheck()) + { + ACTkSettings.Instance.InjectionDetectorEnabled = enableInjectionDetector; + } + } + + GUILayout.Space(3); + + if (GUILayout.Button(new GUIContent( + "Edit Custom Whitelist (" + ACTkSettings.Instance.InjectionDetectorWhiteList.Count + ")", + "Fill any external assemblies which are not included into the project to the user-defined whitelist to make Injection Detector aware of them.")) + ) + { + UserWhitelistEditor.ShowWindow(); + } + } + } + + private static void DrawHashSection() + { + DrawSettingSection("Code Hash Generator", + ACTkEditorPrefsSettings.HashFoldout, + foldout => ACTkEditorPrefsSettings.HashFoldout = foldout, DrawContent); + + void DrawContent() + { + var option = ACTkSettings.Instance.PreGenerateBuildHash; + + EditorGUI.BeginChangeCheck(); + option = EditorGUILayout.ToggleLeft( + new GUIContent("Generate code hash on build completion", + "Generates hash after build is finished, prints it to the console & sends it via CodeHashGeneratorPostprocessor."), + option); + if (EditorGUI.EndChangeCheck()) + { + ACTkSettings.Instance.PreGenerateBuildHash = option; + } + + EditorGUILayout.Space(); + + GUILayout.Label( + "Can differ from runtime hash if you post-process code in resulting build (e.g. obfuscate, compress, etc.).", + GUITools.RichLabel); + + GUILayout.Space(5f); + EditorGUILayout.HelpBox( + "Always make sure post-build hash equals runtime one if you're using it for later comparison", + MessageType.Info, true); + + if (!CodeHashGenerator.IsTargetPlatformCompatible()) + { + EditorGUILayout.HelpBox("Current platform is not supported: Windows or Android required", + MessageType.Warning, true); + } + } + } + + private static void DrawWallHackSection() + { + DrawSettingSection("WallHack Detector", + ACTkEditorPrefsSettings.WallHackFoldout, + foldout => ACTkEditorPrefsSettings.WallHackFoldout = foldout, DrawContent, false); + + void DrawContent() + { + DrawShaderPanel(); + GUILayout.Space(5f); + DrawLinkXmlPanel(); + } + + void DrawShaderPanel() + { + using (GUITools.Vertical(GUITools.PanelWithBackground)) + { + GUILayout.Label("Wireframe module shader", EditorStyles.boldLabel); + GUILayout.Space(5f); + GUILayout.Label( + "Wireframe module uses own shader under the hood and it should be included into the build.", + EditorStyles.wordWrappedLabel); + + ReadGraphicsAsset(); + + if (graphicsSettingsAsset != null && includedShaders != null) + { + // outputs whole included shaders list, use for debug + //EditorGUILayout.PropertyField(includedShaders, true); + + var shaderIndex = GetWallhackDetectorShaderIndex(); + + EditorGUI.BeginChangeCheck(); + + GUILayout.Label( + $"Shader status: {CSColorTools.WrapString("included", "not included", shaderIndex != -1)}", + GUITools.RichLabel); + GUILayout.Space(5f); + EditorGUILayout.HelpBox("You don't need to include it if you're not going to use Wireframe module", + MessageType.Info, true); + GUILayout.Space(5f); + + if (shaderIndex != -1) + { + if (GUILayout.Button("Remove shader")) + { + includedShaders.DeleteArrayElementAtIndex(shaderIndex); + includedShaders.DeleteArrayElementAtIndex(shaderIndex); + } + + GUILayout.Space(3); + } + else + { + using (GUITools.Horizontal()) + { + if (GUILayout.Button("Auto Include")) + { + var shader = Shader.Find(WallHackDetector.WireframeShaderName); + if (shader != null) + { + includedShaders.InsertArrayElementAtIndex(includedShaders.arraySize); + var newItem = includedShaders.GetArrayElementAtIndex(includedShaders.arraySize - 1); + newItem.objectReferenceValue = shader; + } + else + { + ACTk.PrintExceptionForSupport($"Can't find {WallHackDetector.WireframeShaderName} shader!"); + } + } + + if (GUILayout.Button("Include manually (see readme.pdf)")) + { + SettingsService.OpenProjectSettings("Project/Graphics"); + } + } + + GUILayout.Space(3); + } + + if (EditorGUI.EndChangeCheck()) + { + graphicsSettingsAsset.ApplyModifiedProperties(); + } + } + else + { + GUILayout.Label("Can't automatically control " + WallHackDetector.WireframeShaderName + + " shader existence at the Always Included Shaders list. Please, manage this manually in Graphics Settings."); + if (GUILayout.Button("Open Graphics Settings")) + { + SettingsService.OpenProjectSettings("Project/Graphics"); + } + } + } + } + + void DrawLinkXmlPanel() + { + using (GUITools.Vertical(GUITools.PanelWithBackground)) + { + GUILayout.Label("IL2CPP Strip Engine Code caution", EditorStyles.boldLabel); + GUILayout.Space(5f); + var linkXmlEnabled = SettingsUtils.IsLinkXmlEnabled(); + if (!linkXmlEnabled) + { + var linkXmlRequired = SettingsUtils.IsLinkXmlRequired(); + if (linkXmlRequired) + { + EditorGUILayout.HelpBox( + "False positives are possible due to IL2CPP Strip Engine Code feature, enable automatic link.xml generation below to prevent it.", + MessageType.Warning); + if (GUILayout.Button("Enable automatic link.xml generation")) + { + SettingsUtils.SwitchSymbol(ACTkEditorConstants.Conditionals.WallhackLinkXML, true); + } + } + else + { + EditorGUILayout.HelpBox( + "False positives are possible due to IL2CPP Strip Engine Code feature but you're safe since either IL2CPP or String Engine Code feature is not active now.", + MessageType.Info); + if (GUILayout.Button("Enable automatic link.xml generation anyway")) + { + SettingsUtils.SwitchSymbol(ACTkEditorConstants.Conditionals.WallhackLinkXML, true); + } + } + } + else + { + EditorGUILayout.HelpBox( + "Automatic link.xml generation enabled, you are safe from possible false positives caused by IL2CPP Strip Engine Code feature.", + MessageType.Info); + if (GUILayout.Button("Disable automatic link.xml generation")) + { + SettingsUtils.SwitchSymbol(ACTkEditorConstants.Conditionals.WallhackLinkXML, false); + } + } + + GUILayout.Label( + $"This setting is duplicated by {ACTkEditorConstants.Conditionals.WallhackLinkXML} conditional symbol in conditional symbols section below", + EditorStyles.wordWrappedMiniLabel); + + } + } + } + + private static void DrawConditionalSection() + { + var header = "Conditional Compilation Symbols"; + if (EditorApplication.isCompiling) + { + header += $" [{CSColorTools.WrapString("compiling...", CSColorTools.ColorKind.Purple)}]"; + } + + DrawSettingSection(header, + ACTkEditorPrefsSettings.ConditionalFoldout, + foldout => ACTkEditorPrefsSettings.ConditionalFoldout = foldout, DrawContent); + + void DrawContent() + { + if (EditorApplication.isCompiling) + GUI.enabled = false; + + GUILayout.Label("Here you may switch conditional compilation symbols used in ACTk.\n" + + "Check Readme for more details on each symbol.", EditorStyles.wordWrappedLabel); + EditorGUILayout.Space(); + + var symbolsData = SettingsUtils.GetSymbolsData(); + + GUILayout.Label("Debug", GUITools.LargeBoldLabel); + GUITools.Separator(); + + DrawSymbol(ref symbolsData.injectionDebug, + ACTkEditorConstants.Conditionals.InjectionDebug, + "Switches the Injection Detector debug."); + DrawSymbol(ref symbolsData.injectionDebugVerbose, + ACTkEditorConstants.Conditionals.InjectionDebugVerbose, + "Switches the Injection Detector verbose debug level."); + DrawSymbol(ref symbolsData.injectionDebugParanoid, + ACTkEditorConstants.Conditionals.InjectionDebugParanoid, + "Switches the Injection Detector paranoid debug level."); + DrawSymbol(ref symbolsData.wallhackDebug, + ACTkEditorConstants.Conditionals.WallhackDebug, + "Switches the WallHack Detector debug - you'll see the WallHack objects in scene and get extra information in console."); + DrawSymbol(ref symbolsData.detectionBacklogs, + ACTkEditorConstants.Conditionals.DetectionBacklogs, + "Enables additional logs in some detectors to make it easier to debug false positives."); + DrawSymbol(ref symbolsData.genericDevLogs, + ACTkEditorConstants.Conditionals.GenericDevLogs, + "Enables additional generic development logs all across the toolkit (used mainly for development purposes)."); + + EditorGUILayout.Space(); + GUILayout.Label("Third-party related", GUITools.LargeBoldLabel); + GUITools.Separator(); + + DrawSymbol(ref symbolsData.exposeThirdPartyIntegration, + ACTkEditorConstants.Conditionals.ThirdPartyIntegration, + "Enable to let other third-party code in project know you have ACTk added."); + DrawSymbol(ref symbolsData.newtonsoftJson, + ACTkEditorConstants.Conditionals.NewtonsoftJson, + "Enables Newtonsoft Json Converter for the Obscured Types if you're not using com.unity.nuget.newtonsoft-json Unity package."); + + EditorGUILayout.Space(); + GUILayout.Label("Compatibility", GUITools.LargeBoldLabel); + GUITools.Separator(); + + DrawSymbol(ref symbolsData.wallhackLinkXML, + ACTkEditorConstants.Conditionals.WallhackLinkXML, + "Enables automatic link.xml generation to prevent stripping of components required by WallHack Detector.\nSee details at WallHack Detector settings section above."); + DrawSymbol(ref symbolsData.excludeObfuscation, + ACTkEditorConstants.Conditionals.ExcludeObfuscation, + "Enable if you use Unity-unaware obfuscators which support ObfuscationAttribute to help avoid names corruption."); + DrawSymbol(ref symbolsData.preventReadPhoneState, + ACTkEditorConstants.Conditionals.PreventReadPhoneState, + "Disables ObscuredPrefs Lock To Device functionality."); + DrawSymbol(ref symbolsData.preventInternetPermission, + ACTkEditorConstants.Conditionals.PreventInternetPermission, + "Disables TimeCheatingDetector functionality."); + DrawSymbol(ref symbolsData.obscuredAutoMigration, + ACTkEditorConstants.Conditionals.ObscuredAutoMigration, + "Enables automatic migration of ObscuredFloat and ObscuredDouble instances from the ACTk 1.5.2.0-1.5.8.0 to the 1.5.9.0+ format. Reduces these types performance a bit."); + DrawSymbol(ref symbolsData.usExportCompatible, + ACTkEditorConstants.Conditionals.UsExportCompatible, + "Enables US Encryption Export Regulations compatibility mode so ACTk do not force you to declare you're using exempt encryption when publishing your application to the Apple App Store."); + + GUI.enabled = true; + } + } + + private static void DrawSettingSection(string caption, bool foldout, Action foldoutCallback, Action drawContentCallback, bool drawBackground = true) + { + using (var changed = new EditorGUI.ChangeCheckScope()) + { + var fold = GUITools.DrawFoldHeader(caption, foldout); + if (changed.changed) + { + foldout = fold; + foldoutCallback(foldout); + } + } + + if (!foldout) return; + + GUILayout.Space(3f); + using (GUITools.Horizontal()) + { + GUILayout.Space(20f); + + using (GUITools.Vertical(drawBackground ? GUITools.PanelWithBackground : GUIStyle.none)) + { + drawContentCallback(); + GUILayout.Space(3); + } + GUILayout.Space(5f); + } + } + + public static bool IsWallhackDetectorShaderIncluded() + { + var result = false; + + ReadGraphicsAsset(); + if (GetWallhackDetectorShaderIndex() != -1) + result = true; + + return result; + } + + private static void ReadGraphicsAsset() + { + if (graphicsSettingsAsset != null) return; + + var assets = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/GraphicsSettings.asset"); + if (assets.Length > 0) + graphicsSettingsAsset = new SerializedObject(assets[0]); + + if (graphicsSettingsAsset != null) + { + includedShaders = graphicsSettingsAsset.FindProperty("m_AlwaysIncludedShaders"); + if (includedShaders == null) + ACTk.PrintExceptionForSupport("Couldn't find m_AlwaysIncludedShaders property"); + } + else + { + ACTk.PrintExceptionForSupport("Couldn't find GraphicsSettings asset"); + } + } + + private static int GetWallhackDetectorShaderIndex() + { + if (graphicsSettingsAsset == null || includedShaders == null) return -1; + + var result = -1; + graphicsSettingsAsset.Update(); + + var itemsCount = includedShaders.arraySize; + for (var i = 0; i < itemsCount; i++) + { + var arrayItem = includedShaders.GetArrayElementAtIndex(i); + if (arrayItem.objectReferenceValue != null) + { + var shader = (Shader)(arrayItem.objectReferenceValue); + + if (shader.name == WallHackDetector.WireframeShaderName) + { + result = i; + break; + } + } + } + + return result; + } + + private static void DrawSymbol(ref bool field, string symbol, string hint) + { + EditorGUI.BeginChangeCheck(); + field = EditorGUILayout.ToggleLeft(new GUIContent(symbol, hint), field); + if (EditorGUI.EndChangeCheck()) + { + SettingsUtils.SwitchSymbol(symbol, field); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs.meta new file mode 100644 index 0000000..38781a1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsGUI.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b26f8a79ff8f40aeba8abe91f4d3c9b9 +timeCreated: 1557586094 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs new file mode 100644 index 0000000..61e1ab6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs @@ -0,0 +1,31 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System.Collections.Generic; + using UnityEditor; + + internal static class SettingsProviderWrapper + { + [SettingsProvider] + public static SettingsProvider CreateMyCustomSettingsProvider() + { + var provider = new SettingsProvider(ACTkEditorConstants.SettingsProviderPath, SettingsScope.Project) + { + label = "Anti-Cheat Toolkit", + guiHandler = searchContext => + { + SettingsGUI.OnGUI(); + }, + + keywords = new HashSet(new[] {"codestage", "Anti", "Cheat", "Toolkit", "Injection", "Hash", "Wall", "Hack", "ACTk", "Patch", "Protect", "Detect" }) + }; + + return provider; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs.meta new file mode 100644 index 0000000..976829b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsProviderWrapper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4cad2b15267a468e893f905d662976b2 +timeCreated: 1557591437 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs new file mode 100644 index 0000000..7517cb0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs @@ -0,0 +1,248 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using Common; + using UnityEditor; + using UnityEngine; + using Object = UnityEngine.Object; +#if UNITY_2021_2_OR_NEWER + using UnityEditor.Build; +#endif + + internal static class SettingsUtils + { + private static SymbolsData cachedSymbolsData; + + public static bool IsIL2CPPEnabled() + { + // ReSharper disable once ConvertIfStatementToReturnStatement - it's not redundant ;) + if (IsScriptingBackendIL2CPP()) + return true; + +#if ENABLE_IL2CPP + return true; +#else + return false; +#endif + + bool IsScriptingBackendIL2CPP() + { +#if UNITY_2021_2_OR_NEWER + var namedTarget = NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + var scriptingBackend = PlayerSettings.GetScriptingBackend(namedTarget); +#else + var scriptingBackend = PlayerSettings.GetScriptingBackend(EditorUserBuildSettings.selectedBuildTargetGroup); +#endif + return scriptingBackend == ScriptingImplementation.IL2CPP; + } + } + + public static bool IsIL2CPPSupported() + { + return IsIL2CPPEnabled() || ReflectionTools.IsScriptingImplementationSupported(ScriptingImplementation.IL2CPP, EditorUserBuildSettings.selectedBuildTargetGroup); + } + + public static bool IsLinkXmlRequired() + { + return IsIL2CPPEnabled() && PlayerSettings.stripEngineCode; + } + + public static bool IsLinkXmlEnabled() + { + return GetSymbolsData().wallhackLinkXML; + } + + public static SymbolsData GetSymbolsData() + { + var groups = (BuildTargetGroup[])Enum.GetValues(typeof(BuildTargetGroup)); + foreach (var buildTargetGroup in groups) + { + if (buildTargetGroup == BuildTargetGroup.Unknown) continue; + if (IsBuildTargetGroupNameObsolete(buildTargetGroup.ToString())) continue; + + try + { + var symbols = GetConditionalSymbolsForPlatform(buildTargetGroup); + + cachedSymbolsData.wallhackLinkXML |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.WallhackLinkXML); + cachedSymbolsData.excludeObfuscation |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.ExcludeObfuscation); + cachedSymbolsData.preventReadPhoneState |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.PreventReadPhoneState); + cachedSymbolsData.preventInternetPermission |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.PreventInternetPermission); + cachedSymbolsData.obscuredAutoMigration |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.ObscuredAutoMigration); + cachedSymbolsData.exposeThirdPartyIntegration |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.ThirdPartyIntegration); + cachedSymbolsData.usExportCompatible |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.UsExportCompatible); + cachedSymbolsData.newtonsoftJson |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.NewtonsoftJson); + + cachedSymbolsData.injectionDebug |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.InjectionDebug); + cachedSymbolsData.injectionDebugVerbose |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.InjectionDebugVerbose); + cachedSymbolsData.injectionDebugParanoid |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.InjectionDebugParanoid); + cachedSymbolsData.wallhackDebug |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.WallhackDebug); + cachedSymbolsData.detectionBacklogs |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.DetectionBacklogs); + cachedSymbolsData.genericDevLogs |= GetSymbol(symbols, ACTkEditorConstants.Conditionals.GenericDevLogs); + } + catch (Exception) + { + // ignoring obsolete ones + } + } + + return cachedSymbolsData; + } + + private static string GetConditionalSymbolsForPlatform(BuildTargetGroup buildTargetGroup) + { +#if UNITY_2021_2_OR_NEWER + var namedTarget = NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup); + return PlayerSettings.GetScriptingDefineSymbols(namedTarget); +#else + return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup); +#endif + } + + private static bool GetSymbol(string symbols, string symbol) + { + var result = false; + + if (symbols == symbol) + result = true; + else if (symbols.StartsWith(symbol + ';')) + result = true; + else if (symbols.EndsWith(';' + symbol)) + result = true; + else if (symbols.Contains(';' + symbol + ';')) + result = true; + + return result; + } + + public static void SwitchSymbol(string symbol, bool active) + { + var groups = (BuildTargetGroup[])Enum.GetValues(typeof(BuildTargetGroup)); + + // this is required to get names for obsolete items alternatives like iOS instead of deprecated iPhone + var names = Enum.GetNames(typeof(BuildTargetGroup)); + + for (var i = 0; i < groups.Length; i++) + { + var buildTargetGroup = groups[i]; + var buildTargetName = names[i]; + + if (buildTargetGroup == BuildTargetGroup.Unknown) continue; + if (IsBuildTargetGroupNameObsolete(buildTargetName)) continue; + + try + { + var symbols = GetConditionalSymbolsForPlatform(buildTargetGroup); + + if (active) + AddSymbol(ref symbols, symbol); + else + RemoveSymbol(ref symbols, symbol); + +#if UNITY_2021_2_OR_NEWER + var namedTarget = NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup); + PlayerSettings.SetScriptingDefineSymbols(namedTarget, symbols); +#else + PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, symbols); +#endif + } + catch (Exception) + { + // ignoring obsolete ones + } + } + } + + private static void AddSymbol(ref string symbols, string symbol) + { + if (symbols.Length == 0) + { + symbols = symbol; + } + else + { + if (symbols.EndsWith(";")) + symbols += symbol; + else + symbols += ';' + symbol; + } + } + + private static void RemoveSymbol(ref string symbols, string symbol) + { + if (symbols == symbol) + symbols = string.Empty; + else if (symbols.StartsWith(symbol + ';')) + symbols = symbols.Remove(0, symbol.Length + 1); + else if (symbols.EndsWith(';' + symbol)) + symbols = symbols.Remove(symbols.LastIndexOf(';' + symbol, StringComparison.Ordinal), symbol.Length + 1); + else if (symbols.Contains(';' + symbol + ';')) + symbols = symbols.Replace(';' + symbol + ';', ";"); + } + + private static bool IsBuildTargetGroupNameObsolete(string name) + { + var fi = typeof(BuildTargetGroup).GetField(name); + var attributes = (ObsoleteAttribute[])fi.GetCustomAttributes(typeof(ObsoleteAttribute), false); + return attributes.Length > 0; + } + + public static bool IsPhysicsUsesTemporalSolver() + { + var solverTypeProperty = GetPhysicsSolverTypeProperty(); + if (solverTypeProperty == null) + return false; + + return solverTypeProperty.intValue == 1; + } + + private static Object LoadDynamicManager() + { + var dynamicsManager = AssetDatabase.LoadAssetAtPath("ProjectSettings/DynamicsManager.asset"); + if (dynamicsManager == null) + ACTk.PrintExceptionForSupport("Couldn't find the DynamicsManager"); + + return dynamicsManager; + } + + private static SerializedProperty GetPhysicsSolverTypeProperty() + { + var dynamicsManager = LoadDynamicManager(); + if (dynamicsManager == null) + return null; + + var so = new SerializedObject(dynamicsManager); + var field = so.FindProperty("m_SolverType"); + + if (field == null) + ACTk.PrintExceptionForSupport("Couldn't find the m_SolverType field in the DynamicsManager class!"); + + return field; + } + + public static void ShowPhysicsSettings() + { + SettingsService.OpenProjectSettings("Project/Physics"); + } + + public static void ShowSolverTypesProperty() + { + ShowPhysicsSettings(); + +#if UNITY_2021_3_OR_NEWER + EditorApplication.delayCall += () => + { + var solverTypeProperty = GetPhysicsSolverTypeProperty(); + if (solverTypeProperty != null) + Highlighter.Highlight("Project Settings", solverTypeProperty.propertyPath, HighlightSearchMode.Identifier); + }; +#endif + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs.meta new file mode 100644 index 0000000..b84fcee --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 45ebf9a6511c49819d3a64fc4ca0eb03 +timeCreated: 1557586492 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs new file mode 100644 index 0000000..bd58096 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs @@ -0,0 +1,138 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode.Validation +{ + using Detectors; + using UnityEditor; + + [InitializeOnLoad] + internal static class SettingsValidator + { + private static bool injectionValidated; + private static bool wallhackValidated; + + static SettingsValidator() + { + EditorApplication.hierarchyChanged += OnHierarchyChanged; + } + + private static void OnHierarchyChanged() + { + if (!injectionValidated && !ACTkSettings.Instance.DisableInjectionDetectorValidation) + { + var instance = InjectionDetector.Instance; + if (instance != null) + { + if (InjectionRoutines.IsInjectionPossible()) + { + if (!ACTkSettings.Instance.InjectionDetectorEnabled) + { + var result = EditorUtility.DisplayDialogComplex("Anti-Cheat Toolkit Validation", + "ACTk noticed you're using Injection Detector while having build injection detection support disabled.\n" + + "It should be enabled in order to work properly.\nWould you like to enable it now?", + "Yes", "Open Settings", "No, never ask again"); + + switch (result) + { + case 0: + ACTkSettings.Instance.InjectionDetectorEnabled = true; + break; + case 1: + ACTkSettings.Show(); + injectionValidated = true; + return; + default: + ACTkSettings.Instance.DisableInjectionDetectorValidation = true; + break; + } + } + } + } + injectionValidated = true; + } + + if (!wallhackValidated && + (!ACTkSettings.Instance.DisableWallhackDetectorShaderValidation || + !ACTkSettings.Instance.DisableWallhackDetectorLinkXmlValidation || + !ACTkSettings.Instance.DisableWallhackDetectorPhysicsValidation)) + { + var instance = WallHackDetector.Instance; + if (instance != null) + { + if (!ACTkSettings.Instance.DisableWallhackDetectorShaderValidation && + instance.CheckWireframe && + !SettingsGUI.IsWallhackDetectorShaderIncluded()) + { + var result = EditorUtility.DisplayDialog("Anti-Cheat Toolkit Validation", + "ACTk noticed you're using WallHack Detector with Wireframe option enabled but you have no required shader added" + + " to the Always Included Shaders.\n" + + "Would you like to exit Play Mode and open Settings to include it now?", + "Yes", "No, never ask again"); + + if (result) + { + EditorApplication.isPlaying = false; + ACTkEditorPrefsSettings.FocusWallhackFoldout(); + ACTkSettings.Show(); + wallhackValidated = true; + return; + } + + ACTkSettings.Instance.DisableWallhackDetectorShaderValidation = true; + } + + if (!ACTkSettings.Instance.DisableWallhackDetectorPhysicsValidation && + (instance.CheckRigidbody || instance.CheckController) && + SettingsUtils.IsPhysicsUsesTemporalSolver()) + { + var result = EditorUtility.DisplayDialog("Anti-Cheat Toolkit Validation", + "ACTk noticed you're using WallHack Detector with either Rigidbody or Character Controller option enabled while having Project Settings > Physics > Solver Type property set to the Temporal Gauss Seidel value.\n\n" + + "This can lead to the physics anomalies and unpredicted behavior due to how this solver operates while having few continuously colliding objects in the scene (which is going to happen when you use the WallHack Detector with current options).\n\n" + + "It's recommended to switch the Solver Type to the Projected Gauss Seidel in such case.\n" + + "Would you like to exit Play Mode and open Settings to switch it now?", + "Yes", "No, never ask again"); + + if (result) + { + EditorApplication.isPlaying = false; + SettingsUtils.ShowSolverTypesProperty(); + wallhackValidated = true; + return; + } + + ACTkSettings.Instance.DisableWallhackDetectorPhysicsValidation = true; + } + + if (!ACTkSettings.Instance.DisableWallhackDetectorLinkXmlValidation && + SettingsUtils.IsLinkXmlRequired() && + !SettingsUtils.IsLinkXmlEnabled()) + { + var result = EditorUtility.DisplayDialog("Anti-Cheat Toolkit Validation", + "ACTk noticed you're using WallHack Detector while having IL2CPP's " + + "Strip Engine Code setting enabled which can lead to stripping of components " + + "required by WallHack Detector causing false positives.\n\n" + + "To prevent such stripping, components should be added to the link.xml so linker could exclude them from stripping.\n" + + "Would you like to exit Play Mode and open Settings to enable automatic link.xml generation?", + "Yes", "No, never ask again"); + + if (result) + { + EditorApplication.isPlaying = false; + ACTkEditorPrefsSettings.FocusWallhackFoldout(); + ACTkSettings.Show(); + wallhackValidated = true; + return; + } + + ACTkSettings.Instance.DisableWallhackDetectorLinkXmlValidation = true; + } + } + wallhackValidated = true; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs.meta new file mode 100644 index 0000000..e54a596 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SettingsValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 78821826b15a44e79ed6c8549e3c1f1d +timeCreated: 1557605995 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs new file mode 100644 index 0000000..696492c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs @@ -0,0 +1,27 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + internal struct SymbolsData + { + public bool wallhackLinkXML; + public bool excludeObfuscation; + public bool preventReadPhoneState; + public bool preventInternetPermission; + public bool obscuredAutoMigration; + public bool exposeThirdPartyIntegration; + public bool usExportCompatible; + public bool newtonsoftJson; + + public bool injectionDebug; + public bool injectionDebugVerbose; + public bool injectionDebugParanoid; + public bool wallhackDebug; + public bool detectionBacklogs; + public bool genericDevLogs; + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs.meta new file mode 100644 index 0000000..7d13527 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Settings/SymbolsData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8259422d2c3f43a6a50862621be7436d +timeCreated: 1557586522 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools.meta new file mode 100644 index 0000000..85f1764 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b8ffd81fe391c4c4d99936ae7a0bbc08 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs new file mode 100644 index 0000000..5190263 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs @@ -0,0 +1,129 @@ +// +// original source: https://stackoverflow.com/a/5097066/929246 +// + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace CodeStage.AntiCheat.EditorCode +{ + internal static class AsyncHelpers + { + public static void RunSync(Func task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + synch.Post(async _ => + { + try + { + await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + + SynchronizationContext.SetSynchronizationContext(oldContext); + } + + public static T RunSync(Func> task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + T ret = default(T); + synch.Post(async _ => + { + try + { + ret = await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + SynchronizationContext.SetSynchronizationContext(oldContext); + return ret; + } + + private class ExclusiveSynchronizationContext : SynchronizationContext + { + private bool done; + public Exception InnerException { get; set; } + + private readonly AutoResetEvent workItemsWaiting = new AutoResetEvent(false); + private readonly Queue> items = new Queue>(); + + public override void Send(SendOrPostCallback d, object state) + { + throw new NotSupportedException("We cannot send to our same thread"); + } + + public override void Post(SendOrPostCallback d, object state) + { + lock (items) + { + items.Enqueue(Tuple.Create(d, state)); + } + + workItemsWaiting.Set(); + } + + public void EndMessageLoop() + { + Post(_ => done = true, null); + } + + public void BeginMessageLoop() + { + while (!done) + { + Tuple task = null; + lock (items) + { + if (items.Count > 0) + { + task = items.Dequeue(); + } + } + + if (task != null) + { + task.Item1(task.Item2); + if (InnerException != null) // the method threw an exeption + { + throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); + } + } + else + { + workItemsWaiting.WaitOne(); + } + } + } + + public override SynchronizationContext CreateCopy() + { + return this; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs.meta new file mode 100644 index 0000000..7cd42d8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/AsyncHelpers.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f7a87b8e9d64a87bfeac78cba14813a +timeCreated: 1683630296 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs new file mode 100644 index 0000000..4e5869c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs @@ -0,0 +1,90 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using Common; + using UnityEditor; + using UnityEngine; + + internal static class DetectorTools + { + public static void SetupDetectorInScene() where T : KeepAliveBehaviour + { +#if UNITY_2023_1_OR_NEWER + var component = Object.FindAnyObjectByType(); +#else + var component = Object.FindObjectOfType(); +#endif + var detectorName = typeof(T).Name; + + if (component != null) + { + if (component.gameObject.name == ContainerHolder.ContainerName) + { + EditorUtility.DisplayDialog(detectorName + " already exists!", + detectorName + " already exists in scene and correctly placed on object \"" + ContainerHolder.ContainerName + + "\"", "OK"); + } + else + { + var dialogResult = EditorUtility.DisplayDialogComplex(detectorName + " already exists!", + detectorName + " already exists in scene and placed on object \"" + component.gameObject.name + + "\". Do you wish to move it to the Game Object \"" + ContainerHolder.ContainerName + + "\" or delete it from scene at all?", "Move", "Delete", "Cancel"); + switch (dialogResult) + { + case 0: + var container = GameObject.Find(ContainerHolder.ContainerName); + if (container == null) + { + container = new GameObject(ContainerHolder.ContainerName); + } + + var newComponent = container.AddComponent(); + EditorUtility.CopySerialized(component, newComponent); + DestroyDetectorImmediate(component); + break; + case 1: + DestroyDetectorImmediate(component); + break; + default: + Debug.LogError("Unknown result from the EditorUtility.DisplayDialogComplex API!"); + break; + } + } + } + else + { + var container = GameObject.Find(ContainerHolder.ContainerName); + if (container == null) + { + container = new GameObject(ContainerHolder.ContainerName); + + Undo.RegisterCreatedObjectUndo(container, "Create " + ContainerHolder.ContainerName); + } + + Undo.AddComponent(container); + + EditorUtility.DisplayDialog(detectorName + " added!", + detectorName + " successfully added to the object \"" + ContainerHolder.ContainerName + "\"", "OK"); + Selection.activeGameObject = container; + } + } + + private static void DestroyDetectorImmediate(Component component) where T: KeepAliveBehaviour + { + if (component.transform.childCount == 0 && component.GetComponentsInChildren(true).Length <= 2) + { + Object.DestroyImmediate(component.gameObject); + } + else + { + Object.DestroyImmediate(component); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs.meta new file mode 100644 index 0000000..d3a5c2d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/DetectorTools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2efcce1fc5ffdd740845b9df0f9cd7ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs new file mode 100644 index 0000000..6ea3270 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs @@ -0,0 +1,447 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using UnityEditor.SceneManagement; +using UnityEngine.SceneManagement; + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections.Generic; + using System.IO; + using Common; + using UnityEditor; + using UnityEngine; + using UnityEngine.Events; + using Object = UnityEngine.Object; + + internal delegate bool ProcessSerializedProperty(Object target, SerializedProperty sp, string location, string type); + + internal static class EditorTools + { + private static SerializedObject audioManager; + + #region files and directories + + private static string directory; + + public static void DeleteFile(string path) + { + if (!File.Exists(path)) return; + RemoveReadOnlyAttribute(path); + File.Delete(path); + } + + public static void RemoveDirectoryIfEmpty(string directoryName) + { + if (Directory.Exists(directoryName) && IsDirectoryEmpty(directoryName)) + { + FileUtil.DeleteFileOrDirectory(directoryName); + var metaFile = AssetDatabase.GetTextMetaFilePathFromAssetPath(directoryName); + if (File.Exists(metaFile)) + { + FileUtil.DeleteFileOrDirectory(metaFile); + } + } + } + + public static bool IsDirectoryEmpty(string path) + { + var dirs = Directory.GetDirectories(path); + var files = Directory.GetFiles(path); + return dirs.Length == 0 && files.Length == 0; + } + + public static string GetACTkDirectory() + { + if (!string.IsNullOrEmpty(directory)) + { + return directory; + } + + directory = ACTkMarker.GetAssetPath(); + + if (!string.IsNullOrEmpty(directory)) + { + if (directory.IndexOf("Editor/Scripts/ACTkMarker.cs", StringComparison.Ordinal) >= 0) + { + directory = directory.Replace("Editor/Scripts/ACTkMarker.cs", ""); + } + else + { + directory = null; + ACTk.PrintExceptionForSupport("Looks like Anti-Cheat Toolkit is placed in project incorrectly!"); + } + } + else + { + directory = null; + ACTk.PrintExceptionForSupport("Can't locate the Anti-Cheat Toolkit directory!"); + } + return directory; + } + + #endregion + + public static bool CheckUnityEventHasActivePersistentListener(SerializedProperty unityEvent) + { + if (unityEvent == null) return false; + + var calls = unityEvent.FindPropertyRelative("m_PersistentCalls.m_Calls"); + if (calls == null) + { + ACTk.PrintExceptionForSupport("Can't find Unity Event calls!"); + return false; + } + if (!calls.isArray) + { + ACTk.PrintExceptionForSupport("Looks like Unity Event calls are not array anymore!"); + return false; + } + + var result = false; + + var callsCount = calls.arraySize; + for (var i = 0; i < callsCount; i++) + { + var call = calls.GetArrayElementAtIndex(i); + + var targetProperty = call.FindPropertyRelative("m_Target"); + var methodNameProperty = call.FindPropertyRelative("m_MethodName"); + var callStateProperty = call.FindPropertyRelative("m_CallState"); + + if (targetProperty != null && methodNameProperty != null && callStateProperty != null && + targetProperty.propertyType == SerializedPropertyType.ObjectReference && + methodNameProperty.propertyType == SerializedPropertyType.String && + callStateProperty.propertyType == SerializedPropertyType.Enum) + { + var target = targetProperty.objectReferenceValue; + var methodName = methodNameProperty.stringValue; + var callState = (UnityEventCallState)callStateProperty.enumValueIndex; + + if (target != null && !string.IsNullOrEmpty(methodName) && callState != UnityEventCallState.Off) + { + result = true; + break; + } + } + else + { + ACTk.PrintExceptionForSupport("Can't parse Unity Event call!"); + } + } + return result; + } + + public static void RemoveReadOnlyAttribute(string path) + { + var attributes = File.GetAttributes(path); + if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) + File.SetAttributes(path, attributes & ~FileAttributes.ReadOnly); + } + + public static string[] FindLibrariesAt(string folder, bool recursive = true) + { + folder = folder.Replace('\\', '/'); + + if (!Directory.Exists(folder)) + { + return new string[0]; + } + + var allFiles = Directory.GetFiles(folder, "*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + var result = new List(); + + foreach (var file in allFiles) + { + var extension = Path.GetExtension(file); + if (string.IsNullOrEmpty(extension)) + { + continue; + } + + if (extension.Equals(".dll", StringComparison.OrdinalIgnoreCase)) + { + var path = file.Replace('\\', '/'); + result.Add(path); + } + } + + return result.ToArray(); + } + + public static void OpenReadme() + { + var defaultReadmePath = Path.Combine(GetACTkDirectory(), "Readme.pdf"); + var loadedReadme = AssetDatabase.LoadMainAssetAtPath(defaultReadmePath); + AssetDatabase.OpenAsset(loadedReadme); + } + + public static Object GetPingableObject(Object target) + { + if (!AssetDatabase.Contains(target)) + return target; + + if (!(target is Component component)) + return target; + + target = component.gameObject; + + if (PrefabUtility.IsPartOfAnyPrefab(target)) + { + var asset = PrefabUtility.GetCorrespondingObjectFromSource(target); + if (asset != null) + target = asset; + } + + return target; + } + + public static bool IsAudioManagerEnabled() + { + return !GetUpdatedAudioManagerDisableAudioProperty().boolValue; + } + +#if UNITY_2021_3_OR_NEWER + public static string GetAudioManagerEnabledPropertyPath() + { + return GetUpdatedAudioManagerDisableAudioProperty().propertyPath; + } +#endif + + private static SerializedProperty GetUpdatedAudioManagerDisableAudioProperty() + { + if (audioManager == null) + { + var asset = AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/AudioManager.asset")[0]; + audioManager = new SerializedObject(asset); + } + + audioManager.Update(); + return audioManager.FindProperty("m_DisableAudio"); + } + + #region Trversal + + public static void TraverseSerializedScriptsAssets(ProcessSerializedProperty itemCallback, string[] typesFilter) + { + var touchedCount = 0; + var scannedCont = 0; + + try + { + const string progressHeader = "ACTk: Looking through assets"; + var targets = new Dictionary(); + + EditorUtility.DisplayProgressBar(progressHeader, "Collecting data...", 0); + + AssetDatabase.SaveAssets(); + + GetScriptingObjects("t:ScriptableObject", true, ref targets); + GetScriptingObjects("t:Prefab", false, ref targets); + + var count = targets.Count; + foreach (var target in targets) + { + if (EditorUtility.DisplayCancelableProgressBar(progressHeader, + "Item " + (scannedCont + 1) + " from " + count, + scannedCont / (float)count)) + { + Debug.Log(ACTk.LogPrefix + "operation canceled by user."); + break; + } + + var unityObject = target.Key; + + var so = new SerializedObject(unityObject); + var modified = ProcessObject(unityObject, so, target.Value, typesFilter, itemCallback); + + if (modified) + { + touchedCount++; + so.ApplyModifiedProperties(); + } + + scannedCont++; + } + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Something went wrong while traversing objects!", e); + } + finally + { + AssetDatabase.SaveAssets(); + EditorUtility.ClearProgressBar(); + } + + Debug.Log($"{ACTk.LogPrefix}Objects modified: {touchedCount}, scanned: {scannedCont}"); + } + + public static void TraverseSerializedScriptsInScenes(ProcessSerializedProperty itemCallback, string[] typesFilter) + { + var touchedCount = 0; + var scannedCont = 0; + + try + { + const string progressHeader = "ACTk: Looking through scenes"; + + EditorUtility.DisplayProgressBar(progressHeader, "Collecting data...", 0); + + for (var i = 0; i < SceneManager.sceneCount; i++) + { + var scene = SceneManager.GetSceneAt(i); + var roots = scene.GetRootGameObjects(); + var count = roots.Length; + + for (var j = 0; j < count; j++) + { + var root = roots[j]; + if (EditorUtility.DisplayCancelableProgressBar(progressHeader, + "Item " + (j + 1) + " from " + count, + j / (float)count)) + { + Debug.Log(ACTk.LogPrefix + "operation canceled by user."); + break; + } + + var components = root.GetComponentsInChildren(true); + + foreach (var component in components) + { + if (component == null) continue; + var so = new SerializedObject(component); + var modified = ProcessObject(component, so, GetLocation(scene.path, component), typesFilter, itemCallback); + if (modified) + { + EditorSceneManager.MarkSceneDirty(component.gameObject.scene); + touchedCount++; + so.ApplyModifiedProperties(); + } + + scannedCont++; + } + } + } + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Something went wrong while traversing objects!", e); + } + finally + { + if (touchedCount > 0) + { + EditorUtility.DisplayDialog($"Objects modified: {touchedCount}", + "Please save your scenes to keep the changes made to the objects.", "Fine"); + EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo(); + } + + AssetDatabase.SaveAssets(); + EditorUtility.ClearProgressBar(); + } + + Debug.Log($"{ACTk.LogPrefix}Objects modified: {touchedCount}, scanned: {scannedCont}"); + } + + private static bool GetScriptingObjects(string filter, bool loadAll, ref Dictionary results) + { + var anythingFound = false; + var assets = AssetDatabase.FindAssets(filter); + var count = assets.Length; + for (var i = 0; i < count; i++) + { + var guid = assets[i]; + var path = AssetDatabase.GUIDToAssetPath(guid); + if (!path.StartsWith("assets", StringComparison.OrdinalIgnoreCase)) continue; + + if (loadAll) + { + var objects = AssetDatabase.LoadAllAssetsAtPath(path); + foreach (var unityObject in objects) + { + if (unityObject == null) continue; + if (unityObject.name == "Deprecated EditorExtensionImpl") continue; + results.Add(unityObject, $"Path: {path}\n" + + $"Object: {unityObject.name} (InstanceID {unityObject.GetInstanceID()})"); + anythingFound = true; + } + } + else + { + var root = AssetDatabase.LoadMainAssetAtPath(path) as GameObject; + if (root == null) continue; + var components = root.GetComponentsInChildren(true); + foreach (var component in components) + { + if (component == null) continue; + results.Add(component, GetLocation(path, component)); + anythingFound = true; + } + } + } + + return anythingFound; + } + + private static bool ProcessObject(Object target, SerializedObject so, string location, string[] typesFilter, + ProcessSerializedProperty callback) + { + var modified = false; + + var sp = so.GetIterator(); + if (sp == null) + return false; + + while (sp.NextVisible(true)) + { + if (sp.propertyType != SerializedPropertyType.Generic) + continue; + var type = sp.type; + if (Array.IndexOf(typesFilter, type) == -1) + continue; + if (sp.isArray) + continue; + + modified |= callback(target, sp, location, type); + } + + return modified; + } + + #endregion + + private static string GetLocation(string path, Component component) + { + return $"Path: {path}\n" + + $"Transform: {GetFullTransformPath(component.transform)}\n" + + $"Component: {GetComponentName(component)} (InstanceID {component.GetInstanceID()})"; + + string GetComponentName(Component target) + { + var result = target.GetType().Name; + + if ((target.hideFlags & HideFlags.HideInInspector) != 0) + result += " (HideInInspector)"; + + return result; + } + + string GetFullTransformPath(Transform transform, Transform stopAt = null) + { + var transformPath = transform.name; + while (transform.parent != null) + { + transform = transform.parent; + if (transform == stopAt) break; + transformPath = transform.name + "/" + transformPath; + } + return transformPath; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs.meta new file mode 100644 index 0000000..654dcc0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/EditorTools.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 8ea824ce9fb98314d8b42d371d177b05 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs new file mode 100644 index 0000000..2e0b009 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs @@ -0,0 +1,442 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using Common; + using UnityEditor; + using UnityEngine; + + internal static class GUITools + { + private static GUIStyle iconButtonStyle; + public static GUIStyle IconButtonStyle + { + get + { + Init(); + return iconButtonStyle; + } + } + + private static GUIStyle lineStyle; + public static GUIStyle LineStyle + { + get + { + Init(); + return lineStyle; + } + } + + private static GUIStyle richFoldoutStyle; + public static GUIStyle RichFoldoutStyle + { + get + { + Init(); + return richFoldoutStyle; + } + } + + private static GUIStyle richMiniLabel; + public static GUIStyle RichMiniLabel + { + get + { + Init(); + return richMiniLabel; + } + } + + private static GUIStyle richLabel; + public static GUIStyle RichLabel + { + get + { + Init(); + return richLabel; + } + } + + private static GUIStyle boldLabel; + public static GUIStyle BoldLabel + { + get + { + Init(); + return boldLabel; + } + } + + private static GUIStyle largeBoldLabel; + internal static GUIStyle LargeBoldLabel + { + get + { + Init(); + return largeBoldLabel; + } + } + + private static GUIStyle centeredLabel; + internal static GUIStyle CenteredLabel + { + get + { + Init(); + return centeredLabel; + } + } + + private static GUIStyle panelWithBackground; + internal static GUIStyle PanelWithBackground + { + get + { + Init(); + return panelWithBackground; + } + } + + private static GUIStyle compactButton; + internal static GUIStyle CompactButton + { + get + { + Init(); + return compactButton; + } + } + + private static GUIStyle compactImageButton; + internal static GUIStyle CompactImageButton + { + get + { + Init(); + return compactImageButton; + } + } + + private static GUIStyle toolbarSearchTextField; + internal static GUIStyle ToolbarSearchTextField + { + get + { + Init(); + return toolbarSearchTextField; + } + } + + private static GUIStyle toolbarSearchTextFieldPopup; + internal static GUIStyle ToolbarSearchTextFieldPopup + { + get + { + Init(); + return toolbarSearchTextFieldPopup; + } + } + + private static GUIStyle toolbarSearchCancelButton; + internal static GUIStyle ToolbarSearchCancelButton + { + get + { + Init(); + return toolbarSearchCancelButton; + } + } + + private static GUIStyle toolbarSearchCancelButtonEmpty; + internal static GUIStyle ToolbarSearchCancelButtonEmpty + { + get + { + Init(); + return toolbarSearchCancelButtonEmpty; + } + } + + private static GUIStyle toolbar; + internal static GUIStyle Toolbar + { + get + { + Init(); + return toolbar; + } + } + + private static GUIStyle toolbarLabel; + internal static GUIStyle ToolbarLabel + { + get + { + Init(); + return toolbarLabel; + } + } + + private static bool inited; + + private static void Init() + { + if (inited) + { + return; + } + + richMiniLabel = new GUIStyle(EditorStyles.miniLabel) + { + wordWrap = true, + richText = true + }; + + richLabel = new GUIStyle(EditorStyles.label) + { + wordWrap = true, + richText = true + }; + + boldLabel = new GUIStyle(richLabel) + { + fontStyle = FontStyle.Bold + }; + + largeBoldLabel = new GUIStyle(EditorStyles.largeLabel) + { + wordWrap = true, fontStyle = FontStyle.Bold, richText = true + }; + + compactButton = new GUIStyle(GUI.skin.button) + { + overflow = richLabel.overflow, + padding = new RectOffset(5, 5, 1, 4), + margin = new RectOffset(2, 2, 3, 2), + richText = true + }; + + compactImageButton = new GUIStyle(compactButton) + { + fixedWidth = 24, + fixedHeight = 24, +#if UNITY_2020_1_OR_NEWER + padding = new RectOffset(3, 3, 3, 4), + margin = new RectOffset(0, 0, 3, 2), +#else + padding = new RectOffset(3, 3, 1, 4), + margin = new RectOffset(2, 2, 3, 2), +#endif + }; + + iconButtonStyle = new GUIStyle(compactButton) + { + padding = new RectOffset(0, 0, EditorGUIUtility.isProSkin ? -5 : -4, -2), + overflow = EditorGUIUtility.isProSkin ? new RectOffset(1, 1, 1, 1) : new RectOffset(0, 0, 2, 1), + fixedHeight = 18, + fixedWidth = 22 + }; + + centeredLabel = new GUIStyle(richLabel) + { + alignment = TextAnchor.MiddleCenter + }; + + panelWithBackground = new GUIStyle(GUI.skin.box) + { + padding = new RectOffset() + }; + + lineStyle = new GUIStyle(GUI.skin.box); + lineStyle.border.top = lineStyle.border.bottom = 1; + lineStyle.margin.top = lineStyle.margin.bottom = 1; + lineStyle.padding.top = lineStyle.padding.bottom = 1; + + richFoldoutStyle = new GUIStyle(EditorStyles.foldout); + richFoldoutStyle.active = richFoldoutStyle.focused = richFoldoutStyle.normal; + richFoldoutStyle.onActive = richFoldoutStyle.onFocused = richFoldoutStyle.onNormal; + richFoldoutStyle.richText = true; + + toolbar = new GUIStyle(EditorStyles.toolbar); + toolbar.margin.top++; + + toolbarLabel = new GUIStyle(EditorStyles.miniLabel) + { + richText = true + }; + toolbarLabel.padding.top--; + + toolbarSearchTextField = GetBuiltinStyle("ToolbarSeachTextField") ?? + GetBuiltinStyle("ToolbarSearchTextField"); + + toolbarSearchTextFieldPopup = GetBuiltinStyle("ToolbarSeachTextFieldPopup") ?? + GetBuiltinStyle("ToolbarSearchTextFieldPopup"); + + toolbarSearchCancelButton = GetBuiltinStyle("ToolbarSeachCancelButton") ?? + GetBuiltinStyle("ToolbarSearchCancelButton"); + + toolbarSearchCancelButtonEmpty = GetBuiltinStyle("ToolbarSeachCancelButtonEmpty") ?? + GetBuiltinStyle("ToolbarSearchCancelButtonEmpty"); + + inited = true; + } + + + internal static void Separator() + { + GUILayout.Box(GUIContent.none, LineStyle, GUILayout.ExpandWidth(true), GUILayout.Height(1f)); + } + + public static bool IconButton(Texture icon, params GUILayoutOption[] options) + { + return IconButton(icon, null, options); + } + + public static bool IconButton(Texture icon, string hint, params GUILayoutOption[] options) + { + return ImageButton(null, hint, icon, IconButtonStyle, options); + } + + public static bool ImageButton(string label, Texture image, params GUILayoutOption[] options) + { + return ImageButton(label, null, image, options); + } + + public static bool ImageButton(string label, string hint, Texture image, params GUILayoutOption[] options) + { + return ImageButton(label, hint, image, CompactImageButton, options); + } + + public static bool ImageButton(string label, string hint, Texture image, GUIStyle style, params GUILayoutOption[] options) + { + var content = new GUIContent(); + + if (!string.IsNullOrEmpty(label)) + { + content.text = label; + } + + if (!string.IsNullOrEmpty(hint)) + { + content.tooltip = hint; + } + + content.image = image; + if (!string.IsNullOrEmpty(label)) + { + content.text = " " + label; + } + + return GUILayout.Button(content, style, options); + } + + internal static bool Foldout(bool foldout, string caption) + { + return Foldout(foldout, new GUIContent(caption)); + } + + internal static bool Foldout(bool foldout, GUIContent caption) + { + return EditorGUI.Foldout(EditorGUILayout.GetControlRect(), foldout, caption, true, RichFoldoutStyle); + } + + internal static string SearchToolbar(string searchPattern) + { + var searchFieldRect = EditorGUILayout.GetControlRect(false, ToolbarSearchTextField.lineHeight, ToolbarSearchTextField); + var searchFieldTextRect = searchFieldRect; + searchFieldTextRect.width -= 14f; + + searchPattern = EditorGUI.TextField(searchFieldTextRect, searchPattern, ToolbarSearchTextField); + + GUILayout.Space(10); + + var searchFieldButtonRect = searchFieldRect; + searchFieldButtonRect.x += searchFieldRect.width - 14f; + searchFieldButtonRect.width = 14f; + + var buttonStyle = string.IsNullOrEmpty(searchPattern) ? ToolbarSearchCancelButtonEmpty : ToolbarSearchCancelButton; + if (GUI.Button(searchFieldButtonRect, GUIContent.none, buttonStyle) && !string.IsNullOrEmpty(searchPattern)) + { + searchPattern = string.Empty; + GUIUtility.keyboardControl = 0; + } + + return searchPattern; + } + + internal static void DrawHeader(string text) + { + using (Horizontal(PanelWithBackground, GUILayout.Height(20), GUILayout.ExpandHeight(false))) + { + EditorGUILayout.LabelField(text, LargeBoldLabel); + } + GUILayout.Space(3); + } + + internal static bool DrawFoldHeader(string text, bool fold) + { + bool result; + text = "" + text + ""; + using (Horizontal(PanelWithBackground, GUILayout.Height(20), GUILayout.ExpandHeight(false))) + { + result = EditorGUILayout.Foldout(fold, new GUIContent(text), true, RichFoldoutStyle); + } + GUILayout.Space(3); + + return result; + } + + private static GUIStyle GetBuiltinStyle(string name) + { + var style = GUI.skin.FindStyle(name) ?? + EditorGUIUtility.GetBuiltinSkin(EditorSkin.Inspector).FindStyle(name); + + if (style == null) + { + style = GUIStyle.none; + Debug.LogError(ACTk.LogPrefix + "Can't find builtin style " + name); + } + + return style; + } + + // ------------------------------------------------------------------- + // tooling for "using" keyword + // ------------------------------------------------------------------- + + internal static GUILayout.HorizontalScope Horizontal() + { + return Horizontal(GUIStyle.none); + } + + internal static GUILayout.HorizontalScope Horizontal(GUIStyle style) + { + return Horizontal(style, null); + } + + internal static GUILayout.HorizontalScope Horizontal(params GUILayoutOption[] options) + { + return Horizontal(GUIStyle.none, options); + } + + internal static GUILayout.HorizontalScope Horizontal(GUIStyle style, params GUILayoutOption[] options) + { + return new GUILayout.HorizontalScope(style, options); + } + + internal static GUILayout.VerticalScope Vertical(params GUILayoutOption[] options) + { + return Vertical(GUIStyle.none, options); + } + + internal static GUILayout.VerticalScope Vertical(GUIStyle style, params GUILayoutOption[] options) + { + return new GUILayout.VerticalScope(style, options); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs.meta new file mode 100644 index 0000000..d115107 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/GUITools.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 91b4cedaccda1604fa6d0f05bc76b0f1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs new file mode 100644 index 0000000..3553333 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs @@ -0,0 +1,92 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Reflection; + using Common; + using UnityEditor; + using UnityEngine; +#if UNITY_2021_2_OR_NEWER + using UnityEditor.Build; +#endif + + internal static class ReflectionTools + { + private static readonly Type ScriptingImplementationType = typeof(ScriptingImplementation); +#if UNITY_2021_2_OR_NEWER + private delegate object GetScriptingImplementations(NamedBuildTarget target); + private static readonly Type NamedBuildTargetType = typeof(NamedBuildTarget); +#else + private delegate object GetScriptingImplementations(BuildTargetGroup target); + private static readonly Type BuildTargetGroupType = typeof(BuildTargetGroup); +#endif + private static readonly Type ModuleManagerType = ScriptingImplementationType.Assembly.GetType("UnityEditor.Modules.ModuleManager", false); + private static readonly Type ScriptingImplementationsType = ScriptingImplementationType.Assembly.GetType("UnityEditor.Modules.IScriptingImplementations", false); + + private static GetScriptingImplementations getScriptingImplementationsDelegate; + private static MethodInfo scriptingImplementationsTypeEnabledMethodInfo; + + public static bool IsScriptingImplementationSupported(ScriptingImplementation implementation, BuildTargetGroup target) + { + if (ModuleManagerType == null) + { + ACTk.PrintExceptionForSupport("Couldn't find UnityEditor.Modules.ModuleManager type!"); + return false; + } + + if (ScriptingImplementationsType == null) + { + ACTk.PrintExceptionForSupport("Couldn't find UnityEditor.Modules.IScriptingImplementations type!"); + return false; + } + + if (getScriptingImplementationsDelegate == null) + { +#if UNITY_2021_2_OR_NEWER + var mi = ModuleManagerType.GetMethod("GetScriptingImplementations", BindingFlags.Static | BindingFlags.NonPublic, Type.DefaultBinder, new []{NamedBuildTargetType}, null); +#else + var mi = ModuleManagerType.GetMethod("GetScriptingImplementations", BindingFlags.Static | BindingFlags.NonPublic, Type.DefaultBinder, new []{BuildTargetGroupType}, null); +#endif + if (mi == null) + { + ACTk.PrintExceptionForSupport("Couldn't find GetScriptingImplementations method!"); + return false; + } + getScriptingImplementationsDelegate = (GetScriptingImplementations)Delegate.CreateDelegate(typeof(GetScriptingImplementations), mi); + } + +#if UNITY_2021_2_OR_NEWER + var namedTarget = NamedBuildTarget.FromBuildTargetGroup(target); + var result = getScriptingImplementationsDelegate.Invoke(namedTarget); +#else + var result = getScriptingImplementationsDelegate.Invoke(target); +#endif + if (result == null) // happens for default platform support module + { +#if UNITY_2021_2_OR_NEWER + return PlayerSettings.GetDefaultScriptingBackend(namedTarget) == implementation; +#else + return PlayerSettings.GetDefaultScriptingBackend(target) == implementation; +#endif + } + + if (scriptingImplementationsTypeEnabledMethodInfo == null) + { + scriptingImplementationsTypeEnabledMethodInfo = ScriptingImplementationsType.GetMethod("Enabled", BindingFlags.Public | BindingFlags.Instance); + if (scriptingImplementationsTypeEnabledMethodInfo == null) + { + ACTk.PrintExceptionForSupport("Couldn't find IScriptingImplementations.Enabled() method!"); + return false; + } + } + + var enabledImplementations = (ScriptingImplementation[])scriptingImplementationsTypeEnabledMethodInfo.Invoke(result, null); + return Array.IndexOf(enabledImplementations, implementation) != -1; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs.meta new file mode 100644 index 0000000..1803d2f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/ReflectionTools.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ab4b33806d114d87a9398e9929685f2d +timeCreated: 1557616224 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs new file mode 100644 index 0000000..35ee460 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs @@ -0,0 +1,77 @@ +// +// douduck08: https://github.com/douduck08 +// https://gist.github.com/douduck08/6d3e323b538a741466de00c30aa4b61f#file-serializedpropertyextensions-cs +// +// Use Reflection to get instance of Unity's SerializedProperty in Custom Editor. +// Modified codes from 'Unity Answers', in order to apply on nested List or Array. +// +// Original author: HiddenMonk & Johannes Deml +// Ref: http://answers.unity3d.com/questions/627090/convert-serializedproperty-to-custom-class.html +// + +namespace CodeStage.AntiCheat.EditorCode +{ + using System; + using System.Collections; + using System.Linq; + using System.Reflection; + using System.Text.RegularExpressions; + using UnityEditor; + + internal static class SerializedPropertyExtensions + { + public static SerializedProperty GetProperty(this SerializedObject serializedObject, string propertyName) + { + return serializedObject.FindProperty($"<{propertyName}>k__BackingField"); + } + + public static T GetValue(this SerializedProperty property) where T : class + { + var obj = (object)property.serializedObject.targetObject; + var path = property.propertyPath.Replace(".Array.data", ""); + var fieldStructure = path.Split('.'); + var rgx = new Regex(@"\[\d+\]"); + foreach (var fieldPart in fieldStructure) + { + if (fieldPart.Contains("[")) + { + var index = System.Convert.ToInt32(new string(fieldPart.Where(char.IsDigit) + .ToArray())); + obj = GetFieldValueWithIndex(rgx.Replace(fieldPart, ""), obj, index); + } + else + { + obj = GetFieldValue(fieldPart, obj); + } + } + + return (T)obj; + } + + private static object GetFieldValue(string fieldName, object obj, + BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | + BindingFlags.NonPublic) + { + var field = obj.GetType().GetField(fieldName, bindings); + return field != null ? field.GetValue(obj) : default; + } + + private static object GetFieldValueWithIndex(string fieldName, object obj, int index, + BindingFlags bindings = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | + BindingFlags.NonPublic) + { + var field = obj.GetType().GetField(fieldName, bindings); + if (field != null) + { + var list = field.GetValue(obj); + if (list.GetType().IsArray) + return ((Array)list).GetValue(index); + + if (list is IEnumerable) + return ((IList)list)[index]; + } + + return default; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs.meta new file mode 100644 index 0000000..66f4994 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/SerializedPropertyExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d8a254c37bd4bb6b7e47a556d284f24 +timeCreated: 1667670637 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs new file mode 100644 index 0000000..640fcac --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs @@ -0,0 +1,42 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.EditorCode +{ + using System.IO; + using EditorCommon.Tools; + using UnityEngine; + + internal static class Icons + { + public static Texture API => CSTextureLoader.GetIconTexture("API.png"); + public static Texture Forum => CSTextureLoader.GetIconTexture("Forum.png"); + public static Texture Discord => CSTextureLoader.GetIconTexture("Discord.png"); + public static Texture Manual => CSTextureLoader.GetIconTexture("Manual.png"); + public static Texture Home => CSTextureLoader.GetIconTexture("Home.png"); + public static Texture Support => CSTextureLoader.GetIconTexture("Support.png"); + + static Icons() + { + SetupPath(); + } + + public static void SetupPath() + { + CSTextureLoader.ExternalTexturesFolder = Path.Combine(EditorTools.GetACTkDirectory(), "Editor"); + } + } + + internal static class Images + { + public static Texture Logo => CSTextureLoader.GetTexture("Logo.png"); + + static Images() + { + Icons.SetupPath(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs.meta new file mode 100644 index 0000000..dc7ef60 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Tools/TextureTools.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0b7ab4c6b69945fa980b355a1f1b9dee +timeCreated: 1557660491 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip.meta new file mode 100644 index 0000000..2a86cdf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 688c2be7bb7259b4382618cce8a240c6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll new file mode 100644 index 0000000000000000000000000000000000000000..7e3cf7ebb8fe2f163115c3bd80c5074d80115246 GIT binary patch literal 196608 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≻m{;LKY@GqDTkOs{mmd+^lit0V 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png.meta new file mode 100644 index 0000000..aeac67c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 40fd6ffeeb9882e4e936544cf3ad2a7f +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png new file mode 100644 index 0000000000000000000000000000000000000000..1ff41f2d4141ce66ba48cf2d9ee4878e805f99c1 GIT binary patch literal 598 zcmV-c0;&CpP)9HIxOh@DumI~J9;}EuCc5b~DZD^0f zz!wa~VOF7xefW$4oW`Sk@`ehP&cHiN9>ZH)jMu3vJv+u^a4q!>7h&f(=%kEIMTD2e zQJhyQ3EQz@90^;oK2Nx-4kfrdPuNul!mY@%_`4ldfW2V=eN`}*u?2hZF@c$eatUjy zBNd z?o%S?f-Fj+C>CN##ad?pZhJvPSewW>CksO^iU!=qI?N2R3kgy6gwe0SU9_ZxQ^NEr zqG`vyxVDtXHsX48j^^K##-t42Yp9`G486Gq%#SS56GclI{)+;Ck7tR!mJG)eo5R=~ zw)dh2q9N=L!8}P|E|zdCPSl5`xy_9sngduClfZJ!jS(WlhiKR@@jL`JP?1Mqj^OI( zb>57pHwZ>Yi?-Z+G89j>m{LJDg7Y{UqSDyW@r#WPMqhjtrEmv_|KR(*iE?Vf$?(>G kd`rzV6NB&s;lD@t6LLRRX+m)x9{>OV07*qoM6N<$g6|y*J^%m! literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png.meta new file mode 100644 index 0000000..809030e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png.meta @@ -0,0 +1,132 @@ +fileFormatVersion: 2 +guid: c19afd3f1792e84469c891524f2bebbd +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png new file mode 100644 index 0000000000000000000000000000000000000000..40e79652c57cfe4981dedb58a1216dcf89e9fb51 GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GGLLkg|>2BR0px|;( z7sn8b(@QTK@-YSqG(60|KF?`efJFm$htp%G=oK8{512&!93S&(wK_dz^K*E_Vs+Nb z?8v)Y-^=rj-p@a|r!sI_YVMf{E1orY8%{{*n_Bh7P=_sP%a!Na<`;W3gWfo?FuQCt zh+4>Wu<5*HOrieC`_no7Bp%*e()|5tq1{8RD%XROv-cFuvOga$E5rR2BR0px|mx z7sn8b(?>7q@*Q#zXnVN4<-vu9_q}5Ibkl4ne@mEo_ z=A_DI6`xdb;=(x2iyGQj};?woXEz*4t*Z=z@ tT>Wx$tF52DZpqQ?hU^*hK0eg7VQ^S1Bmbo2TQJbs44$rjF6*2UngC(IVC(<@ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png.meta new file mode 100644 index 0000000..8c7c977 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 92ca6df7507706a4cb3e1b65f76feb32 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png new file mode 100644 index 0000000000000000000000000000000000000000..c25455656c679ec6705295bb184abb476a7dc550 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GGLLkg|>2BR0px|jw z7sn8b({C?t^kWJXV7;(;wy%juQixSfuI`Er8=4{{lDD>eh!^?SbnO%46cv$Mww~h<0_?151dObbp7T@_EElf$n@NYW^K>1_Y&_z+?P2$P36}MbW#c`x%?tk@;F}xK z7HYA+Q_jz@)9_!?)Lcaa7kPG9J5R&o$trW(FZUI6hu?X?_}#*d*>awNzuB5%-CtXD bynisKcPM=e5D~Zo^cI7stDnm{r-UW|+GT8d literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png.meta new file mode 100644 index 0000000..10ad257 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 9aae83a07b8e94f44ba4ce6a8e06395d +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png new file mode 100644 index 0000000000000000000000000000000000000000..149cedbbf0df03e59e679e0b4114c7951fc315f0 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GGLLkg|>2BR0px`-A z7sn8b(?>5Y^kWVbV7;(efA*CG&Q*(=u3Q!T$LOOi#w_}m*`OtV#Y=k=jerN=l%q@z znsr=l5n)X`vMjUlY}dUfs>bi1K0CL&eA6P0EsmFjIAcS8u2pN3^U~`T0 zQwC!n1HPj?dw+aSC|2BR0px{nV z7sn8b(|a%4W;q24us-njJ#bE~dO}I$f#w{iGf655?_Y26oURl)%OtYlXm(7~%9u8# zMQ26XD#P^zZ43_<=Ms#OP^Py9`|VYJ6p-hYLD_r!!5H}@UV zPt#mi%yKl7a$`!ZajOgw>myiOUI{nM_JKO|5 z{*z}Fyd3Rcapuc=Z&9CjWllAZt&Xa0%L_I*w4>nT_nVfC`_g4X+RUn713kgu>FVdQ I&MBb@0I2U}!2kdN literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png.meta new file mode 100644 index 0000000..b4fa8dd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 23b913f6e7520ff479f45d45f7cd88ee +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png new file mode 100644 index 0000000000000000000000000000000000000000..adf4549d0237c26dac7b7ec14a5856b476f373a0 GIT binary patch literal 583 zcmV-N0=WH&P)Ej(z+MJi`y7!%1W`jH+q#ovf_?|-pV*n*q5jZc$z)k&LJ_7^f) VTyY9ed{h7c002ovPDHLkV1mI41yBG0 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png.meta new file mode 100644 index 0000000..ff7a11e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png.meta @@ -0,0 +1,132 @@ +fileFormatVersion: 2 +guid: 8957daa28fe154b429a7301f247cc79c +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png new file mode 100644 index 0000000000000000000000000000000000000000..d23a3cd5d073a09c1d91403c5f753a98d381a657 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GGLLkg|>2BR0px`o3 z7sn8b(@QVg^DzbrG<>}O&$2aVVF81wDuJkK!iRuMnPNc<{p&(%;xD78Kb%%K_+O22WQ%mvv4FO#tohUt0hG literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png.meta new file mode 100644 index 0000000..fbb3128 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 7b4e1479a7e9dff41aa6ca712956a416 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png new file mode 100644 index 0000000000000000000000000000000000000000..3e0cf930a1f4cfd078062470d01093ef8a6bb3d6 GIT binary patch literal 268 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9GGLLkg|>2BR0px{1F z7sn8b(`P3s@*N5gaEX_0axP}fYmoJIGT>-pII3vD+Q+@%K*Iq6p)V160jzY3GzLSvd*2d2<>fGu}3|E=gb8_?EALfvxo- z>kN-77v7xmM&S$nD!ZAKJ-<(Cd@EPLR%Kd#x?$lG9tGY2BR0px`M_ z7sn8b({C>udN&mcuzi@Xudl+ZwQ}~_b-aFN7NWe0ey(5kO8w%py3XEFE+kV_-nlG? zOIGU2G-0WG;;l{7?xacnvKp~;QY_)KZ9j`vz$~!VjKIO2BR0px_x# z7sn8b(?>6__iIWNIsWl{^)a`NLcA>Li!F}ZCQMww%6q3#?73;g4)*jzOM3r>nOLt@ zPAKJ@{dC9P*hxG@h*D;4%XT z`RA4!9gM%{oxQy(R3_x=A>%xw{a)L}WH}T3O;~(?9 eM|rR3Uo_WvDtE)!Wr`BeUkskEelF{r5}E*&$90AP literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png.meta new file mode 100644 index 0000000..83f82e4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 031d945f217d56e4c95e17d5ff7ba66d +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 9 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 2 + aniso: 1 + mipBias: -100 + wrapU: 1 + wrapV: 1 + wrapW: -1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 1 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 0 + alphaUsage: 1 + alphaIsTransparency: 1 + spriteTessellationDetail: -1 + textureType: 2 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - serializedVersion: 2 + buildTarget: DefaultTexturePlatform + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Standalone + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Android + maxTextureSize: 32 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - serializedVersion: 2 + buildTarget: WebGL + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + vertices: [] + indices: + edges: [] + weights: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..90a016be23e06dce8fb55f2a006199e899df10e1 GIT binary patch literal 1459 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�!5PKQR|zSd~Qg=}I-R=_gak1a1?@hbDrs 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

b+ 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

FlpcM|rt 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 z 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 RqHr>{&qc!7IPs{yPWC?U8)cJ)(r0_kmV8I&$q? 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
fu59i+)1I6{9jsq`h?bY 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%0A{igl9gj5p55^1vO-p6Qj@saWz|`AG9tGq zfBCU(l*;7cd54C+Np~|IDf^H+i0=z>cm@L#pmKxxDPgdYncKd5Dv@Gt)@pj(3oKhG(yxFP7sY3@6|CM-uUE%T-gCV(EP7xGKFTJ#L?Yn=) zsm}l^kd#afzwf^{slk7i+45uQE&uB$YB^h>7XzrJx*aa0oEn&E`*wBurG~?9*K)W! z*W0;w8Kp3~EoNXN|L_1VpA_3&klya!{WWpz0XSbwb7~Br|KKD=e3$+MK>u#T(#grm z_rY;KI^F}NB=%p#6XfsdgIE-MN{p9E(xr+LDy&rH=NTP_pvkGjEV5u}UYK$yjS5q^ z)aWpknj9uaDXA@#r(WwKUtL#X5tpu3YcFVDtJ8i@`!8f%L(7+8WC)VteO8wvA_Ivkr-0fFXlL zujf@1-i#}FA0PHpi9B4UwSkk$w3Fn4slWg~f_vaqO0&~eGjdT zaP%!|rkqXV_{%Tml}2i*Iw#mYAM9pW9i{IA`?1`X#r<}wRc{NncXhYa{$w!|>1RuS zY}e&Qz`t*Hmv5nIVM^nQ14uA<7ZYNkUm(3MUA)9si@8~)9f&0ltTIyj69HA4SNdb& z7OD-QYT?q!)I?dz@g?ac;GOz5?)Ql^WvMx{)T)T7IU~4i3mj44Z6rCpgXf(ZlGwP_0>GoWPuQVWa$wN#z*<~k^q6@&VD+`QX$|Qw z;vFiISiME1ocJdJHw)wuna9m1&gr!ZkIR@iu2muz+}^}-PL859fqkFc?Ka`_40^T4 zuE%FVE1hB$OyX61mPRe^88#%&;qx#8$bhR<5f#7|VFTFPi09S5{=OE<-&|N;QBTEy zmHV$TO{j;HnJ9C2>%d|!HO~ys<$6LPtfXV8r=|Yq6@3*PSJ5vk|9PR$R9FH20}Vrg zHTE^>qY<&+bvBjySiLU)tT47K>y66Eb1B}7P+9`ht(2*q3f!pTMKCrJLh_?L-<-}+D zaBDv?!RSpUU{U=^tD*H~vq5ncP!o~#>Q#*jZF4w}%ZzLNV8g$sR>QFS@4ctepe-Qj zpK!#T1Cv*%1ymH+;iXt-ay(Fo*{}dn7?UgA6Q(7h33eIiynV!d*#n!H%H*C9OiS3% zgpg6@x{lT`SGQBhCp@O@+}8CHa|WXJZq>});??FKx2v3P_evC z+#`;6fBlJrL)Ei3Jls*cbI0c4g|)uf8$UZxxU4f;+_`>iZ++2VXQa4u?bu#uFAPpz zCB~?H%#GcFkSfFEZj(YIS1QKwmY7_Qxk=hKKo6!h8m$ey2@$O5Fh_npaoJ_2MXPjHJqko-6EjUH<>dTFG>k5+XmQ(s)Ybxe5D{vV=T~L>b>|K`DD~ zLa;B9mn8&w7NJt#YEvV9DmjUbD8{gATBI3Jk~Dc)X7H5M=Qo_%w)UYO9}5mn(!NA9?R}%mBh>WDw3eM~Ea^E3n0w)1){(UEk;JpmceFD(kj#Xmo zlXS1c99TY4cV1PR@9vt|Z^``1BK^;crFmHVtiTU*@P;!&#vSQ- zk%@F1NFuE)a2*UL92E;H<~+B4$^DB9Ro0x+8UEJOD|+@XjhtM!JUm?LDh)dHGCtB# zQL!rDjSh(4c0c#jp~{A)qTXE{HQTm~tXkxsSD)8?&&rXZ+!A-^;uXsW0wo=lu26xy z103`N%J&04o=*h<{+FRu4sI;T#qBVBAmqv+IzzT6x%l-6iX$j7aXTRRjf!V6F`LcA z_Yn%SkLO(mmN+qCGgAtk3b!atyi?D+bTn>()2MI>5ZQaLN?}p>ye{@}Rz?$W;vLd* z?&SOA7Ak@{0WDV~X=w+BU5Eh8sVNP)awxg?PuAh$Kg(}S#+X4YX!ZU{unx&Z*BG-?`$t=^*f4lY&zMz1;s77 z_M%)HAmDFuR&Tv)+nQiiUD3kb3xaF5-o14=IHNk;x2t_*nJ>rQw|aCe01*karh?m;E)MV4=jjmV85=3$U)mf+_O+oXO}P$~U~vtxkIvz`5^SL<O&K--Yz3Nkj$dcw+>w6o@a?Emlbf9Iy zJu4fFP2`T5hmJn_;EukizpiW9P^A0y@4tGu-(T0gY`Cg?ZCA9oYyDmK-aS%Kxuz>T zZ|9eueHzmEvw%yVrTJ;Nv@Irg!ysq2E;_@qo}NqF0GHmV_{XYRLMf?Q;und_9uuX| zrz9{iv8*zYO=VQ=BU+^yP|zd$Hc68>^wtE_YX{Vm0qVK2>ST;{@$t!ZlQSm29g}H@ zc5DW&A+eWcV%{;hC!cNV4sFTcO;cMW>Xa8 za!{?ep2_VB8OCw!OpNQ1f{y{MF3N@r7gKs&>{Yo~&BxxG?AaG#QDhIao)bW64iy(b z@wCo`7Qu9a<>QS4rG|v_i@+%OE-(s=Dw>9nTtKVzRvj`5ehZ9(VaCJ*``xI6af)UOKapXvMFfGX{7DARV8~C!QzTFdhp{+5Gs^m<99UUjsJ3{iIe* z3i9$;hq%S(M7D1qT~rooSzZy|wqvxfEYdz$+0|ay*f-GQ>gWkI^$qkwxnrCR;|~xm zfM*A#Nc3(u^Z?d~rU8&Bspv| z#>HV$p|crG7CA{r`eq08CW2Dg3_7Ed#+`QM`qxiBI+J37jPr=#D^Pt7$)3$g+vc(Sh4O^UbDQRyezm?1+%gX|36PtK>K@(`Q95q=%GNqu& zIuk*vtp=S*K@$!;J|?{W0%|jy)aP2Ced&#Lb9OhvRkCm2d<<_ji@YO++%-6FzjJ-pAj<3 zXL-NgkQ2HUj!4HyYjtmxL*a_F3(c|q3jU#@+PvD3L(4=e^6El%EsLM`FB`g}qr_F! zT@korXnAXiZ$?*TOV) z?V<0z&KLf|MHqs*TJna!L9yv9RKO*HCvkv*L>VW-A z0QfWbpF0(Dt_^O;*#J-!=@=jx+-b5YXv}UK# zY?m<#P9|eXCr`^b1w*oGqXNUU*f6%38lXBb7GN7%H$kif*mm_;6V{0>0=jKAwh`No z?ZMknpO4I6BlHMWJ9gIY%p2WWxYe_KRn97|xlP%I#pY0RwBa&inXq%~s#BeunZu0efQueq0~naRwQ7Zj_D@7z5y*gLbh zcxLb5$nHDY!0;Wu09JCb1WtdINRc0-+KZ8!|KRWr{U^BtrCGhb_Qe92rNs70n}`?( zPOU{FL1}A{w!E}WUT3q8v$xsTS##!bZdU!t=aHAfWo6+<;Liuq(r9T8+)GqOz~6Jx z($Xl=1%D@O@C31Ms_ew`;j&012QMuvE5-jWyqH)5e?NewAAx)1QScK6M~R|GHK5-h0){GPCm`N{JRldseb;W+a>o>)%b+4(~$usGZ_>Xb^>nCq-N zG{1XOqf7bbXOBGAGI#df^DH`*Tul(f;`&B!ZFgkJzMj0sB46tar{9^Qx8^!|1#iun zHBcF?IkWMOiaAX%bCNf4m@K7tU=5;;@M1V@t12w49>=f6jJ5`f!j#H}nVo^SzNrd} z7b=^v`skGi=p!6D4Mj_|7p_F0p@6zaJF`o5{nD4u%$j4iqxZ=toX-f$IFcM z1=AGBugj1a&WE9{QiAw^P`3cQNC_=q*GQ<*I!ogMD9bD2f>;`0 z1@%k1_PF)#!F8#3Jod?ZC@s3vt@qF5WHP53!Qcxq_yx3^c#GudcYz`C5juXExI}8` z--6?77}U8xAl@Vw(^s%C)`Q|C6c!r1 zlLcH6d+kM)<9R_Wb-tj0%y~fo zJ%GHcz3BD)UKpBE+{0sp*Pm}CA7VT_KHvi5d`;png*dL!(n^CWag}&qr88-Xmz@?b z<8<;r)obKVI~+f~4e0eG{U5+0!O+`$2hjIXNM9L_j=xL1h5rg26X^IgaJ?HHQ|R~& z;u5h19nyF*$i3m&p_aBlO+!r}F!zqy z!WQ1l(O=+f7M;eRsfqZCgLxHgRnfj!4h8Hx&S+y>Z3p^ zM@!&j;3>2E6>y1!7f%ZaKB4+(ifw{o^dd8Fz{OAcgo7(6vbyvfK1Pxn7w`8F19%JT zE+{hUi1)N|f|1LJH?>ANsZ>n-A7YbAVer6qz6+@Q9%`oswey#tox`bi#?(4sIfBMw zIIibdio_&ZxhV#&7q3}Fw{cPeIT@%BJ$ohJ1A?xka&rPaQT4doU8Xmy zXky(5T%e%TU?wLMzXwLW0=MDkJUWt=F^T8!ZiQ0kf#V#Y>6i*2)i+@W#K>|lVe<)B ztbFt0T@7UIKrKaWS~ai|Q*Kgi%CYc{Topgq*08wco(~tbZ~v&JwX#u&7c?oYam?SW z?@S8(dI^Z|eJ;Tuvr)LxrX&g%nna+BEb3yI$623@vNK__zzxADu`FoROsbt zQHI*#ObDEo6wTC|c;QCo} z>lf)X=>G3boz>H=xcLlhv%=}yh*|YH%gCTPhzLB--wuK1DKe1%)Q@r z;J}lIKIb~3!agVLSU)zlZ*+9U`t_dsy!%$vKif+#s;U}Xv~>TD!*Rj=MDv54yE_)Q z_14e*#)sYQPkl7EHQG2F4>VchbR!Z~Q!oL4Q2-n;)`-3?;sY+~f|-usj0=R$r3)8e ze%J^)K;S9bzvBt;n2hIie*?x>o%_^B0(@3rI4%U5Xn-W}JS6p|FoYf$ibPV5=C_g# z{U$&P+$=|Xwws59)a%ezd-Jrzk63jxS7s(chhU=#n8i{8+er0{MKciCP*&M{OZ8+h zFW*UJ)^tV zhT}2!X!Ekpu8x{aY$hRjsk-_?R5vXW(dehYZ4>}4SxKPgdeD6mtbL5}KP`?v9yc(y zxpW<;Q66=pGuINDSpY+-Puak?f`yxqUCcC{x}sNcpOBy;^%xV-NBgj&h0X&I8V&+eOO zpQyOd=Js`un4$J2Ic+m^(WlitI-hUJ$c)(HDjUmgf~nScPys`V88B=V)FnRI-f+TqKcwB&wczAzY$aqLj>>~j_hVBOp z--H-mL`stD>q8lQ|LJjYYckw-2(ABNVR3bJ@ni5H(1|~xumBJzeOpO8>+Y8<0 z&^qZv@t6@BKb2bHKSpd(Wz*@A+rrsxD3{S2$~j;mxf6$}#Q>=lSTlB?4TrsQ ztinhsDk{f`IZ5}D zhPsD`yEl{xv&)5z5L}+IvA$LPE2AS3EMj08ufm8iYdZ$pI^s1=MR9B6ZiJYvBST!g zC#r8Iky?bJPs#%&4$U$YqX@#x4un_J-KOw=P$XSb#Y+GM6vRu`x7(Q_vjZ3|5c1 zpr*j7MD!z{Pl>oE6YJjP);r z#jr^G4cIMzKa!e(ymkoHxDh`#O(b}Tjw*x>F^)|%9UC{r#Pwjf5frj<;K;_owABB{ zlm35|*#9`XN*bgGP_YBMLyTAb64nXW+S%VJ+7C>1+f~@#+6tX zO2w)Ez7_G93@n+Mcspxp>YOP-c=;Bj=S$jf+lF>esnE!O7GnkIfSeIu!UB zpmJdHc^yzWN##Qpi^3BU>xN=>b?4o^g#aKVrD9nVZ_z7hjy4vzR#5+z&1NYXycau) zy(Y=vvF^L>>MpzYp4sL1?1M7c``OR-?HKOg9^IS9aGU=&*pXzo!zhXS!M$T5-|d2o z7tIjEHy~U#{}~52|4kU|Naw(VsB*1vP``I9$&0%XGe$FIap-@VA+Jla{=X`kAvi`5 zI7k|RgG+%U;8c7)g|mOGu)ZOd$c7{muNU5;?6!i@?I`vYgsG}EYgYEoC@gFZ%?tG| zY^krWoHuV_QRS-9mDoxED2S)l!pNNYZIPBh<6zv{G|I(SB?Y)>`M|+O_8_+eZcEVj zaXs>PlRib-Qk7W;0f?GLA#zqt331UdLN(qDG-<`i%0^4_&TD#*GHEUlp^; zTPj$J~Oowxtc;lqzU@W6fB?<;$({Lv-t?d#iww(WPWTfV$c5bo^gi$0zv zG>&wvZ|@%3)Yje7)VN0y9*-a5;`^u3)`&dU>FgxQUzbRpK7lIAkeu{~)a*$~lE)80 z6zrc)my6H3O#$+0LGmfIzExMZ^5K=HSX~KAkg1tc{3-m)08Kd-tH+Q;6DLbUQ_2$f zE15R3Rp`f)c?Vy*9s59<5QT9BG7*Os@?;~9VwIVQn{M>_IrQvN5qVS}kSU$mh#2Ln zscCkos<5n~b2c_x5+WsSfyO!@K03L0L#Ft+ZhB1mJa2@zSnHsW=!EcS$PyB_CLi!= zKC;}76iEDy$}h0OR5zcB%dftv)4(iC)P)=IFmo92@R%f>fgIknX*(3rE6aA2Z*S{u zUl<)r%JFkJU^O_(GDxnH+TColMKkI@JB4Fw~An3aWr4O;%z- zwMaz09g5ykCgh6B%8F@eDS5^e1zeDp$kt-@cE6>duF$E};tx%wNMi_;)s{|X#4U)x z^lLELG3a^D8!9nZ_Eg#lf+oqK#MbHgkW+}%GXpbjiUPY9fb$8QU&36rScC77Q(%kXH%rDk|acAS)&+Mw7tF$N_4n-YSp~Zt0N8@{& zw#8R8HqErmk3Vs@l3Cn5uXA>X`@_<9G(TK_A&Qt*qUnV+3p`UqX3Y)z_a2Q4dz)5l ziwmgo#q;Ars`^s*hXQy2niob-2t}sojo$_tvuC3|g+)&v3K2lvSrLO4z!aSfr_gYJ zSUGKiz3xf}qOg$IkmA(K|HB48dHyyqk!0%B2=MkTd-(NR^5DW8m|M&W7qhtJPK83} zmT?Zf)5&2v*V9g5*{k_+;^0~JW_oj0M79!rHAGMZE<#J%-v}#mx$9}+<8DRJKpyyk zV9+alT~2;MV96*+lZ3_%j2P0E_{|{a&Mh;V@cU_%-eI&j^&GL`*`JY|-mIk5x)aZ< z)qH?>1#|*Ia4Nt#u><1lgAf18Ia0$g8VsfF;qBU>hIAaydnLddvZ zOjQxWk^$@_+c4?IB?W-?qtq&7YEM%?J5m$v+dBIVhn+dV1dU(0OL(ZbW=Uu;uga(4 z>*}`@?I@U;Z=h@I*Z4IZ<#UE+dmS#~OD?`=(BuE9BUG07PJYpUSPCj2y(ND&Ob_VY zos5+BrSk@>+$OW0P{G%>onSU+uWUhY3m4w0tS1Cm>P5zOLSQyex4I?$m81pIFkk?9 zmC;#a&j~N^E_OeY!+)vmuHKRdT@~|+7LWGyjCBU63nSj%}YGxw7|EN{O_=OY@@hF!J6v;|5(%#z^uo8 zzGBsLRpZ11XHBPyw_Nv%(0wpkBE@Y$FX*!#7r;$bs^n@me*9#-{EBrdW45#=qrzu?DST*4q0USFHSR_PzwXt?F8LpFz^mXxUC2 zIe0iR8Jxs%l%d2VA(5xVP8{3V&J5JDEZZWQkmT5ANEBmI19`!1X`2hTz3IKBErkXO zq`+%$F$9tp0;Me-=;dpn7r32xO-ox+2+sZY-sed25Sq4M-@AREwPJaXYp?b1^{;&t z9m#gb(lyBHQ%P%c|TKo3W$4P-W{HQYPf#3&C;;}lKC31a%43-yEvyf-<9KXD#{$POf2%9 z;_~-L>1X`J_3uB$>W>r@nsWj_HRj`Crba zcmK|Nz!cYwC)y`3SFr#8e9H$IWer4j;;%cg5n%w|N%MwxCp2v2FdLe5?G!@>p+p`^wvfSM1#zYFmEzj(O|L z^A~T}xvQ;s{uO1eMK#-Zwb8RyySo`tR>D6;K)vbn*z*dq6i4BGCX=<`z8uQ#@!ZgI zxqjq&Y^K8df*71ra9?nW;pq%czq%{^f>ytzNFTpNh4UBeyJpu)QJp)#P`=$bfA*aN zHw@1xS>kH`(5A&TOI?P7wO5xfT{-riEju?`e6%RP{n~;{XPCy$T;i@qlxp`Uli8$^ z|MfazH0C%=cBA9V^a}4G%Xl~F4URu}eg*#)MB^;SmxEJ`TD&~{bx{-Ehrtmm<}+( zTduX3-X@&|hP#d##-E-1?Q}{T82U9*%*TDz;5rsGj6W<>e;Q_f>YL5;_!pbAzkQ_D zi?i16j#phjEE}$(iGQ}dTb6EVisqnJQaW3bepeUSydV;pQ9e`n7R|zAmu0K=o4R%h z&(S0WAGG_a$x@Q!*}$Q=F3mR?$=tanmo#tbtgJ=UnIe#SuFE7@XVAnoiPGBlcCUDP z`7HkZ5cD7OaM49hPUQnV4`kdiu76i|>LY{FuytN(*<7*ozbuz7a?cglh@zvwRXAT< zAjq;MD}Uz9e1|M75v;P=IeSKaq0L|se>>CWa0!1JGvqlOv&F}=XIdp&!TT?Ym$NS- zP#l)`za_4tpEi^ou3W+%U*jV5Ur5Aq@l;x*1}^eckNXTGx)`@HId&m2wL+dui*iS% zn6ob+$1}z9nY38-$ET+f+ics<(qfNKlHXrQ9G}Q?XUIQsapq4UcVw?g$@i(`6i$#* zCU@lAky`?}AuTi18OPHybM6J?o|*ULRpk8_msy|4kUw#8MW&RO@~_urwqbT`qFl1z zg7Uk9Po|~t#iHM;1&|+dnRDA@DY@p-hv(fq|I~sXExdBk;>of&G+D|z$~u-jQT}!J z9QSXyEO)KQqq6eG4~2BO%&*I;A}04ulDAjAU2*pEFRsple1poGS!r2oS^L#Yx#F@5 z$k{8-u6ttr4lbTWX{p@DrD{Ew>Wb=jCQHpvH>}*ac?$XCR8n_C{rZ%=vMF={`P1gR z8wwh}x}~L2X*}K3)AVw4d-ItqFTe79%k3?{YQ3XvY1BJ-YgZLtwP2DQyy^{IuCBWJ zGfX~z^)X$p*)~a@`rG8gU-TZk1f}R_K1591!o0|{~}osTpBzY z{9^FIkSUZEniVRBEC?+Pt%9r%ZDevX^g`$d;gawoNZ+(f%d||(wEX`rkpt0JuX`f) z?}?nmHzrDNWpCx)=84j`qF?Hl2FkC$8}f0JAXIlKRCvMqTk zdFsIS1J4W+$PI%hZr;e`*v-d=@*q7!&)%|qTBc=Mre#{DWm=|XTBc=Mre#{DWm=|X zTBc=M{+tj(mWU;UetH5A(aG+-lGt~9I#`XCMPieGpp_-ETz*h1%cMX)sg(`HCI3t- z8`1u*RyL8nhCHpTkVS^Ow6d9~rq5_)i+D7(mX&NXeM2kT$RcHiR<=8g$~vv=Ae%5o z;J1khN?wgt7Kmw9gH{%a(e;2=6KXwZrMge`iZj80`VpJzXO+|YTYuiHVVG~6sz~+S+u4~wQ zKO5mEA*@MJ?qtuZW|2NtW$kgcrvcca?_Syu+Mj?G0nCg8g=*$afO!%~`QgP+2s5~a z+#fGnL)G>=0F6|u7vrd|0o3|XO0a#1!@mxcgUqHF!-D!7z;m~T6xW(yKJhif%p)JO zG|X0svwf;(yV8Xg8jrmU!8p_F*Y+a7eBxNdSyaTK)vLuT-La_FuCEe;o*=^~s#zIE zONgz?b;cP|X$$CzQRWNhhK?<_J;uH?>P%79*4ap>clcna2l9ylj1+wto2(8EW+; zKl%RX`@c<#96jzXP?<1Egj%y*80K9BC|PPPWm zLIVtGj!Yu8+xlodXZWu$DWx7Qa^aYWdpFvQ2<_$gS&O zcIdl2amNzc3?4tRNiAI|AIdH&6YvwGlVO_BPA1MzzHV7+orxas4BN+W@-aS5g;}5G zX@D^;$T-EBKN)*Eho3s77{72_1W&D<+wj+7o5>G;@~hg}onSlX8+V3I^dNm=PPA)H zMhs9-xG(%lLeG`4)Ky6*JD0;Ok9aTWDUUtxxTxa!Afi2UuXwqa@rCE7PIkrxwA{k= z(2+rw{VyD&Jd205ok?rg84}32;^<-dE}-E|v$~z-OTXrWe)XZFJU*(+*v@!axs&ME zUK8`&L?)C@$P0d!r~BB|Mu6=;-BmBzC_>#Bq4zD-bbfe3?p&y`H=QlgR|>i{f63`| zk*9%LFhNIyu0t(MMf0_28Lu8P`Eb$t zNct6zK6>ixRyHBK>DW)49b~T<0u%h!?Mh#RrCF0ciS#`zBl;^h`U*|2`!gaW%3hlV zS-kaRoUq*L4rYsAJE?k8dzqO__#Q6Rc0A5l5=_~k^Ll(NT|BCpCp`Bu^Q0Lc(`h97 z7>=R8av$~6pqIV!s_*J6Y(>R4YxUKAr<2qXK z+=%*4mg6=MmDOo&GsZVU7oA&6cCa;Sp{jSr+8$ zHDVTj4N9kM3=zEqYX|AHWf=MepCL?et_^DC(6A6KYp$YUK-Q z1~>0jm%Eo$s9OTQSR@|lN~qP5STqvzCIXRgxmpLRqW*B(K-8}`cn2cA2{jn$4)|1GBsvhIGgPYCy+WN&f2}H0TfD(&k6Pyq`y#$Q zXx$X)39EIzopHKOTTdXa1~c_^MPh1Ipd%RYd4sC9BF03ps2Y#-#(aL2n%n1%`PJTV zr$449di?5^`Zl#8;PZ#${xxdc?^pey4u5B-zf%qJR<+X~_r(HH>K*sQ5?I3*FH_?oFL3pFqbSoUq26F35QWNcZ^$3R z$hbej6vWkNEP~yj)ooDYu)#7Y4{NFMNpw;uKN8H>CDP=`zsRjh1-edJIoQ z;Lu*`l2^qBg!o!CcziwH7!32r%2NTgT3-|XQ2)09918wr<;z!SJxh4cxGhM;yq*4# zH@1iR!?rdRq1`|}N}GKVzz`1j|A$C*U7>h&_J&8m#zIy4>&WJBw9@1x) zW5UwJKs3@F^G16HmU=r7Z*(X|277(pcvmD0;4vz_SiCnH4F(WEw69#<8R-Rb18Ofq zDM5plHd8=+*y4o0OzjNBqX=ZavC&uny*>=_5qj1i3HSj3^1?sumog?pGZtE zbkP;cCi{+f=90deG^KxSn!9-`vQ9cQGaK^TONsZFQv7m82Mo>w=Bf=van!WplYU0hEpZ6 z?`k6&=!ox8n6Hh%CkhQX6-0t#aF0)y6v}Z4({693n-gbLg5Q9^k68$8Ak$fr8pRY#%$o>?zwDknUa2f>11ufK2>#9hBi?Er;z(nA{TT;uIFg{0;YmH9 z(U?by))nue=R${n9CN)Hj>hQn@dSb?fGtX$KpzAEs+Cps4fSn1 z%hV0^ZH-jt1}Lpmn=4z|>Z`XlRJN$iTU(l&T5GX<4b(Q)H*RRbDz#f`8{2U7Hlj_f z-G++VT36Z7z?Q1q3hP^#ebr6PJ6q~E*0rg1O${}*XsoJ*WtCM8wR|Z!RozfozoksA zsoYYzv6jthf|eFGOtWr#T`gUmZLLk)Qd3*m09~zga^~Q2`}Erb({B&_ z1=vo%J@EH?d%(herr#p?$9#)`@80y=1k-O5OutPq{WihGY(D)~!T7fdbabZQE|`A1 zVEXNX|8Z{@fSdF_|MP#qkBb~6Q$0lOu6-hu;>X7B{{NtdESK7B0>+3dFLu1$PRC20 ziyfbpMaRnx7dzhRq~i@cE_Qr&HXU#5yx8%%xfm}??-2Sa2APeQ@pA=x&IZgmWHxaj zkrj}YWIo_ufQ>05yKw;bkhMsq>&PIs?+zrb&tZGMLarg-KpKAzy+1+}ah_^kA6@rTk|;_K2o;%~9< z?~cbp9Q!+Cu>@FD0E-R4;!0rQ1r}joaU-y}6<8br7M}+ej{u8jfW?bw{SRRAb71iY zVMHXr!U`;0z~WM1Q4TED1B*?-Vmq+#1B(!_=m!@2fW<*z@kwCu&%okefyG0>;wfNp z8d$spEM5Z^{|8vShnO~u$HFLOVBr831;Anvo-2UG24F!G(H>wi04zQNEIt7&{ta0C zZ(#8qVDVF6@fNUnkHiHtNeHumMLDoo3oPn@#dcuf0~Rr0u@6{`0E>SC7L2`RR9sEd zE*zZT1a}SYGB||b9^BpC-JPJp-QC?Cg1fuByW1J=`+44T-XGsu-(qd1y1VM?>Z)tc zFznv72YmV#eEV*?w$XI1sC5|0R!P+Y)cd%%oNO~}L^ZzBaChZ^sGNeLYjzPs(pZ6@ z6F{Jg`1XNyZ8Pdzu~fMreEPQzj@}80-Whu@QRAR89LxK?csh6b=h4D6)e&v6lADMb z1iEt6K+kH1uMm0_1t_|NPoJ7jHP$Drt&S};tut7dh)>_w+cr>|_a7C=2Gf+gG5Fcw zDl}l|_&U`nDz{(4z^gDp(Mh_tDXN+XRJcKCw7#J8fuLK1gx&lU9R23jr>9%lgsV~p zhMwxvC#^FDM)R$U_$v(pSXir1-+^!6PS-XTuoh313!X|F1kF3?SwaYE+^C#ni=eou zeV*qus7^Jo4g&}}mro#uilA?wmyRu_$|@^9>`E(^3cGJ049)zPu(2*ZwyH&ek8y;m zN1Ccfm@0O78ZG_{E`!!TU^L=BeRevs5HxB&LeMI3U|~RC@pY~gb!nn;ka1E0PL-@eR2PNJw;XxKrcY)BOs-#%U)Ted0}I28{96+&&DOd(mc znl4LnJ&%S(3e?|3*$Qp^Cg@S1VU=IPP`b8Xy0#O$w$mo5IRe_Jxwptn18qtbC|Bv~ zp@T^?8HhE>3Bh0n^0@+Jk7jyer#(Lje8p7tm|Lf)ly_zqStp>Bzjh5uNkJd0ca1|!)MqZ-faJ%2u~%< z&v>^mdy5DUpPrAVFBCzZEQug;mywdawZ&X^ARJXlplQrZE!Ia$F}zGQvDKZO?FE36 zx5DigK!y;y-s}#V;$U?gI};HR4nkA?1*bNF)ki~tZatl9;p+iPd88ClP;d6flvT&7 zuA<@`PF@fd%t9d@#v+f$SWz*5crlHNJ1FUUj-KBhiAYo=8CqD8N-$6F5Q)krep`5v zFGE;RP-^OtK`uW7HuZ6kh;Wm16x0cPRGat;{CSIkU0!-UH4MSu{?=lC*|4KFVx0JT z=|YsCa4J)&apjp7VPRo*{D4-==n3kW*h?`BbfJK4dk0boTs#vNSm6Etr8_2DdC z3Hyi?w96XJDK%YYhT*Di(>RD++`SgKBu$XRw8|8NZc_L0$$h7Sf=Dw1FDwSctf|1U z-XU+|hZuSyA~=*>#Y{ zgzv(p=u0+zl5M{*T8<{ST3f9(w;-d_qp_kQ;}esmgF(vHF(8nR!7!#qpi4-L4ZRP8 z8O7=-%_k_#5v~W1r=ZP-?pMu~&QGVfuBC}{mmp;1lSrNDU~ltrbR@8(GS(y&iCHkv zRUmE>x55mN%QF}wsPGHS&~&rmS2@6FHW|=0v^BfBgb4YpJI`C7j5?vQ=iZpKt5sUb z1#=7Fw}j@0j1py#vR;0f*DW=nQ<%GDZa1Nz01-2AEy_&h*q^lvQAHk07#{BCcPg7q zdFt9ET&s#cg5rZLbnshDHbdS{gA)v+!-0qD z$2p&-z_aWzajV(Z5dy6jr3{HB3)87NlXP-5BkZMVXFz0GE0a6|dsmVCn-@n*Pq{^* z#)Kd2b%g=E&Anq*;G z_DC1jX169#ak|pcK||S)z-a1115d*}5Nv3p2u*(hV_KMdrCf|hp;Gh+?Ycx^sZhDH zVay=TIg5UsbiEtS2noF)i+8)V>-lzIISV| zDU;-pg*iF0Q@&Y@NjCgdbpByF{K$8Cy5A)U3b9ryh)Qawtk|vjy9_6zrFDLpdDMyf zDJn5To1#hHmkN8Dp#>Dw5lwt}{FEbi_^Aa>QjUUklrku~*Cr4&EGbOJgOIG^C~lU< zf-O|KZBe?JSH~n*qcS2^9is><{s;@<6ZA{TL9N7CDn=)EC5maJ9Hv^0o%yKQ*+&?% zD0#bJF5E3eyJhmRfy!^Lrh!yQK}~tSlv92p|Kuf!Pbo~N-st-pe#J2fwj$M4PfCSe zzCpU=!td%HxEzo4)a}yoMTMlR?1M6=?i3-)lY%(Qf;b3M{w1P#+9a`M7R%x#_Vq0# zv=IhWqQ2-c7wS-fHzkx!0{em_SYp-kc++FGv7EV{Irtum45gxMd_BjI`7(ajUmQuq zc45K>kn6EU6;6s!?J1tmjAwrRy@M9=lVK8+vIG^K;@l#Y z%e8Sg4J_##ndRa^c1Ui1@7YA~4mtkk3~7zWar5j_2UVm$Dz{c_;jMFJ^K)g$DV6xe zs?`oyZzQyX6mJu2=N%?yqGVT@k-HQDt#yT~MlDBSj%{sD)J?z-*ND=*T8}k~8MVHO z7gm}guN0ADAwbJpR#PE-WvSUFyirP1*Wgg!kU1LvN3tQ7+SiSk|bJ898 zevb%jo;aEB|Jo>eI-fEeLKD5_pGM5SSjq@UBLt9ua_Qf4s3+*yE1@c)mbcS10YnK3 z{R;(xGdS#q9f$kSA-|>6V!Nm;ibN0o{ga!t6@~Rt6B5>}&JPm;#zn-B5QBr&wSSWf z&?BjUvt>@+q|uJy9GQ0qRlTVrz0@fsKJv@U!pqNhmk(k~j7yf{;1I-^6} zVrQNW|2Wg6XDGHQsD8wXji|WY5qn|<{x*uHb+K29pmO@R5$Dtb+UW&i25-5{tN<#? zm{WHeT4aCJqlSibOECkI+)1?>GTV_sCvEPu!ULHYT5E3aqfE*XIf{Ktt}RcK-~A)-6OHS<LXrDH)GU-itWC=zjW+-+MP+_-%J;(O z0~P@UrzT6&TF=A3W!di{O8bSbKV|q#tWT!ufSH3>!(&W$e8HHoEpiGM)LL(6nwFSq z+RTIwlUO_lR;`oVGDWb|o1yO#`6OHLaGh8Tzb^QwH&E>e(E#v*`GDv&wqb_h+ry`M zZJKI3)LH9xKJ^ph=2T%1AaiS@scjh(?$rw>9S0yaE|{oV{KaBw5=Y(5EkCDTGsL2W z_)v?>vp)P~s`rp8xQM57`<~~huxif~H^kgga}v1NTiJHwQLpFjx^-|c-`=$SU>}9h z($E66hjPw;)RFrQlz&tc1SM+2TmF#5ec#yH0FuCYMSgypo8+9=sGv>}upg?fp19Xi zYbrEUZ}HIY4!U(NNZK}f_EtWT3DHh5z2FV&trD+R3WCK0Uiy zW8v$LUx^-A3MTs;osu%IR^L!>>!>JXc^89rJ{&KhM62Fxx5WLBznbeu$z!%hAZdpP z^F0|F7LphqMiu-F-S!vKAP-x`<5kOo_vIL9l`(X}+b%0HKx&Amgg!NA!Nbntq_=mgwZmcP!K+c*bB}B7Dkg9% zmDlU^?`sPIe(}rD$=RCB;6;Cr5QlxL+oW6Mm}{H?(I^aWvc&1f8@kIhtp zt=3GQ%lDjjc>=^WBUQV{t4M8L`}aX#*9WfyqXhys5p>uGOZbn?Grpuo z;J*!Tt^NJ5LNHeYed;EO4u+Vm=w9<%uFu-7TfY%}TqX2&QnVbT;8^Q2D!3G%+8um1 z)@Zpt9ihd^NoeH0IP<*N>O;(Uoa|LS2XJPotZ%QMR`9i4nVfZ-oz+TqsMz#CZRWUx z);Sj6%ho(j&jO}34N^mjXaQ|oA-=|cIRL!=VyhvvVrmMU?|p??SHg?$p{QoKvy`yifIwMmy(t7pbD+B7gwNXNR6TCrl`2LsyJyeeJ0~t98Fo`=*p8IOFW%plK?(@zxPcEt_hG8oDEW`?$|-%xdR*L%9>`7*o)VC zOtI1}!8SI~f*>VVrRnnELuQ1WK=dwrof92A`ZF1ZF>C6Y0YQ}fMQyitW$|6e+_Mk*gMaEf6JMCX0B-LSyb;7-uv6Tm>&9QEUb1ezOc zvnHMdTH$F0b)!cS0DD~I{Di=`&HRvE4(jSK z8=s$K>~tmL-8b?FV+KmF?+|rS1Vzc^u%SW+f0IS)ju;ee9OQYix_>2vRL0pm^xLB4 zAIGYRJhSNfqnCNjPTb{HHuERrJ{({acLM0N|liM9P zd$bkyEY0!ouuKUN?i83r)g^Nz%4g@B{vJ57qwoHtkvsfb3kT1k9NAyZLd{pbmg^!{ zN^5>xsNvgmNtBEja|{{10Y|W&OoxsB3;Mf9cmb&;Z>?d85Pz$_usk{NwM_CqL=b2gId92 zu!I`RdvM|WUhW(!OLP}QQownbLY%84chojigKz#a-#!p>U*c-iPegC|lMTOlcd3kAjiHRy z&8^)55Cqobh%(03A3RN9-+V9$Lw|&Zfy%Krks!ZF$?8--ZR|~Y4?N(Ona@2Ix#e^j zVz9pn?(DWkI(SOA*A(hIaB84RfC+)A8Lof9nd9EF&o#h~AQkTWd(C3+bAUFuC!n+Q z6Zjntl7q$adr4xwNZg6p{4u!*S$29?vgm#@Rywx@Y@zPMon<`l_WKRmTYTuGx_V#* z8?N?cyAo?z_+jS0eBjOc?@1p0AAmse+r6J2+?!sGXSjdr@wn5}ZhU!IUF?w>gcXbr zjck;^^NQd(sEzrCCT?W2J04?!Jl~d=R}oXOn(0YOFK%Pave`h^;>)s!eEX$Y=H6SZ zwn1kRC*SQS_u~;*BX%TUy-Q8NEICT?%)&s)Khw?x`^;*qvA!nyefU9cH3Ss|HTZ8g z)TNEKh|7ELsU70RDC#c?X>a5&-$AbEGk$=ruYiJ1nnGC!4}cw>5Y6s7Gbj~?yUG_f z>vDmjkOmDM6kJy~Jk5W!a5Kie8`dq(G(#AwX^~|@>)N>gxadM<`I3gXN3};KIQVhX z_E_a^E%ciw?gGbe3R&P6lmf^eNf6=F$L?SEPJyG%q7Mdw{s>mX<9dKS_g<`it@FsM zaOU%gxqs>AdgAEnpiaIF0c8JLFd|+j+K!R^2Th(xFnmEGFS?D{wS{M(7~~8%GyAqQ zj~Q!=H$P+>%M(K+c;`*a^KK~7Sdx|L_Uz~#?1X^YI(hlGkbs>rGH4rHjn`{eW0-gZ zz6O4F*J@vBa_afOzsyg(O2-AcHo?44X%WrbmTD}iucSm^cBL4$%NRt|hhobd&azHy zY2bi$aXq}&>+Sd7uIY!=c-wvlH!1r#exhh#!EiiFi9Y9UaqZ1mkKkWfpEjwF>+UkW zoEVCc(UX^8q7LWS-v2l<4&6n@%}*MC6s$Oa0A5ELnV$NfUokCO3{+QD7^(B30*_zf z%nBOO{meG@Fx!kbA+}My`K^-vH0{t_3a#B zan^DyzQh|r7@zPJKfu685DL_}fX_D5NF9VH!fxalJ4(2-YMfJwboXcvawvZXRBT}NF6~Vw^?BSi;Rz}=ZELK)QQjXd4_mFY zQjok7K{TzW=M94@m`YiNBKD5_EoC4;KsI2EcCS!{bCy51Q(=3#q^kjlg_^Y$<#?*dW@#{R&qufkAUY?L!3jh2asq}0p%7qCxz0cC+ra#8 z5Hv>PD=ggQn7T)VSFQCa>ih7^)|quDWDQVll3C|~H-`L(0V%oK6vx3DNeURr-66@N zjwwF^k58AI=$?h{GnO5AJ*$8uSG8?cGB96FbL8Y>&oEVyBA!*csu8T>_G#J{8g90t zhJ00p+CUTq%h(}i&KGp^WF2-yCpoj>&Xg;x$8TgcwWm2FpM$dges*mb%h%@4bBrHt)Yc@St zDHsW+_ON1~ibu#ayuM0bXj*D$A~GEY>rqkcOOS_>Ke@W1W;6vBcM=+LU4?#H7v1<8 z*`Aei-(|N{D3jZGRfY`WC2@tdO2sV>OCPDGrHRqQenZ|)>%zzg`A|BUlA~KmMIzHSH2)MQx0ID~k^*>i zVrSZ)K}Ux@N^ zGPbs{Ud17!o)5D)90LzSW4n4$OY?Gb3NrS`f)s(q>UIt~Mp>}X@9%_WzXi`%R-Z@! z#$OIWI7KX^uQHcbwQ)CaejJ=?a^s+;!(_#Nap>71?7sTqKtcF%azv=3Hq}X8d#~i$ z^TuS%W-jBs5~gKCZq2qiy9Gk%g9#fGft3eQ1I2MZp<1_^S?j_uFh{U({cLz&{aeh1;aQn7vfjfDEtn0X-u*niJP29sesb(`zRE+&F0kywr?wc}2PIT`oQ_2#(Z)TPHB@&Wt5?VGy{DY$Y!_hjKKf7- z4k1uK>Ln%@TkE7bTvPOAoK@wQZkzMroeU2*lA`atdEDL8_eX=|FzFTP%Uul+R}c&o zcy%Q`W9ON=xZ+8fFlyQWIf#aP(orUciQp!*AdJRFByz9P;O$z+&}aG7O_ZZ@p|yQwV!&)Z>q! z^xPFjTRJp}f} zc<^8uL9)M)tBBE{`<|Y`PoEjDZZu;&L4mEs3hALcuQLG8tc`f~)9J5H1>avm@3B$| z-@RhWR080WnZN{GXBSdY3x21EBSiKDV*K*i10<(xq34?nnu8>4XLF_&cz_7LF~jrh zna>wSWmXZRv^7-QHD`CGzD`r;B~|A3`rM{NRj-}YqOiGGPS7Pk7$$3x<~UlEabSr{ zrCGLQbY)Ct;ws}&m`>6p<&Z_lDA(ne5h-{xk>UtjGG{r_=+s*&zM7N^UzfW}_&Pa<**0a7$h^hw2K^ zwxY@z@w&mkUBskSvd>wa{;@CPe;MF4T?Ysbc%#LrdSoKZSs+7!9zpTyi_T8{ZpPhq ze-x$MwQi4sf|t;5{UDWh*3f)Ly-P` z`EoBfc^v$r;fYi!?3GMj>Vj)8JglP|+M%GV>U7e7Ho&8h&Q)1;H1TZrKTP&X%Ow6AW(2|Mu z(+cnj&BX92F#&b|m4H_4te;41tUwD^7NErbITz!n3miZcmVay+8Gyzt?4O;C44>F6 zpNNc%KqFQF8zDQ#CoCh=C+n^_CN{=@L|_eaz-N;ksPvx^b^uVH?bCZE z4xq@)@aYIMGf@0jftlt15jlYCVE&wj82|)iV*U&ZGvFT&|1kr6F7#goHel@7I2iwn z!v2o~pTS_}0FL|zo8!}WMixR~=~mzf%jW`_**`&97(YekPf!--e`4{u3>KEp0J8uH z+5QPU3+w01%*?>9&!Dig09VD#^tnKG*3ZnbetHUwEKmfn|0eFXbAlM@6UhW|I-I_?9+`;Uq3zjFYNzl|JUksJ^z(IUx5VuFEu|&`ANtB z67iFQ|KI_&n1FKw4`4`uHb9~QW6$;v4v=7E^Z9=h`M(1A>FGabB{w&{ zu&ITEp&h-jg|364prO9Cfg!!5p_Q?N2_Z8hfR`5@=D%mPOPZnFnw38xYR3U((Ha40IF@#UAUgKYbO|*HG)FN2iYTJu+^U9~E zdnPl>zqkd&P6re!P%(}}cjlPG{Z4Dn2tsZVZ{(qb!EWcW!#oqjP+ub0@)fL9@>6^k z#K?SE-g>qeWpl_985UKQ`&tg`W;H4?0}?UWP?ond$4;AmAalitmBpxspMu;T(9HsB zkt_29W?xAxjJ#1CRBioI%mz>WYEDIgTzX7pR9w(p(A19tb~QzR`gE)FYoebjgJEix zw6WvnlV$fQlEKT#T_$7mFD0_~}$}k9q;snmetI`+}q^+^N-5 zqXXGC7{%?!7IJS_ul~fLklK1Hibo_HY%c`y-o5gqb(h2qJ}Rvm?EkN~$4}z^|49TJ z3-f=n!U&`oD+~MoPRwcAR}ICv=ZDPt2_pq05vg>M1n(E~OJcM`{FskkaJAa8X3{6z{-`nSRINwyL z%g|J|^5_`Zh_L$)5xx^@c11bzg;E+_{oY%@0%0ysd*#j6&zA{%pddI)kp$$0XMryV z32PdxDgPOxL1&Zy0s&P9FDjTYRo1{(yqL9#lq;kYqMHQheGLcoG+`jvNHiG*5BAp( z9Dt`2_*J318@>2=^dkCZ>7zNXurF<;lLkDFMVcxfr-`WNX zvuIk(Q>Cw6bWhjMWm0%eKXRH6)bOf(WbzMLmPZHT1OtKG-K9)s&TH-j;Tc&cQ>Ff0 zy~17Mom+$0>jdk-a!xC znjaE$vUlW)17{le+RfT&HDsoxDThaY^q0ZT=1Jd2q_&UTEB_uN`LpCIxRa;rdXDGO zyc^9}Vj z#!Um!OI5Yd!G(^>{BYiMek_Nu)6mBc(FqJ!&lUZ#SQ^S>Qz>UEp|I4ckB0DPEz2Qx z=p;rdT*S6(mjm2`92*HzCHwHJB;S}-8rvE?!c%ct>k6u<^_X+J_F#Qgr<8qfAg8$?;L}aCE2vWOH)`H0K!kLN|D5>G)a^&3c~@UA*dLnD z@o^aKw7bSGRjnVk;3_^P4PS^GA}UY~tj?9t8m>laNM|YsTHcQ^3(tu(y2me7eGJyX z%UROAn6j#r47+4&d!8#>GEZ4x3W&s8nP}WUKhpqk9%LgkHS@0%_QV)*F0x^LCB|s$ zgF=m6q-8@&ye0a+mssa2G=EcE(JG(RmyRq2Go$%S#n(tsGp=$_-b~(WrjR<)k*J@0 zN&h$TfP>?mp+5kZ+FD?*y}AQhbppjqa&^PU#{SX!yJf5VkCLc8Oe$H&S*zc;7j|Bq zM+f95WfPG#GIWZTjDq#8882CZH_MjDLywV+%a-M~KL#CfO@+t??^L<*#Vf5SVSDp=j$ z*YmE!OJhppN(aTkRp4#=anF!6gZQJ@d;C4ug?MJd6Y`#*Ki08n6tNkfteEi%XWIaz ztQpi^E{;mg=SE?XodInXy64L^3NjVV&%iAXNe5-)q79Drx$yyZUaZjl`=bRksTC)4 zeQ3i=-L??!KF~fKFRv84ppL+CNWPx=v>dn^1o9^W#lt5jI{mT0m!}RUKB9vjnMnz> zIZ01mwwmD@^>eblKaN?-sP88c;4hU;Kl|K$OqZ?Zc^nrH3X4)Tw0TWU=ug)C3sMQ_ z0uf*ZU#CL5L&MP8QFqXm`4qF?xTqa?{ZSc1>B8?ckXIR${(33Cqe(5!gBNb&3a{sO zoVU>Ks{YlzULskb*T~@6#S*H}w$qF?58!qlym_Rn-Fgjo=}45+8VJ+%*1vWKP2Rw@ zA~)CSv*n$~CVn&Y9<2Sc|1CoPka%2RrY6IOdF8iOAp@&rM^%m)wvDoEE)AUK-x{;w8kd#N{CP8%surwFVm8XimT_CO zS}Z(ekVV?bYsQ(^#$p$)*S+qzW1TqWxUvguUo*2`k9Fo$Ury{_is!M@jn(sh%bk^M z?3K$?4XBq7?P&FvGr4MM3caK67Tb*6Y0YXBIXsV?EU zP<&Z!F5#PgQ`o0pn2HwP!zv83t2EfX3HxJ=kru!A0%fi(#*EXBQ8OMeHU`C!q5rmu z1!Ed@HA4OYw<64!JLF9C=Hl_#!BB3WD8tJp_%zjxn6AawshGa?_8NT=UqHdr*D84N zK+(HbMjo%+IJYs@f3coI9qe_0>mFLQzaEy6yR39S18#-m30ah>%~b9&zwtE#)Y@0K zMB6wS-q-}|oKFUWB1XzfJ7)rusj|=O3Q$x-e>+kt9xv7zd((L5j{bB?Kd`A)54p#( zxpI^k<%RIa@I3oj;HHMaj+>|K&y)6%i1%D@3&E~S=e&i>2hBo)LanZ6^o~3J1xCvA z1wFp3Wfgxs{gj1EChf`&8Cqu{!Ial#xLJgvD%l;}se4fN&0H%UmUY0;OI4Xn%Wv1gooTpN$ zouu;J;=mgvu+nF4hW(Yt_g{$5m|5E855d>3ksOp{$sYJ{3KN1Cl&xF>e5tP;;QBx7 z94W#QOj^xWhfssZE)ZZF;6o}({IoY zavzag7E|3&pnc$Uvh!eX53)|ZP(3uucn#!^2WzE8d%6_dY`4)K6kdSLWnxxd^OUe! z35-2+Y{goxif0e}!Oe}{AKJ(lMNfv`;R+m)-OzTE9%sYZKLL#&kd7}1eGBwo5!Imy zy)U8lN3D@!BonlDgv2lU(Oh=G@Km8+VkR;KM&$(#%~1ZpP8_{6)RD_3dEz<(6SWDb z%NSzWnf2tNaw~4Kqxb6BJz(Wfw&_Pjaalcn*!an7-JadmVcdQ*f8lnky7r-3Fmw~| zfvBH-GidI&QkS7!#)P@qOmw$$_}FNYM~xTWJ_=SkK5{Fy>1 zPXmIbaxhOFg7GBEOETx_i6d-kQ+3Du*j~%4?rQK4nfMO@sZ~VKvUW#pK->n5$UAwJ z%)I4oZMD+E)~Re`%uI%l=QeFT#{4s9=S^q4RgQS$7V0^MFYbn|H||2=`pnUWH;ZFt zOn4`QSL@T#GZ%F8gh;xo+lI*Sd+tT=2l0F|wtM2m8DI4NrfE-P8kuEgkkdQ!neqnt z+PlH>$Cv9?7uSaB@d0GA3H|)Ljmir7K}W4~j^|eMC$FECJW`#h3FbD@p!Q1-Xe1Ll zN*&LwYUzpLY(+$fCp_4!kE*75D%5sW6qmn?H&y{sHvf6NSbUD(+Zoe71;G1V zup^4UOx61x{kRc&-qkUSvs3z)C-Fq#LlLKO3jD@P3{|cb7!yu^vKJfqNzMk&umi~O zhr&kGGs%GO>PrRl6P8M(a&x2MOW=_GusoF{ul(^%a0ZtCXkTgP0IPuwQ;cp2K|7bg`AHUgb5i zM{_$~jx;!zHAZK=Dh4*lPN+WK*Cy;*La2%`@+Y4tw%kh7f^lZ`+NnOo8s1+TCAJ>6 zT5IMujY-85RS-2N_P_=Hertha9nATuQ3*9-imNelWIkNrJ9$@!scWhrXv#}KTdij} ziKg`WGbPacn`J(JQ{NA9l+r`4>(Fn@G|w}AaRQ1gYMP~&Y{Dg&;OWNArAP^o=p=Ve zO%3X{OWJCQQ-zaGaS}suB=eyaPW)AVlwRxgOvf>^!}8slBJLG7gp z*;9m81eL}s_N=4A5V*nzy2IFcsomyyUZ(1^&afO?A93yy@!6XokBNvG%?NKubfhO} zLmi7ch4R00OBcImS$%n4p12J;X2;8AxdP@hBMOW2xh+8LN zeJlcILSg2~c+46a20z)KfiJ{kM8l_NeKqY3oMy`&SYu$3phwuvhvY+6HP*2Q#Z=PYak) zBp=9w-niGDhk36Ds!!T`P4mMaK|7#Nup9J6D}924AeI;I;}2=DezbxwV4GY`D+`@ID-8+SW>@QxR@I0z?d#9zt8uC!CsdU2X9h$k?u zQL$sgMFbmwTh04CatA4pV+9eGm-Q`jR}P)jgq$bM)CA0rq}9k1uorOR`|VZ;cOdm4 zAVRgv)4VL7C7hbz?^>Pxr9Y4(Msm0-kar3JA8bZbq0OW$i)i)g8vDISjTFc|?e)tX@q$P6TF_5=9qUkQFWpN14%>j0XW<-? zwIo|*t0V8Amix-lyvXxhZoDo^?@=C$MB8REIZapaMW0ZAc)!2%F?$ci*BWR&txAmS zk7g)x-o#*ip9u?tDU?cQ;&7IeZs0QC4j8?{+Ud8#v)?+DC7BV)%SRwch&dI<<}|p> zf`vpl^!Dlu(7NJjb&lW}aCLGpXq`tc?@}S*rQC%f12-9yl)(?dq(80#tn2A1iaJfft<}?!; zcVRn4>rG!mm_Q!E*IzPH9zli_k%W_Dmm`q~;^HQrh&~om|0S24!iM{#*a(fckE?`= zy%Ad?px$KxGBUHKszlp@h?b!1Ak&_;oVCf|svboPVC|fYWn53^T*XI;wS1alpr)7E zWRUq2pQs;1!%XX}@UW`sDqsmNH4Ibqw1scacL6E~QO|2`VX z-&i$R{jEG-$C+ffjA2B4f(7oo!@pWl{}$gjWg8W6g`kQjCvt3}NhGOfvS!ElwZDgZ zvCjXyW1{4R^Hd$BdedOU&V>_BpwL08+yMjKJ?G{$5Hqt6p^>M5XIS{gkZVn7sU|TE zIRig)%ZYIwuUw%>J$8|^rp)!1MOClmqUBOet_h>u48XKR~q5zv0LDpNd=FZ z?cVKj;D-lmjU3hH&63)9%#c={9v<#7tLYo=wyZ=?KxVLTZ7|l*XqaK99mgV(z~89l zOj7HY9K{J*N)3XTOisA?Ym}grtbJ0Nq@;Rgr=j5Og@a8iEF;OU1eveE)mL*hM^|m}GtylIJX(KA&^dxAT-TLyY3_hhj zuktnyA=qIsjcE(IVSB~7DTJ!**UWX*Dnz{>O{dNoc~RE9PA7DStn!I4T^cN`nG}NU z(IVNa-%_QYzO!<*Kk_#s0jF;b=ry2E@=`TJn%N)~I?5rX`N&3DV)@GO9!|toAz9_L zLP=H1BomS&tx5_C!A+-JWob-`qcDHtywL8vD4N6f6Oqpc&?d}^_<=iKs1Z_otTd5H zguEE&NF*3as(SM{VfI4Ws9N)w=+!I8XF+l?J_1D8gJTA45QKh%sk{A57oyBSA4fgP zBz=or%M#RlOOgBjH|2=3maC$g{KxpPaq34BNh3e<>Ub>Of*;tS+ZN~2(_zF5&6&!z_E&O`Sy z(SrcT`(OtcN_-7Y3b~gjs zOOPuqoe~Nf?2Zk|#UwdWDp?vAJn!c*XK^f@v1A)j^S2ENlY3B9X+S=DYjDJAcdLr3 zzg1uFG%4bj2%~hxxJNUZfsH4VU0JV$S3d4`K&?c>8cINU347-tmOoD)i87&;r>d~L z6i$t@5+^m!e4CVjfx(92IfvY3CCzxUHYws<-?gNsLB5oLZTWn3^OAge(umMy!}2%y z;C$ zlM89eLZGZ+Vlf`RevZ0hRJ>Q7q}c*q|InuX8IhTn;y|b&*1NlW1-Y5SJ}DPAAcJB_ zcU9<07|l>N#+J>gVQtl%a58kAJhGemahd7+Vxjq0I&IenPv8p2!i@6e?Z4VzwAnY}1tqTcogPNwOOyroA@#M|{)OtH|fVL3Y0Z(%t)EnEyRGTZrPIXWr)8&F`LtAZo6 zOff6$3n(xp(Z+FIPAZ9@Tuv&B(6E%87H$BnE;p&*V3?9f;Gon;7e`zz4^H;8TZYf| zV_Jq!_lsKQnUV>)OP`?y_}^Vn17_h_p6Dr*O4q7I>SB@F)lnG!%v#n{dLABXav#r6_+$+@# zZHf$l)XX=0Pdo(vAJeq3Ew1%3pju3%rfcECi z(Wc}hb)b%>y?JNUkvI?oz}Wz>sH{2T0(1U7#R4n^tTY0QI)P@)Q#)Fijj9d0L-(A( zYOOls&g3IlU>G31S$DK4(2ReI59kc+1f(~mHclI5&alLkrkYVsQ2nJXg7p5g*HGmLo`A(K{R9lI50!R8WN|V(>#R;xIp7Wb_V+gm~Zi3F+Rckp#*}8 zcO`DYUkQDo;{zQAId}7SZ5*+EA^RXA2C#OCU-9ul@`DrxsSE{Pu|L6mA^0JP0$&Dw zcDHV)Pdx@UcIj^^J;8erpM!dL*>7n*A$#EU!5D+F1|AHNJQ4Ze@<8jBx}E%R`5^Nk z6aw`Osa8R)2M-K+J>hM^b%YQq5VJ9_Ky?PpZ>d)y2!BmQ`eVN%dm{6JTtmME`3(Nv zwRgm-0K*%EY9Oou_XyTD$*krAPUL^a7{8uvnX6bc)7*R-9a!sD5}qrd$b~Rn(OQ!dTLKG`T|~(G3Y8>CM^|C zeqH10sHvT#Ue4#iT6OCJuTnTjq}_8ima1y>#JV}x{g!8IEa|F9MQa^imLu~{N`>?+ zBt-Lb)t9CDwxl=F`INLmH1AKeRR&M&~>aOkJHH)-|sK| zjKjfaf-MMAB)kW%uL%ABbmn@uh@N;oklPRrfh&Xj4Ol%;`jGX3>4P%6Vz*$PgqNUm zK^B9ohMb=N=W#<3HbC;has){X4DFKK5_^JdB3*;O1a}YW6~Nj;TnzF!Qfb012QKX* zHo$Ho+Jn;#*6w0DvUdF1gi#NacKodg1q9=Ri=o)n4x}<_gwX~6hN^?opqRQyGbHK2 z*M+)Wq&W_9X2O~VZ5{+D!kP!m48SXbm4z59Lcj`vWo)aK2- z!}SY^L<>#<44*Rn5;ph08dUH|cRaRje8>ELgT;FzdAWe|zJq~pzqB^{O&Nj8RFt-_ zzEr>9-bC~f9=mMo{_9-&@P74Y(nYUvVX80TxaGxE#BU(q9Sr1DVtm81gI&MHie`th zWBRvxf|wqtOdE2%VEUhK5ssr?^mB#;oF$2#(U-XshaS`y-d8T>U$++cYv)(TQ}z~^ zKAGB`tc#rp2H|On%cH@7W zt{&^Jc$Q@E&kSAJ*J23*l1Rn*YxRRCDC?p+6}aCXI{evZdY=Tuj0ELqkH5bnolt4l zBjvH_MTW6!2*p&5Ta_8K?Ko!2xh?CRtMOM9A+4z|+*_BRRy6G>HzH&@D<*EN@w9i< zt3RuiV72PfDnbAP>0g9X2^SvDSEi?aPkZH6KU+^ugu-^eRYi2H@a)RRlpba(d=PXK z2K_-=10-9=i(&2x)VQuq)GwjG{%gxY*S7g`fBxl-%329@A4t}?dO^QZvUmU2TRnK< zItbB%Q7@*eMBu5d>8IOP90LGqrA_?PpM{`21-(y7Ed zhMy~#pBosf#E}L!Gvlmh3CIeA`e^3( zXc84PP}x-&~@s_qDs!%J3y4n4RN`q3fc~>Y@c>QB+NDXBYK-i$U5xX133w* z9!eQX8xLub&tjH*kjHAW4)^VFZ*6y{G<7>5y=>ZJo^(~5NwbF447Mi-heI0&MP9OV; z3Y%WN&0-fB%a~XHAy_0f>lo+z`}yF=Tl5d}>%q^Li};)cxHA?T>=cIM_#3Cr=vm;h z643npJM-T_CuhFTo@{#aSS-6(Z*Oa3?+_2qdP~$bHsLli&%pObA;`y_smuBu!sy;> z&7nP>JRn{{p#_UFK41Su&bTIer7Vt&1wRfs8goi426C_}x%S8!&6-tYI?zxg6vi0> zGCUM&CE9UCD|`lX;Wzm$rAcv60uFixKC&UK5h*yEim|ZGg@H0DEm!Bv0BF=N6p8o9 ziqPR<`6QnY-Cox@!b0>~bu??u%r-``vLLD>%r&lV4sbNI{r7@-!qwNMI_p^r>gk#F1V9fL2I&W zKLCJo-{rh%s;eVYn-yh>~s{6KMbolPyKmZ?E+*~2M>}vC>rN=YQxdEEX ze8_8$hsE%p&XfmFAx(=+i&zUaioPBE*sA{xOolH6#&6`iyvvMp$4pZjE6)nq##%PE zBLJJqMs2ADj?(>=B298(7vr#$;>N0Ad5E@2EamgrpGLoxy4mKTxaWV|Q2du2^oqm1 z|AC)?%MXr)4)c~-La)n zI#{LBAs|~VAn6e{bh){v=DU$s-5W9DIWIAMbM7Ohc9uo4Ph+x`D%VcmLk(*8-QzKJ zzXkW6Ynkxuhf_Qe!qQ6I&Ylb=VkWh2gup4)0?&tyN(zREJ5d-RIX7f+pZYWSZcnAzE_$j=S*)6WR{<`V(xCVH%@qQ%RQKra_^GH#q zFp(Qk#vp4YPYADKp&&n!($Y4?M0TXoN>-{>r;k9x;znxO{kbSY!twchdhajeH1;xtW1WD=<#sxY%v2oK zvdxF}#0@*S!lD+)gDN@cFHWRpw7qY7m9eWn9Wsr9Iqs5pM8B>8!PYiY%b!dcl__T9Vl?SJam9g zD<9>~pQ~v&(c(bD01ck2zhKq!TQ_6}UEm&e$E57Abs8=uMEwMGAV-v!3;`b@-E=>4;v$-Es2vyGK zVeI;4{f8N0rbS4C9W7{^TpHGMYI4VAf}Bvie_>E)JW@u$Tc?xf1+{!d@ENTId$C?I zk&Hz87*jE7yR=4sV(X?|W0`vgR|-#}*(mWH>UWEfeUxKZ{dW(=0fwja4o)Z&3?B9A zumOnGv;j&kTp((0^;Tqob(Yu^Hdc#<^+5-GO*Q!Z6 z0mZ`?#E{sMx=d7=H)QSh!O%t+cB*r@z1hkUU*deF;ex0&)M_n5grSFk`9*Qg!e$ibAUyYBPpUD|BD{4ASU6#`F`lR&(llNNT~Y6>TSPo zCA*VeP@53M52Q^gDH~8OPE7vyH@ymy%p(l}NnIdW7zpvNi(q=}S6@V3I7lC6od(or zxMbY}OVl)ucdmBrQLH)I(14m&@w~AahJ0E|ymirN-{4PVS1hh}so^4Ru5u-N_G1@M z{9jU0t48?4KwNT?B^1KAA4oZK^tv$Ot4l_t1H-GsBY_6fe^8OZ+*>UiR4L3%1vXL2 z7!$wDpZ$s^2#msBd%G*%>JMv-`1Im210)TC&x~IMjt={<@9*vVgBSTAo7yjzLMM&z z8iDXXhsAr#{BjQB^}&NvDa^cV(vK<~~MPuWayp=t0l)4h&izo^Em*K!g7dverZTj+az;)j2*~DC^HJHJA3w zJ$m>hzlz+BZPN2MVs;a>>PG__Kd;89TKSzkCwd(Opb{biuT42j3-DC|I4V0^4yrn8 z*i(6VB(Hq1xMi%2v>{!xV(`uKPTYJ&GmkYySwJ~ z+Fc#u34E=5Zt}47&GI6@TxU!h6Xob~UZ(vn2&H_#xfEYuHN9{ZPl}u?(uQZ*Ti}!! zy2FF zUNHX_lbjh6jP(kP3QLY*rI3wA%JHkdL{>EQ7sRn5>ak(`C3er#HJ{_-&PX$b(_hkP zeP3}LN2l*k+vMm=xUPmfapW`%$Zzy_zFIhQ>oK#3tJQ7Nj5Q10kP;2z^2WTRB0sXy z^OqcZAIypll40mw2!O$<>=`r=bEEW8(I4zIhP$YZP#y9Yw0WhYGoe?^c~v1&)`a3@LoX@`y`TpVUG;8v>Z&O}!CitfrKB3$&vx1eflO z60*;#_;HvsH=f5X_l!( z-R?uueEA-ea$`r>`XMo`TVtU+JPj?qnA|RQ)e%e?2h|&&|~6)Ny>(B5A39SMbL92QqXLDEhzF+T9>%u5$ri85fInb6*Cw{9Q~ zNziId%Y+)b6*Atv4rBYZ?Cb3<{*J4DkA8D$BEcDh=a_ob9JOFhrb(i3%_G7At@R5OgzP zQ^_PBHiEL(-tn1x6k&a-qU!q>rYf`&+ls$GmUcLpsihd)kg)-_rO%(Y-u!lVacAHa z()F`6^7%U&Qmsvxht`zVx*W++JtUB8s>LX1|BlNlXr>s$%(x{!8I+(#!;0W1iMCY3 zNm~3?#Q|kjeID1%q8R=!CtECul3eAckf^*ON$D7@WYb4$X@X-Ko;cV64N+z%ng&-@ zEKD|~%R9ep6Q>~GMU5!$dH6?fCLz9dV{@^=SX^vHVax$H`@)^%eKOiWfPemaJtY?- z=jC;An=k=dqjQxzs|L>`MtPt#-M27PL=pW3tu4Z)g<8Hc2qO zMKt)6DcS=OW`T?20uNLi6`QOOfx3O1Ekxh92~=ImH5=xXk)XZMLhI~u-*1l2!T)G^ zHclm`>n6kC$JJ(Ue;3I>)Pm6Wr}2*G_d09Cd+i1myWOSER`<`h&%A`;{c7DcIKww0 zf4C1oS-kG=nqYMAN3-plB7HAP>l$oRJb$GiteDU&vxjVea(VQFo%2$lUQ7v&VoOdE z!Bpiq5AA@Z$1L+LMecV=!GW5SAyZ|7>T;o~SM6{^m95m+KY6xFnS<~6hAlU;r>)vj zdqZ^Y_3MEHUmK;a_XfjgqRwoOaP)6O0Y6`PV_+$q%hc6eU&#UvyMngf0Y`81`7>w! zWre}pjUB?2@rYPsH}2uwe}Moqy4S?Cu58O#wU@$c%PgVlrAq4VS#!e!?P6`aeZUGe zkNx?sHYh=ml5T%^2=ekP*=N2#lEQoG`X8f0IVg5KED*#c>v)!Vr=V%lMtN%=3}80- z3z*)Tt#caTeYmGXCpgUlVfT|mg@Wxl>W(Oa<;uR>$}H`7GD?7-O;Pl>;RRvK5)H%H zRs;7wAPnPCRZgzxScynxem;;8x>ZhG&mmQ5owTe5SGuyU!rxkcZSk|IQf2BMr~ZKH zonT3FsQ{_i|AxLt41a~K?n=aMwu4k$PbyC2VDVtFT~$3F`!CDI(4^*}rZ?4uFIk3} z;P)D(vcMgdtk5PbIWyK|s3375IGCvwA`Beguc5b3t{7^zIF)ukYRUBUy5D8*p-g3^ z&dU+PW`N($vVj;d4dSq+6eSq2azZrR4O4b10vS9VP$0P`guo; z<=i~HJQlV?;H-2H_E~s+Z?gpqSvn6E)+2MKf#&xHa0-?_phC-`2<7;Ze`hUs_sgIcD!Y)H_8V zq$y{N(k<0<71k6E_J9XL=SX#c{h9#f_#r<57Wc1Pw;!x#wm|5%RMm`@%}I@}q^Gzj z2LntcCG9=j3bgp$WiJedxv*GSnuNjuH%uB0OSM+rD%{Yl2>vM!gw?S>_s4HfaZKdg zL-TNv{}&cDL!K~E@qZUTQIw13sVD2UokuwLWULpJ7mRjWlgb|G1v+~@;lRcC+IJxaW zZ^~a(5oklq@}ywYayEU8)LcTVy1*Ye%_&YW_E`1>9K7?&*9YOu*iB_2vRBhA>+AQo zqF*}yX&q3>Pj;S=%u7Q{H2HjY1x(D{;HDgJ4t39DmHQ72=Ls`Xc*#$KY-lkO8xgMJ zP^q0l)3EdO8x$9IwExK`X|xzPB?c8wFXB_SWT$5N-kwWnSbDc~j7?nbBY0yQoKU7;(RbdQGi38WybCM!~Sj zHIbP^;fCB(rW$>O_igcq3XxoJzY)pq{W>} zMtDA$^UNd&H-AuzyO*Ic%fGs6-l0K#8arKcCMSRwpU!2o58fo*lP4*A7-v`Kn!t%-#Bm|DSZ!m{KxL$%^q_|#iWSud$|^9rpE8kzYjcm8OGhf%9v6y>H(v## z6|{rzWq;dB<#+2-ip&ekiHF*zs-br=qZ4QE-gh^}z@R_3&23RI_v?XmdH_-!a2s_*b4w3-zXN!(^_AL*%`npJRqV5MOdOJ&f zj_qs#Da+vm$)1}nssh~arS*^PpfQAgZ_j76X7JV+4u!x;9D)5yUEN`LkQsGajr)o( z@7dx}@!>a`WQ6ra@BZ1`U6U@%8T1{esLx1rbERGQYwz(^48rklv|zT>Cjy0gv?S8w zTUi3UNsrR=wCRE22qXYau1?zv_m!w5tb^o|j02MWnp8E>+sx2Yj(pAt|NXt)j`ZRV z@L3k!y69Kse!)zH64pPFJo+9tCM`TCqN(M)u2G70&}so8+&Fctq00s=y9u2|wh2SF zSMR7=R(lefvFY!R-}-}qO5beDnC}6Vdurcoj)3P_&raXZEv$x`g`F|`Amg|;61W+O zb!{kym}P*1w!AhX^uqO;!#=Iws|cC1BiZPs_2fiMcC>09_AoZbWN*b*d1-4nU6rX6 z^J2oFPFNuAZ~>qXUxBd1#k5G>tb?>-y|0*}n7D!7?LQ%CFOkY9JIm&wqzR@7m(jMF zJR;3U>y4J)TpOZ>RL0D;j-FyRhuK-^s(fpEpROi*@3g;|`imTXOXQ3!5j^M8EC}Wo z^6A~o$?6#ziRK9L*=Y2de{hx`=CtV54T$M$sRee<5EHV)%}|4~&cWNTdprr}G3&=p z%}!KlTZby#t6rygz?3@}}lu+IzXej$!}n^h#k zb|s+dQnaQDh`KvejgO}2O86=E)?Lqt>~kN2#bVi{@2GjtX@)5MSYy?0gx8GhZ)}Ka zcMOgH11eo#`CamwRA!Rhl(0i;QVAH+p~t(XEY|84i?twVtjg9-HdJ*q^xoq+gRTQvzNCA=^M z(f(^*di0B}K~*AbjW%N2q=jPk3kis|#!l-}t2Aw#Pfv#?9lSkVQ~r@yrxuWIBj*a2 zMj(rOmQ;k2TtE`)dndb7Tv~C6dHD(F&e!a*LF)bL!k`|9ggu{#sx?4^z1Iv=uKa7I zhF`v9y$EZ{au*w17AKy^sRH%;`UzXI8oJ$!f5eV(^FE5FrDxW1ADy;Wzf`H6TCJAN znjJ06i81mk{}^kJ1BGb|F1fQGVz}Z;eJzv+wbRJ?OlhU?*$OZ~t^z zgJ(KyWBI#fbrn7{2IESfJn}&ZJ$KF)?7(WZC2Tu_odxkQ3F-civPM+y>!M$XfhemV z|N4PQYM#<58$SQupCV-%9c=OWXyi8R8mu#&by^-}#2vJaGJ=AnWRqBArg0+t&*xT> zKF8+5e1mSSErDFzIEhBdN~K+;LnH)VXLQ2iGSvm_`v@rikM#-%Jt>*WlBaQ^9QQ+N zuoSWh56Y+r2bwV9TY}-8=uek@in|L|%ao2Iv=Z@Y8Yfn5MtebxKP&q@kBN~w!m6!Y z39F4M-l>{N+tyCXgw0Urbm<$*oUc|$i(1F(=wlp&SfwQJPNZI=cmx%jlN z)f0eMLu*Jd#F-w9nX^f6l;f^XA;Dlum2}7zm2yB%%QkyJmeRaag+@_KBq1XPV zC$-mL>Aj@IEq=nq61wi9@bPbWnj>9f@ip~@XIR)AzncvCo>NXd7B+(Vw-N{OA-~yF z;r0^7w#AzxRlHQE&Dz4CFp>V8)2*U2q$Z3CbnI*!_;=;IS|HH=ODqgGVbMZ=Y5}vQ43tO8xN-2WwNk2) zdbeZPY;gl-LLFoqvKO*smpk+iV(GYl4>i0aa%4)Rd=G><^LOGo2HWyX*&lNVxtlHM z90Z3ujfUY-@~Sk$O_e?adr+?6Ae~%TaQsp^vN_YeJn}od9Xwvv=7bYOtqE(rOyTsL zdV%p&Ts(blN6`JuI35`_)yuZJlBJ$L$+zx|6Q*pqvr%5oXYgHY7!e`SX)C4NI$mnJ z4o%KE@!a-Te_AKA`3sYcU7H)vP{h4;Y@)&2x6L1e{R%5~c55DAJ;s4%%e89_X-v)gAv>pX;0i1!Do+rN$enqH z%1;p4HB^0tI^Rmag+wT%+drGVh3i=EvO3CagW2trWruvO^`NKKXXR;y5h}@#&QYLu z7xR45RatP8DGn5KsXZ9`iv>U3gm^snBBG zu+be@=e3{VcRZP0FgcF74SOViF)n<+|Nc24Q~sgKWGcz_qIMgXoph2buyxf9T;sX! zD3Iw&a|IE#zb#oe6iuvD*Q`Pdr_}#}H>27xa%Qawn8NG|Zy90|2r;0U49pj{hCUIWpL4TM7Ur?(v#h96kUgJKqwWTfTG&dkVnQa z%Nq^1)PDNR{yZ(wTxIJdKAy z7*awSwWB(TR#}|GI$TN+6P5sbeo&C;c(&Hk+t51m6<2O9NB<9S#-3oUA6t{8QQ^d1 z1~9M>5<|QhvNMr3DI^W8tHXv1XR%a`bKO)I)@8kSFs-$~Eq-16WiW z{O|V8C>t7;wR49ukNbDB`jg~;;b#;vu+l!7(3K$4t|$8`F?zq<^Xg%|8XWB)mA29(UuCBw$&-T&uEGNHbHplFJ5<$u5JN4cH?Q(0!i@EusVz= zrBy|wfp}L++at+Ul6b7bR*%3;R#@%dEaj}`=q(?g55fl;@^sm(%5IH&WnR$!_br5Z zHJS4H@9J>0mCPuIO@cfL5l1MkA%cARq~Lk`;*mkARx~t*Bb~~!Df2tWI+Ft5G%GuE zM=vgrU3OqC28dlxN=DY%hb|bFiIe5if$#irKC+1FNoIb#BLjT{8=zvutXI(+D08uu zAIKhpCLN>hh$>8L5}-%Y=Lm_NXTc~19H^GRs68nYaoo!FP&PB;I}&mJ?#A?xSZac+ zF6VNddR^zNnU2|rjuR6E8&v`EE-Ig4{;IZH?=&r2jGA+{D@+))FX;#fXg>%x_{tsB zoZLjs&cGP|hGuoeG2<4!GpAYZi8Yx)3J_$h&&F{_xjU47+q;Sd8_Y=3b|Ae|f{2<) z^aUlySPH6e?lWLXR+ZHJ##;Tsdi{>D{T3-B&WRYX7a;j)K#SbcZt3VXQPgP-WW8Dp z97z<$@hVP$K+o&3D}(~khacKCgXn^gyZ6U_ka|j>nqKRxX!_V@$BE-)H}}4(OV)7* zs8iSD5pL8h=(tJ|k*+!yBjLpDifEV-oxh&&ySj}>@O%e+Ak%L%3p_!1W`JwqUgwlb z5v+o%(?v{YAcXv#=p;Ckzi=vPIp7h4drR?G#BupyP7?sNBX_$Plg!&(S>d@_J^;%b zPSS#^ej$pWP-D`FUQ+I6S*uk_Y9WV-qT;EW&Rp#*XnR~%D)qpOSf`Ss77mL# zRw>VT=!V6U&dGVlC?3)0=w!L;Pt3{j%}G|k$%nSrT|}>h%Mcg2-dwtH{!6P-U59k$ z{d6p(2Hz_A5$&u%Hf^HzxXbL#M?Lw=JIzax7~CmXcAUVvZvTN_Ihw?6I@%o2;n7pv zW!|#HT2~jH0PC{x;J5)`>ztmjemw6LuNKPG+t3GUCRFAixrdnPOaGRWFR^Z&+{dTD z?3&GjGB7*ho&+;t#?0#srHw2#karnvHtwp{mfPe)Pa!Rr!W4_|lZ+63r@(mJJ)a{;)-Hp>%A?xFs}Y-@GM*5=;pr7dNqL_W`8 zYqUI$efHjoMds+4mC}ybP92Fj=FoU>)qhwFO9sn?jBh%YZoGNcA=qGFC(k1D#LuRQG+o z*S~48{B+;&@zWgCtZ-cw8H)!IE%+Z28kGJIfr)G4d+ptjv>b~kL_&Atdcr(h!P;|? zC$U`jGod#+q2S*RV3P@j)&)J13otUQuL6-mVtUvnL7J6$#kW*3wi~#eIf_#hxU?k0fsC zfz;)`M1tc}(^5Uc9z_C|Wl+#bS@t1x!&VqzC8Zp}mj>X7h=LF%1%$F!^}b*V?3M)^ z!gTM60sVz>)?+YFK86t)3;sOT12_1{<2u+WoBin@K0C=z%~o^f+j;8e&1=4;R%fM& z^oOZU*>woisVmoQN2#S0JJKPd!LN9~1&PSMQj1dipQOK+g~a4HPpxi~Sr-z#T0g4^ zM{P^&!sfwjv)-PKnP#llMhvfxLf%ZratouSh@y&-MO0*Yi^^3xQhpgD?)z&beBxR; zO-8(Cyr9|noc3OpRd=T~3+jj^ZcSSxD0y3>&ja=44isz;Rb^--Ep8{wodah5?>A|3 zRmeHFRk^8CmM#nGqX(NxKZtax>&|}CxZrxFo9P(+o|d9Fh7pV>u#CraUM+cRn9UDy zp%E?Bau*lymIvlkY<7zqywZ-56aFZ>wwykHB{2BDXzXi0XK+#6#odnlAl7tW5wv`` zJQ`RctjZ?6+L-q>MXMJ*Es}cH1)i9UKR{QC5jX4YlbVBnupFf~b<|x>^FLZHT0eKY z)~prtmMtk?C+G(MkbPR!R^l~+eM!haPMx6F5Y}F2fE?&vCqSeNz6qcjUdFu`CL#LY z`}6!^Q*!we-VLpuwq@P~6*3+E>*jMopZ%fizyGo=)HEe#HoHuPpRmRh{PpP>&d)^t zPEtlJxPSInTJD1>FmgrRs|4ZD7dO-qqy9Dg_#Mg~7YEY$oBCr)@} zG&91qG7tdMt8J#jGo1%ibIT2kFORu0PQ=&Anu4r-v#z=VKA66EkGH($AqybhYq3ud zd|&Zi348&mr&d&}&nv@iA<9S@#>lmX>u2t4xmohh^-eo6t1oz!=@W?T$aC+CiErLW z8Lu?9Tj&%F$^g^@$5z{9b|$t5ge+lVBr+u=<35ys;e+kHhu)aF-*Bv$zaib2iZWL+ zAww}S)aVN1!Th9VaeaTuOH{JgR1xf5eHAAalMDP7;W6obJ)&M)^cdo0IrQ9v_Dk;L z4ar05UzIZ^u`eh{c`aFF@$KjJf&I^vX3@+*(nIeME7jbL=Q1^S*>R7h8bOHNxOpQ< zr_vSg&SF%pgT&x00oQr7;UpEeE0Ez&&Wy(kiOXUp@Lx;QtWhnDg;VK>v;@B|i4SX* zY*O4ONS|F%PQT);2#QA#xp0X&_g}^x4@nMXPv5`f-(yn=CDe*dClFSRzB5`Raexy{ z!`~8X+%G5U6 zvsHDEk>vfVZrULPB*sb`-KTZCZM*H|ayl}BEG@nE>*Yoak3Qdex2yY37t(BvZaPYh zhVp;u^s8nlIy(0bn~fW*GfzwL#9mLOGp5VN^5)Z(I_6prdED-MV5D<|`*mn`*$HLd zKBnt&sEoLl5UUMz+BA1jrgK%+d#vSXu7P6Sf~=ckhI#C3^DAwmHe!&r^{Pyh_BV9( zh}C@B zaI~^&vz20)nUaBV?<4I3D*$%X8=Jn+cDGojh~v)P3h-9mp&RC;AAzDx$a(QNbX5leXwo91oR3at{Dj3h0i@HKJ%|NheU$u9|}eDEJn zBTk;chY0!p*U-cF1WkRRU?I=@pM`8Z(+;E6Ed<}u9h|1xT0=7Tft--Obkb8<;7T%P za{7QFWo=-+4z&T1Kr-^sE8vg{om@a@6iy&;N%oJ;9SiIcRp*8a^xny#1^1Z1%=WRE z>a+V!<iLYg5huXUr%#0U|9J0^doX9={o5W^VqviUpSXj`e-C-%%A{n_h zPxGAxS+Wa>&a+OZ@|aO7lo2&nsf66DZS`Ly1KT~ZgIXM{wJ_()!DkG_2g8ZOMBzk% z5a#Zwn*kznDlV4~!zMXNc@9i{^w{<$94yF=K>WlKI&}Y+OzZ%{|9X=fT^R~OHha{u zt<|4uwC~sd5y5G_baw|AfD|q>K&1^5JA(~_WDi)Ba$h6)I_9v#89gt9$JRoV&Sv)k zEMFfv;kf;6Bph9tnC}x(?}O;_D*R)Lp@g0L*Qkemq6{JNAStRsRdjW9ZDzzgrmp}m zirh>Ee=5NeFuj=pIl@5_KM3v~2hCXSULlg=VY{P2##j9^VCX1ma-uzvRY7MwvwZJ!$MM*Ty#8l0vpisSMZgUFK4`{p*W#b_ z9Fw!RQ!m=FbFZ#iZH!$j@3r^i_)M{Dr?%2%kuUUjo=*p8i_k`~2BeV5qnc<&8;eKd zjY2c#b%(N0L?uQZ7d0P+kt87*)P+gC-wkgYc0!F1^zo7t{$L1tHj$(%_@chLIO2im zcxf%Y+pFzOFrAX}_VE!giNU|}n_ai5@BMClz9m8&C0#v|T1&)tM&J0=BFuLX-JJm9 zd)R&=fIbJ~lpMu{K348>RlctXYQf$%&!vijl~^XPncn4^!-l;305Y={@7nISkZn>pJsua`a?5dP2J2wBV))xOQ79i845m$SkgyZog zpMWj&a&|~$IHFC-UT`6(S{Sgn%idf}{m|NM$%!fJj>_KbENF5bO{4|?%#-I5bB{cn z;9XZ%4}T-+v8H5S%&3;rF~HV+xkA8rAzW?kG@bc-p-!l$*Yq%3h0*+VbJ=mVOrSOY z{l39*TI*Kbo%K#zyIuBuzwm8NWPP!{rGu{B(fM?J)4D9cioey<(o=Bp4BSXq;?l;f zD@|wAZ*eSaFRc1csmsclyuGxNW=w5o^%#yVqUKo8Wpb$L*DduL6Dc8ShW$jNw`TDJ zK97vh{h5nb$X$sgb8aF13bS)u1S>}G_I_}L< zhk3?S&pXmUf@Khd|FD;)I>83N`^n_NM)uvw`N0P67>@b9%fI&bQ8$;*lzJ9Gt-HPc zI=aKlJc3TZ-KOA%2@%1z_uJa{TEf?R=4FM*DvOVl)o16`S}UUK&LzdsMZet4AK1~{ zjbUai!TdY`{+U zSfNf%!9NJv4V>HSAv(Eho)=&>uzN!nB$mOv;!e* z-8iQhZ52y8kv5@xL^fRr?J*$)$<(*|V8_ zX~bc4L`SE`Vbr06d*#*3dbMPyU$E!r=@0nCzFZ?!=SW99$u3!03WRT;?Y6(K+2=5}iXWsr(=WOTRSu3vY}$oRNmoMDHiN9gkqziR$=h^@TbW zZ6bBKGXO3Kbu|<(UVL6hknb=LP@M1@h~;%m=nqgnkahS{+vQkWBeqGqANX>>PB4wd z!^xCa*w`hR9aAQWGmib2ve_IWO8*;2*}8G;6?pGiNAQWTNUM5I!WDSuJXWVy+M_4u zpZFD%cp&2D4y%tvfYk)c=b8q`In2t*;S$!ygoVhszxPOr%_LZe#Bwb*Nq+mBj-JUx zmBCuLK=XyhKJ&)}r@uKF0r_pmQ=MDp;2T&~OUEo=q4PbW;Xlk?$ZeU;*fh(M<=axdP_$Ks*-<-s;2 zP5hsu;jvmYi`mj$7w)_?6-)fu$TKZO-i~}S!aRt(dzLbR-=k1iSf95saKrs!DJUGN zC#nJo_zMaRLAhAv^+7W(+S~pTs}Kn|?+IGri+H z0(T2`O{lY~ZF;Yj_Rs4)+50}l?%%qgOPfIkJyjG8G_tf6YDR5D{+T#n3`z^3zv-VM zHDoi5qP+}pbuHyn^UfTlDZ`nGlKEg4Qgphz`E|AHRo!PTI4 zIsGYzJBLNO4}DW~Ui5S;U60#{e(k!R>H&hQDv!n!JHXBQKH8)rz}>!XEyYYF%O)&f z^48pp`VGE(1(!N8dy@%Q|J9u10V-GMZvT|vNGRfznMwQ?UHWZ5NKR>RQcTKT47KMO z-zuJvPXp^WmeXf0MjrsiVAwB%FI|S(cN^LNv*{L1^_!(ilj0L`EulbmPo?1TinF00!5Z}7bmUp!>NrQbMsSi+&Kq%%rk!*+n$1l9ivB0*n%$I1LU zn)NQd=`Hy_O-f0EN$K&|gHtVxBWHDq{dLzkV2>W@8Sc9%BB7tZ;dJ^XKK16=VKcz< z`oHq$`Z+X>zOPswIjHT_WFxZihP^TtTL>JE=~NQ#wX<52@l;A{5FA<&JpHxb9=C(~ z01+Y;M3&EjA1E9qb6=M_3?aSI4A4GrG7}W$5M3{tWiu&(_ z`SS}qMLsO804|`b}BdtsTVz-k6w%pUk6=M(0ncte|Gf zi%td;5=zYba6SKlWRJ~;o3xZa7Agx8)~IJP5|-?#(!|D>s~ z$&iTmY`h^gQsIipp4*2zhxVLWIK8hPHgR1U^RIEe%^vdN{lQz!z95#@9C)LavA)Rw zyTVhWl{>IBkhN&kWSzc6x^kjHAeBmwu?2dPa!bm$Ls0!U_^auT2rI=pVJziHG;b12 zH-36`=kSqqfucmqtn^50=pv6M{`9w3SmvDLGKJPR{74&tFdfh4c1^>3t}yH4Y`!L1 zv(i26-o9+&b|Wf-JTPVQ7eTow!^y1EKXd|kuVuUY>Z{+v<=oEizh&%~Q9kj4D8L7qUvBw{F>wI>hW<;uI_?Y1f7% zFsBI%%^y7WhWaBAtqlBT0sV;?3Q>}+lG>qavRin`jaEp*Oc+296+4niHuOfjNAbC7 zO2Uf9w6#hA+Nj_Zh6AuwDGM!N@{w_pA3B=|i+6z!=Mevw%>O@>y#-Vq&C)I$5^Uq{?iyS+F2UX1 z-66OW*tolUaDux_aCdiicLJC9J?DJqJNLieUH4zJdZxOnp01v1*?Y}QcWrL9Hfeul zq1a|tcz}qVZ3CB@wM{C7mQ6*lku`Y;N;-IZ7-6s-EY;OsnR{hxWS?EpRWmOT%kpkE z(WsZ%6byHW5rvq(oXtr&88+q_xo*qo70t`r1B8C-CO6lN6;NUhRls0J5)z=4tr|vk zpptY9<&+^6A&Dw9$q;m;eq*FD_{2;5iiHk+kq})U;D0-!{~d-bd~4^bN47o&93) z$Jsjl>wBK~9KCbJ=y0F2SI`^@KbgAJ@US)h3I=*2{OK_?!@U#@+&zoby3oE<8GZ@VZAs^!-O3*$o~+C$GTuZdll+dvf?B*y(gx9X(OB4L!JV6 z9{N#=(yB>4g%=VYD84}fbs_`JdGv6a2wNs2^3+TtC+DLg-9+LpLPc{}?BoDbe~J?(MPP$JFO(HMzH*ybIiew|@IHBa&*_e-TeqG4Se3wj;4j?Miq*_@_veMLT zPyOcy7`6Edk>RtRfk~-fJsO7v?*YRgLIZeSxS9k%Iy`iW9q<~yS7zxnnaRAOkPu} z!RygXWdx54z)>2yDW9#xhum6rLP1(RsL`n!n8_1tW;te09LET^WghVP1TcY;DK`|n z>O<@*N1*`ZYiaHLEgr_KZ&q25S??a>KRHZU7*9l6>T7>Q3LS2L7O5OmA9 z4tL|lkPD^=Hk=mDLM}7e@+jJAA}J!vq1u^lBiBv(H9JPs*a}b*=JKR4u)IWb`h8Mn zH%6q!VTSxpM#N+sCFn}x?UE%ma7j!DMxRBvD|FsQl zvaPBsrWvXPO&dr&!(%@67ciToTbZaC8*op5q$SlZCAyNwNq_%*)7m)ogw%t(O8=zh zUGYfi$XTYxu$di#ka)Wx#>k(DGuTdP=vn=HQ%Sj+FPb*C&OT}{nyOTKc+T8b9wdi) zp!>E`9^nORR>;)Ng~?;iLDKv@lCsZy@PmUygl0rE@smnfmUZ^@pW%T8oSUYgg#yONj6Hqrc1{Svn(h8U>eNU7%T(y>GfRu&+t*K4tM-6;HG z-F~T`im4x)%OpycCJ&igcxcC6zZrzU#bF6>B8NPv>FSN7>B=Oav~?(>)oUlXI$W)j zW2f>y1gUWvNA)?XnN+8$Uxxy3-ak#N+33AcZppQCPeotaN|62`Eer}*Kp3XXV&sR>2w=f0ZJ>gYObC+0WyeLTinl3R;kW}S1bdOw@-J5<;qHCwES6t#i?!#j_ zpj_wn_34#nnEQNQW={YvRd@F?esFuvw*3;mY99=WaMPkB*{lQuiN zanfij^s-%Sp>#NuUs@i1Z9Ohit9yE|Ik7+tlEj2MY;5ffjIuX6pKkID=<^Ehw}hXd zM)ruUXWs^(f!n|QxlJFHlz{#&Pg$>+u{X{cYzbH~Im2$3wx~}RWmVUQ@WwQOiUn4; zD_jOm&OcDp#dGrWeSu&rjBP5^&7vELopw;nDsT1U&XDl2hzrYL-A;{1yV)D=Ip;Q0 z;Z<*shW%B%(X_YTGXGkjYvz#DSTH(N%GGd-hC?sCmbh}#BgeztM4?Xos#!9R$pC67 z&SlWbq4yXj)!YTN(dN4-rvZ*M&nzTUEzCF_c@Ygu1gRiyBk;h-C?c1$@&G-xO_M)R zn^cM<(CeFZWzynw!%6S9f0~A|gp3}LY#+zr#VMi1rQnK4qr`AcdW&h*ecxEK-WU%% zmwfR?ua5Bd7fNrR+AD`QV|rg|t}l`gPqC8QsIIkN|K(_lKY5U_PZXw>5`LgGGc#mot_fh zeL2!jp-&iUQi)17%7}M_+gK|3#|n0Dbk-$cR7$uz2OeJ>4VQGi;i+^cQP^^2~vAUyHN#OokFH9oMm;AqsVWOuSd%pfGxn5 z0Eh1nmtIZGI1IFuM4A}=!XvU-NR$&@!@SW&7SIbW-%YMPN<~McOGVq%f$ci|)}cR@ z*gTk2@}c{hgj2lQnHqB|Njm$ArvtB}0x`Zhe&0VoJX@Mg(>WYzI9U3Xx;}4`m=tr& z55D6MQ9$owH~Hpf0!O_)lflRF+pSFd=&s?KZyu(?;+dooLIEq_wU z5*Rftv46zDyD!a?7Zbr4piA@0o6N1=!*U#pkhWpcnCzTW{w-U9h;6>PcfpK%)oo= zy@lxcKr$BILwMMDWvXaue!Za(bV=>b0VZCDFW)W4OMXtqw*5eso^kyVhvD~a{_)Hg zd1-^|fYud2bPHkIlM9R|0IL1Z&p8WLBR57Az3TY1!pd;}0k29#uYHI|MB@rIB_FC7 zDO+Sp4hQ+X+UBLm@|gq|<2-FO=05XeR~8{|mQRp0^4Me8EjFesc6Fwy4Zrs4WL>ig z$O?zPzpz*x2%h+A7da$9fuJVkG7t)C^90=d2s&nzG76&DxO;8aw)@18Hhiz@Hj-cOApL&Lk0V}7U1Y3A&b#}?gwTw(g^NG98n-5gAA z(l#A;M9qzd{c>Py$?x`i!(HqpU+h9_5x@N57-Jld~8!gmRwnPESCke>zCgJwf%bq@%_Kx=$rDXTlaz1`&k@$JVGPGF5q zf-}C*s?WXJ+<0Y3KL%mrM2TLv+MZx(lh$MG!*nW@su{qx3+U-*tS%&IWWe&|`p*`y zQ>clPB}fZP)GrQEq5tHDBbBbMZ#J^};C-TWUYVBqSWf9sEPrP%$%}gjiSt zg;^R|=_|8M%#pI$dfTfFVis3DVsl`0N8;Lk5d*EU)qH-}v+sCYmF}Zgr8ZbTH*9%f z7;Rt&Qgb?TV0!~W-05;WOd4|s%(Ak7N*eOHiW{Ryf4I01WIqeBY=;~=?hdOyUx~kk zwlP)TVg?y0ZLhYmiq>LR-0@`_%|VCO4W`Haj2%NIUA@|^a*iDUk#|)w^xiGGZo2{H9^3C>V)rMe2t_= zQ?Aj0f}h3%<8dhzjsD5fESy%IQ>mDnd`kWqncyMLyEOT?HdZvYEbldv?>uU26xdSZdI7f(vbabmM2WPN9{qk?J&Kb3*%&S{5bni zn}JSXV1eP6j%M;N;-#O+k~91)8>g1mwyr*2!Ck|%hRmX6A+aoa|Nk} zy1sd=ByKUKxQf_K`4Lt#A*=&eZ@>^#bQlmnbuB?}vf1^bf5B8s=YA#`NA44(CI>k} zQRrx8VfJ-Ss9IHBY~GbatmB)NmfP(ky)D9 z-Sw&CA-uRsy}Ek7&O?YnMu(ZQvpn-xNDfp&9TKCj;`6L~qOHWHle{Pc1^r~D0S<~$ zDLFDPQw7+@5=uAu%_WUjTPYxiorT&&x(A4Pk$rmfjsS#5T6?Tb28IJ>O1(;4b9<|~ z^vJ?2+uQpveuy=$U7o*y1X3 z!<=qy720U;Kb!aMbGOIRso13ZX-w&UI`R=;ZxdZl##EBJGQ~+UB$rGx{CThmWF941{dlq?YIpA`cd)GrDR-sXN|X}n)Z3P}U$prm zC&E^XZGo|QO9l7NmYyAJOS;CiwWewi%+2MCVM*GVKlmJ~`Qx%@7WEFS;7l;){)8UD z|8T*g$1hKN(~JX5b-sckV?{ijSPzo$gK>xr0XK#Z*aKimiQK4*n*9ma;0R7} zVJYHi5mQvoyzK*)|UqZUU=cXRnVpKD%hm8tk&?NV2^9v?Nlms zDKC@{5v>_;t!eES?w-^4o!N{KRY%fNB!|Ec`*}sD00FjmPCX+C_Qz^R-hLr3CFYs~ zNIcRz+r8%MOPXE}c0RSwPY3+eCCPY`t200~PSE^V=6e##1z}3xx9(o<;*Wl@FW<*h z&!(Wek}w!ARfo6$v@&SRC`3TRoRCF}sKyBZi~)31a{puTr(ZOqn}J zt8k%}jQP>h*X_9LJOQAq;6bA+{MGjY5gTTrD2o!;1xS|2EJHEdP!T0#*F;mSVMp&f zLEM3HbYp_rjZB+dpfG_4BVGtvQ24OG!i~U!Xq7O_VyC~9IeevX{M;>p{STg0Yiant z^ng-_rsA&6(W{l<;M5-X+zR4((6Lo1nyPPueVorhk&c0#9$`bZ$R%Fnt{jqkO7Up? z_xn#-iFiupC0`gP?+q%Rr4+7!Zl1`xwXC3cO-P&RTLn-DX&wHA3kC+4&W}&7)k-NV zOA`E9*_nyi*@>Ca+0|L0)1AR)o2cX!Gv6hIa(m`s*Cz_O1!QJ( zOSF{Z7LM&*c2(HCBFl#;r6TRM40A9XW3e!;gdJ`L5u-SvSH4aN{7r`;2p+hnepPHBmmWEZY zSkm{cJQ{lGBFve2ZHT35Jw7DnGvsr$>X%9mlf!3XluuMZo)m1s>_c2KL=29@Eb+`=9EXq(OtqK?(i%3`q-z|8$Js)&x=Wf_=3^C zA_Fw@2YVh^%G5G5J-UY~F=r z{s~>wSTl^5@MCX}`;EP)P1{&KO>@ehn{uMlH{Y0t?fqjj19B$>Q97bgh79Ft zAjB%TA2@4VHawnWFC8~dbp2Yu!RuKDeZGqK6^ItG{BmDX9}ZnJbt1~wzrhe_dPJTAJ$9$s&^&wmTA`1ZWL-&e4)M;*g# zEG2K?4s^ROQZ!3sL=v88tN>i9@LT(#%@cpa6o?WDVo!{oNAYm8q@|9T0zQKSgkXw? z5XlGtLg30G;%LRQM4D4c?25=l^~b{KBE`yG}6Wv-QJoq1h%&dky?i&XuyOmxWdyX5fxh;g2E~n*u zFfKM_+82S}=T_ZD_LB-_uGreOTGif2ebol`pom_ktZoUdV}9Za=kDJLugUk{)Or@I zA>FVS=O7!h$2fPE!}5Q^=YeJ@U%JQ^-VS5~X?gXns;9-bNWRBMC5=mJk)E-{)gJ^G z1Yf}(5^lwiOoJU|%KHu?@S@6sYPX7d4oH+@rFS#UX*@WeO>f5*txqSa71yNKa-R>$ zgM04|aBa;w=QtM#M*89Z))fK3qN?A}e7=w0!27mhGMe$% z1kYz)q?|P&Ufx62? z#qVoZ5-0;p22bKO(cmQM*8}ryIoK)K>eS75h9jFp8)2t=7gESij_90<{Uago_iPLD zKeBb1A9dc*|A@W3r>>?b$Gzh$a^}Fl8g2@^2YAW*(9b1ved1&>N8|&#xr89BDG9@~ z&C2%{{Md>SaC!V?!@s}i!?xK?JOBCnXS--?Twn<2osLnR?q*VDpx6i}hllOJY19D3 zxZYDfj%9If&_7P4+mDH6{p^t@16jB)4{jc>Q&$U=+o&s)wke#ztNZag?pi-1ZvKqZ z^fvbz&ZpDejUrWWJqoUR_;=k6%EZNFRFVbzk*05&S0PtOq4AC2i1FY+TDPA)6q56j zzx)Si`cDSmm@6s0H$!hAg$f9|(+4x0GB?L!CU*QAK^MtyWNsN%7r-RwckHM)QTxzY zu?;kxg` z(9%UeaBtJS=8QMNbz-^frITs1^LoPBdtjGxGM)0Y55y8OY4B0+xG846IBRq!RBwa& zS%u&-R?Cf@Ub3mu_)dmTfVV8@id$;s>9SnJ(r~g^v5nh6K4UTSvm$ornZVgu&h_Ca zjmJnU%Z7%4ji*$8Lxq*Ms0nsfR*An%&26~JW!<2+G}94nWRmyEgEyW7z0sOQ^oyNi z%ZZ>k7Y!o9`EVI;*n$*WrtZmdL-w7w8C@a`8qD{vDbxWo33^Va5oMf9hLU$P4SSwF z30HN@7dWt^woK#<7o3H;RteaHw-nrRj*_way!hXPJr)`7Y)V^NwofEVv9pY5`p8u1 zBDpHS%v2bs3=ltawxqLo5w4D5R=do|JBL5{qY~7w`Tf)Y?S2o$TbREt&HgE^nUZeo z=>I851Xe?MOx0Lbzf`Lk1xF0R11@Cy1lS;;{Uy)RrJLDCM5{Ebr(jw~6`?LVw(Vlq`;dw@e#zK*Mx&If zoV|={R71Fn_%NPrAAV5djmGMenty_aGHe)xZarq-_T=SdTpFj;bEGDde*a0+_|Dx+4CXhGK_Z3{}fyNuQ2m}#}?Nj zV$>pHV`J1IB4YWQ_$%}OCw%~!IQ|3q!C_|l56*ut?=O9p|5^OsRsV1FU&XL;{*PAv zJM=@9g_Z69qxu({?cX=g#{9R&UtIQob2V6#;Umii{0HVQyMJf@ z3&+m*Z<6UBHvXx^&cyyNlk7~u|Ek{yoSpgKn17o6i_7_s`~8dj59>Nae>d~r?a2gW z<@|Ts{-4^C@k9LY7XCN&Kk5F9|1Z@48SyXazqJ2fuK!umf9C!>{vS2|hx}i5{%7s~ zj{LvT|L-OIt@*z>8TfA}Gc&XQ?b3f$laYvpiTUsJ4-O0CUvgF!*1xsb82=i3|MS8A zw>BFSkcge-1I5Wn#LD&;&GC_#h?vyT8}kR|Be8ze_3tZ?>7&l_p6L zA0=@z{!Mc-vVO=o{+a$Ni-qmuE`h8cgX&}BV)^H+ z!^6WMYGLhU@|{7{+Q7-=n~9N~u?d5;iLIHF`3Dxr!tu`x6A=>=CyAIx>dRY;&_RO#RA6hG7(Cu}|3#<9<05H7_q`cE0Zub_f|y>z?P$ z4{M(1?yl=dj9s6)A{ai;CSxSdYFoZPQB}cjecGCl3KvCpVDDc5Y=N75!lKfLz zRcdYWxVZ&O=V!)7$jwL&oFWeCm!~w7!;xD~U0YI|h>?5*gLd$f&`3v&uh<%y9+dN) z;Fl5Eympqt*O+%S`n_>r8Ig`SNvul)qLqF3qPL9`sU1~YavYgW;OZ~m%NbHv7|ou? z9`N9x*mofPM(+#VVKJV^?CC4Sa5mOieLZIGN)KEuKw*~I8;)<%wIMDhKRH22mV5xi@Hc~){iRncE#NAr4`mA#2|DR zwFUk@0Nd0^58)`t!#ec$$@j%!SoBp{c|T2uA`;x-2+HfqZdAPDA1o!Dx=3{y_RtYN zh-A8=3lLa3HjQ7-ha`UN=PY+MpLV%O*u2^XDrizi+4At>-qYAVc)qP&GK6f#nR+)+ zImK+$j{AZ^cwThf891$0ljgn`4&6aB#dpm3I&;EYyPQ^_uwgr4>3gb#y zT{w{-LCYi%Ysz~_c}3`a*YSt>5Jf z=o+&NfE{0QAvJzzS%2<0!_LJXzFTb)4zO7(3{i;Bd)Yl78>ylNMk^7ei-g2XnO-Pse zcg9BC`5KWbRdc_)Rm7?&?ufHsgBDiE7j&Bd10Xk8w0?T@3oH+@x;{rEpl#I@ul3XZ zy|c|bKP>lSc9x*LKT1MQjJ<2`TIUiwY{g@C8dT@3FSXub=UF+B&d+PMr6a0W2f=xD z@2zN}W+AtI{M{C@bLsG5zLRx-VG$ zL~q>6%9|a6Kojq)cn~iXw?b=nb(7e{c=W~*ZPmeRdg}}O6aV4NYnsn{YLsW=O>@UM zF_j=-*tZi}t{d)6EM#9b0Bp{)VxsX~rzg0ZDmC_!`QydkFmF`$4_p7>r@gA+Yyct) zA)j%7?m-frg52!qJ4{SLTmg?P4oAf?_Hk!&U-NQF`C=O)N*VcW) zgdA}44^xtVI{ z{%Q1@pZ0Y8{TA*o_y4OR*S^w^e*IH=tW{!FLF7KD(5Dov2|u9Fa(>5wp%6h#cf)Hi z!in~9UiLsRf~DzWTZ4jgGw%){HD}8I{A!->p8sqWt7F8mB6Ui8s2dfBTKqGwTQ&jKkfPK`?lcEoF=ghmbKE3L5 znby1Vxkd*ZCMPRn9Y%kT(k1oP8nZ{q=%X&tv8Rt2 zjaegG87x$vEWw|CZOA+`m8)()1>Ve9Q; zy1DT3bQgNakfZG0dkqr+ER0PgNo~BHbACQfwF)9A3#xE7vdCRE5~;Mvpu{51j zUCusqZ|_J^$67#G7*V)=BC4=vosZA6{nYg0>_~6|+sw^laAxLgX!QOwmAG7Oa+u3T z2g=lXH-+-Np}S3}y4eGM>`4Az&1M`eWH~3^Vy`aFn!4dbwTEX(rL}^Qm4!DTYN2oj zBfM{>{>WmoaLzy>m|U-Bakf7$n7O%&JQ=}uN5CfL>&Z@L0sM^D4vm$R6di(Crgea! zJ6(3oVo}^c%|zTjoYkp~MXOfj1!Hf*v+^HS2hCoQdcF=Y?)vM3U%$${h)X)qs(&Zf zoXWF)b#Gyip`*Sl2;)>2QF(w!k=tSozn?eqi^q)inpv4fs-nu=HzGnWAa@A{th5gM zIrd_2KjR@-e6`}@VT7RVNKC9(ZtO*q;&xjtaptSgwOm@8L)l8yRCTF$a;?O~pH@wr zhw8v&6Ma#Ytu87uxZSg(^f78(8)!W)lD0`$WNcTVqt0!bn|IP`BzQsf z@8M9Z9fg6uXq5`l zvU*7ahFCIdg;#z#zWu!bw>e9Bnu_XqUDC`zgtVkRY}IA;-&ky51QXIxD0r{NnQZ+}_Ubl2+*h zGt0`F8=UGm!gx%-RLU#ps|Fo^mD*I(#eYSIK`+lMq~e92$jW1n{Z(OoQ#Ch-YU!E+ zc3Ng-xdQA*U%;HJCpXkOL*ULjt4WM6k5edJEC^#&L|2`y=`;z3(l1!08H8-+s}J~L zt>n6dC4IIzXnJ1bV2(PtA8Ql0Ng={v7;@D_UoRKmVCJr4WaXXdB5t4#z36|WGcquVXCor^|1RGL}D_-+Ngr|rx*Rs2Z3fQ3*aThXe=yl^ND6E_u#TDe?5M^%FTrhEx(Ja|ChBLDs+@e~3C37jqPDz&Z#;H+a zd7Eip%jQwc!7Vh}l*}fdS+O~Ze56ctf}EsiGD=&x(%Q7O(Cxdd(!IGdV#~y+zTh)* zEwT!w!TMD8lt@;{N%Sha2qZRv%VAhdUyIXN-(zQx;#^)9y>Zor1hjCK6|e|lVi_T7 zs7w#vVY#kr%xrbaX&)aFA6ewx?h}zysJrMJ3hSJtLT&_>99bN*{DNFsT`pzMX#LVB zWphY@lPlBfYVT{?xVy;J)Vg8>MKq7R-#7sGO+@dr_Z*d8egG=hJo zKIw1NauBBwT(?jN#kYE~q$RFJO3)WjG=LD9kIYNpk$cO##}niVxIkK`Xp?XYugbps z`0k;{3Zw@80?mM`OVTFp_T!Rg3)rLEL(szlDgwwMXPHOGTv~d9FslP5KR!;rRQLSN z`rD-^A7le^>8WLY%y7}-B1w-CIg}eDYuanyV<|Q@k9H+>Vs45*o0t9#=wSe50|o#C z(EP|gWUm5loxERhuL!nudbmN2&@TWx6qiZu+XUNa)ODgZS+|Hws@wp@D>;xS02i}WHE&@ z%9}Wru(}ME7?u>43>J9+hk^}Ru0IkrB{HU9ic~QP2(O_8%T$FH&y9D0?)4crydVx*{_!3)_cu9gaC)&eqiS~H(j3qpCASWRwp(G(; zpxP4Ak+7m-pkN>sPOdSfGKMn7P6`a>>I_jBBR``u1Ma{%hy!9|#mR3;ev;hUBBk=A-e+K89YBZb9`tfbu~X&>JXGNFBs@6kalqVVC4vussK$3FranVCZZV z1Vx`hrTGG6MZh0uYLKxIO1A_O000ivEjpnre%?rx8R7vV+z` z?I7`za7$#qM(;8B=v3aIWNLIhvNi#?EL(NVxn*i}Z_qE07_=+$IoYb9Tj*sDoUY)I zEAAFek7N%z2pu#6n4v~*L^egnq1H1+Dnwp}E&zQOLN>ta7N#Q8mT8K!=g#$GOo)-g zk{%?DAcCVzK!!wyM43(Kq3J>LkINx~2G2qobQh%}Mnm0G+&y{#Zh#!h@^bG2kr#6l#T>F0 z>QYTvRY8-IO;J^8Rbh-lj4k*9E8U{VG|;2~Qs_O<7KmAhI``+Aau^i_8uG`y;2(%2 z_0g*vcXVB}5BQluDBrNK$N1tw9QoJcGHIR48!q6FRe z?of9&vyJi(`5mFpkjE#*m0MreB7(P z=uMwR_QuxJ_Jzmz*>1MR*v4kkFxfYz+X&%HWyYe}FD&-CUt4)|#{#ZLRM|HsM+1$x zp~gnZQqRV?jFx(?pVlF?_B{iiLT{}0Z`{QWSjJhh=O*mZCUR#Qo zJIvmio?Z*~ZrWtD_T3MXCa!!qf>VPn+!+=X^n~}ie=l@-boB2W=)25V%Q`YuxTy9^ z+wCN!u47}*w9Pb1-^h-oY}*VLKgf=!9A?&;C3GsBV(3o7uf61KnP2!}PFy zS#>Apw9?D90wJG>afLZ&JZ5+ce^L09ThttJ$8V5XvsM4<*XdV_d{y5u-r*s& zW0rJYKV>q#WnjVPL1zzG>B4M+4-Be?^lAU$4u`E_LLh9YsFCYa?o*T1DK^35p(eTH zs@a)zV_w~z?@+KKl~4fZW@-kPg56!_fJk71+`#-+Dg9ho3Zs7tSuFAEQ2wcm#_QMt z^Lf!SyH?ZVPFePnTJ5Ead#h)ey?=hLo~fd#AM@)UEZqvdS{Hita2l`q<7F409Z@R< zoj|(+<$Jf?8aeCKHt zA7hn2_TL{`)M}uQ>9>(hw2YHnc+~s)zG6D~HiP=ePd^o3;LD{_50-PYPte&s39i;f zs1Iu$Ou0$zhP)0UOvO0f!dZmK?pe6}lJPrTy^lm4PwHr`NzZ0usa~ z|JHly4cNPyn<|#4x^2H^!X}r^Rq%6khQ&!+b8Y?&dI7@dcRiK|6wT-w(l=D?T;+!Y zNoU(cYqn8nazKU7(kSR${0x&dT5#u z^eThvs}SaUBkfUF;TpSs+2gJvxOQdQW3EO{y^>lByx6F35HeX}am-2D={Qy2a~8_=Z5(Jz$UIc!lIe>M4H$bxGWSCvYP8cpZ^- z;q*XW89j9o--VUki+T8tj`zdP^OpD>aq>ip6M^4oyi9|xmYEbbz~~Zo9-aZ#D3#3hU;Ot4?A`h`R&(q6MnO z)t&Y{z0S(jXtbbG=lgCppV-g)Ey;@kU7Kry>~=LdC=Z_KGX}%;yW2RI>r~x*31naS ztRD#+aybL%0vDJquENiaZ4VD&`+|>fT0fg4&Mt=O8HN3lRA%?=YUl7hO zR@O*QyPtggy*IkN-G%StT+VovhYlcaJ)l?kVNO?*?Xg^?mTN1k?;(<0hbd>wIE^eA z_~Gl?Bk0Ah+MWTf_uP*JQv8M*&mJ)J{5d}1^B0#e{CSdm!4A4&4x$^I1n+*WZ!8V3 zUq%MD)Lx$fW=@}F4J9ny3ALg|?&3FtWiNM12C)X*>R$E+GW7N;1MFeUWz!_oD=Gwc|VI(^+l+$}h#}sFG!A zMa9Sk3=I=hpJO?`0k3XK2ab_Z^W5>UH+uF}oE-8vcF)=WL_L~i^ ze}c>$%L= zO)M3wKO)#EB*~eB8HKy)gdKHKt2HTH`gO}-WCo?i1`(J*4zTrG<2|RZipg2rU0nR8 zwMAt2;qsT3wXuNAe#T!p5yzA;Bf=z3JeA>aE1t*RN3KFAe}V%GV2~lZM_EWr>;0Pp z)cBLW{)VYW#yNt51rK5*0>~K5Bo%U-bE%A6mUKN>M98`rbxbKE2*;YIkF9 z*@6+cGQR3rTl289uhH8gU(reYK_6>f6+yc|s0B)7btBi`ewA#0;pN5dDKh zO(jqV%Sf*(?wumJ_C~W4*-GVtBTYG$EIso;5LIA6nl_ZHbNOWf^LpxO$muF7L1_(_ z&i&_ccqNK|+3Rl+z+SWR(%!KJU4BotWr1 zb$ede22T`PdZ*g{VcMgxFQUZUWoBsO8)w?cF}7Fd^!l7$>8|xC7 zb$p1>V4O}_bYj}SGkoTxv?)%du@nhNU{rho<&egHA@-6~gej}|Q zOiGvBs87kp2X2pXPOK>6D zRXJ?CTVk#5D+!OX+}7@+D+nC+Mr)|*?d#{yo%(~xZ>0_|bnNe1rl(*B$by4wXRDxp z=}1Sw%1H4!lZ@ugaG%Czq2o)LcHZyu!Ul@~wUMi_?(p6Lf$$pvtCx)|%=D78xF~Rd zDTScoZ<+H)F8=JLdMbH~-ASI-1UhvynMCUOb^6e4T8F+5Yld>CCA@*7e>CUM>8N3a z)m`e`?Oa7|Ul>n znP03?7IaYSO@9gfV90ozmD4fVda6(~BYDXwlb+gz)Mq8lxs5PSBM~Tyocy6GpHlW2 zwtH#EAR{vn?DBBj_N2ME>$CdSk>?54{{lxqxW7IqWxHJctvx1rdSduq>EG`EhTDm= zaY5agv(YBGAkGr!vVfp)RN)!8Vw;DqOu5b6(s{8@nwjRey`+@ymCo{;WA|)1K4kF3 ztLog|fhIw%Gn&j$^e|t0w0dqa(u93H{QYQF@ah#5p*X zzfx<`Dg>=bNAC`NIIbiPYR*`RAv(qg21B%wSBF)_bg<@a9(7Hxb?lP^{P=IWNMSyG zs(0rM9&h2ie4?G&YPR4B{td%yNs^P|HFk$l*QT;1_Y))KQ~Qptu%G-k5-1N;3Ov6D zL!8GnpfX(-&YP3)h&5vlLt&x3y_mG!+bc5Z8N-#ti#?N9eu@gqW`UwgY2o$OEN486IKUYN9lA|`I4NZ;^S`=(&cyj-OlqX^mBNW2v zB(a`66cZ8^BG^tI?6zGIlWZ}X5(lUJ+R1ZCdCm}{B`GFwK2$40@yTPs8Iey+HtW*U z`-3On9Bzxxt%?r^U3!|yoNVi#ua8NnjPWXK0{1H}R!;Q&vA7u_*&*3dUPYa+OCbO0 z@zUi=67lft`3^+kiHwZO&du%KIANv`Wpjo%C1yBcjk_Y9A)GeWd^Kl^cZ*_rw2J>q z<4L~G;daF6o(i*ta5{_eGR|nt5XFpWHFr@|VzkbfI5d+hDqdYY_Ri6#F45AvlvcRj z?UqvZ)Q&-O2bSMi&P~ypGzx{rq?Mk_Ci}lq3{yBE3eQn*?>Ozk_V4h4EfHV!U}X#2 z!>Uu{Bvf@jYT}!b{6MzjH`;r=wRGKRikx0gq=I6YefYx72i7m$v0|8G#G=g~tzEj~ z@?o7{TM8P=F1UJ1QF4f7NW<{)S2tjZpIH0+vyWa^mD}{-f=TF-uNW@{op-#LmMRnGremh2xjxRSrqD==s+NEo+`t>F%6DcY{eM ztaZCpYJFD4^hudzMwOy-ge9$@s2BqAn1}J`4?|&7?|3{G6{*%MlA(iFdJI{~dDi$r z_?42Z$m?JOJ;szYeR6!HCQ7ZcTE#*55c{|%ty1)c1m4u-g+@sW&FdYZQz3c#=?rW8 zr$?fgaVoq?@J7LhxWI?C4F1e8_I$MGgn8nqr59ulix?m%3<>$^{j%}U%TinV4e3`k zRelF@Nm2bqJus17c;U^BgE~JC>sRc)bwo==qsPksfSe4a^s@))d5+)3D>VkQ#@KI2RZeb2W>jLq=&_><5=X6hcFC~0-obH# z^th)DahKH>=hqe367ws@ROBa?uWY|0Yr@E!aE-7<9iQm5g~wQ9;`BB5%(qFaa32jxAwietM`3h)vewnb!%5ivb9;8SIP2jNnSCVSh7xQR^5C4bIyPMd#c3xBQd|(7x8;*mnI_hnW}94vaRi7kL_vE+uSA#jM+yZ zM)yOE2EoP!F9XVUp9z6M7O$rP4(`%M(1)$ISmg^!!94`!Ix zEYl_TqudGWqLV)+w6y7hX|wdIUVz&TW|4SUl*r#QuqX&x|MT=rkTqFNtS^=bTGT9h z1B|KzFzYA5?uFbm2?BnLRp6s5fSQzivZ7<6@GZOWciO}fwEdLQ(WEZmCy>eiFDx3%B- z`W*zQ4D&1)xVkqKTXw}#g05^s<9!3NhU0L&%?s5a#gP$&h!l>9d^QX6%^(-Hi#ajZ zY!98pm%ywO#QzCWXM1r))rzdpY|li3dDa6Nw2cgh7gA@HHMhZuai0FwX#?~ON5&4z z7i4l|^vWZeFV9E$z*)KqX$)3*7FFE>w`eqGmeAy_R+^z6;+?6^nnGtphh^~6Fa*h)+*bVF zlG9Jng2ASzbZ)ny(<9nFQP-J2n$6IaVgXCo#d>@`Ua&$QPneRl4~7p5z|T#c`+)dY zGNr1IkVglB-4+ogq&9}7llWB-RXqMbr+_UQnZ{g-B!oPu44X9WpmxN+K`bGb!YNB? z2rxFBI{ObuUNoF`WRSF|{zoP8j6N7!Odliy#BWH<)m%vB?F{BEZQsfmgZ0UD&LEj^ ziZg}V>Y97wdi>Y;yI6EnFkyj&OUJ)DEy>7`i6HT~0h*NLEymB6`q7p48TjKpG77vP z0SaJ`!iTfDP%dQ6S*lLrAD}5&v-(%Vv!s)IaE$ z$f0gRiPlS0Y&j>dLT19C2tv$eSmHfz zp)Va((oRR+ifaz9FFh3rawq6~5bIlg&se7PAFWNF$sJ91R+(dRxIX%|!ts1>&PMd- zN4pCK+MDZ0rpH!x)p^2E;?Zc>QCPVvkvikgHI=s7B2InjKirvC6j4Ub{ek!q*#y~p z+mtGu5Q4&|O?3&6Dt4gm&bn=O)bg3wIe)mSq#;*y5_NRs;wmUTSI!`QgwmhPK}y|S zXx!9S49l*XW$C)XhPYm0SxL6k4Q#C0^y%FVK4tv=uU{Ej+EyRb5#MIKk%Zss@H*1{ z6Ff4q^T23E`+)6 znYy{P^k-+&h84T--L?A4HBC_&e`?v2NA4MKWMq#8*(1C4(Oa`Cn*3+C#5%_&cB&O2 zMCK8AwkfbqkvX%4wXo5MB_i5IJBV=8m_rewiAdaF#>{3vi@ISG6BhK~UlfOP^i3G7 zXM_}OG)y3Gt0;F11xqV&gkX5d$d~R+V@quq!EieG;$$s$w-sh1NKMXu$KWtf@)o~%z1+$x3N?TaFC#QjhxYKLW4EJ(N)7(aw8mF6f9Hp+UWcipI;P# z501_Al0Rhenaxf(uI^)@3Fo{3GGC|6sM%-1Xcku=ZzSRQ8imr+HCU%zRndgfEB%CC zRYf4(c#Y2aakn6l1f)z6zo`^wJi)NnSlZ9)5Czro#K~ybfUGlm?)T)4&`%Vw=|y+K zHH}}Pa8*?ahCohp5`P=i0XJqoQI(BGo3m}uZKgE$>3gvmxzFH>+4J4!w5&$P)0zj_ zU}BIP7W1P*u~=Twnvn=;dfv*yjmR(tUdr@rThf2?#;&wAsBCHt_xV!a5F}P-)nm7K zT_xouA!4^5w_x-dGo^_GtDb50L0i8Cw;rrUOcLO$G!J-c~h<)Vfb8Rsj+N zJLv&DBnB7E4w_7-%71U2s>zq@npr*iQj|O58-&3R?V5p^R2jX7Q6Zd-HNrWctsBxc~k1_RBPO0aj zu`O~@5e|FJP`mPmVRJkh_KC>#^&D@sdd-fg%fuYS4d_JkE*{4MJ$r`|5NVQ8ru>Oy z#Lf%6=t=qUAEFZ{(KMBjQ3ubl0EU$~ZDC-vqUaP=ow6jY)?~n+pS1eTj0J8<26$I= z(zQds01zrEho_AStW!u0(zs_ifnxLO)bjvQ<_=^XC7Pttr+>~cg0CT+$hZXJpSR%% z399RVw`>5nfRAD~aTb3r7OVA&B+bfZo1yezDPr;pqAbuPq~6&3B^W$ZB=E#LGx!+5 zUJ&%KbmjEr_>CWf<937UvgT;lNd#+}bfC*17Ni&rC2G;JxU`5LgN#jY(Uk~;9md+% zAcpf1RSo?-)+GsFpgoazz@kRjS1YhNbIJ_QBX#ZrIu9dlBN$ie0N*HxIVqdVrtKM< zBjOB4!gia$7ba|yGt7fb)?pWgbS~0p@Wm&5JI?dYvNhCy8u5pOX6D&EfpUi0pD)3c z6-p~Z?ZzZ;E*ecc8SGiSlqdC`T-2X(O4xq<86574Mbi!jf0Zr7o{u+1t<*LGTV+Y) z+pE7C4|21vk~{N{oWznOE3rh~nSZL7gm^KL(ghonXWziv62+h{l>pj|kWWF&w1A~b z2(;8x>&(6s6P3J7{iN5-fa;Xwi`KLVj^Ko22f2L_FlG=8p|wtBRExprt7@@nA{K%K zeg1f@Hj|gI)j*OyW6$64b>S+Jbo93?JO-8tz z)=7GH3>TcKU@+;RiPeczB!zv)-#5?~2=p%N^_9rEq5(xEenMDhXx|p_hv#C zWI!um)_R0&R#nIBYwDkPLOSE0Rh@C!i>7S}giU5aYATD37ZVi8M?9?)55IELo-bV0 z;A$Cv=v%k!eQr-}=}(sIKz--7{#u`8%?%cn@&4L?9)ETC%TFKN-Im_?(3YVuf9~Nu zZ8hT$-H;im^VF=|wP$B6KTzw;4sYMH8=W=c3a250eV`f)Al~-gLJiSAM+>wcvrXtO z#1|F_iI*Y|;>2lldf@8E$L~~7=^lw?-7NkJTbIPF@t$DaS|wEaV>oE2vg~Q!)w&Y0 z3`=@q%Vo{MkMxgb^?yK7USbQ%WH>g$TzT8DBL zBGa^Mw8Nwy9sY^gC9o2M=0bQU+7L69?wFaHSE6Be^M>t~uw7UB_dsnM%4(%^zb85& zN_)Wyq~g5{r>BVjLeV>0;TMR?#ZF((pBNEc*44Q!d=hg(T;w6~_07dCEVa=0d1~GT z__^@iyxT2HmpRVK#@V9jdcZY-OCSbtQE|5vy9@^jSwe4gg6O;x&?Y%?@K05=UV`GIAWy9{c1*& zTY&O8%ge+M308m%zVrpOuo;PFVOoFgj1JbyqE6-rAaW$m`=b%B>CCrhOx9vDiJ@@V zEt}xEO~8n96vom7Xi{tm;PYA`6ADizeDJ|*1uW!4YQ8(4ifB1q6ROWw(5&+XG}*lB zz7yBp@cGRy+rCPs=J8t{D>m1z?x+@T#r0k!+(RaX-8T8?_PWL^pS}*?Qb~koAG>Xj zw`o-yzOAwap7{eX3*4cq8BH(oRx7aC1p7(+e)!sgKdJD7XVQ8;nL}rNT5F1`nVawC z$X3M}u?pYInxbuW%}YZ9ej7MLB6O^8_JSjKpK%go%Re zLOk;aoRH!4lZ+*Slqc{Q%;2xWGi?SNl)MxcBQR-4?9HG#p9=+SkagLMlU0*|w@KMh zE-Z-6_IxB0Ff2;0H6ibkW-lY599*EOm>CaTN__?)b<*Fy>f$ZLuRP1@Y4F zSX-<)-P|1!uwk5bHDpscJDtI?5!x84uTJJ1bR5TqDA`w+O66rD!e2@DpR@P#a$IfD}bR&JC!CD^$iK-)E|)yC>?f)M@|Z~y`SXGOw5 zShSOv1Af^eC-HmW0TTX{BBA<2G}1Z0Az~>1ZvcYF#|B_cSYe^Hqfwv(br1 zOAUb-tlM~lgiV&75Dgqj+oC~Om^>AZn^g>yUd5Kc?F3~?gdqa%gyXG&;|+s?;)Kj! z!~{|BO$wL@>{8g~S&T?2qqB3@zM>lUTZ_b_ZuuCNxaVn zqCs9X**)g7FIx<>Hwt+*FIz;$6Yz27Yy|JIm?7Ja`OUmehFQGz+`FWM_!)?TCUEE* zL=VwB+hNFgSno8RJOg+2_W2=rUx&flU zyo!mUWJ3e03r@fFtJ5fymzysY;nLrXB=$;E?A*Q!tF7Gj%3zS^%u(oy!~|Jv@x|;6 z?$&pV?P(m|rMT?*!95SIU3q8L0QY(0HWn}akI?G+s;)x9C2{t+FSUNSMHjFbQTyvb ze|KZFe$&3rwj+l>v8!!q$B@N{R=rDqE*9gRqnoxQyoD-9-MX8XB5oIkvj?cFVFvF2 z&&{7b#VE)gug@PU);G8t+(=vmX!5wU%s12rNu~x4UXfybZlf%aI$M{nzZuTMl)?;@ z*Jo5OIIY%JZ=J5_M7mSjKO=@F^TbE}sF@YMXiQaIqLs*qXg{MqCCkhhXCUKJnK6Jf zc;$m5tM1C^;S4q>NsPgD{#+!IcCmOjCF=Ezv2)FMzF}2s+|HHGGPZc2dfjlV~Dlr@{S!uZhy8PynpM5(Lh&+&1$8_4n6lUN8)fXCu5X8Qamu`rCMW^8y$iD<(w zb19gxwJz9ig4#=ZLwPZIR=u*$6M>^M8t|B4bQ$#SL~E{gMN8Z%bobW}HzZ`9Vs>|dmZWC4Vy;%%U5|q&~S21ZM8GtG<@YtEsq}h zHZ{{H3brmDoE zO-)Aizcx+QgQW(7&*?mJWtejfKYl~2Ln=^&)yUg#y{Xb5rkrNY^Ey{5jqJ1ARIi1H zSv5jWE;`4!wt`Y|`DkUrarh>NqA5{lU`!pW$7`2tY<4p29>}b6k#NSz;k!tNGy83c zQHa4|ZFAPi5x?UdY{%My%_uW0ikc?T;E6Y9W{ft}5I1tjXo8_(nQFCM|IYhY8H18R zGA8@>KDj%+uCIosU~d1VHJ?ix{Yq^hx@2R0xI1+A=cs*)fetkd-{GrDEQ453bmMxj!Q=Jlfer&z)d&|-!gmJ|zOlP) zW!uUng9r(h%>&_nOb6hRG;Qx+@|U_@bnhG_yp`9uZn;IE0)xzqYJw0^lUH{d8?>4f zn}xsyw5^YCeDVcsfVYS9s2fml`AVnWV|g8by=F|=xD+Dlyn9s*Cl47%_QieHc)I$H5!DLpK1h~4@_fm#r%-9%32k1{YBTl>Y*NV zG&!&x-6i7Y0UF)rVW2C5?h;WPnCtrLiVL*(DQJ4ttOit!X}!azv=(4ZzElfy!yGLF zx%qsROqEQP<%1e>1wk~o6nc|Jqn@D!lS{96#+oi_ zUQ^O#A6WC1V>BhbE(@@Z)SHA;D+w}^um>C_mgN~y=D2XK=xJWp>cdHj7@d?v z*5EKs5FZ%*`i9zgQ>QDC(=!Ii)>sp?d+isoFdbGX0c8RbR0S&FZ?W2E!(BlmA_O?I#AjMs%*R%R^W9ITr9N{0vq=A_l&vkR&SqgVEw z#BYN2g$yTC?rrW-dYhD9tF>2YB0-f1Q`6L7w-++j_=zT8*x1ukK%12CPRd&*;wt z?X3QDdXZp7ok@81vvSkeErYdPJVg>TC+IjDZq}otxKCd#N(93jOwyGmL+iR*2A#E4 zewwDJTG|y1`%E-L8)L1>esmQ>BbO6wix&Dgnw0q6n)A$z^(T$F*$?||5u17Puue%Qt$@o<3 zbv;{ECNVrz)t`w)AAG<-TOLODAqoxL2Oo}E`lzls>7&bTrkz*hq31*ZkC#yd!Nm@cVa;bPwCLiAF>}<(0B#Hf)wI*Qs zG}Nkd2S9^k|Gy>#@eQ{Vpq`4#>o zz8T2iEBK>I(=!`}*KEIT$6n%!>-XhbiQ+@OJxA_N9u3IG@G}s9#h$y5%He083ClDTx7J>w;!{QDEHKMa25C2%eq)2>JNhmM z9$O{;%!Hu@RrQAhay}jdmyT1*yyz8}-C?_E70n{08$gkPf#rU zk|E}YDwsbjuGzmfZ4fyt;|)c;CXyzRPvGw?<_yNTGRGO#Kxas4aaE#SA$UmHq1v~u zzDwQ1kQ{v>hipaeQz#1zfC)V!@*JTsb*}8B=&lr4tqGu@B z&-Kqu%X9K^TUi#wE+*N0%nW;8fWqnZ409za)x(hGbHq-PX3c(EeC<%Hv|Ov;k(6^e zQ!B0}b@bcHN!{GBYP_yY3)I&a$;f0^Eftoz~%-OnOVf4FP&rjFZ@r$7JY!Y6xfLc6vNt%aU`qGxasdoT3& z%VYQdf<%V1&y;bZ0b)0Sv^{HL?QlyOCu)(nAekLjV*^ZPM?N$*JSjJ=y&TD`W#Z8} z$xH)TMH-)xC@&FYA2*rJN8d+GW(#nsGCvaGatvGv`lhO7>napdl%V9M?XJ{ zl!r^lpS;8%(K5Dg(3Oq4sB(^A8NJzM^rieZR*xTKZPBKxsyYY3Ft%7@RkFrK5Z?-h z&OA3`%AZ`^5am$L)08aI?jSq_{xa3d7$2$eNs_N763+W|I)A=W&HWzE`{Up%VB5>! z5EfH}y9clD$8PgHM$(hW-IsSSLAJWyI{wnR-XUq^KFRz%jM#i&13t9kV(;>m_z#+Mz$c62B1l? z4`z^}I_krvV;>SGh+`}=dsUs2V9>KZ%+~30ysM4Kx!~`9zC4v zvM5tjdPNq(;{tZQIBFm`O!JIS95xo$+`Q6P7juxv5jkWB=!j-}JmBDtR%(yJQjXJh zG7^M_FAcfe9B3G2&6{I$z1dRnX6!G}^dpOSG&y?DSTzJ3N$Ew@H}66IX$Uu^@IO^7 z&08365L$sihHg#G8hYdEyGN@R_3dB?8~PCMejdCAu2i^|K%*C|r8}NR{`z3|oycZa zK({`LokVW^!nWonzi$k=^>g>#yRB!{46Tn|(0mtg^h+}%etC2H#q3V~654&=N?$Fq zJ5AD@q~kcf$!WGH{HoobkXs=AZdxJmjAW8n+2S+=(kLKYzH;=U;bLTwAV7}XGnT#p zW=ha=s|_M+6>IAf6~BG&vIGqkW%Gl^A}G`9g*~udxEJ&&x?4@s-Mu$-HLmepL$<|G zov^dJVFX2j>hYfC2ytygj(+LFb%K_+FTAXGxeA1`+DGqk`b*!LS=e()#7{T=&C7z% zVuQRrT!SuU<%!SDuJcK-cq2K3G_%fkS*w9F|7T`xv0Mophq2*1U_vpRG)b@b9`71$ zyl%Dc>+}X>w->+I{TWmN+}Aa-rr~-N6h8NK^<6zzphEWC3Hn@l-&#wSJmPP-D z)W3`X_PBHI(ymLYEbXc}`&~k+5dNwQ5&i}0)#1|AWeFDpi10r=?&@sKumpmSuT1#= z4jbU?5p+?^eE6VcVv08i^WgJeELuqn!OcUQAfxqaNkbgu4L5;F(5!HqyTS^$j!eiX zM6B!%wWAPW8|Z05)IKppETs08_@G@#a9Jb46J%3cEbr$32HvhJ`(cYky$b)p<#Ob5 z%zYPn@3UZ35&pibBfPPVdxGvpv-#qq-S;5Jy{4;O32j1-`@pAcyL;B6UEM>CNVQH3 zE}Y-A%Ch=9SSJ4yY9Lsr$h2)a|#A zT!Re1p}RW8EeX#j5C)eU!+Ci zW7}Ir6qQm1R`J`ba4MRx2b@Nh6(zUD)8gVBwq5v)U?Uzm*J#u}|xLS`7EkQzi z&EVpuRE>G+RN0m@4*k(hdig#3LmU{O}{<=Wn8}X=I&+6}~K0$U0?8v{uc791aRF z_oDvmX0ROmdO=r@C2VlI@cx?GmgeQd9(RiyxSLzLQG<_BNVsd8ft#d?y}sowHDp*p z%{kdVqtVun)=Y))K%B6dY`BxKO=HBALX~?V)P52*kd(W3)TN(Or_m*W<)wJph&42T zq(VX@Yc|4y9a>U0%Z6}$qJ7jIXs`9vuD`XX{pjKQ zcec(pfWN0UfN$QM4A#dib?f#m1;n{$ONWT}iJyWlFa~ym2igT-#`7QtmgCi+0j$HH z13u7=Cln)>&K2YaU#`K&alVEe2_{bBkANhgF`#%md(xZ!pMxvNgtF!xox>6Be@E$y z`?q7;|0Oz4yaU&0v-<1P>WW;0dU4~NrWjdWpPRW-3=f4WygnL3u?0H2t$fE0b;1k9 zsCEyQnT0tUtj;Sd$Ca5UYNN53jwpvF;(gX&(_hW&Qd^(CE;D5E*jcmRF}>!xF0VB| zeBEcpuQ3 zIfcP>?PK*0;?w4uv|o%_n(n@`$Evesjl5CEVKk9!TNVzlSl(M72s8{<_uSQBY>l|; z>l?lH?yBhM=x|Gf=gj}t6!V$F^-BYmxYy{b>pr{0pTa3iEE1Aq)$ZzAfPv__4~T!G zt_JPk?ghSPNISyNe0)f-3+=TeWkRbjMx~)IYbI9at_~3(%L#mWxWg~P8P4U=AXa*;9{BJMb;kXwB;XN z*x(Ff6`VahMGXQINPr#l=kHj;XZC_=0#gLu=k=O>2{P>X|FnGxm>gx9aNT!xRd-ca z^?l#>boca3_gtN0&K#3FVdW6rMKp;rn7Fe35#99< zvM#8o#1#*8HUIN_;p&>seqZ%5-7^Cw?7uWmrlxwj>wE9xd%yRUVDgHrhQ{rUiovtz z%yp!}MlwcM#Ao0BPutp4HS)u=j@n^i+7_!M6WvaNXcCXn#zINN5L)+KH z7BcCLL5Q~#c5>tRPFU-*bm;&b#Fn0%<$9b25rnyZrt0+R*XqcJMcjtIZx--&rsO&k zv(21gv7wv|g*=G2G?76E*exPOX*~w>txkfb?a?}sunet7`vxhAr+VRz z;E+6lHn7dkC3k2x`FjsMxHZa~RhEy%av9kyTXT~Y&K-zae1lz{$f7O1-qA4TY0~Qa zZ?&9eivpq9^4=xrp%w`d?80#EKCEicun%^y?vRYWE;R?}Cszfo%bUxo16_Tken_|D zWNAD(jZPk~+M9)nXN?oT=0X7ws!d2P@N zB4J=B{s8Pm5xIMook$}%k-(E4LLn^)MU8`(w`%c_3b;v%xp9wbiF-+VXvE0CwRC>H zd5Pmp^Wcn8=xCEq&vb{qh;OJj=YNZA9Xcy}hX29oh51vaEq{tPt1U2;nK2U&qsuux zREUK0E`D~_YWCp9 zv&}rBZAuk{hY@4>ZB{NY*Lv00L%D%py$N^RjZo!S_K6Tpv;c*X+3Oirmaq?a$`uKq|jtDC05BTwyniee5GQU*4PD^!{~YA3J*M zc6fD7VnNy#UATVxmFdJnaJ6Xt<*=gohqe0+$P&oV>=Of3(cfJX#BQmF$}7SmhtZNWZL?+KqS$$NfE?geo;Eu6H*FGFI$?g?0w{_-1_01z|c6&3MR%B zC{6ao2VzRs#QKS@($2r$nwT8Qay)*ckj(`Z-D2@3Y~DmT*1vAS(p$H7n^XtSfRNe+ zd%D=%b|sLq2UC$)W!-|&Bby4mMdJKiQqif4A)7nDc-hLB9F#<% zd+#UrKYfCrgnyLbnM6}P?;1|Pyeq?Uw2^wx)$^`6Oub(%3bgDnU&9mlK!1KLqnmgJ zcJwhZfO8faoP!;^I0h(f81D%yBxz3TLr1RYe`oI^cPW+ZNiJmA1?++zHkr)z=sh};TR7IUpr1*>tui+0FO9*( z`thoN=6GEBT>gyF1LaKp2y(~CRH*MS_8VrJ?O!C(+fw8JCK{?UKq|OP60o;+NkUz{ zu4amS{Vs!4mg{4N3t?RxYX=hy-$d#jff;5Ke((lR!Co3XXcG&Iz{&-At%j2(4Cmx#Fb z+WvoP*7n<*N9rDHZ0GZj!P=jjR#a9AEG?)aBU_!#+MnH*j&Jln6_yfBI`VLjfqKic zca7p5*4k0LbEzb{eC;jkn+NnT$o<6Y{2E}bC6q!A0am)<5l+Z%l&&crBlpGV<$Dag3S;k2XG@8}|P}tLqzP5zsd$kiAv*zDMtS^e&)V46P$SJ^IP9C&wNf`z@B`m+)Afkf*yY7be&&g zufOmM!iK+q^dpC7`Fc*?hIGN^e<8aK;ccO=e1Fi+l0D;|ap0$||9n+mMz%Ukv^H5z z8@V>4gMxffpK430UF0?eekCS46J8j4;!bsB({;Tgm-ji@wnJ*zbs*4eZZ#}Lp_tBeO^m!Mijir~z``F(bF*~5>2_6kwv2oUH)KlP>yf1)%1=MvI+@ z_z6!yvE)u-_aPOe5B<#vOT`jccoKU80Gya2j(3m8lqxTc^-o`T{y6xV0Y9q} zyy#bOdvv@bS&k%=P$|^W(`pvcz>^HWY`#wo&4V#~F6yib-5Tkk=rdTPG=>Ooxc1Ou z)*UYf5+yf}X5M6!@IY5?07%d>6lGl9nJB<$5~a`xDY>)3aK^!*MU)CJ8LK*AZ}Mmu zypKO21%wU+W0CVeFlz#7AUn!AIK?K>2C}CF0Xquw@CKvp;rZ&rpFXy(iF)+H*8qoo z4`4n!TMl98$;XY(lc(l%p1jxSJo)9Ssj4T&Ve83p%TlU|sB)d}va^~_I;+CGe+zM{ zXdSy1jdqkxPMqmR`PYw3({I)BfS2OoKCHB>k<;Dz5J2%f^9 z2ioS~Y+hh-4RIquT&+r^+ZH9oD0m?@gbBhj;LKQnH9D%OOX`7he#qzpW|=bu=xzSK zIh&25-f9NWOk>{^0l0y7=(UaL8c8(9QVQpfD=I-zI8KX-gnqjAl1Zx1*21Dz34fUO z1bnO`;XHp{)fnIkdlcQqINeT$S2c$jBUC%*4TM}41?JWN7j_EoCOxnxF*5vYAc)Z2 z&R}vH{eIPMrVu*W9dx<^Ebg6(JZ;;Tdqy~b?+4z-1iqxh+km}H3XM*>^?{c2wyD%; zy4muqVR5h*@I)@-!$me;9*Go2l8WRjjBctFS9=*emC5+=pC~zRun>?*(Pq~3nJ|OB zZjvO^awQ(n0+r>d=*G)d4u+!fq{$>oPdohS;guoDsRC9Ri30fU0`P?>0f__qyS^%N zZcm}u?E){0IWdj?pz1`p?qb46(%H|1_gP#<*T~(b{k_l72ioB5$flpmwsrkO3v)YO zG~FRU-^OKUVjROm29)LES}%hc@P8cTZDF@7tb$;Yk~tw!9PoCJCd^+a1>K_O(_w~J z(!M~^Zzh(+H*Q!t5RN5M5D&OabAS^lj{dr%Usr-oIo!XbBsesaw|h8Jc6gJERzX>R z5c>!03DSj>kn(ZZD-yzPiJNl~J836X?vuHF>fc8?L2gaMYnudg5uMCnNPs;-3kuIG zj*!!v3F;;)k@5qlpQCAl6&Nm*D|`1Jlmb1I*AClr2_MT5uSkio!(=hpqxnMC981WG zED3xt2;Ngn?5=CV>n~e16rn{k%Qv|8YKli9NDs2MD$rTP8SQZ)5m!$ZvaS=bt}8;| z{@vhqmL`P+VBY+E%-h_M9!Z)dKcsKh zQfmq0Z4nnBERELwUFq@$3IVgrYb$1gbd!-|K`k_}EFRl<*@}Tsz=2ADm_W8Ust2*6DMX-y-2u&Q1#vx*Wxs8WVKiT*2);SBn%stqxl1?v9TXG_nQ zuu{q0^W#U81vA6m7O?evxmhpQ76kmI&RRrz)16y-QM9`^KH3vu zfig02Ty|(8wBU+GK{-@ey=P=_OTYU|p`bhM*Xge0K*UVEJ2~F%q0DR|CP;#Xa{GNe zCkeEzu)HU>dBdu~up`xoB_n7$uj?7Uk||VV zxl+gwh(Dvd_)4sNib0vjhxTaMr-bs}*oinAf6{fZ9Ru(npmAaY*xxY)qjo_H@!k*vtEHpSww zh~(OZEK3R&(*hp6y{4puTvnXK$=@)csGAQba)QXk;-1=getD0JqbY$6$J{ihcs2A> zz{!ck+~vY#$%&IRK^l{3KaTz!F9BXDBNND9RYlkMM8)YEN1Ww~b0HLxJ|R{vAWniT zO?ehhRPtnS;OXo>vsoK{Cb&O#kM@Z6jD~+%`=*9zACKKa9wi?o@z0XalNi~KNMsA( zBKXhjO4`%sPQMHS6{K8#&j-lU1|plaQynRa`Kw;rEJZ`a{ltVtiT zsv3(YteP!mv&DRUJj!`_Uo2?zqMXL}Wf;x4YX-o7DdCH@Gg&=w*;MLJy8y5Srzis zQS7Ven?Ucv3cc>Cu6m+gg!6jfPguJ6CK;NtcK|$7=XjSw-ky1L2KX!O^l#hv!~ z;(+r>vnK_wh{sW0kGfqUD}`N;3P72b!#Md2pc=<%LAx!e@w^s1?`%SZSs@T66M|j% zCD0hCvDzMF;6zVaO(D~mx2ke!Z>lGqQVDxrBJ)%6zq5C!hM}`(>WiK!Jez0Ljq0lg zBhSRs=$}b*69xjn;P=H<;z=$xxVAUe&k#7AHAHcOB6~v29<)wBmB!{m#N=01yaI#s zG#O6%aRLuVu@Hm}_lYmVItd(A51>o9{#y%{77X3AV zRzVU~v%(`lauH793DUH?Q^e}*)=9SJiqVzE!dzi%V`0E7W7v;q4nCQKPX_YE(eQcq zU;vgtX}@13J_xkudSrXGSWRbo)8z?G3+Vp!^*Sl@@yUI$0g4X$M&Cg%g{Sn(o&Ey#Swn zfX*C1rC-)B4FuaNqUSJ8qbmI+V`l##V)r+1$u#xT+oK@9{8LRRS46HdaM{ zp(uz2u~4rr0*iAeb)i^DB7Ta_d?vE5Q57_0c~{Td#6xqdi&}+3^eh2v#Y2&f9+P2{ z;V#=#VGj=&)&|r>2=M0pL^7*;%@k_p<9)-Cu91}bb+=nDWWqFW$@=uDN0aDgJj6*> z;ioOC{9F=nil-;lc);rGUEUvz8sU)Lr-stS?z((qHyNIEscH*JvO{trju7{i_&#_^ zSUpqL*=l9z+!<&SnygnR(OlVVf~kQp=q7l^OJsPbRZqvfbc@%3++oq2?lDuCB*)S@ zUG>u>i4pcd#H(_?!UF$m?E(csS!PdqWSS;n4iP(ry%(%~2+ma!(KAR9Nuw`UeQFWB z5MNrfmj@ppxd+PoJP*fS3jbRe3nw13x6|+Z%fSDA%ehL8Adl*-&}lPvo%K1`dvVsp zvd(bU69OJtUm*}4-!&2%$oVN2YIw#KDFjkEU#>Uj^DVq;*xi%zfk5ze+8?kBqTse! zbgMm7ie)DI0-Om%KN8~)IwiBo@3QEc9x6r?%gTO=7ikLWkk0_5=F{s zu)si>qIy|!RCPZnzM#`1MWdOe-T90HUMcFsT`va?=7Qx^-R*=M&jw)FJm-s(w!zOBR8Ydx6%Wdo zV2^sC2_?=mHsRJkO~DodMi+yZcpC$L5;zFQYPV#zY`vn}@L4DZLhwBH0`MVJWE9!) zxkP*#{pvACZ_hM(;rE<+bpE-#46}+2U>l4&U&bD8b|}q^ecQeV@j-$}-?l~^ECdodW50tG z-Pvd~YiH3MhLYBJ*c-A?sE&V%5VTM|n*mfqA{I1Zygll12NjAq&)K+J{=8Qe49tXU z-xp+#sAGv!Y0<)y2A1w;S@ilkk^t@RW!d2RtykvSu(lTX2s*%8eI^w8D$LBIXJ=>T z(SL=RdGv>HCe##6woh61Q?pR@mNTK6bMsn*$(3j`2e0?Ea`3CJ#7SE^Y$b3#2~eWY*uW8-*TTMFLctjPPqp9kG6&D=l3(}&#Q=TINgy)(Jshco z5e)UzQzQrgFveu;1l@)H7Izr@z2q1J6YQ=NX1~Q8sdKmweYI-VG{npZ$tgdy!8Zs8 zXMr~aQ**7vyWC=U;KbHbkpQxu4(hiO><*H$=7%Qp4+ukj!MFuuKYTTcbGDe<2Mur8 zm5z8sl(#4RT~XqXv@Z4>eD|%3UzBAMMBdM!|4CVCQRZ-*5&7EFu{D=%OhflsfctpZ zH?Rjt6Ox3siN)?loQN0OSM`!kkH%SIJ|f7FVi3F#4Pm^WjP3QXPboLFo2Jf@QE(O_ z1nx&o+XOirZ{}f|S@Tk9Ci?=1tUiDfBt}Wn@4m+IB(IukdqoK&2#hqF-+YGUNluZ_ zgOW(RNm+G`mfceAHzpGkjeAToWl_zP*{z_m$-+b;ZXWtg2ob^3Gj1m274GY2TIXc!Oh^WGomUgeVI_!$x$ZNq*W5pEKrP3HEXc( z4}(9TU_r-!-fhWsB}GNyHLogX^J$Z27Ihzh?SP+8pi4&e{<*VB#o}GWOF`7?4chO*c3UBOJGuUCw(45-&IR31 zDZUK&dK-%a@%E;@@Tu%+9t7F6q)X(raH=r{uHZx!^d4*!+X9~CIEL_+FQEy9L1ImY z%EB2@%`xmVyHVIE&Iqz*s%^JO7!9r@^if5^x@b=*>{G3F#v2TKEjn`H0jaYOA9>{aq85=PR`Au1L+#*wa*SOEx+anghlLn8Zq3A85gU&Mlab92y$c9&CKyWVD0$gawP$M2*S>R0 z=DJ-wQ?f3@2{`nA6#K|~Pz#zu7kviqmeM8-P~a$%p9I%oaYZ(&FVpX}u#z>@Cy7s=!2_QK$Y?x_8;_8-5yHoAVpnh?+p6hX4owwDiG^ZJ`8e-8s3IN%0Dx%n@QYR*1H9FN)r~Y+^mj;?kjJhH^k9vaMr8i$r%Fc8!n9}es-GN$B2Cne3`U*i1 zMs9lruCVqdTpmjwKeAeD3ufN|+yVZ> zj}ZeP#$Wy%Qo-JM)?x_*GKjWm+5Qh^QB{sBiYoxiMd&7fx>$E=A+`X>nrW@T2@oV6)b5%U=SDg|?sR0*S zs;n=&1W!JaTfMkPQLS*ekUVka4ZS<=SRG1jzWa)QMqiapk1?JQh=ggADvI5M{pxG+ zC8MJev)>_GT~3O&_@s0y!pb3!8Xwu*weaBngA4A2dqf<7{3`(RL1g7~NI&+oXJLF8 zH6ZsKD~YL-XsQl*mF-h(IMcP+(mw}y;DNvbx=R4Qajz44{0I(<;f3=y#Q_3$HRwkB z2G^DByt6BkTQ^!(I9Z@+p!|i=9Y?BHesEPNvf2X&ay zw?P9@N5f8_$7Kb`K*UWcArG3}w5y_s-cr1{d0Dq0h@_yHOp7l+IJo1EH6bB5wBsXJ zJ&XR*3}nC;3VRj1ODYak9Vj<>+clF;H5JmmVXp=-(VaJm(XhR^>gs%Q{no1w-m&r_ zC(@9CUjx_|!SlX#Seg}P!xx^fvJ$oo8Ac_%I*pxa%7J@#0X1 zaHg=@QU!Q9UImCTPIJwV64>O%`FZ18Fa9flS_Gfl&?#2vAlZpeVh%pvZFE)>&)Zao zOi`Aw2kq+LFc{Tn!P6b@-oCs?5P6JbISB~Xm4}C}{qU-Q6kfRFp3A4va~9KMv=_1$ z^lGL2z>pK=OIufrRJs%;5rmkvSs7O#9CUL+Bxvtmy(5>}u-kr8`_mj;Hnly%p_-77YtUY46=V+o(xDnybg%e}#Y?u^wHvREyG zg$u`njA&OyUvYsywQkEb{Ub&N8BzN?^mEv&K(zjgy)OZ87B)|ZmXgRT+P3(A_*y9{N#xsuN8OQ#{N$j;HIhN0j zV#Wr!6*UG{ z**xj3GZ;C!xz=v8o0M#E>D;-~_YFd;gX1+Ot^c8C{%Nsyd52oB;c<(}_entfLEvj5 z%hwCJe0}qb#jd^xUrc5!3pC*gzB#QBX2O9P(^{)b%WI6B!Z`tq893fjW4DzX6>PDc zxncf=)AtSVDh0=DjlkNo=NG-p+ws_A{LyaYUfeE%-aXsI{uNlmC|CpY`V)G6C8|U! z%UO2GYjvvXK3iTcFMh;husCJ%hU@ih56a)a)-3SmlXySU4Ss2zajf-Aw5yb{4(8X; zXx6R{mRkX8)2C`Zm3oD-)Ku2us8FdictoXZsjGi~TcLgD%YN~6i z^(*Dhh8l~?q*v)p2BS$`Rb3&s6_>fX?M;4Ppt+T_ua2-cv5)W-P!fvJ2iThsv-*|a zy(XLDTcJe-{Tnm$8p6AHzIIxv=d%)K`cm~o5!r3ZCpFfJhVs7B64_l4YAma)*DG{T z#j0h3UG`HvGgt|I6J$ik&_UT1vN5CpeOsZJ)k6=o6ZN7I6hzbLD4IhFw1Tcj-|@!x z&M!PDyDdE&bGk*Qry=dP(E@#{_~ z>WjXY4Nnw;LvJkD;y7dT3S482>)Iv!57#MX5wCW#NF1~ zTEn!owY4x`!8cbA;oo24*tg>lcPIR~;cWF~kEiAPaKhXLfhnBYd*O$9w$;^s!3Uu` z-0n735F@QBAn+!B?A11Rn-c=iwzvK6E$)8qWz-671n+6jPNfYG_H9L->}{uNP0F)u z&F7KltktS5JIgRnH1FTYF_@x~7JmRZHJx5|%?i8*c-K7UV%XPY3`@NL%0Vw>JzHj5K?44oa0 z-+r}3SLS*OWn=xle)e&(}yP7N6?F!{URT(+cvKb52(l_dSxB}#h1NhM{!wN6rK z_=@Z9v2q4_*5Gpk?2B9*|0XL}{u*HiBPZhq( zpXDY{uedzMId==~kXp+*Mb3h{nU6qp;DIeb3Uftrp6!JxG$40<)M)|++4TG#ga`yPUa0yO;kV$aI0o_$Zurk@Hm|skCW+v4d;q?sUj*;cIQo`wbfYj%}5Kq{b zRsQF!9O^X8<-?$fXRszzjC9WO=(K3lKfPe`%@&oCUbs-oNEb6*RwCMKLSheqZY5xTUjzv3DlzVmhjzAHh>|V zDtrp;VG?CVBG8Y*=Z)vZ7Z`Q*PPQYn>=}gUXW+I@(P~)vI>?-}Z;XZW_g(XOGWnOAbGOrg^&?TwvPbbt2H4L(iN4- z?fPfUfYNDg*|RbV6CL{RIo~SI%LL&ot2(6-{GHg6$bdaO#-IH!a`4_YE|rRvYw*X1 z)gPMVa$Obkg%*{DQ$iPT^&?D=UcpsVZ|m&PSqg0?=5yPsM_am0HY+@NpaJSE@ZV%# z(?jSz$p0id%szAmjjI$hXPL<}`*-_>i}2dJ-Vr>J`b>|nF-TmS-KPs2Kg&!!rWi$Z z*GDpFUm9&94P?k}*LX>8P8{H1l|B_`#wD&_14h1LYYi^ky8po=23hCM9ouAYsI_{3 zztg*|L}~a0^@w-m@%_f$=q-mQPZ*(*-!nqiYZ~Eo(uRnW$9G!kc8E=f_U+W!t0%f0 zYqmqYF+g@h{E%+b3Inf&T&Pnh%!TW=FZ9k{9g_C`ys5Lju5aq-EX7~>9N>Qgx*JVC zi8O%rb;C<|uia~WR|Ss-ufQ|d_xbt*+jhA>fmb2iG5TSw8~1Kucn{W%ZR8k4dCcTP zq7H}_h)#ORB1DYzd800O0ph$s7hbyBDmSU8HthGhi<2vPxmG1rTX?nMcT~n@>3H?@ zMtz&A&WJUj?Aknfa(9Cb?Sxs4T`5NC$ej07}Y+m zxng*rYm6-C;xtY9Ms@@pMI)&9e6Oe11MP>_-t+nNDB)eW?#|_DE3bB{PTgD5wyi?0 z!SA_w=-0a%1ZS01X}Etw(`s|**P$H#+{3&|qtIHFW!2R>y}1Bi9lKN@DQaYw#^b2# z)DfHEEVKX2?C$a5N?a87jBLl=X~@?eY{6@i)cb4!9yh^q9h5j}xo*vpWPcbxMV5&B zK3S8>=awCp$?*zicq2Vow|}=w_J-;*y_CFXNL*{9P*avdYCfs)jCbcR4!0Xd$At z4%y4B7mcICUhTH_#>y(QxxKNfarasFcTadLtU?iL)Zy+-_edpP;O9)6JIDm_5(26r zv$@Sz8?=*>KHz?%> zOQ~6C5(@ENV*%Y~CEa{<^-R9b-edO^IUB%>F^fuTefPHPo@98ZDZWQlR#l}p6!1K6 zuJ7Fz7^0iQ0m$Fl*b#hKrqsyQH`le|x%jPh*}3=_%MihG&|8p$2PRwC<&J2EtucYw$l^Z=7&^}bmI8OO|{kY0)8L7sux!G41w47yXALDOCQd8$`aLZCtXU#b4%|VlfW@j+Z zyN6`&KD^Y5MMt)eboZO?%;#DPs!rWg(o$c_s})+amTVGP-b^=%4Ctow*f-fDvPh{e z(sM0*%TaNg6qwg;750XTt+vez>`P^cqK-9 z@TQzs`63v-(C{F3%45D=K~E42H~6?c=)RG;5ySjm18bcRe}S|w?c2x>rBNhyG(!ej^>+biR5V&U3R^Bb!ORbOYW=RC2Lzio7S-MIJ8OUP^VXImL2AFv;OJf8mz;ykzKe1_r2b3gRNhZ(iPe365v^?h$F# zaE-OvQ&-nQRt;~iz^jH^YuD^`rx91Wk==ADuOv7*PkXjxX>p^PC;K6i_Wt95?O&n* z#`XqI_hJ8a6x$Ocy|}a_d@+1BJ?zJ&W!yIq%!jp9JbpjGFRz@e??7aBHr!Mv8uez4 z_EVQtR7Uf3ATCRFH(qAry=1dq!v@WgeFuk7zqde+wkw9}+_mO_a`m=u6$b?;Ee)k) zt4LSpFASGp=yEmPYrv=$-?GTx0u&a}thYptqKZYw{)YXnI~rQ*57d>J%gqPM>*j}X zEB(~bkq~axc!wQj9@5X{%MxL>9{&f*dUMqjsz0Xa0 z!Z}Wef_{@+`3JDkjQbJaeBs^uu0)8!zwH{CK76=NPF~yW?e;YWK_j8Z%IWK6 z47|s9p3KygW>Rta){>|rQ;jZ$FIhfVE}<*mup6HW5X7s@);5yW;>=2MJz)FQ?^DUA zSD(z+dwTqy_6eOA}0>$5As37G}p=2r@bOPSMoK02Co zn&Oh3Rfd9sz0)J>R;2~>$S!)fqCNBt%}v86v1k6EFBO~*?!n9W9U8?go6~JQxS``X z)$AiX+ZK%^a$nHA-FyD+&0fz)CYcLb)+Ecb*FYlm}`QFzIEz38hLR{FMz>QDm;d-V>zuA$yw zY^bw0G}v@cvwDP(ku`hGwtB}i2Dr>s>NuNGrq?SgpW`M_AyRUa;vh=|P6|Ad6;E&R z;Lk{8#=}mR$Af1h(sf6QilljK^_5ghc%F;2;2Ptp=UP~XVbzwZlBzm0&zM(N{k+cR zsAy@FF&YJPQm(f(RM$1zRP5^O4_0tytyQkk${9|fQU2wJ@d#>-g}3V1$MAt{1%RS9aWJHlZ7AeJbk-mcexT~wl2)fg%;)2zv%`U$QxMuD)>eQ-Y zgj4J;?R;#YAZx2{Hj)-(>1~0X}K5FHiN>XE}0(axN@{ZV>>b@G#SgTHRx2z5(A^K z7V}59LA%*Jef@(oHG|zvI=xBB@Q0u<%MI1|ZRa)bQ7S(!G;OOaFI|1! zRA|yEO1h8Vb>zys<~vn}0;Nh%=Fmvr!chg9@ouv!RYfYBLS8JFqvDDpqsm~j{)@s` zR9qo5Be}{TODL~bvPvaqH{)WXMckTV;{hlRXA2HCI;hWc7wi!$_S}#97zmFPsOPqI zb=Pp)f4QA&?CP%NKF&3DcU5!kzij8Wb$8Wp>`x3PlYwbieHs5{zo$2u^sE2I=5#*#(J7D|$#n`Dr+yZ=&E=I&xAmNF&GJM!V3sHcka1TgKbj9tUmO{LYLL^b zEkorshVq&+B;zZwb(H*feyw%TIryYWlUZR03SFi#Lb|tNzQ54a?V8?E+FV)0@iIBD z)@T$;y+U1TE~(edagE(wwH)_Q$5c;+Qmd2kT8*Kyw8F?MIbKoQ$ub5w#IlG-DxdP71&S6|<*J6_^gPDn z!b1W@9FK)S+t8%9+Ni9qwr#6XDCB5cmC00GU{e~AyueniFx6BQZ_{xOI~mTP<8nFi zV9OEpVe-6mzSTo^EW$1~s~&Nj1D9ht;>wI9RHTp{laG^kLqS#p+IECBJb?P!7ZdK z=j7_~gvs^tlylY&GHX&)#Q{Z2*??8B6{xS1@iH09Dfvmx(biGUeMI3bn<%cb8kG@+ zMx~T-GH7*l4B?ZtG+} zIZ3S=?tJ}^p1tQ&3Ps)jdhYJ~_AE_!P`ehd#bdfO=aCTYacT1_bMC_y|7se{{H^xXaJPOh;BJiUEZdXXh4K!Rv5Y!OSdganzL86eyS)jib4yi^_N_RH-j@M}1Xl?M$GnsFr7M zk{c^s#Vys_JNK|Z#`Cl|rB?ZHPs{3CMC|9wN~|6Gy`#~Rx+`xhE@Wl)DzoAg*-t|p z;R8j(?bRch%&6rxyhbV0zG~j6pH>rTtbFghhYW4X9sZTAH@T3i#Q4P3)F)p3`2vkf zZ7X1#jXM7J=9&u+5r(E~n%#nc^A|@Hp)%CtwG<(1nL%Y#B4d$KWw4ehxe{X6=Jj@+ zDY!4SN+Z&8R`}uMxvrZ#DV)21blF#I+RwS#!BHM8Xd4`g7!P2#S;xtkzrD9%{MrfT zDN2T4c0JAF1+pr^xXr~#Tcn0N z)y=NT;!YjkW_MrG+6A@eNGFHj6|7kF5 zpxQATm`|)O>dhLS)0mCy14VkPhEo`{t7_(F(7TXvDwA$i$NUGL{i-ffTJUf$f}74JDKs%Nu`J#NN?r9`U)o6BH}^cU{oakV zqa`mruyZCu|GH~FLvQC&@8RCpy*}@`zW%=N_TMld8@OWNYlD4*Cx>c=?jHK#a17`x zBf}$K^7Z)s#^2%p%fbkH;u=}e=xCs;{3!vUlx6D;(L?5lOvPC$&XL|_2l18erEC%&{LCNoc!A4w`@t>xz34wEMfxJ2jC?XGL~n{daZCZ^J@(jK9ncEU*XQ@n ze{}x)v8`k4*gCe3tz+xhI<}6jW9!&DwvMf1>)1NBj;&+s*gD?vKnOLnRd_*iJmiWs zl95*&S!GL4&TyDTMY8XRVGiw(Jt~G}s804}G0Y>I>?dMaj%s+B7*?PYyh98tQ6v93 zF|0y@LP|%?-j~TsgQgVU5W`y3sH_viI=x)ER}AaXZivIsVPcH3Xi5w-NMSu9hFPSs zJuikiRBn4j49k$&_M{l*k=FL27?z^~+bd#NfwtRzEQXb+u;{QDRv}|?tr%7_doy`y z(6-`sF|0*}#aD`9oq{V~7Q=c}3voEa$W*{w0e`O;ra03u#hHdF&NNJMreTUR4O5(H znBq*s6lWTyIMXo2nT9FOG)!@(VV&M4TrGwv&JQ60wIVlaL0u3UMKLssk|=>v@c$S} z!?ghjCD9W34a1cfgyP5vclyu*kbpvPZ4S-Dy%af%!rv&wJ^{ZGh^a$92+hEiC|ZFS zK}anMX-uG#BqX2!qcAlWU{M4?JOXV&u6v!F4-%K1yOl(IVuD zQI3#bLF7n^E0F6cqSF}gB55xx2fm*ME@JRx3Q!mz(!_`)v5XvH_`e8GP!6d)VUmX+ z>N*A~;#9*B52tk!&Q>6lCVEJLd@~SUAUq`r7FgaG{LYC;(Nxn!CYooQNHj}0jgwqb zL{EOAm1A%P+v74pFh$ahin@pqnJ5-1VihS!H7wdI*4UDGUCLz<(pez*EQwsk;mRV( zm8O{@NM$*|IW7@dXxWgkrMxc?tHG8qFIq0hWB(+77!byU|vRF!U@s_MFE?P2{pXwz^tUb$mtImm~ zU?~$D+c~w5IK+<v4)U=YsG_VncJpim+}@!qqVFPBE5JrD-k@9xw;T2)EQL(zNo~Xo}eR5|N#v zAU%h*dVu6X{nAN-G({$z(Y6#@@*=aMr^h~_iC}=^Es0i<>(!SCu5r#V4r!BsW|+mXV?9k~{&eLm~vzv{+Zs@=5b;%H*?N0_t;D z2u`!4Jmte|MU*r~O4mdikZ&+i&`BSGnyjyH@%Li=>2x4uXCYqaF zQ>(6*AX|s7=WBb84PZ&AEVOMQ`O0Lbof086b)5K-@I@u1wijMwRn#9O#9t~E4KI`O zLj6;O)Os<|x6pKO%mw28FK(mMi^oOHWK)+)NGzufGEe+nOvD*`bsh1SQBek|JtCpJ z)~cI`X2K*KK~igMy`NiO5*+LNLX`OF71I8Q5$$8GhT$4UXbxgX_grF{N7wnz2C?*J zy+yX|AaQd!wbLcm27-NE8UZN{p)6y~SHU%^C&_APTV_G5MY7htSq&#y<;80`thv3J zl9S45uTXtcD~O7DQI8!L_1;8ePKvdU)UKeds5w#3k{wgKS`yntG=~IfrH6@}lBI-E zww7P-&;AIy$RHFZvSZw0qOXsLWp!3;na2sQxpiiYwB1w0HbovUu3HF?udU}n+YLDw zMRNKRx#i)K(?i)lkQ6(=cWYYb-6ZVSKfOTu5V3V~OMGS9VA)cWt%)QZHX*4mhx=^O zc{ImDmPl`Hf!N!8P7O=Bo*}$M#hPk4qsv@hLUrg8HJ&1+WFfEKSCssYP_B` zUYxeZPLOcER(G7#5mGIa+nbZ>iF`g~?Nce@E2yq!M7i_Vx#5dwG?|e;MXWSVQm3V8 zV?X)bT7Xo)`Opx#8$`o!HVw69h+Of*H37V62<}Y5*&tjUge&zBV_dvnPc$`6>LDM* znm#jK+f>hN%*@L;*FF1`-sex+c6@;Fx;oI3=s}+&Q4KQ8V}<$ zCEme0!u$n*vQqUC419!}EPey`kcb(UHbBm@Qc+C} z5NR-~7=u9wkHY_v40a*%OL+<9q_!5jX>vasi^|t0{tgi2g5->9V}P7Z5MANBO`Plgy2#%K5=p>Dg?qO6U%8~Au$)56=oAlCzJRI0jKQt2zB^RXOj>L zFD%UqzHodtF?$@Y?oQ0d1>bTch4Y!1kEMi#+;om5l0tuMW+65kUJ%3_Ax;7^6;g@i z29QDHeAi6({gd{h|qPY8k7Y&4#VZWmI~s1RM8iAEyPh_FDf3Xy1PHW^#O z;*mTe(R4Vrka7-$7h*HX7|tUsEG8g9$R`|6K`P1EG2vKvF}840Sc#?Qh1Bv)dLb$# z6OeB#J_k%e)O2(ao{UETfMh(HOgROAS~wOBrN zVf@JA@748%S{uuB2kuK=gD11Ui953JaisMVc2jp4s_u5*Ujnof(7bk@6J!6AKX# z3WG2O2w@F$I9om9?Ph$N-d&@MbTS-?E{2oGv0y~U8B?7D6)fS)vkAZ>9*d@&f#q38 zIMo1Z6-JVYM0!4*UP|@2T#>|V%DE^#>4XPd>61%|xny{0{-i5B1BQpALd=Eb*>LJu zA`TjWSlP@{%S%fOF|Z_j&nX;8ECYlmg=Mg*G`3!R86z_bx=u%%gh(v41Qty-yp)W= z-C2kdg}-6YYc#nSOQ#{ZnUh2+$vy!)Fr-9M3LL{ZG;Nd}3?s5Un{LAPc>X|V$12SZ4uld)N9p;89K zFr~D%69gPF$OQ@s_ANaU^%@6ZXpuIV&XXS(S@b8 zh=QX6W2VuuLSm%g%*SS8Y3#6c6TtGZ1TH?9WfAHoVJ4gcUK8<*>yVV-5N#nEcdo>a z$CjdzSlF3J&bjcJ3t}D>olFC$mzV`96gZjuUNN6H`<56ZfMa|c!+cc&WWvxu;aUJs zN8n!TH!+lJJf}{#7b_=4iWA5U5JcfAFl<03(j**9f)~U^1WM){$c!-ttU#mixR96u z?-$3Qgo)>t?CjE|zzl^`sl;q7jO_!;8ThbxI!qmGYypsQ;1t(LD~yY-``ZnKqX==2 zR1bOM5yy)!=a^fQXl|H$>Gnbl?3Ct>(@N5+3vwWZ2us+6oqOyU{u?ELEG>gTsd-Xh zA?cZATzFIXqG%-`p$i00MX}FLEXAmcy(p`+z(ba_(1=JACRXMXi<`)Zi@|a-4$MSJ z0+9qbRl>_v(b=?QU|Bl`l$v zjR^hl+*lAQdOwszNOU47;0(p2{6ph7vC*N>fDcal`uzd_#DOMZ*gr9b(;S9G`-HuH zp$Y%MWS}o3?41nl4UP{%_Jfe@n15_I1i1{24vkGf9XtltgrO-o5ypLefdI*>ZxXl< z5&i~(dk=*CBfbg27Yqyz!NvX|;H zZ-`ui{QBVEz=S_IhQ$~Nj!lH%v%%RmX5Qnu~YJ8mz$0w5}E-AjjK;r-8QsWzqIKJ$a zOO0^Nf_a{~mU)r6nR%JHh4~@#QRb)2 zUo*d99%tpu7g!VXJZopZ%+@nsVO#%CapwWoMDqUs-E6Yi6pCVrNEH<<;06R^p@|?^ zQBXW<=pdm8s8JCDC^l5AUk44q0<61$H4oTMf6K}V(_+;HRwGEgfmH&m z9>6+{`R&d@!03c!0PA*OJr1m8!1@QU{t2ufuppd`h2ib7c)S;|x&Z4KV4V!C;lMf@ zSQi0n2C(jgtNFmHgpwP;S`DlXP@@^2!)lK&WSQX0SiSLd)<8Uir-I;NMsT`;x*BpP!VRJr{3SPQfswXy8x>du(|@PH?YnC zRynY)0oH6_JqoPnf%Pu1Heh}@51WjOu<5uZusQ&%JFrd%*15o%2CQp=btkYM0oL=t zdKFk70BbFs(+>1=iKTx(!%!f%Q1BmICW- zV0{d%^}yOp#1dviB4J4+5rcqrG_Xzt)?i?r^)0KA&|>WhtPa3B4p{wxbr!Iu1M5Cu zJqfHOz7IIbaxz`6!lj{xg6xOyL0 z>wvWhbH}>^s{~jl0BbC;t_Idaz2~Fu)fQ=J+zAAD&LQ;2Fdid^0f>KTgPibw02z1=bzFdIDH) z0c$m|z9nMWhD0LUoJe9j5Si?e#B25hLdA{+x0{IK6~%=wp;0G?ki_C*io_{W5+qeB zm8CHh7pJI%kdTn#vN9D@k|34Jp{O+@RY8uaHY7l*ykAz9z+~W-#4>nM1V#~13pJ;t zIL#DW1TUJVt0*>3aWo|j6c4BPfr>!IY)F+DO1CggLv!Zbhi27Xz(8Oma;9^+OeSMG zhYXj=R8&+@B*u(BMk30JVX8GkXQ-Q&VTF{T1_U@ID3X>b%ajik53qXdHFz8}4P+uI z6wy*;BS~T;IYd@gQ6XpA1Z)}P8b}UCa_BIn@}`uzE)=ROksO>P=}8SrWelHeqS!*w z5QY;#+gcJew6z6;NTgC28<&l7+0q7dS<2igLyf3mDk^R^ zR4GXcCwY~Xf4r_OQ&*7Fw7i1S)D45Ns@s#JS!Lu1GjnlK zfV>H|lF!B{w!WF#B3#Uvtcw}VP`fAyf<_O0H*={%OGLF= zDy%5iC;&B7B-ggohW}uxM*l}k<=|)`m=YDm2g{kIj8n!c=OEir+=E0>IK>MLjElQ| z9fpN6CV_#4g~i44Hsk#NwNxQa35)4s`nvSG@{aPk;yG6Qy`|zLS8ZQB66bNDkrq?M zTTGS5g#wcNyRD)%V(W^ujJ35fQG-@<$XeMrW1kvpCBa&SLQJH&5!EH3uG(BRbzAKf z|K47qmlk`4w=MRnzN)rYGclTN$oUR3>NBZ3>My!&_+d!l;lHaEy6~! zCb`gGh)e>VP?~C!kPw(=6JYdG6&fyE+G@8{GtjVD8pBoK1kPqx2~Ztmw=QbK6(FNj z8?Kqga(N`OT;xoRdNPaC2$sudOKGrN9)AIQj!YbloQ$|FVHc=;;-;m6k>%M zl42|Y#)0#63q>WO68Z*RDXo;gRX&C)OiRe*8Jp*FF)rnVg28$d)5w+sq{snK^Dm033}+0#WGjngv{3LBO#Sbb|@e|6q@K zY7W8|oV{~!E^)Lin4IXuww;{Vwr$(CZJpT37u&XN+s=t?XL9eIJFniW_iCo5`q$OF zzK!bM|9suORfqsP;?)9Rbg^z6^S@a%IlWmodmz- zoPrQ)j`6aN4pi5vp|?)NTpS@|Tcw~XVmfNNieRe$_YpLGH$PFbxQS$vAVD$(6k#4P zdGWNN9KS5yo1Xh{(3CY2i5?Ft~qybey z7Z=PbI0sPdSBfi^W24^K1Ix(~qZN@Y@egADYT5k-oREWYR*tNmk&g*Vk!uf}h7^qw z#ykgD5szzAk=v_`a)>u1{fjhwgda4WwOB=jNQ7A~vT8W+>yWT91*@6%7m}{v15yAD zp>n%S#4jD~Tylm4nE27grtl|4X*!B(AN)1RMG*eMh9sJMPla3c_~3A05Kwb;jB+#* z0M0OQMEroi1Z059N)&2(S#?=j3dU)IMYN+SI6zA%N4eJs67=gYKBRK)2ogbnB?;CV zkpe=QKSUMhz#T$WXh2jxBvQjEP9}=Fx?`6`Ok95m_o9NbqPD)i!-CJFEC+-CZH6FT z(mqtuZ)^Gn9e%uH&PGNtpCd*|7z^b9-^Wr@g9=|Qu+k;OwbHlhntj7YX&NNahC(S; z=cDl2aSMyeg%dGOBf?5wlf`9q;(UvF)$la znP(Pko7s9!bH)x^1f~o8J{d>*ZqX_6X+X4>zCOjQyf)g<2?q?Q45UU+DB>3I(K~N_{k>`^ij+BNq z4y1N$5Ofc6t1|ppv&dc*k{Kjs1k;nne$V9QPhlsv)XWc0ZMT*`KL3&P79a0+)%FkrWBBthGYDJzWVR1`v ze=r&a-i?BW;&PXVzNA5T5Iw>$%jzqqrE!uFWRTS}pxG~C$b45S0u-oqsHHDLVPY3T`0fXKB{0}T zVqm3tuxBa#GU-jRi9Rb;R;s1Yxdd}E$XDt-`EnNAbuREcUa8e9LrVio15F7{iMN{5 zdPa?qPQh)21q3D1L!q4M+KU&ruL4Y@h9a?gQ|Bt7Jx=dJ6;UN|#R+usu~d$745RY0jJGTz?Bd=R2Qq+{Jt#4;qvyP8Gz(SdVvJpGMND{go9s1Rg8KMW_@sXQ zM@xoGid^~k1sOO}AkBo80FRQZi$lMcnF z!6Wr7F%6Cq$s)LjR@qTJ1#T#F3-eu!OU)^oGLGIcVmQB*L@G52dhSH|OwL!67hNzX zvM$hAArJ7Z>TveFebQxRZLF-v)Z$TB-)%Y&R6v||U3bI7im_dw*L!8fI?l&?)>Ad| z5Xs~-;5W>*y90M-fMGUIIeadzd(Ax47|Y3?nw(|W`J0wfot+kKmOEiVEL9)Vk$yer z@R`toHJi~tq@ls*#KBpwib|AA2F1Kj9&6$wfuH%_it8j*GE+W(stL=;jee8wY`*O( z*41ux(_=iII(e$^F4}gDG9S_zsv}O85Y7~tI&+AzHi$3giD_?9qwKjk zp`iYQwrScRD62&;V3(LRcOwtRr1$wg78*JhDmpd>>3pI6glNT|iJ>H~ru8NAH9n@%(dCh3hVwEa*DS~>@ILSp()(8;A=TXY z{218x=%}+f@E>%HTCvziJi6vWuhIrG1=~G_6OM2L-Ye59UL$bWBzKqwS0{uHtq!gS z^hmE+G)tlae5BXX9I`y68{2iJC?|R%u$6&b&Ya}H1NE4VlM3CXBavp`iARWrcV>AIsi)0n&KvBu=F>TJy1DM`t)0y5z6w1@y7%98WWJtv!soi}ukVpp zB*|@FPE=|SwX#0QZ(p7|X|p#%ueE?0m!`|Dm3k&$PDDFaEwS&n&SEd$_Oj+sxt#Q; zDsN_;nygEtfxlSizSUN#RHw0a9Z>*PhR1Dr_1)pOIG~|0-!9s3NJQX4+}sv<8>lT;X%>CNB)GeBDAm=5JL7r>OLB3l3IXe7C)75)DJ$gYYAPa4#kMJm`sW z)-j3~)l;`3wghT8U#y0HX2N?_VU6S4=$*Rj?>#UMhepw?616Ah2Z{JCb=~4Id~l}H zId!8vj8Qex%@+75fGIthdy-rx^Kftcuq*F@B=svVI!aOuiTdZ3d;!OP`)^IO#F`?e zh<$%-a-n!43i;D;;Lu0b3QiCk&7`tTi(u!R>D{h2@m&yb-t9DFN?>Q*y=p_4dx|6i z-(=%J>l3EVA1h-V@OjC6-MD+YjAs=DG}x5BDYqdtde~#y9gQotLN36V&~@IdU2o`Y zfpArD4ASZCj*2ow34J_YVZNBZX2V{NG;|W?x8FP~f9T#a*aaQsWy9n9$wTxjhc>b! z5r1hD0Gs1cI*28Ii6zzw9J++5E@wRMo;txU=AaO>LkW2PrA zR|4&!_{>UnHe8qTd0djF*J2KQWh>07-@Pk0?+rigN&yBC(lWnSFKE4iwwa$fz z$vQ99Fk@x15_~;0D6!r3vWw$vu0qqWsXiE{Tl&^NN16^tqgu=WfHu|l`Sz(RPqHoN zGAvUez%pKg!x-hhd;9Z``G=y|u=%A14YjZmhBKN>PG9_ty#bEEMhdIcOGDg`8drwyD^6wl zt(>a8qc&zOuI#9$E9vskGM3UWTE4B8i^|=t5AW{Yt#r5I*{VLg)!P?uH|dJSelgN% z>n7zm98S;iws`lfe&3!~HqA%_tjt8TrSgvk)lOsYJ3rA?&p0g6SH4c=IQ5X5Q+P8z z+;88xG9IPXE`91t?}xb5+%OJE^?05!E1M>mpBq(ler8K^xo#g@S}NC2jy)z&3~ewq zfd{J5Y>NXkCFHuY@x*mlL{An_bgGmEr*yQtlIzdGp7y3r<)s#G^m zsOv+&#FOpt!?$=_Xr`E8I5DykTQJ<<4M1x5^Y^Lkarq7a{;Yc6SeK|Ib%kqQ7C`cH z2=A$?^7)SIwbRZuQ=V0_o32U%$%246apiXWURtY!{ay$AniUcm8D!8!m;}4PsKkK5 zSi6RKm;&JG%Sd6MpVa*OMLt`rHRl*`^<5W)M)zXZ9$pe+z6;L2J!#q}dZ)#KOi7JH z%$2VCrgKNzgwf%Y`C*%Nc3yMrtM>I+c0S0NGk>#}xf5Bvw9IS^s5cPhibzg4u$6D} z*q(17grJ(~G?b}jKQ$+Gi{{RMgU;ymU2rU5+z!pihz^}=^Wsd-#N++vlk-L8TA9t9 zYacZ?XRG$;S0z3-(`3g!U*+ub+%-mpr-8)-$)I~=yl^2F)s2x1uz5c_4)ondE{T7| zU66_fksF4@-$~z5s(BWD_GvDY#m@TZJkq4L8egH)_)0oszjDkO+ouFEv)%0RvKSPt zIO+Kt)5(3j-A1i1ednMzuvbz4B>bmysYJZ%mCA< z0gP&zT=q>KseQ1=(Mwgq;;rdqZ%H!a(d8BY?qqa5UH4tjI#bCr=8q-T$Cvmf(B0}F zwvKI%N6*(8QUTlF^p{m+ox}quTba`%Zu5kbx%rhm5#9HHwWrM5%)2h1<*tkvc17`)%pTdI@Bm*z>IJC}LiiGDlr#1nqXr)|w{g26JWXHG1!baq%~dp<93 zAaiL~o;7|O&l{x!w~ZPdYMVPgY|amwJ1!^d#2QMc*?#(nezfdr9Z?m}3aMF3wUv_( z0G(&jjqOfoma~o4-B-nf)R~cs@iy~4CzpR_&)A(A3$fdi*yG!;7B$v7Cps1Hc)T7K zY&n`9tLk`?*jxskH;{AB6O&OeoR(u7IVUzb$k)bb9~Rl^rGMDmrLrC(aK0P7hT-I_ z2XEqBQ@RA7%y`>G$YNJtE#|si2e@t&U8&162<-aVu)UNb8GP0Yt`3EuW0^#jySZWj zqdG%Q6V2RMneDVAIWC*(5!Tq?*eJ@K8?B+BYU%;9|iwr z{8~GNuQt?Ur@-H(3LYi0$;g}s=TM_$rxo9i4q-Swit>Z5@=(eqgeN9Tcwn%+)b4#) zKOT(TWOr@9{WiIk9*%LZl9-6RX7&^u61N>-tphFWT;y-^3E@mSOgf4=zMtRsmkl4x zfa0jkeg)R3^4}EloET^V3*7mwArr%~xm0}r^TjyQ&(`wr*>0V4 z@0R(fq>L8~3R;<=Q}-D^a(&M_jR!9IP+u8N!*sXvq~9qTzMh-7=g>|EQq1W#u4!K<<7hPLUTn>{tT(saN?!z z3`0*X>A(D<>xhr^m%yyhmoMyNGqApLp&6 zCSlZf$&#Z&$>70+Q`qVen#XCc3m+xJec)ab;CWi5Pj}{$Mw}OInTWM`+4vx`c74pD zcR8=q*n&icJdeS`H z5KwaB?7C;yA%)~bK{ck^$-pf&^O-QoI=dCBp1xK(zPvqq)IRoZ?%TXS$35@izGBkY zaeff4$htSGScm64W$DVVp0<%W>jE1=D|G2PPRilEoG~#%$LtRT4OAk*PJ zT{QNp@VB4jb9JsFsq@arzkX*xUP;?{roh2KO*(Y)tk~Y8MT@NN;*u$>`d}~EJ9>dW zJx|S40gODS5!Q1mm|BpY#Jt~Km7|`e9M@wY`$A(HL{S2wP=|XUi7323|zB3toe7lD{bKTi0N?(a~iJeH7G z1Yy4+o~>TYtr0JDe#!AY0B;3a3RG5wC15sg!DwlbP0Fl5IUQKoc}A(GVZZH!wD~Rg za%Xjdz-~unWlE6Olq9Y+$|k@HkeAF)(`?n<$hv-?riFYl!^ee)y^TymM@2M1M#dKE zXkzQneacu*Mb#;&)1!@Zo3jRa%u0Xi?{kk1S>UC^*!tKn4o|*_LDbE%S$Nf#dmm%2 zZ*6FzHuFD9q(NgD-Pqt!k4;0rVmeW7Aj4l@6Py5}~z;)AeyRB^8jQ2us zT|67hLhB~g*@uKZ2Se?x2RjbLi`s?3=rDYlZm)!o$ZBWkYGre{ZaKZT-fljESm}c5 zU>;HA*xfGc?`=oDEGA!9KN@>HbT?}Mu+X(*?4@*8kLfdD*SfO2#H8<_nE!={$xN@m zkUVBNK5E7C!ec}1aGUAjFCC076r{MY;dd_aw2%E^vTCd@*oAGnh_T44DlOite|)6e z@O#17u(>wJeYd+NxJ`S(bSzJdm*H3FsL8pCm12ibtEfuuF znKar>(8v3_ohgJogJivK_xx2_^>BuIM}QtVJ%s%}?|nSLhiLX;Psq{^&Ws%n_Xt)m{Tzdi%BLYm zIG;x`Jzj{+;}T#n(U68xrfVy=6EN?$kJTw^^=u8N6qgLp z9Qz$T_Ml_5a(;d&A{(V2Ygv8T*XWV^wqq&AXImZDdO@hJ$URFWe1aF?RJf?&@lL_2 z>u4x_OXP3fbyqut+p8^q1_{5eBK0kT`dt@gv=n*3OV3{$@;E#6ejwx9QlBff9LT?J zQGXqSX!R`Gu(xO*y;q3fAKU1ek>25aQGa?`EUJKfZ60=?9X~wL5fw5eC)0YSldyBrd}TQXcQV>Sm>Haa`jD= zuduz#RdqTHJ&~_m|I9yC4HVSFs?ONJ{Jwdq`!E|a>H;)%#i9#qR-U`OZJ*O9KMrVM zyZUy0G}LR0n6ksEcgcNmY%^JnK6%NI(VZM`hzXt(ApOi59RVZ+##yXrU!-!&K;eg)3$Giw%lL=LUj-giPk4Oqd8@xGr=X)NKRJ8lQRxZGD& zDYDDyK+E!)n_p$YX-U2KE+kfFhLyPbte8mnFCO#zJ7o^=>dXjz9h7ve!_~TZqEu%r zG%eUS4}to1NR|val;?R6gSSq>a-Bqf@>!Zo)51cT*cv-IJDM2S{HJMWXbB6&z`?>m zKu_?WHa9n&sD-t&i6fn;wSlvVu!)hKu?d~DiLIHlIRPUhD=#lB)PLu@XX?bsSPs&| zggojLj!pnGn@+me+Ubg+J}WRLkIVke~ZSg zFM)*9OVxezjlRV;D+Eop)UszE&qYVpn~KVXcD=|v;k6Mn_`=E25-yeUdxJF!8X(1r zv^E!9QdXp4o>8n4bo_qE!V>jj%G`QX*?e3$Xls3bp8R*cCA5~TahHUfM8FY9-dRH# znpWoR3xtqjC;WeE7vuk@cCpcOaQxq`V<2E)W@cvppS!oj1?`SJlFrnTpz6Ed5{;`L zQp=#;{L#zGN*92?%1+|%vFd@ND`912BvDamY)#(f9o$(Ou+Q4KQYa%hPXdO71T0}B zPAg$S_~4mZywmhtL@HB5^O|7gz`IU1rGvEbJTqBM5;XSswv}q-mX_sb`t^G3H&gi$ zKrcvvt4pTr;ZxGke)hN{O%Uuu-@b$#C+HQU(hZWR7gmSO%|*1&G(8Z8D9IHZ*H*{2 zi2m{gF_91C2gJVd{xQ&%x+rr^l;i?T*ms;rdOZ}jZ40W2p0^wyPP2JIa% zDnCH^CGzv80O7eN-y8|~r8g0xTHmfUeXU*C+jpztvXLf%v z(z--Y%oI4)V9GDO28BB1*6?$oE1^| zxn%7!i}NU`C#?B`g92WIMlot)PcbG0ZgLvsD_6<3XMgV$f22nmsN0vfadf;kLINE} zFnk@I)R@aGU<#&m$miP2vPRb3SlQeXx9S1yR|O}p{@H#TAw)lT7eAteoADtpgQvZb z+J0qpXGceXd0T;zQYvg~bIS#41V%=CDJVY*I(vWwqv)XVuZbr##(Aem44L|xx_43A zQ(z<17~#2MgN@sMm+C~N@0jJLaN>-Pi{_JZBCnQ3@2NT*=6Z`4;SMS59A2d>_LTTB zW*=&w6u81-(qE3&F@h*r{Jl+imeTC?EkTjOBC)?So!1JqZx!znQu7gK6#0Wnu!BTV zXZ2>pMTr@L+t>$aW4yzA5ibtVOJc>}!i(4sgoOF`X&F+3JV0Vnl10$z$g+u;11tg> zk{k83u2vB*Yr_}^%^^x*Y)%42wxVU_+onV-JIy9THfJNQHdlw*`- znQE|@+O$R|WsS(1J4fKIK5$?UH%psHp6pabbzLKC82;Y#8flu|Bk|yLs%CYFs^HpIg`LuA?2~IaqFlx?og!TJ z&S2RwoGPgF2xhsgv@n{|T&^^Tj%1u1@aRykFz zs6$tQEpuDNuuK39WLkpWxxoGmnxHe?#sFtRyAZ&R-*i6SmY`rXg6eMCGrwxaLGtG%I$A30fJ zdV-JkJV|;xj)Lj0-+y6V2G1#Qa!QJdotgvlb_1)piFh|&fZl_5XjCZ(s~ATM$Jn8*<{q}!xbr!{*5n4i7-=U&tE7&s`Rg7LM@T9 zwJWjA+0pex3CxYU0X3^X?4b+>V;WS&cRMxe`}Xx##jHHn-5%YI+zo_(hu_wn@Ane) zBk&6&M{kxsdnvdjO0LU^&OL{6G&84eP&d%E=|fI#tJmqM<6)==n|@A!E9s<1?oiS& zaA#_>U+fk5de5<}eM#Gbvn%SXju^fAo^0AoAA6n~x+i!S>`o@eR?JmcTjI%xF{(T- zP|Lqqd&(r97hLXX8-E4qCkW0@e;=S1AIwjfPsHQhWOvXWP%0Z^e_xUq}^f`XTvi;!F$ zb5#uGm7M_`orreBydNyy2=44bBYEDv$xapg=Y`(M*9=8~ZKmf8{2<5adJ*?gOW<|W z7kO%7qCcWi{N-q?M#MK4A}zTa=54s+==`Z2v&1I^o+!AYBeRqbI`!n7vD>2f0j{P3 zgpNxG;GM9NY$&ih0oUL@7ZMcjH*B|%-cT>^gkO|w@P(#B@bgTx*ZX*f*$2L(pG?nE zSHGUMuAaH~6JIVnGvM##Zp2>jZ}}LT(%}GjEL|p^6H!wN`TG5<^_@F=`ONb>Yr zwO;CP;%>4Ip_1SoIrytx%(2B;U=qB6X|IVFEk|;>!?MF1;XYGFflVY+gOk8FqqJ_( zD7Id}TY*9CG2n+tJaPCU;P;OCQ*s17kaI?Q`g;bh7w!Bi)4Z`;Wo@xnW_+T( z{NKr*QQQw9uSldNK7K3Sqq5ieV&0%6}i6O-P$>@ZDv;> zMb77nvtbtd=y zYbPRCKpu?yLfRdMf1E>)u9d>z;|PBz7Hp6w=8n$(>EE++f&Ayj@*dASTnh}bYA^ak z?nUUqt=1`6D{4BQE`Q4%0*4)Rx06hRKa`O1aOP*#t z#I8V*8Q*&gW+&#*D2})%{)UV2&4ZobqFSS0uJ)AtMeBx!C1g_RL*fHYaC+=E%AxVh z$6ZZj*?65X(k8t*iyN>ymM3A%`+Pf}RqS*amg1sx90EUiz|R48f=3IT;#u5*l>|EKgQ? zmsXl2(zDBo-D96<`wFR;@D6*d$=^pxq3yQ=&a{C+;!>q{ZpOqqUWZ(oq$DryLr$kS zJEuE84X;MvZv*@&hF8C$AYfiHfb1N9nsfbQTBeJ7q zk;dk*MoY04tnpoteBX3N!{Q3>;7ksM{>gjc`Cc1u-O5d z;&nL0UBCsnh2c}QRjS>wydi8pOdC2B?P_QBk26dgtLnWAc^zyr*T_9Kf6?@SH+ z==c~C?cKY#ocxV##pon};m)$W?8^X>>^v8K;puf~=`br}KHOB^ znu2y^E3rbdR$E17?AeA!PuIz4XN4`4lPgHo%vV=(BjGSFek z?pTXQHYB|f?91c;6LCp~)*Td^HB=s?aU$JNbjz#MNf}~=1|5brf0FOZ%xn8cw?AM` zSl$<=V*%Ut{;Khw2!+Nv$wHcSSdSp*466x|)gXw&#|rdhaK;u%!345)(!maVWL0l% z=o$3gl=6SQOr(=z-CeoCqNtH!mF|u*JMc-|8*|GGzU?+sYfLPAN`Ce8 z{+G;`S#Dufp)tQ4qgQERR}&!XurDb%24c2vO`!)^#DKhd8dJMDW24m_46-p65dA|Po zSgMWpf1aW`;l$tFJ*+2gq9q*`+QPf+2SG3X(_jVOsK+!6nf!QRXZNnAWP(^bE?AG+ zUvKw3dKpYSmzW+SjOjwq=469kF*94aVaLz7pHiooMsxQyV7(scO5}4t|2TxVw|i{& zD(aA3?&j<8v?d-d8 zxbc}hCbkXuAlHT%fWM@bp1Rz479T>+Z*$+fQ%dg0kseuDC)4YnN<4PB?HtR|%KWK9 z_qKFcCha|SxMQ~en}a4MA0!3(p)oDY)?+&v&tT4o{X#8vkdl1Uzi_ycy=$#)B0n(t zc)K*^a{(ym!y4=563R?ab=`9*&L{;{#WFZ23LdkXpSrYW;$bq7?54_b_fc?Kvmcoa zoYeYB_t|h-3KrGC6HyrOuP$dYw(210p0QzhJ_k}%c z{{|>%%FIN6CE*oL3T|=(Z(t3r*391J&KLLc?rVd(_WF8R?HYGxmdYp5K{6HSG60Ig zqJBv0`ZYQmrBAoG`X))3iA~r=)#^p!kd0*R3^WV%Q@Oy;sB;#LhjD`Ww0CIpi3jU2U;}ru$OC0 z%qzo60%>suH$)Yg@cYm2QUMX%-yk3iCL#aAOP~Hi#Y4J6TI3${6Ep4{*YFAx6c2N6M}m5(u|m-!n$TPTi}xC8kBQUCrJ2-F=T4m09}P?3_y zgzhRQvo&`N4_*o{=NR<$Sgn!-q{0A$#mOgff7;SV28AD@b^+=^Lc1he^sRjkepUc!^m4(2avXDa!`_18Pl8>HFkbA;bs+ z^GATLscWPr*!e2_A_(cEj|Nfn&)`!og+~|Et+80($RB}NKcK}LJML0p?|iKg^wFVO z0hM5N?GAm)B6MYp2Y>cG;Mmx^8p=uO@-s8Qb03wow-^yugpY6judFcyOh~UJdv((O zHj{kb7A*ULM!Bbl$aZ7MzmTQ+Ny5cR{)-UaBN%a{wJb)lw&!8?z{o#isy2I(3DM@1 zd)CFOY6`{#V)H#dc0B~-YseJ1Zv=ZT2saR7<9`hfgwrciTk^=bNGnRN1`QZ<1y<|M$3QM(w#`>w*?_Q0r7Q#_|~_n8CC+d38WkIjJK;1QvGhw z6-jil9TR3}yddvy4m`h#V-|^lVbTC09Q!$QNBEad$6!oB@U4gQHOVD$KwfoMw0USP zh8di`C|wH9n=uQ481oP@;|5~YCMQr7vRCQX9xni%5bUXLi^3@mfodOXmE;-rg|tdR zduL5t=}UDr{G_@$zy43CYIOmrFf@i%o-J8G*dwJdf__wM5l&pAZycB@QhOIu4yo|c zAek0H#VE6$*y`La=&wIpy#;Wf0^<4e>=9D~gvoD1wRA|3ESyU3HcN#1j-OPmVige21p2hDM8)CdwTL;h^o^_#=c@CB%a7sPH(%&HIGY%!MI5MF8}9r0Nc?yV5ss?nL?`?24!f%E~m& zz!a7U`Ms&VYq=;=THEZ;mI%{7(qi!x5SxP}49@#YIej!DC74h+;qJ+Z{?;I-lv&G+ z0M&xZ(V8Aqz3#687Hpe9Srp_7lJ1&QAsj zpm>;k{${XCf^q%Y76Vz{5~ez_6s-{aYGQ z4L8>UN({v>@FIvdXPJ8(=87EkNQgffVj&l*3Vwlm^YrV;G%eA<6nhs8c%h;Nv?Eo~ zhzjELPvB`0^Y0~sB0?fItWY~8uh3+B3r=;`KFfMIgaQZlnqNjXKOHlI zDUxxOp&5(l&U6uS)d%$;fD$csC1;4dMN37zC|g3a(x?gF;LZVN-a{US%Lea*Hbsi- z;C@lI;wu&9?@~Bk{_8RYnJ_}p@>1lUO?4UEQ_%a3@8-s#K#}${rSK;VqYpE#1l_xN z^V+A!fNHK~GRwSFO>JRpg7$D8m@3f|cFfZ-mVsTZ@@yp->S2(EJkjSX2x>H%n6%{1 z#XmnJ_>)y#tb@-*+IS4Gh%@;@q)?X%%m%{t?YM=!_fLe7-`Nl(u7looahCJ==QAWW zbkUdtD<6w?%v;1=^!vc4`ziWJQqD3&($0*+ELXYje-`s^Tc3eqer?LFWEngQjN`|T z$q*LDLjhz0QD&rEOb(4lR2-=TMrA?TpXE~B;}mb^E^^Nh8q|nvBv#N5tjTsv7>eYl zJSd9AT4d8qDfI%sShDI7W&SKVJ5#oPG4lfYY;!x+faZQvK2rb_C*L@64!@087IcY4*aR*^xJA&@=XSvz9r>Y0vNhGJj3EBRw$T=Vr3od^af7f@QuKh>?4mLbBr_Eq! zW=c32Yy~=eRd;ec%ylUE$5<>{4O%#uy+GaaN%W|&J4YsVNa*!{#%=w2FCIf%$t>KN zHN6XvVeSVv_g$1HCSt3SUB_zqsA?Au-C6pPS#8bHk*NA$v}DSmp{`F3wkA8}sEnN! zb?&(#GnPs>6^lO7Vre!#TGM^#d8K9OTn|sAdD9V*ZPgQ#-&YG#I_8&&>lM0}lW!^9 zD`Ik}!=y&fe_a_xA7JJr0%H4RLp}&YiTZ%X>*EsQ8^d|Z3(~%lNPR9HZc^fFC%)L> zB&s_~iJbqsd?OzOwbz|7K6ph&(!6>ZWg(fK!nePJ2k@08-JTF!#11X-F!}f*{dp1+ zr$!ckqtPj5a}?=m8tOTPk$No?W{d_NM%O}&c^!R--%f*xQQygBNpxLx3rx)(MC3tR zQ!7X6C@W<+CztHywv^|C_Ewu))4yO%ci*_1F7>Jp^@&aT^+kjw0PM+is~gfDU-8Yj zHC#4wEl&-C*>-k^Os^0)mc3!>;u4Ep`Sn zl*|9h{GqmV>|kT`1iljJ5Y8zLMUK`mbH5YsE-K!ApP72sZl@&lKzV-l@#32nd*2vvI;mHB_fGBNx| zA~XGefUy6&jftL#fQkJ-FvtJ>#>U7_@ZbA?MX<1Q5U~DdJr>sgwJICi|M-QK@xN?V z7S{hmZ5Bor0u~k~0_LAO|8ZntWF=r?VE-?hh5ZK-=J?5E=J+p*otgf}^W$ayiTsJC zCtzaz@iPD9Ffsq9=RYF5%b-$7^wRwhRF{|8oOVdh|D{-0sh3m<4_ z<)yZp?c+?2dtVbg3Dbm0%+TOCiL^L30(x?}>|cW6nDhy8pua?sQFE50)^(xb78PxN zW%=jX_kMfE-vYH=@O=Yzdv!1lbqRnZ@YXixvT(q z8fIRf-ZyrCE?3kUxG#&G_3! zhS6Q)Z#%rShzha-@rL@5x2jRZ2Z-&g?OVTugUWy|d?Ldi@4XN4fJ~W{Pj4TvTUZ9= zr`rq5&`%4OAO*8G%qaVKW*v}ZScp1y2C-b}G74%}1_rfAcY`axB}PukxPO^?`eTHT z-RKCBN^6vMzXlyrZI(vZt19fm2KGYMB!Znn&UaxBPmTl}+r*KiNpTYY1@j*;L@we> zppcOo>TRSQkl3UgW3ZrbAlCe1;22ton;6@PYZbV|xR&nuY>DbKcF*R9^!Rlr#dIDL zHhS65R2b367Ps*|k7GD?ybXZ+vaD8!M81%1J+T_}RfQQYQYd%fb|Co9uPJ zh434BjIDJ~M-cG6&2FMd_Om{5kx04ULBLpv;@;D0Qg8~PNuBl<%m$qSyE|;^{8-`(&NXe<$d$@!B5}`Xb$~Fjl*({LWJ%+i5pDDd*bi zdu{qA#s1Ei0?3s8UnM(oj%Er%cjit0}XyF_Ke~cs-mL)7~asaHNzz6p1^QEaEOjA+2XCIGi1?x>+pnOf` zx6Q_1b12cJQ&%VkD;h-rTK4-2^H0Ts+)$5yK-KcH@AXM- zu)fV6K3TT24cC%1?cAsiWN`N#44ZoMv^}-U;(t4lvVy%jRzp7mdf-tJR zpnn&sD2;v0K--u13VLElyw1~Zf{{@~tGL)C8Bp4Z6z_=hXRk(2-ON@V%vlWc&WQu{ zwF;}a(yb%KZN{#QXWTuFt%My#5(+9*NyD@{43=E7=qA~Yy8OoryO^kf^H^QU0{Kg1gExRxcPPXOT3vdL zqOHXXzS=GBn632LqvqS}w8^yca-%YL%2G({S<;9csi8hjhEpKBhFTD{L?2R4_qGt# z{~-Zg77Fl!>_1BitszGc63!dc%p57&P^R4rQd|JY)FbmLLH}43PU+P_yz$# z5gb*k8lY0^c+E~)IbFD-FwZqz=0fX|N7NiA&2Emkh^BE(!=EKlg{|O)Zq+3-yWgJ@ z2Kj>AkF~@s8OK~dM37-M-1!$0 z(G8daNZ;tE3(qN&B>9{b_lr#Q6N8~=zLF%jD69>ykV`ME#|>H%w%U8SF`)}G`z5sE z)_dp!WV}noPBLcp0yaBNj7Rnw8w;5U$use?fz%1%8W%LTvY8zHKpp?kXIc21LcfP~ zCY*Eje`R~tN9gzbnt@tOV*pGoVkBsm@QUcJdiWUPujll~2fnFLi3t#Qyzzzid99aDfin9rUDIkfXVd>iA8~Y%4+x2c zDB!xk9r!p71TLr$v7R}vLY_4Uip{5WWu`JoBI!E{y!?rAy==ESk?KmN_{Qc=G{EQq zRfA))CZdteUUp!Rxitk$3%y|$$Kql9jW<^Sws=`{D za?=bAyfn%ty-VN-wVVLdIuJD2z{E@*10-Xq3!koku!}H?-d%ebjBaQP<|;!K0^U2G zO*t(=x5BB)@|57iTB_9`c(VvWT1%pXnbS&g4g%5;7-`=%Il)EIP4FTVA|)4&mH@&N z!p=e~j!?{V?oYMSYZL4NrTa6nLi-=iw0y(hbSEu2KM+FvYAIsn3!>P-QhMTaY0>`0 zg25I6v-DmFWLwbQJud8+rzc=E2cC+uycio`XABqnR(&gw=61YF44MFY{ioK0A~uYG z_0CQLNNQ)YrbI;_#ArLTH<*I*wj!)-w9@(%ZjX^AjPmK(|3UB;I{<>g9Q~MpT5A;V}_;?{-UgLxg zgG{gD05;ptob@~?Rr3I12*9l+e_g?z z&iMT*8%2R5rI_*cfQUbp0=D8eT&~|Y(n}m*##PYHFdpfhy+*5Dz3n7W)apZ9Dq>|Q z=~esMOS|XgRtITUflyX~TEg}@fHH`JUjX$!06bxH>j;ED6^DGR_gj<4w2FXy`@jHL z;LRmF5}L;V>e6AN4I+l0BX)QEcsHHcy*Q`8is3JD-I!hZsn zbxXtbO2c(a=Xqtwc1stOck{#b^22rW=XnLlcKeSc(Txbv^&&&Wd}aP%{$n(q-AO%F zkVy&3@o4D1BDe6)KY)OX&4c?{xvp0G1U5^qE9}6 z3EGYi=~8-OWm$!b=OFhoV3r9vvwdUmNamH?E;6^U|8Yq~k4PeD%=(JPCYeoqmB>`5 zKG}#*a(dWm+G_I7lzI%D*0qDb@TkpA^z_~41jY%w*QbFPUXKhL^b%Su?<4G#JlEQF zK3wg~-7Ve<4PfG9Ox#WOzjH-VCkwx`4b_K&8-ONO5LdejyhZ6k?o~n10{6tfvg!bW zf~96BqyZq84bDkGt#sD{N46^_@f2}34dh_vms0qeF(;gtJ(8UQ#=j~+y|{vKvA1Hg zT_0b@q4@)YQ{sm6y{=IEQcs8M6^!da&GmF<^fPA^_aO*}r;F!#clR|X6hG$qy??KT8MuCv=1$%EAF66H#8uP2`Vtgo|O^BA*$ ztIs{BB^8l3a<$7P0Jr~MH5;wmFwnf!TfeVwrd`?0Jtyzc@E+sf zrJ>Wlc=JrHfw2ymt;H>wEqJx6701t^xnKOQal8Oq zxp_OMu?e|}xbYbOSvG@JzTgG;b)jB?UNKl-*Yb4c_7J|=N=&lXgxf@c2dw-j2J`@W z#fPlB?f`Xh|6u5C&0VjF-;cVhmtQeN+5=nwOP?sN0X7FQ_K-LSAirQ=q@!ykUHt7k z34ouf0NBlO%KR~&qcMC9w)%ljfkwq6(|9=Pw1LyEBcunF8{IQMl8(e*-ahz^*mx3S zs&7P=fiuqs{GOz40oDOC^yp2jCp3N^bP8+&V0;^~V6|wDQMU||fJaa%Mr;JZsLEAB*KbEv`WOZybM!-K3uwuTUATy0gg5>tPrpPfojH;ndIAsoC zQX0V2PXTM>WWUr+uF_jUeA|uY{i6R-ES_X}Cs~X}cZ>Pa&V2GqxGRjT)Z1Y#BQeM+ zfcZW{tp~OXqz=rhsXRNOUVx*p4>*l0Z-7-H#I{nNdS7?LG|WG)D~PuG7^TWzgccJ?z&(!c7H3BzbHE2_n5+#|2aX`v zTuUt6Kg%a~d^*DimlCBiQXm#;#~g0uv>xYl>Z`|Px@BkgIKo#vBxzjH&y|2t4(7~# z9J~q?K)!SbK#RPm=gb>tiw0Ru==r{U% zRTuKg6=u%}pvx8f2zYlY^sg?uEFA;C(*R(PVm&AcN%6WmwJNXX1WJ-4%O-m=j8l@M zO9#|i^^%=d>4GJ;jE^T69r*5#7PvpfdgLS4H9J{y98b6s=4YigUQ@X~qN7M!7h@?X zR9Vq{wP(*lDjEdNY+MLi`*7NOTtapWi863 zDy&Vm2L9!pnHS`6IXuI*Lgb>E1*pJ6*bQFQt#TK{=S)K=YoxYG_5sI0ZI_C(ws5ESAeGkIZtM0K{~S!pBGkE{(G{RA zcfOi4f`zo|0N#Z&7xK@kmbyTu+`-Ig&Z!cVWyVrrM_ro5g__(;1RpG_k-95Nv>}wp zunLWu`{!am5wOP9XZ*E>RpS@?e-ek;DQ&A9eb|Z4E(J$jDxz)lbBm&QP*Z_lwQ=KU zeef9n z)fiM;n|PWpCEq!S>ModNmC(zVm-CMmS%NY3;s#ZC!p{{7KI0!pba=-9orA!)F5$X@ zvU+#@$s;4$k|SkvtizP0R05tnl7dulvusCkwJh>llWpRn-g~%!W=SQm9iOvVpT1^= z*80nh2`elOz+Wq3UeqzvI5DYbQVIq&mc>CJl}@J&MI+c{-=L37yj6~mUSpbzDPtOy z!e$>+`&4FM-o}(PQu51f)7$QJ5+%ggL)Dehfv7VpCdYJ9^;#*$oi)bYZjx5C z$2V-TVP*hBI0g$WY!v2SvrsK;5U5%|Suj6t(F{V-3=y+sW0nRB@C(C3rihndleue* zfcc>O%X6XT{!DFHJL!&p_1WYk7?)@lZCH@P>aoE300gTHRt;NbYko4e@W#51I9V4=g^^j)`ZaCPh4Eh+^bg|YaeqW*`bD4}uF_4c;<^jc#`tb8?Nyl*={a*Wz^J5S zMn`=IeJ(@UW&BNeA||C6YS9z=82p4Xoe?waAObT=9+j_A2Tn%E-AtCO+xO8{&|{Jz ztk~^72RjdE-e9Q6ePdmdksP(1?@dcjIitShG@f^9fofwk%jKB!)sV0NvUg|T!*Cj6 zqHENIlzw_-*nU^vL;;cNml@fxR$#{ig_`BKo5La4uk6e>_hQGq$*X7O+qvA z*ay;_bTa>h4kbN~s^67RL5<9(%3W5aF;1q^99B zHY|F?h%PEB4f4Tpa3B2QVBw;Od~E1>lA!j@#6(b$djXp!T&cr+F%&jzsH9GoILYlo z)CB)I6DIaTNF$W-y{(N4N*?P7<;#KSS)6@d3tj}h78iSb2mD;0ovp~)mz7H+6BaEu zUEztg$ba?q|{NTsp&&(prCxu8PT{=SB>!T z;c)2-oAdAmXMlH*N}emj(C_Xa9`)*~%;yDx*hS!f$AH&{4vi3Fio8j${v4O3mw$K{ z0Lk#{#mGu$Cuu^1Q5`yX(^9KdS1G4_)WeSJ;U*^RXF3$8v|^4?ZWvp+I3L+ebuF0x zVBhG2l$oLnAPa0m_!4@lkHa@J5j1|Xm_3`3)&q2xUjPr|pAxUa*4v6*pSv+rv^uZR zK@F7JsH$9WTcQ)3y1GlVXOQg~sm_c6Aq8u&5kn+N?3RF9(&ta^Nx%P#7Koz76e4?$ zWaIBLm)|a#B!KH!hDY=4MrId6N*3aOgl z-e3~4v^1=3k8>v_NUOx8&s|4cihgU(H-220u=gX$1_WuGu&;Ob-2vf8=FuW>n? zxVldor9-K>e}|2NXI-E5Xa(3n^Ju}}MhVCR3kUJnnR^WZg0M1=1F%9>c;*s5V=f%f z7057E%otY@n>KfZ_oQL%9W0jatshL^7)S^kXfwiaWYtjH554G;lrC zsSJBLUmDL=vo_t_MyIE>;yf))=Pk*!icOc*?sQN~)X#A&0V8Zty`atnJe2I0X2w^3lx}~}seJZ1|sfVLD ze}YQBo{SVq!0*~bLD<#5GrmVz_(hQiH-9lVYT>}c0Q~as&JYhA>r9_;Z;mHzNP+v- zDHrN$@Q-V!nJNY$ryI#bU$Ht1z!zeLxDXyWy}kPq?}nc zX}K+cxj+4{0QE-5nAb%N2nHqW_3g& zb)T32{-YbkU3hI}mIj5tJ@a@#VS+oT)z=6lU05ia9hy$!#wz=*w9yARs6E_ZJPhV> zDpHC?ab2+a)s?myxI89)wl?eSdLD^y${(`b{)G8Z*>!c-Z(ZKk=r%kY*X@2RbfREE zp3W=fMFPOHO0~A=HwA5=)YqiAT_F?AgZ;k`&?}&t+q?k!#tG*XAW& zePBpK(V^dE-U#U`*XdrrG%l0_$0>kHOS_XYaWi3gqrx6Q*@M(gLC>b8$WB4CCpbMg zY4<72&GzmyqMjggP64URsG1qhxCMKG8X3TX&~+TMk_l)%O$5o(6W7CiVX#dpMSXgJ zL~}#MA6LU}Y0Jve+S+u*oScN>mvfNG6X?v1atZ=&8g)APqiTI1!v~D0+fB+Q18#03s@dQu6X0P+{k`<2v zq3Gzi4&(Fu(p2+aO+XL~%)`1|+;-d3#lvK)wUzs2_r@?zwle%qujg{CxkLqezR8l< zc5{b7Dx9CqCSC5tqnQ{F+0|pUEZXbTavEw%a;k_Foi11}IUdM^njzpsK>|i1`pi87 z;jqu}h57|6#uixDgf%JbqK)bSv1}X59{=I7>5Dln5;LjLRk~@-J~W4sY%Wa+IEX3@{`gIOqklgpK5Uwh;~ng% z0Jv^6V^jbD6SDh~2@rf%FZGbscWwG*a;UA0p!Kou$wV)O{pIgw*Nb(cE;qg(ewAHsp|*9O z`=7$wyqHJ6U*CPDS*@7z&wm3ZX1v@1 z5>F};$Q`ac5k>^9h<}m*ZuD|~xgwdmE?^ppSMY-|c4q0!mF=~0x}@5vgUwlJ+1q}7 zF|ynK8Tw7t%jU7w#HhNg;WE(TRNQ}|Ma%OsnpyfLN7t?2W{vYr-19?5Wf6Uum-PG9 z5QeA6+_Hn*ysiUvGK*)uy@6cjvDA25qB6DmmyVK;%j{xlX$R*>l>HtI8gI$-yKEp&Zg;het!Sf>43 z(CN8BEceVqE@=5+^)*@G-+34)9X%+$si?;v52JT=1I+l%i`^`{SP6uBF+0#es z!-KZ0ksHh&zCQ#i+0&&?q|BH+GXSd&q-E5UnGrDV`1*W6jtGo;?Nj{*FpBWG+rbf# zf2vC$bMj{u0ve;V%xJo28{a|?>O4TnE0X^pm$|gL$dE~M(uyvS9S~ds(u9MG)So^3fDTeiC-2g zEyTD&4!nnH@5qutolR0fcVWCVL$O6bbt*u;!k=wChCs&Hm@WN9?B+}j-~Oe5k&BXAOqomKPSfrm#DqL#00ujb7&s3p zdzQC4ssM;)3?A-D4m?xxN^pH52CCI-e;7X1_z~cio<_fhAFXxnr;k)tFV!h{-dtnB zmK~M>dRu4vwS3Sy@|#~+h;O|`yz-AqSIX_D$yKdlNnJ{1URhpYaaCEzj=GqlvMHgu z1aydT9}))qjUPaM0`Q}g0b|!b)|;%81Bb) z(vKTpbW=}+0&0Bz|J?U8Q5U?{5hel*9;V`E6W1=p`r#=GOBL0U~-!hv@ zj$Bt}${~zSc%tvc8a*?5vpsnBDB5}T;=5e#-Vx@`WY39LKq!;JLzIj2DFuCXbLmNJ zI?adebT~{vD~7<2sIplup<*IUsUU6l?~2ooCp0@`7|*eLkV=0|hYGZ6YmWrR@=WV< zswtK>dd_rvmX))6>#yC1W4r41+wH{4(n@^jV(l|>5Zd1G_2cGLn!aVNY5x*o@tF!` zyXI)O^OLgLIh1=wW4Vhj=Jr!)tUtNpPt5{v{Q3J+ z$aPAG`K2&J27>FAJT~H&Myc1Il6_6rs+-eS{tf8Ya76hfvIpUeHlTOa`OvKin!QIX zaDJ((OMb2bZC9t`l0cXfZUmR9i+?pTb@E;%9_q=6VnSIjJw{U#tEGuEq{2xlAeG$J zZQW`LY$6JGO3UC^U5h=-Ht8VLHMn?V1y@bJeWr1&g|em|84nl?tG1I6JmomJ-|3if zFFwh328jf`UJ&{?7&p>@ODe!WJ?1{Zi9WIDci=t5As(BimLer$h@?f_eL*;b5d|JK z$my5|5p6`zZ7hMLNuK^Qm+xCm&4*^FY6(IXmpnQIm$to`)lelVVJB*kAkS@HM21a` zE0X-OrK(ah+5450*4UR4nfDuU^f@_p)Bf1|dGpop<4FD4bR}|*IYE{pA=MOTrssWA zQI_lV&{1|iq3$Xy1LXE5F6=omh~ryU3!>_&+=VJj;W~8O<~TlkYCj$~?abjyFDkB5 z!eoxLF=(2;G01OY0AXW*4uuN z@{O8$ucf+6ryRj&t=WB>^+!D0ikqW0V~FB}APZ?4k3$y}9m>TJ>0;Q_md~af%bKA7 z+obiIS>6nN%{G6XF?gM6xONeK%tSDv`2=)1tJ?X1%yfhwPEOw>R8ja(8Dlc(Qi!Es z%mN8|dF{>;sYv8AfQ*c(-{eu4g`>oG$shi!m{BLN3irW^Q-DGd__iAUT zb<+zUnWvj+-uTaITCQf7^~sA!fmyp8DPL8oM1pekPR-EYN5d3lP;==#t_#_A6@42) z*($%X$qULbwI-}|tV8m`4u(?^Tj~B3F38uTq?gAa)}>kIdB%_k$<}zCc)B!wQ(Ler zeiy!yPMiu`F}bCgEtMSA#%O`-Gl-$@HhQulUfpaY`Cc&RRd}%lx7lK?3g9twJXsHT zs=7|fA^E{{;+OFe;u>84uj(RV-JWyW{O19=7vzhF1&xXB zIW`j4idt&dU>+{ZwjOTlv6VIV3?9vv%_i)=lD!QVt(BXWQd7Xk10(??11JF~0zB~0 zxi*oYnVE)UnLCS5x#I@UZhb@nywKZhtR~bZyM( zm4(5f4LU_37A1s4oX6uy=G!RfuG{{MW5#7E%PKLJ*}V>Da<_fZ#vhhegLC*)RuM&c zF(z{luM^GC9Z+)tBb}bzTZ(0|q(;bsatR=v*8EKbkrG)+tCc#9^zuuo$XoyCuGU|rX>)aP-Nm`7^{8Z5)zwrwfNE`ft%KZ{ z;*R3u^nFD$YT3Qg>@d-vzECuaD7*M>tM<~WZppEXPNeFK=d1CF4xXq=hiYX{9Nacq zy14?uDSu(N*3{6*Ph0aMQp9lh$W|yjK;EG+O)qr2a2Cb3&AHjXIty(dSsAn`C2LpE zX%}Lx(=8E05mCFi6P9p~j~s6=I?tB2MwT`&gp)@je^rJ+t7X}iQKQ&7GU~*aDVk-f zaoD0CwrE9=nWbcf&e|+}F@}digeQ}lgJXmG+Ug3*m3z|=tjuT@kxMPU^*b6^EGsMF zSqFde_fyidu3uYs5IQ%*O^Vy1dN%2EzWrO0v&yox5_+BY@DY${R?A)Y1^Hyx@l?(t z7G>|4qBNu`Y-N%ul@y(itzN+qh*DR=!Iwz+I>aAf7G*}3?41>&(Fd%y{lPhN* zUJdc2!gbLjVOc%)^b{4Yy*JC+dtk3Wbouo~X1CD- ze}3nu;qYORsqLC~eru_|L`p-#L~4vjKl5w>Y!b#tK=5~&OMvuwGMWTBkEo6I!VFvm zzA(%Q@LyxMs1gH?uTMzncxS13qrf3g1>+Gk25@^LDhY*76eR_Vq@UWzVOS{4TLJeD z@`pkBm0|hTSRd^|3_*-zAq;3l#e%X79N=Bv9I*@xMWdo>O9&1TvvB9_2MjPOzviah-z6aE#BWg3xCRAw~LI@o?4xHCA4DIG#?~ z({*pgqeb-FJ%sXGHhQzP@W)wQ`UbJYyUxpooXIOMZHuG>%Xi;zekt8<-BpRQ8^E&P zA7wYmRmDmUpv}@n`j-9rsZJSEevOfMVBE|A zXdMNV3EOBx-|H|mp94DE`V5ZJ+Huu6p5*jOom7&tAqnhAgEawt>|s)1#m>@;#O(rd zGZim>m21R?^_dGrfM(c00pbur{Y93ciU~@Gd{CNmXZhFVIMto~*sj-(xK5OB+7uk} zDXJy+MX0YZ*z}|AZ5h4++Mgi$AFSd{7`--zS(c2o8pS=IXhaTl`eDZaUtwH!9f(du zo5Y7Hw5H!2pL2`z)~gIOk~U;_(ofa%fGgY%1>32cl$*SFUP&QWkdgt?lzis5h-pHY zOc6}$!Ge5@dubA8*whQ14;N2SwW$N>&TeKn%ez+L>t{o z7)x+|aly($AfzfO@tn#`=xX=9!iBDUeSHzKCo|nfsRTf~!E>11U6~Xnx3!xVDP6A= z9@||rKFd|#8cEA+Cq@@^h`75yogqiCJK>|Q5GyI-O& zcZZ6KlI7>C)(c6N-^XNud7wrn>xE-VxvZq{tQODFt&K23RutO_w|vU<98o z0*i9<#E(g-U)}+TObPkGm?>hVOu{?q|7R88{Y zCt6leIh5}!8@_3qmsJlV{~T_ouqaVake+K%5xC-PbgDC_job_GAXb_8OqTP1(Vw)? zTYzc_?c_#-X+!o1as;c%+-albv*~R}T1ZER8`>RRIl1Lse>eS{{)DG!?!0Ft-1OP3 z)omA+i|t^Ud7w@N;aN*HdnyZMNBUb+Ub)4Y-QPud8oYT8fXZR&zM===*nbxkh29Ar zH1H`|L12&5FsBQ~d4@(6WM=m9?pA+{O(_sAb`0zT$W0R0gSUkim-4*;@!Qra) zdepMjSn;v0EO`G&5XoBUh*qIUL6@g2jOxrnqp`eE-O--Ug?RHeLD6E}VrOXh?axfH z>#?x7eA_Qvu+hg%eT5dRSnn!hY(6a=@_NDUmEe#+ykj0UbYTG({}My%IzY>7KO2h? z*m@ln*%k3aQ}#i#SpFFBRm}GJ>>c`;z2Gk6Gmqi7f%z6Qy?l3L_=SD2yWe8H^nH1~ zI&EF}`W$H*MSG;!1!W_>7x46Gp;=GW7PeZSQGI)ywV5!^>W{bHb>y zMPr$a1rMf<9NSt{#yo3bl2{7IVxEqwO@jd09!f5yeQ>PXFM%8lr^QK zTUyeFJ$osN{fBAhfjI!$RS^^a7$9Cp-jk6v2JzP*p2l0)l{{H;*XE*{WVKy3UY`K` zJslT!y61pf^pukQeGVq{EAlpOwA0C~*S@d3?-0P=Pefsy$^hHE&#{~n3Ew!|qNABu zR#q@&Qbt@8KU93nm(LI#DaDE`Y}dEzZdIbmxjkJH#YR&XB(;UPY#eRnVP2)BhB!Sm zQdhx^vRSu?gh#hPB2(_?h{qq=+5t6yTEYA!*-*^x$s3uTQvQWb7G`k^^RP0e@r6if zQ7h;kl0lCMC8!jCl$F18Yd5Um-mqosida?odO33>QI_=<$Bj@@sK6I=#==6?t&IxV za;;%dQa-Jt&`K^-MK~vCrDddL#a6?h)h=(c*qmc%B$#JNETd`r&lfj7k;htyVzvVq zZ_9vrj~jnng_CQD{Ec zPUu8?dUg}+U%Ga#Zyvv5UVVDGyxrcIM1BtX;J%C|))(-SfAHUC8r3HGFgy9OVaupe zmAQXbIqhCD3kjQn27!7(xje*2R^0PtLUs+U!6Q;i9F=- zuM$Bpb!x95GGPT|LPQjNwUzvru=azmZd!!c z4^JHxF#+GuWo1d6=%hI*^NNd9SB!LqOAvD+Pq!@@iX=%L*94{sM_m_>$s|TK7j-*3 zMfQ(Z{Y_)Dm-+UuMD-_m_79zY5Bi13Pn{8u{<&V@Tcc-1Ne}j}59*~sc2o>T!&61$ z5}Ltpot z*#0hsg}5S|p-cGYXaSq-;XMhw=)8d2KjvKGumepJ-B=;F3U9p#wM27^GT3h#;IE(e z?-FNh07kKc;#>g0no&S(Fa)e*_B+r^u!P(SZ`dKcWzAz30LUDz!Jji*94!1XntR@j)}Gws zi1?E7k~6p!dOJebkUfx>HH;WIYch*gFHpyExNlAXCJPTHBG1V1vA=%M;=#|&dNDi z2Ti5Q7tlD|OcbJ8U5Xy|@;85p?r+iG*yzWUi5Oa9<7g!hpl6olR-^10j;_WarObl_ z0cg3*NtDd^ePK8DWM_i9)`%&z!?XS=X3JfEBIywN*v+o!Q7Ge^iNZZ zTN3R+CrqP-;!OXOxP~}2i?~9RrqMOx(Qr}eSYBuw>l%>L=t7cNd#=>OyVa(KKqj=- zCd22}Ohjgj`4j7H47TWp_jFj?)63mxcR713@~cULqmLl(8c;r_AI?!4u&e-2nZGA7 zSzC<4j=iJSJuhbJa7mIv;anx#=&SEU+NNO!Pgw2MN8NOsz$wh~n5m@)Y+6G!J+9qhd`?&Tq4cRcf6zBH@cQd566W_`01W6o8mc7STV^OE-Co5T%a zvJ`IdMl@j4UyD#-3qGQ1=7^(Ho0_37z9FW_+tkVawlrTLwT3$M9wd=dU?71JY`%9p zKP$IrdWM!P9~?b8$0Cw-tUisdD5!&8RKz+>Mr-1u4^ZVWiKPwA8Lb%#mFkL-F+tG> zqC-rzdB?Ki1uDc9o@DI);)!_?P|L=O4pttY881`4+sPF6>R-0x9rE^l<7n!ukV!*I zKjf?+PuhbKut(;a&2;uD(AIBsx)`&(pyONZ*`le>+N?F=ZWQLrv<)N)v}=LZROOf8 zdRm{(UOJ4p7RYFVf4dg;7#UdyU81({#&p`kL>%z+Y(jju^{YQ^FCR^_k6EJIaJ_7W z8rg-e$lUd0z82X%2~Ekimp!+X!>oI2?a{OrY0O>|1v!H^i^)Jg7HGyXL5{NyZL^~L z;rMNU8`X{7lYcq?u&D1E4t9hJZGX}A%P)sE`=gx|X+39aD2GM<6DHFAJa$Jf7~ZD<-G zXyf?cU>FpIpK`rR&Xz!xc;YPt54LP)dlV#Oc%K|F3Yn7)e?Ov^VN6GDMxTh7(z6z+ zR!X=Ob*lD&)#}W7K{Vq%FK5hf68orrv|@+=rKrKZd>r&9iIC+G2b1AIh>yVQ9{Z%IopVsCz_sjDf%SKEXoQk&G#8A zC}^mtaZ7z_UmD)=8rfYv|4!9T#l{{>ZG`_JM37h})B&d&OO2m;K^^z8o+ znEkJphqtmyqu+8zThh$Vx{x5*wnbySECd$;bFmO&Yq&KaB8UV;06rs#1_(C(#U7%3 zKd6HHVEJKrxHIAsh`jxa_j2yLo%+N0>6zuE!q+3m!z!Fz&&Q?uj4t2)xN8`5 z=o#g?DH5$P{^8OJ@^zGH=_lVX_Ky4Z8@9;~b!as_Ue5Q%pGGr5mYsLTO?F7f}^6J3{ccLt%etyv^XnGvpb4J+6nJEutk~ljB1o`OvyQLj2!n zM{<}Fxpn}yEI@bG5z(fg?VR+`DOQj(8>H@`2>M)N?m}RLyjqbzSVi6BOyqZ{N}fu~ z3-lQBoQlt|mJcxeZl8($)>*tDGzD1^%9WzN?;1P61$i8#*ao6RuK$O449AV-qnYg{m`+F|GG%-m$X+y{C^&UqpVR=Y^QckNmcf6ghH5M@&DddV}G0fsk-U zwXX(j-6CRdoVtN1xCP(pMNr+|WbE{by`XKk;N6mN0)AVgOaOF1FONdr7lbWb<@g*T z3+t6{0q(^4**^k!4}JE!b_L=WN@p_F`vN?>}@GI@zEf?sZlK|Pnj2e zIse}2yQwek{tA4hfO)_${(zbHD0=Lg0G!v;x{(>TvDy98Imw5ayIt5m)UF-uoCeKx z9NlEAcqi=wxKl^y9AH5-LB28mI9fG!JbI{al2~xF*I?U}*KPZ145I+Nl}8rtNH_pd zigpEwgd<@-HrIqgJuE$i4POCBKU6#b+iT(iwZYoNPbft1jNuczDP}NgDWlV;eV;Ra3z4w`R2Ben;>WVTmf(kbM z4bL~ChWOIiWS2HLO?uRlg+?cV&V#u+4Gq^YeXecbY07I8v|?*=O$n*@S4iGK7Dotf zH@M^eviC&GJ%x0@0rfbH2TTZvQSJW%dO(H0kX+8~umk-zr<~cZ1Ab5I!7JXrvMv}a zkk)2b-Q(3UdoQs-CHnP%-@4xk@Y=Mu(U)q){!ygFXI`Rzq;9E&50|AZuO%6^0{+*AAIU7%WQQQ!g}hjTw3%N0C; z-N?J({UL-8Bz?C6$j%UUq4#mb`2aabn$}H?-c$}0A(Q8o5yoH$May;a1!r; z3PW%M4Djv}96S=%ECDxBU)flwgcSo2-f3PmM7=sm8GC{D?E{xmCt@NxMsgf z?Loht^l$J^Ci3}^^Ubi!2P^#Phx;FC(?qz(h9Y$)imJhr974X;d;DwVYDdG1J z?m+vKyjRONzUM!oS1v%F@yC3VPh0qPm{*VOl%D=&_;Z%XcIeHEUhSnQEflFir1tS+ z=XVAY6TlUI^uI&s{4Sw0HY;73)1iqvzh~%*{`U@D-#>Il3wTDN-$#}fi$tlV{O>6w zPDcMclx@UbXLW&2kC9{~aVO|p2N}2&y7Uua{5ei(v%=smuL33CZt4WG&o;mzN@q+FwSsU3Q|H}rKM zfCgQj2^~HJ8r=moUNTq}7A-P9E zgXP*foI?`tKr4r`vLtNb$3&cng$GeiC*cczs=SIL;Dryd&i^YfqO-5=vn#v$-&eHi z{g!%{*zb>b^~*1_to@dFS8s!G@4bjn-soF#-&KIy&(hW04K^pi&O8I|n?eH-uEvQ* zbi5_cQM}j)UaCR+X*iSBIDaK~VdfEV0{X9F}?3gbm@UJ956>)1u7 zV28d#$59>w-ihHdzFKk5D2|4=evTI@=+8xxv-lfu*b!wvq=Wkg;7sMcxCXaE7cGO4 zyb$Vzu9}TafX?O8Vt)bBkp*2Iq3$ASL6jkmKuYTHoeK7;H+FvAF7IL7+&t9_^b);< z^M&kU?^0HmpnV-|lX7Ki%Uev|TJjd~dbc<6pZPRrE9rM(u3l8nYrJpKc{$fYmo5j? za~f`}dUdNTrB9I_0_!0Wl*r*v0IL9BD{xT^zsk>X3wq7rUAVRPV&*fjZ&pwc^`;2; zIsbx>a}FBkU07%D06yd|_#@o83i^1g#6LT6O4 zwDz8-*^s3mXpV5i;W&whakhc5ghEg=U!9J8d-N>zQB?jEwxDvzn??=rXPo#O{3!p4pBAa$lU?2rx_3PA zP2R?T<-ZE{0zU{#_ho)e`LXit?qv^3&Di_jp*7WeW7+{*a0}#T8T`&}xRG`PCsGC# z!{50FJUbfl^crluZm^bOaUSs)dlFU}2@h=$Qr%Fti0-9t)Hjh@dXQhj_`m02ydONg z0DApCDuQ1%PRZ*cSmzaVJzL=;-+>t?)5oxgH>2-AjZf%5s2PqE`~kQAHITL#XslI` z@E96^8*nXFFW(GGzjY9Fh=e#`v${J58HYPGd9%{j{>QI#>qM54g}33M@0H&<)rl1; zD?Z!@5m;pucK)XhjqZPw`Y39ybaP0}>_5A%Z({wLd^Z0VX!--s=Y=@EU8*M>J@}zL zco-dKt6HfSyZgQbPxpQS=2`MPy5c7@`skDjX`4+8=?1k6`^B8`nIF1-OXdK&_~BUy z@_kY6)BvcPE@zl4J-vUvc;v<8M3NuP|9^V^pQ-3BDxX~DE*Lh{H6(v<-k<^f`}OV9 zJGWO(wlk||W=48i4@auqmXd7ko|M=vAwDiPCORt85)mF28WJ324h%5qnqbNx23zIC0lGRa^+;( zN*p%Nkz$9fg{Ms@NBXW}M}^IER;9Uy|P_$Q*`6c@iDPC7y1MVz~m3mR3?V z+cSPbc}a1S-CmKC?ct(o$1D#yhI=BMstFaTX*>Z%ot+O>|A8c6PVxd`; z&d}M8*;UiaJz7LV4#} zy9_HTFb4XHv=NmJBQW)P5V3TU4YP^073CgYiz#h#CvsQb{na>1WJ%?9HcyaaxTCh= zx=I{PVuOb!uCO;HCc0aV)09|ZYbYys*gXYFj*6<{?u{|jFmXk5H@B_Zr8PO(jh09+ zVH?9Ee2LJo&WW0iI+aq*WvX;y2W45V$T1oW;jvZQu#$2I_LL`snmlT#&OgO5aE`zMjUPqlT<%upT*OG)UC6Y8%3#Odj(O726Lp^#L{sI(J&u$4c zgDX`D+eUaSm7~02MX=reD?7Cqf0w;fbg`RnnVx*-rTHP3*=DjY+6G@ z@FjI4pn)11MmTIE8Y&yAT8#Qx4x7c%(5j_t=?!%ymHrcLG4`%Y@{CwtflbtMKDbrT z@J0vUF`?1TcTAdA-fAJT-BDKF1Vg5%a(G2!57d>n+Msn+sgR|zP-bj0L!}HxZxUwJ zKB*PTyZb2(gb@z&f z1{=VE@vEnldqa@l!`H}A{iy*P2a=;Z#;%Y`-cvsd12jx;nC7rUhgdO+x5zHD;oU3L z2sno=-60GF_p8h}s2yyY+|S*DC|^a*;XV4+%Qz%V#Z5u|3JP}E5L)%9l;6dQqKv}XEC3{h_7bSa9QlPaEYtL)XHT6ir)O(t{_2~Ou zVWQSd22g05v~{?YQ?zS+@l0R50dW@MjlTFUZC%rll!(G0ksI1BI2^WDLDqg*&t|gd0>iQ-$MHxJK2kQR#&$ zy-=kKRJy>ImSJwEFhzwCGSnt&lc*<3CTL?+JYFk-t(l^YLte&LYok>>RvW3}t5BYR zxD@T85RcK+du(kq^2LZpAur>R+K8s&l-`AP$j?NbzK)Y1Kq&!z)GMA<7A^>HrADm8M3t;>VdKBVm-Wu6wT&~Q^Y#? z?LbQw>za~N+=W464~+*_0_%YFVo#GPDxxq3?PS|r;5gt+;2Pj|;BKIq3cNM$5K$ls zv~gmbrh~hCHoIJXRori&H|}or#-WLQBMNWOdV)+nX**EEl6zvwJ+W1PE(IvSIvI2T zcocXFC<&ecVq}0A8Q5S3`e&$C0jk}1Km(|Oi83($rEN^AcM34K(HJe~%5o-M|2?70?rq0muZT0_*@A04J&?<1{w{ zHURDh+yz(>hAnK;S-61*jC2?qG_GgDnshX-+J( z2px`C82?9wyHt3C3f(GdTI>QPh;jB-kFnUpi!&TT4}m(%U{aCEHt)?u~lbU(hiEP3EU5ke%-A zz}Ew32D$?W2lfig3Cs-42y_Id1jd-7%ocOFIn*3%Hk$*?x>>;4j%hJYyPeWQj0v#F zC_tB?uF@9yc3nA>@(yIPpfTi$)=EX`q~ToZIap1lvuvK9COKL-7*>VJF`PY7rBqrr zJi#-_S=th4O!VYAOFcp3uPJY2zPkcBkGKQ3c3F7~8?tC^k~H93i8*`iT}i&UqC)m5 zZ`Ap&yDBJdSwTWU)Ue3GBZ_|}sPu)-i%){Ha|SE1dN!9%D)&5Pt?=}f3By`Z3d%`) zzg6UkfhEPQVvvj~%3Fi$MPA87Ssq+pTye1-*-&2GN_H8kc4U+7$kwG@vKS=WrOC+K zE?KopzNB5_PaOeN>a4U`B6OBbHrL$D&D5(Kfde$wgO_0Wlt(A)SgwKykubfp~E90t~ z7CzyqDfSdOifxT!R$gB3St+Z>IEou-Wl33i<4Si;anl(0m=Z@-aYggUs;pg?On0Y$ zy2h-kpBb!54wfb78oBFds&~oik#eqGa;{x+u95DMYA(g~U`sO%uYh%~;${&N3ZH9o@e>pRXC)MlZx~Qkf~UVg$? zWkGSIV>l(0%qzy<;>Etiul!pqpC#8WzE;KRZ}F0)KzUH|ClyNwdngQ5S~&&!St!jc zHL}#&+Tz6(OGusS;-w_VTOxyt!*`^XVq{+2nGI-h*GKY(le~!G7B6MAk`0&o7)Smr z$BAJ`F48xO{w0xq4<#W^)@I=bC*zb4Kb8O0AnV)P3`4vR1y$xl?^6c2Uxj5n)*I7o zI;MWV@BqsC@musHxhVqW$4F!1a&pnVbR!+7$;S66wbP^Y9c9yCsx{ix_o{YYMUS%g z7vy>Lp8RGbT$)q=8p<(?duu!S7RtdWWwe>%=_p3bGJ=tB7FOXxuQGZ=n`zEAdK*9R zLH%`O7Cpi)aYBEF-lVgfs#E)|#yVrGv5ms%N6p&yveCy_fL@cSl9tkMv4VPfn2vCT z7%C1JcdGvrs6pxT^aeY@P?fOoCZhH4XbZK{i*%GepwF2(f-||E-{WH@YCF_^$QW(R zG8R$^T}|Vu9<^3Z<3ce_o2Kp3-f#P?{j`ycvCC)~EvK7kgZdwe_vtV65o;n?l!?jO zE=r=I>ev07K(mKI$=B%=o4G&dvzu?@r^PZ|YdeG+U#D15aFn9{CfW*`{(*MWA$ptM z!IKp)>T~bPjU_a0=Esic7KIEg1h4 zUjRFq#cJ`iFklUD)Lz%S>08>bZeP&8rM=ncZ;SXW>O_wfn-h`)vR93WyrC#R?uw}^Yi z9&t#V5N9;fCc&p!q}`<5tL@R=*8Zkj^lZJiK31>PSLiEEWYPlS%x_+Zzp$WfR@*~u zFSqw zB!<8?+6OLQKrw+^1MC5I5kr>1N;!sjP~>P+^>i(imdIZ=iD}|CQAv;UemXBkfzy_0 zN5l>>Q`@TFqYvZv;cvX8lL+IVsE`VI7|!lJT7(nI(RS4@L<6}-d+|cIwoJhn&T^wRiW>R6{<{7;jPLWH zq!pZNhQa*_czP>l`7_zIbZ|``nFRbg$WtX`JyM+G--_#L9&ge9oBtpRX&lvPi^T}u z+}>+fUL; zP-hgh+d9b7DEg4&_*$Nz8=_P1*|+`fqVJorl)Ejqag`=ufy!9>cwr0XkjnFY^l2ru38aDXcBzl2^@`?2jP@b&~Lr*9%k!FNznfNA*JAZ z<7?xD@kHBEjQ6>4Ha-=fnoR0j?>KkFiIC4jggG#nEF8Tg5yL<4jt-;5kho_o z!#H@D^%=NPfgHGBjK=NI&R0`{)AG}dvuDm&&YYowg0q&h92qqje|>sGEouP)j@0xF zEqy@$f&Kc%#l~nV3~-9FVaM=!_liI!#Q+VmJIZJ+NRkO6K&%0gpkx; zy&S<8%tM{ouAx~uF6kcyi$7{F>F=uF>sB^~n_9$e?qCiMlK&MN{C?10@fd}O7u}(@ z$ODl_BTq$s7io&z%W)*ci_K=pev5eQ+1}=b@XPj#2XUK!&*Q!O`0=cz4ZHdAENJJl zxIj;A!|vO~#RTRW5n$`q%@)9ORWc#bX42nnPfSlqN#`%TG1iiRlROB^Do^CO3qG}e zkt{~gn7o6ymEYqJy1!%niGJdrtifrNVa-TR&l}l&YWF9STa%B`F+OJfivMN}D^F$) zjf@&TnczM?D-)qnSiL)Xdjv;Bq(q2_p3xBzQPI}Wlr&jxq15rIBDH6FYHC`#H6?d| zEDY(}Z(!fP0|r`iLrf}f?x&m0Cfyp66zd%vyVaV^B8Fv{oJW*wO^!hk$ZBRV^>1cuV19Ymtgjb)8$RX!rZ{yWEJIXEsgGiXL|3s*O1 z+C$?IyKSlVm}CkKi3yZ1KH^h?Z1vKLW=_mbv)5bL(!%STomuq>Eu6g;;<@N7RNIV2 zP;oAKPz43@NY3EzN9dcuS0-+s-ld+nNu{116Q-3nhnu6!d3hC7>IwA~wZeb+rpXqQ zvDf$)r5j&1JIp=0<*BEFX0V^Mjsa5mC3&IB;{9h3-9O!t8W0;3*RStDUDQdEzH-ke zH@vfA#XE~nZdUoa5ANUm!3Ue~|3Lrp`~peIKfbo&^o`3;t$d9?OhER+YdcP!+_C-R zk3ri_psh=*rx1$gQSQ8`I6W>VK2Cd`Uk^DhJ~DkAcswLve&D=FQ6p;fdFFY+*M(gl zS@S>beFs!i*}Cvap?3lZ2yy_W8R3K?#R36>L}?}Z zv5gITAA23g-h0Eb>%aFtNeGH_=ic?tyYH=qTTXWQ_SefPDU6&J#`f+sD|Zu`nTe6P zJ4hCLYOS0i(W_+(^crPhAF>|4sfGaMj|O6Obd;m5yI~XnGmHW-a>F{qQ-(JUUm6-1 zZlm0;b@W@K)q5tmh!-~NnZShb2YvjYcXQ*bbX2QdFM%GK5^ z(#X!t7A%5;gPl!_&UWy?u(Ps*5C@`cLC4h8+#2iz2P)0Vts}hjZTv5TVuyKpU?IU+ zP#|WcZ?BGDpY1#F^*P1%z&;8i?N)X5E%--Sx996iicQ@fip|%Tdly{4F@N688z7sn z0@=J5tq5FM+eg_Av7|6fl1=;D7TZ?Z&NQ6QFmmyL4sYgm#M8~q!_&j1rTup5TFj9W z6=j05sz=MVZ6HLlPf}|ipEj*M+L~F~p|>;`7+HYR20Ke@)7EV|U~LUeBdy)(M)n{;#k($mn>iTPzBnc>K~e?Jq{twd;^$Y;-B ztG5fJsWMDgMnT%klAfCX5Y-Pvvja^ zLDq$DRkUy4UK1;zNP0m%8`-!wow}&hC5t)T%A6RcmJH8er_ic8iWT58Jofft>EvP$T*q}>?P)(bn`yBuO*G5hGx7ydH8tnvZ z^cl^qxiz=u*4&y~b8BwRt+_R~=GNSrTXSn}&8@jLx8~N|np<;gZq2Q^HMi#W-)|U( zMNr}Q>H1kF*?H^E#Cd^CLvOGATL?KcTfEEruieF|n~m#*nkF(bQ)nm!G~?Ph5DbUhdY z%-n9Xrf-N@+U?c!jj&K1j4|fO=&tFT0GLynzJ(FZ?i&0y2|5kXGH-bk_2GN=tXsZB zeM30!f_`&=ZUpCD%u(MM^<7Zk1Tfl)W~%9vIwbp~4#_^LL$XiTgCTWD_DLO*eNu;H zpVT4QCv`~nEi4^fn5b{6$G;im%`X=9&GqIjVc#zm^{pXqej?OofWEDt67}u$;O&tf z$i9Q#yc60x67^dmS|m0lk#)>fonu&qmTLJp;C;;;k1mO=>*q9VF9OHqxT(Dn_ zsnAFaUg0+(4FpFKg0uiF9*nZVtQac-Gsy_M4A9lmNdVZ30q#P82M2iN0H*{Kg1!*+ z6<|%Nql4?XC$J#U^U{q%F(%?c05B*3EDq=j03C=!h~;ZwyMj?3n1!o_fJc>1Ca4Dq zl0*7aesYj5a4Z^(v%w0S6(CJCmXX9G*GP&ZDurNGh~$N%9DutB>{X(fLI5Q~n!~}o z)*kRXa-eo3XrBz}wgcKPMi64G0R0Mv2<;UiUiD#dG_L|PP=5-Y1smjm>uSJ-1ng7+ zEyQT}lxTQKY9x;UaR+@tglI$V^O2l6|B)X-f5`>(qzKdZ`yzhIjSqm8AgSa!UHW1@ z5R^(MV|zd$9Qa0KEF_K;jE})j=lst`f+_lIj)wm$(GU;jNvOb<;LC*)EB%~~AL{FQol*pfpk^ew{ zmZ2CH{8UoX_XLf+ii}0M=159K_F+~~XmSJOR%=Zy9ta6D&|mo|nMY+B%QRruMuuCc({zIr+mp(-P7lxKdF@h|Y9>?=Y0 zw9rjwH|BTQO{@FwcSEg_`BYzSEnf}iKMhgSP>HlQWTJd8M^tijW3irxD9|@jOOe0j z=~Y;g>ukh}SW~GAb+**cC8P}lG!|E(D3R)T(8hIRU;6u6)vxfRl=_vXu}?Q>q6q1+ z;6JpZwi>|mGnqy+Vm%H-=m=>x=%qgZ85@;)4M58P&02t*c<1~H7 zOP-l)t4xD_w3VzuNBTLX@h%n06{M}QHF7sya|J)Ks8T1r3VEpvVJD-Ati1Xa{Xg{p zZGDT!IA}E)ivy!{P%U|Ah70C!kVSc5r3VmyT z@W3$%j5APSQxi!}Q^7p0ldv&YTtrdJSt1zm0RDK*DjVSDB7Bg4NIwqslXQH> zX*gvg9YM?xC;Xgz0vf^DH1L`N;P{9>8_7&^n}lSD1M8$L9K->n?5~lPgoFC&p;>`8 zg8U_b)*uxd=^!3))1bc?@Ctup4&v{EzNr95FbT+tBxE$&4`qbXCZJJ+RHUV1kThKM zP02Xe%LY9*;YDzX(^Wom56Lvnmi zH63{(2SKrs#C)BH#3An`xz~CpNh4X06OtaZtv)YWug3o(Mo28$^)!v8f7A=qIveQ( z^2OIt{uyQvn=A1^f)$FV=85q{xlFDuR*3N!xl$ol3e*z0%pYe*xCe*mi6GnyzJxMyoN}(9M z<#S9|p7V1Z@x-}>Qh`#t7NL*ECs86)$|0A&J;X{C zq}bj+JWvAyAX4~=squ0kf(Y*>R;#6ArEUkVDpV+>62N$lT&DKNGvtMMfuI;K1R|)R zvfwnXmg7RDSfCa&agju&019N{0+|R`C?#N32tdT(RiMHZVr79utp@0_i;<$V>QI9P zpjD-|lLIL*;VV+7jva+kE-DnNnK*O<1JZzx1W-|n3!tHt5gvk?26^%6tB12ZJ0fz!FF7p4T4Pul_Efi zLhEOLUkb>OK&6rkB?9OlBDt`z09Zso#PG3+-sMm65yvKZHP-r=1M>T1rd~xi5JL4k{tLdMha0B0)bR{C}08V z>_Qm4Dmba}5+Gp!5L_h&$roUNw$^B=Nmj{#2PDa$(P$bmQIsby_zM|f7!)dHfEh7D zAd-WOig@WS7OJ%l*5Jp$`9%^GcoC$F3$o<{#d--Jq(B%lh#weaiUv>7EUEGYK&otU zqsSHL395wTRchc&5?~?_ykwyNl>%VA#dC0ea$IUUo5#Vqd_0Ah+=Cm-iN(Fyd@%NA z;_2Mf_~f)y96<2cNvRolavaW1%D}sElVX`Tr)LU}!{_74Je-@DlECGFIc`!+LRu_0 zsS6$r_9Z2Qy21sK2#}^G+@$Pzicn0PQ`M{^UnsToW>j+>eUamE3pY&?a{ zOXbF-C9rvTN*XUEna=^_V*%PEZc-c%P~jwUl2ZKvRWOHhdVm4Wk7p+&AX4l!z&#J~ z7n7Wl!Q*y`PsQVt6Jj}FGMWQ8V@D@&NK!zkm;^RAk%`B$6WLujXjd}8!b4yh?$YBq zXbR9{ga0w9+~g!EMoe;2Dh~{qKuTV!ZfiQ1&tc+h9+wXl630sh=%G5nj%0)c>`UU1 zSfHx$Miv1eaGb{HH1HD3VJ84we7IR3*xv%2waC#G5WE_Zp(~ASte9c}t|$6~@gsCC zq+RE0u3kjseQw%Z+6LM#S{?ZNmA0L>y7@kL^L_4rL$}TMx&OKQ+~m{4=6l`$H}7?m z)@#1s-F&~h`F?lv{qFCxdGkH*#`nCn+G)P;-F)A>`M&r6y8GTBHXE)n1*lGF$G6Zm zr?}BIsJPKpCc4g~x1zJ?-RNEDoxm|1KnpXWR*&n-e`WJm!a~O_#Q^YCgxI8|(G3~YG(L+#*ua4?!!%u>%9F@))p8ljny`eEMhqjK zSX3aFiCC=&7dT_euy45At#^l?p2VVK^KDBJjtaAr=J!gVtSjh!6B@+R7lqgJvQi2~l5j^%T34nHZPeRN#= zc7d@Wf$hQrV_2*4VVKny&TU^`r>cU_b-#f)!XUscR(C@+f_?N#~w&XrD3hn3{ z;kcmk%O~c%b-CZv_VY}}7>oJ zIh0b;Z(@|S2ld{;D+8Spo*%UyyuW0p`@TP?mUv`&RW5k(SyWj@N%%JSV(_TLqcfS~ z_7%Lg+RE_!lIT&oHP~xg>(iTNm%qC?X42ewNgKDcofly7V0qa!hhNgdd?VS@Xdf?6 z8L*d117WndoMHkrVnDb8mAYEe9q4w}A)i;)r&RUr*`;0Alb3F8wb|?X0lAQ?C*6^7 zD7Etpet(4*r!ajM^=aUz+P3TWhtygTsSv=8o=9{fxYb>%ITbOQX97Z{)W1M$Cx4;5 zAV85XfwKXcM>47aof)AOkr9DY`U4Q6r=c;3O9KNV3Wc6PbS2`oV}e@IQA41psHiCd zV&z|8Ruc@!ZyP#vK@Ccp@pth^gI>~o?1?>9hbVhWod;j;S?%Fi5?=hg{@V7pire># zlR8Q-%$;vO!)VH|`b#oLe0GzkTAOp`z|BLy@))0*-=hkGxNcjy6Bdp@2-`cdcS6C z#_vH7--JvGAJ<`ifb-jkUMcZur*D>;I`kgfv47=waf^PlrCmGik4m%8d|Y+q)UHGG zLnkp}*A@*qnexW0x@eeXZEyMDq&>5vjiZ^D?*znn4W_NK{Zh%_aI?$3(F-FYJA9av z&6&Jz)YRe8={Z9z&Uj8`UM{b_GiTE>@%f;u-s9K!J|fBuLCDY^>SeM0mQ~9yZ~WsO z6J@de`dTvsS!~!pk}G@&FEZ%e^w&jVoG-~m4`hI0;p1QyN@k%%7>gB1fEG+9vxXs| z{zv%JtkZt7{x7r9j`T}mXEqoP=eAo}P%B(mvVBX0d+$xN*G@RUq^$a2;X&q$@+iNp zW&ENyLW=3mlc6JNQ8DS|-A+Dp+w!Hf;OM?7nFfdd=#hclGJleO{mZLulfCN-yM8X* zsO-7rV0=|jw!xVh)0ftTd#ssYn;4hBQmB59-WHyZC-P^_ygaxmmv_x%Wr5tV;Y+&?VyV zmAwMN>lwB+7Dj7@?w9N5xO^LwR`z^p@k6{k%k=lne5X`Oy2a=z6ZQ>xm0D4HEBk7> zseFsA4tm8O@jmNPQl+$+-_ z(w;A9(f;x4)G;AW>xk}f*@g}h#*#Q9_Pat8Oa#J_0i$hT5J9j4+X};o;Or2wpj~iy zc5u7kz@V^pVL|N!+lj(LSUG~gz>we^VWSKfFB9EMF*sNLON-D@kIe-ujuld8{5%6T znV{qf6-t7@TYwt_CkFlt-8Ty!+7Y4ch%l4^1$r4UjR5B=dKr-OF9~Rq;9rnX6XuX{ z28HsCP9?DKqM24srC^D(l7ol6QcRn7=Yn&$c{aoHy$&pGU4J9?eCzGC{f#T<%stL} zps4z0=eph~eE40W1HqWh2gUse4zi$#^kk>+&4Ta#2E? z^M5?ZG@>5!2^Mz+k+x{{*8EeXCZ@AK>QeWny#wZTY#g z?TvibKAc)Gc{p}-MepaQ>Ecf{mg)QxuV+`jS!h4)h~WVtPe4shk9T?dsnGV=<`4Dz zBw0IZ=37Wcct07@*)^ZF|GDL>10!QbKWEJ|!~%zG#mD|??D@FIddKq{ciBG;eI`1W zZ%_3+G&X2-#F?rsduC=Zt10}El&sf-_m-@Gdj2x+&#c0-*bIj-Z~l&yH+=`(cz3D$ zAFK<`!Vte%!xrX*W}Qk4da?1?PNwHCv8|qe%8lRjFnYh$*zP?S#Zd)by`1X$On_E@$?r*iE#k=Tlky9#J@0ahay%)jz!!KxfSJ4#lWwFhctNpib zlJY*+jT_)_fO%3ixB5}0@m>yRsc*$o3ag;6`cMy$F3Sy#Kn-|7)&Nt1LtZdS{Vw01 zz-FOrYHBjot8&_FrikL?Km*>$aw1wZnl#ZlD{#ZMWZG=qkT!X8Imn&BbtO3xp+GIh z*@fynxl*DohPj;xC4z|{R$xdF5e{;DAPWtH2sr%jok9Pr^uDl0y5Yvv_^EzF^8KA| z?Ye#E;GFKBDQiw%b4+S&_5958GYM(NovX?n8L}j^#fbyz6PD zk<~j(`s|mLC)|z)wH`hHb$zZ2^Yh>bV_Y9UNLpO8*OPy2!bi?2lhb|Ion9YJU-V&_ zbXx8upFiUG>nl#*^NI8KUR{x##xuW5V}9yCc`_jz{U(E$|8dyGS+x({XAOIQmhr}T zE5CrZi8Fa&Jl3^Kj*Yi(&Wc%g&l#3=UG!n(a+@x8Cglr9K1&<)l`_{g#ds8EO~gIh zdfhW_$ANaK3)i(8#AX$psJhW%#Iza#b+fC*hR^S+Hd0P{bW8pA!C?PB+)SI^R{@PI zC#-ZC$AF-L7rk`exCBdG8etDZHn@#5CvdKi*gi<@p)#d%7 zdU(&e*M{-g@0KZlM#kMGHNqu=f80IGt&7(<)O4+0x+X!@v)+i|FD6pRqQE7(5S;3m zYIa5B-#;zZEh_;NYyI{@dT)DdIcfu-#I0Qa>S5W|K{m1(6#lfvHSbbV%uMP zv}sMz)sw~D6Db?~)dPALm@`(L+&y^GHvjXsi^dmZZ%d~hPr?}~bFP&{-A>=JuIF5r zTdtIf)jI~g9(Vd_2g>u?yC<0%9GMV*`z7E0TJox?cOOjXf1z~m{pqg_14hvvP4R2( zq4@OY=evXE_*=X)x~iw|t!4C(>c|I6U&Uk#pdO6RfTS zS)JM{&5k@)bow^RlyPI9sbJ#EOWRsJNg6l&U`X4(i|d~39BLLl_&i_f{+u|rW01H{ zZ%PYOJIk}b+s%I4@zB=6qI-{r^A*#jtHTq{|5;r3i(^T)?~6rMzQKk? z&e=yhwJLBce`$7@x#Lt!?Y$3Ahi<;JWQ96pThhS+p0-{C%{ubN59k#aW4E)mc70;* zk%iIUN{ih~7uXXy52J1SIv-i!;eI;iQQJp5>f=u^&tDEKP4M!IZ=KcaagP_vuFsi& zEJD7k%v)_}^L(ItT~+yB@6;_D`gf|V87SB!t6?mw`=!fETltrvg7e(9i9wbe5Vov%zC%_#H;2wY(- ztL{C%OBywYsw5y_GJvd7D3on-lbvpm?l&*j9HHJ3jI zEQs_^bI3o+Sp0=3H!2~@4YIYRz;g0g^3(0#Uj>wn`A1T5AVH7;>HBvAvf+Y&1_=N^2MYHJ4?-lv^hTZ-2d|r~AU_ zmVWt=`q4|ewFPps#+c(E>{gLns6gyV*xk`&-(dc2*`?Z#? zTfm+7D6j9?8&&*`rp*28uB>dkw!~!JrI{JW`Z*gs${F}DkmqF^@L-j3%BkAet(lh( z_|pnk<-Ivx@Ft>9jYECh_M2g%)iP1Ypk>uUt9Iw2roF#&-N@oXpW>xl-v<`Es~JVR zr+0es=}y~T)^3SCd=`}`Z`wv|<@UY&>{-l|5myFp99+@zO6LvZGaptak92-r6OeIt za))+ngL)p^+WBkXxmsGM4I9@@4I6fLekt>9QjaO_A#L`D%S6NZ+vi!Waq=8_ynZ{a zV#2$um#2Ak{FNW5CEu>GS&375VtQdRDOCXA*N#RA}ezh}5y7hSZ zVb&SX%3z`wS=`_a)a2^K>TVU>f9swPh+7b~AXs%5C0RsJR$w41bA9#79FIsLlJv@4 z^xrFUe}P|3lr4nJwrY>G}v{xqU&1QDqvN2NFf{j19?kzA+(l1T~#%3`5H z<)5c6Afj{#s6=q9K-?8ez~IO2;SKpL^tg_Eyju)LD$RpuvF`D^KknMpg;?(Eilwt} zrWQN&_Bbx!omp=XQDC+`(!`7=Ae->*DVFyia($cLuKI@EPpx%iFb zs<6%@Wa+F-@yN+T$Hk?jT{fROFvys1V)%{K_m!9A3S~NZU z_9M~J*iM5=Jl`;eE}N_#F`@pr7d6gr-&pG%OI8|~S3S%7nCCyE+Aq>Czb9AdW+IXG znmzOGi26N~-o&-N{<*{HT_G=IZPwmf=l$&TwKtaQ=J?E-ooLy~?6q;_MYsKdj<;VP zYxZ{wA#_G7wpdWHoK@OB=)q2Bxbb!G%EnY}TiGEXL7zE!nRoH%3#f{(JynpRb zGuQjpZ%b#Lex500-|1~MZ**tFBEvI=8w%a*b_)cXU;c5ZC4Kh|_F+q(=hwvnPiOsE z(`V*o>|#yau8cRcmYQ^nx1Lk#b{g|NxS?ukB&VoV$f2`~7A-6(@%R`&!)?{4E}o@t z7rd{_-`Z`~?I(qUoS!}pom1@C?c2p#&%DC>>pp%S_r$F9v82Pg&%`r&!o(Xl3JZi& zI-Qx{BPqGAG~J_SkWHX_$qTmWhR9DVPAtjXTQjCAeL#<-c+Q^aqg4ZYo0i7se<@zL zcUM6{|D!w=!=fbRH&!`)JyA|yO{GwXvKjyF!qxQMz=lU7)nx}@^3gc435{j0|J(&| z(J(S&SrYoI_Jn7{Mmh_mw#6lTmQR>^-QY!5&ywx5qa(e0e7Qu3^tPC@dJw7Aex*%) zI|Z(JCyiY5z8?5KqT(8_($+tX?9^g~JXa}DQ1KdE9s7rMdjfa9@!SMbv=^g3CXCrb6$?lRHA=WAGEP?s~= zM^=7(oW8W}tC)L_I&&gVadWdW%RW`yPTmlRJu)7*X;i-wA}Ky2)phJmk22q_p(l5^ zdh=rhGX$@foK+WJ`n+{er_6E1vX#osUI(x3+xUXG(B1OJ#d%A;-3voDxtyF^ z+WX0yQA>ti8xXhb(;(}Zt8vrajq@Iq{dTYQ3q@S@f}$OqgDqOLEjh=3FHW(1wCL^S z0ehZW5`C)6Iz-0qDx%+-HqAPH_2>nZZ6CTHH>~OZ@NKyF;PDAXGapV2bNsWurkv^n zPET4l*vODoPPGS9Hpn$6{?{(Vn|{uw=aZR)qrOX;H9Rk*0OGn81C|xMjm%=Pf{EbZ zU{-LiA3QP<8+A!o?|0yJ*I#3v@g97(Xa2RD8ucY zXLwds*7pY+7>I~c0-;2rf!4iJZrz&xI(HU- zn?B@R)053!etcbCcwY92cMc~%GxVjsTlb9o{N+>0JrDi3;4kkM#9Z(6G@hr6wEEvH_5&&WD_`oV~#L52B;dNkM-zUJKSHJ+z8 z+*#1)mx8y(*FBcm@5kIjyV}$}Y%ed!95(r=+1$m;tUE@YO1-l1#dAy7J`;7c+2!o_ zMyIu3eWG9Dmx$aod2G2~>jh2wtp0x$Ey}$oAXL}kY4H&q;xl9W$7aSxbQ#(&Qwd@^ zw2x>XpE4kGV2J6ltf;8KfQ-!a_}JvYfTqo}(_-TW$7hE0iyx4f(yadF&o|T$N$lUO z{;O68PlvRY@dFcI7?B>|WkkoWaU%xD`TN&z9@R8EGCMgf8O4NTCnu$3L}oXuAKO2* zUwkC~t;7-aLrPUL2REy4hU4+E$EY6_&@{b&LS*Mw(f>$<-2j7v|=NKMErTpIFf zYI^?=ugCB=Rr>$ZX&Rx*x~J@a*mIAB)~0{lZ$_pKO;0K{v431dd{TUJd`e~pDrA&a zsDE5!9J(YkH9e}dow~#ix%-c##HfVSxS<($D}dkb{-gBo5%;G0A65`O`CARkG*@

D_9y8M8 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf.meta new file mode 100644 index 0000000..8ddda7b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf.meta @@ -0,0 +1,30 @@ +fileFormatVersion: 2 +guid: 4d2d6fd090757104e8198ec673f419ac +labels: +- cheat +- hack +- CheatEngine +- hacker +- cheater +- cheating +- PlayerPrefs +- memory +- injection +- speedhack +- security +- anti-cheat +- toolkit +- hacking +- protection +- protect +- detect +- detection +- secure +- GameCIH +- ArtMoney +- SecurePrefs +- PlayMaker +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime.meta new file mode 100644 index 0000000..c55e6b2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7cca0bad55a675408eadd7dfa383d43 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef new file mode 100644 index 0000000..c396b33 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef @@ -0,0 +1,24 @@ +{ + "name": "ACTk.Runtime", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [ + { + "name": "com.unity.modules.audio", + "expression": "", + "define": "UNITY_AUDIO_MODULE" + }, + { + "name": "com.unity.nuget.newtonsoft-json", + "expression": "2.0.0", + "define": "ACTK_NEWTONSOFT_JSON" + } + ], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef.meta new file mode 100644 index 0000000..8fbd595 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/ACTk.Runtime.asmdef.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: db2875c6bc6e11c4fb8730f4afcd8265 +timeCreated: 1554196056 +licenseType: Store +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins.meta new file mode 100644 index 0000000..c7499b0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 9b66923e82dedcd458e649439a9a8821 +folderAsset: yes +timeCreated: 1529194413 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android.meta new file mode 100644 index 0000000..dc30897 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 593ae315404df664bb50772b005744b3 +folderAsset: yes +timeCreated: 1529194419 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar new file mode 100644 index 0000000000000000000000000000000000000000..5b50158fd1e4748353a794374758a9ff22988114 GIT binary patch literal 16442 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 + /// Contains ACTk version in case you need to know it in your scripts. + /// + public static class ACTk + { + ///

+ /// Current version in X.Y.Z format (using Semantic Versioning 2.0 scheme). + /// + public const string Version = "2023.2.2"; + +#if UNITY_EDITOR + public const string LogPrefix = "[ACTk] "; +#else + public const string LogPrefix = "[ACTk] "; +#endif + + // used at external integrations, thus it's public + public const string DocsRootUrl = "https://codestage.net/uas_files/actk/api/"; + internal const string SupportContact = "https://codestage.net/contacts"; + internal static readonly char[] StringKey = {'\x69', '\x108', '\x105', '\x110', '\x97'}; + + private static string unityVersion; + private static string applicationPlatform; + +#if UNITY_EDITOR + private static string buildTarget; +#endif + + // getting this information here because Unity APIs + // can't be accessed from background threads but this info used at ConstructErrorForSupport + // which potentially can be called from the background thread + [RuntimeInitializeOnLoadMethod] + private static void GetUnityInfo() + { + unityVersion = Application.unityVersion; + applicationPlatform = Application.platform.ToString(); +#if UNITY_EDITOR + buildTarget = UnityEditor.EditorUserBuildSettings.activeBuildTarget.ToString(); +#endif + } + + internal static void PrintExceptionForSupport(string errorText, Exception exception = null) + { + PrintExceptionForSupport(errorText, null, exception); + } + + internal static void PrintExceptionForSupport(string errorText, string prefix, Exception exception) + { + Debug.LogError(ConstructErrorForSupport(errorText, prefix, exception)); + if (exception != null) + Debug.LogException(exception); + } + + private static string ConstructErrorForSupport(string text, string prefix = null, Exception exception = null) + { + var prefixLog = string.IsNullOrEmpty(prefix) ? LogPrefix : prefix; + var logText = $"{prefixLog}{text}\n" + + $"Please report at: {SupportContact}\n"+ + $"Also please include this information:\n{GenerateBugReport(exception)}"; + + return logText; + } + + internal static string GenerateBugReport(Exception exception = null) + { + if (string.IsNullOrEmpty(unityVersion)) + GetUnityInfo(); + + var result = $"Unity version: {unityVersion}\n" + + $"Asset version: {Version}\n" + + $"Current platform: {applicationPlatform}"; +#if UNITY_EDITOR + result += $"\nTarget platform: {buildTarget}"; +#endif + + if (exception != null) + result += $"\n{exception}"; + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs.meta new file mode 100644 index 0000000..77293a7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4a84f340806547148432dd93c28cb7ea +timeCreated: 1623170452 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs new file mode 100644 index 0000000..8fdecbd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs @@ -0,0 +1,65 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Common +{ + using System; + + [Serializable] + internal struct ACTkByte16 : IEquatable + { + public byte b1; + public byte b2; + public byte b3; + public byte b4; + public byte b5; + public byte b6; + public byte b7; + public byte b8; + public byte b9; + public byte b10; + public byte b11; + public byte b12; + public byte b13; + public byte b14; + public byte b15; + public byte b16; + + public bool Equals(ACTkByte16 other) + { + return b1 == other.b1 && b2 == other.b2 && b3 == other.b3 && b4 == other.b4 && b5 == other.b5 && b6 == other.b6 && b7 == other.b7 && b8 == other.b8 && b9 == other.b9 && b10 == other.b10 && b11 == other.b11 && b12 == other.b12 && b13 == other.b13 && b14 == other.b14 && b15 == other.b15 && b16 == other.b16; + } + + public override bool Equals(object obj) + { + return obj is ACTkByte16 other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = b1.GetHashCode(); + hashCode = (hashCode * 397) ^ b2.GetHashCode(); + hashCode = (hashCode * 397) ^ b3.GetHashCode(); + hashCode = (hashCode * 397) ^ b4.GetHashCode(); + hashCode = (hashCode * 397) ^ b5.GetHashCode(); + hashCode = (hashCode * 397) ^ b6.GetHashCode(); + hashCode = (hashCode * 397) ^ b7.GetHashCode(); + hashCode = (hashCode * 397) ^ b8.GetHashCode(); + hashCode = (hashCode * 397) ^ b9.GetHashCode(); + hashCode = (hashCode * 397) ^ b10.GetHashCode(); + hashCode = (hashCode * 397) ^ b11.GetHashCode(); + hashCode = (hashCode * 397) ^ b12.GetHashCode(); + hashCode = (hashCode * 397) ^ b13.GetHashCode(); + hashCode = (hashCode * 397) ^ b14.GetHashCode(); + hashCode = (hashCode * 397) ^ b15.GetHashCode(); + hashCode = (hashCode * 397) ^ b16.GetHashCode(); + return hashCode; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs.meta new file mode 100644 index 0000000..229b4c3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte16.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8114eabec2d57e647a78a9263ef8cb77 +timeCreated: 1466433451 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs new file mode 100644 index 0000000..cf1a955 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs @@ -0,0 +1,33 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Common +{ + using System; + + [Serializable] + internal struct ACTkByte4 + { + public byte b1; + public byte b2; + public byte b3; + public byte b4; + + public void Shuffle() + { + var buffer = b2; + b2 = b3; + b3 = buffer; + } + + public void UnShuffle() + { + var buffer = b3; + b3 = b2; + b2 = buffer; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs.meta new file mode 100644 index 0000000..fb2f471 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte4.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9780c29cd9992542b6506217d67ce76 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs new file mode 100644 index 0000000..9118580 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs @@ -0,0 +1,47 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Common +{ + using System; + + [Serializable] + internal struct ACTkByte8 + { + public byte b1; + public byte b2; + public byte b3; + public byte b4; + public byte b5; + public byte b6; + public byte b7; + public byte b8; + + public void Shuffle() + { + var buffer = b1; + b1 = b2; + b2 = buffer; + buffer = b5; + b5 = b6; + var buffer2 = b8; + b8 = buffer; + b6 = buffer2; + } + + public void UnShuffle() + { + var buffer = b1; + b1 = b2; + b2 = buffer; + buffer = b5; + b5 = b8; + var buffer2 = b6; + b6 = buffer; + b8 = buffer2; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs.meta new file mode 100644 index 0000000..9c245be --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTkByte8.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6089ec68ab2197d408c7a6bfc628a4a9 +timeCreated: 1466433892 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs new file mode 100644 index 0000000..346ede0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs @@ -0,0 +1,21 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Common +{ + using System; + + internal class BackgroundThreadAccessException : Exception + { + public string AccessedApi { get; } + + public BackgroundThreadAccessException(string apiName):base($"Attempt {apiName} access from non-main thread! " + + "This API can't be accessed from child threads.") + { + AccessedApi = apiName; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs.meta new file mode 100644 index 0000000..69dcede --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/BackgroundThreadAccessException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 31cfeb8a503e479e8dc80c95cc055959 +timeCreated: 1623151207 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs new file mode 100644 index 0000000..3e35af8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs @@ -0,0 +1,63 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using UnityEngine; + +namespace CodeStage.AntiCheat.Common +{ + internal static class ContainerHolder + { + public const string ContainerName = "Anti-Cheat Toolkit"; + private static GameObject container; + private static bool containerSet; + + // making sure it will reset the container even if domain reload is disabled + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void SubsystemRegistration() + { + containerSet = false; + container = null; + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + private static void AfterAssembliesLoaded() => AssertNoContainerExists(nameof(RuntimeInitializeLoadType.AfterAssembliesLoaded)); + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)] + private static void BeforeSplashScreen() => AssertNoContainerExists(nameof(RuntimeInitializeLoadType.BeforeSplashScreen)); + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + private static void BeforeSceneLoad() => AssertNoContainerExists(nameof(RuntimeInitializeLoadType.BeforeSceneLoad)); + + private static void AssertNoContainerExists(string phaseName) + { + if (!containerSet) + return; + + Debug.LogError($"[ACTk] {nameof(ContainerHolder)}: container created too early ({phaseName})!\n" + + $"It should be created only after {nameof(RuntimeInitializeLoadType)}.{nameof(RuntimeInitializeLoadType.AfterSceneLoad)} / Awake phase to avoid state corruption!\n" + + $"Make sure to avoid accessing ACTk APIs before {nameof(RuntimeInitializeLoadType)}.{nameof(RuntimeInitializeLoadType.AfterSceneLoad)} / Awake"); + } + + public static T AddContainerComponent() where T : KeepAliveBehaviour + { + if (container == null) + container = new GameObject(ContainerName); + + containerSet = true; + + return container.AddComponent(); + } + + public static void TrySetContainer(GameObject gameObject) + { + if (container == null && gameObject.name == ContainerName) + { + container = gameObject; + containerSet = true; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs.meta new file mode 100644 index 0000000..430a7e1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ContainerHolder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cf0b42e703ec4f19811989be4515def4 +timeCreated: 1683220715 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs new file mode 100644 index 0000000..bd2b568 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs @@ -0,0 +1,155 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Common +{ + using UnityEngine; + using UnityEngine.SceneManagement; + + /// + /// Base class for ACTk in-scene objects which able to survive scene switch. + /// + /// \htmlonlyWARNING:\endhtmlonly Will behave incorrectly if created within any non-default [RuntimeInitializeOnLoadMethod] except RuntimeInitializeLoadType.AfterSceneLoad (which is default). + public abstract class KeepAliveBehaviour : MonoBehaviour where T: KeepAliveBehaviour + { + /// + /// Will survive new level (scene) load if checked. Otherwise it will be destroyed. + /// + /// On dispose Behaviour follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit": it will be automatically + /// destroyed if no other Behaviours left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit": it will be automatically destroyed only + /// if it has neither other components nor children attached; + [Tooltip("Detector will survive new level (scene) load if checked.")] + public bool keepAlive = true; + + protected int instancesInScene; + protected bool selfDestroying; + private Scene originalScene; + + #region static instance + /// + /// Allows reaching public properties from code. + /// Can be null if behaviour does not exist in scene or if accessed at or before Awake phase. + /// + public static T Instance { get; protected set; } + + protected static T GetOrCreateInstance + { + get + { + if (Instance != null) + return Instance; + + Instance = ContainerHolder.AddContainerComponent(); + return Instance; + } + } + #endregion + + #region unity messages + + // making sure it will reset statics even if domain reload is disabled + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void SubsystemRegistration() + { + Instance = null; + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + protected virtual void Awake() + { + selfDestroying = false; + + instancesInScene++; + if (Init(Instance)) + { + Instance = (T)this; + } + } + + protected virtual void Start() + { + ContainerHolder.TrySetContainer(gameObject); + + SceneManager.sceneLoaded += OnSceneLoaded; + SceneManager.sceneUnloaded += OnSceneUnloaded; + } + + protected virtual void OnDestroy() + { + var componentsCount = GetComponentsInChildren().Length; + if (transform.childCount == 0 && componentsCount <= 2) + { + Destroy(gameObject); + } + else if (name == ContainerHolder.ContainerName && componentsCount <= 2) + { + Destroy(gameObject); + } + + instancesInScene--; + + SceneManager.sceneLoaded -= OnSceneLoaded; + SceneManager.sceneUnloaded -= OnSceneUnloaded; + + if (Instance == this) + { + Instance = null; + } + } + + #endregion + + protected virtual void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + if (instancesInScene < 2) + { + if (!keepAlive && mode != LoadSceneMode.Additive) + DisposeInternal(); + } + else + { + if (!keepAlive && Instance != this) + DisposeInternal(); + } + } + + protected virtual void OnSceneUnloaded(Scene scene) + { + if (originalScene == scene) + { + if (!keepAlive) + DisposeInternal(); + } + } + + protected virtual bool Init(T instance) + { + if (instance != null && instance != this && instance.keepAlive) + { + DisposeInternal(); + return false; + } + + originalScene = gameObject.scene; + DontDestroyOnLoad(transform.parent != null ? transform.root.gameObject : gameObject); + + return true; + } + + protected virtual void DisposeInternal() + { + if (selfDestroying) + return; + + selfDestroying = true; + Destroy(this); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs.meta new file mode 100644 index 0000000..bf14870 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/KeepAliveBehaviour.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cce5e7aa50344452aa5288a5ac0852b5 +timeCreated: 1556838390 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs new file mode 100644 index 0000000..8d31fb0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs @@ -0,0 +1,126 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +#if !UNITY_WEBGL +#define ACTK_ASYNC +#endif + +namespace CodeStage.AntiCheat.Common +{ + using Storage; + using UnityEngine; + using Utils; + + /// + /// User-friendly wrapper around few internally used Unity APIs which can't be accessed from background threads. + /// + /// You only need to touch this if you are going to use ObscuredFile / ObscuredFilePrefs from the background threads. + public static class UnityApiResultsHolder + { +#if UNITY_IPHONE + private static string deviceVendorIdentifier; +#endif + + private static string deviceUniqueIdentifier; + private static string persistentDataPath; + + private static bool? isMobilePlatform; + + /// + /// Call this from the main thread before using ObscuredFile / ObscuredFilePrefs from the background threads. + /// + /// Calling this method avoids getting exceptions while working with ObscuredFile / ObscuredFilePrefs from the + /// background threads. + /// Pass true to init API needed for the Lock To Device feature + /// (SystemInfo.deviceUniqueIdentifier). + /// You need this to be true only when using ObscuredFile / ObscuredFilePrefs from the background threads + /// with DeviceLock enabled and without custom DeviceID set. + /// Passing true is similar to the DeviceIdHolder.ForceLockToDeviceInit() call, please read that API docs for + /// more information about possible side effects. + public static void InitForAsyncUsage(bool warmUpDeviceIdentifier) + { +#if ACTK_ASYNC + if (System.Threading.SynchronizationContext.Current == null) + { + Debug.LogError($"Please call {nameof(InitForAsyncUsage)} from main thread!"); + return; + } +#endif + + GetPersistentDataPath(); + + if (warmUpDeviceIdentifier) + GetDeviceUniqueIdentifier(); + + _ = AppEventsDispatcher.Instance; + IsMobilePlatform(); + } + + internal static string GetDeviceUniqueIdentifier() + { + if (string.IsNullOrEmpty(deviceUniqueIdentifier)) + { +#if ACTK_ASYNC + if (System.Threading.SynchronizationContext.Current != null) + deviceUniqueIdentifier = GetDeviceID(); + else + throw new DeviceUniqueIdentifierException(); +#else + deviceUniqueIdentifier = GetDeviceID(); +#endif + } + + return deviceUniqueIdentifier; + + string GetDeviceID() + { + var result = string.Empty; +#if UNITY_IPHONE + result = UnityEngine.iOS.Device.vendorIdentifier; +#endif +#if !ACTK_PREVENT_READ_PHONE_STATE + if (string.IsNullOrEmpty(result)) + result = SystemInfo.deviceUniqueIdentifier; +#endif + + return result; + } + } + + internal static string GetPersistentDataPath() + { + if (string.IsNullOrEmpty(persistentDataPath)) + { +#if ACTK_ASYNC + if (System.Threading.SynchronizationContext.Current != null) + persistentDataPath = Application.persistentDataPath; + else + throw new PersistentDataPathException(); +#else + persistentDataPath = Application.persistentDataPath; +#endif + } + + return persistentDataPath; + } + +#if !ACTK_DISABLE_FILEPREFS_AUTOSAVE + internal static bool IsMobilePlatform() + { + if (isMobilePlatform == null) + { +#if UNITY_EDITOR + isMobilePlatform = UnityEditorInternal.InternalEditorUtility.IsMobilePlatform(UnityEditor.EditorUserBuildSettings.activeBuildTarget); +#else + isMobilePlatform = Application.isMobilePlatform; +#endif + } + + return isMobilePlatform.Value; + } +#endif + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs.meta new file mode 100644 index 0000000..8953a88 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/UnityApiResultsHolder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3f01147a33cc454f8b196c9c1334ac86 +timeCreated: 1630166740 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors.meta new file mode 100644 index 0000000..dfef81c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fbf6c61c50aaf094e8d04d7554893641 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract.meta new file mode 100644 index 0000000..e996ae2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ac72640b50efad458b747dd66c98f6b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs new file mode 100644 index 0000000..e1a5757 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs @@ -0,0 +1,173 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Detectors +{ + using Common; + + using System; + using UnityEngine; + using UnityEngine.Events; + + /// + /// Base class for all detectors. + /// + [AddComponentMenu("")] + public abstract class ACTkDetectorBase : KeepAliveBehaviour where T: ACTkDetectorBase + { + protected const string MenuPath = "Code Stage/Anti-Cheat Toolkit/"; + + /// + /// Allows to start detector automatically. + /// Otherwise, you'll need to call StartDetection() method to start it. + /// + /// Useful in conjunction with proper Detection Event configuration in the inspector. + /// Allows to use detector without writing any code except the actual reaction on cheating. + [Tooltip("Automatically start detector. Detection Event will be called on detection.")] + public bool autoStart = true; + + /// + /// Detector component will be automatically disposed after firing callback if enabled. + /// Otherwise, it will just stop internal processes. + /// + /// On dispose Detector follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit": it will be automatically + /// destroyed if no other %Detectors left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit": it will be automatically destroyed only + /// if it has neither other components nor children attached; + [Tooltip("Automatically dispose Detector after firing callback.")] + public bool autoDispose = true; + + /// + /// Subscribe to this event to get notified when cheat will be detected. + /// + public event Action CheatDetected; + + /// + /// Indicates if cheat was detected by this detector. + /// + public bool IsCheatDetected { get; protected set; } + + [SerializeField] + protected UnityEvent detectionEvent; + + [SerializeField] + protected bool detectionEventHasListener; + + /// + /// Allows to check if detector is started (stays true even when it's paused). + /// + public bool IsStarted { get; protected set; } + + /// + /// Allows to check if detection is currently running and not paused. + /// + public bool IsRunning { get; protected set; } + + #region unity messages +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + protected override void Start() + { + base.Start(); + + if (autoStart && !IsStarted) + { + StartDetectionAutomatically(); + } + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnEnable() + { + ResumeDetector(); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnDisable() + { + PauseDetector(); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnApplicationQuit() + { + DisposeInternal(); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + protected override void OnDestroy() + { + StopDetectionInternal(); + base.OnDestroy(); + } + #endregion + + internal virtual void OnCheatingDetected() + { + IsCheatDetected = true; + InvokeCheatingDetectedEvent(); + + if (detectionEventHasListener) + detectionEvent.Invoke(); + + if (autoDispose) + DisposeInternal(); + else + StopDetectionInternal(); + } + + protected virtual void InvokeCheatingDetectedEvent() + { + CheatDetected?.Invoke(); + } + + protected virtual bool DetectorHasListeners() + { + return IsUserListeningToCheatDetectedEvent() || detectionEventHasListener; + } + + protected virtual void StopDetectionInternal() + { + CheatDetected = null; + IsStarted = false; + IsRunning = false; + } + + protected virtual void PauseDetector() + { + if (!IsStarted) + return; + + IsRunning = false; + } + + protected virtual bool ResumeDetector() + { + if (!IsStarted || !DetectorHasListeners()) + return false; + + IsRunning = true; + return true; + } + + protected virtual bool IsUserListeningToCheatDetectedEvent() + { + return CheatDetected != null; + } + + protected abstract void StartDetectionAutomatically(); + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs.meta new file mode 100644 index 0000000..9a3d462 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/Abstract/ACTkDetectorBase.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6e4e2aa87fa03d04bbe3979a971cc4f6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs new file mode 100644 index 0000000..d0f8052 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs @@ -0,0 +1,564 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if (UNITY_EDITOR || DEVELOPMENT_BUILD) +#if (ACTK_INJECTION_DEBUG || ACTK_INJECTION_DEBUG_VERBOSE || ACTK_INJECTION_DEBUG_PARANOID) +#define ACTK_DEBUG_NORMAL +#endif + +#if (ACTK_INJECTION_DEBUG_VERBOSE || ACTK_INJECTION_DEBUG_PARANOID) +#define ACTK_DEBUG_VERBOSE +#endif + +#if (ACTK_INJECTION_DEBUG_PARANOID) +#define ACTK_DEBUG_PARANOID +#endif +#endif + +#if (UNITY_STANDALONE || UNITY_ANDROID) && !ENABLE_IL2CPP +#define UNITY_SUPPORTED_PLATFORM +#endif + +namespace CodeStage.AntiCheat.Detectors +{ + using Common; + using ObscuredTypes; + + using System; + using System.IO; + using System.Reflection; + using System.Text; + using Debug = UnityEngine.Debug; + using UnityEngine; + +#if ACTK_DEBUG_NORMAL + using System.Diagnostics; +#endif + + /// + /// Allows to detect foreign managed assemblies in your application. + /// + /// Just add it to any GameObject as usual or through the "GameObject > Create Other > Code Stage > Anti-Cheat Toolkit" + /// menu to get started.
+ /// You can use detector completely from inspector without writing any code except the actual reaction on cheating. + /// + /// Avoid using detectors from code at the Awake phase. + /// + /// \htmlonlyNOTE #1:\endhtmlonly Make sure you've checked the + /// "Enable Injection Detector" option at the "Window > Code Stage > Anti-Cheat Toolkit > Settings" window + /// before using detector at runtime.
+ /// \htmlonlyNOTE #2:\endhtmlonly Always test detector on the + /// target platform before releasing your application to the public.
+ /// It may detect some external assemblies as foreign, + /// thus make sure you've added all external assemblies your application uses to the Whitelist (see section + /// "How to fill user-defined Whitelist" of the read me for details).
+ /// \htmlonlyNOTE #3:\endhtmlonly Disabled in Editor because of specific assemblies causing false positives. Use ACTK_INJECTION_DEBUG symbol to force it in Editor. + /// + /// \htmlonlyWARNING:\endhtmlonly Only Standalone and Android platforms are supported.
+ [AddComponentMenu(MenuPath + ComponentName)] + [DisallowMultipleComponent] + [HelpURL(ACTk.DocsRootUrl + "class_code_stage_1_1_anti_cheat_1_1_detectors_1_1_injection_detector.html")] + public class InjectionDetector : ACTkDetectorBase + { + public delegate void InjectionDetectedEventHandler(string reason); + + public const string ComponentName = "Injection Detector"; + internal const string LogPrefix = ACTk.LogPrefix + ComponentName + ": "; + +#if UNITY_SUPPORTED_PLATFORM + /// + /// Subscribe to this event to get notified when cheat will be detected. + /// The detection cause will be passed as an argument if possible. + /// + public new event InjectionDetectedEventHandler CheatDetected; + + #region private variables + private bool signaturesAreMissing; + private bool signaturesAreNotGenuine; + private AllowedAssembly[] allowedAssemblies; + private string[] hexTable; + private string lastCheatDetectionReason; + #endregion + + #region public static methods + + /// + /// Creates new instance of the detector at scene if it doesn't exists. Make sure to call NOT from Awake phase. + /// + /// New or existing instance of the detector. + public static InjectionDetector AddToSceneOrGetExisting() + { + return GetOrCreateInstance; + } + + /// + /// Starts foreign assemblies injection detection for detector you have in scene. + /// + /// Make sure you have properly configured detector in scene with #autoStart disabled before using this method. + public static InjectionDetector StartDetection() + { + if (Instance != null) + { + return Instance.StartDetectionInternal(null); + } + + Debug.LogError(LogPrefix + "can't be started since it doesn't exists in scene or not yet initialized!"); + return null; + } + + /// + /// Starts foreign assemblies injection detection with specified callback containing string argument.
+ /// Assembly name will be passed to the argument if possible. Otherwise another cause of the detection will be passed. + ///
+ /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + public static InjectionDetector StartDetection(InjectionDetectedEventHandler callback) + { + return GetOrCreateInstance.StartDetectionInternal(callback); + } + + /// + /// Stops detector. Detector's component remains in the scene. Use Dispose() to completely remove detector. + /// + public static void StopDetection() + { + if (Instance != null) + Instance.StopDetectionInternal(); + } + + /// + /// Stops and completely disposes detector component. + /// + /// On dispose Detector follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically + /// destroyed if no other Detectors left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only + /// if it has neither other components nor children attached; + public static void Dispose() + { + if (Instance != null) + Instance.DisposeInternal(); + } + #endregion + + /// + /// Manually triggers cheating detection and invokes assigned events. + /// + [ContextMenu("Trigger detection")] + public void TriggerDetection() + { + if (!IsRunning) + { + Debug.LogWarning(LogPrefix + "Detector is not running, can't trigger detection."); + return; + } + + TriggerCheatDetection("Triggered manually"); + } + + private InjectionDetector() { } // prevents direct instantiation + + private InjectionDetector StartDetectionInternal(InjectionDetectedEventHandler callback) + { + if (IsRunning) + { + Debug.LogWarning(LogPrefix + "already running!", this); + return this; + } + + if (!enabled) + { + Debug.LogWarning($"{LogPrefix}disabled but {nameof(StartDetection)} still called from somewhere (see stack trace for this message)!", this); + return this; + } + + if (callback != null && DetectorHasListeners()) + { + Debug.LogWarning(LogPrefix + $"has properly configured Detection Event in the inspector or {nameof(CheatDetected)} event subscriber, but still get started with Action callback." + + $"Action will be called at the same time with Detection Event or {nameof(CheatDetected)} on detection." + + "Are you sure you wish to do this?", this); + } + + if (callback == null && !DetectorHasListeners()) + { + Debug.LogError($"{LogPrefix}was started without Detection Event, Callback or {nameof(CheatDetected)} event subscription." + + "First cheat check is executed without listeners, possible cheat will be ignored!", this); + } + + if (callback != null) + CheatDetected += callback; + + IsStarted = true; + IsRunning = true; + + if (Application.isEditor) + { + Debug.Log(LogPrefix + "does not work in Unity Editor.", this); + return this; + } + + if (allowedAssemblies == null) + { + LoadAndParseAllowedAssemblies(); + } + + if (signaturesAreMissing) + { + TriggerCheatDetection("signatures are missing (did you enable " + ComponentName + "?)"); + } + else if (signaturesAreNotGenuine) + { + TriggerCheatDetection("signatures are not genuine or damaged"); + return this; + } + + if (!FindInjectionInCurrentAssemblies(out var cause)) + { + // listening for new assemblies + AppDomain.CurrentDomain.AssemblyLoad += OnNewAssemblyLoaded; + } + else + { + TriggerCheatDetection(cause); + } + + return this; + } + + protected override void StartDetectionAutomatically() + { + StartDetectionInternal(null); + } + + protected override void PauseDetector() + { + AppDomain.CurrentDomain.AssemblyLoad -= OnNewAssemblyLoaded; + base.PauseDetector(); + } + + protected override bool ResumeDetector() + { + if (!base.ResumeDetector()) return false; + + AppDomain.CurrentDomain.AssemblyLoad += OnNewAssemblyLoaded; + return true; + } + + protected override void StopDetectionInternal() + { + if (IsStarted) + { + AppDomain.CurrentDomain.AssemblyLoad -= OnNewAssemblyLoaded; + } + base.StopDetectionInternal(); + } + + protected override void DisposeInternal() + { + base.DisposeInternal(); + if (Instance == this) Instance = null; + } + + protected override bool IsUserListeningToCheatDetectedEvent() + { + return CheatDetected != null; + } + + protected override void InvokeCheatingDetectedEvent() + { + CheatDetected?.Invoke(lastCheatDetectionReason); + } + + private void TriggerCheatDetection(string reason) + { + lastCheatDetectionReason = reason; + OnCheatingDetected(); + } + + private void OnNewAssemblyLoaded(object sender, AssemblyLoadEventArgs args) + { +#if ACTK_DEBUG_NORMAL + Debug.Log(ACTk.LogPrefix + "New assembly loaded: " + args.LoadedAssembly.FullName, this); +#endif + if (!AssemblyAllowed(args.LoadedAssembly)) + { +#if ACTK_DEBUG_NORMAL + Debug.Log(ACTk.LogPrefix + "Injected Assembly found:\n" + args.LoadedAssembly.FullName, this); +#endif + TriggerCheatDetection(args.LoadedAssembly.FullName); + } + } + + private bool FindInjectionInCurrentAssemblies(out string cause) + { + cause = null; + var result = false; +#if ACTK_DEBUG_NORMAL + var stopwatch = Stopwatch.StartNew(); +#endif + var assembliesInCurrentDomain = AppDomain.CurrentDomain.GetAssemblies(); + if (assembliesInCurrentDomain.Length == 0) + { +#if ACTK_DEBUG_NORMAL + stopwatch.Stop(); + Debug.Log(ACTk.LogPrefix + "0 assemblies in current domain! Not genuine behavior.", this); + stopwatch.Start(); +#endif + cause = "no assemblies"; + result = true; + } + else + { + foreach (var ass in assembliesInCurrentDomain) + { +#if ACTK_DEBUG_VERBOSE + stopwatch.Stop(); + Debug.Log(ACTk.LogPrefix + "Currently loaded assembly:\n" + ass.FullName, this); + stopwatch.Start(); +#endif + if (!AssemblyAllowed(ass)) + { +#if ACTK_DEBUG_NORMAL + stopwatch.Stop(); + Debug.Log(ACTk.LogPrefix + "Injected Assembly found:\n" + ass.FullName + "\n" + GetAssemblyHash(ass), this); + stopwatch.Start(); +#endif + cause = ass.FullName; + result = true; + break; + } + } + } + +#if ACTK_DEBUG_NORMAL + stopwatch.Stop(); + Debug.Log(ACTk.LogPrefix + "Loaded assemblies scan duration: " + stopwatch.ElapsedMilliseconds + " ms.", this); +#endif + return result; + } + + private bool AssemblyAllowed(Assembly ass) + { + var assemblyName = ass.GetName().Name; + var hash = GetAssemblyHash(ass); + + var result = false; + for (var i = 0; i < allowedAssemblies.Length; i++) + { + var allowedAssembly = allowedAssemblies[i]; + + if (allowedAssembly.name == assemblyName) + { + if (Array.IndexOf(allowedAssembly.hashes, hash) != -1) + { + result = true; + break; + } + } + } + + return result; + } + + private void LoadAndParseAllowedAssemblies() + { +#if ACTK_DEBUG_NORMAL + Debug.Log(ACTk.LogPrefix + "Starting LoadAndParseAllowedAssemblies()", this); + var sw = Stopwatch.StartNew(); +#endif + var assembliesSignatures = Resources.Load("fndid"); + if (assembliesSignatures == null) + { + signaturesAreMissing = true; + signaturesAreNotGenuine = true; + return; + } + +#if ACTK_DEBUG_NORMAL + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Creating separator array and opening MemoryStream", this); + sw.Start(); +#endif + + string[] separator = {":"}; + + var ms = new MemoryStream(assembliesSignatures.bytes); + var br = new BinaryReader(ms, Encoding.Unicode); + + var count = br.ReadInt32(); + +#if ACTK_DEBUG_NORMAL + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Allowed assemblies count from MS: " + count, this); + sw.Start(); +#endif + + allowedAssemblies = new AllowedAssembly[count]; + + for (var i = 0; i < count; i++) + { + var lineLength = br.ReadInt32(); + var line = br.ReadChars(lineLength); +#if ACTK_DEBUG_PARANOID + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Line: " + new string(line) + ", length: " + lineLength, this); + sw.Start(); +#endif + var lineString = ObscuredString.Decrypt(line, ACTk.StringKey); +#if ACTK_DEBUG_PARANOID + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Line decrypted : " + lineString, this); + sw.Start(); +#endif + var strArr = lineString.Split(separator, StringSplitOptions.RemoveEmptyEntries); + var stringsCount = strArr.Length; +#if ACTK_DEBUG_PARANOID + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "stringsCount : " + stringsCount, this); + sw.Start(); +#endif + if (stringsCount > 1) + { + var assemblyName = strArr[0]; + + var hashes = new int[stringsCount - 1]; + for (var j = 1; j < stringsCount; j++) + { + var parseResult = 0; + var success = int.TryParse(strArr[j], out parseResult); + if (success) + { + hashes[j - 1] = parseResult; + } + else + { + Debug.LogError(LogPrefix + "Could not parse value: " + strArr[j] + ", line:\n" + lineString); + } + } + + allowedAssemblies[i] = new AllowedAssembly(assemblyName, hashes); + } + else + { + signaturesAreNotGenuine = true; + br.Close(); + ms.Close(); +#if ACTK_DEBUG_NORMAL + sw.Stop(); +#endif + return; + } + } + br.Close(); + ms.Close(); + Resources.UnloadAsset(assembliesSignatures); + +#if ACTK_DEBUG_NORMAL + sw.Stop(); + Debug.Log(ACTk.LogPrefix + "Allowed Assemblies parsing duration: " + sw.ElapsedMilliseconds + " ms.", this); +#endif + + hexTable = new string[256]; + for (var i = 0; i < 256; i++) + { + hexTable[i] = i.ToString("x2"); + } + } + + private int GetAssemblyHash(Assembly ass) + { + string hashInfo; + + var assName = ass.GetName(); + var bytes = assName.GetPublicKeyToken(); + if (bytes.Length >= 8) + { + hashInfo = assName.Name + PublicKeyTokenToString(bytes); + } + else + { + hashInfo = assName.Name; + } + + // based on Jenkins hash function (http://en.wikipedia.org/wiki/Jenkins_hash_function) + var result = 0; + var len = hashInfo.Length; + + for (var i = 0; i < len; ++i) + { + result += hashInfo[i]; + result += (result << 10); + result ^= (result >> 6); + } + result += (result << 3); + result ^= (result >> 11); + result += (result << 15); + + return result; + } + + private string PublicKeyTokenToString(byte[] bytes) + { + var result = ""; + + // AssemblyName.GetPublicKeyToken() returns 8 bytes + for (var i = 0; i < 8; i++) + { + result += hexTable[bytes[i]]; + } + + return result; + } + + private class AllowedAssembly + { + public readonly string name; + public readonly int[] hashes; + + public AllowedAssembly(string name, int[] hashes) + { + this.name = name; + this.hashes = hashes; + } + } +#else + //! @cond + public static InjectionDetector AddToSceneOrGetExisting() + { + Debug.Log(LogPrefix + "is not supported on current platform! This message is harmless."); + return null; + } + + public static void StartDetection() + { + Debug.Log(LogPrefix + "is not supported on current platform! This message is harmless."); + } + + public static void StartDetection(Action callback) + { + Debug.Log(LogPrefix + "is not supported on current platform! This message is harmless."); + } + + public static void StopDetection() + { + Debug.Log(LogPrefix + "is not supported on current platform! This message is harmless."); + } + + public static void Dispose() + { + Debug.Log(LogPrefix + "is not supported on current platform! This message is harmless."); + } + + protected override void StartDetectionAutomatically() + { + Debug.Log(LogPrefix + "is not supported on current platform! This message is harmless."); + } + + //! @endcond +#endif + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs.meta new file mode 100644 index 0000000..8d42fa2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/InjectionDetector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 2c0c2cd00b8d16c43b34c7f120c7df15 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs new file mode 100644 index 0000000..e942655 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs @@ -0,0 +1,244 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Detectors +{ + using Common; + + using System; + using ObscuredTypes; + using UnityEngine; + + /// + /// Contains detailed information about latest Obscured Types cheating detection. + /// + public class ObscuredCheatingDetectionInfo + { + /// + /// Type of the source. Holds type of the obscured type instance which triggered the detection. + /// + public Type SourceType { get; } + + /// + /// Actual obscured value (in clean decrypted form) at the detection moment. + /// + /// Please note, some types have both whole values and separate components checks, + /// for example, ObscuredVector3 has checks for whole Vector3 and its components like Vector3.x, + /// thus this value can hold either the whole struct or just one of its components. + public object ObscuredValue { get; } + + /// + /// Faked "honeypot" value at the detection moment. + /// + /// Please note, some types have both whole values and separate components checks, + /// for example, ObscuredVector3 has checks for whole Vector3 and its components like Vector3.x, + /// thus this value can hold either the whole struct or just one of its components. + public object FakeValue { get; } + + public ObscuredCheatingDetectionInfo(Type type, object decrypted, object fake) + { + SourceType = type; + ObscuredValue = decrypted; + FakeValue = fake; + } + + public override string ToString() + { + return $"SourceType: {SourceType}\n" + + $"Decrypted: {ObscuredValue}\n" + + $"Fake: {FakeValue}"; + } + } + + /// + /// Detects CodeStage.AntiCheat.ObscuredTypes cheating. + /// + /// It allows cheaters to find desired (fake) values in memory and change them, keeping original values secure.
+ /// It's like a cheese in the mouse trap - cheater tries to change some obscured value and get caught on it. + /// + /// Just add it to any GameObject as usual or through the "GameObject > Create Other > Code Stage > Anti-Cheat Toolkit" + /// menu to get started.
+ /// You can use detector completely from inspector without writing any code except the actual reaction on cheating. + /// + /// Avoid using detectors from code at the Awake phase. + [AddComponentMenu(MenuPath + ComponentName)] + [DisallowMultipleComponent] + [HelpURL(ACTk.DocsRootUrl + "class_code_stage_1_1_anti_cheat_1_1_detectors_1_1_obscured_cheating_detector.html")] + public class ObscuredCheatingDetector : ACTkDetectorBase + { + public const string ComponentName = "Obscured Cheating Detector"; + internal const string LogPrefix = ACTk.LogPrefix + ComponentName + ": "; + + /// + /// Holds detailed information about latest triggered detection. + /// + /// Can be null if there were no detections or if detection was triggered manually. + public ObscuredCheatingDetectionInfo LastDetectionInfo { get; private set; } + + #region public fields + + /// + /// Max allowed difference between encrypted and fake values in \link ObscuredTypes.ObscuredDouble ObscuredDouble\endlink. Increase in case of false positives. + /// + [Tooltip("Max allowed difference between encrypted and fake values in ObscuredDouble. Increase in case of false positives.")] + public double doubleEpsilon = 0.0001d; + + /// + /// Max allowed difference between encrypted and fake values in \link ObscuredTypes.ObscuredFloat ObscuredFloat\endlink. Increase in case of false positives. + /// + [Tooltip("Max allowed difference between encrypted and fake values in ObscuredFloat. Increase in case of false positives.")] + public float floatEpsilon = 0.0001f; + + /// + /// Max allowed difference between encrypted and fake values in \link ObscuredTypes.ObscuredVector2 ObscuredVector2\endlink. Increase in case of false positives. + /// + [Tooltip("Max allowed difference between encrypted and fake values in ObscuredVector2. Increase in case of false positives.")] + public float vector2Epsilon = 0.1f; + + /// + /// Max allowed difference between encrypted and fake values in \link ObscuredTypes.ObscuredVector3 ObscuredVector3\endlink. Increase in case of false positives. + /// + [Tooltip("Max allowed difference between encrypted and fake values in ObscuredVector3. Increase in case of false positives.")] + public float vector3Epsilon = 0.1f; + + /// + /// Max allowed difference between encrypted and fake values in \link ObscuredTypes.ObscuredQuaternion ObscuredQuaternion\endlink. Increase in case of false positives. + /// + [Tooltip("Max allowed difference between encrypted and fake values in ObscuredQuaternion. Increase in case of false positives.")] + public float quaternionEpsilon = 0.1f; + #endregion + + #region public static methods + /// + /// Creates new instance of the detector at scene if it doesn't exists. Make sure to call NOT from Awake phase. + /// + /// New or existing instance of the detector. + public static ObscuredCheatingDetector AddToSceneOrGetExisting() + { + return GetOrCreateInstance; + } + + /// + /// Starts all Obscured types cheating detection for detector you have in scene. + /// + /// Make sure you have properly configured detector in scene with #autoStart disabled before using this method. + public static ObscuredCheatingDetector StartDetection() + { + if (Instance != null) + { + return Instance.StartDetectionInternal(null); + } + + Debug.LogError(LogPrefix + "can't be started since it doesn't exists in scene or not yet initialized!"); + return null; + } + + /// + /// Starts all Obscured types cheating detection with specified callback. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + public static ObscuredCheatingDetector StartDetection(Action callback) + { + return GetOrCreateInstance.StartDetectionInternal(callback); + } + + /// + /// Stops detector. Detector's component remains in the scene. Use Dispose() to completely remove detector. + /// + public static void StopDetection() + { + if (Instance != null) Instance.StopDetectionInternal(); + } + + /// + /// Stops and completely disposes detector component. + /// + /// On dispose Detector follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically + /// destroyed if no other Detectors left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only + /// if it has neither other components nor children attached; + public static void Dispose() + { + if (Instance != null) Instance.DisposeInternal(); + } + #endregion + + internal static bool ExistsAndIsRunning => (object)Instance != null && Instance.IsRunning; + + private ObscuredCheatingDetector() {} // prevents direct instantiation + + /// + /// Manually triggers cheating detection and invokes assigned events. + /// + [ContextMenu("Trigger detection")] + public void TriggerDetection() + { + if (!IsRunning) + { + Debug.LogWarning(LogPrefix + "Detector is not running, can't trigger detection."); + return; + } + + LastDetectionInfo = new ObscuredCheatingDetectionInfo(typeof(ObscuredString), + "This is an example of encrypted string.", "This is an example of modified string."); + OnCheatingDetected(); + } + + // boxing all around, eeek! =D + // but it's not in the hot path and get called only once per session if cheating was detected, so who cares? + internal void OnCheatingDetected(IObscuredType type, object decrypted, object fake) + { + LastDetectionInfo = new ObscuredCheatingDetectionInfo(type.GetType(), decrypted, fake); + OnCheatingDetected(); + } + + private ObscuredCheatingDetector StartDetectionInternal(Action callback) + { + if (IsRunning) + { + Debug.LogWarning(LogPrefix + "already running!", this); + return this; + } + + if (!enabled) + { + Debug.LogWarning($"{LogPrefix}disabled but {nameof(StartDetection)} still called from somewhere (see stack trace for this message)!", this); + return this; + } + + LastDetectionInfo = null; + + if (callback != null && DetectorHasListeners()) + { + Debug.LogWarning(LogPrefix + $"has properly configured Detection Event in the inspector or {nameof(CheatDetected)} event subscriber, but still get started with Action callback." + + $"Action will be called at the same time with Detection Event or {nameof(CheatDetected)} on detection." + + "Are you sure you wish to do this?", this); + } + + if (callback == null && !DetectorHasListeners()) + { + Debug.LogWarning($"{LogPrefix}was started without Detection Event, Callback or {nameof(CheatDetected)} event subscription." + + $"Cheat will not be detected until you subscribe to {nameof(CheatDetected)} event.", this); + } + + if (callback != null) + CheatDetected += callback; + + IsStarted = true; + IsRunning = true; + + return this; + } + + protected override void StartDetectionAutomatically() + { + StartDetectionInternal(null); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs.meta new file mode 100644 index 0000000..ca11362 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/ObscuredCheatingDetector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: a30ad7dd9c3245a488e57ae755cf870e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs new file mode 100644 index 0000000..9cc6288 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs @@ -0,0 +1,387 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR || DEVELOPMENT_BUILD +#define ACTK_DEBUG_ENABLED +#endif + +namespace CodeStage.AntiCheat.Detectors +{ + using Common; + + using System; + using UnityEngine; + using Utils; + + /// + /// Allows to detect Cheat Engine's speed hack (and maybe some other speed hack tools) usage. + /// + /// Just add it to any GameObject as usual or through the "GameObject > Create Other > Code Stage > Anti-Cheat Toolkit" + /// menu to get started.
+ /// You can use detector completely from inspector without writing any code except the actual reaction on cheating. + /// + /// Avoid using detectors from code at the Awake phase. + [AddComponentMenu(MenuPath + ComponentName)] + [DisallowMultipleComponent] + [HelpURL(ACTk.DocsRootUrl + "class_code_stage_1_1_anti_cheat_1_1_detectors_1_1_speed_hack_detector.html")] + public class SpeedHackDetector : ACTkDetectorBase + { + public const string ComponentName = "Speed Hack Detector"; + internal const string LogPrefix = ACTk.LogPrefix + ComponentName + ": "; + + #region public fields + /// + /// Time (in seconds) between detector checks. + /// + [Tooltip("Time (in seconds) between detector checks.")] + public float interval = 1f; + + /// + /// Allowed speed multiplier threshold. Do not set to too low values (e.g. 0 or 0.00*) since there are timer fluctuations on different hardware. + /// + [Tooltip("Allowed speed multiplier threshold. Do not set to too low values (e.g. 0 or 0.00*) since there are timer fluctuations on different hardware.")] + [Range(0.05f, 5f)] + public float threshold = 0.2f; + + /// + /// Maximum false positives count allowed before registering speed hack. + /// + [Tooltip("Maximum false positives count allowed before registering speed hack.")] + public byte maxFalsePositives = 3; + + /// + /// Amount of sequential successful checks before clearing internal false positives counter.
+ /// Set 0 to disable Cool Down feature. + ///
+ [Tooltip("Amount of sequential successful checks before clearing internal false positives counter.\nSet 0 to disable Cool Down feature.")] + public int coolDown = 30; + #endregion + + /// + /// Controls whether to use DSP Timer to catch speed hacks in sandboxed environments (like WebGL, VMs, etc.). + /// + /// Uses AudioSettings.dspTime under the hood, which can catch some extra speed hacks in sandboxed environments + /// but can potentially cause false positives on some hardware due to way too high sensitivity. + /// \htmlonlyWARNING:\endhtmlonly Use at your peril! + [field:SerializeField, Tooltip("Uses AudioSettings.dspTime under the hood, which can catch some extra speed hacks " + + "in sandboxed environments but can potentially cause false positives on some hardware. " + + "Use at your peril!")] + public bool UseDsp { get; set; } + + #region private fields + private byte currentFalsePositives; + private int currentCooldownShots; + private long previousReliableTicks; + + private long previousEnvironmentTicks; + private long previousRealtimeTicks; + private long previousDspTicks; + + private bool resetTicksOnNextInterval; + #endregion + + #region public static methods + /// + /// Creates new instance of the detector at scene if it doesn't exists. Make sure to call NOT from Awake phase. + /// + /// New or existing instance of the detector. + public static SpeedHackDetector AddToSceneOrGetExisting() + { + return GetOrCreateInstance; + } + + /// + /// Starts speed hack detection for detector you have in scene. + /// + /// Make sure you have properly configured detector in scene with #autoStart disabled before using this method. + public static SpeedHackDetector StartDetection() + { + if (Instance != null) + return Instance.StartDetectionInternal(null, Instance.interval, Instance.maxFalsePositives, Instance.coolDown); + + Debug.LogError(LogPrefix + "can't be started since it doesn't exists in scene or not yet initialized!"); + return null; + } + + /// + /// Starts speed hack detection with specified callback. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + public static SpeedHackDetector StartDetection(Action callback) + { + return StartDetection(callback, GetOrCreateInstance.interval); + } + + /// + /// Starts speed hack detection with specified callback using passed interval.
+ ///
+ /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + /// Time in seconds between speed hack checks. Overrides #interval property. + public static SpeedHackDetector StartDetection(Action callback, float interval) + { + return StartDetection(callback, interval, GetOrCreateInstance.maxFalsePositives); + } + + /// + /// Starts speed hack detection with specified callback using passed interval and maxFalsePositives.
+ ///
+ /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + /// Time in seconds between speed hack checks. Overrides #interval property. + /// Amount of possible false positives. Overrides #maxFalsePositives property. + public static SpeedHackDetector StartDetection(Action callback, float interval, byte maxFalsePositives) + { + return StartDetection(callback, interval, maxFalsePositives, GetOrCreateInstance.coolDown); + } + + /// + /// Starts speed hack detection with specified callback using passed interval, maxFalsePositives and coolDown. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + /// Time in seconds between speed hack checks. Overrides #interval property. + /// Amount of possible false positives. Overrides #maxFalsePositives property. + /// Amount of sequential successful checks before resetting false positives counter. Overrides #coolDown property. + public static SpeedHackDetector StartDetection(Action callback, float interval, byte maxFalsePositives, int coolDown) + { + return GetOrCreateInstance.StartDetectionInternal(callback, interval, maxFalsePositives, coolDown); + } + + /// + /// Stops detector. Detector's component remains in the scene. Use Dispose() to completely remove detector. + /// + public static void StopDetection() + { + if (Instance != null) + Instance.StopDetectionInternal(); + } + + /// + /// Stops and completely disposes detector component. + /// + /// On dispose Detector follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically + /// destroyed if no other Detectors left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only + /// if it has neither other components nor children attached; + public static void Dispose() + { + if (Instance != null) + Instance.DisposeInternal(); + } + #endregion + + /// + /// Manually triggers cheating detection and invokes assigned events. + /// + [ContextMenu("Trigger detection")] + public void TriggerDetection() + { + if (!IsRunning) + { + Debug.LogWarning(LogPrefix + "Detector is not running, can't trigger detection."); + return; + } + + OnCheatingDetected(); + } + + private SpeedHackDetector() // prevents direct instantiation + { +#if UNITY_EDITOR + // prevents in-editor false positives due to PlayMode pause + UnityEditor.EditorApplication.pauseStateChanged += state => + { + OnApplicationPause(state == UnityEditor.PauseState.Paused); + }; +#endif + } + + #region unity messages + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnApplicationPause(bool pause) + { + if (!pause && IsStarted) + { + ResetLastTicks(); + resetTicksOnNextInterval = true; + } + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void Update() + { + if (!IsRunning) + return; + + var reliableTicks = TimeUtils.GetReliableTicks(); + var intervalTicks = (long)(interval * TimeUtils.TicksPerSecond); + + // return if configured interval is not passed yet + if (reliableTicks - previousReliableTicks < intervalTicks) + return; + + if (resetTicksOnNextInterval) + { + ResetLastTicks(); + resetTicksOnNextInterval = false; + previousReliableTicks = reliableTicks; + return; + } + + var reliableDelta = reliableTicks - previousReliableTicks; + + var cheatedEnvironment = IsTicksCheated(TimeUtils.GetEnvironmentTicks(), ref previousEnvironmentTicks, reliableDelta); + var cheatedRealtime = IsTicksCheated(TimeUtils.GetRealtimeTicks(), ref previousRealtimeTicks, reliableDelta); + var cheatedDsp = false; + +#if UNITY_AUDIO_MODULE + if (SystemInfo.supportsAudio && UseDsp) + { + var dspTicks = TimeUtils.GetDspTicks(); + if (dspTicks != 0 && !AudioListener.pause) + cheatedDsp = IsTicksCheated(dspTicks, ref previousDspTicks, reliableDelta); + else + previousDspTicks = 0; + } + else + { + previousDspTicks = 0; + } +#endif + + if (cheatedEnvironment || cheatedRealtime || cheatedDsp) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(LogPrefix + "Detection backlog:\n" + + $"reliableTicks: {reliableTicks}\n" + + $"cheatedEnvironment: {cheatedEnvironment}\n" + + $"cheatedRealtime: {cheatedRealtime}\n" + + $"cheatedDsp: {cheatedDsp}"); +#endif + currentFalsePositives++; + if (currentFalsePositives > maxFalsePositives) + { +#if ACTK_DEBUG_ENABLED + Debug.LogWarning(LogPrefix + "final detection!", this); +#endif + OnCheatingDetected(); + } + else + { +#if ACTK_DEBUG_ENABLED + Debug.LogWarning(LogPrefix + "detection! Allowed false positives left: " + (maxFalsePositives - currentFalsePositives), this); +#endif + currentCooldownShots = 0; + ResetLastTicks(); + } + } + else if (currentFalsePositives > 0 && coolDown > 0) + { +#if ACTK_DEBUG_ENABLED + Debug.Log(LogPrefix + "success shot! Shots till cool down: " + (coolDown - currentCooldownShots), this); +#endif + currentCooldownShots++; + if (currentCooldownShots >= coolDown) + { +#if ACTK_DEBUG_ENABLED + Debug.Log(LogPrefix + "cool down!", this); +#endif + currentFalsePositives = 0; + } + } + + previousReliableTicks = reliableTicks; + } + + #endregion + + private SpeedHackDetector StartDetectionInternal(Action callback, float checkInterval, byte falsePositives, int shotsTillCooldown) + { + if (IsRunning) + { + Debug.LogWarning(LogPrefix + "already running!", this); + return this; + } + + if (!enabled) + { + Debug.LogWarning($"{LogPrefix}disabled but {nameof(StartDetection)} still called from somewhere (see stack trace for this message)!", this); + return this; + } + + if (callback != null && DetectorHasListeners()) + Debug.LogWarning($"{LogPrefix}has properly configured Detection Event in the inspector or {nameof(CheatDetected)} event subscriber, but still get started with Action callback." + + $"Action will be called at the same time with Detection Event or {nameof(CheatDetected)} on detection." + + "Are you sure you wish to do this?", this); + + if (callback == null && !DetectorHasListeners()) + Debug.LogWarning($"{LogPrefix}was started without Detection Event, Callback or {nameof(CheatDetected)} event subscription." + + $"Cheat will not be detected until you subscribe to {nameof(CheatDetected)} event.", this); + + if (callback != null) + CheatDetected += callback; + + interval = checkInterval; + maxFalsePositives = falsePositives; + coolDown = shotsTillCooldown; + + ResetLastTicks(); + currentFalsePositives = 0; + currentCooldownShots = 0; + + IsStarted = true; + IsRunning = true; + + return this; + } + + protected override void StartDetectionAutomatically() + { + StartDetectionInternal(null, interval, maxFalsePositives, coolDown); + } + + private bool IsTicksCheated(long ticks, ref long previousTicks, long reliableDelta) + { + var delta = ticks - previousTicks; + var multiplier = Math.Abs(1 - (double)delta / reliableDelta); + + var cheated = multiplier > threshold; + if (cheated) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(LogPrefix + "Detection backlog:\n" + + $"reliableDelta: {reliableDelta}\n" + + $"delta: {delta}\n" + + $"multiplier > threshold: {multiplier} > {threshold}\n" + + $"ticks: {ticks}"); +#endif + } + + previousTicks = ticks; + return cheated; + } + + private void ResetLastTicks() + { + previousReliableTicks = TimeUtils.GetReliableTicks(); + previousEnvironmentTicks = TimeUtils.GetEnvironmentTicks(); + previousRealtimeTicks = TimeUtils.GetRealtimeTicks(); + previousDspTicks = TimeUtils.GetDspTicks(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs.meta new file mode 100644 index 0000000..e33ffe4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/SpeedHackDetector.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: d0d04994c2cd96140a8cf16a1ede4fb1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs new file mode 100644 index 0000000..0997e78 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs @@ -0,0 +1,1224 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#pragma warning disable 618 + +#if (UNITY_EDITOR || DEVELOPMENT_BUILD) +#define ACTK_DEBUG_ENABLED +#endif + +#define ACTK_DETECTOR_ENABLED +#if ACTK_PREVENT_INTERNET_PERMISSION +#undef ACTK_DETECTOR_ENABLED +#endif + +#if !UNITY_WEBGL +#define ACTK_ASYNC +#endif + +#if UNITY_WEBGL && !UNITY_EDITOR +#define ACTK_WEBGL_BUILD +#endif + +namespace CodeStage.AntiCheat.Detectors +{ + using Common; + + using System; + using System.Collections; + using ObscuredTypes; +#if ACTK_ASYNC + using System.Threading.Tasks; +#endif + +#if ACTK_DETECTOR_ENABLED + using UnityEngine.Networking; + using Utils; +#endif + + using UnityEngine; + using UnityEngine.Serialization; + + /// + /// Allows to detect time cheating using time from any properly configured server (almost all servers around the web). + /// + /// Requires Internet connection and appropriate 'android.permission.INTERNET' permission when used on Android platform.
+ /// Automatically switches to the current domain on WebGL (if #RequestUrl leads to any external resource) to avoid CORS limitation.
+ /// Make sure your server returns correct Date response header value in case of problems. + /// + /// Doesn't detects cheating if there is no Internet connection, should work even with weak connection though.
+ /// Just add it to any GameObject as usual or through the "GameObject > Create Other > Code Stage > Anti-Cheat Toolkit" + /// menu to get started.
+ /// You can use detector completely from inspector without writing any code except the actual reaction on cheating. + /// + /// Avoid using detectors from code at the Awake phase. + [AddComponentMenu(MenuPath + ComponentName)] + [DisallowMultipleComponent] + [HelpURL(ACTk.DocsRootUrl + "class_code_stage_1_1_anti_cheat_1_1_detectors_1_1_wall_hack_detector.html")] + public class TimeCheatingDetector : ACTkDetectorBase + { + /// + /// Delegate with result of online time receive attempt. + /// + /// OnlineTimeResult instance with details about operation result. + public delegate void OnlineTimeCallback(OnlineTimeResult result); + + /// + /// Delegate with cheat check result. + /// + /// Result of the cheat check. + /// Kind of occured error, if any. + public delegate void TimeCheatingDetectorEventHandler(CheckResult result, ErrorKind error); + + /// + /// Result of the online time receive attempt. + /// + public struct OnlineTimeResult + { + // TODO: make fields private in later versions + + [Obsolete("Please use Success property instead")] + public bool success; + + [Obsolete("Please use Error property instead")] + public string error; + + [Obsolete("Please use ErrorResponseCode property instead")] + public long errorResponseCode; + + [Obsolete("Please use OnlineSecondsUtc property instead")] + public double onlineSecondsUtc; + + [Obsolete("Please use OnlineDateTimeUtc property instead")] + public DateTime onlineDateTimeUtc; + + /// + /// Indicates success of the operation. + /// + public bool Success => success; + + /// + /// Error text (check if success == false). + /// + public string Error => error; + + /// + /// HTTP Response Code for the error. + /// + public long ErrorResponseCode => errorResponseCode; + + /// + /// UTC seconds value retrieved from the online server. + /// + public double OnlineSecondsUtc => onlineSecondsUtc; + + /// + /// UTC DateTime retrieved from the online server. + /// + public DateTime OnlineDateTimeUtc => onlineDateTimeUtc; + + internal OnlineTimeResult SetTime(double secondsUtc, DateTime dateTimeUtc) + { + success = true; + error = null; + errorResponseCode = -1; + onlineSecondsUtc = secondsUtc; + onlineDateTimeUtc = dateTimeUtc; + + return this; + } + + internal OnlineTimeResult SetError(string errorText, long responseCode = -1) + { + success = false; + error = errorText; + errorResponseCode = responseCode; + onlineSecondsUtc = -1; + + return this; + } + + public override string ToString() + { + if (success) + return $"{nameof(onlineSecondsUtc)}: {onlineSecondsUtc}"; + + return "Error response code: " + errorResponseCode + "\nError: " + error; + } + } + + /// + /// Describes possible detector check results. + /// + public enum CheckResult + { + /// + /// Cheat detection was not started yet or is in progress. + /// + Unknown = 0, + + /// + /// Cheat check successfully passed and nor cheating nor wrong time was detected. + /// + CheckPassed = 5, + + /// + /// Direct time cheating was not detected but difference between local and online UTC clocks exceeds the #wrongTimeThreshold. + /// + WrongTimeDetected = 10, + + /// + /// Subsequent measurements difference of local and online time difference exceeded the #realCheatThreshold. + /// + CheatDetected = 15, + + /// + /// There was error while making cheat check, please check #LastError for details. + /// + Error = 100 + } + + /// + /// Describes possible detector errors. + /// + public enum ErrorKind + { + /// + /// Indicates there were no any error registered. + /// + NoError = 0, + + /// + /// Url set for the online time receiving is not a correct URI. + /// + IncorrectUri = 3, + + /// + /// Error while receiving online time (check logs for error details). + /// + OnlineTimeError = 5, + + /// + /// Detector was not started yet. It should be started before performing any cheat checks. + /// + NotStarted = 10, + + /// + /// Detector already checks for the cheat. + /// Please make sure #IsCheckingForCheat == false before trying to force another cheat check. + /// + AlreadyCheckingForCheat = 15, + + /// + /// Something strange happened, please check logs for details. + /// + Unknown = 100 + } + + /// + /// Method of the request to the server. Please consider Head by default and fall back to Get in case of problems. + /// + /// Some servers do not like HEAD requests and sometimes treat it as a malicious bot activity and may temporary block the caller.
+ /// For such servers use GET method as a more compatible yet slower and loading all page data. + public enum RequestMethod + { + /// + /// Preferable method as it requests only headers thus it runs faster and has minimal possible traffic. + /// + Head, + + /// + /// More compatible method which loads whole content at the given URL. + /// + Get + } + + public const string ComponentName = "Time Cheating Detector"; + private const string LogPrefix = ACTk.LogPrefix + ComponentName + ": "; + private const int DefaultTimeoutSeconds = 10; + +#if ACTK_DETECTOR_ENABLED + private static readonly WaitForEndOfFrame CachedEndOfFrame = new WaitForEndOfFrame(); + private static Lazy CachedCertificateHandler { get; } = + new Lazy(InstantiateCertificateHandler); + + private static bool gettingOnlineTime; + +#if UNITY_ANDROID + private static int sdkLevel; +#endif + + #region public fields and properties + + /// + /// Gets called after each cheat check and provides results of the check. + /// + public event TimeCheatingDetectorEventHandler CheatChecked; + + [Header("Request settings")] + + [Tooltip("Absolute URL which will return correct datetime in response headers (you may use popular web servers like google.com, microsoft.com etc.).")] + [SerializeField] + private string requestUrl = "https://google.com"; + + /// + /// Absolute URL which will return correct Date in response header to the HEAD request (nearly any popular web server out there including google.com, microsoft.com etc.). + /// + public string RequestUrl + { + get => requestUrl; + set + { + if (requestUrl == value || !Application.isPlaying) return; + + requestUrl = value; + cachedUri = UrlToUri(requestUrl); + } + } + + /// + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + /// + [Tooltip("Method to use for url request. Use Head method if possible and fall back to get if server does not " + + "reply or block head requests.")] + public RequestMethod requestMethod = RequestMethod.Head; + + /// + /// Online time request timeout in seconds. Request will be automatically aborted if server will not response in specified time. + /// + [Tooltip("Online time request timeout in seconds.")] + public int timeoutSeconds = 10; + + /// + /// Time (in minutes) between detector checks. Set to 0 to disable automatic time checks and use + /// ForceCheck(), ForceCheckEnumerator() or ForceCheckTask() to manually run a check. + /// + [Header("Settings in minutes")] + [Tooltip("Time (in minutes) between detector checks.")] + [Range(0f, 60)] + public float interval = 5; + + /// + /// Maximum allowed difference between subsequent measurements, in minutes. + /// + [Tooltip("Maximum allowed difference between subsequent measurements, in minutes.")] + [FormerlySerializedAs("threshold")] + [Range(10, 180)] + public int realCheatThreshold = 65; + + /// + /// Maximum allowed difference between local and online time, in minutes. + /// + /// If online and local time difference exceed this threshold, detector will raise an event with + [Tooltip("Maximum allowed difference between local and online time, in minutes.")] + [Range(1, 180)] + public int wrongTimeThreshold = 65; + + /// + /// Ignore case when time changes to be in sync with online correct time. + /// + /// Wrong time threshold is taken into account. + [Tooltip("Ignore case when time changes to be in sync with online correct time. " + + "Wrong time threshold is taken into account.")] + public bool ignoreSetCorrectTime = true; + + /// + /// Last detector error kind. Will be ErrorKind.NoError if there were no errors. + /// + public ErrorKind LastError { get; private set; } + + /// + /// Last check result. Check #LastError if this has value of CheckResult.Error. + /// + public CheckResult LastResult { get; private set; } + + /// + /// Complete response data for the last time request. + /// + public OnlineTimeResult LastOnlineTimeResult { get; private set; } + + /// + /// Allows to check if cheating check is currently in process. + /// + public bool IsCheckingForCheat { get; private set; } + + #endregion + + #region private and protected fields + + private readonly string onlineOfflineDifferencePrefsKey = Base64Utils.ToBase64(ObscuredString.Encrypt("onlineOfflineSecondsDifference", "TeslaOnMars".ToCharArray())); + + private Uri cachedUri; + private TimeCheatingDetectorEventHandler cheatChecked; + private float timeElapsed; + private bool updateAfterPause; + private double lastOnlineSecondsUtc; + + #endregion + + #region Unity messages + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnApplicationPause(bool pauseStatus) + { + if (!IsStarted) return; + + if (pauseStatus) + PauseDetector(); + else + ResumeDetector(); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void Update() + { + if (!IsStarted || !IsRunning) return; + + if (interval > 0) + { + if (updateAfterPause) + { + updateAfterPause = false; + return; + } + + timeElapsed += Time.unscaledDeltaTime; + if (timeElapsed >= interval * 60) + { + timeElapsed = 0; + StartCoroutine(CheckForCheat()); + } + } + } + + #endregion + + #region public static methods + /// + /// Creates new instance of the detector at scene if it doesn't exists. Make sure to call NOT from Awake phase. + /// + /// New or existing instance of the detector. + public static TimeCheatingDetector AddToSceneOrGetExisting() + { + return GetOrCreateInstance; + } + + /// + /// Starts detection with specified callback. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after each cheat check. Pass null if you wish to use event, set in detector inspector. + public static TimeCheatingDetector StartDetection(TimeCheatingDetectorEventHandler cheatCheckedEventHandler = null) + { + if (cheatCheckedEventHandler == null) + { + if (Instance != null) + { + return Instance.StartDetectionInternal(Instance.interval); + } + + return StartDetection(GetOrCreateInstance.interval, null); + } + + return StartDetection(GetOrCreateInstance.interval, cheatCheckedEventHandler); + } + + /// + /// Starts detection with specified callback using passed interval.
+ ///
+ /// If you pass cheatCheckedCallback than make sure you have no filled Detection Event on detector instance in scene to avoid duplicate event calls.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Time in minutes between checks. Overrides #interval property. + /// Method to call after each cheat check. Pass null if you wish to use event, set in detector inspector. + public static TimeCheatingDetector StartDetection(float intervalMinutes, TimeCheatingDetectorEventHandler cheatCheckedEventHandler = null) + { + return GetOrCreateInstance.StartDetectionInternal(intervalMinutes, cheatCheckedEventHandler); + } + + /// - + /// Stops detector. Detector's component remains in the scene. Use Dispose() to completely remove detector. + /// + public static void StopDetection() + { + if (Instance != null) Instance.StopDetectionInternal(); + } + + /// + /// Stops and completely disposes detector component. + /// + /// On dispose Detector follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically + /// destroyed if no other Detectors left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only + /// if it has neither other components nor children attached; + public static void Dispose() + { + if (Instance != null) Instance.DisposeInternal(); + } + + /// + /// Receives UTC seconds from url. Runs asynchronously in coroutine. + /// + /// Automatically switches to the current domain when running in WebGL to avoid CORS limitation. + /// Absolute url to receive time from. + /// Make sure this server has proper Date values in the response headers + /// (almost all popular web sites are suitable). + /// Delegate to call and pass OnlineTimeResult to. + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + public static IEnumerator GetOnlineTimeCoroutine(string url, OnlineTimeCallback callback, RequestMethod method = RequestMethod.Head) + { + var uri = UrlToUri(url); + yield return GetOnlineTimeCoroutine(uri, callback, method); + } + + /// + /// Receives UTC seconds from url. Runs asynchronously in coroutine. + /// + /// Automatically switches to the current domain when running in WebGL to avoid CORS limitation. + /// Absolute url to receive time from. + /// Make sure this server has proper Date values in the response headers + /// (almost all popular web sites are suitable). + /// Delegate to call and pass OnlineTimeResult to. + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + public static IEnumerator GetOnlineTimeCoroutine(Uri uri, OnlineTimeCallback callback, RequestMethod method = RequestMethod.Head) + { +#if ACTK_WEBGL_BUILD + EnsureCurrentDomainUsed(ref uri); +#endif + + if (gettingOnlineTime) + yield return CachedEndOfFrame; + + gettingOnlineTime = true; + + var result = new OnlineTimeResult(); + + using (var wr = GetWebRequest(uri, method)) + { + yield return wr.SendWebRequest(); + FillRequestResult(wr, ref result); + } + + callback?.Invoke(result); + + gettingOnlineTime = false; + } + +#if ACTK_ASYNC + /// + /// Receives UTC seconds from url. Runs asynchronously. + /// + /// Automatically switches to the current domain when running in WebGL to avoid CORS limitation. + /// Absolute url to receive time from. + /// Make sure this server has proper Date values in the response headers + /// (almost all popular web sites are suitable). + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + /// OnlineTimeResult with UTC seconds or error. + public static Task GetOnlineTimeTask(string url, RequestMethod method = RequestMethod.Head) + { + return GetOnlineTimeTask(url, System.Threading.CancellationToken.None, method); + } + + /// + /// Receives UTC seconds from url. Runs asynchronously. + /// + /// Automatically switches to the current domain when running in WebGL to avoid CORS limitation. + /// Absolute url to receive time from. + /// Make sure this server has proper Date values in the response headers + /// (almost all popular web sites are suitable). + /// CancellationToken to cancel the operation. + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + /// OnlineTimeResult with UTC seconds or error. + public static Task GetOnlineTimeTask(string url, System.Threading.CancellationToken cancellationToken, RequestMethod method = RequestMethod.Head) + { + var uri = UrlToUri(url); + return GetOnlineTimeTask(uri, cancellationToken, method); + } + + /// + /// Receives UTC seconds from url. Runs asynchronously. + /// + /// Automatically switches to the current domain when running in WebGL to avoid CORS limitation. + /// Absolute url to receive time from. + /// Make sure this server has proper Date values in the response headers + /// (almost all popular web sites are suitable). + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + /// OnlineTimeResult with UTC seconds or error. + public static Task GetOnlineTimeTask(Uri uri, RequestMethod method = RequestMethod.Head) + { + return GetOnlineTimeTask(uri, System.Threading.CancellationToken.None, method); + } + + /// + /// Receives UTC seconds from url. Runs asynchronously. + /// + /// Automatically switches to the current domain when running in WebGL to avoid CORS limitation. + /// Absolute url to receive time from. + /// Make sure this server has proper Date values in the response headers + /// (almost all popular web sites are suitable). + /// CancellationToken to cancel the operation. + /// Method to use for url request. Use Head method if possible and fall back to get if server does not reply or block head requests. + /// OnlineTimeResult with UTC seconds or error. + public static async Task GetOnlineTimeTask(Uri uri, System.Threading.CancellationToken cancellationToken, RequestMethod method = RequestMethod.Head) + { +#if ACTK_WEBGL_BUILD + EnsureCurrentDomainUsed(ref uri); +#endif + while (gettingOnlineTime) + { + try + { + cancellationToken.ThrowIfCancellationRequested(); + await Task.Delay(100, cancellationToken); + } + catch (OperationCanceledException) + { + return new OnlineTimeResult().SetError("Operation cancelled while waiting for previous attempt."); + } + } + + gettingOnlineTime = true; + + var result = new OnlineTimeResult(); + + try + { + using (var wr = GetWebRequest(uri, method)) + { + var asyncOperation = wr.SendWebRequest(); + + while (!asyncOperation.isDone) + { + cancellationToken.ThrowIfCancellationRequested(); + await Task.Delay(100, cancellationToken); + } + + FillRequestResult(wr, ref result); + } + } + catch (OperationCanceledException) + { + result = new OnlineTimeResult().SetError("Operation cancelled."); + } + catch (Exception e) + { + Debug.LogError($"{LogPrefix} Couldn't retrieve online time"); + result = new OnlineTimeResult().SetError(e.Message); + } + finally + { + gettingOnlineTime = false; + } + + return result; + } +#endif + #endregion + +#if ACTK_WEBGL_BUILD + private static string currentDomain; + private static Uri currentUri; + + private static void EnsureCurrentDomainUsed(ref string url) + { + FillCurrentDomainAndUriIfNecessary(); + + if (!url.Contains(currentDomain)) + url = currentDomain; + } + + private static void EnsureCurrentDomainUsed(ref Uri uri) + { + FillCurrentDomainAndUriIfNecessary(); + + if (currentUri.GetLeftPart(UriPartial.Authority) != uri.GetLeftPart(UriPartial.Authority)) + { + uri = currentUri; + } + } + + private static void FillCurrentDomainAndUriIfNecessary() + { + if (!string.IsNullOrEmpty(currentDomain)) + return; + + var ownUrl = Application.absoluteURL; + if (string.IsNullOrEmpty(ownUrl)) + { + Debug.LogWarning($"{LogPrefix} Couldn't get valid string from Application.absoluteURL"); + return; + } + + currentUri = new Uri(ownUrl); + currentDomain = currentUri.GetLeftPart(UriPartial.Authority); + } +#endif + + private static NonValidatingCertificateHandler InstantiateCertificateHandler() + { + return new NonValidatingCertificateHandler(); + } + + private static UnityWebRequest GetWebRequest(Uri uri, RequestMethod method) + { + var request = new UnityWebRequest(uri, method == RequestMethod.Head ? UnityWebRequest.kHttpVerbHEAD : UnityWebRequest.kHttpVerbGET) + { + useHttpContinue = false, + timeout = Instance ? Instance.timeoutSeconds : DefaultTimeoutSeconds, + certificateHandler = CachedCertificateHandler.Value, + disposeCertificateHandlerOnDispose = false + }; + +#if UNITY_ANDROID + if (method == RequestMethod.Head && Application.platform == RuntimePlatform.Android) + { + try + { + if (sdkLevel == 0) + sdkLevel = GetAndroidSDKLevel(); + + if (sdkLevel <= 17) + request.SetRequestHeader("Accept-Encoding", ""); + + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Couldn't get SDK version or set Accept-Encoding header.", LogPrefix, e); + } + } +#endif + return request; + } + + private static void FillRequestResult(UnityWebRequest request, ref OnlineTimeResult result) + { + if (!string.IsNullOrEmpty(request.error)) + { + result.SetError("UnityWebRequest Error: " + request.error, request.responseCode); + } + else + { + var dateHeader = request.GetResponseHeader("Date"); + if (!string.IsNullOrEmpty(dateHeader)) + { + var success = TryGetDate(dateHeader, out var serverTime); + if (success) + { + var onlineTimeUtc = serverTime.ToUniversalTime(); + var onlineSecondsUtc = onlineTimeUtc.Ticks / (double)TimeSpan.TicksPerSecond; + result.SetTime(onlineSecondsUtc, onlineTimeUtc); + } + else + { + result.SetError("Couldn't parse 'Date' response header value\n " + dateHeader, request.responseCode); + } + } + else + { + result.SetError("Couldn't find 'Date' response header value!", request.responseCode); + } + } + + if (!result.success) + Debug.Log(LogPrefix + "Online Time Retrieve error:\n" + result); + } + + private static Uri UrlToUri(string url) + { +#if ACTK_WEBGL_BUILD + EnsureCurrentDomainUsed(ref url); +#endif + var success = Uri.TryCreate(url, UriKind.Absolute, out var result); + if (!success) + Debug.LogError(LogPrefix + "Could not create URI from URL: " + url); + + return result; + } + + // naive but blazingly fast standard HTTP GMT Date parsing + // ex. 'Tue, 18 Sep 2018 16:28:26 GMT' (ddd, dd MMM yyyy HH:mm:ss 'GMT') + // (C) Dmitriy Yukhanov | codestage.net + private static bool TryGetDate(string source, out DateTime date) + { + try + { + var chars = source.ToCharArray(5, 20); + + var d1 = chars[0] & 0x0f; + var d2 = chars[1] & 0x0f; + var day = d1 * 10 + d2; + + var mo1 = (int)chars[4]; + var mo2 = (int)chars[5]; + var sum = mo1 + mo2; + int month; + + switch (sum) + { + case 207: + month = 1; + break; + case 199: + month = 2; + break; + case 211: + month = 3; + break; + case 226: + month = 4; + break; + case 218: + month = 5; + break; + case 227: + month = 6; + break; + case 225: + month = 7; + break; + case 220: + month = 8; + break; + case 213: + month = 9; + break; + case 215: + month = 10; + break; + case 229: + month = 11; + break; + case 200: + month = 12; + break; + default: + month = 1; + break; + } + + var y1 = chars[7] & 0x0f; + var y2 = chars[8] & 0x0f; + var y3 = chars[9] & 0x0f; + var y4 = chars[10] & 0x0f; + var year = y1 * 1000 + y2 * 100 + y3 * 10 + y4; + + var h1 = chars[12] & 0x0f; + var h2 = chars[13] & 0x0f; + var hour = h1 * 10 + h2; + + var m1 = chars[15] & 0x0f; + var m2 = chars[16] & 0x0f; + var minute = m1 * 10 + m2; + + var s1 = chars[18] & 0x0f; + var s2 = chars[19] & 0x0f; + var second = s1 * 10 + s2; + + date = new DateTime(year, month, day, hour, minute, second, DateTimeKind.Utc); + + return true; + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Error while parsing date!", LogPrefix, e); + date = default; + return false; + } + } + + #region public instance methods + + /// + /// Manually triggers cheating detection and invokes assigned events. + /// + [ContextMenu("Trigger detection")] + public void TriggerDetection() + { + if (!IsRunning) + { + Debug.LogWarning(LogPrefix + "Detector is not running, can't trigger detection."); + return; + } + + LastResult = CheckResult.CheatDetected; + LastError = ErrorKind.NoError; + + ReportCheckResult(); + } + + /// + /// Allows to manually execute cheating check. Restarts #interval. + /// + /// Listen for detector events to know about check result. + /// True if check was started. + public bool ForceCheck() + { + if (!IsReadyForForceCheck()) + return false; + + StartCoroutine(CheckForCheat()); + + return true; + } + + /// + /// Allows to manually execute cheating check and wait for the completion within coroutine. Restarts #interval. + /// + /// Use inside of the coroutine and check #LastResult property after yielding this method. + /// Detector events will be invoked too. + /// Example: + /// \code + /// StartCoroutine(MakeForcedCheck()); + /// private IEnumerator MakeForcedCheck() + /// { + /// yield return TimeCheatingDetector.Instance.ForceCheckEnumerator(); + /// // check TimeCheatingDetector.Instance.LastResult + /// // ... + /// } + /// \endcode + public IEnumerator ForceCheckEnumerator() + { + if (!IsReadyForForceCheck()) + yield break; + + yield return CheckForCheat(); + + while (IsCheckingForCheat) + { + yield return CachedEndOfFrame; + } + } + +#if ACTK_ASYNC + /// + /// Allows to manually execute cheating check and wait for the completion within async method. Restarts #interval. + /// + /// Await this method in async method to wait for the check completion and to get the check result. + /// Detector events will be invoked too. + /// Disabled for WebGL platform. + /// \code + /// MakeForcedCheckAsync(); + /// private async void MakeForcedCheckAsync() + /// { + /// var result = await TimeCheatingDetector.Instance.ForceCheckTask(); + /// // check result + /// // ... + /// } + /// \endcode + public async Task ForceCheckTask() + { + if (!IsReadyForForceCheck()) + return LastResult; + + StartCoroutine(CheckForCheat()); + + await Task.Delay(50); + + if (IsCheckingForCheat) + { + while (IsCheckingForCheat) + { + await Task.Delay(50); + } + } + + return LastResult; + } +#endif + + /// + /// Call this to make sure detector is ready for the ForceCheck() call. + /// + /// True if you can call the ForceCheck and False otherwise. + public bool IsReadyForForceCheck() + { + if (!IsStarted || !IsRunning) + { + Debug.LogWarning(LogPrefix + "Detector should be started to use forced check."); + LastError = ErrorKind.NotStarted; + LastResult = CheckResult.Error; + return false; + } + + if (IsCheckingForCheat) + { + Debug.LogWarning(LogPrefix + "Can't force cheating check since another check is already in progress."); + LastError = ErrorKind.AlreadyCheckingForCheat; + LastResult = CheckResult.Error; + return false; + } + + timeElapsed = 0; + + return true; + } + + #endregion + + private TimeCheatingDetector StartDetectionInternal(float checkInterval, TimeCheatingDetectorEventHandler cheatCheckedEventHandler = null) + { + if (IsRunning) + { + Debug.LogWarning(LogPrefix + "already running!", this); + return this; + } + + if (!enabled) + { + Debug.LogWarning($"{LogPrefix}disabled but {nameof(StartDetection)} still called from somewhere (see stack trace for this message)!", this); + return this; + } + + timeElapsed = 0; + cheatChecked = cheatCheckedEventHandler; + interval = checkInterval; + + IsStarted = true; + IsRunning = true; + + return this; + } + + protected override bool Init(TimeCheatingDetector instance) + { + if (cachedUri == null) + cachedUri = UrlToUri(requestUrl); + + return base.Init(instance); + } + + protected override void StartDetectionAutomatically() + { + StartDetectionInternal(interval); + } + + protected override bool DetectorHasListeners() + { + return base.DetectorHasListeners() || CheatChecked != null || cheatChecked != null; + } + + protected override void PauseDetector() + { + base.PauseDetector(); + updateAfterPause = true; + } + + protected override void StopDetectionInternal() + { + base.StopDetectionInternal(); + + cheatChecked = null; + CheatChecked = null; + } + + private IEnumerator CheckForCheat() + { + if (!IsRunning || IsCheckingForCheat) + yield break; + + IsCheckingForCheat = true; + + LastError = ErrorKind.NoError; + LastResult = CheckResult.Unknown; + + if (cachedUri == null) + { + LastError = ErrorKind.IncorrectUri; + LastResult = CheckResult.Error; + } + else + { + yield return GetOnlineTimeCoroutine(cachedUri, OnOnlineTimeReceived, requestMethod); + } + + if (!IsStarted || !IsRunning) + { + LastError = ErrorKind.Unknown; + } + + if (lastOnlineSecondsUtc <= 0 && LastError == ErrorKind.NoError) + { + LastError = ErrorKind.Unknown; + } + + if (LastError != ErrorKind.NoError && LastError != ErrorKind.AlreadyCheckingForCheat) + { + LastResult = CheckResult.Error; + ReportCheckResult(); + IsCheckingForCheat = false; + yield break; + } + + LastError = ErrorKind.NoError; + + var offlineSecondsUtc = DateTime.UtcNow.Ticks / (double)TimeSpan.TicksPerSecond; // local utc secs + var offlineOnlineDifference = (int)Math.Abs(lastOnlineSecondsUtc - offlineSecondsUtc); + + LastResult = CheckResult.CheckPassed; + + if (offlineOnlineDifference > wrongTimeThreshold * 60) + { + LastResult = CheckResult.WrongTimeDetected; + } + + var lastOfflineOnlineDifference = PlayerPrefs.GetInt(onlineOfflineDifferencePrefsKey, 0); + if (lastOfflineOnlineDifference != 0) + { + lastOfflineOnlineDifference ^= int.MaxValue; + var differenceOfDifferences = Math.Abs(offlineOnlineDifference - lastOfflineOnlineDifference); + + if (realCheatThreshold < 10) + Debug.LogWarning(LogPrefix + "Please consider increasing realCheatThreshold to reduce false positives chance!"); + + if (differenceOfDifferences > realCheatThreshold * 60) + { + if (LastResult == CheckResult.WrongTimeDetected || !ignoreSetCorrectTime) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(LogPrefix + "Detection backlog:\n" + + "wrongTimeThreshold: " + wrongTimeThreshold + "\n" + + "realCheatThreshold: " + realCheatThreshold + "\n" + + "offlineSecondsUtc: " + offlineSecondsUtc + "\n" + + "lastOnlineSecondsUtc: " + lastOnlineSecondsUtc + "\n" + + "offlineOnlineDifference: " + offlineOnlineDifference + "\n" + + "lastOfflineOnlineDifference: " + lastOfflineOnlineDifference + "\n" + + "differenceOfDifferences: " + differenceOfDifferences); +#endif + LastResult = CheckResult.CheatDetected; + } + } + } + + PlayerPrefs.SetInt(onlineOfflineDifferencePrefsKey, offlineOnlineDifference ^ int.MaxValue); + IsCheckingForCheat = false; + ReportCheckResult(); + } + + private void ReportCheckResult() + { + cheatChecked?.Invoke(LastResult, LastError); + CheatChecked?.Invoke(LastResult, LastError); + + switch (LastResult) + { + case CheckResult.Unknown: + break; + case CheckResult.CheckPassed: + break; + case CheckResult.WrongTimeDetected: + break; + case CheckResult.CheatDetected: + OnCheatingDetected(); + break; + case CheckResult.Error: + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + private void OnOnlineTimeReceived(OnlineTimeResult result) + { + LastOnlineTimeResult = result; + if (result.success) + { + lastOnlineSecondsUtc = result.onlineSecondsUtc; + } + else + { + lastOnlineSecondsUtc = -1; + LastError = ErrorKind.OnlineTimeError; + } + } + +#if UNITY_ANDROID + private static int GetAndroidSDKLevel() + { + var osString = SystemInfo.operatingSystem; + if (string.IsNullOrEmpty(osString)) + return -1; + + var dashIndex = osString.IndexOf("-", StringComparison.Ordinal); + if (dashIndex <= 0) + return -1; + + if (osString.Length < dashIndex + 3) + return -1; + + var apiPart = osString.Substring(dashIndex + 1, 2); + if (string.IsNullOrEmpty(apiPart)) + return -1; + + if (!int.TryParse(apiPart, out var result)) + return -1; + + return result; + } +#endif + + #region obsolete members + + [Obsolete("Please use CheatChecked event instead", true)] +#pragma warning disable 67 + public event Action Error; + + [Obsolete("Please use CheatChecked event instead", true)] + public event Action CheckPassed; +#pragma warning restore 67 + + [Obsolete("Use wrongTimeThreshold instead.", true)] + [NonSerialized] + public int threshold = 65; + + [Obsolete("Use requestUrl instead", true)] + [NonSerialized] + public string timeServer = "google.com"; + + [Obsolete("Please use GetOnlineTimeCoroutine or GetOnlineTimeTask instead", true)] + public static double GetOnlineTime(string server) + { + return -1; + } + + [Obsolete("Please use Instance.Error event instead.", true)] + public static void SetErrorCallback(Action errorCallback) + { + + } + + [Obsolete("Please use StartDetection(int, ...) instead.", true)] + public static void StartDetection(Action detectionCallback, int interval) + { + + } + + [Obsolete("Please use StartDetection(int, ...) instead.", true)] + public static void StartDetection(Action detectionCallback, Action errorCallback, int interval) + { + + } + + [Obsolete("Please use other overloads of this method instead", true)] + public static void StartDetection(float interval, Action detectionCallback, Action errorCallback, Action checkPassedCallback) + { + + } + + #endregion +#else + private const string ErrorMessage = LogPrefix + " is disabled with ACTK_PREVENT_INTERNET_PERMISSION conditional or is not supported on current platform!"; + protected override void StartDetectionAutomatically() + { + Debug.LogError(ErrorMessage); + } +#endif + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs.meta new file mode 100644 index 0000000..d108ad2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/TimeCheatingDetector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1cb994d96ecfe4d4697d649e0e7d5100 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs new file mode 100644 index 0000000..d1e3059 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs @@ -0,0 +1,1162 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if (UNITY_EDITOR || DEVELOPMENT_BUILD) +#define ACTK_DEBUG_ENABLED +#if ACTK_WALLHACK_DEBUG +#define WALLHACK_DEBUG +#endif +#endif + +namespace CodeStage.AntiCheat.Detectors +{ + using Common; + + using System; + using System.Collections; + using UnityEngine; + using UnityEngine.Rendering; + + /// + /// Detects common types of wall hack cheating: walking through the walls (Rigidbody and CharacterController modules), + /// shooting through the walls (Raycast module), looking through the walls (Wireframe module). + /// + /// In order to work properly, this detector creates and uses some service objects right in the scene.
+ /// It places all such objects within 3x3x3 sandbox area which is placed at the #spawnPosition and drawn as a red wire cube in + /// the scene when you select Game Object with this detector.
+ /// Please, place this sandbox area at the empty unreachable space of your game to avoid any collisions and false positives.
+ /// + /// To get started:
+ /// - add detector to any GameObject as usual or through the "GameObject > Create Other > Code Stage > Anti-Cheat Toolkit" menu;
+ /// - make sure 3x3x3 area at the #spawnPosition is unreachable for any objects of your game; + /// + /// You can use detector completely from inspector without writing any code except the actual reaction on cheating. + /// + /// Avoid using detectors from code at the Awake phase. + /// + /// \htmlonlyNote #1:\endhtmlonly Adds new objects to the scene and places them into the + /// "[WH Detector Service]" container at the #spawnPosition.
+ /// \htmlonlyNote #2:\endhtmlonly May use physics and shaders. It may lead to the build size + /// increase and additional resources usage.
+ [AddComponentMenu(MenuPath + ComponentName)] + [DisallowMultipleComponent] + [HelpURL(ACTk.DocsRootUrl + "class_code_stage_1_1_anti_cheat_1_1_detectors_1_1_wall_hack_detector.html")] + public class WallHackDetector : ACTkDetectorBase + { + public const string ComponentName = "WallHack Detector"; + internal const string LogPrefix = ACTk.LogPrefix + ComponentName + ": "; + internal const string WireframeShaderName = "Hidden/ACTk/WallHackTexture"; + private const string ServiceContainerName = "[WH Detector Service]"; + private const int ShaderTextureSize = 4; + private const int RenderTextureSize = 4; + private const int ColorsDifferenceThreshold = 5; + + private readonly Vector3 rigidPlayerVelocity = new Vector3(0, 0, 1f); + + private readonly WaitForEndOfFrame waitForEndOfFrame = new WaitForEndOfFrame(); + + #region public properties + [SerializeField] + [Tooltip("Check for the \"walk through the walls\" kind of cheats made via Rigidbody hacks?")] + private bool checkRigidbody = true; + + /// + /// Check for the "walk through the walls" kind of cheats made via Rigidbody hacks? + /// + /// Disable to save some resources if you're not using Rigidbody for characters. + public bool CheckRigidbody + { + get => checkRigidbody; + set + { + if (checkRigidbody == value || !Application.isPlaying || !enabled || !gameObject.activeSelf) return; + checkRigidbody = value; + + if (!IsStarted) return; + + UpdateServiceContainer(); + if (checkRigidbody) + { + StartRigidModule(); + } + else + { + StopRigidModule(); + } + } + } + + [SerializeField] + [Tooltip("Check for the \"walk through the walls\" kind of cheats made via Character Controller hacks?")] + private bool checkController = true; + + /// + /// Check for the "walk through the walls" kind of cheats made via Character Controller hacks? + /// + /// Disable to save some resources if you're not using Character Controllers. + public bool CheckController + { + get => checkController; + set + { + if (checkController == value || !Application.isPlaying || !enabled || !gameObject.activeSelf) return; + checkController = value; + + if (!IsStarted) return; + + UpdateServiceContainer(); + if (checkController) + { + StartControllerModule(); + } + else + { + StopControllerModule(); + } + } + } + + [SerializeField] + [Tooltip("Check for the \"see through the walls\" kind of cheats made via shader or driver hacks (wireframe, color alpha, etc.)?")] + private bool checkWireframe = true; + + /// + /// Check for the "see through the walls" kind of cheats made via shader or driver hacks (wireframe, color alpha, etc.)? + /// + /// Disable to save some resources in case you don't care about such cheats. + /// + /// \htmlonlyNOTE:\endhtmlonly Uses specific shader under the hood. + /// Thus such shader should be included into the build to exist at runtime.
+ /// You may easily add or remove shader at the ACTk Settings window (Window > Code Stage > Anti-Cheat Toolkit > Settings).
+ /// You'll see error in logs at runtime if you'll have no needed shader included.
+ public bool CheckWireframe + { + get => checkWireframe; + set + { + if (checkWireframe == value || !Application.isPlaying || !enabled || !gameObject.activeSelf) return; + checkWireframe = value; + + if (!IsStarted) return; + + UpdateServiceContainer(); + if (checkWireframe) + { + StartWireframeModule(); + } + else + { + StopWireframeModule(); + } + } + } + + [SerializeField] + [Tooltip("Check for the \"shoot through the walls\" kind of cheats made via Raycast hacks?")] + private bool checkRaycast = true; + + /// + /// Check for the "shoot through the walls" kind of cheats made via Raycast hacks? + /// + /// Disable to save some resources in case you don't care about such cheats. + public bool CheckRaycast + { + get => checkRaycast; + set + { + if (checkRaycast == value || !Application.isPlaying || !enabled || !gameObject.activeSelf) return; + checkRaycast = value; + + if (!IsStarted) return; + + UpdateServiceContainer(); + if (checkRaycast) + { + StartRaycastModule(); + } + else + { + StopRaycastModule(); + } + } + } + #endregion + + #region public fields + /// + /// Delay between Wireframe module checks, from 1 up to 60 secs. + /// + [Tooltip("Delay between Wireframe module checks, from 1 up to 60 secs.")] + [Range(1f, 60f)] + public int wireframeDelay = 10; + + /// + /// Delay between Raycast module checks, from 1 up to 60 secs. + /// + [Tooltip("Delay between Raycast module checks, from 1 up to 60 secs.")] + [Range(1f, 60f)] + public int raycastDelay = 10; + + /// + /// World coordinates of the service container. + /// Please keep in mind it will have different active objects within 3x3x3 cube during gameplay. + /// It should be unreachable for your game objects to avoid collisions and false positives. + /// + [Tooltip("World position of the container for service objects within 3x3x3 cube (drawn as red wire cube in scene).")] + public Vector3 spawnPosition; + + /// + /// Maximum false positives in a row for each detection module before registering a wall hack. + /// + [Tooltip("Maximum false positives in a row for each detection module before registering a wall hack.")] + public byte maxFalsePositives = 3; + #endregion + + #region private variables + private GameObject serviceContainer; + private GameObject solidWall; + private GameObject thinWall; + + private Camera wfCamera; + private MeshRenderer foregroundRenderer; + private MeshRenderer backgroundRenderer; + private Color wfColor1 = Color.black; + private Color wfColor2 = Color.black; + private Shader wfShader; + private Material wfMaterial; + private Texture2D shaderTexture; + private Texture2D targetTexture; + private RenderTexture renderTexture; + + private int whLayer = -1; + private int raycastMask = -1; + + private Rigidbody rigidPlayer; + private CharacterController charControllerPlayer; + private float charControllerVelocity; + + private byte rigidbodyDetections; + private byte controllerDetections; + private byte wireframeDetections; + private byte raycastDetections; + + private bool wireframeDetected; + + private readonly RaycastHit[] rayHits = new RaycastHit[10]; + + #endregion + + #region public static methods + /// + /// Creates new instance of the detector at scene if it doesn't exists. Make sure to call NOT from Awake phase. + /// + /// New or existing instance of the detector. + public static WallHackDetector AddToSceneOrGetExisting() + { + return GetOrCreateInstance; + } + + /// + /// Starts detection for detector you have in scene. + /// + /// Make sure you have properly configured detector in scene with #autoStart disabled before using this method. + public static WallHackDetector StartDetection() + { + if (Instance != null) + { + return Instance.StartDetectionInternal(null, Instance.spawnPosition, Instance.maxFalsePositives); + } + + Debug.LogError(LogPrefix + "can't be started since it doesn't exists in scene or not yet initialized!"); + return null; + } + + /// + /// Starts detection with specified callback. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + public static WallHackDetector StartDetection(Action callback) + { + return StartDetection(callback, GetOrCreateInstance.spawnPosition); + } + + /// + /// Starts detection with specified callback using passed spawnPosition. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + /// World position of the service 3x3x3 container. Overrides #spawnPosition property. + public static WallHackDetector StartDetection(Action callback, Vector3 spawnPosition) + { + return StartDetection(callback, spawnPosition, GetOrCreateInstance.maxFalsePositives); + } + + /// + /// Starts detection with specified callback using passed spawnPosition and maxFalsePositives. + /// + /// If you have detector in scene make sure it has empty Detection Event.
+ /// Creates a new detector instance if it doesn't exists in scene. + /// Method to call after detection. + /// World position of the service 3x3x3 container. Overrides #spawnPosition property. + /// Amount of possible false positives in a row before registering detection. Overrides #maxFalsePositives property. + public static WallHackDetector StartDetection(Action callback, Vector3 spawnPosition, byte maxFalsePositives) + { + return GetOrCreateInstance.StartDetectionInternal(callback, spawnPosition, maxFalsePositives); + } + + /// + /// Stops detector. Detector's component remains in the scene. Use Dispose() to completely remove detector. + /// + public static void StopDetection() + { + if (Instance != null) Instance.StopDetectionInternal(); + } + + /// + /// Stops and completely disposes detector component and destroys Service Container as well. + /// + /// On dispose Detector follows 2 rules: + /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically + /// destroyed if no other Detectors left attached regardless of any other components or children;
+ /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only + /// if it has neither other components nor children attached; + public static void Dispose() + { + if (Instance != null) + { + Instance.DisposeInternal(); + } + } + #endregion + + /// + /// Manually triggers cheating detection and invokes assigned events. + /// + [ContextMenu("Trigger detection")] + public void TriggerDetection() + { + if (!IsRunning) + { + Debug.LogWarning(LogPrefix + "Detector is not running, can't trigger detection."); + return; + } + + OnCheatingDetected(); + } + + private WallHackDetector() { } // prevents direct instantiation + + #region unity messages + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + protected override void OnDestroy() + { + base.OnDestroy(); + + StopAllCoroutines(); + if (serviceContainer != null) Destroy(serviceContainer); + + if (wfMaterial != null) + { + wfMaterial.mainTexture = null; + wfMaterial.shader = null; + wfMaterial = null; + + wfShader = null; + + shaderTexture = null; + targetTexture = null; + + renderTexture.DiscardContents(); + renderTexture.Release(); + renderTexture = null; + } + + instancesInScene--; + } + +#if UNITY_EDITOR +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnDrawGizmosSelected() + { + Gizmos.color = Color.red; + Gizmos.DrawWireCube(spawnPosition, new Vector3(3, 3, 3)); + } +#endif + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void FixedUpdate() + { + if (!IsRunning || !checkRigidbody || rigidPlayer == null) + return; + + if (rigidPlayer.transform.localPosition.z > 1f) + { + rigidbodyDetections++; + if (!Detect()) + { + StopRigidModule(); + StartRigidModule(); + } + } + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void Update() + { + if (!IsRunning || !checkController || charControllerPlayer == null) + return; + + if (charControllerVelocity > 0) + { + charControllerPlayer.Move(new Vector3(UnityEngine.Random.Range(-0.002f, 0.002f), 0, charControllerVelocity)); + + if (charControllerPlayer.transform.localPosition.z > 1f) + { + controllerDetections++; + if (!Detect()) + { + StopControllerModule(); + StartControllerModule(); + } + } + } + } + +#if WALLHACK_DEBUG +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void OnGUI() + { + float x = 10; + float y = 10; + + if (targetTexture != null) + { + GUI.DrawTexture(new Rect(x, y, 50, 50), targetTexture, ScaleMode.StretchToFill, false); + } + + if (renderTexture != null) + { + GUI.DrawTexture(new Rect(x + 50, y, 50, 50), renderTexture, ScaleMode.StretchToFill, false); + } + + Color32 color1 = wfColor1; + Color32 color2 = wfColor2; + + GUILayout.BeginArea(new Rect(x, y + 50, 200, 70), GUI.skin.box); + GUI.color = wfColor1; + GUILayout.Label("Color1: " + color1.r + ", " + color1.g + ", " + color1.b + ", " + color1.a); + GUI.color = wfColor2; + GUILayout.Label("Color2: " + color2.r + ", " + color2.g + ", " + color2.b + ", " + color2.a); + GUILayout.EndArea(); + } +#endif + #endregion + + private WallHackDetector StartDetectionInternal(Action callback, Vector3 servicePosition, byte falsePositivesInRow) + { + if (IsRunning) + { + Debug.LogWarning(LogPrefix + "already running!", this); + return this; + } + + if (!enabled) + { + Debug.LogWarning($"{LogPrefix}disabled but {nameof(StartDetection)} still called from somewhere (see stack trace for this message)!", this); + return this; + } + + if (callback != null && DetectorHasListeners()) + { + Debug.LogWarning(LogPrefix + $"has properly configured Detection Event in the inspector or {nameof(CheatDetected)} event subscriber, but still get started with Action callback." + + $"Action will be called at the same time with Detection Event or {nameof(CheatDetected)} on detection." + + "Are you sure you wish to do this?", this); + } + + if (callback == null && !DetectorHasListeners()) + { + Debug.LogWarning($"{LogPrefix}was started without Detection Event, Callback or {nameof(CheatDetected)} event subscription." + + $"Cheat will not be detected until you subscribe to {nameof(CheatDetected)} event.", this); + } + +#if UNITY_EDITOR + if (checkRaycast || checkController || checkRigidbody) + { + var layerId = LayerMask.NameToLayer("Ignore Raycast"); + if (Physics.GetIgnoreLayerCollision(layerId, layerId)) + { + Debug.LogError(LogPrefix + "IgnoreRaycast physics layer should collide with itself to avoid false positives! See readme's troubleshooting section for details."); + } + } +#endif + + if (callback != null) + CheatDetected += callback; + + spawnPosition = servicePosition; + maxFalsePositives = falsePositivesInRow; + + rigidbodyDetections = 0; + controllerDetections = 0; + wireframeDetections = 0; + raycastDetections = 0; + + StartCoroutine(InitDetector()); + + IsStarted = true; + IsRunning = true; + + return this; + } + + protected override void StartDetectionAutomatically() + { + StartDetectionInternal(null, spawnPosition, maxFalsePositives); + } + + protected override void PauseDetector() + { + if (!IsRunning) return; + + base.PauseDetector(); + StopRigidModule(); + StopControllerModule(); + StopWireframeModule(); + StopRaycastModule(); + } + + protected override bool ResumeDetector() + { + if (!base.ResumeDetector()) return false; + + if (checkRigidbody) + { + StartRigidModule(); + } + + if (checkController) + { + StartControllerModule(); + } + + if (checkWireframe) + { + StartWireframeModule(); + } + + if (checkRaycast) + { + StartRaycastModule(); + } + + return true; + } + + protected override void StopDetectionInternal() + { + if (IsStarted) PauseDetector(); + base.StopDetectionInternal(); + } + + private void UpdateServiceContainer() + { + if (enabled && gameObject.activeSelf) + { + #region common + if (whLayer == -1) + whLayer = LayerMask.NameToLayer("Ignore Raycast"); + if (raycastMask == -1) + raycastMask = LayerMask.GetMask("Ignore Raycast"); + + if (serviceContainer == null) + { + serviceContainer = new GameObject(ServiceContainerName); + serviceContainer.layer = whLayer; + serviceContainer.transform.position = spawnPosition; + DontDestroyOnLoad(serviceContainer); + } + #endregion + + #region walk + if ((checkRigidbody || checkController) && solidWall == null) + { +#if WALLHACK_DEBUG + + solidWall = GameObject.CreatePrimitive(PrimitiveType.Cube); + solidWall.name = "SolidWall"; +#else + solidWall = new GameObject("SolidWall"); + solidWall.AddComponent(); +#endif + solidWall.layer = whLayer; + solidWall.transform.parent = serviceContainer.transform; + solidWall.transform.localScale = new Vector3(3, 3, 0.5f); + solidWall.transform.localPosition = Vector3.zero; + } + else if ((!checkRigidbody && !checkController) && solidWall != null) + { + Destroy(solidWall); + } + #endregion + + #region wireframe + if (checkWireframe && wfCamera == null) + { + if (wfShader == null) + wfShader = Shader.Find(WireframeShaderName); + + if (wfShader == null) + { + Debug.LogError(LogPrefix + "can't find '" + WireframeShaderName + "' shader!\nPlease make sure you have it included at the Anti-Cheat Toolkit Settings.", this); + checkWireframe = false; + } + else + { + if (!wfShader.isSupported) + { + Debug.LogWarning(LogPrefix + "can't detect wireframe cheats on this platform due to lack of needed shader support!", this); + checkWireframe = false; + } + else + { + if (wfColor1 == Color.black) + { + wfColor1 = GenerateColor(); + do + wfColor2 = GenerateColor(); + while (ColorsSimilar(wfColor1, wfColor2, 10)); + } + + if (shaderTexture == null) + { + shaderTexture = new Texture2D(ShaderTextureSize, ShaderTextureSize, TextureFormat.RGB24, false, false); + shaderTexture.filterMode = FilterMode.Point; + + const int pixelsCount = ShaderTextureSize * ShaderTextureSize; + const int halfPixelsCount = pixelsCount / 2; + var colors = new Color[pixelsCount]; + + for (var i = 0; i < pixelsCount; i++) + { + if (i < halfPixelsCount) + { + colors[i] = wfColor1; + } + else + { + colors[i] = wfColor2; + } + } + + shaderTexture.SetPixels(colors, 0); + shaderTexture.Apply(); + } + + if (renderTexture == null) + { + renderTexture = new RenderTexture(RenderTextureSize, RenderTextureSize, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + renderTexture.autoGenerateMips = false; + renderTexture.filterMode = FilterMode.Point; + renderTexture.Create(); + } + + if (targetTexture == null) + { + targetTexture = new Texture2D(RenderTextureSize, RenderTextureSize, TextureFormat.RGB24, false, false); + targetTexture.filterMode = FilterMode.Point; + } + + if (wfMaterial == null) + { + wfMaterial = new Material(wfShader); + wfMaterial.mainTexture = shaderTexture; + } + + if (foregroundRenderer == null) + { + var foregroundObject = GameObject.CreatePrimitive(PrimitiveType.Cube); + Destroy(foregroundObject.GetComponent()); + foregroundObject.name = "WireframeFore"; + foregroundObject.layer = whLayer; + foregroundObject.transform.parent = serviceContainer.transform; + foregroundObject.transform.localPosition = new Vector3(0, 0, 0f); + + foregroundRenderer = foregroundObject.GetComponent(); + foregroundRenderer.sharedMaterial = wfMaterial; + foregroundRenderer.shadowCastingMode = ShadowCastingMode.Off; + foregroundRenderer.receiveShadows = false; + foregroundRenderer.enabled = false; + } + + if (backgroundRenderer == null) + { + var backgroundObject = GameObject.CreatePrimitive(PrimitiveType.Quad); + Destroy(backgroundObject.GetComponent()); + backgroundObject.name = "WireframeBack"; + backgroundObject.layer = whLayer; + backgroundObject.transform.parent = serviceContainer.transform; + backgroundObject.transform.localPosition = new Vector3(0, 0, 1f); + backgroundObject.transform.localScale = new Vector3(0.7f, 0.7f, 0.7f); + + backgroundRenderer = backgroundObject.GetComponent(); + backgroundRenderer.sharedMaterial = wfMaterial; + backgroundRenderer.shadowCastingMode = ShadowCastingMode.Off; + backgroundRenderer.receiveShadows = false; + backgroundRenderer.enabled = false; + } + + wfCamera = new GameObject("WireframeCamera").AddComponent(); + wfCamera.cameraType = CameraType.Preview; + wfCamera.gameObject.layer = whLayer; + wfCamera.transform.parent = serviceContainer.transform; + wfCamera.transform.localPosition = new Vector3(0, 0, -1f); + wfCamera.clearFlags = CameraClearFlags.SolidColor; + wfCamera.backgroundColor = Color.black; + wfCamera.orthographic = true; + wfCamera.orthographicSize = 0.5f; + wfCamera.nearClipPlane = 0.01f; + wfCamera.farClipPlane = 2.1f; + wfCamera.depth = 0; + wfCamera.renderingPath = RenderingPath.Forward; + wfCamera.useOcclusionCulling = false; + wfCamera.allowHDR = false; + wfCamera.allowMSAA = false; + wfCamera.targetTexture = renderTexture; + wfCamera.enabled = false; + } + } + } + else if (!checkWireframe && wfCamera != null) + { + Destroy(foregroundRenderer.gameObject); + Destroy(backgroundRenderer.gameObject); + + wfCamera.targetTexture = null; + Destroy(wfCamera.gameObject); + } +#endregion + + #region raycast + if (checkRaycast && thinWall == null) + { + thinWall = GameObject.CreatePrimitive(PrimitiveType.Plane); + thinWall.name = "ThinWall"; + thinWall.layer = whLayer; + thinWall.transform.parent = serviceContainer.transform; + + // if we scale x down to 0.1, some raycast cheats wont work + thinWall.transform.localScale = new Vector3(0.2f, 1f, 0.2f); + thinWall.transform.localRotation = Quaternion.Euler(270, 0, 0); + thinWall.transform.localPosition = new Vector3(0, 0, 1.4f); + //thinWall.GetComponent().isTrigger = true; + + #if !(WALLHACK_DEBUG) + Destroy(thinWall.GetComponent()); + Destroy(thinWall.GetComponent()); + #endif + } + else if (!checkRaycast && thinWall != null) + { + Destroy(thinWall); + } + #endregion + } + else if (serviceContainer != null) + { + Destroy(serviceContainer); + } + } + + private IEnumerator InitDetector() + { + // allows to properly kill existing service objects before creating new ones + yield return waitForEndOfFrame; + + UpdateServiceContainer(); + + if (checkRigidbody) + { + StartRigidModule(); + } + + if (checkController) + { + StartControllerModule(); + } + + if (checkWireframe) + { + StartWireframeModule(); + } + + if (checkRaycast) + { + StartRaycastModule(); + } + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void StartRigidModule() + { + if (!checkRigidbody) + { + StopRigidModule(); + UninitRigidModule(); + UpdateServiceContainer(); + return; + } + + if (!rigidPlayer) InitRigidModule(); + if (rigidPlayer.transform.localPosition.z <= 1f && rigidbodyDetections > 0) + { +#if ACTK_DEBUG_ENABLED + Debug.Log(LogPrefix + "rigidbody success shot! False positives counter reset.", this); +#endif + rigidbodyDetections = 0; + } + + rigidPlayer.rotation = Quaternion.identity; + rigidPlayer.angularVelocity = Vector3.zero; + rigidPlayer.transform.localPosition = new Vector3(0.75f, 0, -1f); + rigidPlayer.velocity = rigidPlayerVelocity; + Invoke(nameof(StartRigidModule), 4); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void StartControllerModule() + { + if (!checkController) + { + StopControllerModule(); + UninitControllerModule(); + UpdateServiceContainer(); + return; + } + + if (!charControllerPlayer) InitControllerModule(); + if (charControllerPlayer.transform.localPosition.z <= 1f && controllerDetections > 0) + { +#if ACTK_DEBUG_ENABLED + Debug.Log(LogPrefix + "controller success shot! False positives counter reset.", this); +#endif + controllerDetections = 0; + } + + charControllerPlayer.transform.localPosition = new Vector3(-0.75f, 0, -1f); + charControllerVelocity = 0.01f; + Invoke(nameof(StartControllerModule), 4); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void StartWireframeModule() + { + if (!checkWireframe) + { + StopWireframeModule(); + UpdateServiceContainer(); + return; + } + + if (!wireframeDetected) + { + Invoke(nameof(ShootWireframeModule), wireframeDelay); + } + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void ShootWireframeModule() + { + StartCoroutine(CaptureFrame()); + Invoke(nameof(ShootWireframeModule), wireframeDelay); + } + + private IEnumerator CaptureFrame() + { +#if WALLHACK_DEBUG + if (thinWall != null) thinWall.GetComponent().enabled = false; + if (solidWall != null) solidWall.GetComponent().enabled = false; + if (charControllerPlayer != null) charControllerPlayer.GetComponent().enabled = false; + if (rigidPlayer != null) rigidPlayer.GetComponent().enabled = false; +#endif + wfCamera.enabled = true; + yield return waitForEndOfFrame; + + foregroundRenderer.enabled = true; + backgroundRenderer.enabled = true; + + var previousActive = RenderTexture.active; + RenderTexture.active = renderTexture; + + wfCamera.Render(); + + foregroundRenderer.enabled = false; + backgroundRenderer.enabled = false; + + while (!renderTexture.IsCreated()) + { + yield return waitForEndOfFrame; + } + targetTexture.ReadPixels(new Rect(0, 0, RenderTextureSize, RenderTextureSize), 0, 0, false); + targetTexture.Apply(); + + RenderTexture.active = previousActive; + +#if WALLHACK_DEBUG + if (thinWall != null) thinWall.GetComponent().enabled = true; + if (solidWall != null) solidWall.GetComponent().enabled = true; + if (charControllerPlayer != null) charControllerPlayer.GetComponent().enabled = true; + if (rigidPlayer != null) rigidPlayer.GetComponent().enabled = true; +#endif + + // in case we've deactivated detector while waiting for a frame + if (wfCamera == null) yield break; + + wfCamera.enabled = false; + + var pix1 = targetTexture.GetPixel(0, 3); + var pix2 = targetTexture.GetPixel(0, 1); + var pix3 = targetTexture.GetPixel(3, 3); + var pix4 = targetTexture.GetPixel(3, 1); + var pix5 = targetTexture.GetPixel(1, 3); + var pix6 = targetTexture.GetPixel(2, 3); + var pix7 = targetTexture.GetPixel(1, 1); + var pix8 = targetTexture.GetPixel(2, 1); + + var diff1 = ColorsDiffer(pix1, wfColor1); + var diff2 = ColorsDiffer(pix2, wfColor2); + var diff3 = ColorsDiffer(pix3, wfColor1); + var diff4 = ColorsDiffer(pix4, wfColor2); + var diff5 = ColorsDiffer(pix5, wfColor1); + var diff6 = ColorsDiffer(pix6, wfColor1); + var diff7 = ColorsDiffer(pix7, wfColor2); + var diff8 = ColorsDiffer(pix8, wfColor2); + + var detected = diff1 || + diff2 || + diff3 || + diff4 || + diff5 || + diff6 || + diff7 || + diff8; + + if (!detected) + { + if (wireframeDetections > 0) + { +#if ACTK_DEBUG_ENABLED + Debug.Log(LogPrefix + "wireframe success shot! False positives counter reset.", this); +#endif + wireframeDetections = 0; + } + } + else + { + wireframeDetections++; + wireframeDetected = Detect(); + +#if WALLHACK_DEBUG || ACTK_DETECTION_BACKLOGS + Debug.LogWarning(LogPrefix + "wireframe wallhack detected. Details below:\n" + + "wfColor1: " + (Color32)wfColor1 + ", wfColor2: " + (Color32)wfColor2 + "\n" + + (Color32)pix1 + " != wfColor1: " + diff1 + "\n" + + (Color32)pix2 + " != wfColor2: " + diff2 + "\n" + + (Color32)pix3 + " != wfColor1: " + diff3 + "\n" + + (Color32)pix4 + " != wfColor2: " + diff4 + "\n" + + (Color32)pix5 + " != wfColor1: " + diff5 + "\n" + + (Color32)pix6 + " != wfColor1: " + diff6 + "\n" + + (Color32)pix7 + " != wfColor2: " + diff7 + "\n" + + (Color32)pix8 + " != wfColor2: " + diff8, this); +#endif + } + yield return null; + } + + private bool ColorsDiffer(Color a, Color b) + { + return Math.Abs(a.r - b.r) > ColorsDifferenceThreshold || + Math.Abs(a.g - b.g) > ColorsDifferenceThreshold || + Math.Abs(a.b - b.b) > ColorsDifferenceThreshold; + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void StartRaycastModule() + { + if (!checkRaycast) + { + StopRaycastModule(); + UpdateServiceContainer(); + return; + } + + Invoke(nameof(ShootRaycastModule), raycastDelay); + } + +#if ACTK_EXCLUDE_OBFUSCATION + [System.Reflection.Obfuscation(Exclude = true)] +#endif + private void ShootRaycastModule() + { + if (Physics.RaycastNonAlloc(serviceContainer.transform.position, serviceContainer.transform.TransformDirection(Vector3.forward), rayHits, 1.5f, raycastMask) > 0) + { + if (raycastDetections > 0) + { +#if ACTK_DEBUG_ENABLED + Debug.Log(LogPrefix + "raycast success shot! False positives counter reset.", this); +#endif + raycastDetections = 0; + } + } + else + { + raycastDetections++; + if (Detect()) return; + } + + Invoke(nameof(ShootRaycastModule), raycastDelay); + } + + private void StopRigidModule() + { + if (rigidPlayer) rigidPlayer.velocity = Vector3.zero; + CancelInvoke(nameof(StartRigidModule)); + } + + private void StopControllerModule() + { + if (charControllerPlayer) charControllerVelocity = 0; + CancelInvoke(nameof(StartControllerModule)); + } + + private void StopWireframeModule() + { + CancelInvoke(nameof(ShootWireframeModule)); + } + + private void StopRaycastModule() + { + CancelInvoke(nameof(ShootRaycastModule)); + } + + private void InitRigidModule() + { +#if WALLHACK_DEBUG + var player = GameObject.CreatePrimitive(PrimitiveType.Capsule); + player.name = "RigidPlayer"; + player.GetComponent().height = 2; +#else + var player = new GameObject("RigidPlayer"); + player.AddComponent().height = 2; +#endif + player.layer = whLayer; + player.transform.parent = serviceContainer.transform; + player.transform.localPosition = new Vector3(0.75f, 0, -1f); + rigidPlayer = player.AddComponent(); + rigidPlayer.useGravity = false; + } + + private void InitControllerModule() + { +#if WALLHACK_DEBUG + var player = GameObject.CreatePrimitive(PrimitiveType.Capsule); + player.name = "ControlledPlayer"; + player.GetComponent().height = 2; +#else + var player = new GameObject("ControlledPlayer"); + player.AddComponent().height = 2; +#endif + player.layer = whLayer; + player.transform.parent = serviceContainer.transform; + player.transform.localPosition = new Vector3(-0.75f, 0, -1f); + charControllerPlayer = player.AddComponent(); + } + + private void UninitRigidModule() + { + if (!rigidPlayer) return; + + Destroy(rigidPlayer.gameObject); + rigidPlayer = null; + } + + private void UninitControllerModule() + { + if (!charControllerPlayer) return; + + Destroy(charControllerPlayer.gameObject); + charControllerPlayer = null; + } + + private bool Detect() + { + var result = false; + + if (controllerDetections > maxFalsePositives || + rigidbodyDetections > maxFalsePositives || + wireframeDetections > maxFalsePositives || + raycastDetections > maxFalsePositives) + { +#if ACTK_DEBUG_ENABLED + Debug.LogWarning(LogPrefix + "final detection!", this); +#endif + +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(LogPrefix + + "controllerDetections: " + controllerDetections + "\n" + + "rigidbodyDetections: " + rigidbodyDetections + "\n" + + "wireframeDetections: " + wireframeDetections + "\n" + + "raycastDetections: " + raycastDetections, this); +#endif + + OnCheatingDetected(); + result = true; + } +#if ACTK_DEBUG_ENABLED + else + { + Debug.LogWarning(LogPrefix + "detection!", this); + } +#endif + + return result; + } + + private static Color32 GenerateColor() + { + return new Color32((byte)UnityEngine.Random.Range(0, 256), (byte)UnityEngine.Random.Range(0, 256), (byte)UnityEngine.Random.Range(0, 256), 255); + } + + private static bool ColorsSimilar(Color32 c1, Color32 c2, int tolerance) + { + return Math.Abs(c1.r - c2.r) < tolerance && + Math.Abs(c1.g - c2.g) < tolerance && + Math.Abs(c1.b - c2.b) < tolerance; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs.meta new file mode 100644 index 0000000..02346d7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Detectors/WallHackDetector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d123a0bf35a94004aa342821cfcc3ea8 +MonoImporter: + serializedVersion: 2 + defaultReferences: + - thinWallPrefab: {fileID: 100000, guid: 3679c69bab7abbf408e8fcd6d63fd849, type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine.meta new file mode 100644 index 0000000..453a226 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8630c5d4888d6074296f1e9e7f3b4241 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android.meta new file mode 100644 index 0000000..a775524 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e1d5fe30dc27425fb0c97b2325d927af +timeCreated: 1681995444 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs new file mode 100644 index 0000000..2500d29 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs @@ -0,0 +1,31 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Genuine.Android +{ + /// + /// Guessed source of the app installation. + /// + public enum AndroidAppSource + { + /// + /// App was installed on-device from the apk with the package installer. + /// + PackageInstaller, + GooglePlayStore, + AmazonAppStore, + HuaweiAppGallery, + SamsungGalaxyStore, + /// + /// Source of the app installation is unknown. + /// + Other, + /// + /// There was a problem accessing the app installation source information. + /// + AccessError + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs.meta new file mode 100644 index 0000000..8532ccb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AndroidAppSource.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9f22da4768ea44e2b55af0ead88a0f36 +timeCreated: 1682126773 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs new file mode 100644 index 0000000..8fa0782 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs @@ -0,0 +1,53 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Genuine.Android +{ + /// + /// Holds information about the app installation source. + /// + public class AppInstallationSource + { + /// + /// Package name of the installation source, for example "com.android.vending" for Google Play Store. + /// + public string PackageName { get; } + + /// + /// Detected source of the app installation to simplify further processing. + /// + public AndroidAppSource DetectedSource { get; } + + internal AppInstallationSource(string packageName) + { + PackageName = packageName; + DetectedSource = GetStoreName(packageName); + } + + private AndroidAppSource GetStoreName(string packageName) + { + if (packageName == null) + return AndroidAppSource.AccessError; + + switch (packageName) + { + case "com.android.vending": + return AndroidAppSource.GooglePlayStore; + case "com.amazon.venezia": + return AndroidAppSource.AmazonAppStore; + case "com.huawei.appmarket": + return AndroidAppSource.HuaweiAppGallery; + case "com.sec.android.app.samsungapps": + return AndroidAppSource.SamsungGalaxyStore; + case "com.google.android.packageinstaller": + case "com.android.packageinstaller": + return AndroidAppSource.PackageInstaller; + default: + return AndroidAppSource.Other; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs.meta new file mode 100644 index 0000000..d328556 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSource.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 871f83f51e824dd79b63863a40954cc0 +timeCreated: 1682126786 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs new file mode 100644 index 0000000..bbb3a29 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs @@ -0,0 +1,53 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using CodeStage.AntiCheat.Common; +using UnityEngine; + +namespace CodeStage.AntiCheat.Genuine.Android +{ + /// + /// Simple tool to quickly figure out installation source of the app. + /// + public static class AppInstallationSourceValidator + { +#if UNITY_ANDROID + private static AndroidJavaClass routinesClass; +#endif + + /// + /// Allows getting detailed information about installation source of the app. + /// + /// AppInstallationSource instance or null if run not on Android device or exception occured. + public static AppInstallationSource GetAppInstallationSource() + { +#if UNITY_ANDROID + try + { + var installerPackageName = Utils.AndroidRoutines.GetPackageInstallerName(); + return new AppInstallationSource(installerPackageName); + } + catch (System.Exception e) + { + ACTk.PrintExceptionForSupport($"{ACTk.LogPrefix} Error while getting app installation source! See more info below.", e); + } +#else + Debug.LogWarning($"{ACTk.LogPrefix} {nameof(AppInstallationSourceValidator)} is only available on Android device."); +#endif + return null; + } + + /// + /// Checks if app was installed from the Google Play Store. + /// + /// True if app was installed from the Google Play, false otherwise. Can return false if installations source couldn't be identified. + public static bool IsInstalledFromGooglePlay() + { + var source = GetAppInstallationSource(); + return source?.DetectedSource == AndroidAppSource.GooglePlayStore; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs.meta new file mode 100644 index 0000000..1af866b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/Android/AppInstallationSourceValidator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d1b17f686bca423eaf2c29b3cf27f2e2 +timeCreated: 1681995474 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash.meta new file mode 100644 index 0000000..e769bbd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fbcc57ba3ea6b7458c36201af7e164d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs new file mode 100644 index 0000000..0940568 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs @@ -0,0 +1,151 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using CodeStage.AntiCheat.Common; +using Debug = UnityEngine.Debug; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + /// + /// Contains hashes for the application build. + /// + public class BuildHashes + { + /// + /// Path to the build file or folder. + /// + public string BuildPath { get; } + + /// + /// Contains all sensitive files hashes and relative paths. + /// + public IReadOnlyList FileHashes { get; } + + /// + /// Summary hash for all files in build. + /// + /// Use with caution: summary hash for runtime build may differ from the summary hash + /// you got in Editor, for example, for Android App Bundles. + /// Use #FileHashes for more accurate hashes comparison control. + public string SummaryHash { get; } + + /// + /// Hashing duration in seconds. Will be 0 if hashing was not succeed. + /// + public double DurationSeconds { get; set; } + + internal BuildHashes(string buildPath, FileHash[] fileHashes) + { + Array.Sort(fileHashes, (x, y) => string.Compare(x.Hash, y.Hash, StringComparison.Ordinal)); + + BuildPath = buildPath; + SummaryHash = CalculateSummaryCodeHash(fileHashes); + FileHashes = fileHashes; + } + + internal BuildHashes(string buildPath, FileHash[] fileHashes, string summaryHash) + { + BuildPath = buildPath; + SummaryHash = summaryHash; + FileHashes = fileHashes; + } + + /// + /// Checks is passes hash exists in file hashes of this instance. + /// + /// Target file hash. + /// True if such hash presents at #FileHashes and false otherwise. + public bool HasFileHash(string hash) + { + foreach (var fileHash in FileHashes) + { + if (fileHash.Hash == hash) + { + return true; + } + } + + return false; + } + + /// + /// Sends enclosing hashes to the console along with file names. + /// + public void PrintToConsole() + { + var log = ACTk.LogPrefix + $"Build hashed ({DurationSeconds:F2} sec, {FileHashes?.Count} files): " + BuildPath + "\n"; + + if (!Path.GetExtension(BuildPath).Equals(".aab", StringComparison.OrdinalIgnoreCase)) + { + log += "Summary Hash: " + SummaryHash + "\n"; + } + else + { +#if UNITY_EDITOR + var warningPrefix = "[Warning] "; +#else + var warningPrefix = "[Warning] "; +#endif + log += warningPrefix + "App Bundle Summary Hash will more likely " + + "differ from the Summary Hash you'll get at runtime on target devices.\n" + + "Please use individual File Hashes instead.\n"; + } + + if (FileHashes != null) + { + log += "Individual File Hashes:"; + + foreach (var fileHash in FileHashes) + { + log += "\n" + fileHash.Path + " : " + fileHash.Hash; + } + } + + Debug.Log(log); + } + + private string CalculateSummaryCodeHash(FileHash[] hashes) + { + var hashesString = string.Empty; + if (hashes == null) return hashesString; + var count = hashes.Length; + if (count == 0) return hashesString; + + var hashLength = hashes[0].Hash.Length; + + var hashBytes = new byte[count][]; + for (var i = 0; i < count; i++) + { + hashBytes[i] = Encoding.UTF8.GetBytes(hashes[i].Hash); + } + + var averageHashBytes = new byte[hashLength / 2]; + for (var i = 0; i < hashLength; i += 2) + { + byte result = 0; + for (var j = 0; j < count; j++) + { + var b1 = hashBytes[j][i]; + var b2 = hashBytes[j][i + 1]; + result ^= (byte)((b1 << 4) | b2); + } + averageHashBytes[i / 2] = result; + } + + var sb = new StringBuilder(); + foreach (var b in averageHashBytes) + { + sb.Append(b.ToString("x2")); + } + + return sb.ToString().ToUpperInvariant().Substring(0, hashLength); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs.meta new file mode 100644 index 0000000..754a8dd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/BuildHashes.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 738fc3d5fe874cc694342aa834cd729c +timeCreated: 1584031725 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs new file mode 100644 index 0000000..b9d3987 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs @@ -0,0 +1,172 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections; +using System.Threading; +using System.Threading.Tasks; +using CodeStage.AntiCheat.Common; +using UnityEngine; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + /// + /// Generates current application runtime code hash to let you validate it against previously generated runtime code hash to detect external code manipulations. + /// + /// Calculation is done on the separate threads where possible to prevent noticeable CPU spikes and performance impact.
+ /// Supported platforms: Windows PC, Android (more to come)
+ /// Resulting hash in most cases should match value you get from the \ref CodeStage.AntiCheat.EditorCode.PostProcessors.CodeHashGeneratorPostprocessor "CodeHashGeneratorPostprocessor". + [AddComponentMenu("")] + [DisallowMultipleComponent] + public class CodeHashGenerator : KeepAliveBehaviour, ICodeHashGenerator + { + private const int CompletionCheckIntervalMilliseconds = 500; + + /// + /// Subscribe to get resulting hash right after it gets calculated. + /// + public static event HashGeneratorResultHandler HashGenerated; + + /// + /// Stores previously calculated result. + /// Can be null if Generate() wasn't called yet or if it was called but calculation is still in process. + /// + /// \sa #IsBusy + public HashGeneratorResult LastResult { get; private set; } + + private readonly WaitForSeconds cachedWaitForSeconds = new WaitForSeconds(CompletionCheckIntervalMilliseconds / 1000f); + private BaseWorker currentWorker; + + private SemaphoreSlim completionSource; + + /// + /// Call to make sure current platform is compatible before calling Generate(). + /// + /// True if current platform is supported by the CodeHashGenerator, otherwise returns false. + /// Can return true in Editor but Hash Generation in Editor is not possible (nothing to hash). + public static bool IsTargetPlatformCompatible() + { +#if UNITY_ANDROID || UNITY_STANDALONE_WIN + return true; +#else + return false; +#endif + } + + /// + /// Creates new instance of the CodeHashGenerator at scene if it doesn't exists. Make sure to call NOT from Awake phase. + /// + /// New or existing instance of the detector. + public static ICodeHashGenerator AddToSceneOrGetExisting() + { + return GetOrCreateInstance; + } + + /// + /// Call to start current runtime code hash generation. Automatically adds instance to the scene if necessary. + /// + /// Threads to use while hashing the files. + public static ICodeHashGenerator Generate(int maxThreads = 1) + { + return GetOrCreateInstance.GenerateInternal(maxThreads); + } + + /// + /// Awaitable version of Generate(). Allows awaiting for the generation result. + /// + /// Threads to use while hashing the files. + public static Task GenerateAsync(int maxThreads = 1) + { + return GetOrCreateInstance.GenerateInternalAsync(maxThreads); + } + + /// + /// Indicates if hash generation is currently in process. + /// + public bool IsBusy => currentWorker != null && currentWorker.IsBusy; + + ICodeHashGenerator ICodeHashGenerator.Generate(int maxThreads) + { + return Generate(maxThreads); + } + + Task ICodeHashGenerator.GenerateAsync(int maxThreads) + { + return GenerateAsync(maxThreads); + } + + protected override void OnDestroy() + { + base.OnDestroy(); + HashGenerated = null; + } + + private async Task GenerateInternalAsync(int maxThreads) + { + completionSource = new SemaphoreSlim(0,1); + GenerateInternal(maxThreads); + await completionSource.WaitAsync(TimeSpan.FromHours(10)); + completionSource.Dispose(); + completionSource = null; + + return LastResult; + } + + private ICodeHashGenerator GenerateInternal(int maxThreads) + { + if (LastResult != null) + { + HashGenerated?.Invoke(LastResult); + completionSource?.Release(); + return this; + } + + if (IsBusy) + { + Debug.LogWarning($"{nameof(CodeHashGenerator)} generation was started while it's already busy."); + LastResult = HashGeneratorResult.FromError("Already running."); + completionSource?.Release(); + return this; + } + + currentWorker = null; +#if UNITY_EDITOR +#if UNITY_ANDROID || UNITY_STANDALONE_WIN + Debug.LogError(ACTk.LogPrefix + + "CodeHashGenerator does not work in Editor. Please use it in Unity Player only.\n" + + "This message is harmless."); +#else + Debug.LogError(ACTk.LogPrefix + "CodeHashGenerator works only in Android and Windows Standalone runtimes (both Mono and IL2CPP)."); +#endif + LastResult = HashGeneratorResult.FromError("Incorrect platform."); + completionSource?.Release(); + return this; +#else + maxThreads = 1 > maxThreads ? 1 : maxThreads; + #if UNITY_ANDROID + currentWorker = new AndroidWorker(maxThreads); + #elif UNITY_STANDALONE_WIN + currentWorker = new StandaloneWindowsWorker(maxThreads); + #endif + currentWorker.Execute(); + StartCoroutine(CalculationAwaiter()); + + return this; +#endif + } + + private IEnumerator CalculationAwaiter() + { + while (currentWorker.IsBusy) + yield return cachedWaitForSeconds; + + LastResult = currentWorker.Result; + HashGenerated?.Invoke(LastResult); + completionSource?.Release(); + currentWorker = null; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs.meta new file mode 100644 index 0000000..4f56346 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/CodeHashGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a671b141459bfc479bce8bb075fcc38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs new file mode 100644 index 0000000..4171740 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs @@ -0,0 +1,47 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System.IO; +using CodeStage.AntiCheat.Utils; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + /// + /// Holds hash for the specific file. + /// + public class FileHash + { + /// + /// Path to the file which was hashed. + /// + public string Path { get; } + + /// + /// Hash of the file. Calculated using semi-custom hashing algorithm based on SHA1. + /// + public string Hash { get; } + + internal FileHash(string path, Stream stream, ThreadSafeDisposablesPool sha1Pool) + { + Path = path; + var sha1 = sha1Pool.Get(); + var hash = sha1.ComputeHash(stream); + sha1Pool.Release(sha1); + Hash = StringUtils.HashBytesToHexString(hash); + } + + internal FileHash(string path, string hash) + { + Path = path; + Hash = hash; + } + + public override string ToString() + { + return Path + ": " + Hash; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs.meta new file mode 100644 index 0000000..320dffb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FileHash.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4457315821b04863812824a153b98988 +timeCreated: 1583769078 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs new file mode 100644 index 0000000..4a42c82 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs @@ -0,0 +1,43 @@ +using System; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal struct FilesProgress + { + private float progress; + private string fileName; + + public static FilesProgress Step(float progress, string fileName) + { + return new FilesProgress + { + progress = progress, + fileName = fileName + }; + } + + public static FilesProgress None() + { + return new FilesProgress + { + progress = -1, + fileName = null + }; + } + + public static IProgress CreateNew(string header) + { + return new Progress(value => + { +#if UNITY_EDITOR + if (value.progress >= 0) + UnityEditor.EditorUtility.DisplayProgressBar($"{header} {value.progress}%", $"{value.fileName} done", + value.progress); + else + UnityEditor.EditorUtility.ClearProgressBar(); +#endif + + }); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs.meta new file mode 100644 index 0000000..0ccd5cf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/FilesProgress.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fc63887d3556418e9374f436582b7263 +timeCreated: 1682440183 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering.meta new file mode 100644 index 0000000..1c67b35 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 079b58e876ec476aa197244abb78f03e +timeCreated: 1659040771 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs new file mode 100644 index 0000000..0827054 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs @@ -0,0 +1,114 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + using System; + using System.IO; + + internal class FileFilter + { +#pragma warning disable 0649 + public bool caseSensitive; + public bool pathRecursive; + public bool exactFileNameMatch; + public bool exactPathMatch; + + public string filterPath; + public string filterExtension; + public string filterFileName; +#pragma warning restore 0649 + + public bool MatchesPath(string filePath) + { + if (!caseSensitive) + filePath = filePath.ToLowerInvariant(); + + if (!string.IsNullOrWhiteSpace(filterExtension)) + { + var extension = Path.GetExtension(filePath); + if (string.IsNullOrEmpty(extension) || extension == ".") + return false; + + extension = extension.Remove(0, 1); + if (!filterExtension.Equals(extension, + caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) + return false; + } + + if (!string.IsNullOrWhiteSpace(filterFileName)) + { + var fileName = Path.GetFileNameWithoutExtension(filePath); + if (string.IsNullOrEmpty(fileName)) + return false; + + if (exactFileNameMatch) + { + if (!filterFileName.Equals(fileName, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) + return false; + } + else + { + if (fileName.IndexOf(filterFileName, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase) == -1) + return false; + } + } + + if (!string.IsNullOrWhiteSpace(filterPath)) + { + if (string.IsNullOrWhiteSpace(filePath)) + return false; + + if (Path.DirectorySeparatorChar != Path.AltDirectorySeparatorChar && + filePath.IndexOf(Path.DirectorySeparatorChar) != -1) + filePath = filePath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + + if (exactPathMatch) + { + if (!filePath.Equals(filterPath, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) + return false; + } + else + { + if (!PathMatch(filePath, filterPath, pathRecursive, !caseSensitive)) + return false; + } + } + + return true; + } + + private static bool PathMatch(string filePath, string filter, bool includeNested, bool ignoreCase) + { + var index = filePath.IndexOf(filter, + ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); + + if (index == -1) + return false; + + if (!includeNested) + { + var filterLength = filter.Length; + var pathDelimiterIndex = filePath.IndexOf(Path.AltDirectorySeparatorChar, index + filterLength); + if (pathDelimiterIndex != -1 && pathDelimiterIndex > index) + return false; + } + + return true; + } + + public override string ToString() + { + return caseSensitive + "|" + + pathRecursive + "|" + + exactFileNameMatch + "|" + + exactPathMatch + "|" + + filterPath + "|" + + filterExtension + "|" + + filterFileName; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs.meta new file mode 100644 index 0000000..791bba8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FileFilter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dd5b56a736e3406c803e3c0524f4b30f +timeCreated: 1557523858 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs new file mode 100644 index 0000000..2e6431c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs @@ -0,0 +1,15 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal enum FilterGroup + { + Code, + Content, + All + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs.meta new file mode 100644 index 0000000..50e3b0f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilterGroup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fe171be09c2a4f5f9789aba2a34f5bc9 +timeCreated: 1679604861 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs new file mode 100644 index 0000000..4062a33 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs @@ -0,0 +1,65 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal class FilteringData + { + public FileFilter[] Includes { get; } // used from Android-specific code + public FileFilter[] Ignores { get; } + + public FilteringData(FileFilter[] includes, FileFilter[] ignores = null) + { + Includes = includes; + Ignores = ignores; + } + + public bool IsIncluded(string path) + { + return IsPathMatchesFilters(path, Includes); + } + + public bool IsIgnored(string path) + { + if (Ignores == null || Ignores.Length == 0) + return false; + + return IsPathMatchesFilters(path, Ignores); + } + + public FilteringData Join(FilteringData contentFilters) + { + return new FilteringData( + JoinArrays(Includes, contentFilters.Includes), + JoinArrays(Ignores, contentFilters.Ignores)); + } + + private bool IsPathMatchesFilters(string path, FileFilter[] filters) + { + foreach (var filter in filters) + { + if (filter.MatchesPath(path)) + return true; + } + + return false; + } + + private T[] JoinArrays(T[] a1, T[] a2) + { + if (a1 == null && a2 == null) return Array.Empty(); + if (a1 == null) return a2; + if (a2 == null) return a1; + + var newArray = new T[a1.Length + a2.Length]; + Array.Copy(a1, 0, newArray, 0, a1.Length); + Array.Copy(a2, 0, newArray, a1.Length, a2.Length); + return newArray; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs.meta new file mode 100644 index 0000000..17251fc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8218d1a22b9148579530fe1594648790 +timeCreated: 1659040780 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs new file mode 100644 index 0000000..b69d703 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs @@ -0,0 +1,20 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using UnityEngine; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + // [CreateAssetMenu(menuName = "Code Stage/Anti-Cheat Toolkit/Code Hash/Filtering Settings")] + // Going to keep this in ProjectSettings and export to encrypted json on build + include it to the hashing checks + internal class FilteringSettings : ScriptableObject + { + [field:SerializeField] + public FilterGroup DefaultGroup { get; private set; } = FilterGroup.Code; + /*public FileFilter[] CustomIncludes { get; } + public FileFilter[] CustomIgnores { get; }*/ + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs.meta new file mode 100644 index 0000000..c281131 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FilteringSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fc88ed054d2646fd973cb589a44b32d8 +timeCreated: 1680189382 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs new file mode 100644 index 0000000..59c6613 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs @@ -0,0 +1,186 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal static class FiltersProducer + { + private static FilteringSettings LoadSettings() + { + return ScriptableObject.CreateInstance(); + /*return Resources.Load("net.codestage.actk/HashFilteringSettings");*/ + } + + public static FilteringData GetFileFiltersAndroid(bool il2Cpp) + { + var group = LoadSettings().DefaultGroup; + switch (group) + { + case FilterGroup.Code: + return GetCodeFiltersForAndroid(il2Cpp); + case FilterGroup.Content: + return GetContentFiltersForAndroid(il2Cpp); + case FilterGroup.All: + return GetAllFiltersForAndroid(il2Cpp); + default: + throw new ArgumentOutOfRangeException(nameof(group), group, null); + } + } + + public static FilteringData GetFileFiltersStandaloneWindows(bool il2Cpp) + { + var group = LoadSettings().DefaultGroup; + switch (group) + { + case FilterGroup.Code: + return GetCodeFiltersForWindows(il2Cpp); + case FilterGroup.Content: + return GetContentFiltersForWindows(il2Cpp); + case FilterGroup.All: + return GetAllFiltersForWindows(il2Cpp); + default: + throw new ArgumentOutOfRangeException(nameof(group), group, null); + } + } + + private static FilteringData GetCodeFiltersForAndroid(bool il2Cpp) + { + var includes = new List + { + new FileFilter + { + filterExtension = "dex" + }, + new FileFilter + { + filterExtension = "so" + } + }; + + if (!il2Cpp) + { + includes.Add(new FileFilter + { + filterExtension = "dll" + }); + } + else + { + includes.Add(new FileFilter + { + filterFileName = "global-metadata", + filterExtension = "dat" + }); + } + + return new FilteringData(includes.ToArray()); + } + + private static FilteringData GetContentFiltersForAndroid(bool il2Cpp) + { + var includes = new List + { + new FileFilter + { + filterPath = "Resources/unity_builtin_extra", + }, + new FileFilter + { + filterPath = "bin/Data/", + pathRecursive = false, + caseSensitive = true + } + }; + + return new FilteringData(includes.ToArray()); + } + + private static FilteringData GetAllFiltersForAndroid(bool il2Cpp) + { + var codeFilters = GetCodeFiltersForAndroid(il2Cpp); + var contentFilters = GetContentFiltersForAndroid(il2Cpp); + return codeFilters.Join(contentFilters); + } + + private static FilteringData GetCodeFiltersForWindows(bool il2Cpp) + { + var includes = new List + { + new FileFilter + { + filterExtension = "dll" + }, + new FileFilter + { + filterExtension = "exe" + } + }; + + FileFilter[] ignores; + + if (il2Cpp) + { + includes.Add(new FileFilter + { + filterFileName = "global-metadata", + filterExtension = "dat", + }); + + ignores = new[] + { + new FileFilter + { + filterPath = "_BackUpThisFolder_ButDontShipItWithYourGame", + caseSensitive = true, + exactPathMatch = false, + pathRecursive = true, + } + }; + } + else + { + ignores = null; + } + + return new FilteringData(includes.ToArray(), ignores); + } + + private static FilteringData GetContentFiltersForWindows(bool il2Cpp) + { + var includes = new List + { + new FileFilter + { + filterPath = "_Data/", + pathRecursive = false, + caseSensitive = true, + exactPathMatch = false, + }, + new FileFilter + { + filterPath = "Resources/unity default resources", + }, + new FileFilter + { + filterPath = "Resources/unity_builtin_extra", + }, + }; + + return new FilteringData(includes.ToArray()); + } + + private static FilteringData GetAllFiltersForWindows(bool il2Cpp) + { + var codeFilters = GetCodeFiltersForWindows(il2Cpp); + var contentFilters = GetContentFiltersForWindows(il2Cpp); + return codeFilters.Join(contentFilters); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs.meta new file mode 100644 index 0000000..8981e2b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Filtering/FiltersProducer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc6fa73d31024c40b3e61445c307ab3f +timeCreated: 1679605696 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs new file mode 100644 index 0000000..a5bb47b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs @@ -0,0 +1,95 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + /// + /// Result produced by CodeHashGenerator. Contains resulting code hash or errors information. + /// + public class HashGeneratorResult + { + [Obsolete("Please use SummaryHash property instead.", true)] + public string CodeHash => SummaryHash; + + /// + /// Summary hash for all files in currently running build. + /// May be null in case #Success is not true. + /// + /// Use with caution: summary hash for runtime build may differ from the summary hash + /// you got in Editor, for example, for Android App Bundles. + /// Use #FileHashes for more accurate hashes comparison control. + public string SummaryHash => buildHashes.SummaryHash; + + /// + /// Hashes for all files in currently running build. + /// Feel free to compare it against hashes array you got in Editor to find if + /// runtime version has new unknown hashes (this is an indication build was altered). + /// + public IReadOnlyList FileHashes => buildHashes.FileHashes; + + /// + /// Error message you could find useful in case #Success is not true. + /// + public string ErrorMessage { get; private set; } + + /// + /// True if generation was successful and resulting hashes are stored in #FileHashes, + /// otherwise check #ErrorMessage to find out error cause. + /// + public bool Success => ErrorMessage == null; + + /// + /// Hashing duration in seconds. Will be 0 if hashing was not succeed. + /// + public double DurationSeconds => buildHashes.DurationSeconds; + + private string summaryCodeHash; + private BuildHashes buildHashes; + + private HashGeneratorResult() { } + + internal static HashGeneratorResult FromError(string errorMessage) + { + return new HashGeneratorResult + { + ErrorMessage = errorMessage + }; + } + + internal static HashGeneratorResult FromBuildHashes(BuildHashes buildHashes) + { + return new HashGeneratorResult + { + buildHashes = buildHashes + }; + } + + /// + /// Checks is passes hash exists in file hashes of this instance. + /// + /// Target file hash. + /// True if such hash presents at #FileHashes and false otherwise. + public bool HasFileHash(string hash) + { + return buildHashes.HasFileHash(hash); + } + + /// + /// Prints found hashes to the console (if any). + /// + public void PrintToConsole() + { + if (Success) + buildHashes.PrintToConsole(); + else + Debug.LogError(ErrorMessage); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs.meta new file mode 100644 index 0000000..8cca091 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/HashGeneratorResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b641e2e931fb654794a4c8e18097e5e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs new file mode 100644 index 0000000..70870ad --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs @@ -0,0 +1,42 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System.Threading.Tasks; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + public delegate void HashGeneratorResultHandler(HashGeneratorResult result); + + /// + /// CodeHashGenerator interface to make it easier to use it through the Instance. + /// + public interface ICodeHashGenerator + { + /// + /// Stores previously calculated result. + /// Can be null if Generate() wasn't called yet or if it was called but calculation is still in process. + /// + /// \sa #IsBusy + HashGeneratorResult LastResult { get; } + + /// + /// Indicates if hash generation is currently in process. + /// + bool IsBusy { get; } + + /// + /// Call to start current runtime code hash generation. Automatically adds instance to the scene if necessary. + /// + /// Threads to use while hashing files. Use Environment.ProcessorCount to use all cores. + ICodeHashGenerator Generate(int maxThreads = 1); + + /// + /// Awaitable version of Generate(). Allows awaiting for the generation result. + /// + /// Threads to use while hashing files. Use Environment.ProcessorCount to use all cores. + Task GenerateAsync(int maxThreads = 1); + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs.meta new file mode 100644 index 0000000..468de05 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/ICodeHashGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f06aa8a64f773404da00090f642383dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs new file mode 100644 index 0000000..5a514ed --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs @@ -0,0 +1,42 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + using System; + using System.IO; + using System.Security.Cryptography; + + /// + /// Just an Utility class to make it easier to work with SHA1. + /// + /// Not intended for usage from user code, + /// touch at your peril since API can change and break backwards compatibility! + public class SHA1Wrapper : IDisposable + { + private readonly SHA1Managed sha1; + + public SHA1Wrapper() + { + sha1 = new SHA1Managed(); + } + + public byte[] ComputeHash(Stream stream) + { + return sha1.ComputeHash(stream); + } + + public byte[] ComputeHash(byte[] bytes) + { + return sha1.ComputeHash(bytes); + } + + public void Dispose() + { + sha1?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs.meta new file mode 100644 index 0000000..75f2b79 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/SHA1Wrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 64afe032c42b00a45aa5627298cf5630 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers.meta new file mode 100644 index 0000000..172041a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5d753138687289347859825ac64935e2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs new file mode 100644 index 0000000..7d89004 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs @@ -0,0 +1,121 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_ANDROID +#define ACTK_ANDROID_DEVICE +#endif + +#if ACTK_ANDROID_DEVICE + +using CodeStage.AntiCheat.Common; +using System; +using UnityEngine; +using System.Diagnostics; +using System.Collections.Generic; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal class AndroidWorker : BaseWorker + { + private Stopwatch sw; + + [System.Reflection.Obfuscation(Exclude = true, ApplyToMembers=false)] + private class CodeHashGeneratorCallback : AndroidJavaProxy + { + private readonly AndroidWorker parent; + + public CodeHashGeneratorCallback(AndroidWorker parent) : base("net.codestage.actk.androidnative.CodeHashCallback") + { + this.parent = parent; + } + + [System.Reflection.Obfuscation(Exclude = true)] + // called from native Android plugin, from separate thread + public void OnSuccess(string buildPath, string[] paths, string[] hashes, string summaryHash) + { + var fileHashes = new FileHash[hashes.Length]; + for (var i = 0; i < hashes.Length; i++) + { + var hash = hashes[i]; + var path = paths[i]; + + fileHashes[i] = new FileHash(path, hash); + } + + var buildHashes = new BuildHashes(buildPath, fileHashes, summaryHash); + parent.sw.Stop(); + buildHashes.DurationSeconds = parent.sw.Elapsed.TotalSeconds; + parent.Complete(HashGeneratorResult.FromBuildHashes(buildHashes)); + } + + [System.Reflection.Obfuscation(Exclude = true)] + // called from native Android plugin, from separate thread + public void OnError(string errorMessage) + { + parent.Complete(HashGeneratorResult.FromError(errorMessage)); + } + } + + public AndroidWorker(int threadsCount) : base(threadsCount) { } + + public override void Execute() + { + base.Execute(); + + const string classPath = "net.codestage.actk.androidnative.CodeHashGenerator"; + + try + { + sw = Stopwatch.StartNew(); + using (var nativeClass = new AndroidJavaClass(classPath)) + { +#if ENABLE_IL2CPP + var il2cpp = true; +#else + var il2cpp = false; +#endif + + var filters = FiltersProducer.GetFileFiltersAndroid(il2cpp); + nativeClass.CallStatic("GetCodeHash", GenerateStringArrayFromFilters(filters), new CodeHashGeneratorCallback(this), threadsCount); + } + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Can't initialize NativeRoutines!", e); + } + } + + private string[] GenerateStringArrayFromFilters(FilteringData allFilters) + { + var serializedFilters = new List(); + if (allFilters.Includes != null && allFilters.Includes.Length > 0) + serializedFilters.AddRange(SerializeArray(allFilters.Includes)); + if (allFilters.Ignores != null && allFilters.Ignores.Length > 0) + { + serializedFilters.Add("IGNORES"); + serializedFilters.AddRange(SerializeArray(allFilters.Ignores)); + } + return serializedFilters.ToArray(); + + IEnumerable SerializeArray(IList filters) + { + if (filters == null || filters.Count == 0) + return Array.Empty(); + + var itemsCount = filters.Count; + var result = new string[itemsCount]; + for (var i = 0; i < itemsCount; i++) + { + result[i] = filters[i].ToString(); + } + + return result; + } + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs.meta new file mode 100644 index 0000000..a478e18 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/AndroidWorker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e2effac38f14644699881c7c79150e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs new file mode 100644 index 0000000..1e48ab0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs @@ -0,0 +1,32 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal abstract class BaseWorker + { + public HashGeneratorResult Result { get; private set; } + public bool IsBusy { get; private set; } + + protected readonly int threadsCount; + + public BaseWorker(int threadsCount) + { + this.threadsCount = threadsCount; + } + + public virtual void Execute() + { + IsBusy = true; + } + + protected virtual void Complete(HashGeneratorResult result) + { + Result = result; + IsBusy = false; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs.meta new file mode 100644 index 0000000..848763f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/BaseWorker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0bee74c0f58db645aa3c72ec1eea123 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs new file mode 100644 index 0000000..36082ab --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs @@ -0,0 +1,135 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Diagnostics; +using UnityEngine; +using System.Threading.Tasks; +using CodeStage.AntiCheat.Common; +using CodeStage.AntiCheat.Utils; + +namespace CodeStage.AntiCheat.Genuine.CodeHash +{ + internal class StandaloneWindowsWorker : BaseWorker + { + private static readonly object ProgressLock = new object(); + + public static BuildHashes GetBuildHashes(string buildPath, FilteringData filters, int numCores, + IProgress progress = null) + { + var sw = Stopwatch.StartNew(); + + var files = Directory.GetFiles(buildPath, "*", SearchOption.AllDirectories); + var count = files.Length; + if (count == 0) + return null; + + var fileHashes = new ConcurrentBag(); + var options = new ParallelOptions + { + MaxDegreeOfParallelism = numCores, + }; + + var latestPercent = 0; + var filesChecked = 0; + + var sha1Pool = new ThreadSafeDisposablesPool(() => new SHA1Wrapper()); + + Parallel.ForEach(files, options, (filePath, state) => + { + var skipped = true; + try + { + // skip folders since we can't hash them + if (Directory.Exists(filePath)) + return; + + if (filters.IsIgnored(filePath)) + return; + + if (!filters.IsIncluded(filePath)) + return; + + using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) + using (var bs = new BufferedStream(fs)) + { + //Debug.Log("Path: " + filePath + "\nHash: " + hashString); + fileHashes.Add(new FileHash(filePath, bs, sha1Pool)); + } + + skipped = false; + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport($"Something went wrong while calculating {filePath} hash in {buildPath}!", e); + } + finally + { + lock (ProgressLock) + { + filesChecked++; + if (!skipped) + progress?.ReportPercent(ref latestPercent, filesChecked, count, Path.GetFileName(filePath)); + } + } + }); + + sha1Pool.Dispose(); + progress?.Report(FilesProgress.None()); + sw.Stop(); + + if (fileHashes.Count == 0) + return null; + + var result = new BuildHashes(buildPath, fileHashes.ToArray()) + { + DurationSeconds = sw.Elapsed.TotalSeconds + }; + + return result; + } + + public StandaloneWindowsWorker(int threadsCount) : base(threadsCount) { } + + public override void Execute() + { + base.Execute(); + + try + { + var buildFolder = Path.GetFullPath(Application.dataPath + @"\..\"); +#if ENABLE_IL2CPP + var il2cpp = true; +#else + var il2cpp = false; +#endif + var filters = FiltersProducer.GetFileFiltersStandaloneWindows(il2cpp); + Task.Run(()=>GenerateHashThread(buildFolder, filters)); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Something went wrong while calculating hash!", e); + Complete(HashGeneratorResult.FromError(e.ToString())); + } + } + + private void GenerateHashThread(string folder, FilteringData filteringData) + { + try + { + var buildHashes = GetBuildHashes(folder, filteringData, threadsCount); + Complete(HashGeneratorResult.FromBuildHashes(buildHashes)); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Something went wrong in hashing thread!", e); + Complete(HashGeneratorResult.FromError(e.ToString())); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs.meta new file mode 100644 index 0000000..6ead1f3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Genuine/CodeHash/Workers/StandaloneWindowsWorker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43857e841d4d9af48bd3c10efb7f9547 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes.meta new file mode 100644 index 0000000..88f57fc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 81cab858d70b02d4e8ee26e389360dd3 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters.meta new file mode 100644 index 0000000..93713bc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 866cfe8eb95465b4a9f8d67e0179b932 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft.meta new file mode 100644 index 0000000..4d4d9e9 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b473e53885ec81142b84b62aaedd530f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs new file mode 100644 index 0000000..c184f28 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs @@ -0,0 +1,293 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +// ACTK_NEWTONSOFT_JSON is True if project has the com.unity.nuget.newtonsoft-json package v2.0.0 or newer installed +// you can add this package to your project via the Package Manager by package name and use it instead of regular Json.NET library +// or you can enable ACTK_NEWTONSOFT_JSON manually at ACTk Settings instead. + +#if ACTK_NEWTONSOFT_JSON + +using System; +using System.Linq; +using System.Numerics; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using UnityEngine; +using Quaternion = UnityEngine.Quaternion; +using Vector2 = UnityEngine.Vector2; +using Vector3 = UnityEngine.Vector3; +using System.Globalization; + +namespace CodeStage.AntiCheat.ObscuredTypes.Converters +{ + /// + /// Regular JsonConverter for Jscon.NET that allows to serialize and deserialize ObscuredTypes decrypted values. + /// + /// See more and usage examples at the 'Obscured Types JSON Serialization' User Manual chapter. + public class ObscuredTypesNewtonsoftConverter : JsonConverter + { + private readonly Type[] types = { + typeof(ObscuredBigInteger), + typeof(ObscuredBool), + typeof(ObscuredByte), + typeof(ObscuredChar), + typeof(ObscuredDateTime), + typeof(ObscuredDecimal), + typeof(ObscuredDouble), + typeof(ObscuredFloat), + typeof(ObscuredInt), + typeof(ObscuredLong), + typeof(ObscuredQuaternion), + typeof(ObscuredSByte), + typeof(ObscuredShort), + typeof(ObscuredString), + typeof(ObscuredUInt), + typeof(ObscuredULong), + typeof(ObscuredUShort), + typeof(ObscuredVector2), + typeof(ObscuredVector2Int), + typeof(ObscuredVector3), + typeof(ObscuredVector3Int), + }; + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + switch (value) + { + case ObscuredBigInteger obscuredBigInteger: + writer.WriteValue(obscuredBigInteger.ToString(CultureInfo.InvariantCulture)); + break; + case ObscuredBool obscuredBool: + writer.WriteValue(obscuredBool); + break; + case ObscuredByte obscuredByte: + writer.WriteValue(obscuredByte); + break; + case ObscuredChar obscuredChar: + writer.WriteValue(obscuredChar); + break; + case ObscuredDateTime obscuredDateTime: + writer.WriteValue(obscuredDateTime); + break; + case ObscuredDecimal obscuredDecimal: + writer.WriteValue(obscuredDecimal); + break; + case ObscuredDouble obscuredDouble: + writer.WriteValue(obscuredDouble); + break; + case ObscuredFloat obscuredFloat: + writer.WriteValue(obscuredFloat); + break; + case ObscuredInt obscuredInt: + writer.WriteValue(obscuredInt); + break; + case ObscuredLong obscuredLong: + writer.WriteValue(obscuredLong); + break; + case ObscuredQuaternion obscuredQuaternion: + var quaternion = (Quaternion)obscuredQuaternion; + writer.WriteStartObject(); + writer.WritePropertyName("x"); + writer.WriteValue(quaternion.x); + writer.WritePropertyName("y"); + writer.WriteValue(quaternion.y); + writer.WritePropertyName("z"); + writer.WriteValue(quaternion.z); + writer.WritePropertyName("w"); + writer.WriteValue(quaternion.w); + writer.WriteEndObject(); + break; + case ObscuredSByte obscuredSByte: + writer.WriteValue(obscuredSByte); + break; + case ObscuredShort obscuredShort: + writer.WriteValue(obscuredShort); + break; + case ObscuredString obscuredString: + writer.WriteValue(obscuredString); + break; + case ObscuredUInt obscuredUInt: + writer.WriteValue(obscuredUInt); + break; + case ObscuredULong obscuredULong: + writer.WriteValue(obscuredULong); + break; + case ObscuredUShort obscuredUShort: + writer.WriteValue(obscuredUShort); + break; + case ObscuredVector2 obscuredVector2: + var vector2 = (Vector2)obscuredVector2; + writer.WriteStartObject(); + writer.WritePropertyName("x"); + writer.WriteValue(vector2.x); + writer.WritePropertyName("y"); + writer.WriteValue(vector2.y); + writer.WriteEndObject(); + break; + case ObscuredVector2Int obscuredVector2Int: + var vector2Int = (Vector2Int)obscuredVector2Int; + writer.WriteStartObject(); + writer.WritePropertyName("x"); + writer.WriteValue(vector2Int.x); + writer.WritePropertyName("y"); + writer.WriteValue(vector2Int.y); + writer.WriteEndObject(); + break; + case ObscuredVector3 obscuredVector3: + var vector3 = (Vector3)obscuredVector3; + writer.WriteStartObject(); + writer.WritePropertyName("x"); + writer.WriteValue(vector3.x); + writer.WritePropertyName("y"); + writer.WriteValue(vector3.y); + writer.WritePropertyName("z"); + writer.WriteValue(vector3.z); + writer.WriteEndObject(); + break; + case ObscuredVector3Int obscuredVector3Int: + var vector3Int = (Vector3Int)obscuredVector3Int; + writer.WriteStartObject(); + writer.WritePropertyName("x"); + writer.WriteValue(vector3Int.x); + writer.WritePropertyName("y"); + writer.WriteValue(vector3Int.y); + writer.WritePropertyName("z"); + writer.WriteValue(vector3Int.z); + writer.WriteEndObject(); + break; + default: + throw new Exception($"{nameof(ObscuredTypesNewtonsoftConverter)} type " + value.GetType() + + " is not implemented!"); + } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) + return null; + + if (objectType == typeof(ObscuredBigInteger)) + { + var input = reader.Value as string; + if (string.IsNullOrEmpty(input)) + return (ObscuredBigInteger)0; + + if (BigInteger.TryParse(input, NumberStyles.Any, CultureInfo.InvariantCulture, out var output)) + return (ObscuredBigInteger)output; + + // Obsolete fallback to read bytearray + var bytes = Convert.FromBase64String(input); + return (ObscuredBigInteger)new BigInteger(bytes); + } + if (objectType == typeof(ObscuredBool)) + return (ObscuredBool)Convert.ToBoolean(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredByte)) + return (ObscuredByte)Convert.ToByte(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredChar)) + return (ObscuredChar)Convert.ToChar(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredDateTime)) + return (ObscuredDateTime)Convert.ToDateTime(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredDecimal)) + return (ObscuredDecimal)Convert.ToDecimal(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredDouble)) + return (ObscuredDouble)Convert.ToDouble(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredFloat)) + return (ObscuredFloat)Convert.ToSingle(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredInt)) + return (ObscuredInt)Convert.ToInt32(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredLong)) + return (ObscuredLong)Convert.ToInt64(reader.Value, reader.Culture); + + if (objectType == typeof(ObscuredQuaternion)) + { + if (reader.TokenType != JsonToken.StartObject) + throw new Exception($"Unexpected token type '{reader.TokenType}' for {nameof(ObscuredQuaternion)}."); + + var jsonObject = JObject.Load(reader); + if (jsonObject == null) + throw new Exception($"Couldn't load {nameof(JObject)} for {nameof(ObscuredQuaternion)}."); + + var x = (jsonObject["x"] ?? 0).Value(); + var y = (jsonObject["y"] ?? 0).Value(); + var z = (jsonObject["z"] ?? 0).Value(); + var w = (jsonObject["w"] ?? 0).Value(); + var quaternion = new Quaternion(x, y, z, w); + return (ObscuredQuaternion)quaternion; + } + + if (objectType == typeof(ObscuredSByte)) + return (ObscuredSByte)Convert.ToSByte(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredShort)) + return (ObscuredShort)Convert.ToInt16(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredString)) + return (ObscuredString)Convert.ToString(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredUInt)) + return (ObscuredUInt)Convert.ToUInt32(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredULong)) + return (ObscuredULong)Convert.ToUInt64(reader.Value, reader.Culture); + if (objectType == typeof(ObscuredUShort)) + return (ObscuredUShort)Convert.ToUInt16(reader.Value, reader.Culture); + + if (objectType == typeof(ObscuredVector2)) + { + if (reader.TokenType != JsonToken.StartObject) + throw new Exception($"Unexpected token type '{reader.TokenType}' for {nameof(ObscuredVector2)}."); + + var jsonObject = JObject.Load(reader); + var x = (jsonObject["x"] ?? 0).Value(); + var y = (jsonObject["y"] ?? 0).Value(); + var vector2 = new Vector2(x, y); + return (ObscuredVector2)vector2; + } + + if (objectType == typeof(ObscuredVector2Int)) + { + if (reader.TokenType != JsonToken.StartObject) + throw new Exception($"Unexpected token type '{reader.TokenType}' for {nameof(ObscuredVector2Int)}."); + + var jsonObject = JObject.Load(reader); + var x = (jsonObject["x"] ?? 0).Value(); + var y = (jsonObject["y"] ?? 0).Value(); + var vector2Int = new Vector2Int(x, y); + return (ObscuredVector2Int)vector2Int; + } + + if (objectType == typeof(ObscuredVector3)) + { + if (reader.TokenType != JsonToken.StartObject) + throw new Exception($"Unexpected token type '{reader.TokenType}' for {nameof(ObscuredVector3)}."); + + var jsonObject = JObject.Load(reader); + var x = (jsonObject["x"] ?? 0).Value(); + var y = (jsonObject["y"] ?? 0).Value(); + var z = (jsonObject["z"] ?? 0).Value(); + var vector3 = new Vector3(x, y, z); + return (ObscuredVector3)vector3; + } + + if (objectType == typeof(ObscuredVector3Int)) + { + if (reader.TokenType != JsonToken.StartObject) + throw new Exception($"Unexpected token type '{reader.TokenType}' for {nameof(ObscuredVector3)}."); + + var jsonObject = JObject.Load(reader); + var x = (jsonObject["x"] ?? 0).Value(); + var y = (jsonObject["y"] ?? 0).Value(); + var z = (jsonObject["z"] ?? 0).Value(); + var vector3Int = new Vector3Int(x, y, z); + return (ObscuredVector3Int)vector3Int; + } + + throw new Exception($"{nameof(ObscuredTypesNewtonsoftConverter)} type {objectType} is not implemented!"); + } + + public override bool CanConvert(Type objectType) { + return types.Any(t => t == objectType); + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs.meta new file mode 100644 index 0000000..e29dcc7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Converters/Newtonsoft/ObscuredTypesNewtonsoftConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c71db1d59986c3b41af10f08c0c54787 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces.meta new file mode 100644 index 0000000..b139a22 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cda1d9a236014fff8ccab83d51cd6485 +timeCreated: 1556987015 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs new file mode 100644 index 0000000..a8fd0d0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs @@ -0,0 +1,21 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + /// + /// Base interface for all obscured types. + /// + public interface IObscuredType + { + /// + /// Allows to change current crypto key to the new random value and re-encrypt variable using it. + /// Use it for extra protection against 'unknown value' search. + /// Just call it sometimes when your variable doesn't change to fool the cheater. + /// + void RandomizeCryptoKey(); + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs.meta new file mode 100644 index 0000000..648d8be --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/Interfaces/IObscuredType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c633e678c4664854b052df4ae54d9cc8 +timeCreated: 1556987088 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs new file mode 100644 index 0000000..dcde969 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs @@ -0,0 +1,433 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using System.Numerics; + + public partial struct ObscuredBigInteger : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + //! @cond + public static implicit operator ObscuredBigInteger(BigInteger value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(byte value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(sbyte value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(short value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(ushort value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(int value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(uint value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(long value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(ulong value) + { + return new ObscuredBigInteger(value); + } + + public static implicit operator ObscuredBigInteger(float value) + { + return new ObscuredBigInteger((BigInteger)value); + } + + public static implicit operator ObscuredBigInteger(double value) + { + return new ObscuredBigInteger((BigInteger)value); + } + + public static implicit operator ObscuredBigInteger(decimal value) + { + return new ObscuredBigInteger((BigInteger)value); + } + + public static implicit operator BigInteger(ObscuredBigInteger value) + { + return value.InternalDecrypt(); + } + + public static explicit operator byte(ObscuredBigInteger value) + { + return (byte)value.InternalDecrypt(); + } + + public static explicit operator sbyte(ObscuredBigInteger value) + { + return (sbyte)value.InternalDecrypt(); + } + + public static explicit operator short(ObscuredBigInteger value) + { + return (short)value.InternalDecrypt(); + } + + public static explicit operator ushort(ObscuredBigInteger value) + { + return (ushort)value.InternalDecrypt(); + } + + public static explicit operator int(ObscuredBigInteger value) + { + return (int)value.InternalDecrypt(); + } + + public static explicit operator uint(ObscuredBigInteger value) + { + return (uint)value.InternalDecrypt(); + } + + public static explicit operator long(ObscuredBigInteger value) + { + return (long)value.InternalDecrypt(); + } + + public static explicit operator ulong(ObscuredBigInteger value) + { + return (ulong)value.InternalDecrypt(); + } + + public static explicit operator float(ObscuredBigInteger value) + { + return (float)value.InternalDecrypt(); + } + + public static explicit operator double(ObscuredBigInteger value) + { + return (double)value.InternalDecrypt(); + } + + public static explicit operator decimal(ObscuredBigInteger value) + { + return (decimal)value.InternalDecrypt(); + } + + public static ObscuredBigInteger operator <<(ObscuredBigInteger value, int shift) + { + return (BigInteger)value << shift; + } + + public static ObscuredBigInteger operator >>(ObscuredBigInteger value, int shift) + { + return (BigInteger)value >> shift; + } + + public static ObscuredBigInteger operator ~(ObscuredBigInteger value) + { + return ~(BigInteger)value; + } + + public static ObscuredBigInteger operator +(ObscuredBigInteger value) + { + return +(BigInteger)value; + } + + public static ObscuredBigInteger operator -(ObscuredBigInteger value) + { + return -(BigInteger)value; + } + + public static ObscuredBigInteger operator +(ObscuredBigInteger left, long right) + { + return (long)left + right; + } + + public static ObscuredBigInteger operator -(ObscuredBigInteger left, long right) + { + return (long)left - right; + } + + public static ObscuredBigInteger operator ++(ObscuredBigInteger input) + { + return Increment(input, 1); + } + + public static ObscuredBigInteger operator --(ObscuredBigInteger input) + { + return Increment(input, -1); + } + + public static bool operator <(ObscuredBigInteger left, long right) + { + return left < (BigInteger)right; + } + + public static bool operator <=(ObscuredBigInteger left, long right) + { + return left <= (BigInteger)right; + } + + public static bool operator >(ObscuredBigInteger left, long right) + { + return (BigInteger)left > right; + } + + public static bool operator >=(ObscuredBigInteger left, long right) + { + return (BigInteger)left >= right; + } + + public static bool operator ==(ObscuredBigInteger left, long right) + { + return (BigInteger)left == right; + } + + public static bool operator !=(ObscuredBigInteger left, long right) + { + return (BigInteger)left != right; + } + + public static bool operator <(ObscuredBigInteger left, ulong right) + { + return left < (BigInteger)right; + } + + public static bool operator <=(ObscuredBigInteger left, ulong right) + { + return left <= (BigInteger)right; + } + + public static bool operator >(ObscuredBigInteger left, ulong right) + { + return (BigInteger)left > right; + } + + public static bool operator >=(ObscuredBigInteger left, ulong right) + { + return (BigInteger)left >= right; + } + + public static bool operator ==(ObscuredBigInteger left, ulong right) + { + return (BigInteger)left == right; + } + + public static bool operator !=(ObscuredBigInteger left, ulong right) + { + return (BigInteger)left != right; + } + + public static bool operator <(long left, ObscuredBigInteger right) + { + return left < (BigInteger)right; + } + + public static bool operator <=(long left, ObscuredBigInteger right) + { + return left <= (BigInteger)right; + } + + public static bool operator >(long left, ObscuredBigInteger right) + { + return left > (BigInteger)right; + } + + public static bool operator >=(long left, ObscuredBigInteger right) + { + return left >= (BigInteger)right; + } + + public static bool operator ==(long left, ObscuredBigInteger right) + { + return left == (BigInteger)right; + } + + public static bool operator !=(long left, ObscuredBigInteger right) + { + return left != (BigInteger)right; + } + + public static bool operator <(ulong left, ObscuredBigInteger right) + { + return left < (BigInteger)right; + } + + public static bool operator <=(ulong left, ObscuredBigInteger right) + { + return left <= (BigInteger)right; + } + + public static bool operator >(ulong left, ObscuredBigInteger right) + { + return left > (BigInteger)right; + } + + public static bool operator >=(ulong left, ObscuredBigInteger right) + { + return left >= (BigInteger)right; + } + + public static bool operator ==(ulong left, ObscuredBigInteger right) + { + return left == (BigInteger)right; + } + + public static bool operator !=(ulong left, ObscuredBigInteger right) + { + return left != (BigInteger)right; + } + + public static ObscuredBigInteger operator &(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left & (BigInteger)right; + } + + public static ObscuredBigInteger operator |(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left | (BigInteger)right; + } + + public static ObscuredBigInteger operator ^(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left ^ (BigInteger)right; + } + + public static ObscuredBigInteger operator +(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left + (BigInteger)right; + } + + public static ObscuredBigInteger operator -(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left - (BigInteger)right; + } + + public static ObscuredBigInteger operator *(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left * (BigInteger)right; + } + + public static ObscuredBigInteger operator /(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left / (BigInteger)right; + } + + public static ObscuredBigInteger operator %(ObscuredBigInteger left, ObscuredBigInteger right) + { + return (BigInteger)left % (BigInteger)right; + } + + private static ObscuredBigInteger Increment(ObscuredBigInteger input, int increment) + { + var decrypted = input.InternalDecrypt() + increment; + input.hiddenValue.value = new BigInteger(decrypted.ToByteArray()); + input.hiddenValue = input.hiddenValue.Encrypt(input.currentCryptoKey); + + if (Detectors.ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue.value = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider) ?? string.Empty; + } + + public override bool Equals(object other) + { + return other is ObscuredBigInteger o && Equals(o) || + other is BigInteger r && Equals(r); + } + + public bool Equals(BigInteger other) + { + return InternalDecrypt().Equals(other); + } + + public bool Equals(ObscuredBigInteger obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public int CompareTo(ObscuredBigInteger other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(BigInteger other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + + public int CompareTo(long other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(ulong other) + { + return InternalDecrypt().CompareTo(other); + } + + public byte[] ToByteArray() + { + return InternalDecrypt().ToByteArray(); + } + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs.meta new file mode 100644 index 0000000..70c271e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d87e49d485644e9b0824650bd0bc85f +timeCreated: 1656253743 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs new file mode 100644 index 0000000..f4aeade --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredBigInteger + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs.meta new file mode 100644 index 0000000..b52c377 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4b71b315cb2a41f183596505f2a19126 +timeCreated: 1667508786 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs new file mode 100644 index 0000000..54e56bb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs @@ -0,0 +1,87 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Numerics; +using System.Runtime.InteropServices; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + [Serializable] + [StructLayout(LayoutKind.Explicit)] + internal struct SerializableBigInteger : IEquatable + { + [FieldOffset(0)] + public BigInteger value; + + [FieldOffset(0), SerializeField] + public BigIntegerContents raw; + + [Serializable] + public struct BigIntegerContents + { + public int sign; + public uint[] bits; + } + + public SerializableBigInteger Encrypt(uint key) + { + return SymmetricShuffle(key); + } + + public BigInteger Decrypt(uint key) + { + BigInteger result; + SymmetricShuffle(key); + result = new BigInteger(value.ToByteArray()); + SymmetricShuffle(key); + return result; + } + + private SerializableBigInteger SymmetricShuffle(uint key) + { + raw.sign ^= (int)key; + if (raw.bits == null) return this; + var count = raw.bits.Length; + if (count == 0) + { + raw.bits = null; + return this; + } + + if (count == 1) + raw.bits[0] ^= key; + else + (raw.bits[0], raw.bits[count - 1]) = (raw.bits[count - 1] ^ key, raw.bits[0] ^ key); + + return this; + } + + public static implicit operator BigInteger(SerializableBigInteger value) + { + if (value.raw.bits != null && value.raw.bits.Length == 0) + value.raw.bits = null; + + return value.value; + } + + public bool Equals(SerializableBigInteger other) + { + return value.Equals(other.value); + } + + public override bool Equals(object obj) + { + return obj is SerializableBigInteger other && Equals(other); + } + + public override int GetHashCode() + { + return value.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs.meta new file mode 100644 index 0000000..9344079 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.Raw.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 76d1d9576d934344b0dbaa48fd7f314e +timeCreated: 1679417356 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs new file mode 100644 index 0000000..f057d19 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs @@ -0,0 +1,192 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using System.Numerics; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular BigInteger for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredBigInteger : IObscuredType + { + [SerializeField] internal SerializableBigInteger hiddenValue; + [SerializeField] internal SerializableBigInteger fakeValue; + [SerializeField] internal uint currentCryptoKey; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredBigInteger(BigInteger value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = new SerializableBigInteger + { + value = new BigInteger(value.ToByteArray()) + }; + hiddenValue = hiddenValue.Encrypt(currentCryptoKey); + + fakeValue = new SerializableBigInteger(); + +#if UNITY_EDITOR + fakeValue.value = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue.value = detectorRunning ? value : 0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static BigInteger Encrypt(BigInteger value, uint key) + { + var input = new SerializableBigInteger { value = new BigInteger(value.ToByteArray()) }; + input = input.Encrypt(key); + return input; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static BigInteger Decrypt(BigInteger value, uint key) + { + var input = new SerializableBigInteger { value = new BigInteger(value.ToByteArray()) }; + return input.Decrypt(key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredBigInteger FromEncrypted(BigInteger encrypted, uint key) + { + var instance = new ObscuredBigInteger(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static uint GenerateKey() + { + return RandomUtils.GenerateUIntKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public BigInteger GetEncrypted(out uint key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(BigInteger encrypted, uint key) + { + inited = true; + hiddenValue.value = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue.value = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public BigInteger GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue.value = decrypted; + hiddenValue = hiddenValue.Encrypt(currentCryptoKey); + } + + private BigInteger InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = hiddenValue.Decrypt(currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredBigInteger)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue.value = 0; + hiddenValue = hiddenValue.Encrypt(currentCryptoKey); + fakeValue.value = 0; + fakeValueActive = false; + inited = true; + } + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs.meta new file mode 100644 index 0000000..b836e9a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBigInteger.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 26872f7c804f43978d827a298593df34 +timeCreated: 1653666933 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs new file mode 100644 index 0000000..f37ec42 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs @@ -0,0 +1,65 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredBool : IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredBool(bool value) + { + return new ObscuredBool(value); + } + + public static implicit operator bool(ObscuredBool value) + { + return value.InternalDecrypt(); + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public override bool Equals(object other) + { + return other is ObscuredBool o && Equals(o) || + other is bool r && Equals(r); + } + + public bool Equals(ObscuredBool obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(bool other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredBool other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(bool other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs.meta new file mode 100644 index 0000000..d6a1ba5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ddd4abd9e1e4456d8f6ba9a829d4939a +timeCreated: 1679402125 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs new file mode 100644 index 0000000..c918dbe --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredBool + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs.meta new file mode 100644 index 0000000..06b4d9b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a509ae45ba98416f8b165dc136753468 +timeCreated: 1667671371 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs new file mode 100644 index 0000000..7498c3d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs @@ -0,0 +1,212 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using UnityEngine.Serialization; + using Utils; + using Detectors; + + /// + /// Use it instead of regular bool for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredBool : IObscuredType + { + [SerializeField] internal byte currentCryptoKey; + [SerializeField] internal int hiddenValue; + [SerializeField] internal bool fakeValue; + [SerializeField] internal bool inited; + + [SerializeField] [FormerlySerializedAs("fakeValueChanged")] + internal bool fakeValueActive; + + private ObscuredBool(bool value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : false; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static int Encrypt(bool value, byte key) + { + return (value ? 213 : 181) ^ key; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static bool Decrypt(int value, byte key) + { + return (value ^ key) != 181; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredBool FromEncrypted(int encrypted, byte key) + { + var instance = new ObscuredBool(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static byte GenerateKey() + { + return RandomUtils.GenerateByteKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public int GetEncrypted(out byte key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted(), GetEncrypted() + public void SetEncrypted(int encrypted, byte key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public bool GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private bool InternalDecrypt() + { + if (!inited) + { + Init(); + return false; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredBool)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(false, currentCryptoKey); + fakeValue = false; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(byte newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static int Encrypt(bool value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static bool Decrypt(int value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredBool FromEncrypted(int encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public int GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(int encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs.meta new file mode 100644 index 0000000..be0defb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredBool.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 087379b55c673b6479929f47298ebe2f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs new file mode 100644 index 0000000..0a3f872 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredByte : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredByte(byte value) + { + return new ObscuredByte(value); + } + + public static implicit operator byte(ObscuredByte value) + { + return value.InternalDecrypt(); + } + + public static ObscuredByte operator ++(ObscuredByte input) + { + return Increment(input, 1); + } + + public static ObscuredByte operator --(ObscuredByte input) + { + return Increment(input, -1); + } + + private static ObscuredByte Increment(ObscuredByte input, int increment) + { + var decrypted = (byte)(input.InternalDecrypt() + increment); + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredByte o && Equals(o) || + other is byte r && Equals(r); + } + + public bool Equals(ObscuredByte obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(byte other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredByte other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(byte other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs.meta new file mode 100644 index 0000000..cf97613 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 01c4ec37f17242e987034c7cfba14fce +timeCreated: 1679403097 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs new file mode 100644 index 0000000..c5da4c5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs @@ -0,0 +1,253 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using Utils; + using Detectors; + + /// + /// Use it instead of regular byte for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredByte : IObscuredType + { + private byte currentCryptoKey; + private byte hiddenValue; + private byte fakeValue; + private bool fakeValueActive; + private bool inited; + + private ObscuredByte(byte value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : (byte)0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static byte Encrypt(byte value, byte key) + { + return (byte)(value ^ key); + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static void Encrypt(byte[] value, byte key) + { + var len = value.Length; + for (var i = 0; i < len; i++) + { + value[i] = Encrypt(value[i], key); + } + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static byte Decrypt(byte value, byte key) + { + return (byte)(value ^ key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static void Decrypt(byte[] value, byte key) + { + var len = value.Length; + for (var i = 0; i < len; i++) + { + value[i] = Decrypt(value[i], key); + } + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredByte FromEncrypted(byte encrypted, byte key) + { + var instance = new ObscuredByte(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static byte GenerateKey() + { + return RandomUtils.GenerateByteKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public byte GetEncrypted(out byte key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(byte encrypted, byte key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public byte GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private byte InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + UnityEngine.Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredByte)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(byte newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static byte EncryptDecrypt(byte value) { throw new Exception(); } + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static byte EncryptDecrypt(byte[] value) { throw new Exception(); } + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static byte EncryptDecrypt(byte value, byte key) + { + return (byte)(value ^ key); + } + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static void EncryptDecrypt(byte[] value, byte key) + { + var len = value.Length; + for (var i = 0; i < len; i++) + { + value[i] = EncryptDecrypt(value[i], key); + } + } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredByte FromEncrypted(byte encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public byte GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(byte encrypted) {} + + #endregion + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs.meta new file mode 100644 index 0000000..8c6e2e6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredByte.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ffd0f98b7bfcb1f418e2aa6c6d8438be +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs new file mode 100644 index 0000000..0253e20 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs @@ -0,0 +1,99 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredChar : IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredChar(char value) + { + return new ObscuredChar(value); + } + + public static implicit operator char(ObscuredChar value) + { + return value.InternalDecrypt(); + } + + public static ObscuredChar operator ++(ObscuredChar input) + { + return Increment(input, 1); + } + + public static ObscuredChar operator --(ObscuredChar input) + { + return Increment(input, -1); + } + + private static ObscuredChar Increment(ObscuredChar input, int increment) + { + var decrypted = (char)(input.InternalDecrypt() + increment); + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public override bool Equals(object other) + { + return other is ObscuredChar o && Equals(o) || + other is char r && Equals(r); + } + + public bool Equals(ObscuredChar other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(char other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredChar other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(char other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs.meta new file mode 100644 index 0000000..19f0bb5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5c0e0cd11aa84b7aa2f060f77c19a6fe +timeCreated: 1679403330 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs new file mode 100644 index 0000000..91a92bb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs @@ -0,0 +1,212 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using Utils; + using Detectors; + + /// + /// Use it instead of regular char for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredChar : IObscuredType + { + private char currentCryptoKey; + private char hiddenValue; + private char fakeValue; + private bool inited; + private bool fakeValueActive; + + private ObscuredChar(char value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : '\0'; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static char Encrypt(char value, char key) + { + return (char)(value ^ key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static char Decrypt(char value, char key) + { + return (char)(value ^ key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredChar FromEncrypted(char encrypted, char key) + { + var instance = new ObscuredChar(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static char GenerateKey() + { + return RandomUtils.GenerateCharKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public char GetEncrypted(out char key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(char encrypted, char key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public char GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private char InternalDecrypt() + { + if (!inited) + { + Init(); + return '\0'; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + UnityEngine.Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredChar)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt('\0', currentCryptoKey); + fakeValue = '\0'; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(char newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static char EncryptDecrypt(char value) { throw new Exception(); } + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static char EncryptDecrypt(char value, char key) + { + return (char)(value ^ key); + } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredChar FromEncrypted(char encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public char GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(char encrypted) {} + + #endregion + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs.meta new file mode 100644 index 0000000..e99eaba --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredChar.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: df2e4baa10859d4419dd288c8844c098 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs new file mode 100644 index 0000000..87c9698 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs @@ -0,0 +1,194 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredDateTime : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable, IConvertible + { + /// Gets the number of ticks that represent the date and time of this instance. + /// The number of ticks that represent the date and time of this instance. The value is between and . + public long Ticks => GetDecrypted().Ticks; + + public static implicit operator ObscuredDateTime(DateTime value) + { + return new ObscuredDateTime(value); + } + + public static implicit operator DateTime(ObscuredDateTime value) + { + return value.InternalDecryptAsDateTime(); + } + + public override int GetHashCode() + { + return InternalDecryptAsDateTime().GetHashCode(); + } + + public override string ToString() + { + return InternalDecryptAsDateTime().ToString(); + } + + public string ToString(string format) + { + return InternalDecryptAsDateTime().ToString(format); + } + + public TypeCode GetTypeCode() { + return TypeCode.DateTime; + } + + + bool IConvertible.ToBoolean(IFormatProvider provider) => throw new InvalidCastException(); + char IConvertible.ToChar(IFormatProvider provider) => throw new InvalidCastException(); + sbyte IConvertible.ToSByte(IFormatProvider provider) => throw new InvalidCastException(); + byte IConvertible.ToByte(IFormatProvider provider) => throw new InvalidCastException(); + short IConvertible.ToInt16(IFormatProvider provider) => throw new InvalidCastException(); + ushort IConvertible.ToUInt16(IFormatProvider provider) => throw new InvalidCastException(); + int IConvertible.ToInt32(IFormatProvider provider) => throw new InvalidCastException(); + uint IConvertible.ToUInt32(IFormatProvider provider) => throw new InvalidCastException(); + long IConvertible.ToInt64(IFormatProvider provider) => throw new InvalidCastException(); + ulong IConvertible.ToUInt64(IFormatProvider provider) => throw new InvalidCastException(); + float IConvertible.ToSingle(IFormatProvider provider) => throw new InvalidCastException(); + double IConvertible.ToDouble(IFormatProvider provider) => throw new InvalidCastException(); + decimal IConvertible.ToDecimal(IFormatProvider provider) => throw new InvalidCastException(); + DateTime IConvertible.ToDateTime(IFormatProvider provider) => this; + object IConvertible.ToType(Type type, IFormatProvider provider) + { + if (type == typeof(DateTime)) + return InternalDecryptAsDateTime(); + + if (type == typeof(ObscuredDateTime)) + return this; + + return Convert.ChangeType(InternalDecryptAsDateTime(), type, provider); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecryptAsDateTime().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecryptAsDateTime().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredDateTime o && Equals(o) || + other is DateTime r && Equals(r); + } + + public bool Equals(ObscuredDateTime other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(DateTime other) + { + return InternalDecryptAsDateTime().Equals(other); + } + + public int CompareTo(ObscuredDateTime other) + { + return InternalDecryptAsDateTime().CompareTo(other.InternalDecryptAsDateTime()); + } + + public int CompareTo(DateTime other) + { + return InternalDecryptAsDateTime().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecryptAsDateTime().CompareTo(obj); + } + + public static DateTime operator +(ObscuredDateTime d, TimeSpan t) + { + return (DateTime)d + t; + } + + public static DateTime operator -(ObscuredDateTime d, TimeSpan t) + { + return (DateTime)d - t; + } + + public static TimeSpan operator -(ObscuredDateTime d1, DateTime d2) + { + return (DateTime)d1 - d2; + } + + public static TimeSpan operator -(DateTime d1, ObscuredDateTime d2) + { + return d1 - (DateTime)d2; + } + + public static bool operator ==(ObscuredDateTime d1, DateTime d2) + { + return (DateTime)d1 == d2; + } + + public static bool operator ==(DateTime d1, ObscuredDateTime d2) + { + return d1 == (DateTime)d2; + } + + public static bool operator !=(ObscuredDateTime d1, DateTime d2) + { + return (DateTime)d1 != d2; + } + + public static bool operator !=(DateTime d1, ObscuredDateTime d2) + { + return d1 != (DateTime)d2; + } + + public static bool operator <(ObscuredDateTime t1, DateTime t2) + { + return (DateTime)t1 < t2; + } + + public static bool operator <(DateTime t1, ObscuredDateTime t2) + { + return t1 < (DateTime)t2; + } + + public static bool operator <=(ObscuredDateTime t1, DateTime t2) + { + return (DateTime)t1 <= t2; + } + + public static bool operator <=(DateTime t1, ObscuredDateTime t2) + { + return t1 <= (DateTime)t2; + } + + public static bool operator >(ObscuredDateTime t1, DateTime t2) + { + return (DateTime)t1 > t2; + } + + public static bool operator >(DateTime t1, ObscuredDateTime t2) + { + return t1 > (DateTime)t2; + } + + public static bool operator >=(ObscuredDateTime t1, DateTime t2) + { + return (DateTime)t1 >= t2; + } + + public static bool operator >=(DateTime t1, ObscuredDateTime t2) + { + return t1 >= (DateTime)t2; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs.meta new file mode 100644 index 0000000..a865dc6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d89b0423d1ce47bba805cbb94fcfe315 +timeCreated: 1684488629 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs new file mode 100644 index 0000000..fee06b4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs @@ -0,0 +1,190 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; +using CodeStage.AntiCheat.Utils; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + /// + /// Use it instead of regular DateTime for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredDateTime : IObscuredType + { + [SerializeField] internal long currentCryptoKey; + [SerializeField] internal long hiddenValue; + [SerializeField] internal long fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredDateTime(DateTime value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value.ToBinary(); + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value.ToBinary() : new DateTime(0).ToBinary(); + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static long Encrypt(DateTime value, long key) + { + return value.ToBinary() ^ key; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static DateTime Decrypt(long value, long key) + { + return DateTime.FromBinary(value ^ key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredDateTime FromEncrypted(long encrypted, long key) + { + var instance = new ObscuredDateTime(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static long GenerateKey() + { + return RandomUtils.GenerateLongKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public long GetEncrypted(out long key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(long encrypted, long key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public DateTime GetDecrypted() + { + return DateTime.FromBinary(InternalDecrypt()); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = InternalEncrypt(decrypted, currentCryptoKey); + } + + private static long InternalEncrypt(long value, long key) + { + return value ^ key; + } + + private DateTime InternalDecryptAsDateTime() + { + return DateTime.FromBinary(InternalDecrypt()); + } + + private long InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = hiddenValue ^ currentCryptoKey; + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredDateTime)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(new DateTime(0), currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs.meta new file mode 100644 index 0000000..6f2aa35 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDateTime.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ff6e0af66f3240eb97476c4a4cbebec0 +timeCreated: 1684488530 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs new file mode 100644 index 0000000..971a323 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs @@ -0,0 +1,114 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredDecimal : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredDecimal(decimal value) + { + return new ObscuredDecimal(value); + } + + public static implicit operator decimal(ObscuredDecimal value) + { + return value.InternalDecrypt(); + } + + public static explicit operator ObscuredDecimal(ObscuredFloat f) + { + return (decimal)(float)f; + } + + public static ObscuredDecimal operator ++(ObscuredDecimal input) + { + return Increment(input, 1); + } + + public static ObscuredDecimal operator --(ObscuredDecimal input) + { + return Increment(input, -1); + } + + private static ObscuredDecimal Increment(ObscuredDecimal input, decimal increment) + { + var decrypted = input.InternalDecrypt() + increment; + input.hiddenValue = InternalEncrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredDecimal o && Equals(o) || + other is decimal r && Equals(r); + } + + public bool Equals(ObscuredDecimal other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(decimal other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredDecimal other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(decimal other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs.meta new file mode 100644 index 0000000..01f27cc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b19e591daa4149e5a58d44647b9c0c10 +timeCreated: 1679403605 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs new file mode 100644 index 0000000..535ea94 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs @@ -0,0 +1,23 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredDecimal + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs.meta new file mode 100644 index 0000000..7d476c7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 825ba42c6957452aa173153134e38e08 +timeCreated: 1684488866 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs new file mode 100644 index 0000000..39538d8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs @@ -0,0 +1,274 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using Common; + using Detectors; + using System; + using System.Runtime.InteropServices; + using UnityEngine; + using Utils; + + /// + /// Use it instead of regular decimal for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredDecimal : IObscuredType + { + [SerializeField] internal long currentCryptoKey; + [SerializeField] internal ACTkByte16 hiddenValue; + [SerializeField] internal bool inited; + private decimal fakeValue; + [SerializeField] internal bool fakeValueActive; + + private ObscuredDecimal(decimal value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = InternalEncrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0m; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static decimal Encrypt(decimal value, long key) + { + return DecimalLongBytesUnion.XorDecimalToDecimal(value, key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static decimal Decrypt(decimal value, long key) + { + return DecimalLongBytesUnion.XorDecimalToDecimal(value, key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredDecimal FromEncrypted(decimal encrypted, long key) + { + var instance = new ObscuredDecimal(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static long GenerateKey() + { + return RandomUtils.GenerateLongKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public decimal GetEncrypted(out long key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return DecimalLongBytesUnion.ConvertB16ToDecimal(hiddenValue); + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(decimal encrypted, long key) + { + inited = true; + hiddenValue = DecimalLongBytesUnion.ConvertDecimalToB16(encrypted); + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public decimal GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = InternalEncrypt(decrypted, currentCryptoKey); + } + + private static ACTkByte16 InternalEncrypt(decimal value, long key) + { + return DecimalLongBytesUnion.XorDecimalToB16(value, key); + } + + private decimal InternalDecrypt() + { + if (!inited) + { + Init(); + return 0m; + } + + var decrypted = DecimalLongBytesUnion.XorB16ToDecimal(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredDecimal)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = InternalEncrypt(0m, currentCryptoKey); + fakeValue = 0m; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(long newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static decimal Encrypt(decimal value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static decimal Decrypt(decimal value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredDecimal FromEncrypted(decimal encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public decimal GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(decimal encrypted) {} + + #endregion + + //! @endcond + + [StructLayout(LayoutKind.Explicit)] + private struct DecimalLongBytesUnion + { + [FieldOffset(0)] + private decimal d; + + [FieldOffset(0)] + private long l1; + + [FieldOffset(8)] + private long l2; + + [FieldOffset(0)] + private ACTkByte16 b16; + + internal static decimal XorDecimalToDecimal(decimal value, long key) + { + return FromDecimal(value).XorLongs(key).d; + } + + internal static ACTkByte16 XorDecimalToB16(decimal value, long key) + { + return FromDecimal(value).XorLongs(key).b16; + } + + internal static decimal XorB16ToDecimal(ACTkByte16 value, long key) + { + return FromB16(value).XorLongs(key).d; + } + + internal static decimal ConvertB16ToDecimal(ACTkByte16 value) + { + return FromB16(value).d; + } + + internal static ACTkByte16 ConvertDecimalToB16(decimal value) + { + return FromDecimal(value).b16; + } + + private static DecimalLongBytesUnion FromDecimal(decimal value) + { + return new DecimalLongBytesUnion {d = value}; + } + + private static DecimalLongBytesUnion FromB16(ACTkByte16 value) + { + return new DecimalLongBytesUnion {b16 = value}; + } + + private DecimalLongBytesUnion XorLongs(long key) + { + l1 ^= key; + l2 ^= key; + return this; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs.meta new file mode 100644 index 0000000..21cddbe --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDecimal.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 4280032ce141abb46abd2b1a00b00737 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs new file mode 100644 index 0000000..86b2810 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs @@ -0,0 +1,114 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredDouble : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredDouble(double value) + { + return new ObscuredDouble(value); + } + + public static implicit operator double(ObscuredDouble value) + { + return value.InternalDecrypt(); + } + + public static explicit operator ObscuredDouble(ObscuredFloat f) + { + return (float)f; + } + + public static ObscuredDouble operator ++(ObscuredDouble input) + { + return Increment(input, 1); + } + + public static ObscuredDouble operator --(ObscuredDouble input) + { + return Increment(input, -1); + } + + private static ObscuredDouble Increment(ObscuredDouble input, double increment) + { + var decrypted = input.InternalDecrypt() + increment; + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredDouble o && Equals(o) || + other is double r && Equals(r); + } + + public bool Equals(ObscuredDouble other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(double other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredDouble other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(double other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs.meta new file mode 100644 index 0000000..9fee8bf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 352a6c04af12482086a0adc92034eb9c +timeCreated: 1679403668 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs new file mode 100644 index 0000000..49ffe47 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredDouble + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return IsEqual(fakeValue, InternalDecrypt()); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs.meta new file mode 100644 index 0000000..e3bd258 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2602353bf39b46778d8977dd0a5b45fc +timeCreated: 1667756465 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs new file mode 100644 index 0000000..fd72a12 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs @@ -0,0 +1,337 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using Common; + using Detectors; + using System; + using UnityEngine; + using System.Runtime.InteropServices; + using UnityEngine.Serialization; + using Utils; + + /// + /// Use it instead of regular double for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredDouble : IObscuredType + { +#if UNITY_EDITOR + public string migratedVersion; +#endif + + [SerializeField] internal long currentCryptoKey; + [SerializeField] internal long hiddenValue; + [SerializeField] [FormerlySerializedAs("hiddenValue")] +#pragma warning disable 414 + private ACTkByte8 hiddenValueOldByte8; +#pragma warning restore 414 + + [SerializeField] internal double fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredDouble(double value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + hiddenValueOldByte8 = default; + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; + migratedVersion = null; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0L; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static long Encrypt(double value, long key) + { + return DoubleLongBytesUnion.XorDoubleToLong(value, key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static double Decrypt(long value, long key) + { + return DoubleLongBytesUnion.XorLongToDouble(value, key); + } + + /// + /// Allows to update the encrypted value to the newer encryption format. + /// + /// Use when you have some encrypted values saved somewhere with previous ACTk version + /// and you wish to set them using SetEncrypted() to the newer ACTk version obscured type. + /// Current migration variants: + /// from 0 or 1 to 2 - migrate obscured type from ACTk 1.5.2.0-1.5.8.0 to the 1.5.9.0+ format + /// Encrypted value you got from previous ACTk version obscured type with GetEncrypted(). + /// Source format version. + /// Target format version. + /// Migrated raw encrypted value which you may use for SetEncrypted() later. + public static long MigrateEncrypted(long encrypted, byte fromVersion = 0, byte toVersion = 2) + { + return DoubleLongBytesUnion.Migrate(encrypted, fromVersion, toVersion); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredDouble FromEncrypted(long encrypted, long key) + { + var instance = new ObscuredDouble(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static long GenerateKey() + { + return RandomUtils.GenerateLongKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public long GetEncrypted(out long key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(long encrypted, long key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public double GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private double InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + +#if ACTK_OBSCURED_AUTO_MIGRATION + if (hiddenValueOldByte8.b1 != 0 || + hiddenValueOldByte8.b2 != 0 || + hiddenValueOldByte8.b3 != 0 || + hiddenValueOldByte8.b4 != 0 || + hiddenValueOldByte8.b5 != 0 || + hiddenValueOldByte8.b6 != 0 || + hiddenValueOldByte8.b7 != 0 || + hiddenValueOldByte8.b8 != 0) + { + var union = new DoubleLongBytesUnion { b8 = hiddenValueOldByte8 }; + union.b8.Shuffle(); + hiddenValue = union.l; + + hiddenValueOldByte8.b1 = 0; + hiddenValueOldByte8.b2 = 0; + hiddenValueOldByte8.b3 = 0; + hiddenValueOldByte8.b4 = 0; + hiddenValueOldByte8.b5 = 0; + hiddenValueOldByte8.b6 = 0; + hiddenValueOldByte8.b7 = 0; + hiddenValueOldByte8.b8 = 0; + } +#endif + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && + !IsEqual(decrypted, fakeValue, ObscuredCheatingDetector.Instance.doubleEpsilon)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredDouble)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.doubleEpsilon}\n" + + $"equal: {IsEqual(decrypted, fakeValue, ObscuredCheatingDetector.Instance.doubleEpsilon)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + private bool IsEqual(double a, double b, double epsilon = double.Epsilon) + { + const double lowestMeaningful = 2.2250738585072014E-308d; + var absA = Math.Abs(a); + var absB = Math.Abs(b); + var diff = Math.Abs(a - b); + + if (a.Equals(b)) // for infinities and NaNs + return true; + + if (a == 0 || b == 0 || absA + absB < lowestMeaningful) // for very small numbers + return diff < epsilon * lowestMeaningful; + + return diff / (absA + absB) < epsilon; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(long newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static long Encrypt(double value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static double Decrypt(long value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredDouble FromEncrypted(long encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public long GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(long encrypted) {} + + #endregion + + //! @endcond + + [StructLayout(LayoutKind.Explicit)] + private struct DoubleLongBytesUnion + { + [FieldOffset(0)] private double d; + [FieldOffset(0)] internal long l; // need to be internal for ACTK_OBSCURED_AUTO_MIGRATION + [FieldOffset(0)] internal ACTkByte8 b8; // need to be internal for ACTK_OBSCURED_AUTO_MIGRATION + + internal static long Migrate(long value, byte fromVersion, byte toVersion) + { + var u = FromLong(value); + + if (fromVersion < 2 && toVersion == 2) + u.b8.Shuffle(); + + return u.l; + } + + internal static long XorDoubleToLong(double value, long key) + { + return FromDouble(value).Shuffle(key).l; + } + + internal static double XorLongToDouble(long value, long key) + { + return FromLong(value).UnShuffle(key).d; + } + + private static DoubleLongBytesUnion FromDouble(double value) + { + return new DoubleLongBytesUnion { d = value}; + } + + private static DoubleLongBytesUnion FromLong(long value) + { + return new DoubleLongBytesUnion { l = value}; + } + + private DoubleLongBytesUnion Shuffle(long key) + { + l ^= key; + b8.Shuffle(); + + return this; + } + + private DoubleLongBytesUnion UnShuffle(long key) + { + b8.UnShuffle(); + l ^= key; + + return this; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs.meta new file mode 100644 index 0000000..5f56104 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredDouble.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e000716291073174da137134a3bee2ba +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs new file mode 100644 index 0000000..af448ee --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredFloat : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredFloat(float value) + { + return new ObscuredFloat(value); + } + + public static implicit operator float(ObscuredFloat value) + { + return value.InternalDecrypt(); + } + + public static ObscuredFloat operator ++(ObscuredFloat input) + { + return Increment(input, 1); + } + + public static ObscuredFloat operator --(ObscuredFloat input) + { + return Increment(input, -1); + } + + private static ObscuredFloat Increment(ObscuredFloat input, int increment) + { + var decrypted = input.InternalDecrypt() + increment; + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredFloat o && Equals(o) || + other is float r && Equals(r); + } + + public bool Equals(ObscuredFloat other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(float other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredFloat other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(float other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs.meta new file mode 100644 index 0000000..0e03e4a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ed318b58608d48869150cc247220c20c +timeCreated: 1679403799 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs new file mode 100644 index 0000000..07480d6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredFloat + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return Compare(fakeValue, InternalDecrypt()); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs.meta new file mode 100644 index 0000000..40f65f7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 352c3042e2c443bc9f873ec73e8a80e6 +timeCreated: 1667756772 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs new file mode 100644 index 0000000..68c67f7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs @@ -0,0 +1,317 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using Common; + using Detectors; + using System; + using UnityEngine; + using System.Runtime.InteropServices; + using UnityEngine.Serialization; + using Utils; + + /// + /// Use it instead of regular float for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredFloat : IObscuredType + { +#if UNITY_EDITOR + public string migratedVersion; +#endif + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal int hiddenValue; + [SerializeField] [FormerlySerializedAs("hiddenValue")] +#pragma warning disable 414 + private ACTkByte4 hiddenValueOldByte4; +#pragma warning restore 414 + + [SerializeField] internal float fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredFloat(float value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + hiddenValueOldByte4 = default; + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; + migratedVersion = null; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0f; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static int Encrypt(float value, int key) + { + return FloatIntBytesUnion.XorFloatToInt(value, key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static float Decrypt(int value, int key) + { + return FloatIntBytesUnion.XorIntToFloat(value, key); + } + + /// + /// Allows to update the raw encrypted value to the newer encryption format. + /// + /// Use when you have some encrypted values saved somewhere with previous ACTk version + /// and you wish to set them using SetEncrypted() to the newer ACTk version obscured type. + /// Current migration variants: + /// from 0 or 1 to 2 - migrate obscured type from ACTk 1.5.2.0-1.5.8.0 to the 1.5.9.0+ format + /// Encrypted value you got from previous ACTk version obscured type with GetEncrypted(). + /// Source format version. + /// Target format version. + /// Migrated raw encrypted value which you may use for SetEncrypted(0 later. + public static int MigrateEncrypted(int encrypted, byte fromVersion = 0, byte toVersion = 2) + { + return FloatIntBytesUnion.Migrate(encrypted, fromVersion, toVersion); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredFloat FromEncrypted(int encrypted, int key) + { + var instance = new ObscuredFloat(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + private static bool Compare(float f1, float f2) + { + var epsilon = ObscuredCheatingDetector.ExistsAndIsRunning ? + ObscuredCheatingDetector.Instance.floatEpsilon : float.Epsilon; + return NumUtils.CompareFloats(f1, f2, epsilon); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public int GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(int encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public float GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private float InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + +#if ACTK_OBSCURED_AUTO_MIGRATION + if (hiddenValueOldByte4.b1 != 0 || + hiddenValueOldByte4.b2 != 0 || + hiddenValueOldByte4.b3 != 0 || + hiddenValueOldByte4.b4 != 0) + { + var union = new FloatIntBytesUnion {b4 = hiddenValueOldByte4}; + union.b4.Shuffle(); + hiddenValue = union.i; + + hiddenValueOldByte4.b1 = 0; + hiddenValueOldByte4.b2 = 0; + hiddenValueOldByte4.b3 = 0; + hiddenValueOldByte4.b4 = 0; + } +#endif + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredFloat)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.floatEpsilon}\n" + + $"compare: {Compare(decrypted, fakeValue)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static int Encrypt(float value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static float Decrypt(int value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredFloat FromEncrypted(int encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public int GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(int encrypted) {} + + #endregion + + //! @endcond + + [StructLayout(LayoutKind.Explicit)] + internal struct FloatIntBytesUnion + { + [FieldOffset(0)] private float f; + [FieldOffset(0)] internal int i; // need to be internal for ACTK_OBSCURED_AUTO_MIGRATION + [FieldOffset(0)] internal ACTkByte4 b4; // need to be internal for ACTK_OBSCURED_AUTO_MIGRATION + + public static int Migrate(int value, byte fromVersion, byte toVersion) + { + var u = FromInt(value); + + if (fromVersion < 2 && toVersion == 2) + u.b4.Shuffle(); + + return u.i; + } + + internal static int XorFloatToInt(float value, int key) + { + return FromFloat(value).Shuffle(key).i; + } + + internal static float XorIntToFloat(int value, int key) + { + return FromInt(value).UnShuffle(key).f; + } + + private static FloatIntBytesUnion FromFloat(float value) + { + return new FloatIntBytesUnion { f = value}; + } + + private static FloatIntBytesUnion FromInt(int value) + { + return new FloatIntBytesUnion { i = value}; + } + + private FloatIntBytesUnion Shuffle(int key) + { + i ^= key; + b4.Shuffle(); + + return this; + } + + private FloatIntBytesUnion UnShuffle(int key) + { + b4.UnShuffle(); + i ^= key; + + return this; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs.meta new file mode 100644 index 0000000..35e78f0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredFloat.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 0062c4ab43af0ba4bb3a8b3d83c1e16d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs new file mode 100644 index 0000000..b3f8f34 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs @@ -0,0 +1,124 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredInt : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredInt(int value) + { + return new ObscuredInt(value); + } + + public static implicit operator int(ObscuredInt value) + { + return value.InternalDecrypt(); + } + + public static implicit operator ObscuredFloat(ObscuredInt value) + { + return value.InternalDecrypt(); + } + + public static implicit operator ObscuredDouble(ObscuredInt value) + { + return value.InternalDecrypt(); + } + + public static explicit operator ObscuredUInt(ObscuredInt value) + { + return (uint)value.InternalDecrypt(); + } + + public static ObscuredInt operator ++(ObscuredInt input) + { + return Increment(input, 1); + } + + public static ObscuredInt operator --(ObscuredInt input) + { + return Increment(input, -1); + } + + private static ObscuredInt Increment(ObscuredInt input, int increment) + { + var decrypted = input.InternalDecrypt() + increment; + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredInt o && Equals(o) || + other is int r && Equals(r); + } + + public bool Equals(ObscuredInt other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(int other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredInt other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(int other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs.meta new file mode 100644 index 0000000..ccc1d6e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 83a81ecd47f749c19fa2fb601d2e77b6 +timeCreated: 1679403896 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs new file mode 100644 index 0000000..ff6549a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredInt + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs.meta new file mode 100644 index 0000000..966631a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c4c7ef58a0b547db891276b5cbbee8bb +timeCreated: 1667756897 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs new file mode 100644 index 0000000..0c26668 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs @@ -0,0 +1,209 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular int for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredInt : IObscuredType + { + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal int hiddenValue; + [SerializeField] internal int fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredInt(int value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static int Encrypt(int value, int key) + { + return value ^ key; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static int Decrypt(int value, int key) + { + return value ^ key; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredInt FromEncrypted(int encrypted, int key) + { + var instance = new ObscuredInt(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public int GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(int encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public int GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + hiddenValue = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(hiddenValue, currentCryptoKey); + } + + private int InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredInt)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static int Encrypt(int value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static int Decrypt(int value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredInt FromEncrypted(int encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public int GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(int encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs.meta new file mode 100644 index 0000000..da16bf6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredInt.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 135d4771d45b98a46bf8fc40cc92c2c5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs new file mode 100644 index 0000000..8fe69f5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredLong : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredLong(long value) + { + return new ObscuredLong(value); + } + + public static implicit operator long(ObscuredLong value) + { + return value.InternalDecrypt(); + } + + public static ObscuredLong operator ++(ObscuredLong input) + { + return Increment(input, 1); + } + + public static ObscuredLong operator --(ObscuredLong input) + { + return Increment(input, -1); + } + + private static ObscuredLong Increment(ObscuredLong input, int increment) + { + var decrypted = input.InternalDecrypt() + increment; + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredLong o && Equals(o) || + other is long r && Equals(r); + } + + public bool Equals(ObscuredLong other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(long other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredLong other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(long other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs.meta new file mode 100644 index 0000000..1214e4b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c1f4e4f0823481790ea9836b60e9c8a +timeCreated: 1679401118 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs new file mode 100644 index 0000000..5cc73a8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredLong + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs.meta new file mode 100644 index 0000000..91eae08 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6447e4a358db4386abc01c188cdda3a9 +timeCreated: 1667757201 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs new file mode 100644 index 0000000..ae6e75b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs @@ -0,0 +1,209 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular long for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredLong : IObscuredType + { + [SerializeField] internal long currentCryptoKey; + [SerializeField] internal long hiddenValue; + [SerializeField] internal long fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredLong(long value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static long Encrypt(long value, long key) + { + return value ^ key; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static long Decrypt(long value, long key) + { + return value ^ key; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredLong FromEncrypted(long encrypted, long key) + { + var instance = new ObscuredLong(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static long GenerateKey() + { + return RandomUtils.GenerateLongKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public long GetEncrypted(out long key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(long encrypted, long key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public long GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private long InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredLong)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + #region obsolete + + //! @cond + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(long newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static long Encrypt(long value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static long Decrypt(long value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredLong FromEncrypted(long encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public long GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(long encrypted) {} + + //! @endcond + + #endregion + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs.meta new file mode 100644 index 0000000..9f6d875 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredLong.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 1486394148a280c4699dd97480305294 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs new file mode 100644 index 0000000..dc645d1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs @@ -0,0 +1,65 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredQuaternion : IEquatable, IEquatable + { + public static implicit operator ObscuredQuaternion(Quaternion value) + { + return new ObscuredQuaternion(value); + } + + public static implicit operator Quaternion(ObscuredQuaternion value) + { + return value.InternalDecrypt(); + } + + public override bool Equals(object other) + { + return other is ObscuredQuaternion o && Equals(o) || + other is Quaternion r && Equals(r); + } + + public bool Equals(ObscuredQuaternion other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(Quaternion other) + { + return InternalDecrypt().Equals(other); + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public void Normalize() + { + var temp = InternalDecrypt(); + temp.Normalize(); + SetEncrypted(Encrypt(normalized, currentCryptoKey), currentCryptoKey); + } + + public Quaternion normalized => InternalDecrypt().normalized; + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs.meta new file mode 100644 index 0000000..6ac9e82 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0fe7d9772d484fbeaf8d33ce0cb5896d +timeCreated: 1679400996 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs new file mode 100644 index 0000000..6bc09a6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredQuaternion + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return Compare(fakeValue, InternalDecrypt()); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs.meta new file mode 100644 index 0000000..ca4278c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c068e4728474ea087f0db89b994b8c6 +timeCreated: 1667757261 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs new file mode 100644 index 0000000..a9147a0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs @@ -0,0 +1,62 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredQuaternion + { + /// + /// Used to store encrypted Quaternion. + /// + [Serializable] + public struct RawEncryptedQuaternion : IEquatable + { + /// + /// Encrypted value + /// + public int x; + + /// + /// Encrypted value + /// + public int y; + + /// + /// Encrypted value + /// + public int z; + + /// + /// Encrypted value + /// + public int w; + + public bool Equals(RawEncryptedQuaternion other) + { + return x == other.x && y == other.y && z == other.z && w == other.w; + } + + public override bool Equals(object obj) + { + return obj is RawEncryptedQuaternion other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = x; + hashCode = (hashCode * 397) ^ y; + hashCode = (hashCode * 397) ^ z; + hashCode = (hashCode * 397) ^ w; + return hashCode; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs.meta new file mode 100644 index 0000000..2d3953c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.Raw.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 913bb305a9394088b8b5d2b82fb12a12 +timeCreated: 1679417305 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs new file mode 100644 index 0000000..6fd621f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs @@ -0,0 +1,277 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular Quaternion for any cheating-sensitive variables. + /// + /// \htmlonlyWARNING:\endhtmlonly Doesn't mimic regular type API, thus should be used with extra caution. Cast it to regular, not obscured type to work with regular APIs.
+ /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredQuaternion : IObscuredType + { + private static readonly Quaternion Identity = Quaternion.identity; + +#if UNITY_EDITOR + public string migratedVersion; +#endif + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal RawEncryptedQuaternion hiddenValue; + [SerializeField] internal Quaternion fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredQuaternion(Quaternion value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; + migratedVersion = null; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : Identity; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Mimics constructor of regular Quaternion. Please note, passed components are not Euler Angles. + /// + /// X component of the quaternion + /// Y component of the quaternion + /// Z component of the quaternion + /// W component of the quaternion + public ObscuredQuaternion(float x, float y, float z, float w) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(x, y, z, w, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue = new Quaternion(x, y, z, w); + fakeValueActive = true; + } + else + { + fakeValue = Identity; + fakeValueActive = false; + } + +#if UNITY_EDITOR + migratedVersion = null; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedQuaternion Encrypt(Quaternion value, int key) + { + return Encrypt(value.x, value.y, value.z, value.w, key); + } + + /// + /// Encrypts passed components using passed key. + /// Please note, passed components are not an Euler Angles. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedQuaternion Encrypt(float x, float y, float z, float w, int key) + { + RawEncryptedQuaternion result; + result.x = ObscuredFloat.Encrypt(x, key); + result.y = ObscuredFloat.Encrypt(y, key); + result.z = ObscuredFloat.Encrypt(z, key); + result.w = ObscuredFloat.Encrypt(w, key); + + return result; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static Quaternion Decrypt(RawEncryptedQuaternion value, int key) + { + Quaternion result; + result.x = ObscuredFloat.Decrypt(value.x, key); + result.y = ObscuredFloat.Decrypt(value.y, key); + result.z = ObscuredFloat.Decrypt(value.z, key); + result.w = ObscuredFloat.Decrypt(value.w, key); + + return result; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredQuaternion FromEncrypted(RawEncryptedQuaternion encrypted, int key) + { + var instance = new ObscuredQuaternion(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + private static bool Compare(Quaternion q1, Quaternion q2) + { + var epsilon = ObscuredCheatingDetector.ExistsAndIsRunning ? + ObscuredCheatingDetector.Instance.quaternionEpsilon : float.Epsilon; + return NumUtils.CompareFloats(q1.x, q2.x, epsilon) && + NumUtils.CompareFloats(q1.y, q2.y, epsilon) && + NumUtils.CompareFloats(q1.z, q2.z, epsilon) && + NumUtils.CompareFloats(q1.w, q2.w, epsilon); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public RawEncryptedQuaternion GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(RawEncryptedQuaternion encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public Quaternion GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private Quaternion InternalDecrypt() + { + if (!inited) + { + Init(); + return Identity; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredQuaternion)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}\"" + + $"epsilon: {ObscuredCheatingDetector.Instance.quaternionEpsilon}\n" + + $"compare: {Compare(decrypted, fakeValue)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(Identity, currentCryptoKey); + fakeValue = Identity; + fakeValueActive = false; + inited = true; + } + + #region obsolete + + //! @cond + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static RawEncryptedQuaternion Encrypt(Quaternion value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static Quaternion Decrypt(RawEncryptedQuaternion value) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public RawEncryptedQuaternion GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(RawEncryptedQuaternion encrypted) {} + + //! @endcond + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs.meta new file mode 100644 index 0000000..3d35952 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredQuaternion.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b5554fb207077af4e9fd8a862cfef2d3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs new file mode 100644 index 0000000..4b3cbc6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredSByte : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredSByte(sbyte value) + { + return new ObscuredSByte(value); + } + + public static implicit operator sbyte(ObscuredSByte value) + { + return value.InternalDecrypt(); + } + + public static ObscuredSByte operator ++(ObscuredSByte input) + { + return Increment(input, 1); + } + + public static ObscuredSByte operator --(ObscuredSByte input) + { + return Increment(input, -1); + } + + private static ObscuredSByte Increment(ObscuredSByte input, int increment) + { + var decrypted = (sbyte)(input.InternalDecrypt() + increment); + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredSByte o && Equals(o) || + other is sbyte r && Equals(r); + } + + public bool Equals(ObscuredSByte obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(sbyte other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredSByte other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(sbyte other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs.meta new file mode 100644 index 0000000..aeb6986 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cf604223ed2241a9a278f0462bcea1fb +timeCreated: 1679404002 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs new file mode 100644 index 0000000..d4fb5fe --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs @@ -0,0 +1,214 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using Utils; + using Detectors; + + /// + /// Use it instead of regular sbyte for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredSByte : IObscuredType + { + private sbyte currentCryptoKey; + private sbyte hiddenValue; + private sbyte fakeValue; + private bool fakeValueActive; + private bool inited; + + private ObscuredSByte(sbyte value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : (sbyte)0; + fakeValueActive = detectorRunning; +#endif + + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static sbyte Encrypt(sbyte value, sbyte key) + { + return (sbyte)(value ^ key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static sbyte Decrypt(sbyte value, sbyte key) + { + return (sbyte)(value ^ key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredSByte FromEncrypted(sbyte encrypted, sbyte key) + { + var instance = new ObscuredSByte(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static sbyte GenerateKey() + { + return RandomUtils.GenerateSByteKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public sbyte GetEncrypted(out sbyte key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(sbyte encrypted, sbyte key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public sbyte GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private sbyte InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + UnityEngine.Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredSByte)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(sbyte newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static sbyte EncryptDecrypt(sbyte value) { throw new Exception(); } + + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static sbyte EncryptDecrypt(sbyte value, sbyte key) + { + return (sbyte)(value ^ key); + } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredSByte FromEncrypted(sbyte encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public sbyte GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(sbyte encrypted) {} + + #endregion + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs.meta new file mode 100644 index 0000000..813973a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredSByte.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 85fc7cb25b13cdb49bac95dfa9613df3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs new file mode 100644 index 0000000..2ea1ffd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredShort : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredShort(short value) + { + return new ObscuredShort(value); + } + + public static implicit operator short(ObscuredShort value) + { + return value.InternalDecrypt(); + } + + public static ObscuredShort operator ++(ObscuredShort input) + { + return Increment(input, 1); + } + + public static ObscuredShort operator --(ObscuredShort input) + { + return Increment(input, -1); + } + + private static ObscuredShort Increment(ObscuredShort input, int increment) + { + var decrypted = (short)(input.InternalDecrypt() + increment); + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredShort o && Equals(o) || + other is short r && Equals(r); + } + + public bool Equals(ObscuredShort obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(short other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredShort other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(short other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs.meta new file mode 100644 index 0000000..8758900 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3305d1b94ab64fb5a9253573b3e9a0fe +timeCreated: 1679404060 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs new file mode 100644 index 0000000..0778b64 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredShort + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs.meta new file mode 100644 index 0000000..7224ce2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ba529d640a1743db9d63ae30476b3ce2 +timeCreated: 1667757696 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs new file mode 100644 index 0000000..39a28b8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs @@ -0,0 +1,213 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular short for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredShort : IObscuredType + { + [SerializeField] internal short currentCryptoKey; + [SerializeField] internal short hiddenValue; + [SerializeField] internal short fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredShort(short value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : (short)0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static short Encrypt(short value, short key) + { + return (short)(value ^ key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static short Decrypt(short value, short key) + { + return (short)(value ^ key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredShort FromEncrypted(short encrypted, short key) + { + var instance = new ObscuredShort(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static short GenerateKey() + { + return RandomUtils.GenerateShortKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public short GetEncrypted(out short key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(short encrypted, short key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public short GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private short InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredShort)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(short newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static short EncryptDecrypt(short value) { throw new Exception(); } + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static short EncryptDecrypt(short value, short key) + { + return (short)(value ^ key); + } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredShort FromEncrypted(short encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public short GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(short encrypted) {} + + #endregion + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs.meta new file mode 100644 index 0000000..5dd54be --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredShort.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 46e3b6b31fa3d9b41ab6f000a24f838b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs new file mode 100644 index 0000000..09bd978 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs @@ -0,0 +1,159 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public sealed partial class ObscuredString : IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public int Length => hiddenChars.Length; + + /// + /// Proxy to the String API. + /// Please consider avoiding using this in a hot path since it invokes decryption on every access call. + /// + public char this[int index] + { + get + { + if (index < 0 || index >= Length) + throw new IndexOutOfRangeException(); + return InternalDecrypt()[index]; + } + } + + public static implicit operator ObscuredString(string value) + { + return value == null ? null : new ObscuredString(value); + } + + public static implicit operator string(ObscuredString value) + { + return value == null ? null : value.InternalDecryptToString(); + } + + /// + /// Determines whether two specified ObscuredStrings have the same value. + /// + /// + /// + /// true if the value of is the same as the value of ; otherwise, false. + /// + /// An ObscuredString or null. An ObscuredString or null. + public static bool operator ==(ObscuredString a, ObscuredString b) + { + if (ReferenceEquals(a, b)) + return true; + + if ((object)a == null || (object)b == null) + return false; + + return a.cryptoKey == b.cryptoKey + ? ArraysEquals(a.hiddenChars, b.hiddenChars) + : ArraysEquals(a.InternalDecrypt(), b.InternalDecrypt()); + } + + /// + /// Determines whether two specified ObscuredStrings have different values. + /// + /// + /// + /// true if the value of is different from the value of ; otherwise, false. + /// + /// An ObscuredString or null. An ObscuredString or null. + public static bool operator !=(ObscuredString a, ObscuredString b) + { + return !(a == b); + } + + /// + /// Proxy to the String API. + /// Please consider avoiding using this in a hot path since it invokes decryption on every access call. + /// + public string Substring(int startIndex) + { + return Substring(startIndex, Length - startIndex); + } + + /// + /// Proxy to the String API. + /// Please consider avoiding using this in a hot path since it invokes decryption on every access call. + /// + public string Substring(int startIndex, int length) + { + return InternalDecryptToString().Substring(startIndex, length); + } + + /// + /// Proxy to the String API. + /// Please consider avoiding using this in a hot path since it invokes decryption on every access call. + /// + public bool StartsWith(string value, StringComparison comparisonType = StringComparison.CurrentCulture) + { + return InternalDecryptToString().StartsWith(value, comparisonType); + } + + /// + /// Proxy to the String API. + /// Please consider avoiding using this in a hot path since it invokes decryption on every access call. + /// + public bool EndsWith(string value, StringComparison comparisonType = StringComparison.CurrentCulture) + { + return InternalDecryptToString().EndsWith(value, comparisonType); + } + + public override int GetHashCode() + { + return InternalDecryptToString().GetHashCode(); + } + + public override string ToString() + { + return InternalDecryptToString(); + } + + public override bool Equals(object other) + { + return other is ObscuredString o && Equals(o) || + other is string r && Equals(r); + } + + public bool Equals(ObscuredString obj) + { + if (obj == null) return false; + + return cryptoKey == obj.cryptoKey ? ArraysEquals(hiddenChars, obj.hiddenChars) : + ArraysEquals(InternalDecrypt(), obj.InternalDecrypt()); + } + + public bool Equals(ObscuredString value, StringComparison comparisonType) + { + return value != null && + string.Equals(InternalDecryptToString(), value.InternalDecryptToString(), comparisonType); + } + + public bool Equals(string other) + { + return InternalDecryptToString().Equals(other); + } + + public int CompareTo(ObscuredString other) + { + return InternalDecryptToString().CompareTo(other.InternalDecryptToString()); + } + + public int CompareTo(string other) + { + return InternalDecryptToString().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecryptToString().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs.meta new file mode 100644 index 0000000..1160ecc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1ece52e9b49435aa1f0bccec969feb4 +timeCreated: 1679404093 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs new file mode 100644 index 0000000..e8fc738 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public sealed partial class ObscuredString + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == GetDecrypted(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs.meta new file mode 100644 index 0000000..6078cf0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2f1581216ccf4e2eb7ac53d0133bc220 +timeCreated: 1667512610 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs new file mode 100644 index 0000000..cdc7c91 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs @@ -0,0 +1,430 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using Common; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular string for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public sealed partial class ObscuredString : IObscuredType + { + [SerializeField] private string currentCryptoKey; // deprecated +#pragma warning disable 0649 + [SerializeField] private byte[] hiddenValue; // deprecated +#pragma warning restore 0649 + + [SerializeField] internal char[] cryptoKey; + [SerializeField] internal char[] hiddenChars; + [SerializeField] internal string fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + // for serialization purposes + private ObscuredString(){} + + private ObscuredString(string value) + { + cryptoKey = new char[7]; + GenerateKey(ref cryptoKey); + hiddenChars = InternalEncryptDecrypt(value.ToCharArray(), cryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : null; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static char[] Encrypt(string value, string key) + { + return Encrypt(value, key.ToCharArray()); + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static char[] Encrypt(string value, char[] key) + { + return Encrypt(value.ToCharArray(), key); + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static char[] Encrypt(char[] value, char[] key) + { + return InternalEncryptDecrypt(value, key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static string Decrypt(char[] value, string key) + { + return Decrypt(value, key.ToCharArray()); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static string Decrypt(char[] value, char[] key) + { + return new string(InternalEncryptDecrypt(value, key)); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredString FromEncrypted(char[] encrypted, char[] key) + { + var instance = new ObscuredString(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Use this only to decrypt data encrypted with previous ACTk versions. + /// + /// Please use \ref FromEncrypted() "FromEncrypted(char[], char[])" in other cases. + [Obsolete("Use this only to decrypt data encrypted with previous ACTk versions. " + + "Please use FromEncrypted(char[], char[]) in other cases.")] + public static ObscuredString FromEncrypted(string encrypted, string key = "4441") + { + var instance = new ObscuredString(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key in new allocated array. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static char[] GenerateKey() + { + var arrayToFill = new char[7]; + GenerateKey(ref arrayToFill); + return arrayToFill; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Preallocated char array. Only first 7 bytes are filled. + public static void GenerateKey(ref char[] arrayToFill) + { + RandomUtils.GenerateCharArrayKey(ref arrayToFill); + } + + [Obsolete("Please use version with ref argument or without arguments instead.")] + public static char[] GenerateKey(char[] arrayToFill) + { + RandomUtils.GenerateCharArrayKey(ref arrayToFill); + return arrayToFill; + } + + internal static char[] InternalEncryptDecrypt(char[] value, char[] key) + { + if (value == null || value.Length == 0) + return value; + + if (key.Length == 0) + { + Debug.LogError(ACTk.LogPrefix + "Empty key can't be used for string encryption or decryption!"); + return value; + } + + var keyLength = key.Length; + var valueLength = value.Length; + var result = new char[valueLength]; + + for (var i = 0; i < valueLength; i++) + { + result[i] = (char)(value[i] ^ key[i % keyLength]); + } + + return result; + } + + internal static string EncryptDecryptObsolete(string value, string key) + { + if (string.IsNullOrEmpty(value)) + return string.Empty; + + if (string.IsNullOrEmpty(key)) + { + Debug.LogError(ACTk.LogPrefix + "Empty key can't be used for string encryption or decryption!"); + return string.Empty; + } + + var keyLength = key.Length; + var valueLength = value.Length; + var result = new char[valueLength]; + + for (var i = 0; i < valueLength; i++) + { + result[i] = (char)(value[i] ^ key[i % keyLength]); + } + + return new string(result); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public char[] GetEncrypted(out char[] key) + { + if (!inited) + Init(); + + key = cryptoKey; + return hiddenChars; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(char[] encrypted, char[] key) + { + inited = true; + hiddenChars = encrypted; + cryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecryptToString(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Use this only to decrypt data encrypted with previous ACTk versions. + /// + /// Please use \ref SetEncrypted() "SetEncrypted(char[], char[])" in other cases. + [Obsolete("Use this only to decrypt data encrypted with previous ACTk versions. " + + "Please use SetEncrypted(char[], char[]) in other cases.")] + public void SetEncrypted(string encrypted, string key) + { + inited = true; + var decrypted = EncryptDecryptObsolete(encrypted, key); + cryptoKey = GenerateKey(); + hiddenChars = Encrypt(decrypted, cryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecryptToString(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public string GetDecrypted() + { + return InternalDecryptToString(); + } + + /// + /// GC-friendly alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value as a raw chars array in case you don't wish to allocate new string. + public char[] GetDecryptedToChars() + { + return InternalDecrypt(); + } + + /// + /// Allows to change current crypto key to the new random value and re-encrypt variable using it. + /// Use it for extra protection against 'unknown value' search. + /// Just call it sometimes when your variable doesn't change to fool the cheater. + /// + /// \htmlonlyWARNING:\endhtmlonly produces some GC allocations, be careful when using it! + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + GenerateKey(ref cryptoKey); + hiddenChars = InternalEncryptDecrypt(decrypted, cryptoKey); // encrypting + } + + private string InternalDecryptToString() + { + return new string(InternalDecrypt()); + } + + private char[] InternalDecrypt() + { + if (!inited) + { + Init(); + return Array.Empty(); + } + + if (!string.IsNullOrEmpty(currentCryptoKey)) + MigrateFromACTkV1(); + + var decrypted = InternalEncryptDecrypt(hiddenChars, cryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredString)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}\n" + + $"compare: {Compare(decrypted, fakeValue)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + cryptoKey = new char[7]; + GenerateKey(ref cryptoKey); + hiddenChars = InternalEncryptDecrypt(Array.Empty(), cryptoKey); // encrypting + fakeValue = string.Empty; + fakeValueActive = false; + inited = true; + } + + private bool Compare(char[] chars, string s) + { + if (chars.Length != s.Length) return false; + + for (var i = 0; i < chars.Length; i++) + { + if (chars[i] != s[i]) + return false; + } + + return true; + } + + internal void MigrateFromACTkV1() + { + var decryptedOld = EncryptDecryptObsolete(GetStringObsolete(hiddenValue), currentCryptoKey); + GenerateKey(ref cryptoKey); + hiddenChars = InternalEncryptDecrypt(decryptedOld.ToCharArray(), cryptoKey); + currentCryptoKey = null; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(string newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static string EncryptDecrypt(string value) { throw new Exception(); } + + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static string EncryptDecrypt(string value, string key) + { + return EncryptDecryptObsolete(value, key); + } + +/* [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredString FromEncrypted(string encrypted) { throw new Exception(); }*/ + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public string GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(string encrypted) {} + + #endregion + + //! @endcond + + internal static string GetStringObsolete(byte[] bytes) + { + var chars = new char[bytes.Length / sizeof(char)]; + Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length); + return new string(chars); + } + + internal static byte[] GetBytesObsolete(string str) + { + var bytes = new byte[str.Length * sizeof(char)]; + Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); + return bytes; + } + + private static bool ArraysEquals(char[] a1, char[] a2) + { + if (a1 == a2) return true; + if (a1 == null || a2 == null) return false; + if (a1.Length != a2.Length) return false; + + for (var i = 0; i < a1.Length; i++) + { + if (a1[i] != a2[i]) + return false; + } + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs.meta new file mode 100644 index 0000000..6591667 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredString.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b7384734914d23c46a03e66efa0e3772 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs new file mode 100644 index 0000000..a139c4c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs @@ -0,0 +1,114 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredUInt : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredUInt(uint value) + { + return new ObscuredUInt(value); + } + + public static implicit operator uint(ObscuredUInt value) + { + return value.InternalDecrypt(); + } + + public static explicit operator ObscuredInt(ObscuredUInt value) + { + return (int)value.InternalDecrypt(); + } + + public static ObscuredUInt operator ++(ObscuredUInt input) + { + return Increment(input, 1); + } + + public static ObscuredUInt operator --(ObscuredUInt input) + { + return Increment(input, -1); + } + + private static ObscuredUInt Increment(ObscuredUInt input, int increment) + { + var decrypted = (uint)(input.InternalDecrypt() + increment); + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredUInt o && Equals(o) || + other is uint r && Equals(r); + } + + public bool Equals(ObscuredUInt obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(uint other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredUInt other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(uint other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs.meta new file mode 100644 index 0000000..87c2a23 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4fd4788d44324ca9aaad04c3eabf4b0f +timeCreated: 1679404128 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs new file mode 100644 index 0000000..ba5ecbc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredUInt + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs.meta new file mode 100644 index 0000000..66ec407 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f70a5adbfb3245b0b3d004bcb31a24eb +timeCreated: 1667757804 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs new file mode 100644 index 0000000..d89c235 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs @@ -0,0 +1,209 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular uint for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredUInt : IObscuredType + { + [SerializeField] internal uint currentCryptoKey; + [SerializeField] internal uint hiddenValue; + [SerializeField] internal uint fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredUInt(uint value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static uint Encrypt(uint value, uint key) + { + return value ^ key; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static uint Decrypt(uint value, uint key) + { + return value ^ key; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredUInt FromEncrypted(uint encrypted, uint key) + { + var instance = new ObscuredUInt(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static uint GenerateKey() + { + return RandomUtils.GenerateUIntKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public uint GetEncrypted(out uint key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(uint encrypted, uint key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public uint GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private uint InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredUInt)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(uint newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static int Encrypt(uint value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static int Decrypt(uint value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredUInt FromEncrypted(uint encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public uint GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(uint encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs.meta new file mode 100644 index 0000000..eb09535 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUInt.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 36ce40c89daa5014fb48c61a9f8e1223 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs new file mode 100644 index 0000000..8e23c70 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredULong : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredULong(ulong value) + { + return new ObscuredULong(value); + } + + public static implicit operator ulong(ObscuredULong value) + { + return value.InternalDecrypt(); + } + + public static ObscuredULong operator ++(ObscuredULong input) + { + return Increment(input, true); + } + + public static ObscuredULong operator --(ObscuredULong input) + { + return Increment(input, false); + } + + private static ObscuredULong Increment(ObscuredULong input, bool positive) + { + var decrypted = positive ? input.InternalDecrypt() + 1 : input.InternalDecrypt() - 1; + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredULong o && Equals(o) || + other is ulong r && Equals(r); + } + + public bool Equals(ObscuredULong obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(ulong other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredULong other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(ulong other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs.meta new file mode 100644 index 0000000..04fef8d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bffdf5db0aff4d60af9b627f8c59426c +timeCreated: 1679404161 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs new file mode 100644 index 0000000..2c29128 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredULong + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs.meta new file mode 100644 index 0000000..5cafd91 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: caa6f1e794994c469fea73a44f03329f +timeCreated: 1667757946 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs new file mode 100644 index 0000000..aa18a40 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs @@ -0,0 +1,209 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular ulong for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredULong : IObscuredType + { + [SerializeField] internal ulong currentCryptoKey; + [SerializeField] internal ulong hiddenValue; + [SerializeField] internal ulong fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredULong(ulong value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : 0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static ulong Encrypt(ulong value, ulong key) + { + return value ^ key; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static ulong Decrypt(ulong value, ulong key) + { + return value ^ key; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredULong FromEncrypted(ulong encrypted, ulong key) + { + var instance = new ObscuredULong(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static ulong GenerateKey() + { + return RandomUtils.GenerateULongKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public ulong GetEncrypted(out ulong key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(ulong encrypted, ulong key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public ulong GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private ulong InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredULong)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(ulong newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static ulong Encrypt(ulong value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static ulong Decrypt(ulong value) { throw new Exception(); } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredULong FromEncrypted(ulong encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public ulong GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(ulong encrypted) {} + + #endregion + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs.meta new file mode 100644 index 0000000..4815f29 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredULong.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ba6f44ca353c8e14c9956d3b2ca79d42 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs new file mode 100644 index 0000000..652b23f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs @@ -0,0 +1,109 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Detectors; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredUShort : IFormattable, IEquatable, IEquatable, IComparable, IComparable, IComparable + { + public static implicit operator ObscuredUShort(ushort value) + { + return new ObscuredUShort(value); + } + + public static implicit operator ushort(ObscuredUShort value) + { + return value.InternalDecrypt(); + } + + public static ObscuredUShort operator ++(ObscuredUShort input) + { + return Increment(input, 1); + } + + public static ObscuredUShort operator --(ObscuredUShort input) + { + return Increment(input, -1); + } + + private static ObscuredUShort Increment(ObscuredUShort input, int increment) + { + var decrypted = (ushort)(input.InternalDecrypt() + increment); + input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + input.fakeValue = decrypted; + input.fakeValueActive = true; + } + else + { + input.fakeValueActive = false; + } + + return input; + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public string ToString(IFormatProvider provider) + { + return InternalDecrypt().ToString(provider); + } + + public string ToString(string format, IFormatProvider provider) + { + return InternalDecrypt().ToString(format, provider); + } + + public override bool Equals(object other) + { + return other is ObscuredUShort o && Equals(o) || + other is ushort r && Equals(r); + } + + public bool Equals(ObscuredUShort obj) + { + return currentCryptoKey == obj.currentCryptoKey ? hiddenValue.Equals(obj.hiddenValue) : + InternalDecrypt().Equals(obj.InternalDecrypt()); + } + + public bool Equals(ushort other) + { + return InternalDecrypt().Equals(other); + } + + public int CompareTo(ObscuredUShort other) + { + return InternalDecrypt().CompareTo(other.InternalDecrypt()); + } + + public int CompareTo(ushort other) + { + return InternalDecrypt().CompareTo(other); + } + + public int CompareTo(object obj) + { + return InternalDecrypt().CompareTo(obj); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs.meta new file mode 100644 index 0000000..07b0c16 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 35caec54866c4efe8ea236bc42b39ec0 +timeCreated: 1679404193 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs new file mode 100644 index 0000000..9ce3335 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs @@ -0,0 +1,212 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using Utils; + using Detectors; + + /// + /// Use it instead of regular ushort for any cheating-sensitive variables. + /// + /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredUShort : IObscuredType + { + private ushort currentCryptoKey; + private ushort hiddenValue; + private ushort fakeValue; + private bool fakeValueActive; + private bool inited; + + private ObscuredUShort(ushort value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : (ushort)0; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static ushort Encrypt(ushort value, ushort key) + { + return (ushort)(value ^ key); + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static ushort Decrypt(ushort value, ushort key) + { + return (ushort)(value ^ key); + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredUShort FromEncrypted(ushort encrypted, ushort key) + { + var instance = new ObscuredUShort(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static ushort GenerateKey() + { + return RandomUtils.GenerateUShortKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public ushort GetEncrypted(out ushort key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(ushort encrypted, ushort key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public ushort GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private ushort InternalDecrypt() + { + if (!inited) + { + Init(); + return 0; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + UnityEngine.Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredUShort)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(0, currentCryptoKey); + fakeValue = 0; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(ushort newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) API instead.", true)] + public static ushort EncryptDecrypt(ushort value) { throw new Exception(); } + + [Obsolete("Please use new Encrypt(value, key) or Decrypt(value, key) APIs instead. " + + "This API will be removed in future updates.")] + public static ushort EncryptDecrypt(ushort value, ushort key) + { + return (ushort)(value ^ key); + } + + [Obsolete("Please use new FromEncrypted(encrypted, key) API instead.", true)] + public static ObscuredUShort FromEncrypted(ushort encrypted) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public ushort GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(ushort encrypted) {} + + #endregion + + //! @endcond + } +} diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs.meta new file mode 100644 index 0000000..4b6eac0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredUShort.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: c45101ba7cb548746b7a533070d39455 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs new file mode 100644 index 0000000..813cdf1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs @@ -0,0 +1,71 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector2 : IEquatable, IEquatable + { + public static implicit operator ObscuredVector2(Vector2 value) + { + return new ObscuredVector2(value); + } + + public static implicit operator Vector2(ObscuredVector2 value) + { + return value.InternalDecrypt(); + } + + public static implicit operator Vector3(ObscuredVector2 value) + { + var v = value.InternalDecrypt(); + return new Vector3(v.x, v.y, 0.0f); + } + + public override bool Equals(object other) + { + return other is ObscuredVector2 o && Equals(o) || + other is Vector2 r && Equals(r); + } + + public bool Equals(ObscuredVector2 other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(Vector2 other) + { + return InternalDecrypt().Equals(other); + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public void Normalize() + { + var temp = InternalDecrypt(); + temp.Normalize(); + SetEncrypted(Encrypt(normalized, currentCryptoKey), currentCryptoKey); + } + + public Vector2 normalized => InternalDecrypt().normalized; + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs.meta new file mode 100644 index 0000000..58aef21 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 17422e8dbb944e89abbcc6611c5f7e9e +timeCreated: 1679404235 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs new file mode 100644 index 0000000..01df3d3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector2 + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return Compare(fakeValue, InternalDecrypt()); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs.meta new file mode 100644 index 0000000..55a866c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d83987ab0d524a19aca947859fe514f2 +timeCreated: 1667758003 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs new file mode 100644 index 0000000..28557be --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs @@ -0,0 +1,48 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector2 + { + /// + /// Used to store encrypted Vector2. + /// + [Serializable] + public struct RawEncryptedVector2 : IEquatable + { + /// + /// Encrypted value + /// + public int x; + + /// + /// Encrypted value + /// + public int y; + + public bool Equals(RawEncryptedVector2 other) + { + return x == other.x && y == other.y; + } + + public override bool Equals(object obj) + { + return obj is RawEncryptedVector2 other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + return (x * 397) ^ y; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs.meta new file mode 100644 index 0000000..b0879e1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.Raw.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 63cd55426ab0482da5c170cc6b7d9574 +timeCreated: 1679417260 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs new file mode 100644 index 0000000..63c42f4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs @@ -0,0 +1,376 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular Vector2 for any cheating-sensitive variables. + /// + /// \htmlonlyWARNING:\endhtmlonly Doesn't mimic regular type API, thus should be used with extra caution. Cast it to regular, not obscured type to work with regular APIs.
+ /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredVector2 : IObscuredType + { + private static readonly Vector2 Zero = Vector2.zero; + +#if UNITY_EDITOR + public string migratedVersion; +#endif + + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal RawEncryptedVector2 hiddenValue; + [SerializeField] internal Vector2 fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredVector2(Vector2 value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; + migratedVersion = null; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : Zero; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Mimics constructor of regular Vector2. + /// + /// X component of the vector + /// Y component of the vector + public ObscuredVector2(float x, float y) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(x, y, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue = new Vector2(x, y); + fakeValueActive = true; + } + else + { + fakeValue = Zero; + fakeValueActive = false; + } + +#if UNITY_EDITOR + migratedVersion = null; +#endif + inited = true; + } + + public float x + { + get + { + var decrypted = ObscuredFloat.Decrypt(hiddenValue.x, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue.x)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector2)}\n" + + $"decrypted.x: {decrypted}\n" + + $"fakeValue.x: {fakeValue.x}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector2Epsilon}" + + $"compare: {Compare(decrypted, fakeValue.x)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.x = ObscuredFloat.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = value; + fakeValue.y = ObscuredFloat.Decrypt(hiddenValue.y, currentCryptoKey); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public float y + { + get + { + var decrypted = ObscuredFloat.Decrypt(hiddenValue.y, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue.y)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector2)}\n" + + $"decrypted.y: {decrypted}\n" + + $"fakeValue.y: {fakeValue.y}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector2Epsilon}" + + $"compare: {Compare(decrypted, fakeValue.y)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.y = ObscuredFloat.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = ObscuredFloat.Decrypt(hiddenValue.x, currentCryptoKey); + fakeValue.y = value; + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + throw new IndexOutOfRangeException($"Invalid {nameof(ObscuredVector2)} index!"); + } + } + set + { + switch (index) + { + case 0: + x = value; + break; + case 1: + y = value; + break; + default: + throw new IndexOutOfRangeException($"Invalid {nameof(ObscuredVector2)} index!"); + } + } + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector2 Encrypt(Vector2 value, int key) + { + return Encrypt(value.x, value.y, key); + } + + /// + /// Encrypts passed components using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector2 Encrypt(float x, float y, int key) + { + RawEncryptedVector2 result; + result.x = ObscuredFloat.Encrypt(x, key); + result.y = ObscuredFloat.Encrypt(y, key); + + return result; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static Vector2 Decrypt(RawEncryptedVector2 value, int key) + { + Vector2 result; + result.x = ObscuredFloat.Decrypt(value.x, key); + result.y = ObscuredFloat.Decrypt(value.y, key); + + return result; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredVector2 FromEncrypted(RawEncryptedVector2 encrypted, int key) + { + var instance = new ObscuredVector2(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + private static bool Compare(Vector2 v1, Vector2 v2) + { + return Compare(v1.x, v2.x) && + Compare(v1.y, v2.y); + } + + private static bool Compare(float f1, float f2) + { + var epsilon = ObscuredCheatingDetector.ExistsAndIsRunning ? + ObscuredCheatingDetector.Instance.vector2Epsilon : float.Epsilon; + return NumUtils.CompareFloats(f1, f2, epsilon); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public RawEncryptedVector2 GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(RawEncryptedVector2 encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public Vector2 GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private Vector2 InternalDecrypt() + { + if (!inited) + { + Init(); + return Zero; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector2)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector2Epsilon}" + + $"compare: {Compare(decrypted, fakeValue)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(Zero, currentCryptoKey); + fakeValue = Zero; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static RawEncryptedVector2 Encrypt(Vector2 value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static Vector2 Decrypt(RawEncryptedVector2 value) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public RawEncryptedVector2 GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(RawEncryptedVector2 encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs.meta new file mode 100644 index 0000000..de1bd86 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: b2747e161005ff74f91cf08fc1184a62 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs new file mode 100644 index 0000000..40f9b38 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs @@ -0,0 +1,56 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector2Int : IEquatable, IEquatable + { + public static implicit operator ObscuredVector2Int(Vector2Int value) + { + return new ObscuredVector2Int(value); + } + + public static implicit operator Vector2Int(ObscuredVector2Int value) + { + return value.InternalDecrypt(); + } + + public static implicit operator Vector2(ObscuredVector2Int value) + { + return value.InternalDecrypt(); + } + + public override bool Equals(object other) + { + return other is ObscuredVector2Int o && Equals(o) || + other is Vector2Int r && Equals(r); + } + + public bool Equals(ObscuredVector2Int other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(Vector2Int other) + { + return InternalDecrypt().Equals(other); + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs.meta new file mode 100644 index 0000000..2161dd1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5ebd36de4e03418596a257ef9bc779ef +timeCreated: 1679404258 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs new file mode 100644 index 0000000..72c3282 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector2Int + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs.meta new file mode 100644 index 0000000..d518cc1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0fdcf5cd346e40e78a452f5bbe0eb95b +timeCreated: 1667758261 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs new file mode 100644 index 0000000..2736cd9 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs @@ -0,0 +1,48 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector2Int + { + /// + /// Used to store encrypted Vector2. + /// + [Serializable] + public struct RawEncryptedVector2Int : IEquatable + { + /// + /// Encrypted value + /// + public int x; + + /// + /// Encrypted value + /// + public int y; + + public bool Equals(RawEncryptedVector2Int other) + { + return x == other.x && y == other.y; + } + + public override bool Equals(object obj) + { + return obj is RawEncryptedVector2Int other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + return (x * 397) ^ y; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs.meta new file mode 100644 index 0000000..f3bd12a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.Raw.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 62fa01c2fbd44ada8f0c54ed89914fc7 +timeCreated: 1679417218 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs new file mode 100644 index 0000000..0054f89 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs @@ -0,0 +1,351 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular Vector2Int for any cheating-sensitive variables. + /// + /// \htmlonlyWARNING:\endhtmlonly Doesn't mimic regular type API, thus should be used with extra caution. Cast it to regular, not obscured type to work with regular APIs.
+ /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredVector2Int : IObscuredType + { + private static readonly Vector2Int Zero = Vector2Int.zero; + + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal RawEncryptedVector2Int hiddenValue; + [SerializeField] internal Vector2Int fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredVector2Int(Vector2Int value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : Zero; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Mimics constructor of regular Vector2Int. + /// + /// X component of the vector + /// Y component of the vector + public ObscuredVector2Int(int x, int y) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(x, y, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue = new Vector2Int(x, y); + fakeValueActive = true; + } + else + { + fakeValue = Zero; + fakeValueActive = false; + } + + inited = true; + } + + public int x + { + get + { + var decrypted = ObscuredInt.Decrypt(hiddenValue.x, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue.x) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector2Int)}\n" + + $"decrypted.x: {decrypted}\n" + + $"fakeValue.x: {fakeValue.x}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.x = ObscuredInt.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = value; + fakeValue.y = ObscuredInt.Decrypt(hiddenValue.y, currentCryptoKey); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public int y + { + get + { + var decrypted = ObscuredInt.Decrypt(hiddenValue.y, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue.y) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector2Int)}\n" + + $"decrypted.y: {decrypted}\n" + + $"fakeValue.y: {fakeValue.y}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.y = ObscuredInt.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = ObscuredInt.Decrypt(hiddenValue.x, currentCryptoKey); + fakeValue.y = value; + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public int this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + throw new IndexOutOfRangeException($"Invalid {nameof(ObscuredVector2Int)} index!"); + } + } + set + { + switch (index) + { + case 0: + x = value; + break; + case 1: + y = value; + break; + default: + throw new IndexOutOfRangeException($"Invalid {nameof(ObscuredVector2Int)} index!"); + } + } + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector2Int Encrypt(Vector2Int value, int key) + { + return Encrypt(value.x, value.y, key); + } + + /// + /// Encrypts passed components using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector2Int Encrypt(int x, int y, int key) + { + RawEncryptedVector2Int result; + result.x = ObscuredInt.Encrypt(x, key); + result.y = ObscuredInt.Encrypt(y, key); + + return result; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static Vector2Int Decrypt(RawEncryptedVector2Int value, int key) + { + var result = new Vector2Int + { + x = ObscuredInt.Decrypt(value.x, key), + y = ObscuredInt.Decrypt(value.y, key) + }; + + return result; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredVector2Int FromEncrypted(RawEncryptedVector2Int encrypted, int key) + { + var instance = new ObscuredVector2Int(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public RawEncryptedVector2Int GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(RawEncryptedVector2Int encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public Vector2Int GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private Vector2Int InternalDecrypt() + { + if (!inited) + { + Init(); + return Zero; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector2Int)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(Zero, currentCryptoKey); + fakeValue = Zero; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static RawEncryptedVector2Int Encrypt(Vector2Int value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static Vector2Int Decrypt(RawEncryptedVector2Int value) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public RawEncryptedVector2Int GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(RawEncryptedVector2Int encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs.meta new file mode 100644 index 0000000..edc2b69 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector2Int.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 7d311f3fb76e0264daaa7162eab7563f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs new file mode 100644 index 0000000..610c978 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs @@ -0,0 +1,145 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector3 : IEquatable, IEquatable + { + public static implicit operator ObscuredVector3(Vector3 value) + { + return new ObscuredVector3(value); + } + + public static implicit operator Vector3(ObscuredVector3 value) + { + return value.InternalDecrypt(); + } + + public static ObscuredVector3 operator +(ObscuredVector3 a, ObscuredVector3 b) + { + return a.InternalDecrypt() + b.InternalDecrypt(); + } + + public static ObscuredVector3 operator +(Vector3 a, ObscuredVector3 b) + { + return a + b.InternalDecrypt(); + } + + public static ObscuredVector3 operator +(ObscuredVector3 a, Vector3 b) + { + return a.InternalDecrypt() + b; + } + + public static ObscuredVector3 operator -(ObscuredVector3 a, ObscuredVector3 b) + { + return a.InternalDecrypt() - b.InternalDecrypt(); + } + + public static ObscuredVector3 operator -(Vector3 a, ObscuredVector3 b) + { + return a - b.InternalDecrypt(); + } + + public static ObscuredVector3 operator -(ObscuredVector3 a, Vector3 b) + { + return a.InternalDecrypt() - b; + } + + public static ObscuredVector3 operator -(ObscuredVector3 a) + { + return -a.InternalDecrypt(); + } + + public static ObscuredVector3 operator *(ObscuredVector3 a, float d) + { + return a.InternalDecrypt() * d; + } + + public static ObscuredVector3 operator *(float d, ObscuredVector3 a) + { + return d * a.InternalDecrypt(); + } + + public static ObscuredVector3 operator /(ObscuredVector3 a, float d) + { + return a.InternalDecrypt() / d; + } + + public static bool operator ==(ObscuredVector3 lhs, ObscuredVector3 rhs) + { + return lhs.InternalDecrypt() == rhs.InternalDecrypt(); + } + + public static bool operator ==(Vector3 lhs, ObscuredVector3 rhs) + { + return lhs == rhs.InternalDecrypt(); + } + + public static bool operator ==(ObscuredVector3 lhs, Vector3 rhs) + { + return lhs.InternalDecrypt() == rhs; + } + + public static bool operator !=(ObscuredVector3 lhs, ObscuredVector3 rhs) + { + return lhs.InternalDecrypt() != rhs.InternalDecrypt(); + } + + public static bool operator !=(Vector3 lhs, ObscuredVector3 rhs) + { + return lhs != rhs.InternalDecrypt(); + } + + public static bool operator !=(ObscuredVector3 lhs, Vector3 rhs) + { + return lhs.InternalDecrypt() != rhs; + } + + public override bool Equals(object other) + { + return other is ObscuredVector3 o && Equals(o) || + other is Vector3 r && Equals(r); + } + + public bool Equals(ObscuredVector3 other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(Vector3 other) + { + return InternalDecrypt().Equals(other); + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + + public void Normalize() + { + var temp = InternalDecrypt(); + temp.Normalize(); + SetEncrypted(Encrypt(normalized, currentCryptoKey), currentCryptoKey); + } + + public Vector3 normalized => InternalDecrypt().normalized; + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs.meta new file mode 100644 index 0000000..90d401d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c2ada4c9123744958b5b7d2575eb5716 +timeCreated: 1679404280 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs new file mode 100644 index 0000000..9a1f627 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector3 + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return Compare(fakeValue, InternalDecrypt()); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs.meta new file mode 100644 index 0000000..b825fe5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 986cba1b8fe54661b153c0ad08e0f095 +timeCreated: 1667758318 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs new file mode 100644 index 0000000..e28ffb4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs @@ -0,0 +1,54 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector3 + { + /// + /// Used to store encrypted Vector3. + /// + [Serializable] + public struct RawEncryptedVector3 : IEquatable + { + /// + /// Encrypted value + /// + public int x; + /// + /// Encrypted value + /// + public int y; + /// + /// Encrypted value + /// + public int z; + + public bool Equals(RawEncryptedVector3 other) + { + return x == other.x && y == other.y && z == other.z; + } + + public override bool Equals(object obj) + { + return obj is RawEncryptedVector3 other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = x; + hashCode = (hashCode * 397) ^ y; + hashCode = (hashCode * 397) ^ z; + return hashCode; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs.meta new file mode 100644 index 0000000..620b06e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.Raw.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3614e359670b47d29e5ce31cec6f1153 +timeCreated: 1679417072 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs new file mode 100644 index 0000000..c991d00 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs @@ -0,0 +1,424 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular Vector3 for any cheating-sensitive variables. + /// + /// \htmlonlyWARNING:\endhtmlonly Doesn't mimic regular type API, thus should be used with extra caution. Cast it to regular, not obscured type to work with regular APIs.
+ /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredVector3 : IObscuredType + { + private static readonly Vector3 Zero = Vector3.zero; + +#if UNITY_EDITOR + public string migratedVersion; +#endif + + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal RawEncryptedVector3 hiddenValue; + [SerializeField] internal Vector3 fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredVector3(Vector3 value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; + migratedVersion = null; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : Zero; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Mimics constructor of regular Vector3. + /// + /// X component of the vector + /// Y component of the vector + /// Z component of the vector + public ObscuredVector3(float x, float y, float z) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(x,y,z, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue = new Vector3(x, y, z); + fakeValueActive = true; + } + else + { + fakeValue = Zero; + fakeValueActive = false; + } + +#if UNITY_EDITOR + migratedVersion = null; +#endif + inited = true; + } + + public float x + { + get + { + var decrypted = ObscuredFloat.Decrypt(hiddenValue.x, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue.x)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3)}\n" + + $"decrypted.y: {decrypted}\n" + + $"fakeValue.y: {fakeValue.y}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector3Epsilon}" + + $"compare: {Compare(decrypted, fakeValue.y)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.x = ObscuredFloat.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = value; + fakeValue.y = ObscuredFloat.Decrypt(hiddenValue.y, currentCryptoKey); + fakeValue.z = ObscuredFloat.Decrypt(hiddenValue.z, currentCryptoKey); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public float y + { + get + { + var decrypted = ObscuredFloat.Decrypt(hiddenValue.y, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue.y)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3)}\n" + + $"decrypted.y: {decrypted}\n" + + $"fakeValue.y: {fakeValue.y}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector3Epsilon}" + + $"compare: {Compare(decrypted, fakeValue.y)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.y = ObscuredFloat.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = ObscuredFloat.Decrypt(hiddenValue.x, currentCryptoKey); + fakeValue.y = value; + fakeValue.z = ObscuredFloat.Decrypt(hiddenValue.z, currentCryptoKey); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public float z + { + get + { + var decrypted = ObscuredFloat.Decrypt(hiddenValue.z, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue.z)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3)}\n" + + $"decrypted.z: {decrypted}\n" + + $"fakeValue.z: {fakeValue.z}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector3Epsilon}" + + $"compare: {Compare(decrypted, fakeValue.z)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.z = ObscuredFloat.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = ObscuredFloat.Decrypt(hiddenValue.x, currentCryptoKey); + fakeValue.y = ObscuredFloat.Decrypt(hiddenValue.y, currentCryptoKey); + fakeValue.z = value; + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public float this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + throw new IndexOutOfRangeException($"Invalid {nameof(ObscuredVector3)} index!"); + } + } + set + { + switch (index) + { + case 0: + x = value; + break; + case 1: + y = value; + break; + case 2: + z = value; + break; + default: + throw new IndexOutOfRangeException($"Invalid {nameof(ObscuredVector3)} index!"); + } + } + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector3 Encrypt(Vector3 value, int key) + { + return Encrypt(value.x, value.y, value.z, key); + } + + /// + /// Encrypts passed components using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector3 Encrypt(float x, float y, float z, int key) + { + RawEncryptedVector3 result; + result.x = ObscuredFloat.Encrypt(x, key); + result.y = ObscuredFloat.Encrypt(y, key); + result.z = ObscuredFloat.Encrypt(z, key); + + return result; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static Vector3 Decrypt(RawEncryptedVector3 value, int key) + { + Vector3 result; + result.x = ObscuredFloat.Decrypt(value.x, key); + result.y = ObscuredFloat.Decrypt(value.y, key); + result.z = ObscuredFloat.Decrypt(value.z, key); + + return result; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredVector3 FromEncrypted(RawEncryptedVector3 encrypted, int key) + { + var instance = new ObscuredVector3(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + private static bool Compare(Vector3 v1, Vector3 v2) + { + return Compare(v1.x, v2.x) && + Compare(v1.y, v2.y) && + Compare(v1.z, v2.z); + } + + private static bool Compare(float f1, float f2) + { + var epsilon = ObscuredCheatingDetector.ExistsAndIsRunning ? + ObscuredCheatingDetector.Instance.vector3Epsilon : float.Epsilon; + return NumUtils.CompareFloats(f1, f2, epsilon); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public RawEncryptedVector3 GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(RawEncryptedVector3 encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public Vector3 GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private Vector3 InternalDecrypt() + { + if (!inited) + { + Init(); + return Zero; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && !Compare(decrypted, fakeValue)) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}\n" + + $"epsilon: {ObscuredCheatingDetector.Instance.vector3Epsilon}" + + $"compare: {Compare(decrypted, fakeValue)}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(Zero, currentCryptoKey); + fakeValue = Zero; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static RawEncryptedVector3 Encrypt(Vector3 value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static Vector3 Decrypt(RawEncryptedVector3 value) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public RawEncryptedVector3 GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(RawEncryptedVector3 encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs.meta new file mode 100644 index 0000000..75ba7f6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ee22c33f589a744438fb51f130130827 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs new file mode 100644 index 0000000..b2d4f92 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs @@ -0,0 +1,126 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using UnityEngine; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector3Int : IEquatable, IEquatable + { + public static implicit operator ObscuredVector3Int(Vector3Int value) + { + return new ObscuredVector3Int(value); + } + + public static implicit operator Vector3Int(ObscuredVector3Int value) + { + return value.InternalDecrypt(); + } + + public static implicit operator Vector3(ObscuredVector3Int value) + { + return value.InternalDecrypt(); + } + + public static ObscuredVector3Int operator +(ObscuredVector3Int a, ObscuredVector3Int b) + { + return a.InternalDecrypt() + b.InternalDecrypt(); + } + + public static ObscuredVector3Int operator +(Vector3Int a, ObscuredVector3Int b) + { + return a + b.InternalDecrypt(); + } + + public static ObscuredVector3Int operator +(ObscuredVector3Int a, Vector3Int b) + { + return a.InternalDecrypt() + b; + } + + public static ObscuredVector3Int operator -(ObscuredVector3Int a, ObscuredVector3Int b) + { + return a.InternalDecrypt() - b.InternalDecrypt(); + } + + public static ObscuredVector3Int operator -(Vector3Int a, ObscuredVector3Int b) + { + return a - b.InternalDecrypt(); + } + + public static ObscuredVector3Int operator -(ObscuredVector3Int a, Vector3Int b) + { + return a.InternalDecrypt() - b; + } + + public static ObscuredVector3Int operator *(ObscuredVector3Int a, int d) + { + return a.InternalDecrypt() * d; + } + + public static bool operator ==(ObscuredVector3Int lhs, ObscuredVector3Int rhs) + { + return lhs.InternalDecrypt() == rhs.InternalDecrypt(); + } + + public static bool operator ==(Vector3Int lhs, ObscuredVector3Int rhs) + { + return lhs == rhs.InternalDecrypt(); + } + + public static bool operator ==(ObscuredVector3Int lhs, Vector3Int rhs) + { + return lhs.InternalDecrypt() == rhs; + } + + public static bool operator !=(ObscuredVector3Int lhs, ObscuredVector3Int rhs) + { + return lhs.InternalDecrypt() != rhs.InternalDecrypt(); + } + + public static bool operator !=(Vector3Int lhs, ObscuredVector3Int rhs) + { + return lhs != rhs.InternalDecrypt(); + } + + public static bool operator !=(ObscuredVector3Int lhs, Vector3Int rhs) + { + return lhs.InternalDecrypt() != rhs; + } + + public override bool Equals(object other) + { + return other is ObscuredVector3Int o && Equals(o) || + other is Vector3Int r && Equals(r); + } + + public bool Equals(ObscuredVector3Int other) + { + return currentCryptoKey == other.currentCryptoKey ? hiddenValue.Equals(other.hiddenValue) : + InternalDecrypt().Equals(other.InternalDecrypt()); + } + + public bool Equals(Vector3Int other) + { + return InternalDecrypt().Equals(other); + } + + public override int GetHashCode() + { + return InternalDecrypt().GetHashCode(); + } + + public override string ToString() + { + return InternalDecrypt().ToString(); + } + + public string ToString(string format) + { + return InternalDecrypt().ToString(format); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs.meta new file mode 100644 index 0000000..ac408b1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.API.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f398f8b21561437c9b36c3dc8770729b +timeCreated: 1679404297 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs new file mode 100644 index 0000000..00ea593 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs @@ -0,0 +1,22 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_EDITOR +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector3Int + { + internal bool IsDataValid + { + get + { + if (!inited || !fakeValueActive) return true; + return fakeValue == InternalDecrypt(); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs.meta new file mode 100644 index 0000000..bcdc005 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Editor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b852214be1af49ca91066b605d494bc7 +timeCreated: 1667758305 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs new file mode 100644 index 0000000..c0e7334 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs @@ -0,0 +1,56 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + public partial struct ObscuredVector3Int + { + /// + /// Used to store encrypted Vector3Int. + /// + [Serializable] + public struct RawEncryptedVector3Int : IEquatable + { + /// + /// Encrypted value + /// + public int x; + + /// + /// Encrypted value + /// + public int y; + + /// + /// Encrypted value + /// + public int z; + + public bool Equals(RawEncryptedVector3Int other) + { + return x == other.x && y == other.y && z == other.z; + } + + public override bool Equals(object obj) + { + return obj is RawEncryptedVector3Int other && Equals(other); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = x; + hashCode = (hashCode * 397) ^ y; + hashCode = (hashCode * 397) ^ z; + return hashCode; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs.meta new file mode 100644 index 0000000..e46f752 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.Raw.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f2c722b1d3654eaca9326f80983c511f +timeCreated: 1679416889 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs new file mode 100644 index 0000000..398392a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs @@ -0,0 +1,401 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.ObscuredTypes +{ + using System; + using UnityEngine; + using Utils; + using Detectors; + + /// + /// Use it instead of regular Vector3Int for any cheating-sensitive variables. + /// + /// \htmlonlyWARNING:\endhtmlonly Doesn't mimic regular type API, thus should be used with extra caution. Cast it to regular, not obscured type to work with regular APIs.
+ /// Regular type is faster and memory wiser comparing to the obscured one!
+ /// Feel free to use regular types for all short-term operations and calculations while keeping obscured type only at the long-term declaration (i.e. class field). + [Serializable] + public partial struct ObscuredVector3Int : IObscuredType + { + private static readonly Vector3Int Zero = Vector3Int.zero; + + [SerializeField] internal int currentCryptoKey; + [SerializeField] internal RawEncryptedVector3Int hiddenValue; + [SerializeField] internal Vector3Int fakeValue; + [SerializeField] internal bool fakeValueActive; + [SerializeField] internal bool inited; + + private ObscuredVector3Int(Vector3Int value) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(value, currentCryptoKey); + +#if UNITY_EDITOR + fakeValue = value; + fakeValueActive = true; +#else + var detectorRunning = ObscuredCheatingDetector.ExistsAndIsRunning; + fakeValue = detectorRunning ? value : Zero; + fakeValueActive = detectorRunning; +#endif + inited = true; + } + + /// + /// Mimics constructor of regular Vector3Int. + /// + /// X component of the vector + /// Y component of the vector + /// Z component of the vector + public ObscuredVector3Int(int x, int y, int z) + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(x, y, z, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue = new Vector3Int + { + x = x, + y = y, + z = z + }; + fakeValueActive = true; + } + else + { + fakeValue = Zero; + fakeValueActive = false; + } + + inited = true; + } + + public int x + { + get + { + var decrypted = ObscuredInt.Decrypt(hiddenValue.x, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue.x) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3Int)}\n" + + $"decrypted.x: {decrypted}\n" + + $"fakeValue.x: {fakeValue.x}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.x = ObscuredInt.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = value; + fakeValue.y = ObscuredInt.Decrypt(hiddenValue.y, currentCryptoKey); + fakeValue.z = ObscuredInt.Decrypt(hiddenValue.z, currentCryptoKey); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public int y + { + get + { + var decrypted = ObscuredInt.Decrypt(hiddenValue.y, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue.y) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3Int)}\n" + + $"decrypted.y: {decrypted}\n" + + $"fakeValue.y: {fakeValue.y}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.y = ObscuredInt.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = ObscuredInt.Decrypt(hiddenValue.x, currentCryptoKey); + fakeValue.y = value; + fakeValue.z = ObscuredInt.Decrypt(hiddenValue.z, currentCryptoKey); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public int z + { + get + { + var decrypted = ObscuredInt.Decrypt(hiddenValue.z, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue.z) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3Int)}\n" + + $"decrypted.z: {decrypted}\n" + + $"fakeValue.z: {fakeValue.z}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + return decrypted; + } + + set + { + hiddenValue.z = ObscuredInt.Encrypt(value, currentCryptoKey); + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValue.x = ObscuredInt.Decrypt(hiddenValue.x, currentCryptoKey); + fakeValue.y = ObscuredInt.Decrypt(hiddenValue.y, currentCryptoKey); + fakeValue.z = value; + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + } + + public int this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + throw new IndexOutOfRangeException("Invalid ObscuredVector3Int index!"); + } + } + set + { + switch (index) + { + case 0: + x = value; + break; + case 1: + y = value; + break; + case 2: + z = value; + break; + default: + throw new IndexOutOfRangeException("Invalid ObscuredVector3Int index!"); + } + } + } + + /// + /// Encrypts passed value using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector3Int Encrypt(Vector3Int value, int key) + { + return Encrypt(value.x, value.y, value.z, key); + } + + /// + /// Encrypts passed components using passed key. + /// + /// Key can be generated automatically using GenerateKey(). + /// \sa Decrypt(), GenerateKey() + public static RawEncryptedVector3Int Encrypt(int x, int y, int z, int key) + { + RawEncryptedVector3Int result; + result.x = ObscuredInt.Encrypt(x, key); + result.y = ObscuredInt.Encrypt(y, key); + result.z = ObscuredInt.Encrypt(z, key); + + return result; + } + + /// + /// Decrypts passed value you got from Encrypt() using same key. + /// + /// \sa Encrypt() + public static Vector3Int Decrypt(RawEncryptedVector3Int value, int key) + { + var result = new Vector3Int + { + x = ObscuredInt.Decrypt(value.x, key), + y = ObscuredInt.Decrypt(value.y, key), + z = ObscuredInt.Decrypt(value.z, key) + }; + + return result; + } + + /// + /// Creates and fills obscured variable with raw encrypted value previously got from GetEncrypted(). + /// + /// Literally does same job as SetEncrypted() but makes new instance instead of filling existing one, + /// making it easier to initialize new variables from saved encrypted values. + /// + /// Raw encrypted value you got from GetEncrypted(). + /// Encryption key you've got from GetEncrypted(). + /// New obscured variable initialized from specified encrypted value. + /// \sa GetEncrypted(), SetEncrypted() + public static ObscuredVector3Int FromEncrypted(RawEncryptedVector3Int encrypted, int key) + { + var instance = new ObscuredVector3Int(); + instance.SetEncrypted(encrypted, key); + return instance; + } + + /// + /// Generates random key. Used internally and can be used to generate key for manual Encrypt() calls. + /// + /// Key suitable for manual Encrypt() calls. + public static int GenerateKey() + { + return RandomUtils.GenerateIntKey(); + } + + /// + /// Allows to pick current obscured value as is. + /// + /// Encryption key needed to decrypt returned value. + /// Encrypted value as is. + /// Use it in conjunction with SetEncrypted().
+ /// Useful for saving data in obscured state. + /// \sa FromEncrypted(), SetEncrypted() + public RawEncryptedVector3Int GetEncrypted(out int key) + { + if (!inited) + Init(); + + key = currentCryptoKey; + return hiddenValue; + } + + /// + /// Allows to explicitly set current obscured value. Crypto key should be same as when encrypted value was got with GetEncrypted(). + /// + /// Use it in conjunction with GetEncrypted().
+ /// Useful for loading data stored in obscured state. + /// \sa FromEncrypted() + public void SetEncrypted(RawEncryptedVector3Int encrypted, int key) + { + inited = true; + hiddenValue = encrypted; + currentCryptoKey = key; + + if (ObscuredCheatingDetector.ExistsAndIsRunning) + { + fakeValueActive = false; + fakeValue = InternalDecrypt(); + fakeValueActive = true; + } + else + { + fakeValueActive = false; + } + } + + /// + /// Alternative to the type cast, use if you wish to get decrypted value + /// but can't or don't want to use cast to the regular type. + /// + /// Decrypted value. + public Vector3Int GetDecrypted() + { + return InternalDecrypt(); + } + + public void RandomizeCryptoKey() + { + var decrypted = InternalDecrypt(); + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(decrypted, currentCryptoKey); + } + + private Vector3Int InternalDecrypt() + { + if (!inited) + { + Init(); + return Zero; + } + + var decrypted = Decrypt(hiddenValue, currentCryptoKey); + + if (ObscuredCheatingDetector.ExistsAndIsRunning && fakeValueActive && decrypted != fakeValue) + { +#if ACTK_DETECTION_BACKLOGS + Debug.LogWarning(ObscuredCheatingDetector.LogPrefix + "Detection backlog:\n" + + $"type: {nameof(ObscuredVector3Int)}\n" + + $"decrypted: {decrypted}\n" + + $"fakeValue: {fakeValue}"); +#endif + ObscuredCheatingDetector.Instance.OnCheatingDetected(this, decrypted, fakeValue); + } + + return decrypted; + } + + private void Init() + { + currentCryptoKey = GenerateKey(); + hiddenValue = Encrypt(Zero, currentCryptoKey); + fakeValue = Zero; + fakeValueActive = false; + inited = true; + } + + //! @cond + + #region obsolete + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public static void SetNewCryptoKey(int newKey) {} + + [Obsolete("This API is redundant and does not perform any actions. It will be removed in future updates.")] + public void ApplyNewCryptoKey() {} + + [Obsolete("Please use new Encrypt(value, key) API instead.", true)] + public static RawEncryptedVector3Int Encrypt(Vector3Int value) { throw new Exception(); } + + [Obsolete("Please use new Decrypt(value, key) API instead.", true)] + public static Vector3Int Decrypt(RawEncryptedVector3Int value) { throw new Exception(); } + + [Obsolete("Please use new GetEncrypted(out key) API instead.", true)] + public RawEncryptedVector3Int GetEncrypted() { throw new Exception(); } + + [Obsolete("Please use new SetEncrypted(encrypted, key) API instead.", true)] + public void SetEncrypted(RawEncryptedVector3Int encrypted) {} + + #endregion + + //! @endcond + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs.meta new file mode 100644 index 0000000..a37f8b4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/ObscuredTypes/ObscuredVector3Int.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 810949a528762374e94ad0834411b4af +timeCreated: 1508447606 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage.meta new file mode 100644 index 0000000..90864eb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 53c58f29a336490ebb583a482b606a98 +timeCreated: 1556983137 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data.meta new file mode 100644 index 0000000..6ec9d56 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5c14e3b6c1f7467b839ce0462687948b +timeCreated: 1622839242 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums.meta new file mode 100644 index 0000000..a3af63c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 97a37e2b444044c0af8884070c16fbe4 +timeCreated: 1623438923 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs new file mode 100644 index 0000000..f0527aa --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs @@ -0,0 +1,110 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + /// + /// Data types supported by ObscuredPrefs and ObscuredFilePrefs. + /// + public enum StorageDataType : byte + { + /// Reserved for unsupported types. + Unknown = 0, + + ///
System.SByte + SByte = 1, + + /// System.Byte + Byte = 2, + + /// System.Int16 + Int16 = 3, + + /// System.UInt16 + UInt16 = 4, + + /// System.Int32 + Int32 = 5, + + /// System.UInt32 + UInt32 = 10, + + /// System.Int64 + Int64 = 30, + + /// System.UInt64 + UInt64 = 32, + + /// System.Char + Char = 33, + + /// System.Single + Single = 20, + + /// System.Double + Double = 25, + + /// System.Decimal + Decimal = 27, + + /// System.BigInteger + BigInteger = 28, + + /// System.Boolean + Boolean = 35, + + /// System.String + String = 15, + + /// System.DateTime + DateTime = 37, + + /// Array of System.Byte + ByteArray = 40, + + /// UnityEngine.Vector2 + Vector2 = 45, + + /// UnityEngine.Vector2Int + Vector2Int = 47, + + /// UnityEngine.Vector3 + Vector3 = 50, + + /// UnityEngine.Vector3Int + Vector3Int = 51, + + /// UnityEngine.Vector4 + Vector4 = 53, + + /// UnityEngine.Quaternion + Quaternion = 55, + + /// UnityEngine.Color + Color = 60, + + /// UnityEngine.Color32 + Color32 = 62, + + /// UnityEngine.Rect + Rect = 65, + + /// UnityEngine.RectInt + RectInt = 67, + + /// UnityEngine.RangeInt + RangeInt = 70, + + /// UnityEngine.Matrix4x4 + Matrix4x4 = 78, + + /// UnityEngine.Ray + Ray = 80, + + /// UnityEngine.Ray2D + Ray2D = 83, + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs.meta new file mode 100644 index 0000000..0c5e134 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/Enums/StorageDataType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d8300df491e14951a99a01d75a2fd1a7 +timeCreated: 1622838527 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs new file mode 100644 index 0000000..e7eb583 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs @@ -0,0 +1,23 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + + [Serializable] + internal struct ObscuredPrefsData + { + public StorageDataType type; + public byte[] data; + + public ObscuredPrefsData(StorageDataType type, byte[] data) + { + this.type = type; + this.data = data; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs.meta new file mode 100644 index 0000000..315885f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/ObscuredPrefsData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa830384d38440d692d9bae231e91611 +timeCreated: 1622289230 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs new file mode 100644 index 0000000..5a027df --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs @@ -0,0 +1,251 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using Common; + using UnityEngine; + using Utils; + + internal static class StorageDataConverter + { + public static Color32 BytesToColor32Legacy(byte[] data) + { + var encodedColor = BitConverter.ToUInt32(data, 0);; + var a = (byte)(encodedColor >> 24); + var r = (byte)(encodedColor >> 16); + var g = (byte)(encodedColor >> 8); + var b = (byte)(encodedColor >> 0); + return new Color32(r, g, b, a); + } + + public static ObscuredPrefsData GetPrefsDataFromValue(T value) + { + var storageType = StorageDataTypeClassifier.GetStorageDataType(); + var data = GetBytesFromValue(storageType, value); + return new ObscuredPrefsData(storageType, data); + } + + public static T GetValueFromPrefsData(ObscuredPrefsData prefsData) + { + return GetValueFromData(prefsData.type, prefsData.data); + } + + public static T GetValueFromData(byte[] data) + { + var type = StorageDataTypeClassifier.GetStorageDataType(); + return GetValueFromData(type, data); + } + + public static T GetValueFromData(StorageDataType type, byte[] data) + { + if (data == null || (data.Length == 0 && type != StorageDataType.String)) + { + ACTk.PrintExceptionForSupport($"Source data for value of type {typeof(T)} is empty!" + + "Can't convert it to the desired type, data will be lost."); + return default; + } + + try + { + return GetValueFromBytes(type, data); + } + catch (ArgumentOutOfRangeException e) + { + if (e.Message.StartsWith("Unknown")) + { + ACTk.PrintExceptionForSupport( + $"Something went wrong while converting bytes to specific type {typeof(T)}", e); + } + else + { + Debug.LogError( + $"{ACTk.LogPrefix}Something went wrong while converting bytes to specific type {typeof(T)}!\n" + + "Please make sure you are getting value with same type you set it previously, " + + $"e.g. load data using {nameof(ObscuredPrefs)}.{nameof(ObscuredPrefs.Get)}() if " + + $"you used {nameof(ObscuredPrefs)}.{nameof(ObscuredPrefs.Set)}() to save it!"); + Debug.LogException(e); + } + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport( + $"Something went wrong while converting bytes to specific type {typeof(T)}", e); + } + + return default; + } + + private static byte[] GetBytesFromValue(StorageDataType type, T value) + { + switch (type) + { + case StorageDataType.Unknown: + throw new UnsupportedDataTypeException(typeof(T)); + case StorageDataType.SByte: + return ConvertToBytes((sbyte)(object)value); + case StorageDataType.Byte: + return ConvertToBytes((byte)(object)value); + case StorageDataType.Int16: + return BitConverter.GetBytes((short)(object)value); + case StorageDataType.UInt16: + return BitConverter.GetBytes((ushort)(object)value); + case StorageDataType.Int32: + return BitConverter.GetBytes((int)(object)value); + case StorageDataType.UInt32: + return BitConverter.GetBytes((uint)(object)value); + case StorageDataType.Int64: + return BitConverter.GetBytes((long)(object)value); + case StorageDataType.UInt64: + return BitConverter.GetBytes((ulong)(object)value); + case StorageDataType.Char: + return BitConverter.GetBytes((char)(object)value); + case StorageDataType.Single: + return BitConverter.GetBytes((float)(object)value); + case StorageDataType.Double: + return BitConverter.GetBytes((double)(object)value); + case StorageDataType.Decimal: + return ConvertToBytes((decimal)(object)value); + case StorageDataType.BigInteger: + return ((System.Numerics.BigInteger)(object)value).ToByteArray(); + case StorageDataType.Boolean: + return BitConverter.GetBytes((bool)(object)value); + case StorageDataType.String: + return StringUtils.StringToBytes(value as string); + case StorageDataType.DateTime: + return BitConverter.GetBytes(((DateTime)(object)value).Ticks); + case StorageDataType.ByteArray: + return value as byte[]; + case StorageDataType.Vector2: + return ConvertToBytes((Vector2)(object)value); + case StorageDataType.Vector2Int: + return ConvertToBytes((Vector2Int)(object)value); + case StorageDataType.Vector3: + return ConvertToBytes((Vector3)(object)value); + case StorageDataType.Vector3Int: + return ConvertToBytes((Vector3Int)(object)value); + case StorageDataType.Vector4: + return ConvertToBytes((Vector4)(object)value); + case StorageDataType.Quaternion: + return ConvertToBytes((Quaternion)(object)value); + case StorageDataType.Color: + return ConvertToBytes((Color)(object)value); + case StorageDataType.Color32: + return ConvertToBytes((Color32)(object)value); + case StorageDataType.Rect: + return ConvertToBytes((Rect)(object)value); + case StorageDataType.RectInt: + return ConvertToBytes((RectInt)(object)value); + case StorageDataType.RangeInt: + return ConvertToBytes((RangeInt)(object)value); + case StorageDataType.Matrix4x4: + return ConvertToBytes((Matrix4x4)(object)value); + case StorageDataType.Ray: + return ConvertToBytes((Ray)(object)value); + case StorageDataType.Ray2D: + return ConvertToBytes((Ray2D)(object)value); + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + } + + private static T GetValueFromBytes(StorageDataType type, byte[] data) + { + switch (type) + { + case StorageDataType.Unknown: + throw new UnsupportedDataTypeException(typeof(T)); + case StorageDataType.SByte: + return (T)(object)ConvertToValue(data); + case StorageDataType.Byte: + return (T)(object)ConvertToValue(data); + case StorageDataType.Int16: + return (T)(object)BitConverter.ToInt16(data, 0); + case StorageDataType.UInt16: + return (T)(object)BitConverter.ToUInt16(data, 0); + case StorageDataType.Int32: + return (T)(object)BitConverter.ToInt32(data, 0); + case StorageDataType.UInt32: + return (T)(object)BitConverter.ToUInt32(data, 0); + case StorageDataType.Single: + return (T)(object)BitConverter.ToSingle(data, 0); + case StorageDataType.Double: + return (T)(object)BitConverter.ToDouble(data, 0); + case StorageDataType.Decimal: + return (T)(object)ConvertToValue(data); + case StorageDataType.BigInteger: + return (T)(object)new System.Numerics.BigInteger(data); + case StorageDataType.Int64: + return (T)(object)BitConverter.ToInt64(data, 0); + case StorageDataType.UInt64: + return (T)(object)BitConverter.ToUInt64(data, 0); + case StorageDataType.Char: + return (T)(object)BitConverter.ToChar(data, 0); + case StorageDataType.Boolean: + return (T)(object)BitConverter.ToBoolean(data, 0); + case StorageDataType.String: + return (T)(object)StringUtils.BytesToString(data, 0, data.Length); + case StorageDataType.DateTime: + return (T)(object)new DateTime(BitConverter.ToInt64(data, 0)); + case StorageDataType.ByteArray: + return (T)(object)data; + case StorageDataType.Vector2: + return (T)(object)ConvertToValue(data); + case StorageDataType.Vector2Int: + return (T)(object)ConvertToValue(data); + case StorageDataType.Vector3: + return (T)(object)ConvertToValue(data); + case StorageDataType.Vector3Int: + return (T)(object)ConvertToValue(data); + case StorageDataType.Vector4: + return (T)(object)ConvertToValue(data); + case StorageDataType.Quaternion: + return (T)(object)ConvertToValue(data); + case StorageDataType.Color: + return (T)(object)ConvertToValue(data); + case StorageDataType.Color32: + return (T)(object)ConvertToValue(data); + case StorageDataType.Rect: + return (T)(object)ConvertToValue(data); + case StorageDataType.RectInt: + return (T)(object)ConvertToValue(data); + case StorageDataType.RangeInt: + return (T)(object)ConvertToValue(data); + case StorageDataType.Matrix4x4: + return (T)(object)ConvertToValue(data); + case StorageDataType.Ray: + return (T)(object)ConvertToValue(data); + case StorageDataType.Ray2D: + return (T)(object)ConvertToValue(data); + default: + throw new ArgumentOutOfRangeException(nameof(type), type, $"Unknown {nameof(StorageDataType)} {type}"); + } + } + + private static unsafe byte[] ConvertToBytes(T value) where T : unmanaged + { + var pointer = (byte*)&value; + + var result = new byte[sizeof(T)]; + for (var i = 0; i < sizeof(T); i++) + result[i] = pointer[i]; + + return result; + } + + private static unsafe T ConvertToValue(byte[] data) where T : unmanaged + { + var result = default(T); + var pointer = (byte*)&result; + + for (var i = 0; i < sizeof(T); i++) + pointer[i] = data[i]; + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs.meta new file mode 100644 index 0000000..5b5d6c8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataConverter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a140fcdfc8c4dc0a88df806ce98058b +timeCreated: 1622839258 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs new file mode 100644 index 0000000..3868a1b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs @@ -0,0 +1,86 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using UnityEngine; + + internal static class StorageDataTypeClassifier + { + private static readonly Type SByteType = typeof(sbyte); + private static readonly Type ByteType = typeof(byte); + private static readonly Type ShortType = typeof(short); + private static readonly Type UShortType = typeof(ushort); + private static readonly Type IntType = typeof(int); + private static readonly Type UIntType = typeof(uint); + private static readonly Type LongType = typeof(long); + private static readonly Type ULongType = typeof(ulong); + private static readonly Type CharType = typeof(char); + private static readonly Type StringType = typeof(string); + private static readonly Type FloatType = typeof(float); + private static readonly Type DoubleType = typeof(double); + private static readonly Type DecimalType = typeof(decimal); + private static readonly Type BigInteger = typeof(System.Numerics.BigInteger); + private static readonly Type BoolType = typeof(bool); + private static readonly Type DateTimeType = typeof(DateTime); + private static readonly Type ByteArray = typeof(byte[]); + + private static readonly Type Vector2Type = typeof(Vector2); + private static readonly Type Vector2IntType = typeof(Vector2Int); + private static readonly Type Vector3Type = typeof(Vector3); + private static readonly Type Vector3IntType = typeof(Vector3Int); + private static readonly Type Vector4Type = typeof(Vector4); + private static readonly Type QuaternionType = typeof(Quaternion); + private static readonly Type ColorType = typeof(Color); + private static readonly Type Color32Type = typeof(Color32); + private static readonly Type RectType = typeof(Rect); + private static readonly Type RectIntType = typeof(RectInt); + private static readonly Type RangeIntType = typeof(RangeInt); + private static readonly Type Matrix4x4Type = typeof(Matrix4x4); + private static readonly Type RayType = typeof(Ray); + private static readonly Type Ray2DType = typeof(Ray2D); + + public static StorageDataType GetStorageDataType() + { + var genericType = typeof(T); + if (genericType == SByteType) return StorageDataType.SByte; + if (genericType == ByteType) return StorageDataType.Byte; + if (genericType == ShortType) return StorageDataType.Int16; + if (genericType == UShortType) return StorageDataType.UInt16; + if (genericType == IntType) return StorageDataType.Int32; + if (genericType == UIntType) return StorageDataType.UInt32; + if (genericType == LongType) return StorageDataType.Int64; + if (genericType == ULongType) return StorageDataType.UInt64; + if (genericType == CharType) return StorageDataType.Char; + if (genericType == FloatType) return StorageDataType.Single; + if (genericType == DoubleType) return StorageDataType.Double; + if (genericType == DecimalType) return StorageDataType.Decimal; + if (genericType == BigInteger) return StorageDataType.BigInteger; + if (genericType == BoolType) return StorageDataType.Boolean; + if (genericType == StringType) return StorageDataType.String; + if (genericType == DateTimeType) return StorageDataType.DateTime; + if (genericType == ByteArray) return StorageDataType.ByteArray; + + if (genericType == Vector2Type) return StorageDataType.Vector2; + if (genericType == Vector2IntType) return StorageDataType.Vector2Int; + if (genericType == Vector3Type) return StorageDataType.Vector3; + if (genericType == Vector3IntType) return StorageDataType.Vector3Int; + if (genericType == Vector4Type) return StorageDataType.Vector4; + if (genericType == QuaternionType) return StorageDataType.Quaternion; + if (genericType == ColorType) return StorageDataType.Color; + if (genericType == Color32Type) return StorageDataType.Color32; + if (genericType == RectType) return StorageDataType.Rect; + if (genericType == RectIntType) return StorageDataType.RectInt; + if (genericType == RangeIntType) return StorageDataType.RangeInt; + if (genericType == Matrix4x4Type) return StorageDataType.Matrix4x4; + if (genericType == RayType) return StorageDataType.Ray; + if (genericType == Ray2DType) return StorageDataType.Ray2D; + + return StorageDataType.Unknown; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs.meta new file mode 100644 index 0000000..1c54666 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/StorageDataTypeClassifier.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e9921377b0f747debccebc031f0c55d3 +timeCreated: 1623439028 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs new file mode 100644 index 0000000..ac5bce8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs @@ -0,0 +1,16 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + + internal class UnsupportedDataTypeException : Exception + { + public UnsupportedDataTypeException(Type type):base($"Unsupported data type: {type}!") + { } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs.meta new file mode 100644 index 0000000..2efbdde --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Data/UnsupportedDataTypeException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bb9d8ea9d58e42a083882e4981608519 +timeCreated: 1623416321 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock.meta new file mode 100644 index 0000000..618dbf3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 342c3ac4daf94102a9818315aabce193 +timeCreated: 1622720390 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs new file mode 100644 index 0000000..a4944e1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs @@ -0,0 +1,136 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if !UNITY_WEBGL +#define ACTK_ASYNC +#endif + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using Common; + using UnityEngine; + using Utils; + + /// + /// Used by ObscuredPrefs and ObscuredFile for the device lock feature. + /// + public class DeviceIdHolder + { + internal delegate byte[] HashCheckSumModifierDelegate(string input); + + private static string deviceId; + + /// + /// Allows getting current device ID or setting custom device ID to lock data to the device. + /// + /// \htmlonlyWARNING:\endhtmlonly All data saved with previous device ID will be considered foreign! + public static string DeviceId + { + get + { + if (string.IsNullOrEmpty(deviceId)) + { + deviceId = GetDeviceId(); + } + return deviceId; + } + + set => deviceId = value; + } + + /// + /// Allows forcing device id obtaining on demand. Otherwise, it will be obtained automatically on first usage. + /// + /// Device id obtaining process may be noticeably slow when called first time on some devices.
+ /// This method allows you to force this process at comfortable time (while splash screen is showing for example).

+ /// Call this if you going to use ObscuredFile or ObscuredFilePrefs from non-main thread while using + /// Lock To Device feature without custom #DeviceId to avoid exception due to Unity API access + /// from non-main thread. + public static void ForceLockToDeviceInit() + { + if (string.IsNullOrEmpty(deviceId)) + { + deviceId = GetDeviceId(); + } + else + { + Debug.LogWarning(ACTk.LogPrefix + "ForceLockToDeviceInit() is called, but device ID is already obtained!"); + } + } + + private static string GetDeviceId() + { + var id = string.Empty; +#if !ACTK_PREVENT_READ_PHONE_STATE + if (string.IsNullOrEmpty(id)) + id = UnityApiResultsHolder.GetDeviceUniqueIdentifier(); +#else + Debug.LogError(ACTk.LogPrefix + "Looks like you forced ACTK_PREVENT_READ_PHONE_STATE flag, but still use LockToDevice feature. It will work incorrectly!"); +#endif + return id; + } + + private readonly uint deviceIdHashSeed; + private uint deviceIdHash; + private HashCheckSumModifierDelegate hashCheckSumModifierDelegate; + + internal DeviceIdHolder(uint deviceIdHashSeed = 0) + { + this.deviceIdHashSeed = deviceIdHashSeed; + } + + internal bool MigratingFromACTkV1 { get; private set; } + + internal uint DeviceIdHash + { + get + { + if (deviceIdHash == 0) + { + deviceIdHash = CalculateChecksum(DeviceId); + } + return deviceIdHash; + } + } + + internal void SetHashCheckSumModifierDelegate(HashCheckSumModifierDelegate method) + { + hashCheckSumModifierDelegate = method; + } + + internal void SetMigrationMode(bool enabled) + { + MigratingFromACTkV1 = enabled; + ResetHash(); // to force hash recalculation + } + + internal void ResetHash() + { + deviceIdHash = 0; + } + + private uint CalculateChecksum(string input) + { + if (string.IsNullOrEmpty(input)) + throw new ArgumentNullException(nameof(input)); + + byte[] inputBytes; + + if (hashCheckSumModifierDelegate != null) + { + inputBytes = hashCheckSumModifierDelegate(input); + } + else + { + inputBytes = StringUtils.StringToBytes(input); + } + + var hash = xxHash.CalculateHash(inputBytes, inputBytes.Length, deviceIdHashSeed); + return hash; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs.meta new file mode 100644 index 0000000..b366c30 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceIdHolder.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 71bc8753816c4dd487c486884a613af3 +timeCreated: 1620332008 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs new file mode 100644 index 0000000..cc26f5d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs @@ -0,0 +1,40 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + /// Used to specify level of the device lock feature strictness. + /// Use it to prevent cheating via 100% game saves sharing or sharing purchased in-app items for example.
+ /// + /// Relies on SystemInfo.deviceUniqueIdentifier when not using custom DeviceIdHolder.DeviceId.
+ /// Please note, deviceUniqueIdentifier may change in some rare cases, so one day all locked data may became inaccessible on same device.
+ /// + /// \htmlonlyWARNING:\endhtmlonly On iOS use at your peril with default DeviceId! There is no reliable way to get persistent device ID on iOS. So avoid using it or use in conjunction with DeviceIdHolder.DeviceId (see below).
+ /// \htmlonlyNOTE #1:\endhtmlonly On iOS it tries to receive vendorIdentifier in first place, to avoid device id change while updating from iOS6 to iOS7. It leads to device ID change while updating from iOS5, but such case appears much rarer.
+ /// \htmlonlyNOTE #2:\endhtmlonly You may use own device id via DeviceIdHolder.DeviceId property to make it more reliable and predictable. Use it to lock saves to the specified email for example.
+ /// \htmlonlyNOTE #3:\endhtmlonly Main thread may lock up for a noticeable time while obtaining device ID first time on some devices. Consider using DeviceIdHolder.ForceLockToDeviceInit() at loading screen or other desirable stall moment of your app to prevent undesirable behavior in such cases. + /// \sa DeviceIdHolder.ForceLockToDeviceInit(), DeviceIdHolder.DeviceId, ObscuredPrefs.DeviceLockSettings, ObscuredFilePrefs.DeviceLockSettings, DeviceLockSettings + public enum DeviceLockLevel : byte + { + /// + /// Both locked and not locked to any device data can be read and does not locks saves to the current device. + /// + None, + + /// + /// Does locks to the current device and still allows reading not locked data + /// (useful when you decided to lock your saves in one of app updates and wish to keep user data). + /// + Soft, + + /// + /// Does locks to the current device and reads only locked to the current device data. + /// This is a preferred mode, but it should be enabled right from the first app release. + /// If you released an app without data lock consider using Soft lock or any previously saved data will not be accessible. + /// + Strict + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs.meta new file mode 100644 index 0000000..9fa4527 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockLevel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 173fabcb544d436ca35870420eb58008 +timeCreated: 1620064587 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs new file mode 100644 index 0000000..423b75e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs @@ -0,0 +1,37 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + /// + /// Controls Device Lock feature settings. + /// + public class DeviceLockSettings + { + /// + /// Allows locking saved data to the current device. + /// + /// Read more in #DeviceLockLevel description. + /// \sa Sensitivity + public DeviceLockLevel Level { get; set; } + + /// + /// Controls device lock tampering detection sensitivity. + /// + /// Read more in #DeviceLockTamperingSensitivity description. + /// \sa Level + public DeviceLockTamperingSensitivity Sensitivity { get; set; } + + /// + /// Creates instance with custom settings. + /// + public DeviceLockSettings(DeviceLockLevel level = DeviceLockLevel.None, DeviceLockTamperingSensitivity sensitivity = DeviceLockTamperingSensitivity.Normal) + { + Level = level; + Sensitivity = sensitivity; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs.meta new file mode 100644 index 0000000..92ceffc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3e7cc245e34a4e31864afbefb70d9c98 +timeCreated: 1622720444 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs new file mode 100644 index 0000000..c148d79 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs @@ -0,0 +1,31 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + /// + /// Controls device lock tampering sensitivity - from fully functional to full tampering ignorance. + /// Emits DataFromAnotherDeviceDetected event when detecting data from another device. + /// + /// \sa DeviceLockLevel, ObscuredFile.DataFromAnotherDeviceDetected, ObscuredFilePrefs.DataFromAnotherDeviceDetected, ObscuredPrefs.DataFromAnotherDeviceDetected + public enum DeviceLockTamperingSensitivity : byte + { + /// + /// Allows reading data from another devices without detection. + /// + Disabled, + + /// + /// Allows reading data from another devices and emits DataFromAnotherDeviceDetected event. + /// + Low, + + /// + /// Prevents reading data from another device and emits DataFromAnotherDeviceDetected event. + /// + Normal + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs.meta new file mode 100644 index 0000000..87ca861 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/DeviceLock/DeviceLockTamperingSensitivity.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a3df350ee20f4958babae3d07e3661a1 +timeCreated: 1620929044 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions.meta new file mode 100644 index 0000000..b85aedc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aeeaf650d39d4346a2bdef4f13139d22 +timeCreated: 1630166180 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs new file mode 100644 index 0000000..aceafdf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs @@ -0,0 +1,19 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using Common; + using UnityEngine; + + internal class DeviceUniqueIdentifierException : BackgroundThreadAccessException + { + public DeviceUniqueIdentifierException() : base($"{nameof(SystemInfo)}." + + $"{nameof(SystemInfo.deviceUniqueIdentifier)}") + { + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs.meta new file mode 100644 index 0000000..80aae91 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/DeviceUniqueIdentifierException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4ddd915e96d44240b4dcb9c159cbef7d +timeCreated: 1630166204 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs new file mode 100644 index 0000000..7a414eb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs @@ -0,0 +1,19 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using Common; + using UnityEngine; + + internal class PersistentDataPathException : BackgroundThreadAccessException + { + public PersistentDataPathException() : base($"{nameof(Application)}." + + $"{nameof(Application.persistentDataPath)}") + { + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs.meta new file mode 100644 index 0000000..c0bd0f8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/PersistentDataPathException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fdf0055c31634e909d8fa139c4ed3466 +timeCreated: 1630167247 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs new file mode 100644 index 0000000..6b8d246 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs @@ -0,0 +1,24 @@ +#if UNITY_IPHONE + +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using Common; + + internal class VendorIdentifierException : BackgroundThreadAccessException + { + public VendorIdentifierException() : base($"{nameof(UnityEngine)}." + + $"{nameof(UnityEngine.iOS)}." + + $"{nameof(UnityEngine.iOS.Device)}." + + $"{nameof(UnityEngine.iOS.Device.vendorIdentifier)}") + { + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs.meta new file mode 100644 index 0000000..f8c8589 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Exceptions/VendorIdentifierException.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: aebcb2d846cd4234a5dbf58722d0a5f9 +timeCreated: 1631283157 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File.meta new file mode 100644 index 0000000..ede4d53 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e4f21e7e364d6e44f9843807ff7a5af8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs new file mode 100644 index 0000000..d0c6320 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs @@ -0,0 +1,425 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_WEBGL && !UNITY_EDITOR +#define ACTK_WEBGL_BUILD +#endif + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using System.IO; + using System.Security.Cryptography; + using Common; + using UnityEngine; + + /// + /// Allows saving any binary data into the file either with or without encryption, + /// with or without device locking and always with integrity check to make sure file is genuine. + /// + /// Uses File IO which may cause main thread hiccups when operating with big amounts of data thus + /// it's recommended to use it from background thread or at the stall moments of your app + /// (like loading screens etc).
+ /// Please call DeviceIdHolder.ForceLockToDeviceInit() before accessing this class from background thread if you are using Device Lock feature without custom DeviceID. + public class ObscuredFile + { +#if ACTK_WEBGL_BUILD + [System.Runtime.InteropServices.DllImport("__Internal")] + private static extern void FlushFileSystem(); +#endif + + private const string LogPrefix = ACTk.LogPrefix + nameof(ObscuredFile) + ": "; + + /// + /// Filename used by default, if other name or path was not specified in constructor. + /// + public const string DefaultFileName = "actkfile"; + + private static readonly DeviceIdHolder DeviceIdHolder = new DeviceIdHolder(24052013); + + /// + /// Fires when saved data tampering detected. Will not fire when data is damaged and not readable. + /// + public event Action NotGenuineDataDetected; + + /// + /// Fires when saved data from some other device detected. + /// + /// May be helpful to ban potential cheaters, trying to use someone's purchased in-app goods for example.
+ /// \htmlonlyNOTE:\endhtmlonly Will fire if same device ID has + /// changed (pretty rare case though). Read more at #DeviceLockLevel. + public event Action DataFromAnotherDeviceDetected; + + /// + /// Allows reading current settings. + /// + public IObscuredFileSettings CurrentSettings { get; } + + /// + /// Returns true if file at #FilePath physically exists on disk. + /// + public bool FileExists => File.Exists(FilePath); + + /// + /// Returns path to the file. + /// It's always not empty and valid even if file was not saved to the physical disk yet. + /// + public string FilePath { get; } + + [System.Diagnostics.Conditional("ACTK_DEV_LOGS")] + private static void DevLog(string log) + { +#if UNITY_EDITOR + Debug.Log("[DEVLOG] " + LogPrefix + log); +#else + Debug.Log("[DEVLOG] " + LogPrefix + log); +#endif + } + + /// + /// Creates instance with file name set to #DefaultFileName and default ObscuredFileSettings. + /// + public ObscuredFile() : this(DefaultFileName, new ObscuredFileSettings()) { } + + /// + /// Creates instance with specified file name and default ObscuredFileSettings. + /// + /// Custom file name to place at ObscuredFileLocation.PersistentData. + public ObscuredFile(string fileName) : this(fileName, new ObscuredFileSettings()) { } + + /// + /// Creates instance with file name set to #DefaultFileName and custom specific settings. + /// + /// Custom settings to use with this instance. + public ObscuredFile(ObscuredFileSettings settings) : this(DefaultFileName, settings) { } + + /// + /// Creates instance with specified file name or file path and custom specific settings. + /// + /// File path if using ObscuredFileLocation.Custom, otherwise represents file name to use with set #ObscuredFileLocation kind. + /// Custom settings to use with this instance. + public ObscuredFile(string fileNameOrPath, IObscuredFileSettings settings) + { + CurrentSettings = settings; + FilePath = ConstructFilePath(fileNameOrPath); + } + + /// + /// Deletes physical file assigned with this instance. Does nothing if file does not exists. + /// + public void Delete() + { + if (!FileExists) + return; + + File.Delete(FilePath); +#if ACTK_WEBGL_BUILD + FlushFileSystem(); +#endif + } + + /// + /// Writes passed data to the physical file on disk. + /// Consider calling from background thread for the large data amount. + /// + /// Custom byte array to write. + /// Operation result. + public ObscuredFileWriteResult WriteAllBytes(byte[] data) + { + return WriteAllBytesInternal(data); + } + + /// + /// Reads all bytes from the physical file on disk. + /// Consider calling from background thread for the large data amount. + /// + /// Operation result structure allowing both to get read data and + /// figure out possible violations and errors if data could not be read for some reason. + public ObscuredFileReadResult ReadAllBytes() + { + return ReadAllBytesInternal(); + } + + private ObscuredFileReadResult ReadAllBytesInternal() + { + byte[] data; + var dataIsNotGenuine = false; + var dataFromAnotherDevice = false; + + try + { + if (!File.Exists(FilePath)) + { + Debug.LogError($"{LogPrefix}File {FilePath} does not exists!"); + return ObscuredFileReadResult.FromError(ObscuredFileErrorCode.FileNotFound); + } + + using (var output = new MemoryStream()) + { + uint hash; + uint actualHash = 0; + + using (var reader = File.Open(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + // getting saved file hash + hash = ObscuredFileCrypto.ReadHash(reader); + + // decrypting rest of the file + ObscuredFileCrypto.Decrypt(reader, output, CurrentSettings.EncryptionSettings); + + if (CurrentSettings.ValidateDataIntegrity) + actualHash = ObscuredFileCrypto.CalculateHash(output); + } + + DevLog("Hashes\n" + + $"Hash from file: {hash}\n" + + $"Calculated hash: {actualHash}\n" + + $"Data integrity validation: {CurrentSettings.ValidateDataIntegrity}"); + + // read file header and exit if it's damaged + var header = ReadHeader(output); + if (!header.IsValid()) + { + Debug.LogError($"{LogPrefix}Header is invalid. Looks like data is damaged, can't read it properly!"); + return ObscuredFileReadResult.FromError(ObscuredFileErrorCode.FileDamaged); + } + + if (CurrentSettings.ValidateDataIntegrity) + { + // it's important to check hashes after header consistency check + // to avoid false positives due to real data damage + dataIsNotGenuine = hash != actualHash; + if (dataIsNotGenuine) + { + NotGenuineDataDetected?.Invoke(); + } + } + + var readVersion = header.Version; + var readObscurationMode = header.ObscurationMode; + var savedDeviceIdHash = ObscuredFileCrypto.ReadHash(output); + + DevLog("Read file header:\n" + + $"Format version: {readVersion}\n" + + $"{nameof(ObscurationMode)}: {readObscurationMode}\n" + + $"Device Id hash: {savedDeviceIdHash}"); + + DevLog("Current encryption settings:\n" + + $"{nameof(DeviceLockSettings.Level)}: {CurrentSettings.DeviceLockSettings.Level}\n" + + $"{nameof(DeviceLockSettings.Sensitivity)}: {CurrentSettings.DeviceLockSettings.Sensitivity}\n" + + $"{nameof(ObscurationMode)}: {CurrentSettings.EncryptionSettings.ObscurationMode}"); + + if (CurrentSettings.DeviceLockSettings.Level != DeviceLockLevel.None) + { + var currentDeviceIdHash = DeviceIdHolder.DeviceIdHash; + + DevLog("Device hashes:\n" + + $"Device Id hash: {savedDeviceIdHash}\n" + + $"Current Device Id hash: {currentDeviceIdHash}"); + + var savedDataIsLocked = savedDeviceIdHash != 0; + dataFromAnotherDevice = savedDataIsLocked && savedDeviceIdHash != currentDeviceIdHash; + + DevLog($"Data locked to any device: {savedDataIsLocked}"); + DevLog($"Data from another device: {dataFromAnotherDevice}"); + + if (savedDataIsLocked) + { + if (dataFromAnotherDevice) + { + switch (CurrentSettings.DeviceLockSettings.Sensitivity) + { + case DeviceLockTamperingSensitivity.Disabled: + break; + case DeviceLockTamperingSensitivity.Low: + DataFromAnotherDeviceDetected?.Invoke(); + break; + case DeviceLockTamperingSensitivity.Normal: + DataFromAnotherDeviceDetected?.Invoke(); + return new ObscuredFileReadResult(null, dataIsNotGenuine, true); + default: + throw new ArgumentOutOfRangeException(); + } + } + } + else + { + if (CurrentSettings.DeviceLockSettings.Level == DeviceLockLevel.Strict) + { + Debug.LogError($"{LogPrefix}Can't read data since it is not locked to any device but current {nameof(DeviceLockLevel)} is set to {nameof(DeviceLockLevel.Strict)}."); + return ObscuredFileReadResult.FromError(ObscuredFileErrorCode.DataIsNotLocked); + } + } + } + + var dataLength = output.Length - output.Position; + data = new byte[dataLength]; + var dataRead = output.Read(data, 0, (int)dataLength); +#if DEBUG + if (dataRead != dataLength) + Debug.LogWarning($"{LogPrefix}Less data read ({dataRead} then requested ({dataLength})!"); +#endif + DevLog($"Loaded data is genuine: {!dataIsNotGenuine}"); + } + } + catch (DeviceUniqueIdentifierException e) + { + Debug.LogError($"{LogPrefix}Please make sure to call " + + $"{nameof(CodeStage.AntiCheat.Storage.DeviceIdHolder)}.{nameof(DeviceIdHolder.ForceLockToDeviceInit)}() " + + $"or {nameof(UnityApiResultsHolder)}.{nameof(UnityApiResultsHolder.InitForAsyncUsage)}(true) " + + $"before using {nameof(ObscuredFile)} or {nameof(ObscuredFilePrefs)} from async context " + + $"with Lock To Device feature enabled while keeping default " + + $"{nameof(CodeStage.AntiCheat.Storage.DeviceIdHolder)}.{nameof(DeviceIdHolder.DeviceId)}!"); + return ObscuredFileReadResult.FromError(e); + } + catch (CryptographicException e) + { + Debug.LogError($"{LogPrefix}Couldn't read bytes because of {nameof(CryptographicException)}! " + + $"Are you trying to read plain file with {nameof(ObscurationMode)}.{nameof(ObscurationMode.Encrypted)} or vice versa?"); + Debug.LogException(e); + return ObscuredFileReadResult.FromError(e); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Unexpected exception occured!", LogPrefix, e); + return ObscuredFileReadResult.FromError(e); + } + + return new ObscuredFileReadResult(data, dataIsNotGenuine, dataFromAnotherDevice); + } + + private ObscuredFileHeader ReadHeader(Stream output) + { + output.Position = 0; + + var result = new ObscuredFileHeader(); + result.ReadFrom(output); + return result; + } + + private ObscuredFileWriteResult WriteAllBytesInternal(byte[] data) + { + try + { + using (var memory = new MemoryStream()) + { + WriteHeader(memory); + ApplyDeviceLockIfNeeded(memory, CurrentSettings.DeviceLockSettings.Level); + memory.Write(data, 0, data.Length); + using (var writer = File.Open(FilePath, FileMode.Create, FileAccess.Write, FileShare.None)) + { + uint hash = 0; + + if (CurrentSettings.ValidateDataIntegrity) + hash = ObscuredFileCrypto.CalculateHash(memory); + + DevLog($"Writing file hash: {hash}\n" + + $"Data integrity validation: {CurrentSettings.ValidateDataIntegrity}"); + ObscuredFileCrypto.WriteHash(writer, hash); + ObscuredFileCrypto.Encrypt(memory, writer, CurrentSettings.EncryptionSettings); + } +#if ACTK_WEBGL_BUILD + FlushFileSystem(); +#endif + } + } + catch (DeviceUniqueIdentifierException e) + { + Debug.LogError($"{LogPrefix}Please make sure to call " + + $"{nameof(CodeStage.AntiCheat.Storage.DeviceIdHolder)}.{nameof(DeviceIdHolder.ForceLockToDeviceInit)}() " + + $"or {nameof(UnityApiResultsHolder)}.{nameof(UnityApiResultsHolder.InitForAsyncUsage)}(true) " + + $"before using {nameof(ObscuredFile)} or {nameof(ObscuredFilePrefs)} from async context " + + $"with Lock To Device feature enabled while keeping default " + + $"{nameof(CodeStage.AntiCheat.Storage.DeviceIdHolder)}.{nameof(DeviceIdHolder.DeviceId)}!"); + return ObscuredFileWriteResult.FromError(e); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Unexpected exception occured!", LogPrefix, e); + return ObscuredFileWriteResult.FromError(e); + } + + return new ObscuredFileWriteResult(ObscuredFileErrorCode.NoError); + } + + private void WriteHeader(Stream memory) + { + ObscuredFileHeader.WriteTo(memory, CurrentSettings.EncryptionSettings.ObscurationMode); + } + + private void ApplyDeviceLockIfNeeded(Stream writer, DeviceLockLevel deviceLockLevel) + { + var hash = deviceLockLevel == DeviceLockLevel.None ? 0 : DeviceIdHolder.DeviceIdHash; + DevLog($"Writing device id hash: {hash}"); + ObscuredFileCrypto.WriteHash(writer, hash); + } + + private string ConstructFilePath(string path) + { + string filePath; + if (!Path.HasExtension(path)) + path = Path.ChangeExtension(path, "actk"); + + var isRooted = Path.IsPathRooted(path); + var locationKind = CurrentSettings.LocationKind; + + if (isRooted && locationKind == ObscuredFileLocation.PersistentData) + { + Debug.LogWarning($"Looks like you pass rooted path '{path}' while using default {nameof(ObscuredFileLocation.PersistentData)} {nameof(CurrentSettings.LocationKind)} setting\n" + + $"Using {nameof(ObscuredFileLocation)}.{nameof(ObscuredFileLocation.Custom)} instead!"); + locationKind = ObscuredFileLocation.Custom; + } + + try + { + switch (locationKind) + { + case ObscuredFileLocation.PersistentData: + { + filePath = Path.GetFullPath(Path.Combine(UnityApiResultsHolder.GetPersistentDataPath(), path)); + break; + } + case ObscuredFileLocation.Custom: + { + filePath = Path.GetFullPath(path); + +#if UNITY_ANDROID || UNITY_WEBGL + var streamingPath = Path.GetFullPath(Application.streamingAssetsPath); + if (filePath.StartsWith(streamingPath, StringComparison.InvariantCulture)) + { + var log = $"{LogPrefix}Can't access StreamingAssets data at the " + + $"{filePath} on " + + $"{nameof(RuntimePlatform.Android)} and {nameof(RuntimePlatform.WebGLPlayer)} platforms!\n" + + "Consider moving data to the supported location first. " + + "See 'Troubleshooting' in User Manual for more details."; + #if UNITY_EDITOR + Debug.LogWarning(log); + #else + Debug.LogError(log); + #endif + } +#endif + + break; + } + default: + throw new ArgumentOutOfRangeException(); + } + } + catch (PersistentDataPathException) + { + Debug.LogError($"{LogPrefix}Please make sure to call " + + $"{nameof(UnityApiResultsHolder)}.{nameof(UnityApiResultsHolder.InitForAsyncUsage)}() " + + $"before using {nameof(ObscuredFile)} or " + + $"{nameof(ObscuredFilePrefs)} from async context with " + + $"{nameof(ObscuredFileLocation)}.{nameof(ObscuredFileLocation.PersistentData)} {nameof(ObscuredFileSettings.LocationKind)}!"); + filePath = path; + } + + return filePath; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs.meta new file mode 100644 index 0000000..b733fe1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87bcb44861ea5794c91502625ccf2b42 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs new file mode 100644 index 0000000..7da8726 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs @@ -0,0 +1,118 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using System.IO; + using System.Security.Cryptography; + using Utils; + + internal static class ObscuredFileCrypto + { + private const int HashSize = sizeof(uint); + private const int BufferSize = 81920; + + private static byte[] copyStreamBuffer; + + public static void Encrypt(Stream input, Stream output, EncryptionSettings settings) + { + EncryptInternal(input, output, settings); + } + + public static void Decrypt(Stream input, Stream output, EncryptionSettings settings) + { + DecryptInternal(input, output, settings); + } + + internal static uint CalculateHash(Stream input) + { + return CalculateHashInternal(input); + } + + internal static uint ReadHash(Stream input) + { + var hashBuffer = new byte[HashSize]; + input.Read(hashBuffer, 0, HashSize); + return BytesToHash(hashBuffer); + } + + internal static void WriteHash(Stream writer, uint hash) + { + writer.Write(HashToBytes(hash), 0, HashSize); + } + + + private static uint CalculateHashInternal(Stream input) + { + var count = input.Length; + var hash = xxHash.CalculateHash(input, count, 1613878765); + return hash; + } + + private static void EncryptInternal(Stream input, Stream output, EncryptionSettings settings) + { + if (settings.ObscurationMode == ObscurationMode.Encrypted) + { +#if ACTK_US_EXPORT_COMPATIBLE + CryptoUtils.EncryptRc2(input, output, settings.Password); +#else + CryptoUtils.EncryptAes(input, output, settings.Password); +#endif + } + else + { + input.CopyTo(output, BufferSize); + } + } + + private static byte[] HashToBytes(uint hash) + { + return BitConverter.GetBytes(hash ^ 2122232456); + } + + private static uint BytesToHash(byte[] hash) + { + return BitConverter.ToUInt32(hash, 0) ^ 2122232456; + } + + private static void DecryptInternal(Stream input, Stream output, EncryptionSettings settings) + { + var cryptoKey = settings.Password; + + if (settings.ObscurationMode == ObscurationMode.Encrypted) + { + var position = input.Position; + +#if ACTK_US_EXPORT_COMPATIBLE + try + { + CryptoUtils.DecryptRc2(input, output, cryptoKey); + } + catch (CryptographicException) + { + input.Position = position; + CryptoUtils.DecryptAes(input, output, cryptoKey); + } +#else + try + { + CryptoUtils.DecryptAes(input, output, cryptoKey); + } + catch (CryptographicException) + { + input.Position = position; + CryptoUtils.DecryptRc2(input, output, cryptoKey); + } +#endif + } + else + { + input.CopyTo(output, BufferSize); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs.meta new file mode 100644 index 0000000..07e919c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileCrypto.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7d63eeaec0204d5d9a24e84d682dada6 +timeCreated: 1616322344 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs new file mode 100644 index 0000000..a8b0664 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs @@ -0,0 +1,56 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System.IO; + + internal struct ObscuredFileHeader + { + private const byte HeaderByte1 = 65; // A + private const byte HeaderByte2 = 67; // C + private const byte HeaderByte3 = 84; // T + private const byte HeaderByte4 = 107; // k + private const byte HeaderVersion = 0; + + private byte Byte1 { get; set; } + private byte Byte2 { get; set; } + private byte Byte3 { get; set; } + private byte Byte4 { get; set; } + + public byte Version { get; private set; } + public ObscurationMode ObscurationMode { get; private set; } + + public bool IsValid() + { + return Version == HeaderVersion && + Byte1 == HeaderByte1 && + Byte2 == HeaderByte2 && + Byte3 == HeaderByte3 && + Byte4 == HeaderByte4; + } + + public void ReadFrom(Stream stream) + { + Byte1 = (byte)stream.ReadByte(); + Byte2 = (byte)stream.ReadByte(); + Byte3 = (byte)stream.ReadByte(); + Byte4 = (byte)stream.ReadByte(); + Version = (byte)stream.ReadByte(); + ObscurationMode = (ObscurationMode)stream.ReadByte(); + } + + public static void WriteTo(Stream stream, ObscurationMode obscurationMode) + { + stream.WriteByte(HeaderByte1); + stream.WriteByte(HeaderByte2); + stream.WriteByte(HeaderByte3); + stream.WriteByte(HeaderByte4); + stream.WriteByte(HeaderVersion); + stream.WriteByte((byte)obscurationMode); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs.meta new file mode 100644 index 0000000..598e1c6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/ObscuredFileHeader.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1e66aeea00dc48e5b6484999ec7a5668 +timeCreated: 1624011321 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults.meta new file mode 100644 index 0000000..c06c621 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 439854bd00ab46028d4c3cd5bf68eeee +timeCreated: 1624047113 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs new file mode 100644 index 0000000..12f5735 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs @@ -0,0 +1,72 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + + /// Possible error codes for the file read operation. + public enum ObscuredFileErrorCode : byte + { + /// Indicates no errors happened. + NoError = 0, + /// Indicates file to read from wasn't found. + FileNotFound = 5, + /// Indicates file header was damaged. + FileDamaged = 10, + /// + /// Indicates read data was not locked but you are using + /// DeviceLockLevel.Strict which prevents reading such files. + /// + DataIsNotLocked = 15, + /// Indicates used tool wasn't properly initialized. See error logs for more information. + NotInitialized = 20, + /// Indicates some other exception occured, see ObscuredFileError.Exception for details. + OtherException = 250, + } + + /// ObscuredFile-related errors container. + public readonly struct ObscuredFileError + { + /// + /// Represents error code. If there was no error it will equal to ObscuredFileErrorCode.NoError. + /// + public ObscuredFileErrorCode ErrorCode { get; } + + /// + /// Contains exception details if ErrorCode equals to the ObscuredFileErrorCode.OtherException. + /// + /// Can be null. + public Exception Exception { get; } + + internal ObscuredFileError(ObscuredFileErrorCode code) + { + ErrorCode = code; + Exception = null; + } + + internal ObscuredFileError(Exception exception) + { + ErrorCode = ObscuredFileErrorCode.OtherException; + Exception = exception; + } + + /// Returns contents of this error. + /// Human-readable error information. + public override string ToString() + { + switch (ErrorCode) + { + case ObscuredFileErrorCode.NoError: + return "No error"; + case ObscuredFileErrorCode.OtherException: + return Exception.ToString(); + default: + return $"ErrorCode: {ErrorCode}"; + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs.meta new file mode 100644 index 0000000..e120bed --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileError.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d10bb1e4419440449fe5083c4c8d20a4 +timeCreated: 1624023251 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs new file mode 100644 index 0000000..592c8e2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs @@ -0,0 +1,95 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + + /// Contains ObscuredFile read operation results. + public readonly struct ObscuredFileReadResult + { + /// + /// Returns true in case #Data is not null and #Error's ErrorCode is ObscuredFileErrorCode.NoError, returns false otherwise. + /// + /// \htmlonlyNOTE:\endhtmlonly it will be + /// false if data is not genuine or was loaded from another device even if Data itself was read successfully and not null. + /// Listen to the NotGenuineDataDetected and DataFromAnotherDeviceDetected events + /// (at ObscuredFile or ObscuredFilePrefs) or check #CheatingDetected, #DataIsNotGenuine and #DataFromAnotherDevice + /// properties explicitly to react on the possible cheating. + public bool Success => IsValid && Data != null && !CheatingDetected && Error.ErrorCode == ObscuredFileErrorCode.NoError; + + /// + /// Contains read bytes. Will be null if data was damaged, file does not exists or device lock feature prevented data read. + /// + public byte[] Data { get; } + + /// + /// Indicates either #DataIsNotGenuine or #DataFromAnotherDevice is true. + /// + public bool CheatingDetected => DataIsNotGenuine || DataFromAnotherDevice; + + /// + /// Returns true if saved data has correct header but signature does not matches file contents. Returns false otherwise. + /// + public bool DataIsNotGenuine { get; } + + /// + /// Returns true if device lock feature detected data from another device. + /// + public bool DataFromAnotherDevice { get; } + + /// + /// Contains specific error in case #Success is not true but #IsValid is true. + /// + public ObscuredFileError Error { get; } + + /// + /// Returns true if this struct was filled with actual data, otherwise will stay false. + /// + public bool IsValid { get; } + + internal ObscuredFileReadResult(byte[] data, bool dataIsNotGenuine, bool dataFromAnotherDevice) + { + Data = data; + DataIsNotGenuine = dataIsNotGenuine; + DataFromAnotherDevice = dataFromAnotherDevice; + Error = default; + IsValid = true; + } + + private ObscuredFileReadResult(ObscuredFileError error) + { + Data = default; + DataIsNotGenuine = default; + DataFromAnotherDevice = default; + Error = error; + IsValid = true; + } + + internal static ObscuredFileReadResult FromError(Exception exception) + { + return new ObscuredFileReadResult(new ObscuredFileError(exception)); + } + + internal static ObscuredFileReadResult FromError(ObscuredFileErrorCode errorCode) + { + return new ObscuredFileReadResult(new ObscuredFileError(errorCode)); + } + + /// + /// Returns contents of this operation result. + /// + /// Human-readable operation result. + public override string ToString() + { + return $"{nameof(IsValid)}: {IsValid}\n" + + $"Read data length: {Data?.Length ?? 0}\n" + + $"{nameof(DataIsNotGenuine)}: {DataIsNotGenuine}\n" + + $"{nameof(DataFromAnotherDevice)}: {DataFromAnotherDevice}\n" + + $"{nameof(Error)}: {Error}"; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs.meta new file mode 100644 index 0000000..829d54b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileReadResult.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6d66c88b42404e0cae8c737bbfcb800b +timeCreated: 1620065234 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs new file mode 100644 index 0000000..dac4a07 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs @@ -0,0 +1,57 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + + /// Contains ObscuredFile write operation results. + public readonly struct ObscuredFileWriteResult + { + /// Returns true in case operation had no errors. + public bool Success => IsValid && Error.ErrorCode == ObscuredFileErrorCode.NoError; + + /// Contains specific error in case #Success is not true but #IsValid is true. + public ObscuredFileError Error { get; } + + /// + /// Returns true if this struct was filled with actual data, otherwise will stay false. + /// + public bool IsValid { get; } + + internal ObscuredFileWriteResult(ObscuredFileErrorCode result) + { + Error = new ObscuredFileError(result); + IsValid = true; + } + + private ObscuredFileWriteResult(ObscuredFileError error) + { + Error = error; + IsValid = true; + } + + internal static ObscuredFileWriteResult FromError(Exception exception) + { + return new ObscuredFileWriteResult(new ObscuredFileError(exception)); + } + + internal static ObscuredFileWriteResult FromError(ObscuredFileErrorCode errorCode) + { + return new ObscuredFileWriteResult(new ObscuredFileError(errorCode)); + } + + /// + /// Returns contents of this operation result. + /// + /// Human-readable operation result. + public override string ToString() + { + return $"{nameof(IsValid)}: {IsValid}\n" + + $"{nameof(Error)}: {Error}"; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs.meta new file mode 100644 index 0000000..39bf635 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/OperationResults/ObscuredFileWriteResult.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6055bbb3199e4e79b38a8ea2d09aac31 +timeCreated: 1624047261 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs.meta new file mode 100644 index 0000000..981738a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 68ab9f6eb5f54aabb21851293e9b04e8 +timeCreated: 1622717571 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs new file mode 100644 index 0000000..3a2344a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs @@ -0,0 +1,60 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +using System; +using CodeStage.AntiCheat.ObscuredTypes; +using UnityEngine; + +namespace CodeStage.AntiCheat.Storage +{ + // these overloads allow seamless obscured types processing + public static partial class ObscuredFilePrefs + { + public static void Set(string key, ObscuredBool value) { Set(key, value); } + public static void Set(string key, ObscuredByte value) { Set(key, value); } + public static void Set(string key, ObscuredChar value) { Set(key, value); } + public static void Set(string key, ObscuredDateTime value) { Set(key, value); } + public static void Set(string key, ObscuredDecimal value) { Set(key, value); } + public static void Set(string key, ObscuredBigInteger value) { Set(key, value); } + public static void Set(string key, ObscuredDouble value) { Set(key, value); } + public static void Set(string key, ObscuredFloat value) { Set(key, value); } + public static void Set(string key, ObscuredInt value) { Set(key, value); } + public static void Set(string key, ObscuredLong value) { Set(key, value); } + public static void Set(string key, ObscuredQuaternion value) { Set(key, value); } + public static void Set(string key, ObscuredSByte value) { Set(key, value); } + public static void Set(string key, ObscuredShort value) { Set(key, value); } + public static void Set(string key, ObscuredString value) { Set(key, value); } + public static void Set(string key, ObscuredUInt value) { Set(key, value); } + public static void Set(string key, ObscuredULong value) { Set(key, value); } + public static void Set(string key, ObscuredUShort value) { Set(key, value); } + public static void Set(string key, ObscuredVector2 value) { Set(key, value); } + public static void Set(string key, ObscuredVector2Int value) { Set(key, value); } + public static void Set(string key, ObscuredVector3 value) { Set(key, value); } + public static void Set(string key, ObscuredVector3Int value) { Set(key, value); } + + public static ObscuredBool Get(string key, ObscuredBool defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredByte Get(string key, ObscuredByte defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredChar Get(string key, ObscuredChar defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredDateTime Get(string key, ObscuredDateTime defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredDecimal Get(string key, ObscuredDecimal defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredBigInteger Get(string key, ObscuredBigInteger defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredDouble Get(string key, ObscuredDouble defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredFloat Get(string key, ObscuredFloat defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredInt Get(string key, ObscuredInt defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredLong Get(string key, ObscuredLong defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredQuaternion Get(string key, ObscuredQuaternion defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredSByte Get(string key, ObscuredSByte defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredShort Get(string key, ObscuredShort defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredString Get(string key, ObscuredString defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredUInt Get(string key, ObscuredUInt defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredULong Get(string key, ObscuredULong defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredUShort Get(string key, ObscuredUShort defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector2 Get(string key, ObscuredVector2 defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector2Int Get(string key, ObscuredVector2Int defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector3 Get(string key, ObscuredVector3 defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector3Int Get(string key, ObscuredVector3Int defaultValue = default) { return Get(key, defaultValue); } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs.meta new file mode 100644 index 0000000..d20d0d5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.ObscuredTypes.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 30c294f0c32d40aab86161ea4a6c6cdb +timeCreated: 1635268762 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs new file mode 100644 index 0000000..daa6d18 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs @@ -0,0 +1,511 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using System.Collections.Generic; + using Common; + using UnityEngine; + + /// + /// ObscuredPrefs analogue but uses File IO instead of PlayerPrefs as a backend, has more flexibility and can work from a background thread. + /// + /// Don't forget to call Save() when you wish to save prefs file. You can call it from background thread. + /// It also will save automatically on non-abnormal application quit (relies on Application.wantsToQuit API).
+ /// Please call DeviceIdHolder.ForceLockToDeviceInit before accessing this class from background thread if you are using Device Lock feature without custom DeviceID. + public static partial class ObscuredFilePrefs + { + /// + /// Filename used by default, if other name or path was not specified in constructor. + /// + public const string DefaultFileName = "actkfileprefs"; + + private const string LogPrefix = ACTk.LogPrefix + nameof(ObscuredFilePrefs) + ": "; + + /// + /// Fires when saved data tampering detected. Will not fire when data is damaged and not readable. + /// + public static event Action NotGenuineDataDetected; + + /// + /// Fires when saved data from some other device detected. + /// + /// May be helpful to ban potential cheaters, trying to use someone's purchased in-app goods for example.
+ /// \htmlonlyNOTE:\endhtmlonly Will fire if same device ID has + /// changed (pretty rare case though). Read more at #DeviceLockLevel. + public static event Action DataFromAnotherDeviceDetected; + + private static ObscuredFile prefsFile; + private static Dictionary prefsCache; + private static readonly object BusyLock = new object(); + + /// + /// Allows checking current settings. + /// + /// Use #Init() to set the initial settings. + /// \sa #Init() + public static IObscuredFileSettings CurrentSettings => PrefsFile.CurrentSettings; + + /// + /// Allows checking if #Init() was called previously. + /// + public static bool IsInited { get; private set; } + + /// + /// Allows checking if prefs cache was loaded \ initialized. + /// It can be true while IsExists is false if new prefs was not saved yet. + /// + public static bool IsLoaded => prefsCache != null; + + /// + /// Returns true if prefs file physically exists on disk. File may not exist until Save() is called. + /// + public static bool IsExists => PrefsFile.FileExists; + + /// + /// Returns true if prefs file has unsaved changes. + /// + public static bool IsSaved { get; private set; } + + /// + /// Returns true if prefs file is busy with long-running process such as loading or saving. + /// + public static bool IsBusy { get; private set; } + + /// + /// Returns path to the prefs file. + /// It's always not empty and valid even if prefs was not saved to the physical file yet. + /// + public static string FilePath => PrefsFile.FilePath; + + /// + /// Contains reference to the last underlying ObscuredFile read operation result. + /// + /// Filled on prefs file read.
+ /// May be invalid if no read operations were executed. + /// Check ObscuredFileReadResult.IsValid property to figure this out. + public static ObscuredFileReadResult LastFileReadResult { get; private set; } + + /// + /// Contains reference to the last underlying ObscuredFile write operation result. + /// + /// Filled on prefs file saving.
+ /// May be invalid if no write operations were executed yet. + /// Check ObscuredFileWriteResult.IsValid property to figure this out. + public static ObscuredFileWriteResult LastFileWriteResult { get; private set; } + + // to be exposed in future + private static SerializationSettings SerializationSettings { get; set; } + + private static ObscuredFile PrefsFile + { + get + { + if (IsInited) + return prefsFile; + + Debug.LogError($"{LogPrefix}Please call {nameof(Init)} first!"); + return null; + } + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void Reset() + { + IsInited = false; + IsSaved = false; + IsBusy = false; + + prefsFile = null; + prefsCache?.Clear(); + prefsCache = null; + NotGenuineDataDetected = null; + DataFromAnotherDeviceDetected = null; + } + + /// + /// Initializes %ObscuredFilePrefs with file name set to #DefaultFileName and default ObscuredFileSettings. + /// + /// Pass true to automatically call LoadPrefs(). + /// This may block calling thread, consider using asynchronously for large files. + public static void Init(bool loadPrefs = false) + { + Init(DefaultFileName, new ObscuredFileSettings(), loadPrefs); + } + + /// + /// Initializes %ObscuredFilePrefs with specified file name and default ObscuredFileSettings. + /// + /// Custom file name to place at ObscuredFileLocation.PersistentData. + /// Pass true to automatically call LoadPrefs(). + /// This may block calling thread, consider using asynchronously for large files. + public static void Init(string fileName, bool loadPrefs) + { + Init(fileName, new ObscuredFileSettings(), loadPrefs); + } + + /// + /// Initializes %ObscuredFilePrefs with file name set to #DefaultFileName and custom specific settings. + /// + /// Specific custom settings. + /// Pass true to automatically call LoadPrefs(). + /// This may block calling thread, consider using asynchronously for large files. + public static void Init(IObscuredFileSettings settings, bool loadPrefs) + { + Init(DefaultFileName, settings, loadPrefs); + } + + /// + /// Initializes %ObscuredFilePrefs with specified file name or file path and custom specific settings. + /// + /// File path if using ObscuredFileLocation.Custom, otherwise represents file name to use with set #ObscuredFileLocation kind. + /// Specific custom settings. + /// Pass true to automatically call LoadPrefs(). + /// This may block calling thread, consider using asynchronously for large files. + public static void Init(string fileNameOrPath, IObscuredFileSettings settings, bool loadPrefs) + { + if (IsInited) + { + Debug.LogWarning($"{LogPrefix}Already initialized!"); + return; + } + + prefsFile = InitPrefsFile(fileNameOrPath, settings); + + if (settings.AutoSave) + ObscuredFilePrefsAutoSaver.Init(); + + IsInited = true; + + // for future use, currently using only custom binary serialization + SerializationSettings = new SerializationSettings(); + + if (loadPrefs) + LoadPrefs(); + } + + /// + /// Releases internal prefs cache, unsubscribes events and frees other used resources. + /// + /// Please call Init() again if you wish to re-use it. + public static void UnInit() + { + IsSaved = false; + IsInited = false; + prefsCache?.Clear(); + prefsCache = null; + prefsFile = null; + + NotGenuineDataDetected = null; + DataFromAnotherDeviceDetected = null; + } + + /// + /// Loads prefs from existing file if it wasn't loaded before. + /// + /// This function will read from disk potentially causing a hiccup especially when + /// you have lots of data in your prefs, therefore it is not recommended to call it + /// synchronously during actual game play. + /// Instead, call it from separate thread asynchronously or at loading screens and + /// other stall moments of your app. + public static void LoadPrefs() + { + try + { + if (prefsCache != null) // already loaded + return; + + lock (BusyLock) + { + if (IsBusy) + { + Debug.LogWarning($"{LogPrefix}Couldn't load prefs: I'm already busy."); + return; + } + + IsBusy = true; + + prefsCache = LoadAndDeserializePrefs(); + } + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Couldn't load prefs!", e); + } + finally + { + IsBusy = false; + } + } + + /// + /// Unloads cached prefs from memory. Optionally saves current prefs to the file before unloading. + /// + /// \htmlonlyWARNING:\endhtmlonly Unsaved data will be lost! + public static void UnloadPrefs(bool saveBeforeUnloading = true) + { + if (saveBeforeUnloading) + Save(); + + prefsCache?.Clear(); + prefsCache = null; + } + + /// + /// Returns true if key exists in the %ObscuredFilePrefs. + /// + /// Calls LoadPrefs() internally. + public static bool HasKey(string key) + { + LoadPrefs(); + return prefsCache.ContainsKey(key); + } + + /// + /// Returns all existing prefs keys in current %ObscuredFilePrefs. + /// + /// Calls LoadPrefs() internally. + public static ICollection GetKeys() + { + LoadPrefs(); + return prefsCache.Keys; + } + + /// + /// Removes key and its corresponding value from the %ObscuredFilePrefs. + /// + /// Calls LoadPrefs() internally. + public static void DeleteKey(string key) + { + if (!HasKey(key)) + return; + + prefsCache.Remove(key); + IsSaved = false; + } + + /// + /// Use with caution! Removes all keys and values from the prefs. + /// + public static void DeleteAll() + { + if (!IsInited) + { + Debug.LogError($"{LogPrefix}Please call {nameof(Init)} first!"); + return; + } + + prefsCache?.Clear(); + prefsCache = null; + PrefsFile.Delete(); + IsSaved = true; + } + + /// + /// Writes all modified prefs to underlying ObscuredFile on disk. + /// + /// By default, prefs are saved to disk on Application Quit + /// (relies on Application.wantsToQuit API).
+ /// In case when the app crashes or otherwise prematurely exits, you might + /// want to write the prefs at sensible 'checkpoints' in your app.
+ /// This function will write to disk potentially causing a hiccup especially + /// when you have lots of data in your prefs, therefore it is not recommended + /// to call it synchronously during actual game play. + /// Instead, call it from separate thread asynchronously or at loading screens + /// and other stall moments of your app. + /// True if save was successful or wasn't needed and false if something went wrong. + /// Check LastFileWriteResult for details if this method returns false. + public static bool Save() + { + if (IsSaved) + return true; + + if (prefsCache == null || prefsCache.Count == 0) + return true; + + try + { + lock (BusyLock) + { + if (IsBusy) + { + Debug.LogWarning($"{LogPrefix}Couldn't save prefs: I'm already busy."); + return false; + } + + IsBusy = true; + var result = SerializeAndSavePrefs(); + + if (!result.Success) + Debug.LogError($"{LogPrefix}Couldn't save prefs! See {nameof(LastFileWriteResult)} for details."); + + return result.Success; + } + } + catch (Exception e) + { + Debug.LogException(e); + } + finally + { + IsBusy = false; + } + + return false; + } + + /// + /// Sets the value of the preference identified by key. + /// + /// \htmlonlyWARNING:\endhtmlonly Not all types are supported, see ::StorageDataType for list of supported types. + public static void Set(string key, T value) + { + if (key == null) + throw new ArgumentNullException(nameof(key), $"{LogPrefix}You've passed null as key for type {typeof(T)}!"); + + if (value == null) + throw new ArgumentNullException(nameof(value),$"{LogPrefix}You've passed null as value for type {typeof(T)}!"); + + WritePref(key, value); + } + + /// + /// Returns the value corresponding to key in the preference file if it exists. + /// If it doesn't exist, it will return defaultValue. + /// + /// \htmlonlyWARNING:\endhtmlonly Not all types are supported, see ::StorageDataType for list of supported types. + public static T Get(string key, T defaultValue = default) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + + return ReadPref(key, defaultValue); + } + + private static ObscuredFile InitPrefsFile(string fileNameOrPath, IObscuredFileSettings settings) + { + var result = new ObscuredFile(fileNameOrPath, settings); + result.NotGenuineDataDetected += OnNotGenuineDataDetected; + result.DataFromAnotherDeviceDetected += OnDataFromAnotherDeviceDetected; + return result; + } + + private static void OnNotGenuineDataDetected() + { + NotGenuineDataDetected?.Invoke(); + } + + private static void OnDataFromAnotherDeviceDetected() + { + DataFromAnotherDeviceDetected?.Invoke(); + } + + private static Dictionary LoadAndDeserializePrefs() + { + if (!PrefsFile.FileExists) + return new Dictionary(); + + LastFileReadResult = ReadAllBytesInternal(); + if (!LastFileReadResult.Success) + { + Debug.LogError($"{LogPrefix}Couldn't load prefs! Load operation result:\n" + + LastFileReadResult); + return new Dictionary(); + } + + var result = PrefsSerialization.DeserializePrefsDictionary(LastFileReadResult.Data, SerializationSettings); + if (result == null) + { + Debug.LogError($"{LogPrefix}Couldn't deserialize prefs!"); + return new Dictionary(); + } + + IsSaved = true; + + return result; + } + + private static ObscuredFileWriteResult SerializeAndSavePrefs() + { + var data = PrefsSerialization.SerializePrefsDictionary(prefsCache, SerializationSettings); + LastFileWriteResult = WriteAllBytesInternal(data); + return LastFileWriteResult; + } + + private static T ReadPref(string key, T defaultValue) + { + if (!IsInited) + { + Debug.LogError($"{LogPrefix}Please call {nameof(Init)} first!"); + return defaultValue; + } + + T result = defaultValue; + + if (HasKey(key)) + result = PrefsSerialization.DeserializeStorageDataType(prefsCache[key], SerializationSettings); + + return result; + } + + private static void WritePref(string key, T value) + { + if (!IsInited) + { + Debug.LogError($"{LogPrefix}Please call {nameof(Init)} first!"); + return; + } + + var data = PrefsSerialization.SerializeStorageDataType(value, SerializationSettings); + + if (HasKey(key)) + { + var existingType = prefsCache[key].type; + var newType = data.type; + if (existingType != newType) + { + Debug.LogWarning($"{LogPrefix}Pref {key} type changed from " + + $"{existingType} to {newType}!\n" + + "This message is harmless if you know what you're doing."); + } + + prefsCache[key] = data; + } + else + { + prefsCache.Add(key, data); + } + + IsSaved = false; + } + + private static ObscuredFileReadResult ReadAllBytesInternal() + { + if (!IsInited) + { + Debug.LogError($"{LogPrefix}Please call {nameof(Init)} first!"); + return ObscuredFileReadResult.FromError(ObscuredFileErrorCode.NotInitialized); + } + + return PrefsFile.ReadAllBytes(); + } + + private static ObscuredFileWriteResult WriteAllBytesInternal(byte[] data) + { + if (!IsInited) + { + Debug.LogError($"{LogPrefix}Please call {nameof(Init)} first!"); + return ObscuredFileWriteResult.FromError(ObscuredFileErrorCode.NotInitialized); + } + + var result = PrefsFile.WriteAllBytes(data); + IsSaved = result.Success; + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs.meta new file mode 100644 index 0000000..0af36c3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefs.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d9b841dfe843485e8f0d22bf45b0789b +timeCreated: 1621647549 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs new file mode 100644 index 0000000..fa62c5d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs @@ -0,0 +1,123 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +#if !UNITY_WEBGL +#define ACTK_ASYNC +#endif + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using Common; + using UnityEngine; + using Utils; + + internal static class ObscuredFilePrefsAutoSaver + { + private static bool isInited; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void Reset() + { + isInited = false; + } + + internal static void Init() + { + if (isInited) + return; + + try + { + if (UnityApiResultsHolder.IsMobilePlatform()) + { + AppEventsDispatcher.Instance.ApplicationFocused += OnApplicationFocused; + AppEventsDispatcher.Instance.ApplicationPaused += OnApplicationPaused; + } + else + { + Application.wantsToQuit += OnApplicationWantsToQuit; + } + +#if UNITY_EDITOR + UnityEditor.EditorApplication.wantsToQuit += OnEditorApplicationWantsToQuit; + UnityEditor.EditorApplication.playModeStateChanged += OnEditorPlayModeStateChanged; +#endif + isInited = true; + } + catch (UnityException e) + { + Debug.LogError($"{ACTk.LogPrefix} Couldn't initialize {nameof(ObscuredFilePrefsAutoSaver)}. " + + $"Are you using {nameof(ObscuredFilePrefs)} from background thread but didn't " + + $"call the {nameof(UnityApiResultsHolder)}.{nameof(UnityApiResultsHolder.InitForAsyncUsage)}()?\n" + + $"Auto Save will not be operational!\nException:{e}"); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport($"Something went wrong while creating {nameof(ObscuredFilePrefsAutoSaver)}", e); + } + } + +#if UNITY_EDITOR + private static bool OnEditorApplicationWantsToQuit() + { + TrySave(false); + return true; + } + + private static void OnEditorPlayModeStateChanged(UnityEditor.PlayModeStateChange state) + { + if (state == UnityEditor.PlayModeStateChange.ExitingPlayMode) + TrySave(false); + } +#endif + + private static bool OnApplicationWantsToQuit() + { + TrySave(false); + return true; + } + + private static void OnApplicationFocused(bool hasFocus) + { + if (!hasFocus) + TrySave(); + } + + private static void OnApplicationPaused(bool pauseStatus) + { + if (pauseStatus) + TrySave(); + } + + private static void TrySave(bool async = true) + { + try + { +#if ACTK_ASYNC + if (async) + System.Threading.Tasks.Task.Run(Save); + else + Save(); +#else + Save(); +#endif + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport($"{nameof(ObscuredFilePrefsAutoSaver)} couldn't save data.", e); + } + + void Save() + { + if (ObscuredFilePrefs.IsInited && + !ObscuredFilePrefs.IsSaved && + !ObscuredFilePrefs.IsBusy) + ObscuredFilePrefs.Save(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs.meta new file mode 100644 index 0000000..07421ad --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/ObscuredFilePrefsAutoSaver.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 42a77b99c66148f893666c084f9a9650 +timeCreated: 1649461440 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization.meta new file mode 100644 index 0000000..0e2b706 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 95f1f2c08107411d8f2778b93c663b6e +timeCreated: 1622828401 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs new file mode 100644 index 0000000..47a5a0b --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs @@ -0,0 +1,43 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System.Collections.Generic; + + internal static class PrefsSerialization + { + public static ObscuredPrefsData SerializeStorageDataType(T value, SerializationSettings settings) + { + var serializer = GetSerializer(settings); + return serializer.SerializeStorageDataType(value); + } + + public static T DeserializeStorageDataType(ObscuredPrefsData data, SerializationSettings settings) + { + var serializer = GetSerializer(settings); + return serializer.DeserializeStorageDataType(data); + } + + public static byte[] SerializePrefsDictionary(Dictionary value, SerializationSettings settings) + { + var serializer = GetSerializer(settings); + return serializer.SerializePrefsDictionary(value); + } + + public static Dictionary DeserializePrefsDictionary(byte[] data, SerializationSettings settings) + { + var serializer = GetSerializer(settings); + return serializer.DeserializePrefsDictionary(data); + } + + private static IObscuredFilePrefsSerializer GetSerializer(SerializationSettings settings) + { + return settings.SerializationKind == ACTkSerializationKind.Binary ? + BinarySerializer.GetSerializer() : JsonSerializer.GetSerializer(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs.meta new file mode 100644 index 0000000..831ff1f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/PrefsSerialization.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4443ceaad88f421ca769f62179f25860 +timeCreated: 1622719602 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs new file mode 100644 index 0000000..d7a7226 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs @@ -0,0 +1,23 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + internal enum ACTkSerializationKind + { + Binary + } + + internal class SerializationSettings + { + public ACTkSerializationKind SerializationKind { get; } + + public SerializationSettings(ACTkSerializationKind serializationKind = ACTkSerializationKind.Binary) + { + SerializationKind = serializationKind; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs.meta new file mode 100644 index 0000000..b78a1d1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/SerializationSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 905728f794eb4c9a8871af1cd83479be +timeCreated: 1622720122 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers.meta new file mode 100644 index 0000000..4245fa8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3205bf6ebaa843d1b8be3afeb38f5ef8 +timeCreated: 1622717626 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs new file mode 100644 index 0000000..752657a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs @@ -0,0 +1,107 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System.Collections.Generic; + using System.IO; + using Common; + using UnityEngine; + + internal class BinarySerializer : IObscuredFilePrefsSerializer + { + private const byte Version = 0; + + private static BinarySerializer cachedInstance; + + public static IObscuredFilePrefsSerializer GetSerializer() + { + return cachedInstance ?? (cachedInstance = new BinarySerializer()); + } + + public ObscuredPrefsData SerializeStorageDataType(T value) + { + return StorageDataConverter.GetPrefsDataFromValue(value); + } + + public T DeserializeStorageDataType(ObscuredPrefsData data) + { + return StorageDataConverter.GetValueFromPrefsData(data); + } + + public byte[] SerializePrefsDictionary(Dictionary dictionary) + { + using (var ms = new MemoryStream()) + { + using (var bw = new BinaryWriter(ms)) + { + // writing binary serialization version for future use + bw.Write(Version); + + // writing length + bw.Write(dictionary.Count); + + foreach (var prefsData in dictionary) + { + // writing each pref + WritePref(bw, prefsData.Key, prefsData.Value); + } + } + + return ms.ToArray(); + } + } + + public Dictionary DeserializePrefsDictionary(byte[] data) + { + using (var ms = new MemoryStream(data)) + { + using (var br = new BinaryReader(ms)) + { + // reading version, for future use + var version = br.ReadByte(); + if (version != Version) + { + Debug.LogError($"{ACTk.LogPrefix}Incorrect {nameof(BinarySerializer)} version at the prefs dictionary data!" + + "Can't read data, something is wrong, please report."); + return null; + } + + // getting dictionary elements count + var count = br.ReadInt32(); + var result = new Dictionary(count); + + for (var i = 0; i < count; i++) + { + // reading each pref accordingly to write format + var (key, value) = ReadPref(br); + result.Add(key, value); + } + + return result; + } + } + } + + private void WritePref(BinaryWriter writer, string key, ObscuredPrefsData value) + { + writer.Write(key); + writer.Write((byte)value.type); + writer.Write(value.data.Length); + writer.Write(value.data); + } + + private (string key, ObscuredPrefsData value) ReadPref(BinaryReader reader) + { + var key = reader.ReadString(); + var type = (StorageDataType)reader.ReadByte(); + var dataLength = reader.ReadInt32(); + var data = reader.ReadBytes(dataLength); + + return (key, new ObscuredPrefsData(type, data)); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs.meta new file mode 100644 index 0000000..00f9288 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/BinarySerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ced52881bfaf4d98a304173fa5ef0773 +timeCreated: 1622717656 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs new file mode 100644 index 0000000..1657726 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs @@ -0,0 +1,19 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System.Collections.Generic; + + internal interface IObscuredFilePrefsSerializer + { + ObscuredPrefsData SerializeStorageDataType(T value); + T DeserializeStorageDataType(ObscuredPrefsData data); + + byte[] SerializePrefsDictionary(Dictionary dictionary); + Dictionary DeserializePrefsDictionary(byte[] data); + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs.meta new file mode 100644 index 0000000..c86f0d7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/IObscuredFilePrefsSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e3bff4cc002a4f849f3e7c6c6fc11d6d +timeCreated: 1622718106 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs new file mode 100644 index 0000000..f7c38fe --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs @@ -0,0 +1,42 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using System.Collections.Generic; + + // Currently not implemented. To be decided: to be or not to be =) + internal class JsonSerializer : IObscuredFilePrefsSerializer + { + private static JsonSerializer cachedInstance; + + public static IObscuredFilePrefsSerializer GetSerializer() + { + return cachedInstance ?? (cachedInstance = new JsonSerializer()); + } + + public ObscuredPrefsData SerializeStorageDataType(T value) + { + throw new NotImplementedException(); + } + + public T DeserializeStorageDataType(ObscuredPrefsData data) + { + throw new NotImplementedException(); + } + + public byte[] SerializePrefsDictionary(Dictionary dictionary) + { + throw new NotImplementedException(); + } + + public Dictionary DeserializePrefsDictionary(byte[] data) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs.meta new file mode 100644 index 0000000..c996b07 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Prefs/Serialization/Serializers/JsonSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 74b302c3833b44648954b9e45c39c811 +timeCreated: 1622827918 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings.meta new file mode 100644 index 0000000..7e50842 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5d93c91b029c41dd981e53cf8697a8a2 +timeCreated: 1649673824 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs new file mode 100644 index 0000000..3301be4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs @@ -0,0 +1,76 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using Utils; + + /// + /// Represents how data will be saved to file. + /// + public enum ObscurationMode : byte + { + /// + /// No encryption, just plain binary data. Serialized data will be readable. + /// + Plain = 0, + + /// + /// All data will be encrypted and not readable in the file. + /// + Encrypted = 1 + } + + /// + /// Different ObscuredFile and ObscuredFilePrefs encryption-related settings. + /// + public class EncryptionSettings + { + /// + /// Represents the way data is stored in the file: eiter plain (as is) or encrypted with user-set password, + /// depending on #Password value. + /// + public ObscurationMode ObscurationMode { get; } + + /// + /// Password used to encrypt and decrypt data. Switches #ObscurationMode to ObscurationMode.Encrypted when set + /// or to ObscurationMode.Plain when not set. + /// + /// \htmlonlyWARNING:\endhtmlonly Any existing data encrypted with + /// one password will not be readable with another password. + public byte[] Password { get; } + + /// + /// Creates new specified encryption settings instance. + /// + /// Password string used to encrypt and decrypt data. + /// Changes the way data is stored in the file: plain (as is) if password + /// is not set or empty, otherwise data will be encrypted on write and decrypted on read using this + /// password. Will be converted to byte[] internally. + /// Configured instance. + public EncryptionSettings(string password) : this(StringUtils.StringToBytes(password)) + { + } + + /// + /// Creates new specified encryption settings instance. + /// + /// Password bytes used to encrypt and decrypt data. + /// Changes the way data is stored in the file: plain (as is) if password + /// is not set or empty, otherwise data will be encrypted on write and decrypted on read using this + /// password. + /// Configured instance. + public EncryptionSettings(byte[] password = null) + { + if (password == null || password.Length == 0) + ObscurationMode = ObscurationMode.Plain; + else + ObscurationMode = ObscurationMode.Encrypted; + + Password = password; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs.meta new file mode 100644 index 0000000..e9f2c75 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/EncryptionSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bd60e7d395014239ab4976b91f4850a9 +timeCreated: 1619918970 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs new file mode 100644 index 0000000..198f9b6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs @@ -0,0 +1,45 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + /// + /// Specific settings to use with ObscuredFile instance. + /// + public interface IObscuredFileSettings + { + /// + /// Controls file location. Read more at #ObscuredFileLocation docs. + /// + ObscuredFileLocation LocationKind { get; } + + /// + /// Controls file encryption settings. Read more at #EncryptionSettings docs. + /// + EncryptionSettings EncryptionSettings { get; } + + /// + /// Controls DeviceLock feature settings. Read more at #DeviceLockSettings docs. + /// + DeviceLockSettings DeviceLockSettings { get; } + + /// + /// Controls anti-tampering setting. + /// + /// When enabled, data integrity is validated and invokes NotGenuineDataDetected event on violation. + ///
Disable to skip integrity validation entirely and improve performance. + bool ValidateDataIntegrity { get; } + + /// + /// Switches Auto Save feature. + /// + /// Auto Save feature allows making sure any unsaved data will persist + /// when your app quits (on desktops) or loses the focus (on mobiles). + /// It's enabled by default and this is the recommended setting, + /// but you're free to turn it off at your own risk. + bool AutoSave { get; } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs.meta new file mode 100644 index 0000000..29bd900 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/IObscuredFileSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bf7cf4e40873480487d04fb9499be4a0 +timeCreated: 1649673805 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs new file mode 100644 index 0000000..d858bf1 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs @@ -0,0 +1,88 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + /// + /// Specifies file location. + /// + public enum ObscuredFileLocation : byte + { + /// + /// Corresponds to the Application.persistentDataPath. + /// + PersistentData = 5, + + /// + /// Allows setting custom file path. + /// + Custom = 10, + } + + /// + /// Specific settings to use with ObscuredFile instance. + /// + public class ObscuredFileSettings : IObscuredFileSettings + { + public ObscuredFileLocation LocationKind { get; set; } + public EncryptionSettings EncryptionSettings { get; set; } + public DeviceLockSettings DeviceLockSettings { get; set; } + public bool ValidateDataIntegrity { get; set; } + public bool AutoSave { get; set; } + + /// + /// Creates default settings instance. + /// + /// Default settings are: + /// - LocationKind set to ObscuredFileLocation.PersistentData + /// - EncryptionSettings.ObscurationMode set to ObscurationMode.Plain + /// - DeviceLockSettings.Level set to DeviceLockLevel.None + /// - ValidateDataIntegrity set to true + /// - AutoSave set to true + public ObscuredFileSettings():this(ObscuredFileLocation.PersistentData) + { + } + + /// + /// Creates settings instance with specified LocationKind. + /// + /// Default settings are: + /// - EncryptionSettings.ObscurationMode set to ObscurationMode.Plain + /// - DeviceLockSettings.Level set to DeviceLockLevel.None + /// - ValidateDataIntegrity set to true + /// - AutoSave set to true + public ObscuredFileSettings(ObscuredFileLocation locationKind) : this( + new EncryptionSettings(), new DeviceLockSettings(), locationKind) { } + + /// + /// Creates settings instance with specified DeviceLockSettings. + /// + /// Default settings are: + /// - LocationKind set to ObscuredFileLocation.PersistentData + /// - EncryptionSettings.ObscurationMode set to ObscurationMode.Plain + /// - ValidateDataIntegrity set to true + /// - AutoSave set to true + public ObscuredFileSettings(DeviceLockSettings deviceLockSettings) : this( + new EncryptionSettings(), deviceLockSettings) + { +; + } + + /// + /// Creates user-specified settings instance. + /// + public ObscuredFileSettings(EncryptionSettings encryptionSettings, DeviceLockSettings deviceLockSettings, + ObscuredFileLocation locationKind = ObscuredFileLocation.PersistentData, bool validateDataIntegrity = true, + bool autoSave = true) + { + EncryptionSettings = encryptionSettings; + DeviceLockSettings = deviceLockSettings; + LocationKind = locationKind; + ValidateDataIntegrity = validateDataIntegrity; + AutoSave = autoSave; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs.meta new file mode 100644 index 0000000..54b81d9 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/File/Settings/ObscuredFileSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 48100ed207eb4b43a61d3e58f737aeae +timeCreated: 1616322302 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs.meta new file mode 100644 index 0000000..e962805 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5f1dc951fb744fc49b4b508bff79157f +timeCreated: 1557164832 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs new file mode 100644 index 0000000..b070978 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs @@ -0,0 +1,274 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using UnityEngine; + + public static partial class ObscuredPrefs + { + #region int + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetInt(string key, int value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static int GetInt(string key, int defaultValue = 0) + { + return Get(key, defaultValue); + } + #endregion + + #region uint + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetUInt(string key, uint value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static uint GetUInt(string key, uint defaultValue = 0) + { + return Get(key, defaultValue); + } + #endregion + + #region string + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetString(string key, string value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static string GetString(string key, string defaultValue = "") + { + return Get(key, defaultValue); + } + #endregion + + #region float + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetFloat(string key, float value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static float GetFloat(string key, float defaultValue = 0f) + { + return Get(key, defaultValue); + } + #endregion + + #region double + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetDouble(string key, double value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static double GetDouble(string key, double defaultValue = 0) + { + return Get(key, defaultValue); + } + #endregion + + #region decimal + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetDecimal(string key, decimal value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static decimal GetDecimal(string key, decimal defaultValue = 0) + { + return Get(key, defaultValue); + } + #endregion + + #region long + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetLong(string key, long value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static long GetLong(string key, long defaultValue = 0) + { + return Get(key, defaultValue); + } + #endregion + + #region ulong + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetULong(string key, ulong value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static ulong GetULong(string key, ulong defaultValue = 0) + { + return Get(key, defaultValue); + } + #endregion + + #region bool + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetBool(string key, bool value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static bool GetBool(string key, bool defaultValue = false) + { + return Get(key, defaultValue); + } + #endregion + + #region byte[] + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetByteArray(string key, byte[] value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static byte[] GetByteArray(string key, byte defaultValue = 0, int defaultLength = 0) + { + var encryptedKey = EncryptKey(key); + var encrypted = GetEncryptedPrefsString(key, encryptedKey); + + if (encrypted == RawNotFound) + { + return ConstructByteArray(defaultValue, defaultLength); + } + + return DecryptByteArrayValue(key, encrypted, defaultValue, defaultLength); + } + + private static byte[] ConstructByteArray(byte value, int length) + { + var bytes = new byte[length]; + for (var i = 0; i < length; i++) + { + bytes[i] = value; + } + return bytes; + } + #endregion + + #region Vector2 + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetVector2(string key, Vector2 value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Vector2 GetVector2(string key) + { + return GetVector2(key, Vector2.zero); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Vector2 GetVector2(string key, Vector2 defaultValue) + { + return Get(key, defaultValue); + } + #endregion + + #region Vector3 + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetVector3(string key, Vector3 value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Vector3 GetVector3(string key) + { + return GetVector3(key, Vector3.zero); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Vector3 GetVector3(string key, Vector3 defaultValue) + { + return Get(key, defaultValue); + } + #endregion + + #region Quaternion + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetQuaternion(string key, Quaternion value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Quaternion GetQuaternion(string key) + { + return GetQuaternion(key, Quaternion.identity); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Quaternion GetQuaternion(string key, Quaternion defaultValue) + { + return Get(key, defaultValue); + } + #endregion + + #region Color32 + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates. Be careful with Color and Color32 difference!", false)] + public static void SetColor(string key, Color32 value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates. Be careful with Color and Color32 difference!", false)] + public static Color32 GetColor(string key) + { + return GetColor(key, new Color32(0,0,0,1)); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates. Be careful with Color and Color32 difference!", false)] + public static Color32 GetColor(string key, Color32 defaultValue) + { + return Get(key, defaultValue); + } + + #endregion + + #region Rect + [Obsolete("Please use generic " + nameof(Set) + " instead. This API will be removed in next updates.", false)] + public static void SetRect(string key, Rect value) + { + Set(key, value); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Rect GetRect(string key) + { + return GetRect(key, new Rect(0,0,0,0)); + } + + [Obsolete("Please use generic " + nameof(Get) + " instead. This API will be removed in next updates.", false)] + public static Rect GetRect(string key, Rect defaultValue) + { + return Get(key, defaultValue); + } + + #endregion + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs.meta new file mode 100644 index 0000000..a95521f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.LegacyApi.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6560e603784748ca9e742adbe8119d1c +timeCreated: 1623342137 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs new file mode 100644 index 0000000..de3a901 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs @@ -0,0 +1,61 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +using System; +using CodeStage.AntiCheat.ObscuredTypes; +using UnityEngine; + +namespace CodeStage.AntiCheat.Storage +{ + // these overloads allow seamless obscured types processing + public static partial class ObscuredPrefs + { + public static void Set(string key, ObscuredBool value) { Set(key, value); } + public static void Set(string key, ObscuredByte value) { Set(key, value); } + public static void Set(string key, ObscuredChar value) { Set(key, value); } + public static void Set(string key, ObscuredDateTime value) { Set(key, value); } + public static void Set(string key, ObscuredDecimal value) { Set(key, value); } + public static void Set(string key, ObscuredBigInteger value) { Set(key, value); } + public static void Set(string key, ObscuredDouble value) { Set(key, value); } + public static void Set(string key, ObscuredFloat value) { Set(key, value); } + public static void Set(string key, ObscuredInt value) { Set(key, value); } + public static void Set(string key, ObscuredLong value) { Set(key, value); } + public static void Set(string key, ObscuredQuaternion value) { Set(key, value); } + public static void Set(string key, ObscuredSByte value) { Set(key, value); } + public static void Set(string key, ObscuredShort value) { Set(key, value); } + public static void Set(string key, ObscuredString value) { Set(key, value); } + public static void Set(string key, ObscuredUInt value) { Set(key, value); } + public static void Set(string key, ObscuredULong value) { Set(key, value); } + public static void Set(string key, ObscuredUShort value) { Set(key, value); } + public static void Set(string key, ObscuredVector2 value) { Set(key, value); } + public static void Set(string key, ObscuredVector2Int value) { Set(key, value); } + public static void Set(string key, ObscuredVector3 value) { Set(key, value); } + public static void Set(string key, ObscuredVector3Int value) { Set(key, value); } + + public static ObscuredBool Get(string key, ObscuredBool defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredByte Get(string key, ObscuredByte defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredChar Get(string key, ObscuredChar defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredDateTime Get(string key, ObscuredDateTime defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredDecimal Get(string key, ObscuredDecimal defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredBigInteger Get(string key, ObscuredBigInteger defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredDouble Get(string key, ObscuredDouble defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredFloat Get(string key, ObscuredFloat defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredInt Get(string key, ObscuredInt defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredLong Get(string key, ObscuredLong defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredQuaternion Get(string key, ObscuredQuaternion defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredSByte Get(string key, ObscuredSByte defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredShort Get(string key, ObscuredShort defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredString Get(string key, ObscuredString defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredUInt Get(string key, ObscuredUInt defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredULong Get(string key, ObscuredULong defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredUShort Get(string key, ObscuredUShort defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector2 Get(string key, ObscuredVector2 defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector2Int Get(string key, ObscuredVector2Int defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector3 Get(string key, ObscuredVector3 defaultValue = default) { return Get(key, defaultValue); } + public static ObscuredVector3Int Get(string key, ObscuredVector3Int defaultValue = default) { return Get(key, defaultValue); } + + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs.meta new file mode 100644 index 0000000..90a65f3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.ObscuredTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 140cedaa8714013488f22776e11e85cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs new file mode 100644 index 0000000..270c842 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs @@ -0,0 +1,481 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using System; + using ObscuredTypes; + using UnityEngine; + using Utils; + + public static partial class ObscuredPrefs + { + private static char[] generatedCryptoKey; + + internal static char[] GetCryptoKey(string dynamicSuffix = null, string prefsKey = PrefsKey) + { + if (generatedCryptoKey == null) + { + var savedKey = PlayerPrefs.GetString(prefsKey); + if (!string.IsNullOrEmpty(savedKey)) + { + generatedCryptoKey = Base64Utils.FromBase64ToChars(savedKey); + } + else + { + generatedCryptoKey = ObscuredString.GenerateKey(); + var b64 = Base64Utils.ToBase64(generatedCryptoKey); + PlayerPrefs.SetString(prefsKey, b64); + PlayerPrefs.Save(); + } + } + + if (string.IsNullOrEmpty(dynamicSuffix)) + { + return generatedCryptoKey; + } + + var suffixChars = dynamicSuffix.ToCharArray(); + var result = new char[generatedCryptoKey.Length + suffixChars.Length]; + Buffer.BlockCopy(generatedCryptoKey, 0, result, 0, generatedCryptoKey.Length); + Buffer.BlockCopy(suffixChars, 0, result, generatedCryptoKey.Length + 1, suffixChars.Length); + + return result; + } + + internal static string EncryptKey(string key) + { + var keyChars = ObscuredString.Encrypt(key.ToCharArray(), GetCryptoKey()); + key = Base64Utils.ToBase64(keyChars); + return key; + } + + internal static StorageDataType GetRawValueType(string value) + { + var result = StorageDataType.Unknown; + byte[] inputBytes; + + try + { + inputBytes = Convert.FromBase64String(value); + } + catch (Exception) + { + return result; + } + + if (inputBytes.Length < 7) + { + return result; + } + + var inputLength = inputBytes.Length; + + result = (StorageDataType)inputBytes[inputLength - 7]; + + var version = inputBytes[inputLength - 6]; + if (version > 10) + { + result = StorageDataType.Unknown; + } + + return result; + } + + internal static string EncryptValue(string key, T value) + { + var prefsData = StorageDataConverter.GetPrefsDataFromValue(value); + return EncryptData(key, prefsData.data, prefsData.type); + } + + internal static T DecryptValue(string key, string encryptedKey, T defaultValue, string encryptedInput = null) + { + if (encryptedInput == null) + encryptedInput = GetEncryptedPrefsString(key, encryptedKey); + + if (encryptedInput == RawNotFound) + return defaultValue; + + var cleanBytes = DecryptData(key, encryptedInput); + if (cleanBytes == null) + return defaultValue; + + var cleanValue = StorageDataConverter.GetValueFromData(cleanBytes); + return cleanValue; + } + + private static byte[] DecryptByteArrayValue(string key, string encryptedInput, byte defaultValue, int defaultLength) + { + var cleanBytes = DecryptData(key, encryptedInput); + return cleanBytes ?? ConstructByteArray(defaultValue, defaultLength); + } + + private static string EncryptData(string key, byte[] cleanBytes, StorageDataType type) + { + var dataLength = cleanBytes.Length; + var encryptedBytes = EncryptDecryptBytes(cleanBytes, dataLength, GetCryptoKey(key)); + + var dataHash = xxHash.CalculateHash(cleanBytes, dataLength, 0); + var dataHashBytes = new byte[4]; // replaces BitConverter.GetBytes(hash); + dataHashBytes[0] = (byte)(dataHash & 0xFF); + dataHashBytes[1] = (byte)((dataHash >> 8) & 0xFF); + dataHashBytes[2] = (byte)((dataHash >> 16) & 0xFF); + dataHashBytes[3] = (byte)((dataHash >> 24) & 0xFF); + + byte[] deviceHashBytes = null; + int finalBytesLength; + if (DeviceLockSettings.Level != DeviceLockLevel.None) + { + // 4 device id hash + 1 data type + 1 device lock mode + 1 version + 4 data hash + finalBytesLength = dataLength + 11; + var deviceHash = DeviceIdHolder.DeviceIdHash; + deviceHashBytes = new byte[4]; // replaces BitConverter.GetBytes(hash); + deviceHashBytes[0] = (byte)(deviceHash & 0xFF); + deviceHashBytes[1] = (byte)((deviceHash >> 8) & 0xFF); + deviceHashBytes[2] = (byte)((deviceHash >> 16) & 0xFF); + deviceHashBytes[3] = (byte)((deviceHash >> 24) & 0xFF); + } + else + { + // 1 data type + 1 device lock mode + 1 version + 4 data hash + finalBytesLength = dataLength + 7; + } + + var finalBytes = new byte[finalBytesLength]; + + Buffer.BlockCopy(encryptedBytes, 0, finalBytes, 0, dataLength); + if (deviceHashBytes != null) + { + Buffer.BlockCopy(deviceHashBytes, 0, finalBytes, dataLength, 4); + } + + finalBytes[finalBytesLength - 7] = (byte)type; + finalBytes[finalBytesLength - 6] = Version; + finalBytes[finalBytesLength - 5] = (byte)DeviceLockSettings.Level; + Buffer.BlockCopy(dataHashBytes, 0, finalBytes, finalBytesLength - 4, 4); + + return Convert.ToBase64String(finalBytes); + } + + private static byte[] DecryptData(string key, string encryptedInput) + { + byte[] inputBytes; + + try + { + inputBytes = Convert.FromBase64String(encryptedInput); + } + catch (Exception) + { + SavesTampered(); + return null; + } + + if (inputBytes.Length <= 0) + { + SavesTampered(); + return null; + } + + var inputLength = inputBytes.Length; + + if (inputLength < 7) + { + SavesTampered(); + return null; + } + + var inputLockToDevice = (DeviceLockLevel)inputBytes[inputLength - 5]; + + var dataHashBytes = new byte[4]; + Buffer.BlockCopy(inputBytes, inputLength - 4, dataHashBytes, 0, 4); + var inputDataHash = (uint)(dataHashBytes[0] | dataHashBytes[1] << 8 | dataHashBytes[2] << 16 | dataHashBytes[3] << 24); + + int dataBytesLength; + uint inputDeviceHash = 0; + + if (inputLockToDevice != DeviceLockLevel.None) + { + dataBytesLength = inputLength - 11; + if (DeviceLockSettings.Level != DeviceLockLevel.None) + { + var deviceHashBytes = new byte[4]; + Buffer.BlockCopy(inputBytes, dataBytesLength, deviceHashBytes, 0, 4); + inputDeviceHash = (uint)(deviceHashBytes[0] | deviceHashBytes[1] << 8 | deviceHashBytes[2] << 16 | deviceHashBytes[3] << 24); + } + } + else + { + dataBytesLength = inputLength - 7; + } + + if (dataBytesLength < 0) + { + SavesTampered(); + return null; + } + + var encryptedBytes = new byte[dataBytesLength]; + Buffer.BlockCopy(inputBytes, 0, encryptedBytes, 0, dataBytesLength); + + byte[] cleanBytes; + if (!DeviceIdHolder.MigratingFromACTkV1) + { + cleanBytes = EncryptDecryptBytes(encryptedBytes, dataBytesLength, GetCryptoKey(key)); + } + else + { + cleanBytes = EncryptDecryptBytesObsolete(encryptedBytes, dataBytesLength, key + cryptoKeyObsoleteForMigration); + } + + var realDataHash = xxHash.CalculateHash(cleanBytes, dataBytesLength, 0); + if (realDataHash != inputDataHash) + { + SavesTampered(); + return null; + } + + if (inputDeviceHash == 0 && + DeviceLockSettings.Level == DeviceLockLevel.Strict && + DeviceLockSettings.Sensitivity == DeviceLockTamperingSensitivity.Normal) + { + return null; + } + + if (inputDeviceHash != 0 && DeviceLockSettings.Sensitivity != DeviceLockTamperingSensitivity.Disabled) + { + var realDeviceHash = DeviceIdHolder.DeviceIdHash; + if (inputDeviceHash != realDeviceHash) + { + PossibleForeignSavesDetected(); + if (DeviceLockSettings.Sensitivity == DeviceLockTamperingSensitivity.Normal) return null; + } + } + + // reserved for future use + // var type = (StorageDataType)inputBytes[inputLength - 7]; + + var inputVersion = inputBytes[inputLength - 6]; + if (inputVersion != Version) + { + if (inputVersion == 2 || inputVersion == 3) + { + var type = (StorageDataType)inputBytes[inputLength - 7]; + if (type == StorageDataType.Color) // converting Color32 bytes format to new version + { + var color32 = StorageDataConverter.BytesToColor32Legacy(cleanBytes); + cleanBytes = StorageDataConverter.GetPrefsDataFromValue(color32).data; + } + + /*if (string.IsNullOrEmpty(cryptoKeyObsolete)) + { + Debug.LogError(LogPrefix + "Data encrypted with obsolete version found but CryptoKey is not set! " + + "Can't decrypt it without a key."); + return null; + }*/ + } + else if (inputVersion > Version) // impossible thing in normal conditions + { + SavesTampered(); + return null; + } + } + + return cleanBytes; + } + + private static byte[] EncryptDecryptBytes(byte[] bytes, int dataLength, char[] key) + { + var encryptionKeyLength = key.Length; + + var result = new byte[dataLength]; + + for (var i = 0; i < dataLength; i++) + { + result[i] = (byte)(bytes[i] ^ key[i % encryptionKeyLength]); + } + + return result; + } + + private static string GetEncryptedPrefsString(string key, string encryptedKey) + { + var result = PlayerPrefs.GetString(encryptedKey, RawNotFound); + + if (result == RawNotFound) + { + if (PlayerPrefs.HasKey(key)) + { + Debug.LogWarning(LogPrefix + "Are you trying to read regular PlayerPrefs data using ObscuredPrefs (key = " + key + ")?"); + } + else + { + MigrateFromACTkV1Internal(key, cryptoKeyObsolete); + result = PlayerPrefs.GetString(encryptedKey, RawNotFound); + } + } + return result; + } + +#pragma warning disable 618 + private static bool MigrateFromACTkV1Internal(string key, string cryptoKey) + { + var oldPrefsKey = EncryptKeyWithACTkV1Algorithm(key, cryptoKey); + if (!PlayerPrefs.HasKey(oldPrefsKey)) + { + return false; + } + + DeviceIdHolder.SetMigrationMode(true); + cryptoKeyObsoleteForMigration = cryptoKey; + + var encrypted = PlayerPrefs.GetString(oldPrefsKey); + var type = GetRawValueType(encrypted); + + switch (type) + { + case StorageDataType.Int32: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetInt(key, decrypted); + break; + } + case StorageDataType.UInt32: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0u, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetUInt(key, decrypted); + break; + } + case StorageDataType.String: + { + var decrypted = DecryptValue(key, oldPrefsKey, string.Empty, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetString(key, decrypted); + break; + } + case StorageDataType.Single: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0f, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetFloat(key, decrypted); + break; + } + case StorageDataType.Double: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0d, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetDouble(key, decrypted); + break; + } + case StorageDataType.Decimal: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0m, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetDecimal(key, decrypted); + break; + } + case StorageDataType.Int64: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0L, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetLong(key, decrypted); + break; + } + case StorageDataType.UInt64: + { + var decrypted = DecryptValue(key, oldPrefsKey, 0ul, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetULong(key, decrypted); + break; + } + case StorageDataType.Boolean: + { + var decrypted = DecryptValue(key, oldPrefsKey, false, encrypted); + DeviceIdHolder.SetMigrationMode(false); + SetBool(key, decrypted); + break; + } + case StorageDataType.ByteArray: + { + var decrypted = DecryptByteArrayValue(key, encrypted, 0, 0); + DeviceIdHolder.SetMigrationMode(false); + SetByteArray(key, decrypted); + break; + } + case StorageDataType.Vector2: + { + var decrypted = DecryptValue(key, encrypted, Vector2.zero); + DeviceIdHolder.SetMigrationMode(false); + SetVector2(key, decrypted); + break; + } + case StorageDataType.Vector3: + { + var decrypted = DecryptValue(key, encrypted, Vector3.zero); + DeviceIdHolder.SetMigrationMode(false); + SetVector3(key, decrypted); + break; + } + case StorageDataType.Quaternion: + { + var decrypted = DecryptValue(key, encrypted, Quaternion.identity); + DeviceIdHolder.SetMigrationMode(false); + SetQuaternion(key, decrypted); + break; + } + case StorageDataType.Color: // in ACTk1, Color32 was saved with Color type + { + var decrypted = DecryptValue(key, encrypted, new Color32(0, 0, 0, 1)); + DeviceIdHolder.SetMigrationMode(false); + SetColor(key, decrypted); + break; + } + case StorageDataType.Rect: + { + var decrypted = DecryptValue(key, encrypted, new Rect(0,0,0,0)); + DeviceIdHolder.SetMigrationMode(false); + SetRect(key, decrypted); + break; + } + default: + Debug.LogWarning(LogPrefix + "Couldn't migrate " + key + " key from ACTk v1 prefs since its type is unknown!"); + return false; + } + + Debug.Log(LogPrefix + "Obscured pref " + key + " successfully migrated to the newer format."); + + cryptoKeyObsoleteForMigration = null; + PlayerPrefs.DeleteKey(oldPrefsKey); + return true; + } +#pragma warning restore 618 + + private static byte[] EncryptDecryptBytesObsolete(byte[] bytes, int dataLength, string key) + { + var encryptionKeyLength = key.Length; + var result = new byte[dataLength]; + + for (var i = 0; i < dataLength; i++) + { + result[i] = (byte)(bytes[i] ^ key[i % encryptionKeyLength]); + } + + return result; + } + + private static byte[] DeviceIdHashModifier(string input) + { + if (DeviceIdHolder.MigratingFromACTkV1) + { + return StringUtils.StringToBytes(input + cryptoKeyObsoleteForMigration); + } + + return StringUtils.CharsToBytes(GetCryptoKey(input)); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs.meta new file mode 100644 index 0000000..8f63056 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.Routines.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c09fe09018b845fa977f45e1d4258802 +timeCreated: 1557319723 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs new file mode 100644 index 0000000..9a93e85 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs @@ -0,0 +1,356 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Storage +{ + using Common; + using Utils; + + using System; + using ObscuredTypes; + using UnityEngine; + + /// + /// This is an Obscured analogue of the PlayerPrefs class. + /// + /// Saves data in encrypted state, optionally locking it to the current device.
+ /// Automatically encrypts PlayerPrefs on first read (auto migration), has tampering detection and more.
+ /// Check out ObscuredFilePrefs if you wish to save big data amounts. + public static partial class ObscuredPrefs + { + // JFF: MD2 for "ElonShotMarsWithACar" (yes, MD2, not MD5) + internal const string PrefsKey = "9978e9f39c218d674463dab9dc728bd6"; + private const string RawNotFound = "{not_found}"; + private const string LogPrefix = ACTk.LogPrefix + "ObscuredPrefs: "; + private const byte Version = 4; + + private static bool alterationReported; + private static bool foreignSavesReported; + + private static string cryptoKeyObsolete = "e806f6"; + private static string cryptoKeyObsoleteForMigration; + + [Obsolete("Custom crypto key is now obsolete, use only for data recovery from prefs saved with previous version. " + + "This property will be removed in future versions.")] + public static string CryptoKey + { + set => cryptoKeyObsolete = value; + get => cryptoKeyObsolete; + } + + [Obsolete("Please use DeviceIdHolder.DeviceId instead.", false)] + public static string DeviceId + { + get => DeviceIdHolder.DeviceId; + set => DeviceIdHolder.DeviceId = value; + } + + private static DeviceIdHolder deviceIdHolder; + + private static DeviceIdHolder DeviceIdHolder + { + get + { + if (deviceIdHolder == null) + { + deviceIdHolder = new DeviceIdHolder(); + deviceIdHolder.SetHashCheckSumModifierDelegate(DeviceIdHashModifier); + } + + return deviceIdHolder; + } + } + + [Obsolete("Please use NotGenuineDataDetected event instead.", false)] + public static event Action OnAlterationDetected; + + [Obsolete("Please use DataFromAnotherDeviceDetected event instead.", false)] + public static event Action OnPossibleForeignSavesDetected; + + /// + /// Allows reacting on saves alteration. May be helpful for banning potential cheaters. + /// + /// Fires only once. + public static event Action NotGenuineDataDetected; + + /// + /// Allows reacting on detection of possible saves from some other device. + /// + /// May be helpful to ban potential cheaters, trying to use someone's purchased in-app goods for example.
+ /// May fire on same device in case cheater manipulates saved data in some special way.
+ /// Fires only once. + /// + /// \htmlonlyNOTE:\endhtmlonly May be called if same device ID was changed (pretty rare case though). + public static event Action DataFromAnotherDeviceDetected; + + /// + /// Allows saving original PlayerPrefs values while migrating to ObscuredPrefs. + /// + /// In such case, original value still will be readable after switching from PlayerPrefs to + /// ObscuredPrefs and it should be removed manually as it became unneeded.
+ /// Original PlayerPrefs value will be automatically removed after read by default. + public static bool preservePlayerPrefs = false; + + /// + /// Controls DeviceLock feature settings. Read more at #DeviceLockSettings docs. + /// + public static DeviceLockSettings DeviceLockSettings { get; } = new DeviceLockSettings(); + + [Obsolete("Please use DeviceLockSettings.DeviceLockLevel property instead.", false)] + public static DeviceLockLevel lockToDevice + { + get => DeviceLockSettings.Level; + set => DeviceLockSettings.Level = value; + } + + [Obsolete("Please use DeviceLockSettings.DeviceLockTamperingSensitivity property instead.", false)] + public static bool readForeignSaves + { + get => DeviceLockSettings.Sensitivity <= DeviceLockTamperingSensitivity.Low; + + set => DeviceLockSettings.Sensitivity = value ? DeviceLockTamperingSensitivity.Low : DeviceLockTamperingSensitivity.Normal; + } + + [Obsolete("Please use DeviceLockSettings.DeviceLockTamperingSensitivity property instead.", false)] + public static bool emergencyMode + { + get => DeviceLockSettings.Sensitivity <= DeviceLockTamperingSensitivity.Disabled; + set => DeviceLockSettings.Sensitivity = value ? DeviceLockTamperingSensitivity.Disabled : DeviceLockTamperingSensitivity.Normal; + } + + [Obsolete("Please use DeviceIdHolder.ForceLockToDeviceInit() instead.", false)] + public static void ForceLockToDeviceInit() + { + DeviceIdHolder.ForceLockToDeviceInit(); + } + + /// + /// Allows to set the raw encrypted key and value. + /// + public static void SetRawValue(string encryptedKey, string encryptedValue) + { + SetStringPref(encryptedKey, encryptedValue); + } + + /// + /// Allows to get the raw encrypted key and value for the specified key. + /// + /// True if key was found and false otherwise. + public static bool GetRawValue(string key, out string encryptedKey, out string encryptedValue) + { + encryptedValue = null; + encryptedKey = EncryptKey(key); + + if (!PlayerPrefs.HasKey(encryptedKey)) + { + return false; + } + + encryptedValue = PlayerPrefs.GetString(encryptedKey); + return true; + } + + /// + /// Returns true if key exists in the ObscuredPrefs or in regular PlayerPrefs. + /// + public static bool HasKey(string key) + { + return PlayerPrefs.HasKey(key) || PlayerPrefs.HasKey(EncryptKey(key)) || PlayerPrefs.HasKey(EncryptKeyWithACTkV1Algorithm(key)); + } + + /// + /// Removes key and its corresponding value from the ObscuredPrefs and regular PlayerPrefs. + /// + public static void DeleteKey(string key) + { + PlayerPrefs.DeleteKey(EncryptKey(key)); + if (!preservePlayerPrefs) PlayerPrefs.DeleteKey(key); + } + + /// + /// Removes saved crypto key. Use only when you wish to completely remove all obscured prefs! + /// + /// \htmlonlyWARNING:\endhtmlonly Any existing obscured prefs will be lost after this action. + public static void DeleteCryptoKey() + { + PlayerPrefs.DeleteKey(PrefsKey); + + generatedCryptoKey = null; + DeviceIdHolder.ResetHash(); + } + + /// + /// Removes all keys and values from the preferences, including anything saved with regular PlayerPrefs. Use with caution! + /// + /// \htmlonlyWARNING:\endhtmlonly Please use this method to remove all prefs instead of PlayerPrefs.DeleteAll() to properly clear internals and avoid any data loss when saving new obscured prefs after DeleteAll() call. + public static void DeleteAll() + { + PlayerPrefs.DeleteAll(); + + generatedCryptoKey = null; + DeviceIdHolder.ResetHash(); + } + + /// + /// Writes all modified preferences to disk. + /// + /// By default, Unity writes preferences to disk on Application Quit.
+ /// In case when the game crashes or otherwise prematurely exits, you might want to write the preferences at sensible 'checkpoints' in your game.
+ /// This function will write to disk potentially causing a small hiccup, therefore it is not recommended to call during actual game play. + public static void Save() + { + try + { + PlayerPrefs.Save(); + } + catch (PlayerPrefsException e) + { +#if UNITY_WEBGL + Debug.LogError($"{LogPrefix}Couldn't save PlayerPrefs, looks like WebGL PlayerPrefs size exceeds 1 MB limit!"); +#endif + Debug.LogException(e); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport("Couldn't save PlayerPrefs for unknown reason!", e); + } + } + + /// + /// Sets the value of the preference identified by key. + /// + /// \htmlonlyWARNING:\endhtmlonly Not all types are supported, see ::StorageDataType for list of supported types. + public static void Set(string key, T value) + { + if (key == null) + throw new ArgumentNullException(nameof(key), $"{LogPrefix}You've passed null as key for type {typeof(T)}!"); + + if (value == null) + throw new ArgumentNullException(nameof(value),$"{LogPrefix}You've passed null as value for type {typeof(T)}!"); + + SetStringPref(EncryptKey(key), EncryptValue(key, value)); + } + + /// + /// Returns the value corresponding to key in the preference file if it exists. + /// If it doesn't exist, it will return defaultValue. + /// + /// \htmlonlyWARNING:\endhtmlonly Not all types are supported, see ::StorageDataType for list of supported types. + public static T Get(string key, T defaultValue = default) + { + if (key == null) + throw new ArgumentNullException(nameof(key)); + + var encryptedKey = EncryptKey(key); + + if (!PlayerPrefs.HasKey(encryptedKey)) + { + if (PlayerPrefs.HasKey(key)) + { + return ReadFromRegularPrefs(key, defaultValue); + } + MigrateFromACTkV1Internal(key, cryptoKeyObsolete); + } + + return DecryptValue(key, encryptedKey, defaultValue); + } + + private static T ReadFromRegularPrefs(string key, T defaultValue) + { + T unencrypted = defaultValue; + + var type = StorageDataTypeClassifier.GetStorageDataType(); + + if (type == StorageDataType.Int32) + { + unencrypted = (T)(object)PlayerPrefs.GetInt(key, (int)(object)defaultValue); + } + else if (type == StorageDataType.Single) + { + unencrypted = (T)(object)PlayerPrefs.GetFloat(key, (float)(object)defaultValue); + } + else if (type == StorageDataType.String) + { + unencrypted = (T)(object)PlayerPrefs.GetString(key, defaultValue as string); + } + + if (!preservePlayerPrefs) + { + if (type == StorageDataType.Int32 || + type == StorageDataType.Single || + type == StorageDataType.String) + { + Set(key, unencrypted); + } + + PlayerPrefs.DeleteKey(key); + } + return unencrypted; + } + + private static void SetStringPref(string encryptedKey, string encryptedValue) + { + try + { + PlayerPrefs.SetString(encryptedKey, encryptedValue); + } + catch (PlayerPrefsException e) + { +#if UNITY_WEBGL + Debug.LogError($"{LogPrefix}Couldn't write PlayerPrefs value, looks like WebGL PlayerPrefs size exceeds 1 MB limit!"); +#endif + Debug.LogException(e); + } + } + + /// + /// Use to migrate ACTk v1.* prefs to the newer format. + /// + /// Prefs key you wish to migrate. + /// Custom crypto key you used for ObscuredPrefs, if any. + /// Don't use this argument to utilize default key from ACTk v1. + /// True if migration was successful, false otherwise. + public static bool MigrateFromACTkV1(string key, string cryptoKey = "e806f6") + { + return MigrateFromACTkV1Internal(key, cryptoKey); + } + + /// + /// Use to encrypt ACTkv1's value key for later use with SetRawValue to let it migrate. + /// + /// Prefs key. + /// Crypto key you used with ACTk v1, if any. + /// Prefs key, encrypted with old ACTk v1 encryption. + public static string EncryptKeyWithACTkV1Algorithm(string key, string cryptoKey = "e806f6") + { + return Base64Utils.ToBase64(ObscuredString.EncryptDecryptObsolete(key, cryptoKey)); + } + + private static void SavesTampered() + { +#pragma warning disable 618 + if ((NotGenuineDataDetected != null || OnAlterationDetected != null) && !alterationReported) + { + alterationReported = true; + NotGenuineDataDetected?.Invoke(); + OnAlterationDetected?.Invoke(); + } +#pragma warning restore 618 + } + + private static void PossibleForeignSavesDetected() + { +#pragma warning disable 618 + if ((DataFromAnotherDeviceDetected != null || OnPossibleForeignSavesDetected != null) && !foreignSavesReported) + { + foreignSavesReported = true; + DataFromAnotherDeviceDetected?.Invoke(); + OnPossibleForeignSavesDetected?.Invoke(); + } +#pragma warning restore 618 + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs.meta new file mode 100644 index 0000000..6713245 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Storage/Prefs/ObscuredPrefs.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6bf8f5de6da8c8e49a2a9db7717a3624 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time.meta new file mode 100644 index 0000000..a680a9c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 6de18cf7b50ad184991cf3d8042a9a5c +folderAsset: yes +timeCreated: 1556318424 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs new file mode 100644 index 0000000..9268e49 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs @@ -0,0 +1,260 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Time +{ + using Common; + using Detectors; + using UnityEngine; + using UnityEngine.SceneManagement; + using Utils; + + /// + /// Speed-hack resistant %Time.* alternative. + /// Does proxies to the regular %Time.* APIs until actual speed hack is detected. + /// + /// Requires running \ref CodeStage.AntiCheat.Detectors.SpeedHackDetector "SpeedHackDetector" to operate properly. Make sure to start SpeedHackDetector before calling Init().
+ /// Uses Unity's %Time.* APIs until speed hack is detected and switches to the speed-hack resistant time since then. + /// May be unreliable in WebGL and other sandboxed environments. + [AddComponentMenu("")] + [DisallowMultipleComponent] + public class SpeedHackProofTime : KeepAliveBehaviour + { + private static bool inited; + private static bool speedHackDetected; + + private static float reliableTime; + private static float reliableDeltaTime; + private static float reliableUnscaledTime; + private static float reliableUnscaledDeltaTime; + private static float reliableRealtimeSinceStartup; + private static float reliableTimeSinceLevelLoad; + + private static bool warningShot; + + private long currentReliableTicks; + private long lastFrameReliableTicks; + private long reliableTicksDelta; + + #region Unity Events + + private void Update() + { + if (!speedHackDetected) + { + UpdateTimeValuesFromUnityTime(); + } + else + { + currentReliableTicks = TimeUtils.GetReliableTicks(); + reliableTicksDelta = currentReliableTicks - lastFrameReliableTicks; + + UpdateReliableTimeValues(); + } + } + + #endregion + + /// + /// Call to add to the scene and force internal initialization. Gets called automatically when necessary if not initialized. + /// + /// Make sure to call it after you setup and run \ref CodeStage.AntiCheat.Detectors.SpeedHackDetector "SpeedHackDetector". + public static void Init() + { + inited = GetOrCreateInstance.InitInternal(); + } + + /// + /// Call to remove from scene and clean internal resources. + /// + public static void Dispose() + { + inited = false; + + if (Instance == null) + { + return; + } + + var detectorInstance = SpeedHackDetector.Instance; + if (detectorInstance != null) + { + detectorInstance.CheatDetected -= Instance.OnSpeedHackDetected; + } + + Destroy(Instance.gameObject); + } + + /// + /// Speed-hack resistant analogue on Unity's %Time.time API. + /// + public static float time + { + get + { + if (!inited) + { + Init(); + } + + return speedHackDetected ? reliableTime : Time.time; + } + } + + /// + /// Speed-hack resistant analogue on Unity's %Time.unscaledTime API. + /// + public static float unscaledTime + { + get + { + if (!inited) + { + Init(); + } + + return speedHackDetected ? reliableUnscaledTime : Time.unscaledTime; + } + } + + /// + /// Speed-hack resistant analogue on Unity's %Time.deltaTime API. + /// + public static float deltaTime + { + get + { + if (!inited) + { + Init(); + } + + return speedHackDetected ? reliableDeltaTime : Time.deltaTime; + } + } + + /// + /// Speed-hack resistant analogue on Unity's %Time.unscaledDeltaTime API. + /// + public static float unscaledDeltaTime + { + get + { + if (!inited) + { + Init(); + } + + return speedHackDetected ? reliableUnscaledDeltaTime : Time.unscaledDeltaTime; + } + } + + /// + /// Speed-hack resistant analogue on Unity's %Time.realtimeSinceStartup API. + /// + public static float realtimeSinceStartup + { + get + { + if (!inited) + { + Init(); + } + + return speedHackDetected ? reliableRealtimeSinceStartup : Time.realtimeSinceStartup; + } + } + + /// + /// Speed-hack resistant analogue on Unity's %Time.timeSinceLevelLoad API. + /// + public static float timeSinceLevelLoad + { + get + { + if (!inited) + { + Init(); + } + + return speedHackDetected ? reliableTimeSinceLevelLoad : Time.timeSinceLevelLoad; + } + } + + private bool InitInternal() + { + var detectorInstance = SpeedHackDetector.Instance; + if (detectorInstance == null) + { + if (!warningShot) + { + Debug.LogWarning(ACTk.LogPrefix + + "Can't initialize SpeedHackProofTime class since it requires running SpeedHackDetector instance which was not found. " + + "Did you started SpeedHackDetector before using SpeedHackProofTime?\n" + + "SpeedHackProofTime will use unreliable vanilla Time.* APIs until you start SpeedHackDetector."); + warningShot = true; + } + + return false; + } + + if (!detectorInstance.IsRunning) + { + if (!warningShot) + { + Debug.LogWarning(ACTk.LogPrefix + + "Can't initialize SpeedHackProofTime class since it requires running SpeedHackDetector instance but only idle instance was found. " + + "Did you started SpeedHackDetector before using SpeedHackProofTime?\n" + + "SpeedHackProofTime will use unreliable vanilla Time.* APIs until you start SpeedHackDetector."); + warningShot = true; + } + + return false; + } + + detectorInstance.CheatDetected += OnSpeedHackDetected; + return true; + } + + private void UpdateTimeValuesFromUnityTime() + { + reliableTime = Time.time; + reliableDeltaTime = Time.deltaTime; + + reliableUnscaledTime = Time.unscaledTime; + reliableUnscaledDeltaTime = Time.unscaledDeltaTime; + + reliableTimeSinceLevelLoad = Time.timeSinceLevelLoad; + reliableRealtimeSinceStartup = Time.realtimeSinceStartup; + } + + private void UpdateReliableTimeValues() + { + lastFrameReliableTicks = currentReliableTicks; + + reliableUnscaledDeltaTime = (float)reliableTicksDelta / TimeUtils.TicksPerSecond; + reliableDeltaTime = reliableUnscaledDeltaTime * Time.timeScale; + + reliableTime += reliableDeltaTime; + reliableUnscaledTime += reliableUnscaledDeltaTime; + reliableRealtimeSinceStartup += reliableUnscaledDeltaTime; + reliableTimeSinceLevelLoad += reliableDeltaTime; + } + + private void OnSpeedHackDetected() + { + speedHackDetected = true; + lastFrameReliableTicks = TimeUtils.GetReliableTicks(); + } + + protected override void OnSceneLoaded(Scene scene, LoadSceneMode mode) + { + base.OnSceneLoaded(scene, mode); + + reliableTimeSinceLevelLoad = 0; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs.meta new file mode 100644 index 0000000..7a6b1e6 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Time/SpeedHackProofTime.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 412e16d0fa167194389bfb6445d52a7d +timeCreated: 1556318424 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils.meta new file mode 100644 index 0000000..d9dc971 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b0fc418f659fbf140875f58cbcdf714f +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs new file mode 100644 index 0000000..85cbd06 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs @@ -0,0 +1,47 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +#if UNITY_ANDROID + +using System; +using CodeStage.AntiCheat.Common; +using UnityEngine; + +namespace CodeStage.AntiCheat.Utils +{ + internal static class AndroidRoutines + { + private const string RoutinesClassPath = "net.codestage.actk.androidnative.ACTkAndroidRoutines"; + + private static readonly Lazy RoutinesClass = new Lazy(InitJavaClass); + + public static long GetSystemNanoTime() + { + return RoutinesClass.Value?.CallStatic("GetSystemNanoTime") ?? DateTime.UtcNow.Ticks; + } + + public static string GetPackageInstallerName() + { + return RoutinesClass.Value?.CallStatic("GetPackageInstallerName"); + } + + private static AndroidJavaClass InitJavaClass() + { + try + { + return new AndroidJavaClass(RoutinesClassPath); + } + catch (Exception e) + { + ACTk.PrintExceptionForSupport($"Couldn't create instance of the {nameof(AndroidJavaClass)}: {RoutinesClassPath}!\n" + + "Please make sure you are not obfuscating public ACTk's Java Plugin classes.", e); + } + return null; + } + } +} + +#endif \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs.meta new file mode 100644 index 0000000..8cb01cb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AndroidRoutines.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1c0ad8ceca64396819c4c567ee0c78f +timeCreated: 1681999141 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs new file mode 100644 index 0000000..4fd48eb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs @@ -0,0 +1,49 @@ +#region copyright +// ------------------------------------------------------- +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------- +#endregion + +namespace CodeStage.AntiCheat.Utils +{ + using UnityEngine; + + internal class AppEventsDispatcher : MonoBehaviour + { + public delegate void ApplicationFocusEventHandler(bool hasFocus); + public delegate void ApplicationPauseEventHandler(bool pauseStatus); + + public event ApplicationFocusEventHandler ApplicationFocused; + public event ApplicationPauseEventHandler ApplicationPaused; + + private static AppEventsDispatcher instance; + public static AppEventsDispatcher Instance + { + get + { + if (instance == null) + { + instance = new GameObject("[ACTk] " + nameof(AppEventsDispatcher)).AddComponent(); + } + + return instance; + } + } + + private void Awake() + { + gameObject.hideFlags = HideFlags.HideInHierarchy; + DontDestroyOnLoad(transform.root.gameObject); + } + + private void OnApplicationFocus(bool hasFocus) + { + ApplicationFocused?.Invoke(hasFocus); + } + + private void OnApplicationPause(bool pauseStatus) + { + ApplicationPaused?.Invoke(pauseStatus); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs.meta new file mode 100644 index 0000000..e62fc69 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/AppEventsDispatcher.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 80ad1116523d402784d923a4c7b71cdd +timeCreated: 1649619416 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs new file mode 100644 index 0000000..bf2074d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs @@ -0,0 +1,40 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Utils +{ + using System; + + internal static class Base64Utils + { + public static string FromBase64ToString(string value) + { + return StringUtils.BytesToString(Convert.FromBase64String(value)); + } + + public static char[] FromBase64ToChars(string value) + { + return StringUtils.BytesToChars(Convert.FromBase64String(value)); + } + + public static string ToBase64(string value) + { + if (string.IsNullOrEmpty(value)) + throw new ArgumentNullException(nameof(value)); + + return Convert.ToBase64String(StringUtils.StringToBytes(value)); + } + + public static string ToBase64(char[] value) + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + return Convert.ToBase64String(StringUtils.CharsToBytes(value)); + } + + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs.meta new file mode 100644 index 0000000..e4af372 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/Base64Utils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a63abd32feb4085af3cd6e18e162b0c +timeCreated: 1556986892 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs new file mode 100644 index 0000000..b501e63 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs @@ -0,0 +1,98 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Utils +{ + using System; + using System.IO; + using System.Security.Cryptography; + + internal static class CryptoUtils + { + private const int BufferSize = 81920; + private const byte Iterations = 10; + + private const byte AesSaltLengthBytes = 16; + private const byte AesKeyLengthBytes = 16; + + private const byte Rc2SaltLengthBytes = 8; + private const byte Rc2KeyLengthBytes = 7; + + public static void EncryptAes(Stream input, Stream output, byte[] password) + { + EncryptInternal(input, output, password, AesKeyLengthBytes); + } + + public static void DecryptAes(Stream input, Stream output, byte[] password) + { + DecryptInternal(input, output, password, AesKeyLengthBytes, AesSaltLengthBytes); + } + + public static void EncryptRc2(Stream input, Stream output, byte[] password) + { + EncryptInternal(input, output, password, Rc2KeyLengthBytes); + } + + public static void DecryptRc2(Stream input, Stream output, byte[] password) + { + DecryptInternal(input, output, password, Rc2KeyLengthBytes, Rc2SaltLengthBytes); + } + + private static void EncryptInternal(Stream input, Stream output, byte[] password, byte keyLength) where T : SymmetricAlgorithm, new() + { + using (var crypto = new T()) + { + crypto.GenerateIV(); + var salt = crypto.IV; + + using (var key = new Rfc2898DeriveBytes(password, salt, Iterations)) + { + crypto.Key = key.GetBytes(keyLength); + } + + output.Write(salt, 0, salt.Length); + + using (var encryptor = crypto.CreateEncryptor()) + { + using (var cryptoStream = new CryptoStream(output, encryptor, CryptoStreamMode.Write)) + { + input.CopyTo(cryptoStream, BufferSize); + } + } + } + } + + private static void DecryptInternal(Stream input, Stream output, byte[] password, byte keyLength, byte saltLength) where T : SymmetricAlgorithm, new() + { + try + { + using (var crypto = new T()) + { + var salt = new byte[saltLength]; + input.Read(salt, 0, saltLength); + crypto.IV = salt; + + using (var key = new Rfc2898DeriveBytes(password, salt, Iterations)) + { + crypto.Key = key.GetBytes(keyLength); + } + + using(var decryptor = crypto.CreateDecryptor()) + { + using (var cryptoStream = new CryptoStream(input, decryptor, CryptoStreamMode.Read)) + { + cryptoStream.CopyTo(output, BufferSize); + } + } + } + } + catch (Exception e) + { + throw new CryptographicException("Something went wrong while trying to decrypt data!", e); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs.meta new file mode 100644 index 0000000..26dbf41 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/CryptoUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f8b626810c114798800a9bb7c101e0a0 +timeCreated: 1620002701 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs new file mode 100644 index 0000000..2efae0c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs @@ -0,0 +1,19 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using UnityEngine.Networking; + +namespace CodeStage.AntiCheat.Utils +{ + internal class NonValidatingCertificateHandler : CertificateHandler + { + // using this to bypass possible ssl errors, i.e. due way too wrong time + protected override bool ValidateCertificate(byte[] certificateData) + { + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs.meta new file mode 100644 index 0000000..280b91e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NonValidatingCertificateHandler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e30989f05f4c4f648ac37eb1393e20e7 +timeCreated: 1657655872 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs new file mode 100644 index 0000000..1daf6be --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs @@ -0,0 +1,18 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; + +namespace CodeStage.AntiCheat.Utils +{ + internal static class NumUtils + { + public static bool CompareFloats(float f1, float f2, float epsilon = float.Epsilon) + { + return f1.Equals(f2) || Math.Abs(f1 - f2) < epsilon; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs.meta new file mode 100644 index 0000000..c4de776 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/NumUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7e877a2da4bf4ace8b8d92b9e3a3daf3 +timeCreated: 1667738122 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs new file mode 100644 index 0000000..1b06403 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs @@ -0,0 +1,28 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using CodeStage.AntiCheat.Genuine.CodeHash; + +namespace CodeStage.AntiCheat.Utils +{ + internal static class ProgressExtensionMethods + { + public static void ReportPercent(this IProgress progress, ref int latestPercent, int filesChecked, long count, string currentFile) + { + if (progress == null) + return; + + var progressPercent = (float)filesChecked / count; + var intPercent = (int)Math.Floor(progressPercent * 100); + if (latestPercent < intPercent) + { + latestPercent = intPercent; + progress.Report(FilesProgress.Step(latestPercent, currentFile)); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs.meta new file mode 100644 index 0000000..0ce4f4e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ProgressExtensionMethods.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8acb09078aef4ba98ac831c94944e1a2 +timeCreated: 1682620618 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs new file mode 100644 index 0000000..d25ded0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs @@ -0,0 +1,82 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Utils +{ + internal static class RandomUtils + { + public static string GenerateRandomString(int length) + { + var stringChars = new char[length]; + GenerateCharArrayKey(ref stringChars); + + return new string(stringChars); + } + + internal static byte GenerateByteKey() + { + return (byte)ThreadSafeRandom.Next(100, 255); + } + + internal static sbyte GenerateSByteKey() + { + return (sbyte)ThreadSafeRandom.Next(100, 127); + } + + internal static char GenerateCharKey() + { + return (char)ThreadSafeRandom.Next(10000, 60000); + } + + internal static short GenerateShortKey() + { + return (short)ThreadSafeRandom.Next(10000, short.MaxValue); + } + + internal static ushort GenerateUShortKey() + { + return (ushort)ThreadSafeRandom.Next(10000, ushort.MaxValue); + } + + internal static int GenerateIntKey() + { + return ThreadSafeRandom.Next(1000000000, int.MaxValue); + } + + internal static uint GenerateUIntKey() + { + return (uint)GenerateIntKey(); + } + + internal static long GenerateLongKey() + { +#if !ACTK_US_EXPORT_COMPATIBLE + return ThreadSafeRandom.NextLong(1000000000000000000, long.MaxValue); +#else + return GenerateIntKey(); +#endif + } + + internal static ulong GenerateULongKey() + { + return (ulong)GenerateLongKey(); + } + + internal static void GenerateCharArrayKey(ref char[] arrayToFill) + { + if (arrayToFill == null) + { + arrayToFill = new char[7]; + } + else if (arrayToFill.Length < 7) + { + arrayToFill = new char[7]; + } + + ThreadSafeRandom.NextChars(arrayToFill); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs.meta new file mode 100644 index 0000000..a2822e5 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/RandomUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 961e7678dbb74bf1aac1f220ce9f4ad3 +timeCreated: 1558131800 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs new file mode 100644 index 0000000..63d15b9 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs @@ -0,0 +1,58 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Utils +{ + using System.Text; + + /// + /// Contains few utility methods for string operations used by ACTk. + /// + /// Not intended for usage from user code, + /// touch at your peril since API can change and break backwards compatibility! + public static class StringUtils + { + private static readonly char[] HexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + public static byte[] CharsToBytes(char[] input) + { + return Encoding.UTF8.GetBytes(input); + } + + public static byte[] StringToBytes(string input) + { + return input == null ? null : Encoding.UTF8.GetBytes(input); + } + + public static char[] BytesToChars(byte[] input) + { + return Encoding.UTF8.GetChars(input); + } + + public static string BytesToString(byte[] input) + { + return Encoding.UTF8.GetString(input); + } + + public static string BytesToString(byte[] input, int index, int count) + { + return Encoding.UTF8.GetString(input, index, count); + } + + public static string HashBytesToHexString(byte[] input) + { + var hexChars = new char[input.Length * 2]; + for (var i = 0; i < input.Length; i++) + { + var v = (input[i] ^ 144) & 0xFF; + hexChars[i * 2] = HexArray[(uint)v >> 4]; + hexChars[i * 2 + 1] = HexArray[v & 0x0F]; + } + + return new string(hexChars); + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs.meta new file mode 100644 index 0000000..5876983 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/StringUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 94dadaebdbbc4a90997d87b8b9ce7c41 +timeCreated: 1558133276 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs new file mode 100644 index 0000000..894b6e4 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs @@ -0,0 +1,41 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System; +using System.Collections.Concurrent; + +namespace CodeStage.AntiCheat.Utils +{ + public class ThreadSafeDisposablesPool where T : IDisposable, new() + { + private readonly ConcurrentBag objects; + private readonly Func objectGenerator; + + public ThreadSafeDisposablesPool(Func objectGenerator) + { + this.objectGenerator = objectGenerator ?? throw new ArgumentNullException(nameof(objectGenerator)); + objects = new ConcurrentBag(); + } + + public T Get() + { + return objects.TryTake(out T item) ? item : objectGenerator(); + } + + public void Release(T item) + { + objects.Add(item); + } + + public void Dispose() + { + while (objects.TryTake(out T item)) + { + item.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs.meta new file mode 100644 index 0000000..9943129 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeDisposablesPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 36a7cddae1a24aacb514e029fed03fa5 +timeCreated: 1682495385 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs new file mode 100644 index 0000000..db7717a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs @@ -0,0 +1,148 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Utils +{ + using System; + + /// + /// Random utility which can be used from background threads. + /// + public static class ThreadSafeRandom + { + private static readonly Random Global = new Random(); + + [ThreadStatic] + private static Random local; + + /// + /// Generates random int number within specified range. + /// + /// Minimal value, inclusive. + /// Maximum value, exclusive. + /// Random value in specified range. + public static int Next(int minInclusive, int maxExclusive) + { + var inst = local; + + if (inst != null) + { + return inst.Next(minInclusive, maxExclusive); + } + + int seed; + + lock (Global) + { + seed = Global.Next(); + } + + local = inst = new Random(seed); + return inst.Next(minInclusive, maxExclusive); + } + + /// + /// Generates random long number within specified range. + /// + /// Minimal value, inclusive. + /// Maximum value, exclusive. + /// Random value in specified range. + public static long NextLong(long minInclusive, long maxExclusive) + { + var inst = local; + + if (inst != null) + { + return NextLong(inst, minInclusive, maxExclusive); + } + + int seed; + + lock (Global) + { + seed = Global.Next(); + } + + local = inst = new Random(seed); + return NextLong(inst, minInclusive, maxExclusive); + } + + /// + /// Fills passed buffer with random bytes. + /// + /// Buffer filled with random bytes. + public static void NextBytes(byte[] buffer) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer)); + + var inst = local; + + if (inst != null) + { + inst.NextBytes(buffer); + return; + } + + int seed; + + lock (Global) + { + seed = Global.Next(); + } + + local = inst = new Random(seed); + inst.NextBytes(buffer); + } + + /// + /// Fills passed buffer with random char values. + /// + /// Buffer filled with random char values. + public static void NextChars(char[] buffer) + { + if (buffer == null) + throw new ArgumentNullException(nameof(buffer)); + + var inst = local; + + if (inst != null) + { + NextChars(inst, buffer); + return; + } + + int seed; + + lock (Global) + { + seed = Global.Next(); + } + + local = inst = new Random(seed); + NextChars(inst, buffer); + } + + private static long NextLong(Random random, long minInclusive, long maxExclusive) + { + var result = (long)random.Next((int)(minInclusive >> 32), (int)(maxExclusive >> 32)); + result <<= 32; + result |= (uint)random.Next((int)minInclusive, (int)maxExclusive); + return result; + } + + private static void NextChars(Random random, char[] buffer) + { + for (var i = 0; i < buffer.Length; ++i) + { + // capping to byte value here to not exceed + // 56 bit crypto keys length requirement by + // Apple to avoid cryptography declaration + buffer[i] = (char) (random.Next() % 256); + } + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs.meta new file mode 100644 index 0000000..8acf5f2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/ThreadSafeRandom.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8e4d27a9c75b48ca82b4eee37273f1b2 +timeCreated: 1552380891 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs new file mode 100644 index 0000000..c965f1e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs @@ -0,0 +1,92 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +#if UNITY_WEBGL && !UNITY_EDITOR +#define ACTK_WEBGL_BUILD +#endif + +namespace CodeStage.AntiCheat.Utils +{ + using System; + using UnityEngine; + + internal static class TimeUtils + { + public const long TicksPerSecond = TimeSpan.TicksPerMillisecond * 1000; + + /// + /// Gets speed hacks unbiased current time ticks. + /// + /// Reliable current time in ticks. + public static long GetReliableTicks() + { + long ticks = 0; + +#if !UNITY_EDITOR +#if UNITY_ANDROID + ticks = TryReadTicksFromAndroidRoutine(); +#elif ACTK_WEBGL_BUILD + ticks = TryReadTicksFromWebGLRoutine(); +#endif +#endif + if (ticks == 0) + ticks = DateTime.UtcNow.Ticks; + + return ticks; + } + + public static long GetEnvironmentTicks() + { + return Environment.TickCount * TimeSpan.TicksPerMillisecond; + } + + public static long GetRealtimeTicks() + { + return (long)(Time.realtimeSinceStartup * TicksPerSecond); + } + + public static long GetDspTicks() + { +#if UNITY_AUDIO_MODULE + return (long)(AudioSettings.dspTime * TicksPerSecond); +#else + return 0; +#endif + } + +#if UNITY_ANDROID + private static long TryReadTicksFromAndroidRoutine() + { + long result = 0; + + try + { + // getting time in nanoseconds from the native Android timer + // since some random fixed and JVM initialization point + // (it even may be a future so value could be negative) + result = AndroidRoutines.GetSystemNanoTime(); + result /= 100; + } + catch (Exception e) + { + Common.ACTk.PrintExceptionForSupport("Couldn't call static method from the Android Routines Class!", e); + } + + return result; + } + +#elif ACTK_WEBGL_BUILD + [System.Runtime.InteropServices.DllImport("__Internal")] + private static extern double GetUTCTicks(); + + private static long TryReadTicksFromWebGLRoutine() + { + var ticks = (long)GetUTCTicks(); + return ticks < 0 ? 0 : ticks; + } +#endif + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs.meta new file mode 100644 index 0000000..44140a3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/TimeUtils.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: c07c3153d9ad3cd48b72fc51968c3760 +timeCreated: 1556312318 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs new file mode 100644 index 0000000..fa44fb8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs @@ -0,0 +1,195 @@ +/* +xxHashSharp - A pure C# implementation of xxhash +Copyright (C) 2014, Seok-Ju, Yun. (https://github.com/noricube/xxHashSharp) +Specific optimization, Stream version and inlining by Dmitriy Yukhanov (https://codestage.net) +Original C Implementation Copyright (C) 2012-2014, Yann Collet. (https://code.google.com/p/xxhash/) +BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +namespace CodeStage.AntiCheat.Utils +{ + using System.IO; + + /// + /// A little bit changed xxHashSharp implementation. + /// Original Copyright (C) 2014, Seok-Ju, Yun. (https://github.com/noricube/xxHashSharp) + /// + /// Not intended for usage from user code, + /// touch at your peril since API can change and break backwards compatibility! + public static class xxHash + { + private const uint PRIME32_1 = 2654435761U; + private const uint PRIME32_2 = 2246822519U; + private const uint PRIME32_3 = 3266489917U; + private const uint PRIME32_4 = 668265263U; + private const uint PRIME32_5 = 374761393U; + + public static uint CalculateHash(byte[] buf, int len, uint seed) + { + uint h32; + int index = 0; + + if (len >= 16) + { + int limit = len - 16; + uint v1 = seed + PRIME32_1 + PRIME32_2; + uint v2 = seed + PRIME32_2; + uint v3 = seed; + uint v4 = seed - PRIME32_1; + + do + { + uint read_value = (uint)(buf[index++] | buf[index++] << 8 | buf[index++] << 16 | buf[index++] << 24); + v1 += read_value * PRIME32_2; + v1 = (v1 << 13) | (v1 >> 19); + v1 *= PRIME32_1; + + read_value = (uint)(buf[index++] | buf[index++] << 8 | buf[index++] << 16 | buf[index++] << 24); + v2 += read_value * PRIME32_2; + v2 = (v2 << 13) | (v2 >> 19); + v2 *= PRIME32_1; + + read_value = (uint)(buf[index++] | buf[index++] << 8 | buf[index++] << 16 | buf[index++] << 24); + v3 += read_value * PRIME32_2; + v3 = (v3 << 13) | (v3 >> 19); + v3 *= PRIME32_1; + + read_value = (uint)(buf[index++] | buf[index++] << 8 | buf[index++] << 16 | buf[index++] << 24); + v4 += read_value * PRIME32_2; + v4 = (v4 << 13) | (v4 >> 19); + v4 *= PRIME32_1; + + } while (index <= limit); + + h32 = ((v1 << 1) | (v1 >> 31)) + ((v2 << 7) | (v2 >> 25)) + ((v3 << 12) | (v3 >> 20)) + ((v4 << 18) | (v4 >> 14)); + } + else + { + h32 = seed + PRIME32_5; + } + + h32 += (uint)len; + + while (index <= len - 4) + { + h32 += (uint)(buf[index++] | buf[index++] << 8 | buf[index++] << 16 | buf[index++] << 24) * PRIME32_3; + h32 = ((h32 << 17) | (h32 >> 15)) * PRIME32_4; + } + + while (index < len) + { + h32 += buf[index] * PRIME32_5; + h32 = ((h32 << 11) | (h32 >> 21)) * PRIME32_1; + index++; + } + + h32 ^= h32 >> 15; + h32 *= PRIME32_2; + h32 ^= h32 >> 13; + h32 *= PRIME32_3; + h32 ^= h32 >> 16; + + return h32; + } + + public static uint CalculateHash(Stream buf, long len, uint seed) + { + uint h32; + var index = 0; + buf.Position = 0; + + if (len >= 16) + { + var limit = len - 16; + var v1 = seed + PRIME32_1 + PRIME32_2; + var v2 = seed + PRIME32_2; + var v3 = seed; + var v4 = seed - PRIME32_1; + + do + { + var read_value = (uint)(buf.ReadByte() | buf.ReadByte() << 8 | buf.ReadByte() << 16 | buf.ReadByte() << 24); + index += 4; + + v1 += read_value * PRIME32_2; + v1 = (v1 << 13) | (v1 >> 19); + v1 *= PRIME32_1; + + read_value = (uint)(buf.ReadByte() | buf.ReadByte() << 8 | buf.ReadByte() << 16 | buf.ReadByte() << 24); + index += 4; + + v2 += read_value * PRIME32_2; + v2 = (v2 << 13) | (v2 >> 19); + v2 *= PRIME32_1; + + read_value = (uint)(buf.ReadByte() | buf.ReadByte() << 8 | buf.ReadByte() << 16 | buf.ReadByte() << 24); + index += 4; + v3 += read_value * PRIME32_2; + v3 = (v3 << 13) | (v3 >> 19); + v3 *= PRIME32_1; + + read_value = (uint)(buf.ReadByte() | buf.ReadByte() << 8 | buf.ReadByte() << 16 | buf.ReadByte() << 24); + index += 4; + v4 += read_value * PRIME32_2; + v4 = (v4 << 13) | (v4 >> 19); + v4 *= PRIME32_1; + + } while (index <= limit); + + h32 = ((v1 << 1) | (v1 >> 31)) + ((v2 << 7) | (v2 >> 25)) + ((v3 << 12) | (v3 >> 20)) + ((v4 << 18) | (v4 >> 14)); + } + else + { + h32 = seed + PRIME32_5; + } + + h32 += (uint)len; + + while (index <= len - 4) + { + h32 += (uint)(buf.ReadByte() | buf.ReadByte() << 8 | buf.ReadByte() << 16 | buf.ReadByte() << 24) * PRIME32_3; + index += 4; + h32 = ((h32 << 17) | (h32 >> 15)) * PRIME32_4; + } + + while (index < len) + { + h32 += (byte)buf.ReadByte() * PRIME32_5; + h32 = ((h32 << 11) | (h32 >> 21)) * PRIME32_1; + index++; + } + + h32 ^= h32 >> 15; + h32 *= PRIME32_2; + h32 ^= h32 >> 13; + h32 *= PRIME32_3; + h32 ^= h32 >> 16; + + buf.Position = 0; + + return h32; + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs.meta new file mode 100644 index 0000000..997afa2 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Utils/xxHash.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: ca55307c6e2ac774987295514b80aa65 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders.meta new file mode 100644 index 0000000..9f2e0b0 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 01bd3305f71f4544aa9db9079f88e4ce +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader new file mode 100644 index 0000000..2af6a6a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader @@ -0,0 +1,45 @@ +Shader "Hidden/ACTk/WallHackTexture" { + Properties { + _MainTex ("Base (RGB)", 2D) = "white" {} + } + + SubShader { + Tags { "RenderType"="Opaque" "Queue" = "Transparent" } + LOD 100 + Fog { Mode Off } + Pass { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + + struct appdata_t { + float4 vertex : POSITION; + float2 texcoord : TEXCOORD0; + }; + + struct v2f { + float4 vertex : SV_POSITION; + half2 texcoord : TEXCOORD0; + }; + + sampler2D _MainTex; + float4 _MainTex_ST; + + v2f vert (appdata_t v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex); + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + fixed4 col = tex2D(_MainTex, i.texcoord); + return col; + } + ENDCG + } + } +} \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader.meta new file mode 100644 index 0000000..9ab7aeb --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Shaders/WallHackTexture.shader.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: daa473204a35ad242922f896f206d931 +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt b/Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt new file mode 100644 index 0000000..ca3a5fd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt @@ -0,0 +1,5 @@ +Asset uses these third-party software: +- xxHashSharp under BSD 2-Clause License + - used both in Runtime and Editor +- SharpZipLib under MIT License + - used only in Editor \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt.meta new file mode 100644 index 0000000..9f88d51 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Third-Party Notices.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bea83117fdebb0a468c22e747faaf69f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant.meta b/Assets/Plugins/Demigiant.meta new file mode 100644 index 0000000..3cc5559 --- /dev/null +++ b/Assets/Plugins/Demigiant.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 224c39b6dc0929243b3223116fa09c57 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTween.meta b/Assets/Plugins/Demigiant/DOTween.meta new file mode 100644 index 0000000..cbebc39 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween.meta @@ -0,0 +1,21 @@ +fileFormatVersion: 2 +guid: a50bd9a009c8dfc4ebd88cc8101225a7 +labels: +- Tween +- Tweening +- Animation +- HOTween +- Paths +- iTween +- DFTween +- LeanTween +- Ease +- Easing +- Shake +- Punch +- 2DToolkit +- TextMeshPro +- Text +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/DOTween.XML b/Assets/Plugins/Demigiant/DOTween/DOTween.XML new file mode 100644 index 0000000..ceb16e4 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/DOTween.XML @@ -0,0 +1,3077 @@ + + + + DOTween + + + + + Types of autoPlay behaviours + + + + No tween is automatically played + + + Only Sequences are automatically played + + + Only Tweeners are automatically played + + + All tweens are automatically played + + + + What axis to constrain in case of Vector tweens + + + + Called the first time the tween is set in a playing state, after any eventual delay + + + + Used in place of System.Func, which is not available in mscorlib. + + + + + Used in place of System.Action. + + + + + Public so it can be used by lose scripts related to DOTween (like DOTweenAnimation) + + + + + Used to separate DOTween class from the MonoBehaviour instance (in order to use static constructors on DOTween). + Contains all instance-based methods + + + + Used internally inside Unity Editor, as a trick to update DOTween's inspector at every frame + + + + Directly sets the current max capacity of Tweeners and Sequences + (meaning how many Tweeners and Sequences can be running at the same time), + so that DOTween doesn't need to automatically increase them in case the max is reached + (which might lead to hiccups when that happens). + Sequences capacity must be less or equal to Tweeners capacity + (if you pass a low Tweener capacity it will be automatically increased to match the Sequence's). + Beware: use this method only when there are no tweens running. + + Max Tweeners capacity. + Default: 200 + Max Sequences capacity. + Default: 50 + + + + This class contains a C# port of the easing equations created by Robert Penner (http://robertpenner.com/easing). + + + + + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity. + + + Current time (in frames or seconds). + + + Expected easing duration (in frames or seconds). + + Unused: here to keep same delegate for all ease types. + Unused: here to keep same delegate for all ease types. + + The eased value. + + + + + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity. + + + Current time (in frames or seconds). + + + Expected easing duration (in frames or seconds). + + Unused: here to keep same delegate for all ease types. + Unused: here to keep same delegate for all ease types. + + The eased value. + + + + + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration. + + + Current time (in frames or seconds). + + + Expected easing duration (in frames or seconds). + + Unused: here to keep same delegate for all ease types. + Unused: here to keep same delegate for all ease types. + + The eased value. + + + + + Returns a value between 0 and 1 (inclusive) based on the elapsed time and ease selected + + + + + Returns a value between 0 and 1 (inclusive) based on the elapsed time and ease selected + + + + + Used to interpret AnimationCurves as eases. + Public so it can be used by external ease factories + + + + + Behaviour in case a tween nested inside a Sequence fails and is captured by safe mode + + + + If the Sequence contains other elements, kill the failed tween but preserve the rest + + + Kill the whole Sequence + + + + Log types thrown by errors captured and prevented by safe mode + + + + No logs. NOT RECOMMENDED + + + Throw a normal log + + + Throw a warning log (default) + + + Throw an error log + + + + Additional notices passed to plugins when updating. + Public so it can be used by custom plugins. Internally, only PathPlugin uses it + + + + + None + + + + + Lets the plugin know that we restarted or rewinded + + + + + OnRewind callback behaviour (can only be set via DOTween's Utility Panel) + + + + + When calling Rewind or PlayBackwards/SmoothRewind, OnRewind callbacks will be fired only if the tween isn't already rewinded + + + + + When calling Rewind, OnRewind callbacks will always be fired, even if the tween is already rewinded. + When calling PlayBackwards/SmoothRewind instead, OnRewind callbacks will be fired only if the tween isn't already rewinded + + + + + When calling Rewind or PlayBackwards/SmoothRewind, OnRewind callbacks will always be fired, even if the tween is already rewinded + + + + + Public only so custom shortcuts can access some of these methods + + + + + INTERNAL: used by DO shortcuts and Modules to set special startup mode + + + + + INTERNAL: used by DO shortcuts and Modules to set the tween as blendable + + + + + INTERNAL: used by DO shortcuts and Modules to prevent a tween from using a From setup even if passed + + + + + Used to dispatch commands that need to be captured externally, usually by Modules + + + + + Various utils + + + + + Returns a Vector3 with z = 0 + + + + + Returns the 2D angle between two vectors + + + + + Returns a point on a circle with the given center and radius, + using Unity's circle coordinates (0° points up and increases clockwise) + + + + + Uses approximate equality on each axis instead of Unity's Vector3 equality, + because the latter fails (in some cases) when assigning a Vector3 to a transform.position and then checking it. + + + + + Looks for the type within all possible project assembly names + + + + NO-GC METHOD: changes the start value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + If bigger than 0 applies it as the new tween duration + + + NO-GC METHOD: changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + NO-GC METHOD: changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If bigger than 0 applies it as the new tween duration + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + NO-GC METHOD: changes the start and end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + The new end value + If bigger than 0 applies it as the new tween duration + + + + Struct that stores two colors (used for LineRenderer tweens) + + + + + Used for tween callbacks + + + + + Used for tween callbacks + + + + + Used for custom and animationCurve-based ease functions. Must return a value between 0 and 1. + + + + + Straight Quaternion plugin. Instead of using Vector3 values accepts Quaternion values directly. + Beware: doesn't work with LoopType.Incremental (neither directly nor if inside a LoopType.Incremental Sequence). + To use it, call DOTween.To with the plugin parameter overload, passing it PureQuaternionPlugin.Plug() as first parameter + (do not use any of the other public PureQuaternionPlugin methods): + DOTween.To(PureQuaternionPlugin.Plug(), ()=> myQuaternionProperty, x=> myQuaternionProperty = x, myQuaternionEndValue, duration); + + + + + Plug this plugin inside a DOTween.To call. + Example: + DOTween.To(PureQuaternionPlugin.Plug(), ()=> myQuaternionProperty, x=> myQuaternionProperty = x, myQuaternionEndValue, duration); + + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + + Extra non-tweening-related curve methods + + + + + Cubic bezier curve methods + + + + + Calculates a point along the given Cubic Bezier segment-curve. + + Segment start point + Start point's control point/handle + Segment end point + End point's control point/handle + 0-1 percentage along which to retrieve point + + + + Returns an array containing a series of points along the given Cubic Bezier segment-curve. + + Start point + Start point's control point/handle + End point + End point's control point/handle + Cloud resolution (min: 2) + + + + Calculates a series of points along the given Cubic Bezier segment-curve and adds them to the given list. + + Start point + Start point's control point/handle + End point + End point's control point/handle + Cloud resolution (min: 2) + + + + Main DOTween class. Contains static methods to create and control tweens in a generic way + + + + DOTween's version + + + If TRUE (default) makes tweens slightly slower but safer, automatically taking care of a series of things + (like targets becoming null while a tween is playing). + Default: TRUE + + + Log type when safe mode reports capturing an error and preventing it + + + Behaviour in case a tween nested inside a Sequence fails (and is caught by safe mode). + Default: NestedTweenFailureBehaviour.TryToPreserveSequence + + + If TRUE you will get a DOTween report when exiting play mode (only in the Editor). + Useful to know how many max Tweeners and Sequences you reached and optimize your final project accordingly. + Beware, this will slightly slow down your tweens while inside Unity Editor. + Default: FALSE + + + Global DOTween global timeScale (default: 1). + The final timeScale of a non-timeScaleIndependent tween is: + Unity's Time.timeScale * DOTween.timeScale * tween.timeScale + while the final timeScale of a timeScaleIndependent tween is: + DOTween.unscaledTimeScale * DOTween.timeScale * tween.timeScale + + + DOTween timeScale applied only to timeScaleIndependent tweens (default: 1). + The final timeScale of a timeScaleIndependent tween is: + DOTween.unscaledTimeScale * DOTween.timeScale * tween.timeScale + + + If TRUE, DOTween will use Time.smoothDeltaTime instead of Time.deltaTime for UpdateType.Normal and UpdateType.Late tweens + (unless they're set as timeScaleIndependent, in which case a value between the last timestep + and will be used instead). + Setting this to TRUE will lead to smoother animations. + Default: FALSE + + + If is TRUE, this indicates the max timeStep that an independent update call can last. + Setting this to TRUE will lead to smoother animations. + Default: FALSE + + + DOTween's log behaviour. + Default: LogBehaviour.ErrorsOnly + + + Used to intercept DOTween's logs. If this method isn't NULL, DOTween will call it before writing a log via Unity's own Debug log methods. + Return TRUE if you want DOTween to proceed with the log, FALSE otherwise. + This method must return a bool and accept two parameters: + - LogType: the type of Unity log that DOTween is trying to log + - object: the log message that DOTween wants to log + + + If TRUE draws path gizmos in Unity Editor (if the gizmos button is active). + Deactivate this if you want to avoid gizmos overhead while in Unity Editor + + + If TRUE activates various debug options + + + Stores the target id so it can be used to give more info in case of safeMode error capturing. + Only active if both debugMode and useSafeMode are TRUE + + + Default updateType for new tweens. + Default: UpdateType.Normal + + + Sets whether Unity's timeScale should be taken into account by default or not. + Default: false + + + Default autoPlay behaviour for new tweens. + Default: AutoPlay.All + + + Default autoKillOnComplete behaviour for new tweens. + Default: TRUE + + + Default loopType applied to all new tweens. + Default: LoopType.Restart + + + If TRUE all newly created tweens are set as recyclable, otherwise not. + Default: FALSE + + + Default ease applied to all new Tweeners (not to Sequences which always have Ease.Linear as default). + Default: Ease.InOutQuad + + + Default overshoot/amplitude used for eases + Default: 1.70158f + + + Default period used for eases + Default: 0 + + + Used internally. Assigned/removed by DOTweenComponent.Create/DestroyInstance + + + + Must be called once, before the first ever DOTween call/reference, + otherwise it will be called automatically and will use default options. + Calling it a second time won't have any effect. + You can chain SetCapacity to this method, to directly set the max starting size of Tweeners and Sequences: + DOTween.Init(false, false, LogBehaviour.Default).SetCapacity(100, 20); + + If TRUE all new tweens will be set for recycling, meaning that when killed, + instead of being destroyed, they will be put in a pool and reused instead of creating new tweens. This option allows you to avoid + GC allocations by reusing tweens, but you will have to take care of tween references, since they might result active + even if they were killed (since they might have been respawned and are now being used for other tweens). + If you want to automatically set your tween references to NULL when a tween is killed + you can use the OnKill callback like this: + .OnKill(()=> myTweenReference = null) + You can change this setting at any time by changing the static property, + or you can set the recycling behaviour for each tween separately, using: + SetRecyclable(bool recyclable) + Default: FALSE + If TRUE makes tweens slightly slower but safer, automatically taking care of a series of things + (like targets becoming null while a tween is playing). + You can change this setting at any time by changing the static property. + Default: FALSE + Type of logging to use. + You can change this setting at any time by changing the static property. + Default: ErrorsOnly + + + + Directly sets the current max capacity of Tweeners and Sequences + (meaning how many Tweeners and Sequences can be running at the same time), + so that DOTween doesn't need to automatically increase them in case the max is reached + (which might lead to hiccups when that happens). + Sequences capacity must be less or equal to Tweeners capacity + (if you pass a low Tweener capacity it will be automatically increased to match the Sequence's). + Beware: use this method only when there are no tweens running. + + Max Tweeners capacity. + Default: 200 + Max Sequences capacity. + Default: 50 + + + + Kills all tweens, clears all cached tween pools and plugins and resets the max Tweeners/Sequences capacities to the default values. + + If TRUE also destroys DOTween's gameObject and resets its initializiation, default settings and everything else + (so that next time you use it it will need to be re-initialized) + + + + Clears all cached tween pools. + + + + + Checks all active tweens to find and remove eventually invalid ones (usually because their targets became NULL) + and returns the total number of invalid tweens found and removed. + IMPORTANT: this will cause an error on UWP platform, so don't use it there + BEWARE: this is a slightly expensive operation so use it with care + + + + + Updates all tweens that are set to . + + Manual deltaTime + Unscaled delta time (used with tweens set as timeScaleIndependent) + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using a custom plugin + The plugin to use. Each custom plugin implements a static Get() method + you'll need to call to assign the correct plugin in the correct way, like this: + CustomPlugin.Get() + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens only one axis of a Vector3 to the given value using default plugins. + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + The axis to tween + + + Tweens only the alpha of a Color to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a virtual property from the given start to the given end value + and implements a setter that allows to use that value with an external method or a lambda + Example: + To(MyMethod, 0, 12, 0.5f); + Where MyMethod is a function that accepts a float parameter (which will be the result of the virtual tween) + The action to perform with the tweened value + The value to start from + The end value to reach + The duration of the virtual tween + + + + Punches a Vector3 towards the given direction and then back to the starting one + as if it was connected to the starting position via an elastic. + This tween type generates some GC allocations at startup + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The direction and strength of the punch + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards. + 1 creates a full oscillation between the direction and the opposite decaying direction, + while 0 oscillates only between the starting position and the decaying direction + + + Shakes a Vector3 with the given values. + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction and behave like a random punch. + If TRUE only shakes on the X Y axis (looks better with things like cameras). + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Vector3 with the given values. + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction and behave like a random punch. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Tweens a property or field to the given values using default plugins. + Ease is applied between each segment and not as a whole. + This tween type generates some GC allocations at startup + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end values to reach for each segment. This array must have the same length as durations + The duration of each segment. This array must have the same length as endValues + + + + Returns a new to be used for tween groups. + Mind that Sequences don't have a target applied automatically like Tweener creation shortcuts, + so if you want to be able to kill this Sequence when calling DOTween.Kill(target) you'll have to add + the target manually; you can do that directly by using the overload instead of this one + + + + + Returns a new to be used for tween groups, and allows to set a target + (because Sequences don't have their target set automatically like Tweener creation shortcuts). + That way killing/controlling tweens by target will apply to this Sequence too. + + The target of the Sequence. Relevant only for static target-based methods like DOTween.Kill(target), + useless otherwise + + + Completes all tweens and returns the number of actual tweens completed + (meaning tweens that don't have infinite loops and were not already complete) + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + Completes all tweens with the given ID or target and returns the number of actual tweens completed + (meaning the tweens that don't have infinite loops and were not already complete) + For Sequences only: if TRUE internal Sequence callbacks will be fired, + otherwise they will be ignored + + + Flips all tweens (changing their direction to forward if it was backwards and viceversa), + then returns the number of actual tweens flipped + + + Flips the tweens with the given ID or target (changing their direction to forward if it was backwards and viceversa), + then returns the number of actual tweens flipped + + + Sends all tweens to the given position (calculating also eventual loop cycles) and returns the actual tweens involved + + + Sends all tweens with the given ID or target to the given position (calculating also eventual loop cycles) + and returns the actual tweens involved + + + Kills all tweens and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + + + Kills all tweens and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + Eventual IDs or targets to exclude from the killing + + + Kills all tweens with the given ID or target and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + + + Kills all tweens with the given target and the given ID, and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + + + Pauses all tweens and returns the number of actual tweens paused + + + Pauses all tweens with the given ID or target and returns the number of actual tweens paused + (meaning the tweens that were actually playing and have been paused) + + + Plays all tweens and returns the number of actual tweens played + (meaning tweens that were not already playing or complete) + + + Plays all tweens with the given ID or target and returns the number of actual tweens played + (meaning the tweens that were not already playing or complete) + + + Plays all tweens with the given target and the given ID, and returns the number of actual tweens played + (meaning the tweens that were not already playing or complete) + + + Plays backwards all tweens and returns the number of actual tweens played + (meaning tweens that were not already started, playing backwards or rewinded) + + + Plays backwards all tweens with the given ID or target and returns the number of actual tweens played + (meaning the tweens that were not already started, playing backwards or rewinded) + + + Plays backwards all tweens with the given target and ID and returns the number of actual tweens played + (meaning the tweens that were not already started, playing backwards or rewinded) + + + Plays forward all tweens and returns the number of actual tweens played + (meaning tweens that were not already playing forward or complete) + + + Plays forward all tweens with the given ID or target and returns the number of actual tweens played + (meaning the tweens that were not already playing forward or complete) + + + Plays forward all tweens with the given target and ID and returns the number of actual tweens played + (meaning the tweens that were not already started, playing backwards or rewinded) + + + Restarts all tweens, then returns the number of actual tweens restarted + + + Restarts all tweens with the given ID or target, then returns the number of actual tweens restarted + If TRUE includes the eventual tweens delays, otherwise skips them + If >= 0 changes the startup delay of all involved tweens to this value, otherwise doesn't touch it + + + Restarts all tweens with the given target and the given ID, and returns the number of actual tweens played + (meaning the tweens that were not already playing or complete) + If TRUE includes the eventual tweens delays, otherwise skips them + If >= 0 changes the startup delay of all involved tweens to this value, otherwise doesn't touch it + + + Rewinds and pauses all tweens, then returns the number of actual tweens rewinded + (meaning tweens that were not already rewinded) + + + Rewinds and pauses all tweens with the given ID or target, then returns the number of actual tweens rewinded + (meaning the tweens that were not already rewinded) + + + Smoothly rewinds all tweens (delays excluded), then returns the number of actual tweens rewinding/rewinded + (meaning tweens that were not already rewinded). + A "smooth rewind" animates the tween to its start position, + skipping all elapsed loops (except in case of LoopType.Incremental) while keeping the animation fluent. + Note that a tween that was smoothly rewinded will have its play direction flipped + + + Smoothly rewinds all tweens (delays excluded) with the given ID or target, then returns the number of actual tweens rewinding/rewinded + (meaning the tweens that were not already rewinded). + A "smooth rewind" animates the tween to its start position, + skipping all elapsed loops (except in case of LoopType.Incremental) while keeping the animation fluent. + Note that a tween that was smoothly rewinded will have its play direction flipped + + + Toggles the play state of all tweens and returns the number of actual tweens toggled + (meaning tweens that could be played or paused, depending on the toggle state) + + + Toggles the play state of all tweens with the given ID or target and returns the number of actual tweens toggled + (meaning the tweens that could be played or paused, depending on the toggle state) + + + + Returns TRUE if a tween with the given ID or target is active. + You can also use this to know if a shortcut tween is active for a given target. + Example: + transform.DOMoveX(45, 1); // transform is automatically added as the tween target + DOTween.IsTweening(transform); // Returns true + + The target or ID to look for + If FALSE (default) returns TRUE as long as a tween for the given target/ID is active, + otherwise also requires it to be playing + + + + Returns the total number of active tweens (so both Tweeners and Sequences). + A tween is considered active if it wasn't killed, regardless if it's playing or paused + + + + + Returns the total number of active Tweeners. + A Tweener is considered active if it wasn't killed, regardless if it's playing or paused + + + + + Returns the total number of active Sequences. + A Sequence is considered active if it wasn't killed, regardless if it's playing or paused + + + + + Returns the total number of active and playing tweens. + A tween is considered as playing even if its delay is actually playing + + + + + Returns a the total number of active tweens with the given id. + + If TRUE returns only the tweens with the given ID that are currently playing + + + + Returns a list of all active tweens in a playing state. + Returns NULL if there are no active playing tweens. + Beware: each time you call this method a new list is generated, so use it for debug only + + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + Returns a list of all active tweens in a paused state. + Returns NULL if there are no active paused tweens. + Beware: each time you call this method a new list is generated, so use it for debug only + + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + Returns a list of all active tweens with the given id. + Returns NULL if there are no active tweens with the given id. + Beware: each time you call this method a new list is generated + + If TRUE returns only the tweens with the given ID that are currently playing + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + Returns a list of all active tweens with the given target. + Returns NULL if there are no active tweens with the given target. + Beware: each time you call this method a new list is generated + If TRUE returns only the tweens with the given target that are currently playing + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + + Creates virtual tweens that can be used to change other elements via their OnUpdate calls + + + + + Tweens a virtual float. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type float, called at each update + + + + Tweens a virtual int. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type int, called at each update + + + + Tweens a virtual Vector2. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type Vector3, called at each update + + + + Tweens a virtual Vector3. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type Vector3, called at each update + + + + Tweens a virtual Color. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type Color, called at each update + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual overshoot to use with Back ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual amplitude to use with Elastic easeType + Eventual period to use with Elastic easeType + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The AnimationCurve to use for ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual overshoot to use with Back ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual amplitude to use with Elastic easeType + Eventual period to use with Elastic easeType + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The AnimationCurve to use for ease + + + Fires the given callback after the given time. + Callback delay + Callback to fire when the delay has expired + If TRUE (default) ignores Unity's timeScale + + + + Don't assign this! It's assigned automatically when creating 0 duration tweens + + + + + Don't assign this! It's assigned automatically when setting the ease to an AnimationCurve or to a custom ease function + + + + + Allows to wrap ease method in special ways, adding extra features + + + + + Converts the given ease so that it also creates a stop-motion effect, by playing the tween at the given FPS + + FPS at which the tween should be played + Ease type + + + + Converts the given ease so that it also creates a stop-motion effect, by playing the tween at the given FPS + + FPS at which the tween should be played + AnimationCurve to use for the ease + + + + Converts the given ease so that it also creates a stop-motion effect, by playing the tween at the given FPS + + FPS at which the tween should be played + Custom ease function to use + + + + Used to allow method chaining with DOTween.Init + + + + + Directly sets the current max capacity of Tweeners and Sequences + (meaning how many Tweeners and Sequences can be running at the same time), + so that DOTween doesn't need to automatically increase them in case the max is reached + (which might lead to hiccups when that happens). + Sequences capacity must be less or equal to Tweeners capacity + (if you pass a low Tweener capacity it will be automatically increased to match the Sequence's). + Beware: use this method only when there are no tweens running. + + Max Tweeners capacity. + Default: 200 + Max Sequences capacity. + Default: 50 + + + + Behaviour that can be assigned when chaining a SetLink to a tween + + + + Pauses the tween when the link target is disabled + + + Pauses the tween when the link target is disabled, plays it when it's enabled + + + Pauses the tween when the link target is disabled, restarts it when it's enabled + + + Plays the tween when the link target is enabled + + + Restarts the tween when the link target is enabled + + + Kills the tween when the link target is disabled + + + Kills the tween when the link target is destroyed (becomes NULL). This is always active even if another behaviour is chosen + + + Completes the tween when the link target is disabled + + + Completes and kills the tween when the link target is disabled + + + Rewinds the tween (delay excluded) when the link target is disabled + + + Rewinds and kills the tween when the link target is disabled + + + + Path mode (used to determine correct LookAt orientation) + + + + Ignores the path mode (and thus LookAt behaviour) + + + Regular 3D path + + + 2D top-down path + + + 2D side-scroller path + + + + Type of path to use with DOPath tweens + + + + Linear, composed of straight segments between each waypoint + + + Curved path (which uses Catmull-Rom curves) + + + EXPERIMENTAL: Curved path (which uses Cubic Bezier curves, where each point requires two extra control points) + + + + Tweens a Vector2 along a circle. + EndValue represents the center of the circle, start and end value degrees are inside options + ChangeValue x is changeValue°, y is unused + + + + + Path control point + + + + + Path waypoints (modified by PathPlugin when setting relative end/change value or by CubicBezierDecoder) and by DOTweenPathInspector + + + + + Minimum input points necessary to create the path (doesn't correspond to actual waypoints required) + + + + + Gets the point on the path at the given percentage (0 to 1) + + The percentage (0 to 1) at which to get the point + If TRUE constant speed is taken into account, otherwise not + + + + Base interface for all tween plugins options + + + + Resets the plugin + + + + This plugin generates some GC allocations at startup + + + + + Path plugin works exclusively with Transforms + + + + + Rotation mode used with DORotate methods + + + + + Fastest way that never rotates beyond 360° + + + + + Fastest way that rotates beyond 360° + + + + + Adds the given rotation to the transform using world axis and an advanced precision mode + (like when using transform.Rotate(Space.World)). + In this mode the end value is is always considered relative + + + + + Adds the given rotation to the transform's local axis + (like when rotating an object with the "local" switch enabled in Unity's editor or using transform.Rotate(Space.Self)). + In this mode the end value is is always considered relative + + + + + Type of scramble to apply to string tweens + + + + + No scrambling of characters + + + + + A-Z + a-z + 0-9 characters + + + + + A-Z characters + + + + + a-z characters + + + + + 0-9 characters + + + + + Custom characters + + + + + Type of randomness to apply to a shake tween + + + + Default, full randomness + + + Creates a more balanced randomness that looks more harmonic + + + + Methods that extend Tween objects and allow to control or get data from them + + + + Completes the tween + + + Completes the tween + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + Flips the direction of this tween (backwards if it was going forward or viceversa) + + + Forces the tween to initialize its settings immediately + + + Send the tween to the given position in time + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + Send the tween to the given position in time while also executing any callback between the previous time position and the new one + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + Kills the tween + If TRUE completes the tween before killing it + + + + Forces this tween to update manually, regardless of the set via SetUpdate. + Note that the tween will still be subject to normal tween rules, so if for example it's paused this method will do nothing. + Also note that if you only want to update this tween instance manually you'll have to set it to anyway, + so that it's not updated automatically. + + Manual deltaTime + Unscaled delta time (used with tweens set as timeScaleIndependent) + + + Pauses the tween + + + Plays the tween + + + Sets the tween in a backwards direction and plays it + + + Sets the tween in a forward direction and plays it + + + Restarts the tween from the beginning + Ignored in case of Sequences. If TRUE includes the eventual tween delay, otherwise skips it + Ignored in case of Sequences. If >= 0 changes the startup delay to this value, otherwise doesn't touch it + + + Rewinds and pauses the tween + Ignored in case of Sequences. If TRUE includes the eventual tween delay, otherwise skips it + + + Smoothly rewinds the tween (delays excluded). + A "smooth rewind" animates the tween to its start position, + skipping all elapsed loops (except in case of LoopType.Incremental) while keeping the animation fluent. + If called on a tween who is still waiting for its delay to happen, it will simply set the delay to 0 and pause the tween. + Note that a tween that was smoothly rewinded will have its play direction flipped + + + Plays the tween if it was paused, pauses it if it was playing + + + Send a path tween to the given waypoint. + Has no effect if this is not a path tween. + BEWARE, this is a special utility method: + it works only with Linear eases. Also, the lookAt direction might be wrong after calling this and might need to be set manually + (because it relies on a smooth path movement and doesn't work well with jumps that encompass dramatic direction changes) + Waypoint index to reach + (if higher than the max waypoint index the tween will simply go to the last one) + If TRUE will play the tween after reaching the given waypoint, otherwise it will pause it + + + + Creates a yield instruction that waits until the tween is killed or complete. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForCompletion(); + + + + + Creates a yield instruction that waits until the tween is killed or rewinded. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForRewind(); + + + + + Creates a yield instruction that waits until the tween is killed. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForKill(); + + + + + Creates a yield instruction that waits until the tween is killed or has gone through the given amount of loops. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForElapsedLoops(2); + + Elapsed loops to wait for + + + + Creates a yield instruction that waits until the tween is killed or has reached the given position (loops included, delays excluded). + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForPosition(2.5f); + + Position (loops included, delays excluded) to wait for + + + + Creates a yield instruction that waits until the tween is killed or started + (meaning when the tween is set in a playing state the first time, after any eventual delay). + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForStart(); + + + + Returns the total number of loops completed by this tween + + + Returns the eventual delay set for this tween + + + Returns the eventual elapsed delay set for this tween + + + Returns the duration of this tween (delays excluded). + NOTE: when using settings like SpeedBased, the duration will be recalculated when the tween starts + If TRUE returns the full duration loops included, + otherwise the duration of a single loop cycle + + + Returns the elapsed time for this tween (delays exluded) + If TRUE returns the elapsed time since startup loops included, + otherwise the elapsed time within the current loop cycle + + + Returns the elapsed percentage (0 to 1) of this tween (delays exluded) + If TRUE returns the elapsed percentage since startup loops included, + otherwise the elapsed percentage within the current loop cycle + + + Returns the elapsed percentage (0 to 1) of this tween (delays exluded), + based on a single loop, and calculating eventual backwards Yoyo loops as 1 to 0 instead of 0 to 1 + + + Returns FALSE if this tween has been killed or is NULL, TRUE otherwise. + BEWARE: if this tween is recyclable it might have been spawned again for another use and thus return TRUE anyway. + When working with recyclable tweens you should take care to know when a tween has been killed and manually set your references to NULL. + If you want to be sure your references are set to NULL when a tween is killed you can use the OnKill callback like this: + .OnKill(()=> myTweenReference = null) + + + Returns TRUE if this tween was reversed and is set to go backwards + + + NOTE: To check if a tween was simply set to go backwards see . + Returns TRUE if this tween is going backwards for any of these reasons: + - The tween was reversed and is going backwards on a straight loop + - The tween was reversed and is going backwards on an odd Yoyo loop + - The tween is going forward but on an even Yoyo loop + IMPORTANT: if used inside a tween's callback, this will return a result concerning the exact frame when it's asked, + so for example in a callback at the end of a Yoyo loop step this method will never return FALSE + because the frame will never end exactly there and the tween will already be going backwards when the callback is fired + + + Returns TRUE if the tween is complete + (silently fails and returns FALSE if the tween has been killed) + + + Returns TRUE if this tween has been initialized + + + Returns TRUE if this tween is playing + + + Returns the total number of loops set for this tween + (returns -1 if the loops are infinite) + + + + Returns a point on a path based on the given path percentage. + Returns Vector3.zero if this is not a path tween, if the tween is invalid, or if the path is not yet initialized. + A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature). + You can force a path to be initialized by calling myTween.ForceInit(). + + Percentage of the path (0 to 1) on which to get the point + + + + Returns an array of points that can be used to draw the path. + Note that this method generates allocations, because it creates a new array. + Returns NULL if this is not a path tween, if the tween is invalid, or if the path is not yet initialized. + A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature). + You can force a path to be initialized by calling myTween.ForceInit(). + + How many points to create for each path segment (waypoint to waypoint). + Only used in case of non-Linear paths + + + + Returns the length of a path. + Returns -1 if this is not a path tween, if the tween is invalid, or if the path is not yet initialized. + A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature). + You can force a path to be initialized by calling myTween.ForceInit(). + + + + + Types of loop + + + + Each loop cycle restarts from the beginning + + + The tween moves forward and backwards at alternate cycles + + + Continuously increments the tween at the end of each loop cycle (A to B, B to B+(A-B), and so on), thus always moving "onward". + In case of String tweens works only if the tween is set as relative + + + + Controls other tweens as a group + + + + + Methods that extend known Unity objects and allow to directly create and control tweens from their instances + + + + Tweens a Camera's aspect to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's backgroundColor to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's farClipPlane to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's fieldOfView to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's nearClipPlane to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's orthographicSize to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's pixelRect to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's rect to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Shakes a Camera's localPosition along its relative X Y axes with the given values. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Camera's localPosition along its relative X Y axes with the given values. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Camera's localRotation. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Camera's localRotation. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Tweens a Light's color to the given value. + Also stores the light as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Light's intensity to the given value. + Also stores the light as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Light's shadowStrength to the given value. + Also stores the light as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a LineRenderer's color to the given value. + Also stores the LineRenderer as the tween's target so it can be used for filtered operations. + Note that this method requires to also insert the start colors for the tween, + since LineRenderers have no way to get them. + The start value to tween from + The end value to reachThe duration of the tween + + + Tweens a Material's color to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Material's named color property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween (like _Tint or _SpecColor) + The duration of the tween + + + Tweens a Material's named color property with the given ID to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Material's alpha color to the given value + (will have no effect unless your material supports transparency). + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Material's alpha color to the given value + (will have no effect unless your material supports transparency). + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween (like _Tint or _SpecColor) + The duration of the tween + + + Tweens a Material's alpha color with the given ID to the given value + (will have no effect unless your material supports transparency). + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Material's named float property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's named float property with the given ID to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Material's texture offset to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The duration of the tween + + + Tweens a Material's named texture offset property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's texture scale to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The duration of the tween + + + Tweens a Material's named texture scale property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's named Vector property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's named Vector property with the given ID to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a TrailRenderer's startWidth/endWidth to the given value. + Also stores the TrailRenderer as the tween's target so it can be used for filtered operations + The end startWidth to reachThe end endWidth to reach + The duration of the tween + + + Tweens a TrailRenderer's time to the given value. + Also stores the TrailRenderer as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's X position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Y position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Z position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's X localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Y localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Z localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's rotation to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + Rotation mode + + + Tweens a Transform's rotation to the given value using pure quaternion values. + Also stores the transform as the tween's target so it can be used for filtered operations. + PLEASE NOTE: DORotate, which takes Vector3 values, is the preferred rotation method. + This method was implemented for very special cases, and doesn't support LoopType.Incremental loops + (neither for itself nor if placed inside a LoopType.Incremental Sequence) + + The end value to reachThe duration of the tween + + + Tweens a Transform's localRotation to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + Rotation mode + + + Tweens a Transform's rotation to the given value using pure quaternion values. + Also stores the transform as the tween's target so it can be used for filtered operations. + PLEASE NOTE: DOLocalRotate, which takes Vector3 values, is the preferred rotation method. + This method was implemented for very special cases, and doesn't support LoopType.Incremental loops + (neither for itself nor if placed inside a LoopType.Incremental Sequence) + + The end value to reachThe duration of the tween + + + Tweens a Transform's localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's localScale uniformly to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's X localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's Y localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's Z localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's rotation so that it will look towards the given world position. + Also stores the transform as the tween's target so it can be used for filtered operations + The position to look atThe duration of the tween + Eventual axis constraint for the rotation + The vector that defines in which direction up is (default: Vector3.up) + + + EXPERIMENTAL Tweens a Transform's rotation so that it will look towards the given world position, + while also updating the lookAt position every frame + (contrary to which calculates the lookAt rotation only once, when the tween starts). + Also stores the transform as the tween's target so it can be used for filtered operations + The position to look atThe duration of the tween + Eventual axis constraint for the rotation + The vector that defines in which direction up is (default: Vector3.up) + + + Punches a Transform's localPosition towards the given direction and then back to the starting one + as if it was connected to the starting position via an elastic. + The direction and strength of the punch (added to the Transform's current position) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards. + 1 creates a full oscillation between the punch direction and the opposite direction, + while 0 oscillates only between the punch and the start position + If TRUE the tween will smoothly snap all values to integers + + + Punches a Transform's localScale towards the given size and then back to the starting one + as if it was connected to the starting scale via an elastic. + The punch strength (added to the Transform's current scale) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting size when bouncing backwards. + 1 creates a full oscillation between the punch scale and the opposite scale, + while 0 oscillates only between the punch scale and the start scale + + + Punches a Transform's localRotation towards the given size and then back to the starting one + as if it was connected to the starting rotation via an elastic. + The punch strength (added to the Transform's current rotation) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting rotation when bouncing backwards. + 1 creates a full oscillation between the punch rotation and the opposite rotation, + while 0 oscillates only between the punch and the start rotation + + + Shakes a Transform's localPosition with the given values. + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the tween will smoothly snap all values to integers + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localPosition with the given values. + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the tween will smoothly snap all values to integers + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localRotation. + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localRotation. + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localScale. + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localScale. + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Tweens a Transform's position to the given value, while also applying a jump effect along the Y axis. + Returns a Sequence instead of a Tweener. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reach + Power of the jump (the max height of the jump is represented by this plus the final Y offset) + Total number of jumps + The duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's localPosition to the given value, while also applying a jump effect along the Y axis. + Returns a Sequence instead of a Tweener. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reach + Power of the jump (the max height of the jump is represented by this plus the final Y offset) + Total number of jumps + The duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's position through the given path waypoints, using the chosen path algorithm. + Also stores the transform as the tween's target so it can be used for filtered operations + The waypoints to go through + The duration of the tween + The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + The path mode: 3D, side-scroller 2D, top-down 2D + The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive. + Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + The color of the path (shown when gizmos are active in the Play panel and the tween is running) + + + Tweens a Transform's localPosition through the given path waypoints, using the chosen path algorithm. + Also stores the transform as the tween's target so it can be used for filtered operations + The waypoint to go through + The duration of the tween + The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + The path mode: 3D, side-scroller 2D, top-down 2D + The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive. + Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + The color of the path (shown when gizmos are active in the Play panel and the tween is running) + + + IMPORTANT: Unless you really know what you're doing, you should use the overload that accepts a Vector3 array instead. + Tweens a Transform's position via the given path. + Also stores the transform as the tween's target so it can be used for filtered operations + The path to use + The duration of the tween + The path mode: 3D, side-scroller 2D, top-down 2D + + + IMPORTANT: Unless you really know what you're doing, you should use the overload that accepts a Vector3 array instead. + Tweens a Transform's localPosition via the given path. + Also stores the transform as the tween's target so it can be used for filtered operations + The path to use + The duration of the tween + The path mode: 3D, side-scroller 2D, top-down 2D + + + Tweens a Tween's timeScale to the given value. + Also stores the Tween as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Light's color to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Light as the tween's target so it can be used for filtered operations + The value to tween toThe duration of the tween + + + Tweens a Material's color to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Material as the tween's target so it can be used for filtered operations + The value to tween toThe duration of the tween + + + Tweens a Material's named color property to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Material as the tween's target so it can be used for filtered operations + The value to tween to + The name of the material property to tween (like _Tint or _SpecColor) + The duration of the tween + + + Tweens a Material's named color property with the given ID to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Material as the tween's target so it can be used for filtered operations + The value to tween to + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Transform's position BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableMove tweens to work together on the same target, + instead than fight each other as multiple DOMove would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's localPosition BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableMove tweens to work together on the same target, + instead than fight each other as multiple DOMove would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + EXPERIMENTAL METHOD - Tweens a Transform's rotation BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableRotate tweens to work together on the same target, + instead than fight each other as multiple DORotate would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + Rotation mode + + + EXPERIMENTAL METHOD - Tweens a Transform's lcoalRotation BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableRotate tweens to work together on the same target, + instead than fight each other as multiple DORotate would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + Rotation mode + + + Punches a Transform's localRotation BY the given value and then back to the starting one + as if it was connected to the starting rotation via an elastic. Does it in a way that allows other + DOBlendableRotate tweens to work together on the same target + The punch strength (added to the Transform's current rotation) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting rotation when bouncing backwards. + 1 creates a full oscillation between the punch rotation and the opposite rotation, + while 0 oscillates only between the punch and the start rotation + + + Tweens a Transform's localScale BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableScale tweens to work together on the same target, + instead than fight each other as multiple DOScale would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + + + + Completes all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens completed + (meaning the tweens that don't have infinite loops and were not already complete) + + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + + Completes all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens completed + (meaning the tweens that don't have infinite loops and were not already complete) + + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + + Kills all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens killed. + + If TRUE completes the tween before killing it + + + + Kills all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens killed. + + If TRUE completes the tween before killing it + + + + Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens flipped. + + + + + Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens flipped. + + + + + Sends to the given position all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + + Sends to the given position all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + + Pauses all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens paused. + + + + + Pauses all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens paused. + + + + + Plays all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays backwards all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays backwards all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays forward all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays forward all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Restarts all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens restarted. + + + + + Restarts all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens restarted. + + + + + Rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Smoothly rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Smoothly rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + + + + Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + + + + This class serves only as a utility class to store tween settings to apply on multiple tweens. + It is in no way needed otherwise, since you can directly apply tween settings to a tween via chaining + + + + A variable you can eventually Clear and reuse when needed, + to avoid instantiating TweenParams objects + + + Creates a new TweenParams object, which you can use to store tween settings + to pass to multiple tweens via myTween.SetAs(myTweenParms) + + + Clears and resets this TweenParams instance using default values, + so it can be reused without instantiating another one + + + Sets the autoKill behaviour of the tween. + Has no effect if the tween has already started + If TRUE the tween will be automatically killed when complete + + + Sets an ID for the tween, which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets an ID for the tween, which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets an ID for the tween, which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets the target for the tween, which can then be used as a filter with DOTween's static methods. + IMPORTANT: use it with caution. If you just want to set an ID for the tween use SetId instead. + When using shorcuts the shortcut target is already assigned as the tween's target, + so using this method will overwrite it and prevent shortcut-operations like myTarget.DOPause from working correctly. + The target to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets the looping options for the tween. + Has no effect if the tween has already started + Number of cycles to play (-1 for infinite - will be converted to 1 in case the tween is nested in a Sequence) + Loop behaviour type (default: LoopType.Restart) + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + Eventual overshoot or amplitude to use with Back or Elastic easeType (default is 1.70158) + Eventual period to use with Elastic easeType (default is 0) + + + Sets the ease of the tween using an AnimationCurve. + If applied to Sequences eases the whole sequence animation + + + Sets the ease of the tween using a custom ease function. + If applied to Sequences eases the whole sequence animation + + + Sets the recycling behaviour for the tween. + If TRUE the tween will be recycled after being killed, otherwise it will be destroyed. + + + Sets the update type to the one defined in DOTween.defaultUpdateType (UpdateType.Normal unless changed) + and lets you choose if it should be independent from Unity's Time.timeScale + If TRUE the tween will ignore Unity's Time.timeScale + + + Sets the type of update (default or independent) for the tween + The type of update (default: UpdateType.Normal) + If TRUE the tween will ignore Unity's Time.timeScale + + + Sets the onStart callback for the tween. + Called the first time the tween is set in a playing state, after any eventual delay + + + Sets the onPlay callback for the tween. + Called when the tween is set in a playing state, after any eventual delay. + Also called each time the tween resumes playing from a paused state + + + Sets the onRewind callback for the tween. + Called when the tween is rewinded, + either by calling Rewind or by reaching the start position while playing backwards. + Rewinding a tween that is already rewinded will not fire this callback + + + Sets the onUpdate callback for the tween. + Called each time the tween updates + + + Sets the onStepComplete callback for the tween. + Called the moment the tween completes one loop cycle, even when going backwards + + + Sets the onComplete callback for the tween. + Called the moment the tween reaches its final forward position, loops included + + + Sets the onKill callback for the tween. + Called the moment the tween is killed + + + Sets the onWaypointChange callback for the tween. + Called when a path tween reaches a new waypoint + + + Sets a delayed startup for the tween. + Has no effect on Sequences or if the tween has already started + + + If isRelative is TRUE sets the tween as relative + (the endValue will be calculated as startValue + endValue instead than being used directly). + Has no effect on Sequences or if the tween has already started + + + If isSpeedBased is TRUE sets the tween as speed based + (the duration will represent the number of units the tween moves x second). + Has no effect on Sequences, nested tweens, or if the tween has already started + + + + Methods that extend Tween objects and allow to set their parameters + + + + Sets the autoKill behaviour of the tween to TRUE. + Has no effect if the tween has already started or if it's added to a Sequence + + + Sets the autoKill behaviour of the tween. + Has no effect if the tween has already started or if it's added to a Sequence + If TRUE the tween will be automatically killed when complete + + + Sets an ID for the tween (), which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets a string ID for the tween (), which can then be used as a filter with DOTween's static methods. + Filtering via string is 2X faster than using an object as an ID (using the alternate obejct overload) + The string ID to assign to this tween. + + + Sets an int ID for the tween (), which can then be used as a filter with DOTween's static methods. + Filtering via int is 4X faster than via object, 2X faster than via string (using the alternate object/string overloads) + The int ID to assign to this tween. + + + Allows to link this tween to a GameObject + so that it will be automatically killed when the GameObject is destroyed. + Has no effect if the tween is added to a Sequence + The link target (unrelated to the target set via SetTarget) + + + Allows to link this tween to a GameObject and assign a behaviour depending on it. + This will also automatically kill the tween when the GameObject is destroyed. + Has no effect if the tween is added to a Sequence + The link target (unrelated to the target set via SetTarget) + The behaviour to use ( is always evaluated even if you choose another one) + + + Sets the target for the tween, which can then be used as a filter with DOTween's static methods. + IMPORTANT: use it with caution. If you just want to set an ID for the tween use SetId instead. + When using shorcuts the shortcut target is already assigned as the tween's target, + so using this method will overwrite it and prevent shortcut-operations like myTarget.DOPause from working correctly. + The target to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets the looping options for the tween. + Has no effect if the tween has already started + Number of cycles to play (-1 for infinite - will be converted to 1 in case the tween is nested in a Sequence) + + + Sets the looping options for the tween. + Has no effect if the tween has already started + Number of cycles to play (-1 for infinite - will be converted to 1 in case the tween is nested in a Sequence) + Loop behaviour type (default: LoopType.Restart) + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + + Eventual overshoot to use with Back or Flash ease (default is 1.70158 - 1 for Flash). + In case of Flash ease it must be an intenger and sets the total number of flashes that will happen. + Using an even number will complete the tween on the starting value, while an odd one will complete it on the end value. + + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + Eventual amplitude to use with Elastic easeType or overshoot to use with Flash easeType (default is 1.70158 - 1 for Flash). + In case of Flash ease it must be an integer and sets the total number of flashes that will happen. + Using an even number will complete the tween on the starting value, while an odd one will complete it on the end value. + + Eventual period to use with Elastic or Flash easeType (default is 0). + In case of Flash ease it indicates the power in time of the ease, and must be between -1 and 1. + 0 is balanced, 1 weakens the ease with time, -1 starts the ease weakened and gives it power towards the end. + + + + Sets the ease of the tween using an AnimationCurve. + If applied to Sequences eases the whole sequence animation + + + Sets the ease of the tween using a custom ease function (which must return a value between 0 and 1). + If applied to Sequences eases the whole sequence animation + + + Allows the tween to be recycled after being killed. + + + Sets the recycling behaviour for the tween. + If TRUE the tween will be recycled after being killed, otherwise it will be destroyed. + + + Sets the update type to UpdateType.Normal and lets you choose if it should be independent from Unity's Time.timeScale + If TRUE the tween will ignore Unity's Time.timeScale + + + Sets the type of update for the tween + The type of update (defalt: UpdateType.Normal) + + + Sets the type of update for the tween and lets you choose if it should be independent from Unity's Time.timeScale + The type of update + If TRUE the tween will ignore Unity's Time.timeScale + + + EXPERIMENTAL: inverts this tween, so that it will play from the end to the beginning + (playing it backwards will actually play it from the beginning to the end). + Has no effect if the tween has already started or if it's added to a Sequence + + + EXPERIMENTAL: inverts this tween, so that it will play from the end to the beginning + (playing it backwards will actually play it from the beginning to the end). + Has no effect if the tween has already started or if it's added to a Sequence + If TRUE the tween will be inverted, otherwise it won't + + + Sets the onStart callback for the tween, clearing any previous onStart callback that was set. + Called the first time the tween is set in a playing state, after any eventual delay + + + Sets the onPlay callback for the tween, clearing any previous onPlay callback that was set. + Called when the tween is set in a playing state, after any eventual delay. + Also called each time the tween resumes playing from a paused state + + + Sets the onPause callback for the tween, clearing any previous onPause callback that was set. + Called when the tween state changes from playing to paused. + If the tween has autoKill set to FALSE, this is called also when the tween reaches completion. + + + Sets the onRewind callback for the tween, clearing any previous onRewind callback that was set. + Called when the tween is rewinded, + either by calling Rewind or by reaching the start position while playing backwards. + Rewinding a tween that is already rewinded will not fire this callback + + + Sets the onUpdate callback for the tween, clearing any previous onUpdate callback that was set. + Called each time the tween updates + + + Sets the onStepComplete callback for the tween, clearing any previous onStepComplete callback that was set. + Called the moment the tween completes one loop cycle, even when going backwards + + + Sets the onComplete callback for the tween, clearing any previous onComplete callback that was set. + Called the moment the tween reaches its final forward position, loops included + + + Sets the onKill callback for the tween, clearing any previous onKill callback that was set. + Called the moment the tween is killed + + + Sets the onWaypointChange callback for the tween, clearing any previous onWaypointChange callback that was set. + Called when a path tween's current waypoint changes + + + Sets the parameters of the tween (id, ease, loops, delay, timeScale, callbacks, etc) as the parameters of the given one. + Doesn't copy specific SetOptions settings: those will need to be applied manually each time. + Has no effect if the tween has already started. + NOTE: the tween's target will not be changed + Tween from which to copy the parameters + + + Sets the parameters of the tween (id, ease, loops, delay, timeScale, callbacks, etc) as the parameters of the given TweenParams. + Has no effect if the tween has already started. + TweenParams from which to copy the parameters + + + Adds the given tween to the end of the Sequence. + Has no effect if the Sequence has already started + The tween to append + + + Adds the given tween to the beginning of the Sequence, pushing forward the other nested content. + Has no effect if the Sequence has already started + The tween to prepend + + + Inserts the given tween at the same time position of the last tween, callback or intervale added to the Sequence. + Note that, in case of a Join after an interval, the insertion time will be the time where the interval starts, not where it finishes. + Has no effect if the Sequence has already started + + + Inserts the given tween at the given time position in the Sequence, + automatically adding an interval if needed. + Has no effect if the Sequence has already started + The time position where the tween will be placed + The tween to insert + + + Adds the given interval to the end of the Sequence. + Has no effect if the Sequence has already started + The interval duration + + + Adds the given interval to the beginning of the Sequence, pushing forward the other nested content. + Has no effect if the Sequence has already started + The interval duration + + + Adds the given callback to the end of the Sequence. + Has no effect if the Sequence has already started + The callback to append + + + Adds the given callback to the beginning of the Sequence, pushing forward the other nested content. + Has no effect if the Sequence has already started + The callback to prepend + + + Inserts the given callback at the given time position in the Sequence, + automatically adding an interval if needed. + Has no effect if the Sequence has already started + The time position where the callback will be placed + The callback to insert + + + Changes a TO tween into a FROM tween: sets the current target's position as the tween's endValue + then immediately sends the target to the previously set endValue. + + + Changes a TO tween into a FROM tween: sets the current target's position as the tween's endValue + then immediately sends the target to the previously set endValue. + If TRUE the FROM value will be calculated as relative to the current one + + + Changes a TO tween into a FROM tween: sets the current value of the target as the endValue, + and the previously passed endValue as the actual startValue. + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM value will be calculated as relative to the current one + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Value to start from + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Alpha value to start from (in case of Fade tweens) + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Value to start from (in case of Vector tweens that act on a single coordinate or scale tweens) + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Value to start from (in case of Vector tweens that act on a single coordinate or scale tweens) + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Sets a delayed startup for the tween. + In case of Sequences behaves the same as , + which means the delay will repeat in case of loops (while with tweens it's ignored after the first loop cycle). + Has no effect if the tween has already started + + + EXPERIMENTAL: implemented in v1.2.340. + Sets a delayed startup for the tween with options to choose how the delay is applied in case of Sequences. + Has no effect if the tween has already started + Only used by types: If FALSE sets the delay as a one-time occurrence + (defaults to this for types), + otherwise as a Sequence interval which will repeat at the beginning of every loop cycle + + + Sets the tween as relative + (the endValue will be calculated as startValue + endValue instead than being used directly). + Has no effect on Sequences or if the tween has already started + + + If isRelative is TRUE sets the tween as relative + (the endValue will be calculated as startValue + endValue instead than being used directly). + Has no effect on Sequences or if the tween has already started + + + If isSpeedBased is TRUE sets the tween as speed based + (the duration will represent the number of units the tween moves x second). + Has no effect on Sequences, nested tweens, or if the tween has already started + + + If isSpeedBased is TRUE sets the tween as speed based + (the duration will represent the number of units the tween moves x second). + Has no effect on Sequences, nested tweens, or if the tween has already started + + + Options for float tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector2 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector2 tweens + Selecting an axis will tween the vector only on that axis, leaving the others untouched + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector3 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector3 tweens + Selecting an axis will tween the vector only on that axis, leaving the others untouched + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector4 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector4 tweens + Selecting an axis will tween the vector only on that axis, leaving the others untouched + If TRUE the tween will smoothly snap all values to integers + + + Options for Quaternion tweens + If TRUE (default) the rotation will take the shortest route, and will not rotate more than 360°. + If FALSE the rotation will be fully accounted. Is always FALSE if the tween is set as relative + + + Options for Color tweens + If TRUE only the alpha value of the color will be tweened + + + Options for Vector4 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector4 tweens + If TRUE, rich text will be interpreted correctly while animated, + otherwise all tags will be considered as normal text + The type of scramble to use, if any + A string containing the characters to use for scrambling. + Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters. + Leave it to NULL to use default ones + + + Options for Vector3Array tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector3Array tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for ShapeCircle tweens + If TRUE the center you set in the DOTween.To method will be considered as relative + to the starting position of the target + If TRUE the tween will smoothly snap all values to integers + + + Options for Path tweens (created via the DOPath shortcut) + The eventual movement axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + The eventual rotation axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + + + Options for Path tweens (created via the DOPath shortcut) + If TRUE the path will be automatically closed + The eventual movement axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + The eventual rotation axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards the given position. + Must be chained directly to the tween creation method or to a SetOptions + The position to look at + The eventual direction to consider as "forward". + If left to NULL defaults to the regular forward side of the transform + The vector that defines in which direction up is (default: Vector3.up) + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards the given position with options to keep the Z rotation stable. + Must be chained directly to the tween creation method or to a SetOptions + The position to look at + If TRUE doesn't rotate the target along the Z axis + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards another transform. + Must be chained directly to the tween creation method or to a SetOptions + The transform to look at + The eventual direction to consider as "forward". + If left to NULL defaults to the regular forward side of the transform + The vector that defines in which direction up is (default: Vector3.up) + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards another transform with options to keep the Z rotation stable. + Must be chained directly to the tween creation method or to a SetOptions + The transform to look at + If TRUE doesn't rotate the target along the Z axis + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target to the path, with the given lookAhead. + Must be chained directly to the tween creation method or to a SetOptions + The percentage of lookAhead to use (0 to 1) + The eventual direction to consider as "forward". + If left to NULL defaults to the regular forward side of the transform + The vector that defines in which direction up is (default: Vector3.up) + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the path with options to keep the Z rotation stable. + Must be chained directly to the tween creation method or to a SetOptions + The percentage of lookAhead to use (0 to 1) + If TRUE doesn't rotate the target along the Z axis + + + + Types of log behaviours + + + + Log only warnings and errors + + + Log warnings, errors and additional infos + + + Log only errors + + + + Indicates either a Tweener or a Sequence + + + + TimeScale for the tween + + + If TRUE the tween will play backwards + + + If TRUE the tween is completely inverted but without playing it backwards + (play backwards will actually play the tween in the original direction) + + + Object ID (usable for filtering with DOTween static methods). Can be anything except a string or an int + (use or for those) + + + String ID (usable for filtering with DOTween static methods). 2X faster than using an object id + + + Int ID (usable for filtering with DOTween static methods). 4X faster than using an object id, 2X faster than using a string id. + Default is -999 so avoid using an ID like that or it will capture all unset intIds + + + Tween target (usable for filtering with DOTween static methods). Automatically set by tween creation shortcuts + + + Called when the tween is set in a playing state, after any eventual delay. + Also called each time the tween resumes playing from a paused state + + + Called when the tween state changes from playing to paused. + If the tween has autoKill set to FALSE, this is called also when the tween reaches completion. + + + Called when the tween is rewinded, + either by calling Rewind or by reaching the start position while playing backwards. + Rewinding a tween that is already rewinded will not fire this callback + + + Called each time the tween updates + + + Called the moment the tween completes one loop cycle + + + Called the moment the tween reaches completion (loops included) + + + Called the moment the tween is killed + + + Called when a path tween's current waypoint changes + + + Tweeners-only (ignored by Sequences), returns TRUE if the tween was set as relative + + + + Set by SetTarget if DOTween's Debug Mode is on (see DOTween Utility Panel -> "Store GameObject's ID" debug option + + + + FALSE when tween is (or should be) despawned - set only by TweenManager + + + Gets and sets the time position (loops included, delays excluded) of the tween + + + Returns TRUE if the tween is set to loop (either a set number of times or infinitely) + + + TRUE after the tween was set in a play state at least once, AFTER any delay is elapsed + + + Time position within a single loop cycle + + + + Animates a single value + + + + Changes the start value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + If bigger than 0 applies it as the new tween duration + + + Changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If bigger than 0 applies it as the new tween duration + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + Changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + Changes the start and end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + The new end value + If bigger than 0 applies it as the new tween duration + + + + Used internally + + + + + Update type + + + + Updates every frame during Update calls + + + Updates every frame during LateUpdate calls + + + Updates using FixedUpdate calls + + + Updates using manual update calls + + + diff --git a/Assets/Plugins/Demigiant/DOTween/DOTween.XML.meta b/Assets/Plugins/Demigiant/DOTween/DOTween.XML.meta new file mode 100644 index 0000000..7a866b5 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/DOTween.XML.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 34192c5e0d14aee43a0e86cc4823268a +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/DOTween.dll b/Assets/Plugins/Demigiant/DOTween/DOTween.dll new file mode 100644 index 0000000000000000000000000000000000000000..0734619ade9815f473e378ee859125dbb6d3a7ee GIT binary patch literal 175104 zcmdSC349z^kw4z*?&+TC8I9eRJR`}Db)0fNu;pLwz6SeE7D|3eR1)<^N=-!Az*{Leh1i^KO9tq(-W%7S^~gu9e`4dY*Nyh} z2FDxH7e36g9?|1iSO3$;9~*P~jhL<-g9;yb^@JXMye`835haP!Ws%9IF7>BR*qWYZt{G2C&|;vZ?4S z-p@_FkKTOUQ*XxmH{WRT#k?B1V>BeWYIJsP_F4c$Hs+lfeM>juF3Z|AI(yv>4Iolh z=3HpKV-emN5}o?_DD{dz%4S;`>-QJ-SQp;ZWAzC1=zmVLofc$pZMW5nN97*7$yY~y zqcxTl*iA+_@+*Kj@bVTQLe<@f1SsOIhGKL~2S>shJ=7i`-?Qy`KIJ9)f(-^UZE$yM zz3mlzcx_O0E2YXhdtO4XYo7o>-7Zz4bs$_C?{C)ukeAVHX`ZpAO1W~eEkU~$NYp%$ zDqnBc@Bq<`e2a!bpyo%bk*}KFUztS)Z;I9fc*{l5vhBFhAhX=J*|l~-#fT2O()27$ zvdTKRx@1{vyiTC!;Oa6UzL44|w0cmK_!pMvDb0$W=vc~8Kwtv`^Z0RB*fG#nAeFJg ziH=iDCpsR1XceT3z6qt-{m}>j+qXbOleC_ig4Z#Kf=BRi3_>9YKAu6S1i>dT2xTC+m%;TCyq-a*8PI(U z(!}iM4G2caffwBeB@T@5J?4(HQOqNyS)kr@&q(<;DldYu1ow;#%sx?ogKcW6?$16C zuhq=#O9VPJ`$~DPiJ&JhK>3%D4Z8tzMB25p_c1n#SZeo!mm1&(+lda+<~P`-2-fXY ztiH{*^*Kxboai@*jBdq`UGJ%s#9T^JpaW7oB`K7W=&mekgJ|WeE6^7SL;Bd1^IFkx{sj#04XH(%^DjcN3`BWHAF`*BCn1qWAk3-C&Ye%q> zYNZXKU3ad6yhC=<9@!6V1Vy*C8X2y<&UQqvoga4&^`FROGE$D7(qnlWk)Hl$J4yig z4Cl^;LITfjeIGPDr}aHP4tnPSItP~)AiSI5QH0%0w4TO{np*`K(8*ZGLW$5(Sj>R$ z{LXDTd92J-R|>?kw)i5@$_)I*CJ=$V`!X|o^Zvjldm!)m`}P$4JJ9O%^a@^|Tk7+x z$Ax}*Y9HeIvY9YD)0Yd~FgMlb=0ZQr9bjaiANv0IKW0LAPhY0g7gWPs7~tPsVP@t) z7yuy%1AqLd{v9yDo<6VCm#YrnAF*y%2g~-hC6}s++_7z~!|efq2EtOtcwd zMq~KV_>~$XV1anq>7ZI9G#Zbw!aP{!!C?Gu+X=l~w2hiVU9AqXA{c!IN#B7Mn8`?K z7Tsc|=#`3oF&k}VCGFcBSg=|7BOVb-<)T;gm9471!uGPhIEnPj#JS{HIcY z`1#P8(H02Q=NaYurM|)>oTU{Op#M`Iju0~v^z{~V<%!e6LTRiVdPunC%xR%f%m{(0 zK4iJ>7QOn#X)skAL?;P>>LgRIj#C#i*DXq0>HyOzi~jcKLBnBh=y}mFOgx$-#p0?W zY*`d41umf$^{Wx6H-Sbl)Z&ju>_{RQYVl`PF*+F!FFFOkeMQ)AAuNgo6|*&$R+RCC z)=H;(PSLCN35F3zZErw8-7>}$`i&ieY|0J`D6aw(z4Ju}A9@I;=%-9kd~y}`m9cI| z-r>W-%$<7!&%JZ+Xz%PN(1i3yABQ9DuXs{z@}AVpLaEQKuJc3Khx3?egO#vA{+?fAL=2rjuQ)na7-snANcRiN)O z4jD#Yt(+}RJo<0QF%rF>^lO8q6f?v$!M<$eAAk&U9OJkDl^tyH#4 z&Vrb;fnFB5V%(V+w;TL8yXH7TWx&xGbb5sN*`>jlgl!-LkYNd;0}!AKylt@5@7OWt z-NJdWY`abhgq&n(Azt(=WO=Ic6{o&R^4A3wi04E*fmj}lxjQ1yROL>gEP02XpjfZG zK$I!84<>^yRpg^(Mnd9ZNe1g zAM)*NyXM&qm;&+|t?Gu941{9#S1_(|1ra)l`iQx^3$&V`Ss4M^(nS9+oO`69 z`6H$IL#25k6P*q^AaD`GXDCf5g)}ctXu_3u(F{oQQHJJEl;)3><|RyYrqaBW;j@$` zh99JPSwa(ok}jI)>xOfWHZ=cLY5r7cPB9VkLOG`yK3i#`pHG@I2~7;9x@e+18_w-9 zH2+O${!D2;hKbHmnwK+-o+b5(Vj;~d5}FtdRV%mJjy;{}cg0-VFiW>Rf}iMQpv_EG zZcIlPyW_6ujzh1*B>E&HhDS1Ur-8^pZznmTWA7b`$vc1_od+ooA%}DxqTN7X55F5V zEmI2brHk>5d?_Tf$4YFuvZm6uO@oYKIhrI4oU0|7AgPvF?M+$P7IbML>mf$v4~P6U z4$mKfKsD1oj%q#yx(RFyK%t%r6uMAl8gcjBmB1TuTK|qB9+9H5_w8x@9B&7`t77%a z5VuW2^f8WgA$ar8uCI{6cX-0nthY4z(0LlL}$5tU(?7HB>c!v~IL{iwAf;cJnWx!McyR z28uwBZdB(ZFv_fvn%?dwzd$1 z1{Y&!o)==!_F|04Cu{rv8{XLzZ}`$bjXtBCDDzKSmjXl6vEVHKG;*Th$O~208{2}H z{u9xS3WluE{nP2S_y2-ki-x9aorQrrdR^fkU7v126Tc?t^1+`|AKc|ZoYJODX=P9K zILB+Ak9MOufvSGz-tzQVxB#%S2knAoL{mQ=S_CUK~4#*gXZi zaR}lwZB_;VgkVV$TD!gLLAm< z^ke1ka3r1DI&E)OkFL3OdY3GV-e}s)HXYJ(6l)4y78<3{zhznU z&$XLhghZl|t(;l2EJH*^Jt9j@zo#qF9(1k5U!j|2t)L$`Trs5T(H=C{EV$CxX{Nqy zi|bq6R33vdaCv<|A+@f$=a;H3J7IMjYZ)BddDE3~yXLC|SiL)p$-JILBXVB_x%p@0 zUQqRDUc{}fS82=Rt79oq#S=e(rN6_)JBJsBp5k!A(*GSU{;!V^&t4Ji#IZhud}5wH zWFM_FE#FgJv9Qxt*IJbHk7X(`?j)z;=$%ZQc3Dz!?5&u%*tMr(>Do2cYd(^0d^=ok zeK77d&0>}LCOi7r0xYN8xEr9@=3Z#>W7oCV5_$V$SyOQJq^3KWf>Tc5$1;Ew(JZ$dV#sf14SKTrv_5YXdKt+cV%;5LLD zr#zBx{RKjP>$7~fTc6|ONI9XbaUKGv)Z$3P(dsf%XtBk}w#dmTxBf;@KY-ubDqu1& z`w}}*iYvKs;+!~=E%m(H3bwwcRO2+zYQO`saGb`a3|D4t#g`lzeL6;;S|?m<2717J zdT67(Eo&*vj^=|>KGwXS);wr-G>;c*9?NTa--G6jEnq&G>rtW6uj|bH2lO6zo(nxo z0->Sh>Y2XvL_Lr6rsRQ2fm zqh{+eDyoxp_3@j?hq8(`8;=GKvp%Treq#!N#>+sDQ~f5R-!F5T5rybgcIZ4Lrb|%z z@mvDZ$e-O_52?g1Y+0mlVR^!}+r#)B91Y}IMo+P)+@hbh+ng|Lv15t6-6s&vF||G> zLC!R_K8_#w5!d=1III@AlgeT&Lh?}W_3D8gftCmkdTc3RBdm|BH*<}3{x)_|McD$~ zH`DqeaYR`W@G#B$9Avz3-A!&J8(alD?`98d02|^U8z;Xji>RwVIn+JeVyP(ut zJzJ^g#G<$e)TAS+S3~z^OxoF8`3W;36CMd>vhkV&!*L6`>&H$oX|@TJN%cTBO_ z*&J4oq5X0MFt!?%E4plJdRr@F*<-oFZ0L`_D$J-P6Ieb~S*D|DRF4f9=2_b&w3mc@ zpb?Wn5<0=O14_i&^7xwHPo(5Y3vNsz1va5ypRaXtvO79 zE)|K@H*>=P*hR+Q$y>QpDoIv0VjBULt2_>>lug0T65_`Ye_FGy__QI{dWvgVWvNT7 zhJouGbhrOEGNr~U4N-YI?-wTjjzI0iLT7f9=*X~lCB;{4ZKis2;=c}NH5AFi){@#!y%?$?HlPu&+EQrk z1XCH->bq8?anxt2S#Xnnx$1Hix6cCyQ*S)h8?VSJq(MVu1qwZ1%+zBr)Zo=~NJpzM z^+4D&1KHK5Zp7mE*UFAbyALe9$U_$uB_b*2$xS4Ry)4CcJ(URm?8$pcyum27{jCQaKB<~dPL zu_0l1i?E9gDF}@v<%vVlP8tdGIwPCK<`kKd4FiB^N?WjdLju_CkuP-{n?{7eG~>b` zHnztewXx;X#s;0HtSztB1}`;@%_T6nKEKQ2@<+5d_0vmQT>Z!vS3vfS#T96A1+h2{ zF0wcULl*^DTz-+o#XDp|f9IS2_o0VM^g$WxGSn5U*daM0* z)<)i?*=#%p2x7LSu~GsRAESl6`Kxg7f@S(E_o5TkHFwc`7s|B0!)~Iwy7h6piN3O1 zhX;ErpJ=+?&gYQbq&=}|e<$Bj_1}SK|3L?1TKdf$ka-X?&s~ivKkfl(bq zigVbYm1bpA)_+|0C>tA1`__zKl? z4V?q%nONNP+f`mDzi{r!hR&~)&Qnr!p1PP0u~Kw$)-@=1lwUaaG(+dtz|aBIRvpKd z#)8=$4mLqw35hV8KIq*_x(`!Xn+)qBFuF5k?uv^hAhXvbA?{7C4#k`4`Zi~+tHBTX z2~zgCK0yNjQ&+al~pr<)z@TJr}X!nxZFzuzv!?;pDIH=pA7^e%qbmzLy@ zgoL5lp~ZTn`NM!AoO_1h_q!wWduEE?v%2`D@<%$|?2>wmQAs%WY{T#Oz(X0`PCBOE zK8NA%dP}TD^>!oaJlD`c8%a9PV_H*hpU-f2y(QKn`#ynmUSQ}PR5~wA(Ya$W9b$FS z*$F#|Nas$W=+d0H~5lLL7Cir58VOQMidXm@zk+>TktJ<-TJdw0sBDCyQ zj}mz)6B-@8jNxt_5vxl_dm$6tWjOa|hK@}-Zp-1LDKAZi8>m!)Sz;`WOUs zr<*U^1o)qD?ry`^Bg2EfFyfhhJq&EUPdV52P?>&q8 zlFnkjn9~U7-e~yd$T_-M*Yli@}AC9sp0S0*}9 zi;Hx4>_v(z;k%7|KWg}v$q@gvWv_8f3rt*E7;qG>iSV<*d z+3$i(+ezm$hRzzL^I4`feWlMatbHY(`te3G(JV&aUX!>qPpFpTkPATzbt;_uyrH#L zY5jSM)?XyF(3_Gjm1W7v1XoE9WTH8t&9n<>pG?|+X=op#w7-y|{Z}zI}w7-<1{nuTzl|h>Jx|lZ8CbU(*r;_%U4eep2{go8$zlmwX$8_nJ zxCt%QFKj5Bd%)0IueAO)MeC~xtt04{X&2B&-zA*;J45?erTzCQ+Fy%lA4$JVyMXpC z(*C-ky+LWC_nO$)KX%bRjDDFmq3v2QOY3yf{)VA_oYMX$(tEr*g@0!F33Li>gz7^d zPAuxWx^ZMb+;@;^x#*`!-O5<(!<|8z-!wFjC-z&=A3i|n-%XJ*@)7H>^1(%fbKf&GH>TwKev0tFqzD`N1T`fe+dx$F zaP9|&)(I-#51G`|{~s}&uK!+>SnT*EZ6M@fUc-_=aNaOVGs)=l<2uJ5lBOS&GWP#Zv`b+C6O|EV$i z&2D`Xs~u*FE|>Yy29ZW|9E8U@+O23gU~S}u#W?E`#_Yji1IVJ6M% zcPU=KUy2uL2rt%c<#9fF{IB7$X(=9W>*8@R#p9u+c#uZIBPU~!3&_KAb)IZ9;?>?$ zI@{4T56}bDSZ6lFiOx!LuutbXNJtpzJU~Z%$XnKenedK+aLzG&$BxX`P4Ufi@fEf@ z-$6P{u#M+D(1!@;Ji~K*DV}IGQgb?fif6WqXL`XT9dw$ro&=p@hBlll7=Bwi{Em|?DlbI!=!tGX1vA^tg4u_8>FoBV*cZFl zr?X4Ci}-7PA4UEv4F9bi{+&6qZiXvU48tylsr-`8B7VO0vL4I2g#1<+e%pYDbH69! zktuI-$}1gIU;-OYM3$TAhXySy%DNtW!u+RN+ZimiCi#$40IeMiqAlr5N!1@qC5}Yh ziL?SmH#0D^Z;y1ThG5?8SFVlFH?BtL6ju>h<{8#1=&dG=4EzZP<<-_HWYZL82fb2? zS2^b8?Pn(Bz^1U3AH!7`4j6`IWjMt??LluKMQbpo)gfT0qD>CcwAOXgnvwo7WsEdP z4a$MVHvFK=)5O({UQ;r0&>JEf$r}76;mj8OmzK|^ET1*N;T-&_h(h_Cfk&r&2yEP# zl+S6zfygMIT@035JNeM^Ih{e|b8RZ0$8_cM4=bN_NhYLx&Lo?rFgxfCr+BT8d3pPp ziK8x`V^g#?#I(}oBUG1FK9tdv4>h>Bd?XVGz2nFxT|Uf~mJb$dxV96{9S0M^Ykhj782ktetbOM3>d&w06~NGA&O!<0O9rg^82=zksozUG~M-qrD90 zPB45PwgjIj#plGs@L}4;e3WUq^*iO6k^SvcZ8N+dp}hHMprKj@?}sbzlTy4Vm*!2P zDc)~FZm?t&&TTimFCZni^+-ON^3r6uaSh~1&qotz=6#^16yof%1U{ei4|+RN0-u}+ ztn=7LStP9jQ&*H1eb;dA6eI6NB;>X(=A$VuO@2 zp0>2SBpu7^TIerYSo8|#b{csvAtBio+j^AJ+(kO3TYWmiso@A6c3Zi5JYTN zXw%xw5NnN>^EpVT4|q6dS*Ct4#TP8 z3>Q&g=u9MIny!&O$4I0PlfpeDhW<>4{ znWB4Phpu!}q^!Lr6UpEkM;jepB*ANZoCpGV+^&cT7O%1qW6lUu83Mr&SDxsv$`d9h z&x`oP=oEfx{!zQa1^yIZ2twWlu8clDDx|?zWyyXnP%lw=<}J{n$Br2VQ+VUud2$Fwf_k z=kv_-xqP;sgI_SYlMmf|`632OtrrVqJ$_p+VX)kKsX&e;uFk`Fog+rnra!4dqnUd14ls}v<9nUs*^Q$nI82~iPt<$h=Nrp#)bSn_yibY%|+ zP!`;Lb2I7-jx->23u}&ug?8TNcv${`Dk1^n$-t=lB2+bt_ov`}pNfYYUQ8_IM66?C zMPiek%I)^>h*Dd0q*gPGL;neefiSb8P+V-5DmX_At#SsUr6f%$N~WbqB*Y?8g|W~y z#A4JC3syrcY7MdQH6$e}RHTF?B!wg)Dc#EG+%Yi1`FSL&d{IwU)`n6iETLLCd)fR8 zVASmRK;uJ$0T`$;bI7z4P!B3r}YMr|43N(EDP(6g2npfaNbnyLGn{OE}hAe z$>e8&U(Y%H(Nk$vNp79BbH706GWs2U%zo=Xj-I;&y-Ok8<5>SyzJ==H{VrbZMCX=K z44MN)^7Qh!de)KK%Br5%cp59gCzx#^mQdz58@4y2#Vty1!EfcIOPOM8@@NQ8l;^X$<|0yLTVXU{*RrtQy)3Nv2$r@b81~DbDeq+zq|l-SI*q^&a;EZde8umP|bTT+$= zz_MsbffxYQ-V)s#05#kaH5&kx*%FN!0QJ@qj?!DaNJTOuRmM}Q>9&$_4(x`Bm!(7`@t zIY6cHj-2(8b2|ng2WQegPY%tf*D^dlMjrf$lYE>2{v`bgjLDALrr2?Gn(X~|SqyvB zT^92U0@4=4{&kndu*cbDG3 za+k%ho7!bD9Ex;V3X|5b}&clu~7rulLt5Q}k|uRyRqs%D^j@h6J9KIMko3))%bTxYWb#`nWJ@+GrKXC=hOm}1i zU%{JE7Nxlj^x`yE*tiHMA&A}zngJ%7vHQy%xD&z6ECq(?5PW+Y8}|gJWP|r1#xs_{ zkg6FOgxNF#ZkPrMNMj;-zuBX;YT;fUKe`B$0yu-D9WFn*SYLH~<42E@S8VZjfO?6% zIEtEeqD%F?`B^BThWE?ly^P^hxfE^3gat#6hNQoZY0Y$zYLQEt5#?@n!lrgLkiH!TMVd8DPM)HuL7glfTHs9UOh)<&mP+2Dv8hi<$?BO$JI zxvJi{72^e{7*cZX@2ptf5B)c@P!GYF1^$YNkdy!#h(A`&EaxlyH{Fi7pqt8qGVY+RoXYu2uocBj3g! z$oF7R&2j6;EAzuKs;*irAWE)lu0!*@MG-a6#^}@vOi!gryGo4ieO=nnBdK=x9Lk@7 zu48QTsCvKBRXDoduO_*%bNv`WAiVa_C2<^8H%WukF`&|%m$cwbq7hb|0gd=u7f?`PO;eJcrP zS`RXeE8I#Lm$gyZD+`mOLL>PvB?-fB>%Wq4ruE;Fe78O5^ur;{f6B!P&}Wkj_mj{? zJf3qoaV)lw0)?tZ{u4QO%F_>XfU*w%SK_~o|JCibEVjC>{{aT>M3A>k>sNd` zrs!@cf8=i`ajKFJ95;^_W`9jZrV^S6zx5C!WZ%W@&}-69hS6{hH|)rUbJUU^mmtFV z2enO3AbQBJvIM~DFqni()n0_rn+^Qv`S`7$jG16f=Pph+oJ!Z%l}^u-wtka{-(;}% zv_;HIDdy!A^A}K7emer)SE9l;%VmCNE&`8c`AF;f{A-SX;&<`?4R5&+<@Vt@p= zZm|vJ0k0!>Wz6r?5w1D-+OLC&Fb0E-20;UiwL2xLs)VcFxI0Q1RVCZF#x z&$pW=x}{hak&$h`jvM-QwzFR+I!n@H0)4h=ct~SF>$mi>jIs_C6v81Mu2kd=3|O#` zd8tzCvjq0HKBwvboDbVBjpQR-^y_g^|A|BP26s<1{ z=3kS9GW-gIdKrhky7d6wDnk-efq>kbup4y>riiNv$OY#}8!rd7I**|@aNn?3KQ~i< zm|bpA7Cm!XE9=voiBF%urmh&x=i+F&MGD1D>GQZtgwOO5^qh~|jJ3ye7Ty%{SZux1NXVwBraA!pt{+h zZw8LJvdbqN$L-I9moHDO@a2TQi)-sb_c~nv;K=!8l~)Hc+luC%13kHXQaUd#?!w2C{V=sb@XJq^Ud&Hf~KA8_QrwD`%f;8*$@C zb&b9x^qxnSh2%W9JN|7`5NmVw!OY+&D6__sGM{m}_}Yjtb7gJBq(BjV5GWMpZ6*ny zNfJil`Z6gk+!%&77wg6sqkio}z0xleoo+Wgc)bUA2GL)k^HJL{`vTv($!oj_p44l+ zSbj0f5JWGcJg`;o8}OY&XLQQwmG6%9*s?ymBk83G#ZKSrrziy1MmwDx%B3*wOnSGA`dK zx4tS`x*H|IF@s~lL&_iaH3w*BxqKT`Bb##-0X{7h?LdnzKm+QXeFcQp&lq6*EUT&k z90%qg0z1Q1RFE-u61CTZnNHH^it_u(yfdX?7KUX)Oc#b_DlB!aPuJBy1D&gXc%I(o z`Oc%f>qzb3B(znu1E_-z)^5_jBm3M0Q02WvcJprm+41+FFSfEB%_DA>crVe8x6L&_ zxM>5*<9#N{034U(vKgr!1Ghj0;(>{tpn=9VXxxpT)~oUJ;BAQk{L4}XV0Ub7(Ae6y zZvRsXU@`!QENM)VN0ML&%=i|ExWHyi7TX0jjN!S`UAkwT<@2JsDR+ zK>k6e)Ex|iS=APd*E@Er7?;Eu-sGoDwylouvXW*Gx8|!DB0*^&dL=Zga}=!0{|;U^ zunZlwIn})K+m5yl#kG)SX8SV%*UEq8;Y;Z9#3#HY*Ih-u#!Dcv_yjE{b0M<0hO!h_ zfBwPC4om(I&O029>VDE1ezdhK*8NkFttYBIi|)};38V+)>0sNGg{zuU?H-{>GNN@9 zNyglx#)@*NB3XmFcoSr}kur$d0}mqum!*LJ$K!t={%^(q>RI+J?L3|07C|FJpnENxpMx&3{fq=qWVDJbFY=blnrcA&$@sYOyC2Q z`nb3-xcCB-q*+UY9yAUBpcynx>)~$tg3oa~KBv_B9_eVO0s8(X-n`a#2`lLcvm}E{ zI4Szs>mUyXPV_mF&TV~L#Nb%8wujKwHo6Pq-FZ zKibhBCa)_B!5-h*dLs;3<~6*Z*%-ONpSsNRr%ZOVuwpU2j&PY8Ze?63-w?n0Qmq7T z<)9%i>MZNaA+%@MrsSEr%-F*tkXQaKiq@`4YM!`Q8COiYI=y|V+x#53nv~~sQr-*bz$k{) zo-3WweKQ7=J?na}dHE7vs_B=Q_(l9YvOYOdZ=B|LNHE&KLrG4PlRCBIS6Ny~qW3^K92nxOex||*gjGj&=DnB76S}VG z>`6iwje8KFw!9zD1{_Ji(PZG(wmZ&#hU80|Ugvw82HFeWIKYqJ&PO-d2MVfX?1wER zu{fE5%D@PR{fGdT3da;QIVFe9N9^7P`Re4Vp8ZVY?B}}#sqTOS*Z^_lW8xU>#5pXo zz;9r5Yx3q;FF+odH`I|6Quzv;5s|=)Y>Fhg)bL6y4v2`E+NG>YiGZ~osq}dxqbs@V zh+xEXMHwA%mt@x%-kRTz0F`T?c}ij;97=}SjG(dsRzJTpv2h$dwq}v1*hEj{XWraH z88$ZbV*?knxzaZlenppsU#Q6!S+^uyu7!7VIfAJphb;0PzeVA!@TG+JBS|oF0ct6W zp6kj1K9_P?9D9FPEZ@?x=uM~6@+}=pv*}Rgn~A0Mboh!brT9v0!dGHbd?hyFE3qlQ z5}WXq*qAS-^^AoUU8!QRDHZ*WEyZduiPDx2w1ghek}&clXvK^nkNvzKM_!HZJq@a! zlREwh09nUBiD%sbt1tsPxor?{s(w-6tDi=d2CRE@wC!*L!+Ps%n#ypvQ?w&wL=UW`_Iyf@= z#hisIDt~c(IQDS$;f9&1q#j({RS(Wux*puHTrV$_S-h-_N2me7RZXCjKCk(7ESAyD zQby>;OBwwIo(*(EgBBr48Sw>W^aa8=FNt4<8(+jvs*FfW%P674GBT<8h|7qnrHn|- zRXQvq;VQJJL;@+J4se=tXUi)inBwxw==!5AqwAMjMnaiow6B=mcf?YfnYtnRYvk~H z)dI)8F9PcmO}VXSh>Vd_h@Zkb+YBs{AtC_&fZh%8InKtP(mb zE0da!xU863%8JBXrNgokt{lV%QzC(sRR=iT`g=r4edy%9&C8u%&**5|@r|%+>=xYd-k8+Rr*oqTtrW)b}iT z-?%sabsu`q@GO+vBdv&_g-fI#?w7`foF+N?3dhZr9Rdbq5Cm>O5|(dx$(J+DHIDCx zNx>&(_~+>Qz^IR)Rk(`24wo`$lBp_I=dw7=IxWPn4;QL6)n8b+3!gm2 zmx^)HGt6xBvbm{3H3$p&BEHpHsN%b<`gPXO#piTW?M`;_5Tnm?np`~Y>kWGcMpuQs zL!*1c-gPH`0;-wpN9P<}5{x5)K7W;8^nEE)Ia}+=?^H3Hf`#mHOaR+yaQuBw2wv=DO?J8*sP^+$#6NM?p#vE0$ivY0UkP2@P*$2Q}u--DE?c;S3DB1#_KWX zWZdHU6bx>WaG5&@@O5-_Q>vA9j(pbwe$A0RX3ZqMe2SyiQ*k)?5{NxP)udp)wM37x zF$GcIG4iBAco0u&$I}@!4&&>T(Y5f2OKZRIz@XN>WfKtav8PoI2lejFqj+t6A1rtf zO+6nBO z$ppVCj#`RufMazj*LVeVHrB6^>VvY;aTu7_b8;0mKUi!e`X#v69;ujI1QfT?7v!2- zKz(3hL+B1}D$M>0Q?Stw!4%)c7LEYNs9}(m<@*|F`{rZFxNLh$ze=9PCDyv~l?%OE z4sJ6mZk!)0AI2r^d3^NTkW^14vGJ$I;Y9v9^lPhun5C;lauHCFK&&-E9fV%%RC)TX z)A&qf%>@4oxy&|RMN2ZO{}DB40Xqi#7yzlBtsX+tWq?VYNx(SZ<=QZ=7PVR^`?!BU z?lh^zdgYL8m|T}Qu!tMOiZDe&9)u}If|LAxG<;r z3l?6<5wpTls^bDVTP#FB!z5oZz_JMDeO^zTOpY(0nQOcTM0rQM+eGKkJ$Ve7(O{nk zsH}y%&G!Jf9s8>g#q@o?tIMd{G|%OUx<=H|nsI`OA2l+pz)~SxmC?)3;fQPX5cAPo zkVH|sqbrn!8)o_G+v-MhOE#j))0@9lJrT%LeK{cK(#Sc3jPEJ%;&K?rw~P7G*fmD) z=*V%>pgeJWEJ6*6mi%+c8>3TNi?rB5H5PYK3@#8)$rmWgSX@_M)lcF29jh&N(B%VU z7IY~eARmM;_;Tq;Z_z7H6wuwF2{wKL+tX5H$HMIBxf^cq4E)dF|KyXwE8{f(2l<=3 zgQj~n(&>9nKCS9BA3|I`>o^!I|0@&bw2olwgUWMR%qlK&Xg3u+M31nYoR zk3+d9@@b+0^>8Agv;%#vY8TG4Nw2NiWH07-cniHN;s5;F3XKfi#=nA3AF}n|h~17c zEee6bfhz|lCgG+VKVy7;m3F;aY%cpCQeOApwA_q z3+k|}Eh|>V@7J~1;;zz8opgWvu+Sydx+~XBj6>#rR)f?GXJ*s;lwufJOfX-^31Im@(G*Y6uOy5j!Tf z2zzBNTxkkGve;Kd-H+CzJ?mQ$(i)KK0FMuy8LpV>gZ}9k2Pd|{L$gDO<^{jwsOg#Y z9|G>azM`c1&>7qMB=DRwCHWR4pYBt7AyA_KKr%GCzX7#cFUC{9MIZug0Ntz~{Q#b{ za<3!QmD3(aI*+dW;)UvW<#&(lt?tI2Nn_)sgFU0z=oO*Ez@Z=79fxbJ)@{<~KyxNz ze3(MeK-&|v2+{c%2+S8xroOoW5T1nqbU~huM>4t1n0$2=?#kQGV0v;GE&!bqR7Q@^ zbssnR>YR1Llk)*7P7LA(fHio?JR6B-YFjvGo$##;pIA=`6a$!e(4}#Y?AQHa0Bg}&S5z6 z4F=NE`K5#o?a8F(Bc5MkYMEamF<0queo43r?J1E!=9fCaX?Ek5Hx~#E%U|4|TYtFu z+SK&Yg=^ph&;9gY+%F0&t%3KRFZaqWF$^n#Rg-b?*Mg~79_sGMu z#TZ9!U1X$NKUNRZ)d#T{i}sAsQ2_tOYZQaY*FZlh?DE91KvOIoAuUW%ePW7fA(eDs zqV8m~5w28i@SQ^s^!3L%PjO}Ku$3XgL zs=aMWi4{|$-7&wK6VVL(7`rR*W9U;a%$uxDlb@SnwE=s9saSX@rDlX786k;^#Bt+~ zP&Ut!vUx9j0rt)rH5zoP95-u-JSIQzpL;<>ifP9@l50urxCKF-2a%ReEiN{n=}EzBfhMBXWn@+dBRcn&%=wW4E`U~oKrR&aaCCZtW)N8d$yE6Y}Kuu z=-xbzoi_z^E_i#XSV~ql=4`aH4KxOjpG;R~i$2;MZP!k~s{Embn&~+`v%312E;n_7 zBo;!ciAGJf>_+VrWJziWWV-M0Z5n#7bTAxo4osJ~-iqmS)_Cmv=XeZs{23{6d1ry) zoez1Z+VL*h7cv7ABgITEx1|5biT}`=52TdeP}nMKKl#bht1_Ot3@|bim@*d_8464V zU<0b;Qhvp@4xlV=XIZKV*lyZ1`to6(83xqGC)QD~Il2H{?I}h$02SmFqBT_@g-ogg zDUe=;Xyp|M$2gQrJC+Kh5nuo84T~+7rm9q6X#7^>_EIz}<4aisFLt`AX zFb3bJs(WF!4q;0eS^G7-qr2?q>uUU;d@g<# z<)MZF+yaR?IRM5%b!L%P4u@S^5}PHbeQwEmOgjviA+Pcdc!n)!YCnBi``iMV(k{1# zlO8wDT%qOQn#B`dgj`8GHw>h>PkRe8&Oa@QxKv2*5V_V8 zIz-k@^pD`-_ zeTQ$4v63XRhzhamK%W>S>T1(ojieSCDbIzGR3szixiFHtWTZShkz#^cIWbx}7D%}8 zYy%$iG$7iPW1-J(q5Z%Z^EgD%j~WsL{Hk6!uR*=QSAQN>m{N<$yea}`A}LC&1Zrg@q8x}w zD?lSC3nJ2)*9gjkh)%{=*h|nSa1m_+7ttkf5l#4QYBN)7aDM3jsYZ1!E%E(gJ+UQG zrb8%EP3{niG?7ay(?oU@y4d%3OxPf^Ag7IGQ_U&vF__F!d}A=#q&QB`jRDXa$B)eA z4a0y|z?LvBApty?AQ+i}oA37Vo^_1z@$tChX@_*qD}2@9imYhQ$L?jR3WQU9!1)k3 zYXjlJJ}VD_vqBI~d4SJ{z*#4ZQ-0S%r~K+a&M7YtJ9`MR1-^vX0$)OGfvea@a>ffJ zKp8BhH-eYoPw*1#306mlrFHfzz#%@vC*(mP0nIUrX<0^R3^4C-W57sjbEAjfbjM*Uvl=l2L#fhX3C5 zO23MoJ=n$?&sRS#-9wqcwi1w9*h4vrt%!%>R?K2!-jT-nGin|Q4SedIGHW?VcuK=C z7%U3LW&BC#C?t6e<2teC`g^8ev-ltp04vc!) zq0v$`;+h7LwAYmM3}SwfIgxb|ijdj)BKhm>4j{edMQ+4bJ>p*8Bu@*;M zuawk5h7TfB4e2#GZOG%1n~uC z2wr9+s;t1~y+w6OfQwmRC@DPPCC;LCuwEU5^2DA8j0?~c79Vjoo{e+x!~HNFAHf$d zI+yVC2p4=*gn3A2e8kY^0DdBbpE$O z{l+8lt98<`&`OG~)CVPcq7O=Ghe7xtYD#<%WzB5IN*vn5C6yIbp8{o_N@YE&dV|wU z2#ZVV=tE4|GU}Ck7>jr-sCLD3^Yv2;Hi`OLP=? zLs)nj7#)JoJ9qLMP@uPN^hw_E%9GhOon(suKS&x<@+lirKez!1az~LhcOj5k7m-`+ z5hWQFXp%9QO13D45HsAUT$7AJ<8>GE=&(1*#H_R;FgTs&q18zZJGvOLDlPr*qwv=8 zzxQF>aOd*QC@y$b6( ziyRYnR=G+C%>r{M%>n~R&ZdF_3yc8+qig~*!V-_11ZG&rP0A(GdMwnV02k^-fFv0! zi(vthW(;Il#x$ZrG(MLCpgz^+x0)^V&(Qu{1}NvH9*t*X3O_AEFfTRDM{`Dg8E)*s zPn;f0AClg!`?FunTQ{x5?Hsk$DJt~ESV&S|%;YkTAvHH9#Px`Eu^f&gbg&WnF~H%5 zXo{gyh_7-jB(`2mnN?^(beg0scf&zgCY3N6DXflT_wrgrnEh+WC=7V@Vjy?O;d+f0 z7B#S0mZ&~anf_3y{Xq5V7$%7>o{c0RQ1A(1vY2FVc5n>)o`{4^kBuwv96oL0-0UE) z96CiKU`YZ$Wnv@-l&2K5Y4jMCXFo+7*T3;k=0>Pju)7(F!_4Z{209yP_)>vfkm=YB+pe#8z=-7@djbQ$IV6%RuotF)um~Kk}Ug ztsRSTQ;~lNLC>G|dP`%gvitmfd-}XwZXXV5?49ndy1DFh??S;gX8lbYvfie3=u;bk z>rSrf;9yKj{Ee7*XL+YY<6d&y!C}1=wor8I{SwcsV6S0$%3Gz4P51b~69A>a5vAj} z!sKnJ-B}#WI<lNB58%?+Qj3(YcjcRM(&Ai%y1(KhALSZzAkqYI+}zLOwi0X%LL zJN2vf@U@M{f1kH_pc;TWPPAk^oDUSlr;+p!zc@^-uqzoEP1 zm3VYmV<+?QwG;gVcU*+i5F@4G<6b*b9=`UqSWNCM8(5gdE2=)$fv24?i0k4x2zRRC z_ArO{0nJdf3){t4kB*3TN`O1Vry=1!$WopPgXzW%2sNIFpN;SZ$N-N0ly$acKuHE9$BUIdhq#GIWmZg;c`+u72Zty$ zU#yc;g_KBRIm)wh_8|yL+=L0?qYl|+1?45gJvWP0;e?R_L2irepn)XlR z_ow`oRYib)#1}M^H-mlUvbkIEm?wj|Co@Ew760gPuZ#Q*pQ1(nz<0nhdJ3^fV|dVj zA56gHnSj5WfGNaqV6eZPfGL$oBe$1|z#1aHhKM2|h=lyR;BFY{l*>R1S$Gwm~#QwBSG zGu;-&%548E(k_wlW0CR6>P0CH%47xiU}^p_BatwYsE!&iBhekz(T2=Oh?f7vis0;n z6tQSqw%19KV-751eH?jw0qvqwz?^IC#k|8dOgUUR`5Y<%TkW9{DdJRVr{@gd4uaOR zft1WLNDAiMq+rlY7c4~H03Oh^q>yq{i(+tE_D>ngYK&?%vNKfSoI}}){tiaZ$@<3; z=4O+PhDkkN=G-h3E_-gEi_3lR-iP0#&)OyX8F6IU9U8qjbl08C`TNPg!4Jmp4}!N& z1klznaOQ&pXFk&t0ep|^g`i?0;M;)3XOndzfCT~~e2@sA2@y=w@;xRZsOEHFOhhLF zSVkbi2Z>1Or6vOS9upB%OazD|7=%+Y8H6)n2J2)bFa`{a=>*0AVMfZGGTL64R{<`R zU4V;a!AL}efv3EkrVBN*9Y28Qt6)pG>2+kW0b6)_*DZmwd?aB)Je9 zmkQ&oNqiOXuNCJvg0mH(w|=V-xFp^`{Chrl?=a6a;J#rTc_6EY_>dEQa*9;%pp&Dc zitNBh{FaU1$_Ie%B7jGR50%7Ih~I%^5yX|zC0T#Ow>wI$KymVX^m9kC#`nenHvW=g z1q0N{M(E_}suK>?K!bfeBwodbs740oGMcZPhIm>t9&~08Ph6@9uvF2XTQ|Cn3vl8p)XfgXZ!GO;L3 z9@ipQH`?+R;_kt3f_q?R6-FdN8*K;?FZIfWqW6K`4!UqW{2UF&(5D(Ny2V9{72N1yGp8Cy$W| zXP*pV_8UawRNVF45-UnqzVPazH}Vh<@Y+~!YV z@>)S0P9Y8};tnD*+~!YVa)%%un?l^6h{Hr=xXqu!Bq}U2vmu3eoFc9!BExO|6eclJ z0^(E(aYzwyyP7x8aGO7c$xjL5*(t>174cz2WVp?r!X!pGpy*hr4S;;1c-37E6cDQ6>lU@&`xNOP1MAvt9|_Y9cTo5;q@Kzf6q6nftH z2c4YU*pS)&KIj%Z@*#!(-nrLs=)-7(V3n*76KWJye~I)W(rwlN>%%=5j4LUqN>G5? z1=K_K6;>7G=uICKl_r5pBydVQ)N{*WKH3Z)Dvp$QOyETLd3aBQJGpTn%vNxjX>G$V zPj2xUwUJxCFeP+Z$z_^XW@4RU~GHlnZHy|HK1lY$`KwN&WA(#q6zt6=*87L<208Xxyr@aI5L^c}d z@q4k_G6_xNG!{In3xhft4{3vc2=VTLoUujWZY)Ze_e&!AfpTH;qd;k&hy*3&kNWUN z8kAUTyP^@4j}dGk#o#5PtYo#E1T0j0V}0OT2m%mfN0_JrGPrW3I>ECx(134;{vwPl zi!Y=3?+vq9Vc_)_s4>j&U-;SF0hu=PcAk!jJjds5PMLjsE{*Mqvef8#=4wEy`8@N1 zzMa!zoxqLWw4KVWc9XA;l)u&>4U2(mS-Z)%y4R2>W^HGu3f4{cjFj#DOnk6JoyZjS zJtG6NkCC`Rdp{X;#SP6qmT~;nJNz0taqJ^~7s|)J9o7eUGS*2tI6hIaM+?qC$2DbY zr)f;dja`rQnp2fg5|-Vv6w`vp>LqdNC8OQgW99u0dDeTJou@cuKPy^VK$Qn$m#F_Q zOxOQAlKP*qPz=2Pd0F*8TgxXlSM4o!IW;$S4w+8%_p$?1;#W2!-GKT8rYonMhaBSA ziHbF*)fRqWkqa=DU!0!yC*eGDGjdZI&3RYHjT}gl6PsqgtIKz&-$imstS(h~1C2e^ zTqi!miL7 zKTic2*G0OOS2+FBL1CX~$tw3Usby?qv5sNAnPnh3*}5WAZk+-Wru$GS;bJ?SJp|;= zy#<_etgh9!FngDC5;_azY5e4|QUnLft9P>F-&O?gu3iU?D~?*Su?gLozKpBA8(fp* znXS{|{La+R#Kgo-`OIYN97gk6qyP=h7QSR! z^pY#w=%r}T@g*6AUWSljy5;B%;xMCo@MvRY05@2*F`w$%2fa4}G?&2`r157+P`USL zxN94OIRfjg^trVb@7X!n6Y#E_gFSf{SKS=!DU^Dv)3%g?Uf76MTiggd< zUm)9&F+%vv3WO6Egzzb|p3)h>om9O!rFG}t@z@=RuESFpG7;fcmx0b_7 zHZS*D*`s*)t^o0XPG2B(PJE$jVeoIg4f(OT0UaMCb)ntIVB9&o9nZ2{R|OW6YdX$MB&chGF{oEVg@0|2~WqJP40(|Tu$_HZx*@@Ii8Ke5E;oqN&Q8!g)S6%H)|aU<$_f1kH+ z59Yy?hr#x9!bTS-$G$23-t)l&n`T3;Oy$Lu>E)_#oeAiM02mq{az|raWXK;G#eFP&Qy*vM4Nch^ zh0^W8wJDzQe7=*q$Ut%&o0vELcUntO>N)8!a@^|U$~Y|AYfR`%pFW}SOw=?TjzVp` zqANH4)qc*bNim!g7X$sjh{P(913}y>rg7#@*M#71)O-~xzKJe7{{;eg@G%CBK`bH$ur+A$M*(3*O~a&r7-RVpqn}Lxe-xm8PQ$1Mup`$xnNQe}TifiQ z`)`}ue`zSNb$nHgA>YxKHD%)CKi~(h7^&;Wj|Uz8nYPBMdCtJ-aCJu;b2glUdO6Bq zo?%-cl8H)tOe5zR$*?UD6S+wv?_?yycALK%i4})80Z!hIbrU*s?~%Gd4c2>L{A~Pi zT5|t~VG$!2(4*~~!6zIEj$VOUr};vIZ#U0m8hitquBCR28W!$%h+V zpWW%IWAm(v8@(CP1v8aRt(Yn7RP0EWpJ@sT*a#O-Wmhj!c3KHjxNxBAf_gbf$Lu)Y z!i;opQfLXu3`k=8TWvj0idZgbTct7%iP1hd4JgK`0 zvL^S-Y(YM`pX7+=wPd?1E(DEU4>BqVjQs#v4YkjQ_SEJ{4{Mv@>=Q7ax9d)S)w5;% zFB?{aHs%Ac{X`yvUgHf&j(Xumm_F6B8<_u<^zAi792PQ8^hFwZn%F(eOSQZVE(0kp zSCWgivww0vr4%1bEX91V{nh#a^zkRlPe*I*l~55n8u~q7_!=vV|0ql=R;U+Aj=e|) zq8*MRTFU2sl#i-UzF>Ixl2M%{X^XwfODo*RXCDjn{^(;U!^-&Vr}1LPFXt6gF<0Wn z#O$7Zt-QPu#cWbuG5ZUGUMNc}DfsT$hp%8df*hs0d-jG^3qZHp_z+roG*>N_=fzkD z^ik3W^JiPfLN^~|Sy8dr^~iy7d7E1;mMUW5<%9fkAU>}PJmLdQb;(WIs9AROCFGIc zk#;$T<99tm2j(rG1#$ZiI`9tnfHXpw$HL5(D<9UCeU=5!zbboG?H1d1E54Cn;Pe9+}9+IWK(fje7+CqekpNe)KQxzX6%Ym%*ND-Cqrg5OksN? zh13TrZp8eVxkKih|7S|(`gp!Dd?_`%1xTaSbju%ox&t#u)Svv-mH@%*}z zS1-(dU6OsAM&Qk^EL%4X4>aBi-2VQ?+wj;}d4{mHqY-2rUso%)E){wm7Sb>HJY?jb zGP0ZGG|hu0ZhJN4tl`76@>0Ufw!GcuQ=^{^oZ47P&~R1i+rhM&;b+r=HaZ&aj7iwf zutFjW!l!bieX4UY>S9*QQZP`s0E3Q{py+yM_ zFooNwr06|JIr}WWQakb*y%(_PlQ0_nrsq$PIr(a1^zVQLUg@-d0A%*LNaS@)Jg+D} z1WIY_IDa-X1e(y98xe#}GRmqKU}0eJf4Uf-palQ?1^7Q+j89O4|HK9OKU<7XP=f!p z1mBN7g$Pq0r1Roo4GPB+UXRxix3$ke8w$Nqp$$So=@x~~^7Spo(MXN&smyL&W8F0OK9u-K^nO|q`b<^H zcID1A<_dXfB#uE+u@DS06X%m7owtWII_R^BlNp-NF8{2-;O>E3OB={tts3_ATAF+6Uqp%@!~t$&%!nh zYeAZi945_-(5@BbfjcTQjgL}Bd{OjfkeBbyO8|gdVt@nycybJo002*k0TR$Wus`*5 zws)pGVl!{}e?0zICv2&C7{!&Rq94J=Dt5%GqJW<$fOSm)|Ed614h8%h0kcX(Q%>0t z@$n$m6eHhEC(5DGb<36aMbt}SRGd;2=2jW`me~X{_ zrz2wh7Z`d5Lc`7#hd#WUooIDuOH_tMkwy; zc?xNa?g5ye_>x=YcC=DY65j&?cQ; z+1=TuNV&VYJ*oC&bnrh3>+>dVKb%veyX%vrQwg5;&K4Q*ON zA-M_UH9v5uyjUGEahDX^%;*oz%Uj^~MFJEZ z1?l7kRSCv+AKUB3^RTf76VN=~k9oWms9Ox7ZXr2a8@|=ow4blp;zPptn*BVxT-7TS z1)mol9rgw$wzXfVn0!c>nC!t+x3piNQG7_4QS2k(XvrNK#fO9$^<2Dk%j4AhRFbKA z5lBR+IOWl@Gcd7HSx?Q21j4hTET`s$v+$}YtEqY6C_LDzt}nTUU2iS9hao zO!^3xvz`V6dnvCva=Ol;`uOapo_2HGlK+h5u0$l^Oy?BS*?Kw~Oy^8C&=YlklDM=1vC1*rPOt-5Mz`a`cyh%F( z_vKOCmv!#rc%vxp1euzny=$h#95J@d;g*lHd`DmD`TyAC8?pg#B10*`1?CnM-rqDxbbGO2*2^ zQj!2$WHmpA)03lIz!Rdc%5iBF4{q5Ld{r|jB&M)Z?n%|WC&|j7sV{$Z@V9od<5dv8 zD&?;dJU7Pk%u!am&$62a4tV%FJ^C@GP%!$bHq^yt^uJBihPh?VuaQz7f{g;Lr9yjH=k1htGEc7SG zbvkIskzS6B)W2kna;xzkBuCY4)X&qo=W%Obf1rNA4e33vnt*gsS5ft}JD{WRUO{__ z?%9s$I2&RxJUc+BcSSov{8$w~bbTZA>C@uIFW7Y!S}XYz}%vM&@+s z@`#i2yoHo9r1fgH?k?stisW{DrtPhRa;gCQ=|;X`MB--@pM2G(0rN z8OnzXy%67|GMz3B>E`G$-f!!DWaYG}r_m}W#L1&pcG%z9cd`i-l&&k+V-Ue{SGKXU zEyk}HBr1+bf9l3Y6t0x*h7INqRbq@V19j_ES^b zVG6MY?MHnx!pgBCth=wEXaAky(cVv#;gTYzDASzY8%xP@n#P2i*O3o{dJA(p%?9Q) z!OaNsaq_mXxZky~JDxBwrqE6kWiO>0btQWd5Ea7XW64(dam&sqhjHP+7LM%}Y}x2d z9Y25*(;~FvJNOOFX&n{9lXf|g%7XYG9v}vi1<{R%2DAz#`z8Y5~18sSW)AMYNA>yl)lmyR5-qkT8-+Ys+QGR$YJH)Tt;HSX<%)} zfv66V6bXFQnZwZ{=&5jeo;##$EUrDGLQ8g`mh^IJZCvhf%df#N#xQXL+ppMKK_dcN zS8Ri^AmR@BZkGPL~6t6n-P*o?T$Xpg*|`1eT4;W>5m83HUk1{VujCGI zV1o<{MPSYi6gPVsY=#j|W*i?Cf~Cl=CKOV|Awv=3YD(Ojxf>#c6Lw&13ydIiF{Yxj z_EN)Qr7KroZlr_#G>qq9tpKh2#l!lzIp4B0`j5ZSxh!jQc5hc);AKIzGf2 zxh-W1Au0vToA|CnOj^e#wxYG=!7U7zWSobXS#;1s@|Yho=~K$cmhTwSwi(tA5sh|X ze8VV)=K^HFSR8TWaU~8THxKQ&`%J$$;82XF+0AgIAzuf1yu(@(+ri}zr(#%_=ER2L z4t3p=P@&Z-^sA11q3)G3m$)(Et*XCKql%&9x-Kr~+Nb*G1NRtNS-HpncMHryQKjYd zl7~KLLAcI`P(G3s=V7jmt3n=(ar2yNoew!Gh_)n&pn--8{QH&nrN<#lc%4Ap- z0>^vK2kz6WaCwS|6At#ckE;AeBEsLq%khO@5Rc~tFZJbz3WFL}iO4adLo<2(k!z#j zsj1PqX#b*#M$*Rz(*Dni&*xDz(e-9PUy_Z4w-InJlGQrW$id1#G9?)qpx(uBUdI5| zM6PI;ea^|Z<;xD?n%7gEXB5XlWiTb7NGh&KT}$vZJB>x%*&E zSwJtt4(8-mqVH83^iDBxHOk}+3(WNe84CNq%}{;}l6w((j4ce&UGp$ZX1jIWg@Yj0 zVbI=D<8;j?kg^DGf0zBo!gHG3rE}D^gSV%&<7-R4q8`QjfLt@c=kPQ&KbiDbRThXS6FCeTL?*biSW-;WdL-Iod5} zJB-{Ai{~{X(cIaIKKpE3FSPLzlS+)EoB>?T8axx=Y>Op^(e5*Umy2k(ncI}pmdWb6 z5o2cmrtPI?4Vm!}*}&{6n|qiJ??U7l}*#f0nfY{O&= za_!=E^1RSm%3og`XXnJ@yU#1pa5*ECC&aZEV`GjxyJu)lIKuc`#LSDwQyI2AU2@~G z4EDM9k!FH{gOe>Apcx&Ua0x>nj;5;cE@r`6$J^-Mur4N`4F9`&#;c)JJ>!)i*_r-& zrgI#Fq8i-BhiU_={Gh6}w)m7uG?v0(u?1a`VdRYAV-N1s%5xVwI_ex#)~&(k zJ2*y0$*b4q!t*Yjv0`~f-3;jZZV1cxDwHSDn^^P~5*nfGOPfl6jz!;&!I%(k**wQ? z@kKLDMwd51`Nv|LitRRRsC%AM!wC-0ZFIwLGi<}LWn**Oov^%D$vO9C#MmrFII~2%`mV!rVDAVRr>J?redxXnsdmt_=K``XoyvPVWlA` zbfwgcUdd~G?RGomY^ur&kBhC5XN>5$Y?mjO_^7pR@oA;pr7$}bX0ECFWC3|<=lKL^Fxod; zqPB3a())g=5Z#VmsSaRgy={sUNPeFaX0~X0`YP=GTgqy#;ORWqevFe%_`Z!d95Z|r z*c5Aya8oj`O?IJ$Co(vyJ&Nb`cnXgLcp5Le%nE@5-FONa#Z!LSxp;-$sNhI}@(U8+ zq*yLz4=SPo7D z{Xtx3ZBQQ=qoefHqTlZBQiFAjuJ@2`4SwIJU(}Bf@*7#K-%IJcFuM|F=)AByQcE{n z2f?ln;e@$9B9ZG5Tz*!9lPH$o`LnQx@qmk2I`?oo)$NBvE5Fr1K9uNfr+j4x${Tu^ z)secXGN{W8%IsZ>%L|z5Nwyz_*ZnOPrBV>P{82ERKJzmi^7~&h2$Nr(Sc_Z^Qr9b{ zsDoXcui{)YyLIi0)WhmA44BqZUR~$<7?vm*o=@O3 zPyi-PGgKmkAxk|+D5v+4RZ0mnsd}hc417l^!?+!cb8{jro`0uU*_XCn8*8g z3$at)gO|4~=)Ndjr|#nM@J+~b!fU%AKe~(7f?-Xr=NL@kK0oeeegHGl78>RupY#v;cev2t{sJh({^k&=I0n7_zo~PR ztG)@UUca#FpZK52x^Dkt(sppe#n%2`wrU8jMgP84|E{SWu0DY^#SN~)aBlcF-4bhL zWbg3x2iNE5Jns5`(pHuKzmRhdaP{{E($Nji3Hphdb%1sm_jqqGR_1&eD4^?wzUY7S zr_%#+xX7dgaxh!N33`Oc9w-e9S=#>VZ87! z=LS{UIw~iwwsFFOir^yFQ3(Oxk)-YvyL1_j$;}AM^KbCc=}la3qf&BGYa2twRNHe8 z22$IDdnIriX;8fvj_%qF9bP9G<2ns*Ow*%X|2t-#^gWEA5YPqhf7WG4ax-mLEQlu`(d$lWnYyM0(y+*Hb>j>#o);^v*ji(2hiwQp+$`sBAFjghbJ%cxjoQSW8*G`_CSkh{8_w_qPH@Cu*xWjv?Zmbn z+h^E{4IvI;yWSLH8jQ@t_B6I;7WyW(Ol-Ze4aar~wkxr9!&Zo`<1{#?W3(Gv>L<sDYY6De7k^$bdSd((;Q$th+$|OYzOuZ=wP#l$hnM#$j#}P%h zQGsd8Ob4Z|(yyNMHwGdC3NO<8{=+}8;p^4j+Kk{1DGEa!^!!%Wnn(-{oND{#{DUI{X*6^j9hMyj zFZR4{vS&w_*r$G^CaMXGFoP<{TZsV`RAV}7tZI&46G3|;@1r&7u$;C3ksLPp=NvY< zAcyETs((?&?29wTg-18PAa{hmy;pSmn_B$WJOvLng~-45v(8wk3iw5e;ylJbIK+qky==| zt*j7oN6x;6XhAnx^-ke`op5e`oTO*3+)z2a^G zs@((pJp%karJwc~|IvYt(YlDE10??Fcu7@Fn2xO++azqaVtX9h4s2gybKqE*j;$OU z9Vc(a_Bgg3*uKQ(&>_cGj%^aQTd_TkZ3nh5vEg2|NXJ%=Z4$Oyu|1A$2evPqZ-m1NaC))Cs^L#my^U@zc5%n+b<`H zyS_14ev4mD5_kQ*!SXqNIZ3eWHdsE_FDHq+{=Q)Ot$sO4-1T^BIIw)T`Q;>W*Dns1 z-|m-_#9jYDuza3hP7-%Lo(vC6AB$wX^+yscFAJ96>6eqlUB5I~KHo1ViM#%xVEF>S zoFur<6fD2XFDD6RXoKZ<`{g8Y*FO?0zsD~piMxJzuzaCkP7-(hieP!8UrrKtJ>Ccs zSU>mr zBsS-&EQ&<=D!Tl9%CZzm12ILf~4y?gHs87zTzkR&=Xl_@r#GN zM`Pxblx(ZU^D}}F-x56$AGedDaE)fxxc=kQv~eTgs+#IZVa1NkHCkeA#Z^sd`Vt>T zcjz|4^^h8Sbhzoj#BQjo7Y*=y{WIXdkscDYaf}dp&Bf``{j>jSKE3Hqk{5W@7bMU5 zzWKkIK2;5$%?S7!%G#w+z#Hq6{|PMcqW0vH3FFi`{@BG2zi2lHN1hdt22EE05xJbx%1Oeskn_CN=7O3)$l{7E`A z-`WOs+zj<%nC-Bp81IYF>o7fFj;#*U>u{}MT2w9aR1j-uaKUJL&QsiC35Ev~7Gd;a zEnL!=9-&JSf#K1JAi@x3dUPcsFg%75Vc0S~rVjfpiLi&5o~BAfV0glbdh2y)ZIjGCc9h5SrR=h`?_M z?T!@C;C@5?Aip8>0jQzz{f7KO$`G=R{s1*}1k;m1wvlarkl{&G*+$=h8XDj9v{GvR zAj6ZSvW;doJ;?-U0RqF5qEbLhBLy^->1nM}@CO;5RFwjn&-AoWDG(T*G?fC{5-Fe& zO;5T?!5?IJGL#zH6>4Zge058y`GX9POR1qrp@!BoJy}Z4A7psk6jrO(q1{YRHb8lE z;N=^S)MZF$(1PVKPp(hJpj-A~o;*qbof0i-dh!WSB?N}2K#5S{CcjyqLgRXIf?jSk6n+z-(z|Q#v<^?>Ju1?z#pqGh@Z!zeVM?Rg=Z1y z_0@I#K(c-ek%M|VK<8UBnBItiMFhqy($VYs!%gQyz2!=PL>}jn!~jZyt^ot$QhbH40$9#=BlCOEnh(T6zq>l=~IYaR|A)i4oIK;|CoNH%KT_3dDEYb{J&3Q$xI66 zBuWAL;fRq4uDG+XI9UyrJ;Co?LajFme z6Dybc@}=|p;8AB7dnptz(Zce}yaX&YZ#jzs@aD$oS>xcrm`se71X7^aT?UkoFJlD& zfqc^AT_^4O6vZ8XEsiT;H~9^Zr%)O%4O+_}q+JROvP%JMcLF@HOU!o3qt{J@EA8ef z!16&W=UoM~CP8}DLzY+7;JR6ef@e8nlxDyj(?S^*X&6UzGlG`}NlP+*V^3Sb*ozylk^Y=b;{-IZ`lyTojlJbK+VaHZW;1+sc6+*iGNod?+N zRn7*b6OfImgjBx+eR-gupgd3j=V2N=$OAFwfjoL$EnJxg^fLz8-fWJdz+CLC8%URD z4)I)8%&eOTV`kOKpPBM!mi(!wAE}ymZ9S$U8}34gyE$eL-Q(f>?Q((M0Rp*R;Ckv- za>0O6LpL{hc>w}(v%iMk&V*?`&8TtrkiJO<>C=*dGlofCo=MYKU#%H1YM@S{H%OP) z4Dj2P1J?}XdDDgJC6p(hA|f-4a({cVfu@vf85vL}%2akZj~tWllNI}uhvJnN8c-&1 zZ~C{3ZA1jv2rLNSY(`DcKdDe1bPcovYz zO}Gort4u$Zz{HhR!f0?24?36CuBpETsXSM5*d;xeRh z8G_R9uKIvCJF;h7u(Ckupb@=llPD!x07Bgp3zt+c47$;e=BxEe`4^M7XdkZ*_E%F> zdCPE7Uu{Je-jMPAkz_h5lTt`}bayr&X%--JvYwVhf#={z)3@qCW|=j;6|bg%@y>6x z>VVf~G?aN49T=>@iw=(cf#Yv$H=yQf4AZ~lfc9tak^{73{tJPfN4vx9? z;;#J<4J1pZ>Y&Qo;TuRsK=3khc6ylF~O&mc1 z+EiAEL!}zOE459Z%6`2dI|-iL4zeCoJmX0je>zt4ja>d>b|{{662EDM!pY0~cs;{z z1g(bxZu5z2LWD>L<4jP@MD~_pLol7Ab8ace7z0=*7r&I;mDos!Wb```8>WE;T|3Y@ z6s}O(lME;7;-~CCdRXGl9CDlFk~=$lc#jrhS5I8si%U6tP4=Qrmgtc~ZX0&bu=^Cd z+t}U0I`?OPiWIJ8*W&OGiv|~2qArKr)tQ5fBEggSZfuxn-hx8bWrk)(h`17R)0&eT5luReM3QvOU<#QtghGz8l~E{Bghd0n#i+@a&^87xtDbPvm!!_gHChtT*2YK z2#=Z@8zEjyB>m74t#QlYo z{<;x|`!*MmT`8Z{T}kKrN(v9pqVUH%QFyv=T}2B3Na(a zw?$qe*~f)MdDtV!`sggOmnUYh=I2!;s{}oY9G)BUbiM%1WX;GPq*;kG5sLSD3ejbX zUd|-CT+y2>yHe3qCXb??tx5BG5anfFU$S?jl4&lI-H7)lYmk*8-V{hyv*uf@*?{+5 zQi(3@P4OD=rVdKwIhHLI9W=_>@$Qt$QgORB8=6lQKb>EoJ))?pjM6+H9%9Yioa^_+ z8m3#AJ_1qAU)?XK?;w0h1u~>EsY4F>#~0#hq#r5v7w7a11HH(y{*Xn0-e9^5)Eu;n zX$i;)I>5BGV@}_A&|#*{kR^e>V2Xt-6>lKeRJwxNG1Y>4fI909DASU@Ien|KF24`U+9H+S;*{vm z6avlupbGs_^ocwAwZ)KmN{rEwHPOY@wqH4DtWI^d5wbzzM@3tiOzjeuW%egosCFq+ zAyb$(j_G~Y4A(AW`c%<)rgKaY+5{#C$7`ldWU6CXq&A7^Tc(!U<($t`EjGFEUKH(L zC|{)L)_aqynu*FFqNVIA);!cfl1Hchl8Jbv>EU>7$|TLektR~?>3YzWsAXw&dT8rN z(SGNi(Kti)~sXAT`mb(hH8QKp_BMV7$hV~=( z5GUKK)6Q@zg}q7ksFrL{kBn=v+%;7^rezq|IYkTC4ZX|7Gg=3OddPzAL@$6yb~Kad zMJ3zLvh9jmwI7AGL`AnrF0sG08N4(ynBZX`a=t zX6oo53qNa9nZ9QFk9IB7VlKlk+VxENc)p@qoYQV(dYRF8P^1~EuVA{J^U_3rjESD)sKzL`nu*q+R*Po(8m0}Lmq>jr(*(BO zTz`(KIa_a`KhLz4sinS=sfP0sqrc2l$=2ia*O)LB0}Ju`>r4-GUJ~@JOas|^qQ0H! zccxbQTTHt-FG>1trW-jg$@*R<7h6x!_cMLO)LMU^X)5O>RsWFbDz@H6|Cq^S>uLHC zrWcsf^OOskgxyA^dF`IOoh>2^*GzZdq9{*u!VNI#bj`43-wT@+nCzx zO_^qM*^BT^I7$Vnp&g3#=1j+!O7#S$yE!kt^fabYwqCAhGBsuEy>&O!YfOFgTqe1{ z_tguS;@EmWy^v`c(*V7g=>g8mAiabMceId~p?VjlpP4H3GNx6WmrA_{Qw8T`q+ZUH z%GRs(zDx(0M(YEZ8n|A@>VwT&QQEQ;vT&(BjAf7FF?FJmOr^L!sutt*u}r@(P0}YY zZN*`(T1?ijV9LSeTeX;?dzcENh^Fe(O&l&nDQ;qvi)-~dQ^(P15RUHE0*~4;IlB_w zsLwPV(42%LYPp!J&tke0IV%@;fQ;6WVoWS)-UVs_&0Ao7ka%8yjOlz3P4tmv701qw zu4*XAoC|ktPjWjBB=^nsbEEyzc?kI`hFoVXx$W8Ag%C@0ja>kDDBNO^R&u_HQ%p=* z80{1vcV7he$?i+w-d8~(z1pnRog#_duhS_cF=MUXLfEYzj*b#~kCh0ywO}>eYx|S* z5YmYf&&H9zE^{5+8-|j|WcBbY`-96T5v=D5QejVeGzHKp`91eS_W2?2cqBw-mkXE9s21eb5}lZa%xC*)3)F zHFj54kYf5nfqDZs)QOec{hl97afj zM(&h&a&Ls|ja86&6d`Z6C-<5xa&Kd|O>gqgFFNYeOe^{vA$75z`$EbqHXvkfDYTHLxj(W0RD1Hjl&ZHh#4l|q*4YGdn-!6J=>SSO%(VgTGnH#~ zL)?-_;SjuW!+HLMOL1{oo++VxURWYc z97lcvOJs40aMeyF59x*KIrY*9@g}(z%|mq`FdLT~(R0 zWmQ923b}frv!yru;lg#OXNQ~I8Hwa>LT3xvWVPyT?$)T;_}wmk3=6A`R^#F@pcBgAEVTkc%Vy1guh(W1#TIvBZr+R{BTlt zggCp9zxgnd{#;4^2V=A z>C$5~+{XTwA|=Mr2-5M_up!p;o8D3rMVU9jt%Fn(XS&`D|1sVR zHX?6^SdW%9(7tow4(YZ4`CnRa7yKV&I^j<4Ot$W4mqw>3v0>!w=wS^njyT`M5;vAn zn(Z*kY2t%)a(nQ;(~Uz0qvvR19onm^;kxwmO{y9mg=_Iq+Y)2@-Am==afXi6mY^fG z#Ybwi8jjQ!AI&Xc;CPK$RUE0&$8h|$__&N2N{pNqAE_-qB3pb!Ml2o&=%{V+QQP9< zyCpuu@!b;5IJ{%Y1F-&VuVrvw;lBDxACm6sO~>dyZ68G~<+q~JUBd2cb{~VAfpPEo zmKh?a2aZZ&CHDGZ4Y32MPVVeUuAXqd$*_j#LOS25?@s3f+gg$PY95^rCa;S zSJ=y1h$VeqLht%;z)R?Ri9I*L-CFTgbX#$)6b0-Tvv8!2*&oZ$#{M2mmP+O3~Sik z>wFVUWVvVr?vwdqGw&$$X8TVt@>~{2ZW6mU_8|X?vQK>Dy6bR`!ndY zC?$6{yEn7@R~Cg_Qpw>-4EydgM55tO< zMD9z29!8&uZoXC@)-VqHb!!os|9#6s?cU~R;m(Zy74CJ;^KjdUv#9y_5wxegRAxAF zzoI?)2f3TDpT@dDSYAWn@o)#Zn{zmgJcHcv?5FeRLGD!em*DsXKh6i}IPONs|Ad>* z>G<7&dF?r*BfF(OH+vL~17Zk;JR3tfmwxH~lk}g$FOGF_$lt~7!TFIc9l6Ai|G&Fd zEVbIM!8B4uvVY5Bpok|9vB(;O4AZ4d>q-x=N<>y9l`G1>@H*XO?LaTyPDle?9L=t zS-E@204GL+0&?|2a?iU4IK9$tJ%=LX>MC+Cg|4% zoOoUbf8KZzKF$B6W}A^d`Z0C36O$mI@85Wrbgiyy4UFvyA*{EJpek`hSL;-N1k%#h@*-I zc3tPp6DOG#iGf|uIP=9zX;O1l@4e2p;&nwW+@)Guu|rWe_c_S^tthYbyt7dJ>Z7=r z4#JTxQ^_lBAJbVx`DjQ?nP}ysD`R?!EFaw((?=BfXhqBb(cMR{#S9UHeDq07g{bz? z?=d6ABp)Tjjuz8=)H(K2G0R7zV<(6^eAE#8FLA$*9*n(8tW>nLe0%Iv@us5gv0uhc z7pHuhX55XUeTFRGV+GCQX5k83(kH1!adQNH3y|I*`AO>NxCLS@QzK}0+@ULj?%QQh}CPlyp%K|pnuGx+ZK6XHol z*A9Is{-pRrQCjmS<4=j91yZwPiqw{P^zs`bV=pBgsxgjv5fatkMRj*+I5O{Cyh_&rtMNx zUa>HtyOzQ$zZQ!zNs|+LX)_cRL$kN`j-sPk;}iO5DIH~+w+vsB&{vy^dkmDb{+(AO z4A7POrTj{+f|iP;Ae#%WU&)h8ZIxJ+B1Xi~w! zgz?&1Mb*gl1nnI~BZq&IFi~5EyDgN;&_Q1$T&}gJ#|J=R?RF(h){ZgF;eG51t!X!s zEfQb1I+bvR_N1b56+b6jr7i3(Wj`1Gm2i!=PSF>jsak9gDf_LRomi_)WZI@LsGJiy zU0bRsV~8fM*S0Ha;SSNR*Zxw}wJVX`lTz8HKVBS_c)b?Ov`Dn-nw&UOo2jTv*Yw0$ z+T32!-ebl1On|nlH&LU|(mN*3)dmib^k{kS#QEAfMeh$zPh6n!(tebE(coc;cWHeG zlICLZL)nDHh1x=;2o1YrQI^ z=A!(0t$xxL_~_wQ|Iy4UDU0p?LaX1jnLc{E)p_l#qO0bU-Z>bxcCa(#u5_9tDVM~{=T zgC)n4uGi=K=!c|P`dLMeHpi3Z>epQ+H63k!NSd#oQ1ou8NWNE}J3-1m1TE3iCP{j) zAR_q@eSxAsL655s@hlea6|_xWtB<-|YW@jYr*Bf!yiNb)4Z8U+Da-9PI{78N!AF-T zzpDS?qiM;T^|h0|nzNF(>SL~uq*dOLyhDFkQ47%9di0f2_Q8nzllSV^DLM%{pnss~ zXVlq2z3)|0bL)te$%pl2iav5bll*A_ZA?Cf2(g%vJbL0C;vNuwkMy~cPUwM<>ut?1895l5Bh#3+tFil z@{a+uJ^74&NXd33ZBG6vfVL-})jw0Ro)ym|{~SOYlYh}qE7`eL&m{jEKpT^P*MCtm zC(`^gfVL-}*Z)$oBPhdP0kl0?81@vZU3r$L8EKMmZTM-jX0*7PW#XsypMzQ{dNS^0 zvTkJh=ybASwDr;1WYg%Z=)~ZY$qu7jQPqIok}cypMWeFpln~<`AH}CMF;4p^H3i>0 zx<*_lQH^LN6cYmH7VI=z~E2WuHpeUoFZAz5UNl|%a+mz-;FGW3*+NQKH1}mE2 zZkrNqj8b$S)Y2HQ=p@K#Oi}b@`?e`D#`TI;r*=$lyal_buwOM;=F{uM!Aprrt~vrD9WffoHD?8L{WL=;gmtf zc17Q29Znfye5MdK?R zt^Z}5QS=MW-L5o3>trflf~FWLidMF3*7_QwhoXByQ;i9V{%9B5y4Gl5Y82rqsja6Q zUntp(qIn53jDP#6Z_16vIUi-Wt~0KiDecWDDr#MCJn5r~*0&hvd^D}~ZAQT?ujW0i z?=+?;T2=XU>${B;KHAWFp)syrYTlJMFJY1KvXAL%vM>(la7?=2{ zTk2CrgO7%%t~HkVXkzNK#>+mMk-E;vm@V*!GynecQ#TkreDp}_i^i2cdLi`{;}IY2 zOx-m2tnKF9=1!8$@#Y^)w~2B2-P7aEs~3{yPLVOBUwWcBRnhdKQR%JBltw9= zUNkv9+1$dkSZp6$m)^#FOUd-SJ3zY?)#mm~PdA(1E90#PWtbBcO)GgQJ=2`3sIh8Q zy4xJMh%|2#N78nt7n=`C;+pRmkh6X19nDoN+bO0O9ZfGW8}9Sw?ECc20eLYp%FLMi zrK~o0UwU`5K+$?o53`@5X(i5#p5_Qeja4Zbz0LXuI4^8{c!2eu8N5wGsc*`6iq8>$QWx*RMc2?N5(ia?LoiwDFN1> z%$Q>4u#Bv~m~pi^!$&(ZJOS1}%(&KkUCC;5pUjwUzOQIK=z8;{qG=^xX54_U$H;s( zR-Mkc$=uH*&*W|kupXXyn|VlSPA^KxyxmNDNXDC9E*d%q>b& z&wD!a3A5?LGH129wV7+o8H(0}o-+3uvi?Kn zs{!^j*J}aP!nN5v$eOf2WVyDQM^rpLuLN{LQEl!IncK|1E2X{lpzUVKDoN8y2D^5c zy%aT8Rl9bX16Oli#ET{Mt`E%0r-){YqV5Y_hs`;P`h$*`>zQPW9rfibW5|Q9qvj@- zQGZ$EI%c+iTH2dl^s4K4K#T2jeQ7?WWVN{uy1q8IDOwLY8L+P$cYR|XQL@IW?_8(M z+-EqSysw-KupW_hPJVU_Bg*um#H?SKP$`7ST!Qca(v7r%ii4KAHlB8YVJ6pG|^wOS~$)==PmnvSuGu7)=ARy zp3I7KOj1;vdu>*Nqe0PnP@?17=cVSflGn0YIT{o-R_(}2aSYr*vf1L-z9+MC9OpJl zy1Q3ySiYmpi$pSK1&$mh>PvrS6*xvHnqJh*-PRHE5@}Msq`C_o-zq}yad&VueObzC zbN|dLaV%7{9@NQUz9MDQN`|^SJNhbWtQzg^>bU(il1c0R9rrNF>xcdUwRDTSzhfE8 z$ohTm0geruWSY~9o^TIx_(%5F-NPIquS;2N?k(;L#{xy`K_eXE4Jn&ea?oAr$Whc- z^_hE=qjD?BWL_o)Shuq$I>xb#thdabm3VOM%HI$-|QH(U8Xs`=&tP90oEVQ zzSU8%L&|D%r)1ym7^rAHXrALkMbk<)WZ&U9p{TLy_3QYFA1=IJbQ^_1Ix(z zkJ%48KHKHBuID@yVBMLs+|hcs*ZT47M;%=htt&M3t2|x`*+TVj&nZxBj->+iNbS_I4VD) zGA7Dx9ymntWUjvtu-+^8d&dfvk@XR| zKRA|rOqxWKa?b=$qlt$R8Qtz@zJ!B zH$(79x{@_k^^Q!il=W-B*O_Up zVA>W|J1D`-v{p&de<*N5bIMnwxlJEEymg-2YX3FS95JC++q^vMh@!#eZSxAOeJ4pK zdqF$vLngWBw6jk8WF>j+tn*B?8m4<*dn@G|inmjIn17R2tV*=aChLA8>m^=UGsrouU_G=R}UNmi#DXAIDyuH`aN)zL)f}do(RfTi&##=LfmNb6Q{JaU)7DX$%F3Ou^75+!c z5=Us_a;pndqevVvEAMjaXFD^yL;xyBmMIhN5#^h(~9 zR^M|Jk7#$^6w7~nKbkkyTC8NXxoh%jt>+Z22VHAzQ8caO$Gq#T&lELQ{hoJ&mGUd4 zDSPCcp#Cz4`;vFPl$U6oRSWG_CEKadIx9bYotl(?dr-W2K22I@b*GPLoz;9F(K@TU zEf?oyamf0SrP@7Kfg~}%;Fx)jHC54@`RVx!twV}7bW6{_*Xs5gm0_`X2y~ydU(uZv z$IQi6)8D1+3eW>qZ$+(&$0sbYDilS49<;_Ox*N3Ax?0gSpogrR6q%!P@|Rh6`KWFF z!`9=9KIm4Q|A_UnqRpTc)*eMGM?U3TX`NDZf4A=1V^-oHl(R^HAvB?ZKmeGV2xDtucE2>8?1?vLPFc#nZMCmq9_&gqP2%10CWu>n9~!2H7U-cO`osvQ6}GE7f4gF32`pO_^qg zduE_C&z{fUV(s$LEBS9) zrEwi6)_q}8vtRpl&fV5HtmNlW5vv0CSeq2JD?FUP$I5O>vPLniaD2jEtAYu6 z>9yCn&zh*Hyw@qv%Zg|<;eIPIT&B6e{YCzMYlV-#%YWY**G$STEjgS2k#&w9Hbt&G zWSa#?t+COPc9$MZIBt0qogOkd;d5)5qMJ)23Qkyq@FWMt`zz~U!bxj}qDv|dCVXR^ zQuG#9c6@8~#F|sm+?{kV;X7-lqVkHkf>YK>MPrg$7kqDRijkVd(EQP=ij{N}7S32# zD|)easrHjKQxUDt`pMd@h}LKQWSvqpqmQfLXKQGjOeGF0vVO4^GBt{r_>Kj?StIav zCCb@ptj{`cZDVQ_%kn2DX!a>ZWvF?>?wd%OjiLmjlxYubB`LelUZ=x0lO&DkQ(oY( z+bik|P0K!!EM*5OhZNX$NQ$I(y{ZaA>@O7E8$UTA)Q)XUvPEJ*`q+Xdc3(v^Vt#EJ zZZA<3Q8BTgnZ1q)YdO+91{PNG-F+0H|0fOv&E9k z1I-HTE=+R0O*^|>5zSv0+Cvr5{B@x{!bLg5O3|Wc3QFv$iaxJ+rl8dRLD9FM?sk8A zc>^@}xi=P++Y^2CMnQl3z5*$0*?CXFQ2Ui4qD7*6)_VoR>>W%rejX|qZhs&Nsmym) z*wMu@-sr4n3P#!!6;WPB+nW?oUM{s0J4j8+%LMyLrbf{|>sZ0R>~S5X?A@W?6kKg@ zSM+((F9o%BWQml0o@BMX!46zCH_IN*vN>W>*m!-GU85+W+3B!ZL7MgUbxL*^n)UWf zMGK)>Z{MouWRxau4vGg-vbIeU%$w~MioR~}kGgx-JJyOY9G#RhoZckM7HtOv5pj77BwMzCN ztk1J=Rx||G=LKorVc(@>?}v=n@35CDS{i;j?2aJKJMAZxtTU|NX>U~YBdp&Uq&eT- zrer6P=6rjd3TWJJ$Am5xx)77_t@PPeIIc&@}3~gh4zR5&4u>m z0h$YgG#l+3mF&~dJ$j=(U(qV0*%+jGul-nn=DqgD0L^=YG#A->m5f?*k$qSZwdSHA z&HL<=O7rMGGQNhus&XdB1IRku`V^YW{vZQc)FZ{{A4%#deaCJs1|(cCnqI zXh^dpP+-kJVE6ZFM%WM7BYm2CA|D9STw+fO&|G5A2+&*-r1_w|AVBj$dwGE7gF%{0 z?H82n+K>o)sl7!}r|>)<|B4hfaW7Xn#=7gl`OSMNYrxs21SROg@XcX zeuaH&faVH&Nq{CO59ZYM-=p?gCA%y%B4gT31=V>zZYO0@GY&w^TCHTxGigG*<;_K5lnWvf;?*<94;8IOOy3AkEeG zEG65C(Pp)Mr=q(s+N=)Je8OI$WUaApK4Cwu=w$fONXPZ#Ur_V`(p(>;`MkYV$=-nG^Y%VPw;|2vgEU{Tk0@CKO7w#LjiNp%(F;ME8|+^K zG&k60H`xxPxgkh%qupG|zCaJzXeTRr3iY`$Nb^NISIJty`ipiaMTepJVvy!bc3&my z3C)-6N=0F?{!);+hV)n2XWCRl$pNb@y&gOdG({`s1{Rne<2X$v&=#jU%{Od!faV)^hXBntf;6|-{gv!) zlzodmQc)$!z9mR=t34?|bE{n&pt&_j^G&-!$*w`!-?Z;il!lsr(|$1(r@6Pq(MZ4S)95|=cAsoq%cGIo?F}lGKXBE%Bgpy=yGIXMOLefm!ycljEv)ab z$12(l>pOj#qQxG4r%&@Rtovo(!unf2+10TAmOVqI5{fJ7T|w4&*;Y?!eJa{$m)$~9 z2eeVJ=G%5_C7T7!x9vPdy`cGaP@22#E&*xow)+L7xjRU6k3BLV%{}(SfHe06X})9E zD%qnrcD!TXtY|Wh9q$Bb?zQhyvL|p3w%1;wXe`dbKmjAzK6`(F=05vSfabm+&3Em{ zUb2=b&3ElsMU>{dL7MyR%K|j_+fxEG_XlYnus15%qfPec2kb41Mn)cuJP@S$o_$Wq zUV-L&Hh)|i#~cqd-wV=w-|kp0^EtW6snGZBZiSM*%p>P5Rm5Kpfo?RpA1Oz6T5X^%Gq&F^OK-7{W41P z6FZAFWj;R%O7n=_QKrKAJYvrYNb^WgntmCjdBmO{kmiw~G(WYM1*G|@{aZkqp9ZDr zmrE%D z&0|4n`el^nG5ee^O}tOXwlSmbJ!?K@w_}p?S+EeWzaO)^vTTm1HRn5z**z8A&~(1@ z3ww;BJEP`1zqYSYbfo!w=Xdr3MK89P@BH3gtY~NSeCJR06N>t^obUX_KB4GK(C_vS zie7ilcm8FE44{0@`G44Z7dW}9DqVb^Q&nBn-PNxoAR!MLLnJXFNx$-d5c-+WlB7H7 zPC_95JC&~L?jqGyO+At{CfW_6AfPgXqmHOSaK;DBfTE)E=s=i(At;Xcyo?5k4>bA% zWk&g5y!U?J+WVY3)m@z%nYlCE-!+}H)?RC`{aSnPwb$NfSCv}xrkl?6h1v{Nu5LOr z7}{c}-!P?t+WKD@7B`&v<#w$N-tEkfxVLTe3m6x3y*&lqYKO79BYZ>U+&OHXLR zP(MRmc7%=@Y7^>mW$62c+Jd_Dg-#gi8q}pf^pc_8kGc$ooIZ-8E_*}#7Vvdv@tg0v z0WEd1n&I*p#lvIE$-j9sWya<+T;9MiIhN|_o*Wy;7_$^1@`NP5DQp_aLvNwXJ!>fQ zopbpO`S(fw#rXlrt)w8gd|529x*FdA)m>d}<9nT|t9|&64A$hL4wh1ndg7bfYFUcr z@7_WF+8s=FbUP&pZFS}fhG$6KzO#_wdoLmXD}X+HzX@|-o&U^#y?Xe?YU-0(#kU6n z`bDdOQ)soiI)LwAJC)9v4}O~oqi*^>D!)kg9dk=w%xfEmFa`?y@t!r+)qb_3J}*);)ks*9ughse!RiP@YHPM93kMO}RnrC2H^b0jgF;c@81Ru^y6 zsVGB^4;<#!yo7v0TkRDM=$tj*$&>P$qx00ziFI-=tV5v;%Q|H0!1^3Q={_|FTFR#) zhkQTyQ|0reICWq?SIE5n;#`J%wlmfJ=p91J=lMRvp$@gA!zpG5I8Hd8QRgPDF^<4{ zU?2SWeyjg%e&o$8m*4+USf4yUp#0KaZ*9G?zeLZLICj|6A}v!QYeDg}|0hel2jhXO z3HyD;0=Dj*Z)5L#aIp?Ewnpmq&bKkVN%)S1r%bTdfzDjWb98KewC5$A@$coZe>q3| zW=;irSra|xnWrsl2Uav$J0_QsuL)Cm$F|N#kNnB0Z1rK3qRY+a;MB^g|7&Qw6aLX! zCtO^frLVnA%S;zObq>X1ZI#6cWQol4YvLQ|w%AyCZPN?+Fuwa$>Zv&;jZ8Z=ti1>= zd7)UX38b>s*{HuyJ&jiT)wf{V1L`X%r9{m+hxtsvqI#jNn93)q{E{jlsqh_kNTnq) z-;tY7T`75zA5afqES0Fo7IPK&s#u}#$PCi?Ys*I4t7pAqqyB3-T*Z8{9{FXZ3t)ZW zddKxBXx0>6b6Tp?mHdy-^Yv+I>MDQgURZKDM+jS5*gJpsrsDjml7DIrf2#cHmw5V; zr(cI#>Np050E=m9YKhuMdRpvlq2{?F|KGwNz)Dv*9;R#Q=}DeWZhxB0ci@}Rs!*%J zt@Je7*5z|Jy;$}sJ!hR3-(4#^KHY1dg-7J%Pk$J{_lVsPzsopZN->$!jh)U4J-wV( z$m<)Q+7?YO{~vFWrmOS6$8u^b_pt1AevFlcJDtgTJ{_5UnWuU@966u;^(*XiOH>Gb z7gSx%`F?qQlE0F5Q1^v52QUBiS!|u^^es|E_HnwU-qCnEeD7@a%6s{z9@S1NtxtL~ zdiSJv1m3W-_o0jvc6!0FEnXi|>vl3nOP(%dS=vj~_4(h03+uyDxa(7AWZ~54wBbFn z$Gld~a9)|iw0R%cHnk@Y3xp*ULF}0aGo--rrxq-!Kh-I{BZs70-veRHt-?ed?RC6JZ}Y{Cs^JPJXo8 zX64m=s_mW*bM?ngN7m(kUo2e`mBWp0&X4K(LxE65?=U%>ycNdEjn^0l|4Ic;@^=;u8c&kVC}_(EO8z6U*ylWhsF1GK?m ztd{?%XVw%um8AxLA!l5=Zn`ZDJEMYmI=N{XmZ&*?Q?BM~Nyhq3>G^!{1$&J6%d6x$V)I)p^N zRQ8Nz>IBxxayc;wo3jO-PZ>^P-`MrcYr`(Ecy9z9{<&_iZ|wb9Z?8{p-nq}+jbA;3 zy>LK9U?rS0!>d|oF(QDL@`nGc^Vg^IH@e>NPN9)&K}I~!O;`o~Y|mfsn)pWV>o=+| z@kZC%>39x~ZvQiVFqUPjPm3=%yPo#^gq$1D&RgnX*|YdCqiy_38Rxj>ywSDoX!4Eb z@#gjBwUFNM>5LQG?1{X&>2>-4h?kDjavQ&3$KL;ey!{X1q|4!KK&&6XW5?0Lu&v&4 z>E!TccnG*TAZO;E$GbngbCg|=mOuTRPhWCs9sbm^rsgn)U9GKdKuh@>e%x7i$yqUV zVk--`M11OECVJAvA1)d#4YJK1DvS8LyTsb(7p5I3H&e zmRc)gPfL2k`X-xG7Hg%$pO;Zx{QiTt6dS)s<@An?-=K2BS_WUijk8U!eBqgf*Q5St zykqjK_siL!_uRu9<~X$QJC2U_EOQgddp65c(8(vC)aPGFi}c+*wh>;sj9A@XZ%dhj za|dH1Zt*#7;f+50qAj3bHN2JllOj1^&U|nBFK4)2>q*If;KAGp~+yG(ScoT^^9KyMo?cQ0^eAddj#pFo( z)Kfidk>>074!rf`Na~tvJveP){tLwhYK{(n(rvG;7K$CX2}>QgVCgxEL}W}P+X zz#R3vYJm+f6u|m66PM)&aRa z>)hJX?<_RbZz8;Pctz&v)Vlre@84qVp~Ta_uWL!IY^gbZTN-oLuWpmtJ|U-VUzXFe zsEnEAfH;SpJ{PYtJQ z*QrzeIrjfX4QT&O*W7FO9+MT})Ns0S@@M|3?(P5ScH__b{C`iM=cr?<3C~JAtMIJG zvj)$FcrL=T7SF|a*5PSWA*)+8st46pJU_+rqIwA7hY)@U;fE1^7~zKzegxr15Pk&V z34|vQoHw=z3&IwGodUNA+$k_3FfQ7U8)9?-Te{z-sj^>)yqddQv{?c9;6`mYLR*^8M*gT0h3;x}F!wJJha= zmRfhHcV9?&{q`oS#=aZBtT@|F;TJg1wYQ($Vcn14XnyidNLvCe*N(>txB`27@=i@Kd@AHy%Rztz42;br!-fNl130-sdAH}A2ZRIi*n z0JwQg5-@gg4)78D?(;{j!*Bk3`$hHQjxT{zx-N%svg2!j*KdCmochb}25c1gk-7MM zEcgTV2`THOlztyd!6$A6z9J>QCeV*ox7lHVvjol+c%Hze0-uC7?(;nf&D`f}wAkK8 zi*0YW_zU1itTWDk$=7c2H^EOz{u_}B?-s33ZJp!aXsvBJ2k_dnm-tWOd(M_1Ol_Q0 zj6JCs+i7oZ-3I=n_)fHw>etIg5bkJtm%mp^-z9L1{pj)^`=b(02;6C%bNQM8VS6Ae zoPz>iMjh@Ayj#LI3%t#u&Tp5R-!3)ZV)L5>1 zLHLU1CBeHS?Ol@gZVBHl;l=n3tPyLm{gH*&Sod4}rlEZAU2dq`E=icjxEOB7e&g z|BGtQh1H=OtJaeHkO+8Nl`D`~dLX z7c$II`m&6}xLrBp@9m>fieGX*DtR82vW`l*VX4(o$un+`%-`k@%g71a97SQ9HH=Ey zu+92}Z9Qu?XlUOlIm*vyIn)2SKB}7N&#NKeIMYiiwJ+xb#3WV$?XK*grD@Cz$df_+4fnYhq=<; zMqQ%lvt2ZNwe>{P&q_xH#;wXNKP%m0-`~u!z45}6rE%*M?Hu7dFFe02Zk4WM_|mNx zAlxGG4;M20-TCBydcjk$CmSwlETdIfTeeopdQf`pK`HAzsmX&<`h(JsOQlv1NAi zH7~V#diU6+*3RDFl$Ba<-Nx{WZ45t9$MBO0AxiQl6EZUzQc;W%Tu; z@~p@|C-TpUd{)}>DrWkc^5-P&t1`!5l{x;ZtTnHyEtvJsNuCF#=C2~3W#DiOzY5E+ zruYI2v&mE|s*Ysy_V*O5B=$IHK7K5GB{iiz@Zd*P;#b*r6S z{sePd{$0QyFMkd>?CJSQ`A6-GFSy3K!-`$@%kn$ywM{R9b9FDvdU@XOkv~_ccT3H0 zl^(y#X1{;d{^GWhFxTZbg^x*#j%hv1m_H^hIwmc8PR9H(Y0=G+&oPFLX@i z_%Ymw8A6zPyG>+HNNn6%gjqaptywq{eh}s2yGHF7F8EORdAsYJ&w+F8+4llc1D*B< zn%9?d-Tz7WNm%Ar!^do{)W^`eneafUpQEz2zGz?H{Hcl;?VrEpGk~`(x)<hX=P;Ro2)G z)}2{7Zta_Yc4Y*T=YdoCmNNnW|AmCj3(l-ODy#odS^am4zr@_?Do3H=YPHzzJi7|v z=eyTb9ub|tDA4j*=jSR*eNVi3ywdXhdReaWZs_(fBrCS#7mlP~PNIhJB1BiS?W3Oby75T!hT}K68{MapR}#*BmR?iN7KFGlcLp=HvN!W?cwGB zqw=I$zJnv`h8;_)?o&(G*Hy*sMEAv2b@2Bzr>E+q^h@0C>wQ!BqUjezM&-L+J(g_y;^83?Y6Kn9A z^yX{QkLUSljbD?VeNFmwu8-e?-idmyFYQD<3A=ie;JmVWed%KBjQTnL#qi$_R+ri% zZ`ornw!ZP!>#F1S9<;sFE_>_x(xpC*t48F!#J^TxyTFYCdj+;ww{PBKw^)C>`8W7N zo&fx-7Hf9%Q`Ifj8VqF4j*<#%x{4Wast;>bKocxZ>-$JUM&EEt3 zf`q@0aNJt6_D6uDveI3Mm9Epe9{G1#Pw&`+uax+2JAMOBT|L9?^}i|GVkHo}#rne~ zPgU;}$(>ez^9h9en|}pZyZN_(i#PvX!he*oU9;0_>Iwl~)>Q!*>6!_c?wSp_c>($T z3&=mPfczU4kbiDVE#Q)tw@CN`2{+V4tiOi+k60OjpT#N=vBm^a!x3u~t&Uqilos8; z;78SqeY7?q{9RrXQepLWz-qMzaF!YboGbiV;hd)u;4D&C11?qjYG$YpA$ErPsKAc{ z+Ulz+J}ZPB9CMqH+>T1xCnUFHlEX9V9f*BajRAgNT@U!2Vd38;{JVv7uW;@c&I2MjA^fAle?s`jg#V1x;akFaR%-H`NFEo-Ur6|*gkKVw zfc=4*uqw6p&I+s9_6T}#o^Z~!bF=W4z`h1>Fxwb zdoUh8ZpV@K(*lnOd|KeQ1U@hD*8*qzSjxG8VYSeA5aBurH%WMn#I^uJ|2~eiEk2I4 zULVW4+{dzZf-^(C9kJ*Uz!@qc;i$+AiA-ElC47U39hQ7@l4=y;u)5iI=8PHY7D;u# zzy~DlgGh_N_I&14;WF_+j-g!a0suTRksnPaw~b`l+P)1@c7ACAXJKIR0NL z;rRbo$>9$r*CU5lC5P8au0{@jlpIu$Gr|h8&i)|l847alhl8B^vxI+Ekgb>-WLdRA zma<6rONGBe_>IC}9b{XYCAM8+H%ho$!o4DSxk&C7epL8F;D=Qr*azK?1f%G$x)A%c zMc@{J5rJ0=92a=2z&ij#>b?-`|Fpn`r5t;U0YhqygfEtGtd#u~FWrlrhfA62kZ{Jq z38`Bp{2_$H>JH(2S~#CAw*K%(JD`*mp$o z`=xB%^N>VONvanm)vrbJWs$MUShqkK%PK8nDHUa`|15!Lm2o`GE@M6Cma!M+K^}ck zHVFQ?l4_x(S|sv|1ujJ@SXYr>Bl%w}k}V?H0U3<{GPWxR7*f|usv9NMEs&p~ZWYcQ z0zWPM&kFw@;XEXqrvYI%%9&3cAgoh4YraKbq@3-Fl~d=VA~P=VMuE2q{ItOP1pc6$ zv-Np_FA98FU?9v{KQGLlT_|udAU??iKE_FyrN<>aEbw0{$gwIJ8>nQsM#5)E_*@Au zlyIGdnPHS^y&o2iCpvt73W z&QKj^lfOyeHbATzbEvVa=a8QR#Jh2DLTY>t`|FlDO#4wlSUll;39(`I)j2Hjh@}02 zr2VNtYc6vroy(fU=CW=%K=i3_t{2WN0zWSNJA{7^!Xfp8c^s=R1LC3wZvMYr@JzL_ zj`SS0P4EJh6}&_pGWdfAf70N;Gx#BcpBCJpUJ!hddP#7b!I!Cj6S~L5U#SB1EU(|h z?=?81mI?nI>hk)2#9xQ{U55{~v7Rp&yuhbvUx~qGO5KU{ZNQX!EX?m@e|wFuLgNJn zw;9}T@O1{?Y4BqPzhJPh(xf-I&ES56uQT{ggC8^a1%rK6CcVLJ2KO6$oxz8JS?@ay zJz?m_41L_tFBlpwsmS|)+0I%+FEDhoq1z1IZ}6DmUuWpUhQ8C#6NY}w(8mq^f}!ye zL6-|GieX6W69?l<(9p|3OaVME_(=m|qVX6WOFe!SW2Dcg9Z}4>n-)Zn&z&COJ8Tti-eP^0{3~n>H-{9*EzSH2x3_c3X{Eh>2e!O7# z3g2u&+5)B?d2bM;KK$_7<}B|7l4@`UeoFJ0ZaadKG)FAhTd)Pn8Ak)o-p{h!3sCH zSl?QMn+@J=@R-4e4W2OgxWQNybb5oE4c=|=n8Ak)o-p{h!PqwI^aeK@yxZV0gAW@# zVeoN-)jX5l;AVq&8$4$4VS^_OK5nqWT_tJ1!OaHmHkjZ0$N0krPZ)gMV0Dg3Z*a50 zyA2*Q_^`nf1|K(A)tdAMHyga$;4y;_8$4m~af8*lCcVMU2Jbd_%;3WYPZ)gMV1>JE z(td-R4c=|=n8Ak)o-p{h!D@j?Z*a50yA2*QIPw;yJ_bFG8+?bsM+`m=%z8X;XodS; zq%B~kt2OkwhHf@=i=lTLI%4QCLmxJH!ri-~dV`w{-fi%h!G{f=F!;E^YKcj2Fu#L=`Rz7%%;3WY zPZ)gMU>r+{e6zv34IVT2u)z}sA2(QCV9GVP+2Gv2F&;~afyc<~bWblN+#|>6* zH~AXeZ18S_#|%Df@bUL4^=;?_i>lyegLfM|X7FKyCk$3MYx!D(n+@J=@R-391|K(A z-D1)i+-&fe!G{f=F!;E^>iwpE2Jbd_%;3WYPZ+E|V9GJL*ceC$nzJKz)>ieVb4F5uZoqwhOVt=Rq z3jaR;d;B;1|HA(f|0n!+`9J6Xw*LqI6aHWNU-JK(|24lI2n8+(Gz8WKIs;vSZGkHT zk-%VJIFJd92Hq98EAY9%mje$5{xR@$;M;*81b!U&Y2a6Zmjeq*T1zf1*<8|Fva4iI z$xunMm)utJ*CmHb{-)&ak}s4zQ1WoelO^9Qd8y>zN?t3mgQ4Ke;OyYSU|n!k z@Zw-wurt^d+!nkl_}k!X!P%j6L(4;d6Z%T%>!GJY&xd{+Dk%+@E-t;S^v2Q;lzzDM z6Qy4${fE-0OJ6SamvxkFEZbTZDLYX1uCg1;K3VqVvY(dyuB^IzcKQ7B73HnvmzQ5v z{;u+ml>d)%D_k9(7hVuv8eSb<7v31&7LJC;!ViSM8UAJ1s;I6wtK$5MrizUf+ba4h z1}f4O*HpZ#;m0{;TRwR9{$gNzMA29_hsmb=z^1$x?H0 z54Ho}9J&EB`%;|Hcd82YHdTo$;8m(uRpYFE7H&zMiQ7?U;a1eyYC_G$EhsGH_+H%Q zn2*P2Hv)F8AiQ?jYQS#`+`V=!!kaE5=c026eeedgJ0Uwj@Wl@q|BEEJ}zSn*e;Encd#@cfL z|H_^R_*MHHz@ORYLjLD~w)%y=0O1z_ZS_lgA;P}`wDD%}e1v}uh|d}M7X$9{F9F=` zzW{KLe>vcQzYcK7-vF5KHvuO7s{qsfHGo?7(~#6F_Fi`Ylh_YwPu`XOQ;QO_ZELLEo!g!&0$C)5eVPN<(Dc0&CEu}9QN#2!(< zLF^Ir5@L_2-y-&idIhm(tGB2I-0kbc2;HMb)FE{P-WA=YzKD{a!aJWA)Nj;($J?5@ z)-J2xdbc&tUTb&S&)Kiq=lhoVF7e4x-Z!W!{bam+^ zrCp_0ltxOompxeaRN1p-zb~`POUrka_m_XEd^CJ8d}H_%;r5CLE52WGcjf(+&s2V{ z>g!bxR~@MeRie@uEMhyPXf;{ zo+PY7O1%ksev`TyPa01KPZm!O&ptf+@f^T2isu?U@4#~q&mlbT#PcpZV|d2#T#M&A zJnzPHJ)ZaAc`u$D@Z5;!eRyudb2FY>@Vp<-2k?9l4}Mot{RN)C#B&>-58?SMJRipM z5j-Eo^VfJjhUa!XAII|vJfFmK7|$JeK85E_Ja^&wG@ie~^S5|DgXgn&K8NS?c<#n? z51zln^Y?h}#d9B?FW~tip8N593D1}Dd%Sx__Utb^m_b#DB-&?-~39ga4bs|6*{1PwTnOr}Jy` z>HOM!I=>FX?=buh!{1=|8w`Jg;ddH-r{Q-R{$+-Lnc-h%_?rxWli_bN{4T@qGW;&X z-(vV%41bH^zwFobf7!3=|FWO;uU5bFx5{sK{tof9f4@V#5A)%760g*efNuX|0iFJ_ zfKLBdK)3&K!++fHA2+pi@q8W6V|bp%^F2Jz zjNmzl_=Dgbv>){!w66y}KX4GT2kj35KZ++}Jb#VnTIBO7`zYkT1DWF`j|P5aJsNl#&+~Y$v7fLG-1D-}aO?Xz~S%qgco;7$b#B&i=ueEqC#?y@Y zHKTql;J4yw!_$tZ1J8OqZ$tds5WfkSup77=xCgigcsuZR;GMubfp-D#0`3Fu1KtC? z2e==%Mg|ZbKzI=OUWM>g2oD1f1CIcY0OQ}J_V6T2^Y5LtLqxq)HkiDU!nT?da{vhyuT%#j*NCDK5fT6y-J+VZc|b2%A(v=nk#l@nz>kHCKb)9uBm8qigFu@avO_sn~HK*7Uixg z$}P&QTUoTaMY#<{xs64+O+~pYi*i>LhQEp>VZc|b2%A(w&%(^v2D^`@-P?XzLl)JJhSD4#l{n=Eyo{Ki-lBOCA z)!x<9A4$Y6cganueI9CK3bBPOk>6P$pQl{;JWJ%SD3H%nu6&-gJ`#<&(vmn&4Mq0G z3R%7J;Ypls_$WhDh1^WmN78MH_(*pmlFXO0IaZ9jH3i=!FC>+n#G`K9tlieQoUU|s zC`EV1Vv*b4n56Zl5&cc!wkBf9XkP}_ij&~@=$ zNK`YHL|-}O8#lkMxFcN$zLuz;MuL3fYP-EnH``6vFik@6v+(y*1HG>3G?HL@%$Q4w z83W}tV?w$%ODI(aQj0u@HV?sJcE1z8fXQ~;~ zd5XC$G*tN?ogK;Ca4a2xPlSk#@k|y7-=*uEcGOQ}2EjLGa2knv@QoQn4boXTYH(9E zOp^+H>3`sDXd;j?iEhei5`yh9i7q835mbAZGYo|&7?|L=V-8_=Bq3}DL%nK`%TZ4x zJ-WMI_1CMGY$RE)`nuy?`(kNR=Xzyo;HajqVH)LuZzcN<^>uZt+8S1^Zf$RCUD?*u*0Q3bWlhtHrn;uaj)wIs)~{-7Tivv3Mg8ig z_SRKvR<6t!QM{Ij&udMH05+t(r!n-j!&WMgsgb^>yt{4Qra3+Uo09w5(p)(6*+nslB10y}hxip?*!<%Jr)n z8&}~xvA({erK!DfWk<{EhSlw>+Z%yaG`U4gQv%p|eF#yY4>x(;%4u2&zG>w&67{ac zGy-7fs~|){72M=?tEQ;}_{Q3_rG`fmG4ZM4b}@me+cZh*U5RM~z|PlAh=RJg$?H~6 zQ#bHU-L}T|$CFW-LJFIDO_QvCwQ8wf(a>5~w`NVps@3fs4Xv%Knp*2uuSY+x=xDEB zzj|d$du#ow#x<>Ebu_fJwbZX_YH4WgsBc=mYUL`oh-pf2jul zOueT`R4)>a)HFh1Z%RdTiP$=|wmTi)hs|0iyKOj@U)sh@c#Om8s zZ)&7HwLghaPdpmS^rusa1Wa$cif6XQ2jkH_spu%E^;ifS+SN!pH4;l_M?2e9e>#TT zTY5INcdW;o+#Ou~WS5VCIL5%zp$;LjJ54OH8@p3wxRk;B*{M>p)nT-DhK>9cUimB3 zzDOb$>+4hf5j3DBF)|cUZ4s`ws(+6f&h)3!iTEDqs$X>`+j4v2#9g_p4n{|lkzued zjiiTDNd$UEGuhbiGOSh!?7E<(%(4x!WGpSoaIT-hy91qpL$sxmSfH}KDFjgWWR|XH zcP!nnMw|e=f*q03kyJdH?My~v2iB)k!y?f?C9R|*KxN~CSXYL6Bk93dwj~+ujH(E# zwl9W2CY#1~9)Z4eER`ONB(c|L?&J(d4$!pji_xdcjew=I=t?69B_lTp_6^6A-KkU} z7L{cs#%Ly<%uDUL3MxS)Of*FXQmOXX9$0KRHZh$w*vPdnI+cw*YcaM+x@oB&)Dmua zLaLH!9R=NgS>rgBbRS9mmCDfiuX4_-XO=`3Y0*LEO!jUI}HYKzJ z!y?*pAf9Q7MwN^{hlpo-Vpr#4$^IDfk0c|5v96>xDvrmuVDjjEBM(M-HQlV?O@+wj(FwBrD_IH{Mjh5ywOt>V=d;L)#-zSu0-l$-weZ znD!W@+1yBb4$d>0s)hDp5T?>PY+kgfn111=`bHu-W)#nK%B0kJy5YFPjAuAWS`vxW zeu%8cnF}Nov6(Ec+v^8(rKMYwlZohU&_UzT^K*>_V)F) zVrPIEYT{r>QB}^#sd0KvPvws|r(9EV%cioM;+YJx*E6UqEyZ-C)2Vc3YDN%uM(`;_ zjLuIXu`P+oJWYH&BPO9W7f)c~cFCaSP)kE$@EV3ANzUi)bZi8pPqmB)YVXq1NajsT zVt-^bvm>4zGE5AE;Z({c;~AW!j#91rBk5?SD_s!lOjVUKb5<3&1uBPb&0O9SgW-*; zt*IO!jLW7NPEDg~SfgB$V+i&+4qh}i5XmL7d>L&xv3zhu%fvHS*VxIaH0y+Rvx*MI z(KBFTP*zWDkSlOE7lXD$Du-&sFl72;VmYDx{=L0vlG{e2SX4LT=n_QEOEAa$C{r}8 z9un_`u?itgo2<&6vM7Nx2GOPCPQ=F4AdFydN?Q`gCMmijJBF|b1W*>2@7@SfSbn2jN59L8Be;w?U-RyfK<)pg3@c6jI7?28zGw2 zW*fG!6+Me4i@7&p9FXFmU!iMzA_FmaMlsdXpN$vJlI=-A<*kNiWF}OX7 zq+`&kEclAO$0JzPvY)U6E?jb73Zd2*Ht;5FoLm?Wkrj`Z7Sws)gwDy(r;g@1@jiL8wn9}mgmGre>@ z6kg!qosl8pnO5h84$m+2w8dgeK`x5@qy2KYMqPO*GwM7X^ot|f&9%NO346zE@Scm_ zLRV6I7OF6o2HB0$bIwgUNff7Jvb)V^4GYaZC0uXX#C$qOa7sic@8+bWT3GFJY$SB- z_=8>I**iQe11mBtdHQ942Faof;Ai!!tt?%7{s7SGLZ;#`?o%h-Xy0lp4pO%XR}=WU_WE( zve@W=1oY5Vea^6Lk0r7Zj#V+ivZCi%EFn{b7j+ZC57rAkybpI8mPS(tO!fZGQe3O0WK2xx3!pl1ur-xLDKu?R#FynnCXBw6J}n(XirD> zZ-k?b`5o0P9A8`ZJtXHbv3D5><=dK4^cv;Y3u+wsog&IX$vN$%{lS9;oT--y6Gd0N7 zG%tbNx5qQ_0v^`^E)~7;tXI@!r{QT2N7A_d;FP0tj-@Y+N254AarxXE;$}d~!*X)r z8iT=CJQ8PZ1Mxv~E|Aa8NsGOX%=m(gorN`H+Jn<`Eqq-wl7vPL03J*7=JJW$QR;CBurTpp~U8;&`G@yuq9 zdmLPN76FCiUb0`@-FziJ);`$;}Rws%OA+dQtlx=s!?f-0k&Pyi@*tAQtv@w zZ%x2GrISqc?pQK3L46GF*b1J4!>1f3YVT^xVbiSGOFBfWt3!P_&K=gl7KCIFYLYrd z{|}`G(~*&(ct3A^NqJM4?Ok2Yl`!}l&iNM2mt3d-59iTcxSNmFXuvV@y+hdbMqyYX zr*B#yKD`$w8gzh#pI`2v1!q~rLF(X+2(E-7CA)2e0d^)2sZ~#Ik3Oz0SS+~&E<@`@ z)Er8Sw`-2JV3s{=gyU?=>9fcAG@a>2XP}_GYpNoN42FKJe{bhNr<@D=y|ZS0u!ckd2TU;dY2B1ME!7nhT8cQyuKiWh8b8>fG5eY}4(LNNWeH!U@E|^H0mO)cIj;k?iR6G{vGt2-ILn@2I+31dV z6hZ0$lUx&2noDH$9L$T!jLHjoNM^EMvSSW9MBYZ(0VWv(x(zTW+*?zl>g(5^=kU3;!Vukj>NcbhD^H_^mSdi_LSb1xQu?M z27MhPnK<0~?HO)aWDKLWaoAmqX2ruXI@s7w>~$TEJV)D@Je_rAF}fs8KMu;^V8bk` z{#-h(od!}E+;XmsSVv@S&twQGTa*F|v z&qb50dMiR2CZv$=3ui zbm7|JlscKg!S=9z@#dj9WwUN9Z$HWM)|phSa4eE^^uqOmC%XDwnlqd9kY?OwI5_65 zBuVTkcql9?Rp#)E>g6=h3$c#U!`{o$5w{QV_~F2noBjP zCJ&t)nW&fIyJR;?ugs2|UY!lKF_j!N!ELZVPPoq-&Upx$Y$Lw`ZlR1HLwAb043VYk zOt>2x-24Sg!|a2}fCb>aa>EflIfaTd% zdiZ8X#Bt~Bn{g%t9}4rBr*Ii22R+ z9G9SdL9E$yvyjXb4rS8Zp*ztofdO%K4hKBOci-yVn{c%TKNZ$Xj{hBpcx!CHTnAAb za1w`Ix^q25oI(tJ^R~}@aiFkI(UV|G3~VM}6Xr!-OPXgzofi;T!nieXJ_xIJ@|Hi} z;ia+fWZRro0*ALnWj@+ z8e>4;xsi7lE*tw)a}MNTVUSK{nimYN5WC(bkO{|h!ezMK?{eJkcR7^dICdEnDPUw% zZk*AUOKUZ_WI~oZmxPfqZ{*D-8kaPOUs}nm!H6Ts(p@6|i4-iw*`C}842a$cZ_)G9&W3_=^rsKMR;bV;9z9q zZG2xLBtPI1A3?^v5DX;UC*khY2>gz`11z<{2Xtft6ZhblYDBoX5k1uu-eKYr8!qMG z*jr+-H$`!H&4rV16e#E6sJ;{0KZ46p@KbS4uXxN3ghPrn&R4k$m758%G+#n-#e#Q> z*P)Pby(EXz2Qz9MCx?a88h9NJrSo>EzJwIzkaD}MHFixrmUdWu{k(iOi5E5H_qFB* z22hVZ8ga_QvBo>gw7&f75PDVN35diw$7;$`p6Yy}T6bF>7#_#AOJaAmZ9zqC2Bn_GFypyFHF8 z1u0(L%&3^Y>!5eKxCGG|g=iw7M`Z!G6TVc6M_66yjsvlNzJD8Zw}UwK%7^iG+qsW~ zL0zzI#9@ovQ*x?e4tAHpt%MOC!R4`ixZmT})QRTG%_Dm^zE9uAboNLYSgRh>1)x^sQ)rwcz(5bwsz$lZ> zMsvjJ7aNSojM_hCYB9)ZwoqgDkJ&f%~madsmqhN6drW2qN(bKMDL7QD3FET5!G zWK;)si9kjV+p@UGu1p%UMrt0mn1eA+6f{D1o;)qV?D2%#^Jm%e%61t~EFi)Y3@Fz4 z%91*x{faiZt!p?~(&(IWDjJR)T**aL!@yoZPdB+~YMAaE^fFyZzT=!M=;67$mYB}i zh)P`wIL`5wTm+w79Yb?YdE?!hnfShlH&(Y7Qy=5a2uOnqIBq-i@t~1&GcMq|vc~94 z7M{dr&!OWzon|_`fag7cz$k+uo5bn&oKT>fb95dxB!@jcM_r1CE%kI} zpob5SA)Uo?;brMh74TNovaPYfTq1%c1=|HUlq?V(AeIJZ0DcjsO+O^)|7Vo5%|-@5;*#N&>A6wwWa(vXfYX9~lU(Z;U!^D44?hd8haBj`9ml$qP66Ut zyLi96T%N(b#_SN%a-_<2bM&$7U|qLBGQ+2TI+G(g_Y+DO7v{4{83i9FJ}{~~iyvHO zkq@<=uHNVz6@A=$jNZv z`5?n0hJKl6uZZ;{10lTEmruv(F2wr>b7R+VA>zH~Yq%^DOAt=o4TH5QV2JhA8OsQi z>=Us8-9ia$kxym7_vUS2zRznNb$FdEe1!`w;ZTasIni)D(~ljO zYKz4ay~rK|4c0KNgHfFs_XTpNnO7qCniq#2e6=;=zU`FN0;j{Sr+^QV$cH%!+y|El zZOgR7#V#X;0|HuctS-pfG&;|4Tutm`8Bbl}-5!Hemwx9%iQbX1)`;l=y>6L#8C5K` zcRZa!%zX0kRE4mXr^vxukXLl=y81pGh{@YB#k~dQKhCrU72oY9hn!g$^RAzHHcA((@DHW*doVZ-SK_MW<((G38D?S zsG_ksz1D=>>yc>r#3RI`N4H#il2{$`-lEnV9C2ah z<8qX{96Ed`UkBmIBf1aD!Zn3~_yN?)br>s#4n%p)0i(;g zQYJ4r-341yatJSroThP%z^`3}3rLqyhjHc3`D{7n2|lNT!)SbnK>9}SJ3Et?;ut-W z?jIVJPayE-DcjyTJRFP0<(dhd*ZiduT=&B5$F3yAM)a;!!p@mRMkvQw6hiw}62uba zoSwQjYA|oP7LCeh;;?_f`6oVFtoouk{Sp@ENe&MOUM4O!kUyyEO>N1=(xWo|*P~S_ zgpK{z@BGN1cs7%#+hfDf3{H{qEU`c4vuV=(=BSJM(B~8xmxG?t{)NlQa_bC-*kwS( z4Wm1GK#CJ!S*3ZrV#1wCpKL)Uof%%Uz!~fC2qyXZ!AXxRYEnUQ6h(>Gwj)$ zP93N!mNY+-_>i*2D$eLWatw;**@QqZtZnTBtZs-lBxeu{h z^Oft7F5{ej19WJoiKtk0yuaf+l?ca1nl5X9a#%herEr3u{5ufhxn_ zJFrsekag(4vM$!9&8RD_a83-L({Z)1%3QYx#YA$gq(Rin4#U(K&7@vYvslJx#nss7 zdtE1hnNm4vz#O8PNdyTvF1XAr@>pFh$8{@nuZOA=I`Rwa#tvsQY$ zD8CwVf!_})ZT0s`nNF$sZm?p#QafELyNr$En$MM1uj5>fa0eMJ;d(>+zZ@`!c&@sq z)xG22YD0oONZv0F)-_T9i*o!DT?m~yz2I<3qe57q9%s~UN@zL)daP<6DFMkiV%a=r z)HNU!!%|PTFNcQciszMVM&4Vc=f1XZa$b%Nw6;yoa{&E7&%FUK zpI;At_+>rvtcCm9g<3Ooid?Vkb#0Q@5OEJd{n8+4OI>Ib=qTnVykkB%n)V?jH&0R6 zw)Ym#+*t^`6GwaA#XWzgu&MrO;iPaZ7AG(V2De?Dde#}6F+{Wl$~RJ7T)cLLTOQWP zF+1MDr+V_K^jwfGgmc4b|6P6rC} zuG}1XF`4h2tu3OgxXj$Vio6DU87kfhg`PiYT+r@Lx0+|52E7k*8mpZgeCk9t7JJYw zv^4F=gEO4V2rb7VGuxb*uFKT6l^cz;_y^8Pnno8pc3BT2Tt-EHc?(Hf#Bvr1*156O zOi3H!_#n(jpU#yI*J3DDxxS3+hw4KwtdS@lmwYv)S)udDkJ!&b3Jw0wT$;KUn-M%Z8Z%|7eL8q;d${XM!1Nj&=eLa&p0EzGx$ zx}nPuK^tRIuk|SVfV9@hRrj}7!<={=dmKUDgCh0`ZO|aJ}*GyC(@fV!OF^yjIehxY$NQ)3~Wh*r3k8!!&?P6gf4^_X^gqh_6d zB_@|+uxSQpRP|1Q?yX+);B1|9B_Di4{$G))(4Cb#XgXu?!Z( zX)eT%zeY{NTj&J@!I&S1}XuXE@(>C964`|!z3{ky2lGbVHe`Qd%wpzo=D(yr$ zQiHfYnxv1e*D<}zpuG0xxy#{{#kb~&J?8}Gx}aBhT0f`mw1*k^uagf^Gtw=}w;aE$ z`i{be=>?R=ny2X8R_Swey`3LHG28@bL+|)HEJnK@G`HIPYJ;vJ7ah9$&SohE!(6yv z?{^oLVkJAy0PPdYb~Y(opdB~EyYzC=8$@}|qD*CTuyA4Hwp}k2x?}ZLhV|2j^3LL& zL5-ZQr0Tg8*5XW5FVwA|wcqEw8*moicEoUJ&u(@G=hP+488Yl}x+&dA!4Bo-PY+l+ zLfm+=EqYmZcIM>j4YA`B)92RPC=OM&milCiwQZk#v_lCxK!v@zNc59GtJftv3qF@~ zYKYqR_BTt=eZv0L8%pNyZ0PiwqTkIhM-F1PfSW-pSSDu~)+LkA6$)((b7NZXX@s{9 z>Kx{)t&(%PQV>5lxz5zFQxmNVj!ow{i}hcG{PHd4W?DNOj_b#%NGFtMGVD9Li>j|y z#+U9P)=LOo=LG-<0&Us=%AvPdD?4jvs4l>{2MxhC>#!ozHx5I{`U67P3%JYmqOco2JUOqwe{sTr^eP)KuEH zrFM#@SUxqyMzo41si=IzRC)HdqlKbrmP}2Pm*X&GpPP1HFjck(b@9G(^GMfdlh0Er zeR@0jH7;MQc~?1gP76w7FAigRal?KA`dXjZ^X-?_aO(IAWYV+7xJrX|GcRlGy*p8e z-eOS|&MQps8$S+3ZF}^gg=63K!54SxS$CP#TebW#qaNCYHlo<+g&J%_8LRXzTYEO~HEU<72%-Qu%5&6<)X^=?$pr^VXmPHSxY=K6UAn zrHhu_<;~yw`g*#&^V%+&Ur%ArId6=)7o&~lipEu&eZiJ|nz3J$2~kl| zGj>7;%gWqfc{zd=S~@nbCRQ_c+@WTSFRB@P*5tIMW{aCsD1x3iPXfRC-3DCO2d3OCe>W+V~6VK-i~L2#;N&tQq5HR8|G; zGit`hEe&giN;DM|R5RocS~WwZ%C;ek|0tm{psdPyl_)oE&6pJ|^GPLvMY+JD8enNG zuxJ`s)C?@`D=pK#H1-FEblVuxieN}SXCFnP~@W{lX6f(cr_V_jscf4%FJ#+_Olmw!$^Ra5xm6hqUPZ5W*p}Gfah{VqqwX z*pK%vu`*P`43Vlb%ao*t%$dO|lZl%P+hCW31Ik9$OrK+(xiAWmyb+CltBI8dOG3y5 z6$phm@>qSHDVwhcu)oZjak*A{q9Uk^*6o&d-4!;~k=_v2XLM6Tx{)DAK)Oc+?hcAB zYDS4yTQ#GVPLuT56rp>KP|OI$Tp`_QB6PnI+G2#ZxI((`baSah^ub&+wwBuS)y!bP zwAaiusKC*H=AZ|yP^~p%?Bg@We(DQa;VRSknwSBSnJPruMn791 z{6RYuDhXl`_lBu#{6mTviSl46M~odpO25J=IU`sBNyLR`B=P}dVk5_(U#Ba<*a^*4 z(((rdP6#|I@Ckv(1U@71*^t)r*!2uR(PP(FJDPSzvBUya8ens`tU}W;^9n6~^BU~dvICDU!k>vqX00ULom6cf6 z)jVG*COuav+Dfxh!J5FDiixIqVb8>ZLH~?dn9UWK*CE@+|C;fGGV#YAw*$3m#&}&& z`70~u&YcUZcote!qOcy#og1c+4EtuPnbu5OEM_BZh&G)wl^%Io2VtXwnp%6NHp4pA zOjQY6BQ4U5YK)t)$AzH{HLRBnBUCefz=i_DGwtw9i|gws>reHJqCsI|*sE~3yv#pi zY)m2!G8v|`QKd7nAzY12E41Qd{bh|CtqNW73PhIaNLhq+WSNdEgN`dGQLZIqdDar; zTB4jQ-}oAX!sV#t_!|8mG35whcwn6h27O$*|iefaip&A)SnHel{h>x$#3cWd4W0FbF zBhs!Jdj>-KkK!2nR!y!1vq8oRTngBFJyzg9QKcBS81~_sEl@*9t3j5>5UYkEm7@k+ z6k`&wOM`w>$Qi)^90ciN8GvKo2WqblvaaS|$gXL}Kt_McT)I(@`Mmcc{RL7l4G7R( zq0&MqOlAfh+b}9vsw*gNmF}lf-A|>gF2_%pqbZE)$sno`4+i`&<2mD`@eCZQ2$qC} zC2V>n2(S?Pbr?W`R$G;!UePyWVC#t(qND*bak*6L;Oj^a)Exba%K=qX~<{8 zIr~<~H_sO$hN(bQD1?PRZuyV_GF3?St;)*MYOF!?FgX-@)Q43f3E%7du)5&j^mkL zs7!#W27QEdX*)k zDxAka;wZ7QESMSwhT`Xi;q*hEG4pE1&(h5aRRlvdTfk-wF!kWV$d*IqUI}^%&0(+Q z+}Xlqn4DOtqO*^`Fy_FpujcBxFpu_3D08NT8CO{|o|Tn=o(RK1A1W-9>4=z!hcHPo z5YE7+CR~aEIX;Rche~SgxpU_sjW5Ij2cwUFffekI0G8hI=H)@(q^;7aNtnMGA}unvsA_n~%jw z);hHC0PG@MP&oOa8JCA@vIt+!QEh`qeXZuKv8pj`Lg*EY_!$Z5Fgr9eSOxQFR|?M# zL5=V*V0vWQ+H)a=rO}4j51}id!*UE4kv4L3=ayk=j9-qZn$^R*+lQ6XGuyA9^u>p zRc!~6_m-ORTd}FriAtSmXxG%Dzu+zy#adyr+1GRxrkE$%o`Ej#(DYUGB96rz8v`uN z_PMoTEcWp8#p2CWK&#PhSd?cX^AJ1-ZXsZ|m0eL$!BpXz@c@^T@jwW6EF7lYfqc*M=+n@9D-Vca|zx|uz=t^f`tTc`pUOfcTc|f_wT))IKS|9 zE{~_YAFF!nsiT+SG*lngXO;g6R-YAMPq{p)4F!E9$#g)7c1ZZuoEy|`9 zQOhJ$K!T*CNl0X5F_tNF0}2^}(LskCeefYbY(p>vn1BsffDKsipMwG20>cNv@IeO| z&_O_a(1E8U-><5>-_Guefe!%!B(pp3bywHxuCDH`uBz_WGkt{1+8UQ1e74mR;3rk5 z+wRo*M!qMjPPM1Q)TGNqmwy6!QQDbLXT+}ZJ;iq!DR_NNI8W{)T`n}Bt9&2kyT*5& z?{U5-Qu@SY2|kH-XK=pi47n|JOngAVK+)66PbGYn@22GJtGc`;EOf4R=Rg~b>A#UW zR>B(ut^kc9rYqa0Xfb;`n$!1i73TGkF8AoNq#S;w&>>xhP~`@hVye{*a;tB273%ku zd>_tDl$ok_gE|jx45g{bDv*^RE33cH1E%So z9b6bn+78b4P-@S9BoIeim(mpHMxDV~1so?1&eBopi>3!%+=GHr{b6ViR*Yw}4p)S1 z>n;T3%HaC?F3HS3m;<_^^l*(4WSiNTj;8P1+$Eg~UNlK&3R;q!X{*?Iv8MxS(q*{h^p`zdCQQlSJvE;H6;B7$q`S+)(@%Ojpm5J$l=rJI+EyX^pvv|mu15JatQ^PU(-0+hElG}W6nqf3JJ!BYlH3raZ6&zZSYpaW% z4>+=>(e4g)Lk&JKwAj#r6(-f5?r?}l7>#&XEwIsD(s$z5en7cYbci;n`_7hJ!CPcx zS@RLfO&iq`3_er!EW(&Fjc-vY)~#JSd0gGt;$x4i+gTi`W5T3f?uEUQCG~RLA37-% zd!C9coI|Nnx4}YOj$v;To)1X)oDiWU#dxNR_?bk!V-Y)M*mdE(jGQAvGICCVA$sCq zMe+tQH<8_je!MTVxuFuH8|t0`abLd$Q?PFhK`a(xS6cjF`VB&4YWExfgOq=fS<*72 zqlKTHQsiw1gfcF9JEjnxpnJ$TB9GJjO)wKZKqdx)Ar4uJ^P>(rH?EfJQ>pDDUVR3% z7&^Lo+I+z1I4w1PO849knl<+IBej~JUT-3m86(D}1WAiez-T2zxSP-`5D3Z5Tj> z2kPf46Te}sO3ezCRh>I>b$u>y)Ox+JR>sftU4gGORVf*eZQ)@7Mqqo@N-DLEK8nUm zp|b;4F%~nBUcoSJVvC_`kt}rkIqrh9K9M@q8-`GyNFC}87p(OOWqsOdAnUu$JuQ*# zs|6&;4z1Vfhtn`W$%N${w?P3n)(@N9D;<9l;XR&x)Fpab3aaBFa0IpP)`YtmZcUK7 zuQ6slJ*x<#6#?@jgo5rj5yuSu>5u$&6S1V2go^?<@lW9PJ&&4&u4`ART!Zr%zg)W! z@pL}b>eOJ=9-Ob2tr5H_P}9IdoMB3HmpTW=)yktwJwZ(}TW+z7Cq?qB%7I}HEaX6U zf5Jh3b+6AsywY#htH8Ao5W4j#Ib;;9mopHtJlAhwxC#hUOCDd(xPxI1)mO_?SE~#h zEK!(cYUCF1q=e2V>4)gdB66vKmf)sjTaOg9i_yS{}$fq-Yy- zC=Vm>OR5iq)R$}klKRK_S&jH>o@hbRG9P0mBvy-vZ)s0S+*WmoYpP^S<0GOIHu+3% z)hHbemJ_iR%OSH^E@-x5Ib;^=iYoE;*4(|)JeR2~(!N3jCb~?st?J_og9a_>ILM+x zeF9Nr^Qcww8mt**37rOI;;Ii~T+{JmnXkJc;K{Dz^6fBC|J*`Lw~yYoym58-c9|hm zW^=nO^MFmW#9WGs&QC zMBIE+BvUn58cY@#D~t;*3l1hM4UXsmLqrPADW%e)l}Cr#STML;eX`%~Y#mBa_Mv)W zzu!*lr9SN9V!zF{8w~^p4Et?o!!9E<-fsBD>fmh#H^zoaa%One$VItwH_M8pcgo^K z^=MU`s2;C3D`qt*!Fh`nYoKPlAuDXavy{ogCR?xSO?g-AYlGxnEhe6=Ou2UzB6#Xr zTpT6Zr1-GGst>cO zX!$(4P&Vr6JJla#rezf1Rkbvd9`6m6rQvwLwbVP>Cv}f;@SV)TVzMfY{~e_#>DZL+ zfUTuFglolAlX`2Cpil!mQR8^*=`w156^T1FY@O4vT)}_O4LfwKH2$5MdeotJfg}iZ zXNLiuQB%;k>B>HfG+jB*Duqc7z;|d}SssWo;npWhS3bGDD`!^)Yu4yxvmL-(JEa3y ztmyz2Wu23Bx9}a1J3x0^2T0B#3@0z7shQ81P0i8_+6+<$sPQ#OQ`;xt6|dRb@Xc%X zcHwn)(uk$0-Iqovwa%HGDT%o&y3a)#eC`beQr(gHTtEaWz!;?R*gV(l9|Yh%;9XXQ zUj4-Eh<5B%jMi6`s+;k=5K)waLPUWyL=+GKBZ9kED|?v$I1#@?guUWK{I0O3@jfY) z|7{I#j=R$E7Hb;bqCIPPcK|uS8~!)3=MDdxT$pfHTfK<$&uZEq2G3S?pn-3e@}|qUJC{g>-vY7HLArCo-a)y7QcR{^c{lQR-(1*@&16T=uZ8Q z)y(x8sM%JAfh{T5T7i`yVyP7w*mHjrd0@CIFPW4nN0o>=NH$<8duE5dS_@xp`my^O z8YX*u3zHpCU-5n{VMssDKxgv1Y*+DqTr`flk(%Io%R(7T6K6Yt9nLIpK<*dl2MGtgqt#a5Y_4BO6SvUuJa(A1)g^da`gQ^7ti9 zUO}D`Fj7_B7X!Ub-rRJ)7`HT%^ z3&M5)g3mShjKNL<{LVPCBHqfq*y;++;nS^`2SbG^bTF)!<*cli#Vni`J@ff$XTf}S z?ur!LjC<*7`L8<&9eA%@2KkR&38C&=SL`dOwSN}>S-r0>wqb4ikbNU}woCCn6o%ba z(Bgi;DG*xWRCUK+@oVb*z(e^ZK7I%Ng|EHX0#ADa=+><;pN?%!Ka&*}TA`OfE62i2 z^r4yPgS;5H*b4g-GAEg$ptVB3iRUb1E9^^9-aOQn1kW}f2OGknR`~d%FI?WVqt-`1 ze|@yhFU9lYL!-wo@xzjrzIN`}6}V4<6;+MiqMW{v-NRf%duZ>mNU-fGR(Pj*CC5!o_b_;i--F zjn`lL)r znT?IlZJarGoL^Xbi6f%Nq@@~yo_-@aotC?KCZ})&|Cy(#)rA+w8Fv5W=bjNo|9d~* z{keA)QTPjmN4wMd!!3Bc?EB~oUs<0_zQp0j;rSPz<>y?-_M6dq_CN0>kN#)EXL;FC zCoFtEJQj{~>cJPn7kP*LOPsEtqaII&r@}@!#cQ&E8BT|%!(XRjk8(KJv9J;z3=eVq z(<+BmdHeqU`RM?=XL-R)uY~%Pi6QU4Hj zEBp7)Wq1Dl_fW;-M1)8oFoq4yir1 zKBuGE)SDW7y##)wd{s`Q9C6A|VDRIH8|r5Bzn^}qxAFsh_TxNvg8X%=13w9GeRtC+ zRIgSYcEU#C^`Mg%RLkc0smBPb-TWZHOZMvJ15kOC@utsxl(e-hZ$*tDy?p)^Mh~x0 zrq7zy=g$)z{w^uML{ACo5vrYY{ln_z{Ckq;{gr9GhuUyMZMF5_qX32C_bmQ)uJ7cz lp4tAAwI5x*wY9cCm+SaHe*b9&7ejbk8_oXz^M8&5{{;_hNJRhu literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/DOTween.dll.meta b/Assets/Plugins/Demigiant/DOTween/DOTween.dll.meta new file mode 100644 index 0000000..482dbb8 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/DOTween.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: a811bde74b26b53498b4f6d872b09b6d +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor.meta b/Assets/Plugins/Demigiant/DOTween/Editor.meta new file mode 100644 index 0000000..532edfb --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: b27f58ae5d5c33a4bb2d1f4f34bd036d +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML new file mode 100644 index 0000000..26bd562 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML @@ -0,0 +1,124 @@ + + + + DOTweenEditor + + + + + Contains compatibility methods taken from DemiEditor (for when DOTween is without it) + + + + + Starts the update loop of tween in the editor. Has no effect during playMode. + + Eventual callback to call after every update + + + + Stops the update loop and clears the onPreviewUpdated callback. + + If TRUE also resets the tweened objects to their original state. + Note that this works by calling Rewind on all tweens, so it will work correctly + only if you have a single tween type per object and it wasn't killed + If TRUE also kills any cached tween + + + + Readies the tween for editor preview by setting its UpdateType to Manual plus eventual extra settings. + + The tween to ready + If TRUE (recommended) removes all callbacks (OnComplete/Rewind/etc) + If TRUE prevents the tween from being auto-killed at completion + If TRUE starts playing the tween immediately + + + Full major version + first minor version (ex: 2018.1f) + + + Major version + + + First minor version (ex: in 2018.1 it would be 1) + + + + Checks that the given editor texture use the correct import settings, + and applies them if they're incorrect. + + + + + Returns TRUE if setup is required + + + + + Returns TRUE if the file/directory at the given path exists. + + Path, relative to Unity's project folder + + + + + Converts the given project-relative path to a full path, + with backward (\) slashes). + + + + + Converts the given full path to a path usable with AssetDatabase methods + (relative to Unity's project folder, and with the correct Unity forward (/) slashes). + + + + + Connects to a asset. + If the asset already exists at the given path, loads it and returns it. + Otherwise, either returns NULL or automatically creates it before loading and returning it + (depending on the given parameters). + + Asset type + File path (relative to Unity's project folder) + If TRUE and the requested asset doesn't exist, forces its creation + + + + Full path for the given loaded assembly, assembly file included + + + + + Adds the given global define if it's not already present + + + + + Removes the given global define if it's present + + + + + Returns TRUE if the given global define is present in all the + or only in the given , depending on passed parameters. + + + to use. Leave NULL to check in all of them. + + + + Not used as menu item anymore, but as a utiity function + + + + Full major version + first minor version (ex: 2018.1f) + + + Major version + + + First minor version (ex: in 2018.1 it would be 1) + + + diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML.meta b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML.meta new file mode 100644 index 0000000..7cec113 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.XML.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 2e2c6224d345d9249acfa6e8ef40bb2d +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll new file mode 100644 index 0000000000000000000000000000000000000000..a5e204aab110481f71dd8074324a48a666bc3470 GIT binary patch literal 69632 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll.meta b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll.meta new file mode 100644 index 0000000..53590f3 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 45d5034162d6cf04dbe46da84fc7d074 +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 0 + settings: {} + Editor: + enabled: 1 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs.meta b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs.meta new file mode 100644 index 0000000..a81ba5f --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 0034ebae0c2a9344e897db1160d71b6d +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..d06fc7c3e49fb705b19f50a23884e11e08fd6e89 GIT binary patch literal 1565 zcmV+&2IBdNP)pK&q+iZU-R{R_dCD)yXSsA=iKiWUaHS%xglyYZad)#h+<5;*}0 zNm4;#XNMU$Zj;|vsJ23aE-5O{$8uo1iN`?c(v%ev86gvrQJJtDUgxox^bsB@>w%Sv@Z{F3?7c1><;yj*g<&fQ;rHj}CCd5!B9uJ9iB}?8sX9 z0l}mbA`+6NSzvKr7orW|#Qq*|(_H8{K}SN-b6PMMr68BfK|728UnV4rbuENZG2Z=Z5Wu9k@Z ztFhSr_^u&Go2vR`!G?lmnDf^U%@^vc&8BfCWA&5;S^i0KcuQ?}kJ(Z3^ukf69xF;y zhTjIduJg}*jhXlo$g+|CIjkSftK3odtF^Ij{rKV$Cnn9$)I>`OWpR2BZvMLfc!?KG z`Ygj57^xT!Rkoeb;;a>--p1*pKcW45EApC=r9;lR-6-kL1bPPs&3JrJ`3>IVgWG}u zrp-R@PdWz2X;89OBJXFclQSuKH%hu+=km#Rb8S^yF>)=)yvW|npJ`O9bTXp9hsHlb znp{n43g)Eywa^bS0=L=}#fV_6`pc{T=00UOIql`_gv<&0h%GG1sFbh_*L zqP^;2G6HL$uEjx);7q^Pe;Vac1Sb6of8vi>KZaIU-M!xHLy7h)J?TTTtlXuy)v(S-r9V9I7cw) zBJ@dWbWCbJy!KBwxl~8X#1q??E z(FRaBcRnf^OG3xEWE{XiDJhYPVBV54Q*B2`fK%)r4bJp zv@(2PX=l*%^bG!@&}Ku`gi%4ta5WNM0#2BfuE7?N_gS0ljFV#0yW1U1N=~9Q$*7V9 zs*5|&bg|QQt;WLQDrER5jfAhm2W6wJag5au!96_|(2Th-DB`E<_rUdkM#GW4COG!3 z`K~-?KL;C^l|r|5RUE^pEPvtTLR^K!B04D#hpLNGOCz;*Z|Rx&7b{!rLVU{NI)eH5 zyg0@a6A$elUi>gA6@P$cWD53gSzVnTr*}j6sd4;47Sd19E6U{>QXP%UxLJ2^hjTS@ z6ZIq2+r)$@>IAiS(jN5U4r-m;p98e&wn5+}NTri*S7~M1@c0mh@Mz$FrSMzj$u5?< P00000NkvXXu0mjftl$Bl literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png.meta b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png.meta new file mode 100644 index 0000000..61c3cce --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8da095e39e9b4df488dfd436f81116d6 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 128 + textureSettings: + filterMode: 1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..7cd74c1a26df1a45564c7a0e21c62d0ef3af2fd1 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^oFL4>1|%O$WD@{!3Opi<85sBugD~Uq{1quc!H=FU zjv*3LlT#WP(iF^Cl2R3(u|Mi}s1fft&-^joZ3WZ(2Ug1Y!S$8-a*li}_21XqSnvJ# z@Y+`2=i8W`Zfg*cV81TuZmqUr`JI~8M}9x(m1v%HMLo`ySuokJ?%Vq7{C4$+ST-HH z5`RuO<@s#=8XoVy+lF)YEaxg?4vAr1(jlM1>Tx0PF<0}pFUf679a{7Ee==}5`qQz? zuIUa#(3byge21?t-^6oqTDwHc&iz0s`zDdQwtGKbESsPtIM1KwqFB4+nW=frYn!|7 zvs(U9y->(A=TFZ3t)>6Hv^;B{u+A(fd3smW;eIaTDS0KOITHVv7#gf%Y$mkMJ`MCd NgQu&X%Q~loCICTRfS>>X literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png.meta b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png.meta new file mode 100644 index 0000000..c343a61 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 61521df2e071645488ba3d05e49289ae +timeCreated: 1602317874 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png new file mode 100644 index 0000000000000000000000000000000000000000..e29d02fe18b777b1d316feb647b339803c5126de GIT binary patch literal 4409 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png.meta b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png.meta new file mode 100644 index 0000000..7ca1911 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 7051dba417b3d53409f2918f1ea4938d +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 256 + textureSettings: + filterMode: 1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..e48db5ef7a2b83eff50d6e3b5fe9ba3bcd4a5015 GIT binary patch literal 4429 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 TqmFO~00000NkvXXu0mjf{EM6C literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png.meta b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png.meta new file mode 100644 index 0000000..f12a1a7 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 519694efe2bb2914788b151fbd8c01f4 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d710d719075150879b1ee76680af87791c4d3b3 GIT binary patch literal 22787 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 QE#Li`lK-oJv9mh=KQ4fgsQ>@~ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg.meta b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg.meta new file mode 100644 index 0000000..26e4255 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 78a59ca99f8987941adb61f9e14a06a7 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 512 + textureSettings: + filterMode: 1 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules.meta b/Assets/Plugins/Demigiant/DOTween/Modules.meta new file mode 100644 index 0000000..24cd2ac --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 143604b8bad857d47a6f7cc7a533e2dc +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef b/Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef new file mode 100644 index 0000000..42ef5ab --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef @@ -0,0 +1,3 @@ +{ + "name": "DOTween.Modules" +} diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef.meta new file mode 100644 index 0000000..4b3b6fc --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTween.Modules.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bc83d82ae5798884eaeb54c583c65909 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs new file mode 100644 index 0000000..c195b6c --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs @@ -0,0 +1,202 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +#if true // MODULE_MARKER +using System; +using DG.Tweening.Core; +using DG.Tweening.Plugins.Options; +using UnityEngine; +#if UNITY_5 || UNITY_2017_1_OR_NEWER +using UnityEngine.Audio; // Required for AudioMixer +#endif + +#pragma warning disable 1591 +namespace DG.Tweening +{ + public static class DOTweenModuleAudio + { + #region Shortcuts + + #region Audio + + ///

Tweens an AudioSource's volume to the given value. + /// Also stores the AudioSource as the tween's target so it can be used for filtered operations + /// The end value to reach (0 to 1)The duration of the tween + public static TweenerCore DOFade(this AudioSource target, float endValue, float duration) + { + if (endValue < 0) endValue = 0; + else if (endValue > 1) endValue = 1; + TweenerCore t = DOTween.To(() => target.volume, x => target.volume = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens an AudioSource's pitch to the given value. + /// Also stores the AudioSource as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOPitch(this AudioSource target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.pitch, x => target.pitch = x, endValue, duration); + t.SetTarget(target); + return t; + } + + #endregion + +#if UNITY_5 || UNITY_2017_1_OR_NEWER + #region AudioMixer (Unity 5 or Newer) + + /// Tweens an AudioMixer's exposed float to the given value. + /// Also stores the AudioMixer as the tween's target so it can be used for filtered operations. + /// Note that you need to manually expose a float in an AudioMixerGroup in order to be able to tween it from an AudioMixer. + /// Name given to the exposed float to set + /// The end value to reachThe duration of the tween + public static TweenerCore DOSetFloat(this AudioMixer target, string floatName, float endValue, float duration) + { + TweenerCore t = DOTween.To(()=> { + float currVal; + target.GetFloat(floatName, out currVal); + return currVal; + }, x=> target.SetFloat(floatName, x), endValue, duration); + t.SetTarget(target); + return t; + } + + #region Operation Shortcuts + + /// + /// Completes all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens completed + /// (meaning the tweens that don't have infinite loops and were not already complete) + /// + /// For Sequences only: if TRUE also internal Sequence callbacks will be fired, + /// otherwise they will be ignored + public static int DOComplete(this AudioMixer target, bool withCallbacks = false) + { + return DOTween.Complete(target, withCallbacks); + } + + /// + /// Kills all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens killed. + /// + /// If TRUE completes the tween before killing it + public static int DOKill(this AudioMixer target, bool complete = false) + { + return DOTween.Kill(target, complete); + } + + /// + /// Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens flipped. + /// + public static int DOFlip(this AudioMixer target) + { + return DOTween.Flip(target); + } + + /// + /// Sends to the given position all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens involved. + /// + /// Time position to reach + /// (if higher than the whole tween duration the tween will simply reach its end) + /// If TRUE will play the tween after reaching the given position, otherwise it will pause it + public static int DOGoto(this AudioMixer target, float to, bool andPlay = false) + { + return DOTween.Goto(target, to, andPlay); + } + + /// + /// Pauses all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens paused. + /// + public static int DOPause(this AudioMixer target) + { + return DOTween.Pause(target); + } + + /// + /// Plays all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens played. + /// + public static int DOPlay(this AudioMixer target) + { + return DOTween.Play(target); + } + + /// + /// Plays backwards all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens played. + /// + public static int DOPlayBackwards(this AudioMixer target) + { + return DOTween.PlayBackwards(target); + } + + /// + /// Plays forward all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens played. + /// + public static int DOPlayForward(this AudioMixer target) + { + return DOTween.PlayForward(target); + } + + /// + /// Restarts all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens restarted. + /// + public static int DORestart(this AudioMixer target) + { + return DOTween.Restart(target); + } + + /// + /// Rewinds all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens rewinded. + /// + public static int DORewind(this AudioMixer target) + { + return DOTween.Rewind(target); + } + + /// + /// Smoothly rewinds all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens rewinded. + /// + public static int DOSmoothRewind(this AudioMixer target) + { + return DOTween.SmoothRewind(target); + } + + /// + /// Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference + /// (meaning tweens that were started from this target, or that had this target added as an Id) + /// and returns the total number of tweens involved. + /// + public static int DOTogglePause(this AudioMixer target) + { + return DOTween.TogglePause(target); + } + + #endregion + + #endregion +#endif + + #endregion + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs.meta new file mode 100644 index 0000000..50aa010 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleAudio.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b766d08851589514b97afb23c6f30a70 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs new file mode 100644 index 0000000..2ab3775 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs @@ -0,0 +1,146 @@ +using UnityEngine; + +#if false || EPO_DOTWEEN // MODULE_MARKER + +using EPOOutline; +using DG.Tweening.Plugins.Options; +using DG.Tweening; +using DG.Tweening.Core; + +namespace DG.Tweening +{ + public static class DOTweenModuleEPOOutline + { + public static int DOKill(this SerializedPass target, bool complete) + { + return DOTween.Kill(target, complete); + } + + public static TweenerCore DOFloat(this SerializedPass target, string propertyName, float endValue, float duration) + { + var tweener = DOTween.To(() => target.GetFloat(propertyName), x => target.SetFloat(propertyName, x), endValue, duration); + tweener.SetOptions(true).SetTarget(target); + return tweener; + } + + public static TweenerCore DOFade(this SerializedPass target, string propertyName, float endValue, float duration) + { + var tweener = DOTween.ToAlpha(() => target.GetColor(propertyName), x => target.SetColor(propertyName, x), endValue, duration); + tweener.SetOptions(true).SetTarget(target); + return tweener; + } + + public static TweenerCore DOColor(this SerializedPass target, string propertyName, Color endValue, float duration) + { + var tweener = DOTween.To(() => target.GetColor(propertyName), x => target.SetColor(propertyName, x), endValue, duration); + tweener.SetOptions(false).SetTarget(target); + return tweener; + } + + public static TweenerCore DOVector(this SerializedPass target, string propertyName, Vector4 endValue, float duration) + { + var tweener = DOTween.To(() => target.GetVector(propertyName), x => target.SetVector(propertyName, x), endValue, duration); + tweener.SetOptions(false).SetTarget(target); + return tweener; + } + + public static TweenerCore DOFloat(this SerializedPass target, int propertyId, float endValue, float duration) + { + var tweener = DOTween.To(() => target.GetFloat(propertyId), x => target.SetFloat(propertyId, x), endValue, duration); + tweener.SetOptions(true).SetTarget(target); + return tweener; + } + + public static TweenerCore DOFade(this SerializedPass target, int propertyId, float endValue, float duration) + { + var tweener = DOTween.ToAlpha(() => target.GetColor(propertyId), x => target.SetColor(propertyId, x), endValue, duration); + tweener.SetOptions(true).SetTarget(target); + return tweener; + } + + public static TweenerCore DOColor(this SerializedPass target, int propertyId, Color endValue, float duration) + { + var tweener = DOTween.To(() => target.GetColor(propertyId), x => target.SetColor(propertyId, x), endValue, duration); + tweener.SetOptions(false).SetTarget(target); + return tweener; + } + + public static TweenerCore DOVector(this SerializedPass target, int propertyId, Vector4 endValue, float duration) + { + var tweener = DOTween.To(() => target.GetVector(propertyId), x => target.SetVector(propertyId, x), endValue, duration); + tweener.SetOptions(false).SetTarget(target); + return tweener; + } + + public static int DOKill(this Outlinable.OutlineProperties target, bool complete = false) + { + return DOTween.Kill(target, complete); + } + + public static int DOKill(this Outliner target, bool complete = false) + { + return DOTween.Kill(target, complete); + } + + /// + /// Controls the alpha (transparency) of the outline + /// + public static TweenerCore DOFade(this Outlinable.OutlineProperties target, float endValue, float duration) + { + var tweener = DOTween.ToAlpha(() => target.Color, x => target.Color = x, endValue, duration); + tweener.SetOptions(true).SetTarget(target); + return tweener; + } + + /// + /// Controls the color of the outline + /// + public static TweenerCore DOColor(this Outlinable.OutlineProperties target, Color endValue, float duration) + { + var tweener = DOTween.To(() => target.Color, x => target.Color = x, endValue, duration); + tweener.SetOptions(false).SetTarget(target); + return tweener; + } + + /// + /// Controls the amount of blur applied to the outline + /// + public static TweenerCore DOBlurShift(this Outlinable.OutlineProperties target, float endValue, float duration, bool snapping = false) + { + var tweener = DOTween.To(() => target.BlurShift, x => target.BlurShift = x, endValue, duration); + tweener.SetOptions(snapping).SetTarget(target); + return tweener; + } + + /// + /// Controls the amount of blur applied to the outline + /// + public static TweenerCore DOBlurShift(this Outliner target, float endValue, float duration, bool snapping = false) + { + var tweener = DOTween.To(() => target.BlurShift, x => target.BlurShift = x, endValue, duration); + tweener.SetOptions(snapping).SetTarget(target); + return tweener; + } + + /// + /// Controls the amount of dilation applied to the outline + /// + public static TweenerCore DODilateShift(this Outlinable.OutlineProperties target, float endValue, float duration, bool snapping = false) + { + var tweener = DOTween.To(() => target.DilateShift, x => target.DilateShift = x, endValue, duration); + tweener.SetOptions(snapping).SetTarget(target); + return tweener; + } + + /// + /// Controls the amount of dilation applied to the outline + /// + public static TweenerCore DODilateShift(this Outliner target, float endValue, float duration, bool snapping = false) + { + var tweener = DOTween.To(() => target.DilateShift, x => target.DilateShift = x, endValue, duration); + tweener.SetOptions(snapping).SetTarget(target); + return tweener; + } + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs.meta new file mode 100644 index 0000000..4b8991f --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleEPOOutline.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: e944529dcaee98f4e9498d80e541d93e +timeCreated: 1602593330 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs new file mode 100644 index 0000000..08b0700 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs @@ -0,0 +1,216 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +#if true // MODULE_MARKER +using System; +using DG.Tweening.Core; +using DG.Tweening.Core.Enums; +using DG.Tweening.Plugins; +using DG.Tweening.Plugins.Core.PathCore; +using DG.Tweening.Plugins.Options; +using UnityEngine; + +#pragma warning disable 1591 +namespace DG.Tweening +{ + public static class DOTweenModulePhysics + { + #region Shortcuts + + #region Rigidbody + + /// Tweens a Rigidbody's position to the given value. + /// Also stores the rigidbody as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMove(this Rigidbody target, Vector3 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody's X position to the given value. + /// Also stores the rigidbody as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMoveX(this Rigidbody target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue, 0, 0), duration); + t.SetOptions(AxisConstraint.X, snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody's Y position to the given value. + /// Also stores the rigidbody as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMoveY(this Rigidbody target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, endValue, 0), duration); + t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody's Z position to the given value. + /// Also stores the rigidbody as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMoveZ(this Rigidbody target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue), duration); + t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody's rotation to the given value. + /// Also stores the rigidbody as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// Rotation mode + public static TweenerCore DORotate(this Rigidbody target, Vector3 endValue, float duration, RotateMode mode = RotateMode.Fast) + { + TweenerCore t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration); + t.SetTarget(target); + t.plugOptions.rotateMode = mode; + return t; + } + + /// Tweens a Rigidbody's rotation so that it will look towards the given position. + /// Also stores the rigidbody as the tween's target so it can be used for filtered operations + /// The position to look atThe duration of the tween + /// Eventual axis constraint for the rotation + /// The vector that defines in which direction up is (default: Vector3.up) + public static TweenerCore DOLookAt(this Rigidbody target, Vector3 towards, float duration, AxisConstraint axisConstraint = AxisConstraint.None, Vector3? up = null) + { + TweenerCore t = DOTween.To(() => target.rotation, target.MoveRotation, towards, duration) + .SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetLookAt); + t.plugOptions.axisConstraint = axisConstraint; + t.plugOptions.up = (up == null) ? Vector3.up : (Vector3)up; + return t; + } + + #region Special + + /// Tweens a Rigidbody's position to the given value, while also applying a jump effect along the Y axis. + /// Returns a Sequence instead of a Tweener. + /// Also stores the Rigidbody as the tween's target so it can be used for filtered operations + /// The end value to reach + /// Power of the jump (the max height of the jump is represented by this plus the final Y offset) + /// Total number of jumps + /// The duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static Sequence DOJump(this Rigidbody target, Vector3 endValue, float jumpPower, int numJumps, float duration, bool snapping = false) + { + if (numJumps < 1) numJumps = 1; + float startPosY = 0; + float offsetY = -1; + bool offsetYSet = false; + Sequence s = DOTween.Sequence(); + Tween yTween = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, jumpPower, 0), duration / (numJumps * 2)) + .SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative() + .SetLoops(numJumps * 2, LoopType.Yoyo) + .OnStart(() => startPosY = target.position.y); + s.Append(DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue.x, 0, 0), duration) + .SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear) + ).Join(DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue.z), duration) + .SetOptions(AxisConstraint.Z, snapping).SetEase(Ease.Linear) + ).Join(yTween) + .SetTarget(target).SetEase(DOTween.defaultEaseType); + yTween.OnUpdate(() => { + if (!offsetYSet) { + offsetYSet = true; + offsetY = s.isRelative ? endValue.y : endValue.y - startPosY; + } + Vector3 pos = target.position; + pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad); + target.MovePosition(pos); + }); + return s; + } + + /// Tweens a Rigidbody's position through the given path waypoints, using the chosen path algorithm. + /// Also stores the Rigidbody as the tween's target so it can be used for filtered operations. + /// NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened. + /// BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug). + /// If you plan to publish there you should use a regular transform.DOPath. + /// The waypoints to go through + /// The duration of the tween + /// The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + /// The path mode: 3D, side-scroller 2D, top-down 2D + /// The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive. + /// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + /// The color of the path (shown when gizmos are active in the Play panel and the tween is running) + public static TweenerCore DOPath( + this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear, + PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null + ) + { + if (resolution < 1) resolution = 1; + TweenerCore t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, new Path(pathType, path, resolution, gizmoColor), duration) + .SetTarget(target).SetUpdate(UpdateType.Fixed); + + t.plugOptions.isRigidbody = true; + t.plugOptions.mode = pathMode; + return t; + } + /// Tweens a Rigidbody's localPosition through the given path waypoints, using the chosen path algorithm. + /// Also stores the Rigidbody as the tween's target so it can be used for filtered operations + /// NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened. + /// BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug). + /// If you plan to publish there you should use a regular transform.DOLocalPath. + /// The waypoint to go through + /// The duration of the tween + /// The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + /// The path mode: 3D, side-scroller 2D, top-down 2D + /// The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive. + /// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + /// The color of the path (shown when gizmos are active in the Play panel and the tween is running) + public static TweenerCore DOLocalPath( + this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear, + PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null + ) + { + if (resolution < 1) resolution = 1; + Transform trans = target.transform; + TweenerCore t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path, resolution, gizmoColor), duration) + .SetTarget(target).SetUpdate(UpdateType.Fixed); + + t.plugOptions.isRigidbody = true; + t.plugOptions.mode = pathMode; + t.plugOptions.useLocalPosition = true; + return t; + } + // Used by path editor when creating the actual tween, so it can pass a pre-compiled path + internal static TweenerCore DOPath( + this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D + ) + { + TweenerCore t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, path, duration) + .SetTarget(target); + + t.plugOptions.isRigidbody = true; + t.plugOptions.mode = pathMode; + return t; + } + internal static TweenerCore DOLocalPath( + this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D + ) + { + Transform trans = target.transform; + TweenerCore t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration) + .SetTarget(target); + + t.plugOptions.isRigidbody = true; + t.plugOptions.mode = pathMode; + t.plugOptions.useLocalPosition = true; + return t; + } + + #endregion + + #endregion + + #endregion + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs.meta new file mode 100644 index 0000000..0ce0d75 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dae9aa560b4242648a3affa2bfabc365 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs new file mode 100644 index 0000000..d01f728 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs @@ -0,0 +1,193 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +#if true && (UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER) // MODULE_MARKER +using System; +using DG.Tweening.Core; +using DG.Tweening.Plugins; +using DG.Tweening.Plugins.Core.PathCore; +using DG.Tweening.Plugins.Options; +using UnityEngine; + +#pragma warning disable 1591 +namespace DG.Tweening +{ + public static class DOTweenModulePhysics2D + { + #region Shortcuts + + #region Rigidbody2D Shortcuts + + /// Tweens a Rigidbody2D's position to the given value. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMove(this Rigidbody2D target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody2D's X position to the given value. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMoveX(this Rigidbody2D target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, new Vector2(endValue, 0), duration); + t.SetOptions(AxisConstraint.X, snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody2D's Y position to the given value. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMoveY(this Rigidbody2D target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.position, target.MovePosition, new Vector2(0, endValue), duration); + t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target); + return t; + } + + /// Tweens a Rigidbody2D's rotation to the given value. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DORotate(this Rigidbody2D target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration); + t.SetTarget(target); + return t; + } + + #region Special + + /// Tweens a Rigidbody2D's position to the given value, while also applying a jump effect along the Y axis. + /// Returns a Sequence instead of a Tweener. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations. + /// IMPORTANT: a rigidbody2D can't be animated in a jump arc using MovePosition, so the tween will directly set the position + /// The end value to reach + /// Power of the jump (the max height of the jump is represented by this plus the final Y offset) + /// Total number of jumps + /// The duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static Sequence DOJump(this Rigidbody2D target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false) + { + if (numJumps < 1) numJumps = 1; + float startPosY = 0; + float offsetY = -1; + bool offsetYSet = false; + Sequence s = DOTween.Sequence(); + Tween yTween = DOTween.To(() => target.position, x => target.position = x, new Vector2(0, jumpPower), duration / (numJumps * 2)) + .SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative() + .SetLoops(numJumps * 2, LoopType.Yoyo) + .OnStart(() => startPosY = target.position.y); + s.Append(DOTween.To(() => target.position, x => target.position = x, new Vector2(endValue.x, 0), duration) + .SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear) + ).Join(yTween) + .SetTarget(target).SetEase(DOTween.defaultEaseType); + yTween.OnUpdate(() => { + if (!offsetYSet) { + offsetYSet = true; + offsetY = s.isRelative ? endValue.y : endValue.y - startPosY; + } + Vector3 pos = target.position; + pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad); + target.MovePosition(pos); + }); + return s; + } + + /// Tweens a Rigidbody2D's position through the given path waypoints, using the chosen path algorithm. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations. + /// NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened. + /// BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug). + /// If you plan to publish there you should use a regular transform.DOPath. + /// The waypoints to go through + /// The duration of the tween + /// The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + /// The path mode: 3D, side-scroller 2D, top-down 2D + /// The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive. + /// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + /// The color of the path (shown when gizmos are active in the Play panel and the tween is running) + public static TweenerCore DOPath( + this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear, + PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null + ) + { + if (resolution < 1) resolution = 1; + int len = path.Length; + Vector3[] path3D = new Vector3[len]; + for (int i = 0; i < len; ++i) path3D[i] = path[i]; + TweenerCore t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), new Path(pathType, path3D, resolution, gizmoColor), duration) + .SetTarget(target).SetUpdate(UpdateType.Fixed); + + t.plugOptions.isRigidbody2D = true; + t.plugOptions.mode = pathMode; + return t; + } + /// Tweens a Rigidbody2D's localPosition through the given path waypoints, using the chosen path algorithm. + /// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations + /// NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened. + /// BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug). + /// If you plan to publish there you should use a regular transform.DOLocalPath. + /// The waypoint to go through + /// The duration of the tween + /// The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + /// The path mode: 3D, side-scroller 2D, top-down 2D + /// The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive. + /// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + /// The color of the path (shown when gizmos are active in the Play panel and the tween is running) + public static TweenerCore DOLocalPath( + this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear, + PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null + ) + { + if (resolution < 1) resolution = 1; + int len = path.Length; + Vector3[] path3D = new Vector3[len]; + for (int i = 0; i < len; ++i) path3D[i] = path[i]; + Transform trans = target.transform; + TweenerCore t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path3D, resolution, gizmoColor), duration) + .SetTarget(target).SetUpdate(UpdateType.Fixed); + + t.plugOptions.isRigidbody2D = true; + t.plugOptions.mode = pathMode; + t.plugOptions.useLocalPosition = true; + return t; + } + // Used by path editor when creating the actual tween, so it can pass a pre-compiled path + internal static TweenerCore DOPath( + this Rigidbody2D target, Path path, float duration, PathMode pathMode = PathMode.Full3D + ) + { + TweenerCore t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), path, duration) + .SetTarget(target); + + t.plugOptions.isRigidbody2D = true; + t.plugOptions.mode = pathMode; + return t; + } + internal static TweenerCore DOLocalPath( + this Rigidbody2D target, Path path, float duration, PathMode pathMode = PathMode.Full3D + ) + { + Transform trans = target.transform; + TweenerCore t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration) + .SetTarget(target); + + t.plugOptions.isRigidbody2D = true; + t.plugOptions.mode = pathMode; + t.plugOptions.useLocalPosition = true; + return t; + } + + #endregion + + #endregion + + #endregion + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs.meta new file mode 100644 index 0000000..ca9ed29 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModulePhysics2D.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 230fe34542e175245ba74b4659dae700 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs new file mode 100644 index 0000000..549fff3 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs @@ -0,0 +1,93 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +#if true && (UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER) // MODULE_MARKER +using System; +using UnityEngine; +using DG.Tweening.Core; +using DG.Tweening.Plugins.Options; + +#pragma warning disable 1591 +namespace DG.Tweening +{ + public static class DOTweenModuleSprite + { + #region Shortcuts + + #region SpriteRenderer + + /// Tweens a SpriteRenderer's color to the given value. + /// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this SpriteRenderer target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a Material's alpha color to the given value. + /// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this SpriteRenderer target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a SpriteRenderer's color using the given gradient + /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener). + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The gradient to useThe duration of the tween + public static Sequence DOGradientColor(this SpriteRenderer target, Gradient gradient, float duration) + { + Sequence s = DOTween.Sequence(); + GradientColorKey[] colors = gradient.colorKeys; + int len = colors.Length; + for (int i = 0; i < len; ++i) { + GradientColorKey c = colors[i]; + if (i == 0 && c.time <= 0) { + target.color = c.color; + continue; + } + float colorDuration = i == len - 1 + ? duration - s.Duration(false) // Verifies that total duration is correct + : duration * (i == 0 ? c.time : c.time - colors[i - 1].time); + s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear)); + } + s.SetTarget(target); + return s; + } + + #endregion + + #region Blendables + + #region SpriteRenderer + + /// Tweens a SpriteRenderer's color to the given value, + /// in a way that allows other DOBlendableColor tweens to work together on the same target, + /// instead than fight each other as multiple DOColor would do. + /// Also stores the SpriteRenderer as the tween's target so it can be used for filtered operations + /// The value to tween toThe duration of the tween + public static Tweener DOBlendableColor(this SpriteRenderer target, Color endValue, float duration) + { + endValue = endValue - target.color; + Color to = new Color(0, 0, 0, 0); + return DOTween.To(() => to, x => { + Color diff = x - to; + to = x; + target.color += diff; + }, endValue, duration) + .Blendable().SetTarget(target); + } + + #endregion + + #endregion + + #endregion + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs.meta new file mode 100644 index 0000000..a0c67c4 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleSprite.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 188918ab119d93148aa0de59ccf5286b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs new file mode 100644 index 0000000..b3a6fd1 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs @@ -0,0 +1,662 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +#if true && (UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER) // MODULE_MARKER + +using System; +using System.Globalization; +using UnityEngine; +using UnityEngine.UI; +using DG.Tweening.Core; +using DG.Tweening.Core.Enums; +using DG.Tweening.Plugins; +using DG.Tweening.Plugins.Options; +using Outline = UnityEngine.UI.Outline; +using Text = UnityEngine.UI.Text; + +#pragma warning disable 1591 +namespace DG.Tweening +{ + public static class DOTweenModuleUI + { + #region Shortcuts + + #region CanvasGroup + + /// Tweens a CanvasGroup's alpha color to the given value. + /// Also stores the canvasGroup as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this CanvasGroup target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.alpha, x => target.alpha = x, endValue, duration); + t.SetTarget(target); + return t; + } + + #endregion + + #region Graphic + + /// Tweens an Graphic's color to the given value. + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this Graphic target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens an Graphic's alpha color to the given value. + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this Graphic target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + #endregion + + #region Image + + /// Tweens an Image's color to the given value. + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this Image target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens an Image's alpha color to the given value. + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this Image target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens an Image's fillAmount to the given value. + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The end value to reach (0 to 1)The duration of the tween + public static TweenerCore DOFillAmount(this Image target, float endValue, float duration) + { + if (endValue > 1) endValue = 1; + else if (endValue < 0) endValue = 0; + TweenerCore t = DOTween.To(() => target.fillAmount, x => target.fillAmount = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens an Image's colors using the given gradient + /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener). + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The gradient to useThe duration of the tween + public static Sequence DOGradientColor(this Image target, Gradient gradient, float duration) + { + Sequence s = DOTween.Sequence(); + GradientColorKey[] colors = gradient.colorKeys; + int len = colors.Length; + for (int i = 0; i < len; ++i) { + GradientColorKey c = colors[i]; + if (i == 0 && c.time <= 0) { + target.color = c.color; + continue; + } + float colorDuration = i == len - 1 + ? duration - s.Duration(false) // Verifies that total duration is correct + : duration * (i == 0 ? c.time : c.time - colors[i - 1].time); + s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear)); + } + s.SetTarget(target); + return s; + } + + #endregion + + #region LayoutElement + + /// Tweens an LayoutElement's flexibleWidth/Height to the given value. + /// Also stores the LayoutElement as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOFlexibleSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => new Vector2(target.flexibleWidth, target.flexibleHeight), x => { + target.flexibleWidth = x.x; + target.flexibleHeight = x.y; + }, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Tweens an LayoutElement's minWidth/Height to the given value. + /// Also stores the LayoutElement as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOMinSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => new Vector2(target.minWidth, target.minHeight), x => { + target.minWidth = x.x; + target.minHeight = x.y; + }, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Tweens an LayoutElement's preferredWidth/Height to the given value. + /// Also stores the LayoutElement as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOPreferredSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => new Vector2(target.preferredWidth, target.preferredHeight), x => { + target.preferredWidth = x.x; + target.preferredHeight = x.y; + }, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + #endregion + + #region Outline + + /// Tweens a Outline's effectColor to the given value. + /// Also stores the Outline as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this Outline target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.effectColor, x => target.effectColor = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a Outline's effectColor alpha to the given value. + /// Also stores the Outline as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this Outline target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.effectColor, x => target.effectColor = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a Outline's effectDistance to the given value. + /// Also stores the Outline as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScale(this Outline target, Vector2 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.effectDistance, x => target.effectDistance = x, endValue, duration); + t.SetTarget(target); + return t; + } + + #endregion + + #region RectTransform + + /// Tweens a RectTransform's anchoredPosition to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPos(this RectTransform target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + /// Tweens a RectTransform's anchoredPosition X to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPosX(this RectTransform target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue, 0), duration); + t.SetOptions(AxisConstraint.X, snapping).SetTarget(target); + return t; + } + /// Tweens a RectTransform's anchoredPosition Y to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPosY(this RectTransform target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, endValue), duration); + t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target); + return t; + } + + /// Tweens a RectTransform's anchoredPosition3D to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPos3D(this RectTransform target, Vector3 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + /// Tweens a RectTransform's anchoredPosition3D X to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPos3DX(this RectTransform target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(endValue, 0, 0), duration); + t.SetOptions(AxisConstraint.X, snapping).SetTarget(target); + return t; + } + /// Tweens a RectTransform's anchoredPosition3D Y to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPos3DY(this RectTransform target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, endValue, 0), duration); + t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target); + return t; + } + /// Tweens a RectTransform's anchoredPosition3D Z to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorPos3DZ(this RectTransform target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, 0, endValue), duration); + t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target); + return t; + } + + /// Tweens a RectTransform's anchorMax to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorMax(this RectTransform target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchorMax, x => target.anchorMax = x, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Tweens a RectTransform's anchorMin to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOAnchorMin(this RectTransform target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.anchorMin, x => target.anchorMin = x, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Tweens a RectTransform's pivot to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOPivot(this RectTransform target, Vector2 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.pivot, x => target.pivot = x, endValue, duration); + t.SetTarget(target); + return t; + } + /// Tweens a RectTransform's pivot X to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOPivotX(this RectTransform target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(endValue, 0), duration); + t.SetOptions(AxisConstraint.X).SetTarget(target); + return t; + } + /// Tweens a RectTransform's pivot Y to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOPivotY(this RectTransform target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(0, endValue), duration); + t.SetOptions(AxisConstraint.Y).SetTarget(target); + return t; + } + + /// Tweens a RectTransform's sizeDelta to the given value. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOSizeDelta(this RectTransform target, Vector2 endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.sizeDelta, x => target.sizeDelta = x, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + /// Punches a RectTransform's anchoredPosition towards the given direction and then back to the starting one + /// as if it was connected to the starting position via an elastic. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The direction and strength of the punch (added to the RectTransform's current position) + /// The duration of the tween + /// Indicates how much will the punch vibrate + /// Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards. + /// 1 creates a full oscillation between the punch direction and the opposite direction, + /// while 0 oscillates only between the punch and the start position + /// If TRUE the tween will smoothly snap all values to integers + public static Tweener DOPunchAnchorPos(this RectTransform target, Vector2 punch, float duration, int vibrato = 10, float elasticity = 1, bool snapping = false) + { + return DOTween.Punch(() => target.anchoredPosition, x => target.anchoredPosition = x, punch, duration, vibrato, elasticity) + .SetTarget(target).SetOptions(snapping); + } + + /// Shakes a RectTransform's anchoredPosition with the given values. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The duration of the tween + /// The shake strength + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the tween will smoothly snap all values to integers + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + /// Randomness mode + public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, float strength = 100, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full) + { + return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, true, fadeOut, randomnessMode) + .SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping); + } + /// Shakes a RectTransform's anchoredPosition with the given values. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The duration of the tween + /// The shake strength on each axis + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the tween will smoothly snap all values to integers + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + /// Randomness mode + public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, Vector2 strength, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full) + { + return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, fadeOut, randomnessMode) + .SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping); + } + + #region Special + + /// Tweens a RectTransform's anchoredPosition to the given value, while also applying a jump effect along the Y axis. + /// Returns a Sequence instead of a Tweener. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations + /// The end value to reach + /// Power of the jump (the max height of the jump is represented by this plus the final Y offset) + /// Total number of jumps + /// The duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static Sequence DOJumpAnchorPos(this RectTransform target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false) + { + if (numJumps < 1) numJumps = 1; + float startPosY = 0; + float offsetY = -1; + bool offsetYSet = false; + + // Separate Y Tween so we can elaborate elapsedPercentage on that insted of on the Sequence + // (in case users add a delay or other elements to the Sequence) + Sequence s = DOTween.Sequence(); + Tween yTween = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, jumpPower), duration / (numJumps * 2)) + .SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative() + .SetLoops(numJumps * 2, LoopType.Yoyo) + .OnStart(()=> startPosY = target.anchoredPosition.y); + s.Append(DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue.x, 0), duration) + .SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear) + ).Join(yTween) + .SetTarget(target).SetEase(DOTween.defaultEaseType); + s.OnUpdate(() => { + if (!offsetYSet) { + offsetYSet = true; + offsetY = s.isRelative ? endValue.y : endValue.y - startPosY; + } + Vector2 pos = target.anchoredPosition; + pos.y += DOVirtual.EasedValue(0, offsetY, s.ElapsedDirectionalPercentage(), Ease.OutQuad); + target.anchoredPosition = pos; + }); + return s; + } + + #endregion + + #endregion + + #region ScrollRect + + /// Tweens a ScrollRect's horizontal/verticalNormalizedPosition to the given value. + /// Also stores the ScrollRect as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static Tweener DONormalizedPos(this ScrollRect target, Vector2 endValue, float duration, bool snapping = false) + { + return DOTween.To(() => new Vector2(target.horizontalNormalizedPosition, target.verticalNormalizedPosition), + x => { + target.horizontalNormalizedPosition = x.x; + target.verticalNormalizedPosition = x.y; + }, endValue, duration) + .SetOptions(snapping).SetTarget(target); + } + /// Tweens a ScrollRect's horizontalNormalizedPosition to the given value. + /// Also stores the ScrollRect as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static Tweener DOHorizontalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false) + { + return DOTween.To(() => target.horizontalNormalizedPosition, x => target.horizontalNormalizedPosition = x, endValue, duration) + .SetOptions(snapping).SetTarget(target); + } + /// Tweens a ScrollRect's verticalNormalizedPosition to the given value. + /// Also stores the ScrollRect as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static Tweener DOVerticalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false) + { + return DOTween.To(() => target.verticalNormalizedPosition, x => target.verticalNormalizedPosition = x, endValue, duration) + .SetOptions(snapping).SetTarget(target); + } + + #endregion + + #region Slider + + /// Tweens a Slider's value to the given value. + /// Also stores the Slider as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOValue(this Slider target, float endValue, float duration, bool snapping = false) + { + TweenerCore t = DOTween.To(() => target.value, x => target.value = x, endValue, duration); + t.SetOptions(snapping).SetTarget(target); + return t; + } + + #endregion + + #region Text + + /// Tweens a Text's color to the given value. + /// Also stores the Text as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this Text target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// + /// Tweens a Text's text from one integer to another, with options for thousands separators + /// + /// The value to start from + /// The end value to reach + /// The duration of the tween + /// If TRUE (default) also adds thousands separators + /// The to use (InvariantCulture if NULL) + public static TweenerCore DOCounter( + this Text target, int fromValue, int endValue, float duration, bool addThousandsSeparator = true, CultureInfo culture = null + ){ + int v = fromValue; + CultureInfo cInfo = !addThousandsSeparator ? null : culture ?? CultureInfo.InvariantCulture; + TweenerCore t = DOTween.To(() => v, x => { + v = x; + target.text = addThousandsSeparator + ? v.ToString("N0", cInfo) + : v.ToString(); + }, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a Text's alpha color to the given value. + /// Also stores the Text as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this Text target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a Text's text to the given value. + /// Also stores the Text as the tween's target so it can be used for filtered operations + /// The end string to tween toThe duration of the tween + /// If TRUE (default), rich text will be interpreted correctly while animated, + /// otherwise all tags will be considered as normal text + /// The type of scramble mode to use, if any + /// A string containing the characters to use for scrambling. + /// Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters. + /// Leave it to NULL (default) to use default ones + public static TweenerCore DOText(this Text target, string endValue, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null) + { + if (endValue == null) { + if (Debugger.logPriority > 0) Debugger.LogWarning("You can't pass a NULL string to DOText: an empty string will be used instead to avoid errors"); + endValue = ""; + } + TweenerCore t = DOTween.To(() => target.text, x => target.text = x, endValue, duration); + t.SetOptions(richTextEnabled, scrambleMode, scrambleChars) + .SetTarget(target); + return t; + } + + #endregion + + #region Blendables + + #region Graphic + + /// Tweens a Graphic's color to the given value, + /// in a way that allows other DOBlendableColor tweens to work together on the same target, + /// instead than fight each other as multiple DOColor would do. + /// Also stores the Graphic as the tween's target so it can be used for filtered operations + /// The value to tween toThe duration of the tween + public static Tweener DOBlendableColor(this Graphic target, Color endValue, float duration) + { + endValue = endValue - target.color; + Color to = new Color(0, 0, 0, 0); + return DOTween.To(() => to, x => { + Color diff = x - to; + to = x; + target.color += diff; + }, endValue, duration) + .Blendable().SetTarget(target); + } + + #endregion + + #region Image + + /// Tweens a Image's color to the given value, + /// in a way that allows other DOBlendableColor tweens to work together on the same target, + /// instead than fight each other as multiple DOColor would do. + /// Also stores the Image as the tween's target so it can be used for filtered operations + /// The value to tween toThe duration of the tween + public static Tweener DOBlendableColor(this Image target, Color endValue, float duration) + { + endValue = endValue - target.color; + Color to = new Color(0, 0, 0, 0); + return DOTween.To(() => to, x => { + Color diff = x - to; + to = x; + target.color += diff; + }, endValue, duration) + .Blendable().SetTarget(target); + } + + #endregion + + #region Text + + /// Tweens a Text's color BY the given value, + /// in a way that allows other DOBlendableColor tweens to work together on the same target, + /// instead than fight each other as multiple DOColor would do. + /// Also stores the Text as the tween's target so it can be used for filtered operations + /// The value to tween toThe duration of the tween + public static Tweener DOBlendableColor(this Text target, Color endValue, float duration) + { + endValue = endValue - target.color; + Color to = new Color(0, 0, 0, 0); + return DOTween.To(() => to, x => { + Color diff = x - to; + to = x; + target.color += diff; + }, endValue, duration) + .Blendable().SetTarget(target); + } + + #endregion + + #endregion + + #region Shapes + + /// Tweens a RectTransform's anchoredPosition so that it draws a circle around the given center. + /// Also stores the RectTransform as the tween's target so it can be used for filtered operations. + /// IMPORTANT: SetFrom(value) requires a instead of a float, where the X property represents the "from degrees value" + /// Circle-center/pivot around which to rotate (in UI anchoredPosition coordinates) + /// The end value degrees to reach (to rotate counter-clockwise pass a negative value) + /// The duration of the tween + /// If TRUE the coordinates will be considered as relative to the target's current anchoredPosition + /// If TRUE the tween will smoothly snap all values to integers + public static TweenerCore DOShapeCircle( + this RectTransform target, Vector2 center, float endValueDegrees, float duration, bool relativeCenter = false, bool snapping = false + ) + { + TweenerCore t = DOTween.To( + CirclePlugin.Get(), () => target.anchoredPosition, x => target.anchoredPosition = x, center, duration + ); + t.SetOptions(endValueDegrees, relativeCenter, snapping).SetTarget(target); + return t; + } + + #endregion + + #endregion + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + // ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████ + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + + public static class Utils + { + /// + /// Converts the anchoredPosition of the first RectTransform to the second RectTransform, + /// taking into consideration offset, anchors and pivot, and returns the new anchoredPosition + /// + public static Vector2 SwitchToRectTransform(RectTransform from, RectTransform to) + { + Vector2 localPoint; + Vector2 fromPivotDerivedOffset = new Vector2(from.rect.width * 0.5f + from.rect.xMin, from.rect.height * 0.5f + from.rect.yMin); + Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, from.position); + screenP += fromPivotDerivedOffset; + RectTransformUtility.ScreenPointToLocalPointInRectangle(to, screenP, null, out localPoint); + Vector2 pivotDerivedOffset = new Vector2(to.rect.width * 0.5f + to.rect.xMin, to.rect.height * 0.5f + to.rect.yMin); + return to.anchoredPosition + localPoint - pivotDerivedOffset; + } + } + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs.meta new file mode 100644 index 0000000..60d55ef --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUI.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a060394c03331a64392db53a10e7f2d1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs new file mode 100644 index 0000000..fa1ac05 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs @@ -0,0 +1,403 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +using System; +using UnityEngine; +using DG.Tweening.Core; +using DG.Tweening.Plugins.Options; +//#if UNITY_2018_1_OR_NEWER && (NET_4_6 || NET_STANDARD_2_0) +//using Task = System.Threading.Tasks.Task; +//#endif + +#pragma warning disable 1591 +namespace DG.Tweening +{ + /// + /// Shortcuts/functions that are not strictly related to specific Modules + /// but are available only on some Unity versions + /// + public static class DOTweenModuleUnityVersion + { +#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER + #region Unity 4.3 or Newer + + #region Material + + /// Tweens a Material's color using the given gradient + /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener). + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The gradient to useThe duration of the tween + public static Sequence DOGradientColor(this Material target, Gradient gradient, float duration) + { + Sequence s = DOTween.Sequence(); + GradientColorKey[] colors = gradient.colorKeys; + int len = colors.Length; + for (int i = 0; i < len; ++i) { + GradientColorKey c = colors[i]; + if (i == 0 && c.time <= 0) { + target.color = c.color; + continue; + } + float colorDuration = i == len - 1 + ? duration - s.Duration(false) // Verifies that total duration is correct + : duration * (i == 0 ? c.time : c.time - colors[i - 1].time); + s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear)); + } + s.SetTarget(target); + return s; + } + /// Tweens a Material's named color property using the given gradient + /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener). + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The gradient to use + /// The name of the material property to tween (like _Tint or _SpecColor) + /// The duration of the tween + public static Sequence DOGradientColor(this Material target, Gradient gradient, string property, float duration) + { + Sequence s = DOTween.Sequence(); + GradientColorKey[] colors = gradient.colorKeys; + int len = colors.Length; + for (int i = 0; i < len; ++i) { + GradientColorKey c = colors[i]; + if (i == 0 && c.time <= 0) { + target.SetColor(property, c.color); + continue; + } + float colorDuration = i == len - 1 + ? duration - s.Duration(false) // Verifies that total duration is correct + : duration * (i == 0 ? c.time : c.time - colors[i - 1].time); + s.Append(target.DOColor(c.color, property, colorDuration).SetEase(Ease.Linear)); + } + s.SetTarget(target); + return s; + } + + #endregion + + #endregion +#endif + +#if UNITY_5_3_OR_NEWER || UNITY_2017_1_OR_NEWER + #region Unity 5.3 or Newer + + #region CustomYieldInstructions + + /// + /// Returns a that waits until the tween is killed or complete. + /// It can be used inside a coroutine as a yield. + /// Example usage:yield return myTween.WaitForCompletion(true); + /// + public static CustomYieldInstruction WaitForCompletion(this Tween t, bool returnCustomYieldInstruction) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return null; + } + return new DOTweenCYInstruction.WaitForCompletion(t); + } + + /// + /// Returns a that waits until the tween is killed or rewinded. + /// It can be used inside a coroutine as a yield. + /// Example usage:yield return myTween.WaitForRewind(); + /// + public static CustomYieldInstruction WaitForRewind(this Tween t, bool returnCustomYieldInstruction) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return null; + } + return new DOTweenCYInstruction.WaitForRewind(t); + } + + /// + /// Returns a that waits until the tween is killed. + /// It can be used inside a coroutine as a yield. + /// Example usage:yield return myTween.WaitForKill(); + /// + public static CustomYieldInstruction WaitForKill(this Tween t, bool returnCustomYieldInstruction) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return null; + } + return new DOTweenCYInstruction.WaitForKill(t); + } + + /// + /// Returns a that waits until the tween is killed or has gone through the given amount of loops. + /// It can be used inside a coroutine as a yield. + /// Example usage:yield return myTween.WaitForElapsedLoops(2); + /// + /// Elapsed loops to wait for + public static CustomYieldInstruction WaitForElapsedLoops(this Tween t, int elapsedLoops, bool returnCustomYieldInstruction) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return null; + } + return new DOTweenCYInstruction.WaitForElapsedLoops(t, elapsedLoops); + } + + /// + /// Returns a that waits until the tween is killed + /// or has reached the given time position (loops included, delays excluded). + /// It can be used inside a coroutine as a yield. + /// Example usage:yield return myTween.WaitForPosition(2.5f); + /// + /// Position (loops included, delays excluded) to wait for + public static CustomYieldInstruction WaitForPosition(this Tween t, float position, bool returnCustomYieldInstruction) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return null; + } + return new DOTweenCYInstruction.WaitForPosition(t, position); + } + + /// + /// Returns a that waits until the tween is killed or started + /// (meaning when the tween is set in a playing state the first time, after any eventual delay). + /// It can be used inside a coroutine as a yield. + /// Example usage:yield return myTween.WaitForStart(); + /// + public static CustomYieldInstruction WaitForStart(this Tween t, bool returnCustomYieldInstruction) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return null; + } + return new DOTweenCYInstruction.WaitForStart(t); + } + + #endregion + + #endregion +#endif + +#if UNITY_2018_1_OR_NEWER + #region Unity 2018.1 or Newer + + #region Material + + /// Tweens a Material's named texture offset property with the given ID to the given value. + /// Also stores the material as the tween's target so it can be used for filtered operations + /// The end value to reach + /// The ID of the material property to tween (also called nameID in Unity's manual) + /// The duration of the tween + public static TweenerCore DOOffset(this Material target, Vector2 endValue, int propertyID, float duration) + { + if (!target.HasProperty(propertyID)) { + if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID); + return null; + } + TweenerCore t = DOTween.To(() => target.GetTextureOffset(propertyID), x => target.SetTextureOffset(propertyID, x), endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a Material's named texture scale property with the given ID to the given value. + /// Also stores the material as the tween's target so it can be used for filtered operations + /// The end value to reach + /// The ID of the material property to tween (also called nameID in Unity's manual) + /// The duration of the tween + public static TweenerCore DOTiling(this Material target, Vector2 endValue, int propertyID, float duration) + { + if (!target.HasProperty(propertyID)) { + if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID); + return null; + } + TweenerCore t = DOTween.To(() => target.GetTextureScale(propertyID), x => target.SetTextureScale(propertyID, x), endValue, duration); + t.SetTarget(target); + return t; + } + + #endregion + + #region .NET 4.6 or Newer + +#if UNITY_2018_1_OR_NEWER && (NET_4_6 || NET_STANDARD_2_0) + + #region Async Instructions + + /// + /// Returns an async that waits until the tween is killed or complete. + /// It can be used inside an async operation. + /// Example usage:await myTween.WaitForCompletion(); + /// + public static async System.Threading.Tasks.Task AsyncWaitForCompletion(this Tween t) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return; + } + while (t.active && !t.IsComplete()) await System.Threading.Tasks.Task.Yield(); + } + + /// + /// Returns an async that waits until the tween is killed or rewinded. + /// It can be used inside an async operation. + /// Example usage:await myTween.AsyncWaitForRewind(); + /// + public static async System.Threading.Tasks.Task AsyncWaitForRewind(this Tween t) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return; + } + while (t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0)) await System.Threading.Tasks.Task.Yield(); + } + + /// + /// Returns an async that waits until the tween is killed. + /// It can be used inside an async operation. + /// Example usage:await myTween.AsyncWaitForKill(); + /// + public static async System.Threading.Tasks.Task AsyncWaitForKill(this Tween t) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return; + } + while (t.active) await System.Threading.Tasks.Task.Yield(); + } + + /// + /// Returns an async that waits until the tween is killed or has gone through the given amount of loops. + /// It can be used inside an async operation. + /// Example usage:await myTween.AsyncWaitForElapsedLoops(); + /// + /// Elapsed loops to wait for + public static async System.Threading.Tasks.Task AsyncWaitForElapsedLoops(this Tween t, int elapsedLoops) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return; + } + while (t.active && t.CompletedLoops() < elapsedLoops) await System.Threading.Tasks.Task.Yield(); + } + + /// + /// Returns an async that waits until the tween is killed or started + /// (meaning when the tween is set in a playing state the first time, after any eventual delay). + /// It can be used inside an async operation. + /// Example usage:await myTween.AsyncWaitForPosition(); + /// + /// Position (loops included, delays excluded) to wait for + public static async System.Threading.Tasks.Task AsyncWaitForPosition(this Tween t, float position) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return; + } + while (t.active && t.position * (t.CompletedLoops() + 1) < position) await System.Threading.Tasks.Task.Yield(); + } + + /// + /// Returns an async that waits until the tween is killed. + /// It can be used inside an async operation. + /// Example usage:await myTween.AsyncWaitForKill(); + /// + public static async System.Threading.Tasks.Task AsyncWaitForStart(this Tween t) + { + if (!t.active) { + if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t); + return; + } + while (t.active && !t.playedOnce) await System.Threading.Tasks.Task.Yield(); + } + + #endregion +#endif + + #endregion + + #endregion +#endif + } + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + // ███ CLASSES █████████████████████████████████████████████████████████████████████████████████████████████████████████ + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + +#if UNITY_5_3_OR_NEWER || UNITY_2017_1_OR_NEWER + public static class DOTweenCYInstruction + { + public class WaitForCompletion : CustomYieldInstruction + { + public override bool keepWaiting { get { + return t.active && !t.IsComplete(); + }} + readonly Tween t; + public WaitForCompletion(Tween tween) + { + t = tween; + } + } + + public class WaitForRewind : CustomYieldInstruction + { + public override bool keepWaiting { get { + return t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0); + }} + readonly Tween t; + public WaitForRewind(Tween tween) + { + t = tween; + } + } + + public class WaitForKill : CustomYieldInstruction + { + public override bool keepWaiting { get { + return t.active; + }} + readonly Tween t; + public WaitForKill(Tween tween) + { + t = tween; + } + } + + public class WaitForElapsedLoops : CustomYieldInstruction + { + public override bool keepWaiting { get { + return t.active && t.CompletedLoops() < elapsedLoops; + }} + readonly Tween t; + readonly int elapsedLoops; + public WaitForElapsedLoops(Tween tween, int elapsedLoops) + { + t = tween; + this.elapsedLoops = elapsedLoops; + } + } + + public class WaitForPosition : CustomYieldInstruction + { + public override bool keepWaiting { get { + return t.active && t.position * (t.CompletedLoops() + 1) < position; + }} + readonly Tween t; + readonly float position; + public WaitForPosition(Tween tween, float position) + { + t = tween; + this.position = position; + } + } + + public class WaitForStart : CustomYieldInstruction + { + public override bool keepWaiting { get { + return t.active && !t.playedOnce; + }} + readonly Tween t; + public WaitForStart(Tween tween) + { + t = tween; + } + } + } +#endif +} diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs.meta new file mode 100644 index 0000000..290189f --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUnityVersion.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 63c02322328255542995bd02b47b0457 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs new file mode 100644 index 0000000..12a365d --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs @@ -0,0 +1,167 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +using System; +using System.Reflection; +using UnityEngine; +using DG.Tweening.Core; +using DG.Tweening.Plugins.Core.PathCore; +using DG.Tweening.Plugins.Options; + +#pragma warning disable 1591 +namespace DG.Tweening +{ + /// + /// Utility functions that deal with available Modules. + /// Modules defines: + /// - DOTAUDIO + /// - DOTPHYSICS + /// - DOTPHYSICS2D + /// - DOTSPRITE + /// - DOTUI + /// Extra defines set and used for implementation of external assets: + /// - DOTWEEN_TMP ► TextMesh Pro + /// - DOTWEEN_TK2D ► 2D Toolkit + /// + public static class DOTweenModuleUtils + { + static bool _initialized; + + #region Reflection + + /// + /// Called via Reflection by DOTweenComponent on Awake + /// +#if UNITY_2018_1_OR_NEWER + [UnityEngine.Scripting.Preserve] +#endif + public static void Init() + { + if (_initialized) return; + + _initialized = true; + DOTweenExternalCommand.SetOrientationOnPath += Physics.SetOrientationOnPath; + +#if UNITY_EDITOR +#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1 + UnityEditor.EditorApplication.playmodeStateChanged += PlaymodeStateChanged; +#else + UnityEditor.EditorApplication.playModeStateChanged += PlaymodeStateChanged; +#endif +#endif + } + +#if UNITY_2018_1_OR_NEWER +#pragma warning disable + [UnityEngine.Scripting.Preserve] + // Just used to preserve methods when building, never called + static void Preserver() + { + Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + MethodInfo mi = typeof(MonoBehaviour).GetMethod("Stub"); + } +#pragma warning restore +#endif + + #endregion + +#if UNITY_EDITOR + // Fires OnApplicationPause in DOTweenComponent even when Editor is paused (otherwise it's only fired at runtime) +#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1 + static void PlaymodeStateChanged() + #else + static void PlaymodeStateChanged(UnityEditor.PlayModeStateChange state) +#endif + { + if (DOTween.instance == null) return; + DOTween.instance.OnApplicationPause(UnityEditor.EditorApplication.isPaused); + } +#endif + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + // ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████ + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + + public static class Physics + { + // Called via DOTweenExternalCommand callback + public static void SetOrientationOnPath(PathOptions options, Tween t, Quaternion newRot, Transform trans) + { +#if true // PHYSICS_MARKER + if (options.isRigidbody) ((Rigidbody)t.target).rotation = newRot; + else trans.rotation = newRot; +#else + trans.rotation = newRot; +#endif + } + + // Returns FALSE if the DOTween's Physics2D Module is disabled, or if there's no Rigidbody2D attached + public static bool HasRigidbody2D(Component target) + { +#if true // PHYSICS2D_MARKER + return target.GetComponent() != null; +#else + return false; +#endif + } + + #region Called via Reflection + + + // Called via Reflection by DOTweenPathInspector + // Returns FALSE if the DOTween's Physics Module is disabled, or if there's no rigidbody attached +#if UNITY_2018_1_OR_NEWER + [UnityEngine.Scripting.Preserve] +#endif + public static bool HasRigidbody(Component target) + { +#if true // PHYSICS_MARKER + return target.GetComponent() != null; +#else + return false; +#endif + } + + // Called via Reflection by DOTweenPath +#if UNITY_2018_1_OR_NEWER + [UnityEngine.Scripting.Preserve] +#endif + public static TweenerCore CreateDOTweenPathTween( + MonoBehaviour target, bool tweenRigidbody, bool isLocal, Path path, float duration, PathMode pathMode + ){ + TweenerCore t = null; + bool rBodyFoundAndTweened = false; +#if true // PHYSICS_MARKER + if (tweenRigidbody) { + Rigidbody rBody = target.GetComponent(); + if (rBody != null) { + rBodyFoundAndTweened = true; + t = isLocal + ? rBody.DOLocalPath(path, duration, pathMode) + : rBody.DOPath(path, duration, pathMode); + } + } +#endif +#if true // PHYSICS2D_MARKER + if (!rBodyFoundAndTweened && tweenRigidbody) { + Rigidbody2D rBody2D = target.GetComponent(); + if (rBody2D != null) { + rBodyFoundAndTweened = true; + t = isLocal + ? rBody2D.DOLocalPath(path, duration, pathMode) + : rBody2D.DOPath(path, duration, pathMode); + } + } +#endif + if (!rBodyFoundAndTweened) { + t = isLocal + ? target.transform.DOLocalPath(path, duration, pathMode) + : target.transform.DOPath(path, duration, pathMode); + } + return t; + } + + #endregion + } + } +} diff --git a/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs.meta b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs.meta new file mode 100644 index 0000000..ab62186 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/Modules/DOTweenModuleUtils.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7bcaf917d9cf5b84090421a5a2abe42e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTween/readme.txt b/Assets/Plugins/Demigiant/DOTween/readme.txt new file mode 100644 index 0000000..37ff7ef --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/readme.txt @@ -0,0 +1,29 @@ +DOTween and DOTween Pro are copyright (c) 2014-2018 Daniele Giardini - Demigiant + +// IMPORTANT!!! ///////////////////////////////////////////// +// Upgrading DOTween from versions older than 1.2.000 /////// +// (or DOTween Pro older than 1.0.000) ////////////////////// +------------------------------------------------------------- +If you're upgrading your project from a version of DOTween older than 1.2.000 (or DOTween Pro older than 1.0.000) please follow these instructions carefully. +1) Import the new version in the same folder as the previous one, overwriting old files. A lot of errors will appear but don't worry +2) Close and reopen Unity (and your project). This is fundamental: skipping this step will cause a bloodbath +3) Open DOTween's Utility Panel (Tools > Demigiant > DOTween Utility Panel) if it doesn't open automatically, then press "Setup DOTween...": this will run the upgrade setup +4) From the Add/Remove Modules panel that opens, activate/deactivate Modules for Unity systems and for external assets (Pro version only) + +// GET STARTED ////////////////////////////////////////////// + +- After importing a new DOTween update, select DOTween's Utility Panel from the "Tools/Demigiant" menu (if it doesn't open automatically) and press the "Setup DOTween..." button to activate/deactivate Modules. You can also access a Preferences Tab from there to choose default settings for DOTween. +- In your code, add "using DG.Tweening" to each class where you want to use DOTween. +- You're ready to tween. Check out the links below for full documentation and license info. + + +// LINKS /////////////////////////////////////////////////////// + +DOTween website (documentation, examples, etc): http://dotween.demigiant.com +DOTween license: http://dotween.demigiant.com/license.php +DOTween repository (Google Code): https://code.google.com/p/dotween/ +Demigiant website (documentation, examples, etc): http://www.demigiant.com + +// NOTES ////////////////////////////////////////////////////// + +- DOTween's Utility Panel can be found under "Tools > Demigiant > DOTween Utility Panel" and also contains other useful options, plus a tab to set DOTween's preferences \ No newline at end of file diff --git a/Assets/Plugins/Demigiant/DOTween/readme.txt.meta b/Assets/Plugins/Demigiant/DOTween/readme.txt.meta new file mode 100644 index 0000000..3799165 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTween/readme.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: fccfc62abf2eb0a4db614853430894fd +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro.meta b/Assets/Plugins/Demigiant/DOTweenPro.meta new file mode 100644 index 0000000..659537c --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: af55cfd0e7084ab4884c5a4f29b62d9f +labels: +- Tween +- Tweening +- Animation +- HOTween +- Paths +- VisualScripting +- VisualEditor +- iTween +- DFTween +- LeanTween +- Ease +- Easing +- Shake +- Punch +- 2DToolkit +- TextMeshPro +- Text +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs new file mode 100644 index 0000000..c7e7b21 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs @@ -0,0 +1,917 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2015/03/12 15:55 + +using System; +using System.Collections.Generic; +using DG.Tweening.Core; +using UnityEngine; +#if true // UI_MARKER +using UnityEngine.UI; +#endif +#if false // TEXTMESHPRO_MARKER +using TMPro; +#endif + +#pragma warning disable 1591 +namespace DG.Tweening +{ + /// + /// Attach this to a GameObject to create a tween + /// + [AddComponentMenu("DOTween/DOTween Animation")] + public class DOTweenAnimation : ABSAnimationComponent + { + public enum AnimationType + { + None, + Move, LocalMove, + Rotate, LocalRotate, + Scale, + Color, Fade, + Text, + PunchPosition, PunchRotation, PunchScale, + ShakePosition, ShakeRotation, ShakeScale, + CameraAspect, CameraBackgroundColor, CameraFieldOfView, CameraOrthoSize, CameraPixelRect, CameraRect, + UIWidthHeight, + FillAmount + } + + public enum TargetType + { + Unset, + + Camera, + CanvasGroup, + Image, + Light, + RectTransform, + Renderer, SpriteRenderer, + Rigidbody, Rigidbody2D, + Text, + Transform, + + tk2dBaseSprite, + tk2dTextMesh, + + TextMeshPro, + TextMeshProUGUI + } + + #region EVENTS - EDITOR-ONLY + + /// Used internally by the editor + public static event Action OnReset; + static void Dispatch_OnReset(DOTweenAnimation anim) { if (OnReset != null) OnReset(anim); } + + #endregion + + public bool targetIsSelf = true; // If FALSE allows to set the target manually + public GameObject targetGO = null; // Used in case targetIsSelf is FALSE + // If FALSE always uses the GO containing this DOTweenAnimation (and not the one containing the target) as DOTween's SetTarget target + public bool tweenTargetIsTargetGO = true; + + public float delay; + public float duration = 1; + public Ease easeType = Ease.OutQuad; + public AnimationCurve easeCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(1, 1)); + public LoopType loopType = LoopType.Restart; + public int loops = 1; + public string id = ""; + public bool isRelative; + public bool isFrom; + public bool isIndependentUpdate = false; + public bool autoKill = true; + public bool autoGenerate = true; // If TRUE automatically creates the tween at startup + + public bool isActive = true; + public bool isValid; + public Component target; + public AnimationType animationType; + public TargetType targetType; + public TargetType forcedTargetType; // Used when choosing between multiple targets + public bool autoPlay = true; + public bool useTargetAsV3; + + public float endValueFloat; + public Vector3 endValueV3; + public Vector2 endValueV2; + public Color endValueColor = new Color(1, 1, 1, 1); + public string endValueString = ""; + public Rect endValueRect = new Rect(0, 0, 0, 0); + public Transform endValueTransform; + + public bool optionalBool0, optionalBool1; + public float optionalFloat0; + public int optionalInt0; + public RotateMode optionalRotationMode = RotateMode.Fast; + public ScrambleMode optionalScrambleMode = ScrambleMode.None; + public ShakeRandomnessMode optionalShakeRandomnessMode = ShakeRandomnessMode.Full; + public string optionalString; + + bool _tweenAutoGenerationCalled; // TRUE after the tweens have been autoGenerated + int _playCount = -1; // Used when calling DOPlayNext + readonly List _tmpTweens = new List(); + + #region Unity Methods + + void Awake() + { + if (!isActive || !autoGenerate) return; + + if (animationType != AnimationType.Move || !useTargetAsV3) { + // Don't create tweens if we're using a RectTransform as a Move target, + // because that will work only inside Start + CreateTween(false, autoPlay); + _tweenAutoGenerationCalled = true; + } + } + + void Start() + { + if (_tweenAutoGenerationCalled || !isActive || !autoGenerate) return; + + CreateTween(false, autoPlay); + _tweenAutoGenerationCalled = true; + } + + void Reset() + { + Dispatch_OnReset(this); + } + + void OnDestroy() + { + if (tween != null && tween.active) tween.Kill(); + tween = null; + } + + /// + /// Creates/recreates the tween without playing it, but first rewinding and killing the existing one if present. + /// + public void RewindThenRecreateTween() + { + if (tween != null && tween.active) tween.Rewind(); + CreateTween(true, false); + } + /// + /// Creates/recreates the tween and plays it, first rewinding and killing the existing one if present. + /// + public void RewindThenRecreateTweenAndPlay() + { + if (tween != null && tween.active) tween.Rewind(); + CreateTween(true, true); + } + /// + /// Creates/recreates the tween from its target's current value without playing it, but first killing the existing one if present. + /// + public void RecreateTween() + { CreateTween(true, false); } + /// + /// Creates/recreates the tween from its target's current value and plays it, first killing the existing one if present. + /// + public void RecreateTweenAndPlay() + { CreateTween(true, true); } + // Used also by DOTweenAnimationInspector when applying runtime changes and restarting + /// + /// Creates the tween manually (called automatically if AutoGenerate is set in the Inspector) + /// from its target's current value. + /// + /// If TRUE and an existing tween was already created (and not killed), kills it and recreates it with the current + /// parameters. Otherwise, if a tween already exists, does nothing. + /// If TRUE also plays the tween, otherwise only creates it + public void CreateTween(bool regenerateIfExists = false, bool andPlay = true) + { + if (!isValid) { + if (regenerateIfExists) { // Called manually: warn users + Debug.LogWarning(string.Format("{0} :: This DOTweenAnimation isn't valid and its tween won't be created", this.gameObject.name), this.gameObject); + } + return; + } + if (tween != null) { + if (tween.active) { + if (regenerateIfExists) tween.Kill(); + else return; + } + tween = null; + } + +// if (target == null) { +// Debug.LogWarning(string.Format("{0} :: This DOTweenAnimation's target is NULL, because the animation was created with a DOTween Pro version older than 0.9.255. To fix this, exit Play mode then simply select this object, and it will update automatically", this.gameObject.name), this.gameObject); +// return; +// } + + GameObject tweenGO = GetTweenGO(); + if (target == null || tweenGO == null) { + if (targetIsSelf && target == null) { + // Old error caused during upgrade from DOTween Pro 0.9.255 + Debug.LogWarning(string.Format("{0} :: This DOTweenAnimation's target is NULL, because the animation was created with a DOTween Pro version older than 0.9.255. To fix this, exit Play mode then simply select this object, and it will update automatically", this.gameObject.name), this.gameObject); + } else { + // Missing non-self target + Debug.LogWarning(string.Format("{0} :: This DOTweenAnimation's target/GameObject is unset: the tween will not be created.", this.gameObject.name), this.gameObject); + } + return; + } + + if (forcedTargetType != TargetType.Unset) targetType = forcedTargetType; + if (targetType == TargetType.Unset) { + // Legacy DOTweenAnimation (made with a version older than 0.9.450) without stored targetType > assign it now + targetType = TypeToDOTargetType(target.GetType()); + } + + switch (animationType) { + case AnimationType.None: + break; + case AnimationType.Move: + if (useTargetAsV3) { + isRelative = false; + if (endValueTransform == null) { + Debug.LogWarning(string.Format("{0} :: This tween's TO target is NULL, a Vector3 of (0,0,0) will be used instead", this.gameObject.name), this.gameObject); + endValueV3 = Vector3.zero; + } else { +#if true // UI_MARKER + if (targetType == TargetType.RectTransform) { + RectTransform endValueT = endValueTransform as RectTransform; + if (endValueT == null) { + Debug.LogWarning(string.Format("{0} :: This tween's TO target should be a RectTransform, a Vector3 of (0,0,0) will be used instead", this.gameObject.name), this.gameObject); + endValueV3 = Vector3.zero; + } else { + RectTransform rTarget = target as RectTransform; + if (rTarget == null) { + Debug.LogWarning(string.Format("{0} :: This tween's target and TO target are not of the same type. Please reassign the values", this.gameObject.name), this.gameObject); + } else { + // Problem: doesn't work inside Awake (ararargh!) + endValueV3 = DOTweenModuleUI.Utils.SwitchToRectTransform(endValueT, rTarget); + } + } + } else +#endif + endValueV3 = endValueTransform.position; + } + } + switch (targetType) { + case TargetType.Transform: + tween = ((Transform)target).DOMove(endValueV3, duration, optionalBool0); + break; + case TargetType.RectTransform: +#if true // UI_MARKER + tween = ((RectTransform)target).DOAnchorPos3D(endValueV3, duration, optionalBool0); +#else + tween = ((Transform)target).DOMove(endValueV3, duration, optionalBool0); +#endif + break; + case TargetType.Rigidbody: +#if true // PHYSICS_MARKER + tween = ((Rigidbody)target).DOMove(endValueV3, duration, optionalBool0); +#else + tween = ((Transform)target).DOMove(endValueV3, duration, optionalBool0); +#endif + break; + case TargetType.Rigidbody2D: +#if true // PHYSICS2D_MARKER + tween = ((Rigidbody2D)target).DOMove(endValueV3, duration, optionalBool0); +#else + tween = ((Transform)target).DOMove(endValueV3, duration, optionalBool0); +#endif + break; + } + break; + case AnimationType.LocalMove: + tween = tweenGO.transform.DOLocalMove(endValueV3, duration, optionalBool0); + break; + case AnimationType.Rotate: + switch (targetType) { + case TargetType.Transform: + tween = ((Transform)target).DORotate(endValueV3, duration, optionalRotationMode); + break; + case TargetType.Rigidbody: +#if true // PHYSICS_MARKER + tween = ((Rigidbody)target).DORotate(endValueV3, duration, optionalRotationMode); +#else + tween = ((Transform)target).DORotate(endValueV3, duration, optionalRotationMode); +#endif + break; + case TargetType.Rigidbody2D: +#if true // PHYSICS2D_MARKER + tween = ((Rigidbody2D)target).DORotate(endValueFloat, duration); +#else + tween = ((Transform)target).DORotate(endValueV3, duration, optionalRotationMode); +#endif + break; + } + break; + case AnimationType.LocalRotate: + tween = tweenGO.transform.DOLocalRotate(endValueV3, duration, optionalRotationMode); + break; + case AnimationType.Scale: + switch (targetType) { +#if false // TK2D_MARKER + case TargetType.tk2dTextMesh: + tween = ((tk2dTextMesh)target).DOScale(optionalBool0 ? new Vector3(endValueFloat, endValueFloat, endValueFloat) : endValueV3, duration); + break; + case TargetType.tk2dBaseSprite: + tween = ((tk2dBaseSprite)target).DOScale(optionalBool0 ? new Vector3(endValueFloat, endValueFloat, endValueFloat) : endValueV3, duration); + break; +#endif + default: + tween = tweenGO.transform.DOScale(optionalBool0 ? new Vector3(endValueFloat, endValueFloat, endValueFloat) : endValueV3, duration); + break; + } + break; +#if true // UI_MARKER + case AnimationType.UIWidthHeight: + tween = ((RectTransform)target).DOSizeDelta(optionalBool0 ? new Vector2(endValueFloat, endValueFloat) : endValueV2, duration); + break; + case AnimationType.FillAmount: + tween = ((Image)target).DOFillAmount(endValueFloat, duration); + break; +#endif + case AnimationType.Color: + isRelative = false; + switch (targetType) { + case TargetType.Renderer: + tween = ((Renderer)target).material.DOColor(endValueColor, duration); + break; + case TargetType.Light: + tween = ((Light)target).DOColor(endValueColor, duration); + break; +#if true // SPRITE_MARKER + case TargetType.SpriteRenderer: + tween = ((SpriteRenderer)target).DOColor(endValueColor, duration); + break; +#endif +#if true // UI_MARKER + case TargetType.Image: + tween = ((Graphic)target).DOColor(endValueColor, duration); + break; + case TargetType.Text: + tween = ((Text)target).DOColor(endValueColor, duration); + break; +#endif +#if false // TK2D_MARKER + case TargetType.tk2dTextMesh: + tween = ((tk2dTextMesh)target).DOColor(endValueColor, duration); + break; + case TargetType.tk2dBaseSprite: + tween = ((tk2dBaseSprite)target).DOColor(endValueColor, duration); + break; +#endif +#if false // TEXTMESHPRO_MARKER + case TargetType.TextMeshProUGUI: + tween = ((TextMeshProUGUI)target).DOColor(endValueColor, duration); + break; + case TargetType.TextMeshPro: + tween = ((TextMeshPro)target).DOColor(endValueColor, duration); + break; +#endif + } + break; + case AnimationType.Fade: + isRelative = false; + switch (targetType) { + case TargetType.Renderer: + tween = ((Renderer)target).material.DOFade(endValueFloat, duration); + break; + case TargetType.Light: + tween = ((Light)target).DOIntensity(endValueFloat, duration); + break; +#if true // SPRITE_MARKER + case TargetType.SpriteRenderer: + tween = ((SpriteRenderer)target).DOFade(endValueFloat, duration); + break; +#endif +#if true // UI_MARKER + case TargetType.Image: + tween = ((Graphic)target).DOFade(endValueFloat, duration); + break; + case TargetType.Text: + tween = ((Text)target).DOFade(endValueFloat, duration); + break; + case TargetType.CanvasGroup: + tween = ((CanvasGroup)target).DOFade(endValueFloat, duration); + break; +#endif +#if false // TK2D_MARKER + case TargetType.tk2dTextMesh: + tween = ((tk2dTextMesh)target).DOFade(endValueFloat, duration); + break; + case TargetType.tk2dBaseSprite: + tween = ((tk2dBaseSprite)target).DOFade(endValueFloat, duration); + break; +#endif +#if false // TEXTMESHPRO_MARKER + case TargetType.TextMeshProUGUI: + tween = ((TextMeshProUGUI)target).DOFade(endValueFloat, duration); + break; + case TargetType.TextMeshPro: + tween = ((TextMeshPro)target).DOFade(endValueFloat, duration); + break; +#endif + } + break; + case AnimationType.Text: +#if true // UI_MARKER + switch (targetType) { + case TargetType.Text: + tween = ((Text)target).DOText(endValueString, duration, optionalBool0, optionalScrambleMode, optionalString); + break; + } +#endif +#if false // TK2D_MARKER + switch (targetType) { + case TargetType.tk2dTextMesh: + tween = ((tk2dTextMesh)target).DOText(endValueString, duration, optionalBool0, optionalScrambleMode, optionalString); + break; + } +#endif +#if false // TEXTMESHPRO_MARKER + switch (targetType) { + case TargetType.TextMeshProUGUI: + tween = ((TextMeshProUGUI)target).DOText(endValueString, duration, optionalBool0, optionalScrambleMode, optionalString); + break; + case TargetType.TextMeshPro: + tween = ((TextMeshPro)target).DOText(endValueString, duration, optionalBool0, optionalScrambleMode, optionalString); + break; + } +#endif + break; + case AnimationType.PunchPosition: + switch (targetType) { + case TargetType.Transform: + tween = ((Transform)target).DOPunchPosition(endValueV3, duration, optionalInt0, optionalFloat0, optionalBool0); + break; +#if true // UI_MARKER + case TargetType.RectTransform: + tween = ((RectTransform)target).DOPunchAnchorPos(endValueV3, duration, optionalInt0, optionalFloat0, optionalBool0); + break; +#endif + } + break; + case AnimationType.PunchScale: + tween = tweenGO.transform.DOPunchScale(endValueV3, duration, optionalInt0, optionalFloat0); + break; + case AnimationType.PunchRotation: + tween = tweenGO.transform.DOPunchRotation(endValueV3, duration, optionalInt0, optionalFloat0); + break; + case AnimationType.ShakePosition: + switch (targetType) { + case TargetType.Transform: + tween = ((Transform)target).DOShakePosition(duration, endValueV3, optionalInt0, optionalFloat0, optionalBool0, optionalBool1, optionalShakeRandomnessMode); + break; +#if true // UI_MARKER + case TargetType.RectTransform: + tween = ((RectTransform)target).DOShakeAnchorPos(duration, endValueV3, optionalInt0, optionalFloat0, optionalBool0, optionalBool1, optionalShakeRandomnessMode); + break; +#endif + } + break; + case AnimationType.ShakeScale: + tween = tweenGO.transform.DOShakeScale(duration, endValueV3, optionalInt0, optionalFloat0, optionalBool1, optionalShakeRandomnessMode); + break; + case AnimationType.ShakeRotation: + tween = tweenGO.transform.DOShakeRotation(duration, endValueV3, optionalInt0, optionalFloat0, optionalBool1, optionalShakeRandomnessMode); + break; + case AnimationType.CameraAspect: + tween = ((Camera)target).DOAspect(endValueFloat, duration); + break; + case AnimationType.CameraBackgroundColor: + tween = ((Camera)target).DOColor(endValueColor, duration); + break; + case AnimationType.CameraFieldOfView: + tween = ((Camera)target).DOFieldOfView(endValueFloat, duration); + break; + case AnimationType.CameraOrthoSize: + tween = ((Camera)target).DOOrthoSize(endValueFloat, duration); + break; + case AnimationType.CameraPixelRect: + tween = ((Camera)target).DOPixelRect(endValueRect, duration); + break; + case AnimationType.CameraRect: + tween = ((Camera)target).DORect(endValueRect, duration); + break; + } + + if (tween == null) return; + + // Created + + if (isFrom) { + ((Tweener)tween).From(isRelative); + } else { + tween.SetRelative(isRelative); + } + GameObject setTarget = GetTweenTarget(); + tween.SetTarget(setTarget).SetDelay(delay).SetLoops(loops, loopType).SetAutoKill(autoKill) + .OnKill(()=> tween = null); + if (isSpeedBased) tween.SetSpeedBased(); + if (easeType == Ease.INTERNAL_Custom) tween.SetEase(easeCurve); + else tween.SetEase(easeType); + if (!string.IsNullOrEmpty(id)) tween.SetId(id); + tween.SetUpdate(isIndependentUpdate); + + if (hasOnStart) { + if (onStart != null) tween.OnStart(onStart.Invoke); + } else onStart = null; + if (hasOnPlay) { + if (onPlay != null) tween.OnPlay(onPlay.Invoke); + } else onPlay = null; + if (hasOnUpdate) { + if (onUpdate != null) tween.OnUpdate(onUpdate.Invoke); + } else onUpdate = null; + if (hasOnStepComplete) { + if (onStepComplete != null) tween.OnStepComplete(onStepComplete.Invoke); + } else onStepComplete = null; + if (hasOnComplete) { + if (onComplete != null) tween.OnComplete(onComplete.Invoke); + } else onComplete = null; + if (hasOnRewind) { + if (onRewind != null) tween.OnRewind(onRewind.Invoke); + } else onRewind = null; + + if (andPlay) tween.Play(); + else tween.Pause(); + + if (hasOnTweenCreated && onTweenCreated != null) onTweenCreated.Invoke(); + } + + #endregion + + #region Public Methods + + #region Special + + /// + /// Returns the tweens (if generated and not killed) created by all DOTweenAnimations on this gameObject, + /// in the same order as they appear in the Inspector (top to bottom). + /// Note that a tween is generated inside the Awake call (except RectTransform tweens which are generated inside Start), + /// so this method won't return them before that + /// + public List GetTweens() + { + List result = new List(); + DOTweenAnimation[] anims = this.GetComponents(); + foreach (DOTweenAnimation anim in anims) { + if (anim.tween != null && anim.tween.active) result.Add(anim.tween); + } + return result; + } + + /// + /// Sets the animation target (which must be of the same type of the one set in the Inspector). + /// This is useful if you want to change it BEFORE this + /// creates a tween, while after that it won't have any effect. + /// Consider that a creates its tween inside its Awake (except for special tweens), + /// so you will need to sure your code runs before this object's Awake (via ScriptExecutionOrder or enabling/disabling methods) + /// + /// + /// New target for the animation (must be of the same type of the previous one) + /// If TRUE also uses tweenTarget's gameObject when settings the target-ID of the tween + /// (which is used with DOPlay/DORestart/etc to apply the same operation on all tweens that have the same target-id). + /// You should usually leave this to TRUE if you change the target. + /// + public void SetAnimationTarget(Component tweenTarget, bool useTweenTargetGameObjectForGroupOperations = true) + { + TargetType newTargetType = TypeToDOTargetType(target.GetType()); + if (newTargetType != targetType) { + Debug.LogError("DOTweenAnimation ► SetAnimationTarget: the new target is of a different type from the one set in the Inspector"); + return; + } + target = tweenTarget; + targetGO = target.gameObject; + tweenTargetIsTargetGO = useTweenTargetGameObjectForGroupOperations; + } + + #endregion + + /// + /// Plays all tweens whose target-id is the same as the one set by this animation + /// + public override void DOPlay() + { + DOTween.Play(GetTweenTarget()); + } + + /// + /// Plays backwards all tweens whose target-id is the same as the one set by this animation + /// + public override void DOPlayBackwards() + { + DOTween.PlayBackwards(GetTweenTarget()); + } + + /// + /// Plays foward all tweens whose target-id is the same as the one set by this animation + /// + public override void DOPlayForward() + { + DOTween.PlayForward(GetTweenTarget()); + } + + /// + /// Pauses all tweens whose target-id is the same as the one set by this animation + /// + public override void DOPause() + { + DOTween.Pause(GetTweenTarget()); + } + + /// + /// Pauses/unpauses (depending on the current state) all tweens whose target-id is the same as the one set by this animation + /// + public override void DOTogglePause() + { + DOTween.TogglePause(GetTweenTarget()); + } + + /// + /// Rewinds all tweens created by this animation in the correct order + /// + public override void DORewind() + { + _playCount = -1; + // Rewind using Components order (in case there are multiple animations on the same property) + DOTweenAnimation[] anims = this.gameObject.GetComponents(); + for (int i = anims.Length - 1; i > -1; --i) { + Tween t = anims[i].tween; + if (t != null && t.IsInitialized()) anims[i].tween.Rewind(); + } + // DOTween.Rewind(GetTweenTarget()); + } + + /// + /// Restarts all tweens whose target-id is the same as the one set by this animation + /// + public override void DORestart() + { DORestart(false); } + /// + /// Restarts all tweens whose target-id is the same as the one set by this animation + /// + /// If TRUE, re-evaluates the tween's start and end values from its current position. + /// Set it to TRUE when spawning the same DOTweenAnimation in different positions (like when using a pooling system) + public override void DORestart(bool fromHere) + { + _playCount = -1; + if (tween == null) { + if (Debugger.logPriority > 1) Debugger.LogNullTween(tween); return; + } + if (fromHere && isRelative) ReEvaluateRelativeTween(); + DOTween.Restart(GetTweenTarget()); + } + + /// + /// Completes all tweens whose target-id is the same as the one set by this animation + /// + public override void DOComplete() + { + DOTween.Complete(GetTweenTarget()); + } + + /// + /// Sends to the given time (and pauses) all the tweens whose target-id is the one set by this animation + /// + /// Time to send the tween to + public override void DOGotoAndPause(float time) + { DOGoto(time, false); } + /// + /// Sends to the given time (and plays) all the tweens whose target-id is the one set by this animation + /// + /// Time to send the tween to + public override void DOGotoAndPlay(float time) + { DOGoto(time, true); } + void DOGoto(float time, bool andPlay) + { + _tmpTweens.Clear(); + DOTween.TweensByTarget(GetTweenTarget(), false, _tmpTweens); + int len = _tmpTweens.Count; + if (len == 0) { + Debugger.LogWarning((andPlay ? "DOGotoAndPlay" : "DoGotoAndPause") + " ► tween doesn't exist"); + } else { + for (int i = 0; i < _tmpTweens.Count; ++i) { + _tmpTweens[i].Goto(time, andPlay); + } + } + _tmpTweens.Clear(); + } + + /// + /// Kills all tweens whose target-id is the same as the one set by this animation + /// + public override void DOKill() + { + DOTween.Kill(GetTweenTarget()); + tween = null; + } + + #region Specifics + + /// + /// Plays all tweens with the given ID and whose target-id is the same as the one set by this animation + /// + public void DOPlayById(string id) + { + DOTween.Play(GetTweenTarget(), id); + } + /// + /// Plays all tweens with the given ID (regardless of their target gameObject) + /// + public void DOPlayAllById(string id) + { + DOTween.Play(id); + } + + /// + /// Pauses all tweens that with the given ID (regardless of their target gameObject) + /// + public void DOPauseAllById(string id) + { + DOTween.Pause(id); + } + + /// + /// Plays backwards all tweens with the given ID and whose target-id is the same as the one set by this animation + /// + public void DOPlayBackwardsById(string id) + { + DOTween.PlayBackwards(GetTweenTarget(), id); + } + /// + /// Plays backwards all tweens with the given ID (regardless of their target gameObject) + /// + public void DOPlayBackwardsAllById(string id) + { + DOTween.PlayBackwards(id); + } + + /// + /// Plays forward all tweens with the given ID and whose target-id is the same as the one set by this animation + /// + public void DOPlayForwardById(string id) + { + DOTween.PlayForward(GetTweenTarget(), id); + } + /// + /// Plays forward all tweens with the given ID (regardless of their target gameObject) + /// + public void DOPlayForwardAllById(string id) + { + DOTween.PlayForward(id); + } + + /// + /// Plays the next animation on this animation's gameObject (if any) + /// + public void DOPlayNext() + { + DOTweenAnimation[] anims = this.GetComponents(); + while (_playCount < anims.Length - 1) { + _playCount++; + DOTweenAnimation anim = anims[_playCount]; + if (anim != null && anim.tween != null && anim.tween.active && !anim.tween.IsPlaying() && !anim.tween.IsComplete()) { + anim.tween.Play(); + break; + } + } + } + + /// + /// Rewinds all tweens with the given ID and whose target-id is the same as the one set by this animation, + /// then plays the next animation on this animation's gameObject (if any) + /// + public void DORewindAndPlayNext() + { + _playCount = -1; + DOTween.Rewind(GetTweenTarget()); + DOPlayNext(); + } + + /// + /// Rewinds all tweens with the given ID (regardless of their target gameObject) + /// + public void DORewindAllById(string id) + { + _playCount = -1; + DOTween.Rewind(id); + } + + /// + /// Restarts all tweens with the given ID and whose target-id is the same as the one set by this animation + /// + public void DORestartById(string id) + { + _playCount = -1; + DOTween.Restart(GetTweenTarget(), id); + } + /// + /// Restarts all tweens with the given ID (regardless of their target gameObject) + /// + public void DORestartAllById(string id) + { + _playCount = -1; + DOTween.Restart(id); + } + + /// + /// Kills all tweens with the given ID and whose target-id is the same as the one set by this animation + /// + public void DOKillById(string id) + { + DOTween.Kill(GetTweenTarget(), id); + } + /// + /// Kills all tweens with the given ID (regardless of their target gameObject) + /// + public void DOKillAllById(string id) + { + DOTween.Kill(id); + } + + #endregion + + #region Internal (also used by Inspector) + + public static TargetType TypeToDOTargetType(Type t) + { + string str = t.ToString(); + int dotIndex = str.LastIndexOf("."); + if (dotIndex != -1) str = str.Substring(dotIndex + 1); + if (str.IndexOf("Renderer") != -1 && (str != "SpriteRenderer")) str = "Renderer"; +//#if true // PHYSICS_MARKER +// if (str == "Rigidbody") str = "Transform"; +//#endif +//#if true // PHYSICS2D_MARKER +// if (str == "Rigidbody2D") str = "Transform"; +//#endif +#if true // UI_MARKER +// if (str == "RectTransform") str = "Transform"; + if (str == "RawImage" || str == "Graphic") str = "Image"; // RawImages/Graphics are managed like Images for DOTweenAnimation (color and fade use Graphic target anyway) +#endif + return (TargetType)Enum.Parse(typeof(TargetType), str); + } + + // Editor preview system + /// + /// Previews the tween in the editor. Only for DOTween internal usage: don't use otherwise. + /// + public Tween CreateEditorPreview() + { + if (Application.isPlaying) return null; + + // CHANGE: first param switched to TRUE otherwise changing an animation and replaying in editor would still play old one + CreateTween(true, autoPlay); + return tween; + } + + #endregion + + #endregion + + #region Private + + /// + /// Returns the gameObject whose target component should be animated + /// + /// + GameObject GetTweenGO() + { + return targetIsSelf ? this.gameObject : targetGO; + } + + /// + /// Returns the GameObject which should be used/retrieved for SetTarget + /// + GameObject GetTweenTarget() + { + return targetIsSelf || !tweenTargetIsTargetGO ? this.gameObject : targetGO; + } + + // Re-evaluate relative position of path + void ReEvaluateRelativeTween() + { + GameObject tweenGO = GetTweenGO(); + if (tweenGO == null) { + Debug.LogWarning(string.Format("{0} :: This DOTweenAnimation's target/GameObject is unset: the tween will not be created.", this.gameObject.name), this.gameObject); + return; + } + if (animationType == AnimationType.Move) { + ((Tweener)tween).ChangeEndValue(tweenGO.transform.position + endValueV3, true); + } else if (animationType == AnimationType.LocalMove) { + ((Tweener)tween).ChangeEndValue(tweenGO.transform.localPosition + endValueV3, true); + } + } + + #endregion + } + + public static class DOTweenAnimationExtensions + { +// // Doesn't work on Win 8.1 +// public static bool IsSameOrSubclassOf(this Type t, Type tBase) +// { +// return t.IsSubclassOf(tBase) || t == tBase; +// } + + public static bool IsSameOrSubclassOf(this Component t) + { + return t is T; + } + } +} diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs.meta new file mode 100644 index 0000000..a10ceea --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenAnimation.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d0390bd8b8ffd640b34fe25065ff1df +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs new file mode 100644 index 0000000..c9df396 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs @@ -0,0 +1,9 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2015/03/27 19:02 +// +// License Copyright (c) Daniele Giardini. +// This work is subject to the terms at http://dotween.demigiant.com/license.php + + +#if false // MODULE_MARKER +#endif diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs.meta new file mode 100644 index 0000000..32c1ec8 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeAudio.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 1d1aa01bacf85c04ea18116651a7f0db +timeCreated: 1587116610 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs new file mode 100644 index 0000000..c9df396 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs @@ -0,0 +1,9 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2015/03/27 19:02 +// +// License Copyright (c) Daniele Giardini. +// This work is subject to the terms at http://dotween.demigiant.com/license.php + + +#if false // MODULE_MARKER +#endif diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs.meta new file mode 100644 index 0000000..9cba4ea --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenDeUnityExtended.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 0a0cc3e90c4a6ea41bb14d7f35c577c3 +timeCreated: 1587116610 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef new file mode 100644 index 0000000..2f0fde6 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef @@ -0,0 +1,6 @@ +{ + "name": "DOTweenPro.Scripts", + "references": [ + "DOTween.Modules" + ] +} diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef.meta new file mode 100644 index 0000000..5aa5663 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.Scripts.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9067f8b15bd1b964e813a931b22d71ff +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML new file mode 100644 index 0000000..8179cfe --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML @@ -0,0 +1,80 @@ + + + + DOTweenPro + + + + + Restarts the tween + + + + + Restarts the tween + + If TRUE, re-evaluates the tween's start and end values from its current position. + Set it to TRUE when spawning the same DOTweenPath in different positions (like when using a pooling system) + + + + Attach this to a GameObject to create and assign a path to it + + + + Used internally by the editor + + + + Restarts the tween + + + + + Restarts the tween + + If TRUE, re-evaluates the tween's start and end values from its current position. + Set it to TRUE when spawning the same DOTweenPath in different positions (like when using a pooling system) + + + + Sends the tween to the given time then pauses it + + Time to send the tween to + + + + Sends the tween to the given time then plays it + + Time to send the tween to + + + + Kills all tweens (path/animations/etc.) with the given ID (regardless of their target gameObject) + + + + + Returns a list of points that are used to draw the path inside the editor, + or NULL if the path hasn't been initialized yet or if its tween has been killed + + + + + Tweens a Vector3 along a spiral. + EndValue represents the direction of the spiral + + + + + Spiral tween mode + + + + The spiral motion will expand outwards for the whole the tween + + + The spiral motion will expand outwards for half the tween and then will spiral back to the starting position + + + diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML.meta new file mode 100644 index 0000000..ddc78e5 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.XML.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: db7d7ef84c388bc4fbc3835d31a15306 +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll new file mode 100644 index 0000000000000000000000000000000000000000..fc08e610e3a3b44ae43656c03e645d831dcf39db GIT binary patch literal 16384 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 Zr93dqU+W;xkWZbzQX~8S!Tb+A@Zb2<1LFVy literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll.meta new file mode 100644 index 0000000..9ecbfd3 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: aa0b1eebb5db27a419fa4564bbe5c9c5 +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs new file mode 100644 index 0000000..12ee7ef --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs @@ -0,0 +1,90 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2018/07/13 + +using System; +using DG.Tweening.Core; +using DG.Tweening.Plugins; +using UnityEngine; + +#pragma warning disable 1591 +namespace DG.Tweening +{ + public static class DOTweenProShortcuts + { + static DOTweenProShortcuts() + { + // Create stub instances of custom plugins, in order to allow IL2CPP to understand they must be included in the build +#pragma warning disable 219 + SpiralPlugin stub = new SpiralPlugin(); +#pragma warning restore 219 + } + + #region Shortcuts + + #region Transform + + /// Tweens a Transform's localPosition in a spiral shape. + /// Also stores the transform as the tween's target so it can be used for filtered operations + /// The duration of the tween + /// The axis around which the spiral will rotate + /// The type of spiral movement + /// Speed of the rotations + /// Frequency of the rotation. Lower values lead to wider spirals + /// Indicates how much the tween should move along the spiral's axis + /// If TRUE the tween will smoothly snap all values to integers + public static Tweener DOSpiral( + this Transform target, float duration, Vector3? axis = null, SpiralMode mode = SpiralMode.Expand, + float speed = 1, float frequency = 10, float depth = 0, bool snapping = false + ) { + if (Mathf.Approximately(speed, 0)) speed = 1; + if (axis == null || axis == Vector3.zero) axis = Vector3.forward; + + TweenerCore t = DOTween.To(SpiralPlugin.Get(), () => target.localPosition, x => target.localPosition = x, (Vector3)axis, duration) + .SetTarget(target); + + t.plugOptions.mode = mode; + t.plugOptions.speed = speed; + t.plugOptions.frequency = frequency; + t.plugOptions.depth = depth; + t.plugOptions.snapping = snapping; + return t; + } + + #endregion + +#if true // PHYSICS_MARKER + #region Rigidbody + + /// Tweens a Rigidbody's position in a spiral shape. + /// Also stores the transform as the tween's target so it can be used for filtered operations + /// The duration of the tween + /// The axis around which the spiral will rotate + /// The type of spiral movement + /// Speed of the rotations + /// Frequency of the rotation. Lower values lead to wider spirals + /// Indicates how much the tween should move along the spiral's axis + /// If TRUE the tween will smoothly snap all values to integers + public static Tweener DOSpiral( + this Rigidbody target, float duration, Vector3? axis = null, SpiralMode mode = SpiralMode.Expand, + float speed = 1, float frequency = 10, float depth = 0, bool snapping = false + ) { + if (Mathf.Approximately(speed, 0)) speed = 1; + if (axis == null || axis == Vector3.zero) axis = Vector3.forward; + + TweenerCore t = DOTween.To(SpiralPlugin.Get(), () => target.position, target.MovePosition, (Vector3)axis, duration) + .SetTarget(target); + + t.plugOptions.mode = mode; + t.plugOptions.speed = speed; + t.plugOptions.frequency = frequency; + t.plugOptions.depth = depth; + t.plugOptions.snapping = snapping; + return t; + } + + #endregion +#endif + + #endregion + } +} diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs.meta new file mode 100644 index 0000000..bc6e863 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenProShortcuts.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1c3190a1a1c53f449926f6d5542b4ce5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs new file mode 100644 index 0000000..935bbee --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs @@ -0,0 +1,1037 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2015/03/27 19:02 +// +// License Copyright (c) Daniele Giardini. +// This work is subject to the terms at http://dotween.demigiant.com/license.php + + +#if false // MODULE_MARKER +using System; +using System.Globalization; +using System.Collections.Generic; +using DG.Tweening.Core; +using DG.Tweening.Plugins.Options; +using UnityEngine; +using TMPro; +using Object = UnityEngine.Object; + +namespace DG.Tweening +{ + public enum TMPSkewSpanMode + { + /// Applies the skew as-is (like normal skew works): the longer the text-span the higher the last character will be + Default, + /// Applies the skew scaled by the size of the text-span: the max skew/displacement will be the given skew factor + AsMaxSkewFactor + } + + /// + /// Methods that extend TMP_Text objects and allow to directly create and control tweens from their instances. + /// + public static class ShortcutExtensionsTMPText + { + #region Colors + + /// Tweens a TextMeshPro's color to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this TMP_Text target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's faceColor to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFaceColor(this TMP_Text target, Color32 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.faceColor, x => target.faceColor = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's outlineColor to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOOutlineColor(this TMP_Text target, Color32 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.outlineColor, x => target.outlineColor = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's glow color to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + /// If TRUE will use the fontSharedMaterial instead than the fontMaterial + public static TweenerCore DOGlowColor(this TMP_Text target, Color endValue, float duration, bool useSharedMaterial = false) + { + TweenerCore t = useSharedMaterial + ? target.fontSharedMaterial.DOColor(endValue, "_GlowColor", duration) + : target.fontMaterial.DOColor(endValue, "_GlowColor", duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's alpha color to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this TMP_Text target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro faceColor's alpha to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFaceFade(this TMP_Text target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.faceColor, x => target.faceColor = x, endValue, duration); + t.SetTarget(target); + return t; + } + + #endregion + + #region Other + + /// Tweens a TextMeshPro's scale to the given value (using correct uniform scale as TMP requires). + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScale(this TMP_Text target, float endValue, float duration) + { + Transform trans = target.transform; + Vector3 endValueV3 = new Vector3(endValue, endValue, endValue); + TweenerCore t = DOTween.To(() => trans.localScale, x => trans.localScale = x, endValueV3, duration); + t.SetTarget(target); + return t; + } + + /// + /// Tweens a TextMeshPro's text from one integer to another, with options for thousands separators + /// + /// The value to start from + /// The end value to reach + /// The duration of the tween + /// If TRUE (default) also adds thousands separators + /// The to use (InvariantCulture if NULL) + public static TweenerCore DOCounter( + this TMP_Text target, int fromValue, int endValue, float duration, bool addThousandsSeparator = true, CultureInfo culture = null + ){ + int v = fromValue; + CultureInfo cInfo = !addThousandsSeparator ? null : culture ?? CultureInfo.InvariantCulture; + TweenerCore t = DOTween.To(() => v, x => { + v = x; + target.text = addThousandsSeparator + ? v.ToString("N0", cInfo) + : v.ToString(); + }, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's fontSize to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFontSize(this TMP_Text target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.fontSize, x => target.fontSize = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's maxVisibleCharacters to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOMaxVisibleCharacters(this TMP_Text target, int endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.maxVisibleCharacters, x => target.maxVisibleCharacters = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a TextMeshPro's text to the given value. + /// Also stores the TextMeshPro as the tween's target so it can be used for filtered operations + /// The end string to tween toThe duration of the tween + /// If TRUE (default), rich text will be interpreted correctly while animated, + /// otherwise all tags will be considered as normal text + /// The type of scramble mode to use, if any + /// A string containing the characters to use for scrambling. + /// Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters. + /// Leave it to NULL (default) to use default ones + public static TweenerCore DOText(this TMP_Text target, string endValue, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null) + { + TweenerCore t = DOTween.To(() => target.text, x => target.text = x, endValue, duration); + t.SetOptions(richTextEnabled, scrambleMode, scrambleChars) + .SetTarget(target); + return t; + } + + #endregion + } + + #region DOTweenTMPAnimator + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + // ███ CLASS ███████████████████████████████████████████████████████████████████████████████████████████████████████████ + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + + /// + /// Wrapper for objects that enables per-character tweening + /// (you don't need this if instead you want to animate the whole text object). + /// It also contains various handy methods to simply deform text without animating it ;) + /// EXAMPLE: + /// DOTweenTMPAnimator animator = new DOTweenTMPAnimator(myTextMeshProTextField); + /// Tween tween = animator.DOCharScale(characterIndex, scaleValue, duration); + /// + /// + public class DOTweenTMPAnimator : IDisposable + { + static readonly Dictionary _targetToAnimator = new Dictionary(); + + /// that this animator is linked to + public TMP_Text target { get; private set; } + public TMP_TextInfo textInfo { get; private set; } + readonly List _charTransforms = new List(); + TMP_MeshInfo[] _cachedMeshInfos; + bool _ignoreTextChangedEvent; + + /// + /// Creates a new instance of the , which is necessary to animate by single characters. + /// If a already exists for the same object it will be disposed + /// (but not its tweens, those you will have to kill manually). + /// If you want to animate the whole text object you don't need this, and you can use direct DO shortcuts instead. + /// IMPORTANT: the target must have been enabled/activated at least once before you can use it with this + /// + /// The that will be linked to this animator + public DOTweenTMPAnimator(TMP_Text target) + { + if (target == null) { + Debugger.LogError("DOTweenTMPAnimator target can't be null"); + return; + } + if (!target.gameObject.activeInHierarchy) { + Debugger.LogError("You can't create a DOTweenTMPAnimator if its target is disabled"); + return; + } + // Verify that there's no other animators for the same target, and in case dispose them + if (_targetToAnimator.ContainsKey(target)) { + if (Debugger.logPriority >= 2) { + Debugger.Log(string.Format( + "A DOTweenTMPAnimator for \"{0}\" already exists: disposing it because you can't have more than one DOTweenTMPAnimator" + + " for the same TextMesh Pro object. If you have tweens running on the disposed DOTweenTMPAnimator you should kill them manually", + target + )); + } + _targetToAnimator[target].Dispose(); + _targetToAnimator.Remove(target); + } + // + this.target = target; + _targetToAnimator.Add(target, this); + Refresh(); + // Listeners + TMPro_EventManager.TEXT_CHANGED_EVENT.Add(OnTextChanged); + } + + /// + /// If a instance exists for the given target disposes it + /// + public static void DisposeInstanceFor(TMP_Text target) + { + if (!_targetToAnimator.ContainsKey(target)) return; + _targetToAnimator[target].Dispose(); + _targetToAnimator.Remove(target); + } + + /// + /// Clears and disposes of this object + /// + public void Dispose() + { + target = null; + _charTransforms.Clear(); + textInfo = null; + _cachedMeshInfos = null; + TMPro_EventManager.TEXT_CHANGED_EVENT.Remove(OnTextChanged); + } + + /// + /// Refreshes the animator text data and resets all transformation data. Call this after you change the target + /// + public void Refresh() + { + _ignoreTextChangedEvent = true; + target.ForceMeshUpdate(true); + textInfo = target.textInfo; + _cachedMeshInfos = textInfo.CopyMeshInfoVertexData(); + int totChars = textInfo.characterCount; + int totCurrent = _charTransforms.Count; + if (totCurrent > totChars) { + _charTransforms.RemoveRange(totChars, totCurrent - totChars); + totCurrent = totChars; + } + for (int i = 0; i < totCurrent; ++i) { + CharTransform c = _charTransforms[i]; + c.ResetTransformationData(); + c.Refresh(textInfo, _cachedMeshInfos); + _charTransforms[i] = c; + } + for (int i = totCurrent; i < totChars; ++i) _charTransforms.Add(new CharTransform(i, textInfo, _cachedMeshInfos)); + _ignoreTextChangedEvent = false; + } + + /// + /// Resets all deformations + /// + public void Reset() + { + int totCurrent = _charTransforms.Count; + for (int i = 0; i < totCurrent; ++i) _charTransforms[i].ResetAll(target, textInfo.meshInfo, _cachedMeshInfos); + } + + void OnTextChanged(Object obj) + { + if (_ignoreTextChangedEvent || target == null || obj != target) return; + Refresh(); + } + + bool ValidateChar(int charIndex, bool isTween = true) + { + if (textInfo.characterCount <= charIndex) { + Debugger.LogError(string.Format("CharIndex {0} doesn't exist", charIndex)); + return false; + } + if (!textInfo.characterInfo[charIndex].isVisible) { + if (Debugger.logPriority > 1) { + if (isTween) { + Debugger.Log(string.Format( + "CharIndex {0} isn't visible, ignoring it and returning an empty tween (TextMesh Pro will behave weirdly if invisible chars are included in the animation)", + charIndex + )); + } else { + Debugger.Log(string.Format("CharIndex {0} isn't visible, ignoring it", charIndex)); + } + } + return false; + } + return true; + } + + bool ValidateSpan(int fromCharIndex, int toCharIndex, out int firstVisibleCharIndex, out int lastVisibleCharIndex) + { + firstVisibleCharIndex = -1; // First visible/existing charIndex from given index + lastVisibleCharIndex = -1; // Last visible/existing charIndex backwards from given index + int charCount = textInfo.characterCount; + if (fromCharIndex >= charCount) return false; + if (toCharIndex >= charCount) toCharIndex = charCount - 1; + for (int i = fromCharIndex; i < toCharIndex + 1; ++i) { + if (!_charTransforms[i].isVisible) continue; + firstVisibleCharIndex = i; + break; + } + if (firstVisibleCharIndex == -1) return false; + for (int i = toCharIndex; i > firstVisibleCharIndex - 1; --i) { + if (!_charTransforms[i].isVisible) continue; + lastVisibleCharIndex = i; + break; + } + if (lastVisibleCharIndex == -1) return false; + return true; + } + + #region Word Setters + + /// + /// Skews a span of characters uniformly (like normal skew works in graphic applications) + /// + /// First char index of the span to skew + /// Last char index of the span to skew + /// Skew factor + /// If TRUE skews the top side of the span, otherwise the bottom one + public void SkewSpanX(int fromCharIndex, int toCharIndex, float skewFactor, bool skewTop = true) + { + int firstVisibleCharIndex, lastVisibleCharIndex; + if (!ValidateSpan(fromCharIndex, toCharIndex, out firstVisibleCharIndex, out lastVisibleCharIndex)) return; + for (int i = firstVisibleCharIndex; i < lastVisibleCharIndex + 1; ++i) { + if (!_charTransforms[i].isVisible) continue; + CharVertices v = _charTransforms[i].GetVertices(); + float skew = SkewCharX(i, skewFactor, skewTop); + } + } + + /// + /// Skews a span of characters uniformly (like normal skew works in graphic applications) + /// + /// First char index of the span to skew + /// Last char index of the span to skew + /// Skew factor + /// Skew mode + /// If TRUE skews the right side of the span, otherwise the left one + public void SkewSpanY( + int fromCharIndex, int toCharIndex, float skewFactor, + TMPSkewSpanMode mode = TMPSkewSpanMode.Default, bool skewRight = true + ){ + int firstVisibleCharIndex, lastVisibleCharIndex; + if (!ValidateSpan(fromCharIndex, toCharIndex, out firstVisibleCharIndex, out lastVisibleCharIndex)) return; + if (mode == TMPSkewSpanMode.AsMaxSkewFactor) { + CharVertices firstVisibleCharVertices = _charTransforms[firstVisibleCharIndex].GetVertices(); + CharVertices lastVisibleCharVertices = _charTransforms[lastVisibleCharIndex].GetVertices(); + float spanW = Mathf.Abs(lastVisibleCharVertices.bottomRight.x - firstVisibleCharVertices.bottomLeft.x); + float spanH = Mathf.Abs(lastVisibleCharVertices.topRight.y - lastVisibleCharVertices.bottomRight.y); + float ratio = spanH / spanW; + skewFactor *= ratio; + } + float offsetY = 0; + CharVertices prevCharVertices = new CharVertices(); + float prevCharSkew = 0; + if (skewRight) { + for (int i = firstVisibleCharIndex; i < lastVisibleCharIndex + 1; ++i) { + if (!_charTransforms[i].isVisible) continue; + CharVertices v = _charTransforms[i].GetVertices(); + float skew = SkewCharY(i, skewFactor, skewRight); + if (i > firstVisibleCharIndex) { + float prevCharW = Mathf.Abs(prevCharVertices.bottomLeft.x - prevCharVertices.bottomRight.x); + float charsDist = Mathf.Abs(v.bottomLeft.x - prevCharVertices.bottomRight.x); + offsetY += prevCharSkew + (prevCharSkew * charsDist) / prevCharW; + SetCharOffset(i, new Vector3(0, _charTransforms[i].offset.y + offsetY, 0)); + } + prevCharVertices = v; + prevCharSkew = skew; + } + } else { + for (int i = lastVisibleCharIndex; i > firstVisibleCharIndex - 1; --i) { + if (!_charTransforms[i].isVisible) continue; + CharVertices v = _charTransforms[i].GetVertices(); + float skew = SkewCharY(i, skewFactor, skewRight); + if (i < lastVisibleCharIndex) { + float prevCharW = Mathf.Abs(prevCharVertices.bottomLeft.x - prevCharVertices.bottomRight.x); + float charsDist = Mathf.Abs(v.bottomRight.x - prevCharVertices.bottomLeft.x); + offsetY += prevCharSkew + (prevCharSkew * charsDist) / prevCharW; + SetCharOffset(i, new Vector3(0, _charTransforms[i].offset.y + offsetY, 0)); + } + prevCharVertices = v; + prevCharSkew = skew; + } + } + } + + #endregion + + #region Char Getters + + /// + /// Returns the current color of the given character, if it exists and is visible. + /// + /// Character index + public Color GetCharColor(int charIndex) + { + if (!ValidateChar(charIndex)) return Color.white; + return _charTransforms[charIndex].GetColor(textInfo.meshInfo); + } + + /// + /// Returns the current offset of the given character, if it exists and is visible. + /// + /// Character index + public Vector3 GetCharOffset(int charIndex) + { + if (!ValidateChar(charIndex)) return Vector3.zero; + return _charTransforms[charIndex].offset; + } + + /// + /// Returns the current rotation of the given character, if it exists and is visible. + /// + /// Character index + public Vector3 GetCharRotation(int charIndex) + { + if (!ValidateChar(charIndex)) return Vector3.zero; + return _charTransforms[charIndex].rotation.eulerAngles; + } + + /// + /// Returns the current scale of the given character, if it exists and is visible. + /// + /// Character index + public Vector3 GetCharScale(int charIndex) + { + if (!ValidateChar(charIndex)) return Vector3.zero; + return _charTransforms[charIndex].scale; + } + + #endregion + + #region Char Setters + + /// + /// Immediately sets the color of the given character. + /// Will do nothing if the is invalid or the character isn't visible + /// + /// Character index + /// Color to set + public void SetCharColor(int charIndex, Color32 color) + { + if (!ValidateChar(charIndex)) return; + CharTransform c = _charTransforms[charIndex]; + c.UpdateColor(target, color, textInfo.meshInfo); + _charTransforms[charIndex] = c; + } + + /// + /// Immediately sets the offset of the given character. + /// Will do nothing if the is invalid or the character isn't visible + /// + /// Character index + /// Offset to set + public void SetCharOffset(int charIndex, Vector3 offset) + { + if (!ValidateChar(charIndex)) return; + CharTransform c = _charTransforms[charIndex]; + c.UpdateGeometry(target, offset, c.rotation, c.scale, _cachedMeshInfos); + _charTransforms[charIndex] = c; + } + + /// + /// Immediately sets the rotation of the given character. + /// Will do nothing if the is invalid or the character isn't visible + /// + /// Character index + /// Rotation to set + public void SetCharRotation(int charIndex, Vector3 rotation) + { + if (!ValidateChar(charIndex)) return; + CharTransform c = _charTransforms[charIndex]; + c.UpdateGeometry(target, c.offset, Quaternion.Euler(rotation), c.scale, _cachedMeshInfos); + _charTransforms[charIndex] = c; + } + + /// + /// Immediately sets the scale of the given character. + /// Will do nothing if the is invalid or the character isn't visible + /// + /// Character index + /// Scale to set + public void SetCharScale(int charIndex, Vector3 scale) + { + if (!ValidateChar(charIndex)) return; + CharTransform c = _charTransforms[charIndex]; + c.UpdateGeometry(target, c.offset, c.rotation, scale, _cachedMeshInfos); + _charTransforms[charIndex] = c; + } + + /// + /// Immediately shifts the vertices of the given character by the given factor. + /// Will do nothing if the is invalid or the character isn't visible + /// + /// Character index + /// Top left offset + /// Top right offset + /// Bottom left offset + /// Bottom right offset + public void ShiftCharVertices(int charIndex, Vector3 topLeftShift, Vector3 topRightShift, Vector3 bottomLeftShift, Vector3 bottomRightShift) + { + if (!ValidateChar(charIndex)) return; + CharTransform c = _charTransforms[charIndex]; + c.ShiftVertices(target, topLeftShift, topRightShift, bottomLeftShift, bottomRightShift); + _charTransforms[charIndex] = c; + } + + /// + /// Skews the given character horizontally along the X axis and returns the skew amount applied (based on the character's size) + /// + /// Character index + /// skew amount + /// If TRUE skews the top side of the character, otherwise the bottom one + public float SkewCharX(int charIndex, float skewFactor, bool skewTop = true) + { + if (!ValidateChar(charIndex)) return 0; + Vector3 skewV = new Vector3(skewFactor, 0, 0); + CharTransform c = _charTransforms[charIndex]; + if (skewTop) c.ShiftVertices(target, skewV, skewV, Vector3.zero, Vector3.zero); + else c.ShiftVertices(target, Vector3.zero, Vector3.zero, skewV, skewV); + _charTransforms[charIndex] = c; + return skewFactor; + } + + /// + /// Skews the given character vertically along the Y axis and returns the skew amount applied (based on the character's size) + /// + /// Character index + /// skew amount + /// If TRUE skews the right side of the character, otherwise the left one + /// If TRUE applies exactly the given , + /// otherwise modifies it based on the aspectRation of the character + public float SkewCharY(int charIndex, float skewFactor, bool skewRight = true, bool fixedSkew = false) + { + if (!ValidateChar(charIndex)) return 0; + float skew = fixedSkew ? skewFactor : skewFactor * textInfo.characterInfo[charIndex].aspectRatio; + Vector3 skewV = new Vector3(0, skew, 0); + CharTransform c = _charTransforms[charIndex]; + if (skewRight) c.ShiftVertices(target, Vector3.zero, skewV, Vector3.zero, skewV); + else c.ShiftVertices(target, skewV, Vector3.zero, skewV, Vector3.zero); + _charTransforms[charIndex] = c; + return skew; + } + + /// + /// Resets the eventual vertices shift applied to the given character via . + /// Will do nothing if the is invalid or the character isn't visible + /// + /// Character index + public void ResetVerticesShift(int charIndex) + { + if (!ValidateChar(charIndex)) return; + CharTransform c = _charTransforms[charIndex]; + c.ResetVerticesShift(target); + _charTransforms[charIndex] = c; + } + + #endregion + + #region Char Tweens + + /// Tweens a character's alpha to the given value and returns the . + /// Will return NULL if the is invalid or the character isn't visible. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The end value to reachThe duration of the tween + public TweenerCore DOFadeChar(int charIndex, float endValue, float duration) + { + if (!ValidateChar(charIndex)) return null; + TweenerCore t = DOTween.ToAlpha(() => _charTransforms[charIndex].GetColor(textInfo.meshInfo), x => { + _charTransforms[charIndex].UpdateAlpha(target, x, textInfo.meshInfo); + }, endValue, duration); + return t; + } + + /// Tweens a character's color to the given value and returns the . + /// Will return NULL if the is invalid or the character isn't visible. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The end value to reachThe duration of the tween + public TweenerCore DOColorChar(int charIndex, Color endValue, float duration) + { + if (!ValidateChar(charIndex)) return null; + TweenerCore t = DOTween.To(() => _charTransforms[charIndex].GetColor(textInfo.meshInfo), x => { + _charTransforms[charIndex].UpdateColor(target, x, textInfo.meshInfo); + }, endValue, duration); + return t; + } + + /// Tweens a character's offset to the given value and returns the . + /// Will return NULL if the is invalid or the character isn't visible. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The end value to reachThe duration of the tween + public TweenerCore DOOffsetChar(int charIndex, Vector3 endValue, float duration) + { + if (!ValidateChar(charIndex)) return null; + TweenerCore t = DOTween.To(() => _charTransforms[charIndex].offset, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, x, charT.rotation, charT.scale, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, endValue, duration); + return t; + } + + /// Tweens a character's rotation to the given value and returns the . + /// Will return NULL if the is invalid or the character isn't visible. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The end value to reachThe duration of the tween + /// Rotation mode + public TweenerCore DORotateChar(int charIndex, Vector3 endValue, float duration, RotateMode mode = RotateMode.Fast) + { + if (!ValidateChar(charIndex)) return null; + TweenerCore t = DOTween.To(() => _charTransforms[charIndex].rotation, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, charT.offset, x, charT.scale, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, endValue, duration); + t.plugOptions.rotateMode = mode; + return t; + } + + /// Tweens a character's scale to the given value and returns the . + /// Will return NULL if the is invalid or the character isn't visible. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The end value to reachThe duration of the tween + public TweenerCore DOScaleChar(int charIndex, float endValue, float duration) + { + return DOScaleChar(charIndex, new Vector3(endValue, endValue, endValue), duration); + } + /// Tweens a character's color to the given value and returns the . + /// Will return NULL if the is invalid or the character isn't visible. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The end value to reachThe duration of the tween + public TweenerCore DOScaleChar(int charIndex, Vector3 endValue, float duration) + { + if (!ValidateChar(charIndex)) return null; + TweenerCore t = DOTween.To(() => _charTransforms[charIndex].scale, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, charT.offset, charT.rotation, x, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, endValue, duration); + return t; + } + + /// Punches a character's offset towards the given direction and then back to the starting one + /// as if it was connected to the starting position via an elastic. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The punch strength + /// The duration of the tween + /// Indicates how much will the punch vibrate per second + /// Represents how much (0 to 1) the vector will go beyond the starting size when bouncing backwards. + /// 1 creates a full oscillation between the punch offset and the opposite offset, + /// while 0 oscillates only between the punch offset and the start offset + public Tweener DOPunchCharOffset(int charIndex, Vector3 punch, float duration, int vibrato = 10, float elasticity = 1) + { + if (!ValidateChar(charIndex)) return null; + if (duration <= 0) { + if (Debugger.logPriority > 0) Debug.LogWarning("Duration can't be 0, returning NULL without creating a tween"); + return null; + } + return DOTween.Punch(() => _charTransforms[charIndex].offset, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, x, charT.rotation, charT.scale, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, punch, duration, vibrato, elasticity); + } + + /// Punches a character's rotation towards the given direction and then back to the starting one + /// as if it was connected to the starting position via an elastic. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The punch strength + /// The duration of the tween + /// Indicates how much will the punch vibrate per second + /// Represents how much (0 to 1) the vector will go beyond the starting size when bouncing backwards. + /// 1 creates a full oscillation between the punch rotation and the opposite rotation, + /// while 0 oscillates only between the punch rotation and the start rotation + public Tweener DOPunchCharRotation(int charIndex, Vector3 punch, float duration, int vibrato = 10, float elasticity = 1) + { + if (!ValidateChar(charIndex)) return null; + if (duration <= 0) { + if (Debugger.logPriority > 0) Debug.LogWarning("Duration can't be 0, returning NULL without creating a tween"); + return null; + } + return DOTween.Punch(() => _charTransforms[charIndex].rotation.eulerAngles, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, charT.offset, Quaternion.Euler(x), charT.scale, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, punch, duration, vibrato, elasticity); + } + + /// Punches a character's scale towards the given direction and then back to the starting one + /// as if it was connected to the starting position via an elastic. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The punch strength (added to the character's current scale) + /// The duration of the tween + /// Indicates how much will the punch vibrate per second + /// Represents how much (0 to 1) the vector will go beyond the starting size when bouncing backwards. + /// 1 creates a full oscillation between the punch scale and the opposite scale, + /// while 0 oscillates only between the punch scale and the start scale + public Tweener DOPunchCharScale(int charIndex, float punch, float duration, int vibrato = 10, float elasticity = 1) + { + return DOPunchCharScale(charIndex, new Vector3(punch, punch, punch), duration, vibrato, elasticity); + } + /// Punches a character's scale towards the given direction and then back to the starting one + /// as if it was connected to the starting position via an elastic. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The punch strength (added to the character's current scale) + /// The duration of the tween + /// Indicates how much will the punch vibrate per second + /// Represents how much (0 to 1) the vector will go beyond the starting size when bouncing backwards. + /// 1 creates a full oscillation between the punch scale and the opposite scale, + /// while 0 oscillates only between the punch scale and the start scale + public Tweener DOPunchCharScale(int charIndex, Vector3 punch, float duration, int vibrato = 10, float elasticity = 1) + { + if (!ValidateChar(charIndex)) return null; + if (duration <= 0) { + if (Debugger.logPriority > 0) Debug.LogWarning("Duration can't be 0, returning NULL without creating a tween"); + return null; + } + return DOTween.Punch(() => _charTransforms[charIndex].scale, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, charT.offset, charT.rotation, x, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, punch, duration, vibrato, elasticity); + } + + /// Shakes a character's offset with the given values. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The duration of the tween + /// The shake strength + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + public Tweener DOShakeCharOffset(int charIndex, float duration, float strength, int vibrato = 10, float randomness = 90, bool fadeOut = true) + { + return DOShakeCharOffset(charIndex, duration, new Vector3(strength, strength, strength), vibrato, randomness, fadeOut); + } + /// Shakes a character's offset with the given values. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The duration of the tween + /// The shake strength + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + public Tweener DOShakeCharOffset(int charIndex, float duration, Vector3 strength, int vibrato = 10, float randomness = 90, bool fadeOut = true) + { + if (!ValidateChar(charIndex)) return null; + if (duration <= 0) { + if (Debugger.logPriority > 0) Debug.LogWarning("Duration can't be 0, returning NULL without creating a tween"); + return null; + } + return DOTween.Shake(() => _charTransforms[charIndex].offset, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, x, charT.rotation, charT.scale, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, duration, strength, vibrato, randomness, fadeOut); + } + + /// Shakes a character's rotation with the given values. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The duration of the tween + /// The shake strength + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + public Tweener DOShakeCharRotation(int charIndex, float duration, Vector3 strength, int vibrato = 10, float randomness = 90, bool fadeOut = true) + { + if (!ValidateChar(charIndex)) return null; + if (duration <= 0) { + if (Debugger.logPriority > 0) Debug.LogWarning("Duration can't be 0, returning NULL without creating a tween"); + return null; + } + return DOTween.Shake(() => _charTransforms[charIndex].rotation.eulerAngles, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, charT.offset, Quaternion.Euler(x), charT.scale, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, duration, strength, vibrato, randomness, fadeOut); + } + + /// Shakes a character's scale with the given values. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The duration of the tween + /// The shake strength + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + public Tweener DOShakeCharScale(int charIndex, float duration, float strength, int vibrato = 10, float randomness = 90, bool fadeOut = true) + { + return DOShakeCharScale(charIndex, duration, new Vector3(strength, strength, strength), vibrato, randomness, fadeOut); + } + /// Shakes a character's scale with the given values. + /// The index of the character to tween (will throw an error if it doesn't exist) + /// The duration of the tween + /// The shake strength + /// Indicates how much will the shake vibrate + /// Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + /// Setting it to 0 will shake along a single direction. + /// If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + public Tweener DOShakeCharScale(int charIndex, float duration, Vector3 strength, int vibrato = 10, float randomness = 90, bool fadeOut = true) + { + if (!ValidateChar(charIndex)) return null; + if (duration <= 0) { + if (Debugger.logPriority > 0) Debug.LogWarning("Duration can't be 0, returning NULL without creating a tween"); + return null; + } + return DOTween.Shake(() => _charTransforms[charIndex].scale, x => { + CharTransform charT = _charTransforms[charIndex]; + charT.UpdateGeometry(target, charT.offset, charT.rotation, x, _cachedMeshInfos); + _charTransforms[charIndex] = charT; + }, duration, strength, vibrato, randomness, fadeOut); + } + + #endregion + + // ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████ + + struct CharVertices + { + public Vector3 bottomLeft, topLeft, topRight, bottomRight; + + public CharVertices(Vector3 bottomLeft, Vector3 topLeft, Vector3 topRight, Vector3 bottomRight) + { + this.bottomLeft = bottomLeft; + this.topLeft = topLeft; + this.topRight = topRight; + this.bottomRight = bottomRight; + } + } + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + + // Vertices of each character are: + // 0 : bottom left, 1 : top left, 2 : top right, 3 : bottom right + struct CharTransform + { + public int charIndex; + public bool isVisible { get; private set; } // FALSE both if it's invisible or if it's a space + public Vector3 offset; + public Quaternion rotation; + public Vector3 scale; + Vector3 _topLeftShift, _topRightShift, _bottomLeftShift, _bottomRightShift; + Vector3 _charMidBaselineOffset; + int _matIndex, _firstVertexIndex; + TMP_MeshInfo _meshInfo; + + public CharTransform(int charIndex, TMP_TextInfo textInfo, TMP_MeshInfo[] cachedMeshInfos) : this() + { + this.charIndex = charIndex; + offset = Vector3.zero; + rotation = Quaternion.identity; + scale = Vector3.one; + Refresh(textInfo, cachedMeshInfos); + } + + public void Refresh(TMP_TextInfo textInfo, TMP_MeshInfo[] cachedMeshInfos) + { + TMP_CharacterInfo charInfo = textInfo.characterInfo[charIndex]; + bool isSpaceChar = charInfo.character == ' '; + isVisible = charInfo.isVisible && !isSpaceChar; + _matIndex = charInfo.materialReferenceIndex; + _firstVertexIndex = charInfo.vertexIndex; + _meshInfo = textInfo.meshInfo[_matIndex]; + Vector3[] cachedVertices = cachedMeshInfos[_matIndex].vertices; + _charMidBaselineOffset = isSpaceChar + ? Vector3.zero + : (cachedVertices[_firstVertexIndex] + cachedVertices[_firstVertexIndex + 2]) * 0.5f; + } + + public void ResetAll(TMP_Text target, TMP_MeshInfo[] meshInfos, TMP_MeshInfo[] cachedMeshInfos) + { + ResetGeometry(target, cachedMeshInfos); + ResetColors(target, meshInfos); + } + + public void ResetTransformationData() + { + offset = Vector3.zero; + rotation = Quaternion.identity; + scale = Vector3.one; + _topLeftShift = _topRightShift = _bottomLeftShift = _bottomRightShift = Vector3.zero; + } + + public void ResetGeometry(TMP_Text target, TMP_MeshInfo[] cachedMeshInfos) + { + ResetTransformationData(); + Vector3[] destinationVertices = _meshInfo.vertices; + Vector3[] cachedVertices = cachedMeshInfos[_matIndex].vertices; + destinationVertices[_firstVertexIndex + 0] = cachedVertices[_firstVertexIndex + 0]; + destinationVertices[_firstVertexIndex + 1] = cachedVertices[_firstVertexIndex + 1]; + destinationVertices[_firstVertexIndex + 2] = cachedVertices[_firstVertexIndex + 2]; + destinationVertices[_firstVertexIndex + 3] = cachedVertices[_firstVertexIndex + 3]; + _meshInfo.mesh.vertices = _meshInfo.vertices; + target.UpdateGeometry(_meshInfo.mesh, _matIndex); + } + + public void ResetColors(TMP_Text target, TMP_MeshInfo[] meshInfos) + { + Color color = target.color; + Color32[] vertexCols = meshInfos[_matIndex].colors32; + vertexCols[_firstVertexIndex] = color; + vertexCols[_firstVertexIndex + 1] = color; + vertexCols[_firstVertexIndex + 2] = color; + vertexCols[_firstVertexIndex + 3] = color; + target.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); + } + + public Color32 GetColor(TMP_MeshInfo[] meshInfos) + { + return meshInfos[_matIndex].colors32[_firstVertexIndex]; + } + + public CharVertices GetVertices() + { + return new CharVertices( + _meshInfo.vertices[_firstVertexIndex], _meshInfo.vertices[_firstVertexIndex + 1], + _meshInfo.vertices[_firstVertexIndex + 2], _meshInfo.vertices[_firstVertexIndex + 3] + ); + } + + public void UpdateAlpha(TMP_Text target, Color alphaColor, TMP_MeshInfo[] meshInfos, bool apply = true) + { + byte alphaByte = (byte)(alphaColor.a * 255); + Color32[] vertexCols = meshInfos[_matIndex].colors32; + vertexCols[_firstVertexIndex].a = alphaByte; + vertexCols[_firstVertexIndex + 1].a = alphaByte; + vertexCols[_firstVertexIndex + 2].a = alphaByte; + vertexCols[_firstVertexIndex + 3].a = alphaByte; + if (apply) target.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); + } + + public void UpdateColor(TMP_Text target, Color32 color, TMP_MeshInfo[] meshInfos, bool apply = true) + { + Color32[] vertexCols = meshInfos[_matIndex].colors32; + vertexCols[_firstVertexIndex] = color; + vertexCols[_firstVertexIndex + 1] = color; + vertexCols[_firstVertexIndex + 2] = color; + vertexCols[_firstVertexIndex + 3] = color; + if (apply) target.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32); + } + + public void UpdateGeometry(TMP_Text target, Vector3 offset, Quaternion rotation, Vector3 scale, TMP_MeshInfo[] cachedMeshInfos, bool apply = true) + { + this.offset = offset; + this.rotation = rotation; + this.scale = scale; + + if (!apply) return; + + Vector3[] destinationVertices = _meshInfo.vertices; + Vector3[] cachedVertices = cachedMeshInfos[_matIndex].vertices; + destinationVertices[_firstVertexIndex] = cachedVertices[_firstVertexIndex + 0] - _charMidBaselineOffset; + destinationVertices[_firstVertexIndex + 1] = cachedVertices[_firstVertexIndex + 1] - _charMidBaselineOffset; + destinationVertices[_firstVertexIndex + 2] = cachedVertices[_firstVertexIndex + 2] - _charMidBaselineOffset; + destinationVertices[_firstVertexIndex + 3] = cachedVertices[_firstVertexIndex + 3] - _charMidBaselineOffset; + Matrix4x4 matrix = Matrix4x4.TRS(this.offset, this.rotation, this.scale); + destinationVertices[_firstVertexIndex] + = matrix.MultiplyPoint3x4(destinationVertices[_firstVertexIndex + 0]) + _charMidBaselineOffset + _bottomLeftShift; + destinationVertices[_firstVertexIndex + 1] + = matrix.MultiplyPoint3x4(destinationVertices[_firstVertexIndex + 1]) + _charMidBaselineOffset + _topLeftShift; + destinationVertices[_firstVertexIndex + 2] + = matrix.MultiplyPoint3x4(destinationVertices[_firstVertexIndex + 2]) + _charMidBaselineOffset + _topRightShift; + destinationVertices[_firstVertexIndex + 3] + = matrix.MultiplyPoint3x4(destinationVertices[_firstVertexIndex + 3]) + _charMidBaselineOffset + _bottomRightShift; + _meshInfo.mesh.vertices = _meshInfo.vertices; + target.UpdateGeometry(_meshInfo.mesh, _matIndex); + } + + public void ShiftVertices(TMP_Text target, Vector3 topLeftShift, Vector3 topRightShift, Vector3 bottomLeftShift, Vector3 bottomRightShift) + { + _topLeftShift += topLeftShift; + _topRightShift += topRightShift; + _bottomLeftShift += bottomLeftShift; + _bottomRightShift += bottomRightShift; + Vector3[] destinationVertices = _meshInfo.vertices; + destinationVertices[_firstVertexIndex] = destinationVertices[_firstVertexIndex] + _bottomLeftShift; + destinationVertices[_firstVertexIndex + 1] = destinationVertices[_firstVertexIndex + 1] + _topLeftShift; + destinationVertices[_firstVertexIndex + 2] = destinationVertices[_firstVertexIndex + 2] + _topRightShift; + destinationVertices[_firstVertexIndex + 3] = destinationVertices[_firstVertexIndex + 3] + _bottomRightShift; + _meshInfo.mesh.vertices = _meshInfo.vertices; + target.UpdateGeometry(_meshInfo.mesh, _matIndex); + } + + public void ResetVerticesShift(TMP_Text target) + { + Vector3[] destinationVertices = _meshInfo.vertices; + destinationVertices[_firstVertexIndex] = destinationVertices[_firstVertexIndex] - _bottomLeftShift; + destinationVertices[_firstVertexIndex + 1] = destinationVertices[_firstVertexIndex + 1] - _topLeftShift; + destinationVertices[_firstVertexIndex + 2] = destinationVertices[_firstVertexIndex + 2] - _topRightShift; + destinationVertices[_firstVertexIndex + 3] = destinationVertices[_firstVertexIndex + 3] - _bottomRightShift; + _meshInfo.mesh.vertices = _meshInfo.vertices; + target.UpdateGeometry(_meshInfo.mesh, _matIndex); + _topLeftShift = _topRightShift = _bottomLeftShift = _bottomRightShift = Vector3.zero; + } + } + } + + #endregion +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs.meta new file mode 100644 index 0000000..613cdbc --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTextMeshPro.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8fb0d65aa5b048649a3a785b82b8f8db +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs new file mode 100644 index 0000000..0c57bfe --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs @@ -0,0 +1,247 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2014/10/27 15:59 +// +// License Copyright (c) Daniele Giardini. +// This work is subject to the terms at http://dotween.demigiant.com/license.php + +#if false // MODULE_MARKER +using DG.Tweening.Core; +using DG.Tweening.Plugins.Options; +using UnityEngine; + +namespace DG.Tweening +{ + /// + /// Methods that extend 2D Toolkit objects and allow to directly create and control tweens from their instances. + /// + public static class ShortcutExtensionsTk2d + { + #region Sprite + + /// Tweens a 2D Toolkit Sprite's dimensions to the given value. + /// Also stores the Sprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScale(this tk2dBaseSprite target, Vector3 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, endValue, duration); + t.SetTarget(target); + return t; + } + /// Tweens a Sprite's dimensions to the given value. + /// Also stores the Sprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleX(this tk2dBaseSprite target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, new Vector3(endValue, 0, 0), duration); + t.SetOptions(AxisConstraint.X) + .SetTarget(target); + return t; + } + /// Tweens a Sprite's dimensions to the given value. + /// Also stores the Sprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleY(this tk2dBaseSprite target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, new Vector3(0, endValue, 0), duration); + t.SetOptions(AxisConstraint.Y) + .SetTarget(target); + return t; + } + /// Tweens a Sprite's dimensions to the given value. + /// Also stores the Sprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleZ(this tk2dBaseSprite target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, new Vector3(0, 0, endValue), duration); + t.SetOptions(AxisConstraint.Z) + .SetTarget(target); + return t; + } + + /// Tweens a 2D Toolkit Sprite's color to the given value. + /// Also stores the Sprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this tk2dBaseSprite target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a 2D Toolkit Sprite's alpha color to the given value. + /// Also stores the Sprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this tk2dBaseSprite target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a 2D Toolkit Sprite's color using the given gradient + /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener). + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The gradient to useThe duration of the tween + public static Sequence DOGradientColor(this tk2dBaseSprite target, Gradient gradient, float duration) + { + Sequence s = DOTween.Sequence(); + GradientColorKey[] colors = gradient.colorKeys; + int len = colors.Length; + for (int i = 0; i < len; ++i) { + GradientColorKey c = colors[i]; + if (i == 0 && c.time <= 0) { + target.color = c.color; + continue; + } + float colorDuration = i == len - 1 + ? duration - s.Duration(false) // Verifies that total duration is correct + : duration * (i == 0 ? c.time : c.time - colors[i - 1].time); + s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear)); + } + s.SetTarget(target); + return s; + } + + #endregion + + #region tk2dSlicedSprite + + /// Tweens a 2D Toolkit SlicedSprite's dimensions to the given value. + /// Also stores the SlicedSprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleDimensions(this tk2dSlicedSprite target, Vector2 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.dimensions, x => target.dimensions = x, endValue, duration); + t.SetTarget(target); + return t; + } + /// Tweens a SlicedSprite's dimensions to the given value. + /// Also stores the SlicedSprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleDimensionsX(this tk2dSlicedSprite target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.dimensions, x => target.dimensions = x, new Vector2(endValue, 0), duration); + t.SetOptions(AxisConstraint.X) + .SetTarget(target); + return t; + } + /// Tweens a SlicedSprite's dimensions to the given value. + /// Also stores the SlicedSprite as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleDimensionsY(this tk2dSlicedSprite target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.dimensions, x => target.dimensions = x, new Vector2(0, endValue), duration); + t.SetOptions(AxisConstraint.Y) + .SetTarget(target); + return t; + } + + #endregion + + #region TextMesh + + /// Tweens a 2D Toolkit TextMesh's dimensions to the given value. + /// Also stores the TextMesh as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScale(this tk2dTextMesh target, Vector3 endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, endValue, duration); + t.SetTarget(target); + return t; + } + /// Tweens a 2D Toolkit TextMesh's dimensions to the given value. + /// Also stores the TextMesh as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleX(this tk2dTextMesh target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, new Vector3(endValue, 0, 0), duration); + t.SetOptions(AxisConstraint.X) + .SetTarget(target); + return t; + } + /// Tweens a 2D Toolkit TextMesh's dimensions to the given value. + /// Also stores the TextMesh as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleY(this tk2dTextMesh target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, new Vector3(0, endValue, 0), duration); + t.SetOptions(AxisConstraint.Y) + .SetTarget(target); + return t; + } + /// Tweens a 2D Toolkit TextMesh's dimensions to the given value. + /// Also stores the TextMesh as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOScaleZ(this tk2dTextMesh target, float endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.scale, x => target.scale = x, new Vector3(0, 0, endValue), duration); + t.SetOptions(AxisConstraint.Z) + .SetTarget(target); + return t; + } + + /// Tweens a 2D Toolkit TextMesh's color to the given value. + /// Also stores the TextMesh as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOColor(this tk2dTextMesh target, Color endValue, float duration) + { + TweenerCore t = DOTween.To(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a 2D Toolkit TextMesh's alpha color to the given value. + /// Also stores the TextMesh as the tween's target so it can be used for filtered operations + /// The end value to reachThe duration of the tween + public static TweenerCore DOFade(this tk2dTextMesh target, float endValue, float duration) + { + TweenerCore t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration); + t.SetTarget(target); + return t; + } + + /// Tweens a 2D Toolkit TextMesh's color using the given gradient + /// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener). + /// Also stores the image as the tween's target so it can be used for filtered operations + /// The gradient to useThe duration of the tween + public static Sequence DOGradientColor(this tk2dTextMesh target, Gradient gradient, float duration) + { + Sequence s = DOTween.Sequence(); + GradientColorKey[] colors = gradient.colorKeys; + int len = colors.Length; + for (int i = 0; i < len; ++i) { + GradientColorKey c = colors[i]; + if (i == 0 && c.time <= 0) { + target.color = c.color; + continue; + } + float colorDuration = i == len - 1 + ? duration - s.Duration(false) // Verifies that total duration is correct + : duration * (i == 0 ? c.time : c.time - colors[i - 1].time); + s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear)); + } + s.SetTarget(target); + return s; + } + + /// Tweens a tk2dTextMesh's text to the given value. + /// Also stores the tk2dTextMesh as the tween's target so it can be used for filtered operations + /// The end string to tween toThe duration of the tween + /// If TRUE (default), rich text will be interpreted correctly while animated, + /// otherwise all tags will be considered as normal text + /// The type of scramble mode to use, if any + /// A string containing the characters to use for scrambling. + /// Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters. + /// Leave it to NULL (default) to use default ones + public static TweenerCore DOText(this tk2dTextMesh target, string endValue, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null) + { + TweenerCore t = DOTween.To(() => target.text, x => target.text = x, endValue, duration); + t.SetOptions(richTextEnabled, scrambleMode, scrambleChars) + .SetTarget(target); + return t; + } + + #endregion + } +} +#endif diff --git a/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs.meta new file mode 100644 index 0000000..c909f96 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenTk2d.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b590cd7c24ffa5d4faa5b6fa993cccad +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor.meta b/Assets/Plugins/Demigiant/DOTweenPro/Editor.meta new file mode 100644 index 0000000..e9164f7 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 34ca5bde92f87fa4dbeb9593d201fde2 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs new file mode 100644 index 0000000..69f753d --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs @@ -0,0 +1,764 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2015/03/12 16:03 + +using System; +using System.Collections.Generic; +using System.IO; +using DG.DemiEditor; +using DG.DOTweenEditor.Core; +using DG.DOTweenEditor.UI; +using DG.Tweening; +using DG.Tweening.Core; +using UnityEditor; +using UnityEngine; +using DOTweenSettings = DG.Tweening.Core.DOTweenSettings; +#if true // UI_MARKER +using UnityEngine.UI; +#endif +#if false // TEXTMESHPRO_MARKER + using TMPro; +#endif + +namespace DG.DOTweenEditor +{ + [CustomEditor(typeof(DOTweenAnimation))] + public class DOTweenAnimationInspector : ABSAnimationInspector + { + enum FadeTargetType + { + CanvasGroup, + Image + } + + enum ChooseTargetMode + { + None, + BetweenCanvasGroupAndImage + } + + static readonly Dictionary _AnimationTypeToComponent = new Dictionary() { + { DOTweenAnimation.AnimationType.Move, new[] { +#if true // PHYSICS_MARKER + typeof(Rigidbody), +#endif +#if true // PHYSICS2D_MARKER + typeof(Rigidbody2D), +#endif +#if true // UI_MARKER + typeof(RectTransform), +#endif + typeof(Transform) + }}, + { DOTweenAnimation.AnimationType.Rotate, new[] { +#if true // PHYSICS_MARKER + typeof(Rigidbody), +#endif +#if true // PHYSICS2D_MARKER + typeof(Rigidbody2D), +#endif + typeof(Transform) + }}, + { DOTweenAnimation.AnimationType.LocalMove, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.LocalRotate, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.Scale, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.Color, new[] { + typeof(Light), +#if true // SPRITE_MARKER + typeof(SpriteRenderer), +#endif +#if true // UI_MARKER + typeof(Image), typeof(Text), typeof(RawImage), typeof(Graphic), +#endif + typeof(Renderer), + }}, + { DOTweenAnimation.AnimationType.Fade, new[] { + typeof(Light), +#if true // SPRITE_MARKER + typeof(SpriteRenderer), +#endif +#if true // UI_MARKER + typeof(Image), typeof(Text), typeof(CanvasGroup), typeof(RawImage), typeof(Graphic), +#endif + typeof(Renderer), + }}, +#if true // UI_MARKER + { DOTweenAnimation.AnimationType.Text, new[] { typeof(Text) } }, +#endif + { DOTweenAnimation.AnimationType.PunchPosition, new[] { +#if true // UI_MARKER + typeof(RectTransform), +#endif + typeof(Transform) + }}, + { DOTweenAnimation.AnimationType.PunchRotation, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.PunchScale, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.ShakePosition, new[] { +#if true // UI_MARKER + typeof(RectTransform), +#endif + typeof(Transform) + }}, + { DOTweenAnimation.AnimationType.ShakeRotation, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.ShakeScale, new[] { typeof(Transform) } }, + { DOTweenAnimation.AnimationType.CameraAspect, new[] { typeof(Camera) } }, + { DOTweenAnimation.AnimationType.CameraBackgroundColor, new[] { typeof(Camera) } }, + { DOTweenAnimation.AnimationType.CameraFieldOfView, new[] { typeof(Camera) } }, + { DOTweenAnimation.AnimationType.CameraOrthoSize, new[] { typeof(Camera) } }, + { DOTweenAnimation.AnimationType.CameraPixelRect, new[] { typeof(Camera) } }, + { DOTweenAnimation.AnimationType.CameraRect, new[] { typeof(Camera) } }, +#if true // UI_MARKER + { DOTweenAnimation.AnimationType.UIWidthHeight, new[] { typeof(RectTransform) } }, + { DOTweenAnimation.AnimationType.FillAmount, new[] { typeof(Image) } }, +#endif + }; + +#if false // TK2D_MARKER + static readonly Dictionary _Tk2dAnimationTypeToComponent = new Dictionary() { + { DOTweenAnimation.AnimationType.Scale, new[] { typeof(tk2dBaseSprite), typeof(tk2dTextMesh) } }, + { DOTweenAnimation.AnimationType.Color, new[] { typeof(tk2dBaseSprite), typeof(tk2dTextMesh) } }, + { DOTweenAnimation.AnimationType.Fade, new[] { typeof(tk2dBaseSprite), typeof(tk2dTextMesh) } }, + { DOTweenAnimation.AnimationType.Text, new[] { typeof(tk2dTextMesh) } } + }; +#endif +#if false // TEXTMESHPRO_MARKER + static readonly Dictionary _TMPAnimationTypeToComponent = new Dictionary() { + { DOTweenAnimation.AnimationType.Color, new[] { typeof(TextMeshPro), typeof(TextMeshProUGUI) } }, + { DOTweenAnimation.AnimationType.Fade, new[] { typeof(TextMeshPro), typeof(TextMeshProUGUI) } }, + { DOTweenAnimation.AnimationType.Text, new[] { typeof(TextMeshPro), typeof(TextMeshProUGUI) } } + }; +#endif + + static readonly string[] _AnimationType = new[] { + "None", + "Move", "LocalMove", + "Rotate", "LocalRotate", + "Scale", + "Color", "Fade", +#if true // UI_MARKER + "FillAmount", + "Text", +#endif +#if false // TK2D_MARKER + "Text", +#endif +#if false // TEXTMESHPRO_MARKER + "Text", +#endif +#if true // UI_MARKER + "UIWidthHeight", +#endif + "Punch/Position", "Punch/Rotation", "Punch/Scale", + "Shake/Position", "Shake/Rotation", "Shake/Scale", + "Camera/Aspect", "Camera/BackgroundColor", "Camera/FieldOfView", "Camera/OrthoSize", "Camera/PixelRect", "Camera/Rect" + }; + static string[] _animationTypeNoSlashes; // _AnimationType list without slashes in values + static string[] _datString; // String representation of DOTweenAnimation enum (here for caching reasons) + + DOTweenAnimation _src; + DOTweenSettings _settings; + bool _runtimeEditMode; // If TRUE allows to change and save stuff at runtime + bool _refreshRequired; // If TRUE refreshes components data + int _totComponentsOnSrc; // Used to determine if a Component is added or removed from the source + bool _isLightSrc; // Used to determine if we're tweening a Light, to set the max Fade value to more than 1 +#pragma warning disable 414 + ChooseTargetMode _chooseTargetMode = ChooseTargetMode.None; +#pragma warning restore 414 + + static readonly GUIContent _GuiC_selfTarget_true = new GUIContent( + "SELF", "Will animate components on this gameObject" + ); + static readonly GUIContent _GuiC_selfTarget_false = new GUIContent( + "OTHER", "Will animate components on the given gameObject instead than on this one" + ); + static readonly GUIContent _GuiC_tweenTargetIsTargetGO_true = new GUIContent( + "Use As Tween Target", "Will set the tween target (via SetTarget, used to control a tween directly from a target) to the \"OTHER\" gameObject" + ); + static readonly GUIContent _GuiC_tweenTargetIsTargetGO_false = new GUIContent( + "Use As Tween Target", "Will set the tween target (via SetTarget, used to control a tween directly from a target) to the gameObject containing this animation, not the \"OTHER\" one" + ); + + #region MonoBehaviour Methods + + void OnEnable() + { + _src = target as DOTweenAnimation; + _settings = DOTweenUtilityWindow.GetDOTweenSettings(); + + onStartProperty = base.serializedObject.FindProperty("onStart"); + onPlayProperty = base.serializedObject.FindProperty("onPlay"); + onUpdateProperty = base.serializedObject.FindProperty("onUpdate"); + onStepCompleteProperty = base.serializedObject.FindProperty("onStepComplete"); + onCompleteProperty = base.serializedObject.FindProperty("onComplete"); + onRewindProperty = base.serializedObject.FindProperty("onRewind"); + onTweenCreatedProperty = base.serializedObject.FindProperty("onTweenCreated"); + + // Convert _AnimationType to _animationTypeNoSlashes + int len = _AnimationType.Length; + _animationTypeNoSlashes = new string[len]; + for (int i = 0; i < len; ++i) { + string a = _AnimationType[i]; + a = a.Replace("/", ""); + _animationTypeNoSlashes[i] = a; + } + } + + void OnDisable() + { + DOTweenPreviewManager.StopAllPreviews(); + } + + override public void OnInspectorGUI() + { + base.OnInspectorGUI(); + + GUILayout.Space(3); + EditorGUIUtils.SetGUIStyles(); + + bool playMode = Application.isPlaying; + _runtimeEditMode = _runtimeEditMode && playMode; + + GUILayout.BeginHorizontal(); + EditorGUIUtils.InspectorLogo(); + GUILayout.Label(_src.animationType.ToString() + (string.IsNullOrEmpty(_src.id) ? "" : " [" + _src.id + "]"), EditorGUIUtils.sideLogoIconBoldLabelStyle); + // Up-down buttons + GUILayout.FlexibleSpace(); + if (GUILayout.Button("▲", DeGUI.styles.button.toolIco)) UnityEditorInternal.ComponentUtility.MoveComponentUp(_src); + if (GUILayout.Button("▼", DeGUI.styles.button.toolIco)) UnityEditorInternal.ComponentUtility.MoveComponentDown(_src); + GUILayout.EndHorizontal(); + + if (playMode) { + if (_runtimeEditMode) { + + } else { + GUILayout.Space(8); + GUILayout.Label("Animation Editor disabled while in play mode", EditorGUIUtils.wordWrapLabelStyle); + if (!_src.isActive) { + GUILayout.Label("This animation has been toggled as inactive and won't be generated", EditorGUIUtils.wordWrapLabelStyle); + GUI.enabled = false; + } + if (GUILayout.Button(new GUIContent("Activate Edit Mode", "Switches to Runtime Edit Mode, where you can change animations values and restart them"))) { + _runtimeEditMode = true; + } + GUILayout.Label("NOTE: when using DOPlayNext, the sequence is determined by the DOTweenAnimation Components order in the target GameObject's Inspector", EditorGUIUtils.wordWrapLabelStyle); + GUILayout.Space(10); + if (!_runtimeEditMode) return; + } + } + + Undo.RecordObject(_src, "DOTween Animation"); + Undo.RecordObject(_settings, "DOTween Animation"); + +// _src.isValid = Validate(); // Moved down + + EditorGUIUtility.labelWidth = 110; + + if (playMode) { + GUILayout.Space(4); + DeGUILayout.Toolbar("Edit Mode Commands"); + DeGUILayout.BeginVBox(DeGUI.styles.box.stickyTop); + GUILayout.BeginHorizontal(); + if (GUILayout.Button("TogglePause")) _src.tween.TogglePause(); + if (GUILayout.Button("Rewind")) _src.tween.Rewind(); + if (GUILayout.Button("Restart")) _src.tween.Restart(); + GUILayout.EndHorizontal(); + if (GUILayout.Button("Commit changes and restart")) { + _src.tween.Rewind(); + _src.tween.Kill(); + if (_src.isValid) { + _src.CreateTween(); + _src.tween.Play(); + } + } + GUILayout.Label("To apply your changes when exiting Play mode, use the Component's upper right menu and choose \"Copy Component\", then \"Paste Component Values\" after exiting Play mode", DeGUI.styles.label.wordwrap); + DeGUILayout.EndVBox(); + } else { + GUILayout.BeginHorizontal(); + bool hasManager = _src.GetComponent() != null; + EditorGUI.BeginChangeCheck(); + _settings.showPreviewPanel = hasManager + ? DeGUILayout.ToggleButton(_settings.showPreviewPanel, "Preview Controls", styles.custom.inlineToggle) + : DeGUILayout.ToggleButton(_settings.showPreviewPanel, "Preview Controls", styles.custom.inlineToggle, GUILayout.Width(120)); + if (EditorGUI.EndChangeCheck()) { + EditorUtility.SetDirty(_settings); + DOTweenPreviewManager.StopAllPreviews(); + } + if (!hasManager) { + if (GUILayout.Button(new GUIContent("Add Manager", "Adds a manager component which allows you to choose additional options for this gameObject"))) { + _src.gameObject.AddComponent(); + } + } + GUILayout.EndHorizontal(); + } + + // Preview in editor + bool isPreviewing = _settings.showPreviewPanel ? DOTweenPreviewManager.PreviewGUI(_src) : false; + + EditorGUI.BeginDisabledGroup(isPreviewing); + // Choose target + GUILayout.BeginHorizontal(); + _src.isActive = EditorGUILayout.Toggle(new GUIContent("", "If unchecked, this animation will not be created"), _src.isActive, GUILayout.Width(14)); + EditorGUI.BeginChangeCheck(); + EditorGUI.BeginChangeCheck(); + _src.targetIsSelf = DeGUILayout.ToggleButton( + _src.targetIsSelf, _src.targetIsSelf ? _GuiC_selfTarget_true : _GuiC_selfTarget_false, + new Color(1f, 0.78f, 0f), DeGUI.colors.bg.toggleOn, new Color(0.33f, 0.14f, 0.02f), DeGUI.colors.content.toggleOn, + null, GUILayout.Width(47) + ); + bool innerChanged = EditorGUI.EndChangeCheck(); + if (innerChanged) { + _src.targetGO = null; + GUI.changed = true; + } + if (_src.targetIsSelf) GUILayout.Label(_GuiC_selfTarget_true.tooltip); + else { + using (new DeGUI.ColorScope(null, null, _src.targetGO == null ? Color.red : Color.white)) { + _src.targetGO = (GameObject)EditorGUILayout.ObjectField(_src.targetGO, typeof(GameObject), true); + } + _src.tweenTargetIsTargetGO = DeGUILayout.ToggleButton( + _src.tweenTargetIsTargetGO, _src.tweenTargetIsTargetGO ? _GuiC_tweenTargetIsTargetGO_true : _GuiC_tweenTargetIsTargetGO_false, + GUILayout.Width(131) + ); + } + bool check = EditorGUI.EndChangeCheck(); + if (check) _refreshRequired = true; + GUILayout.EndHorizontal(); + + GameObject targetGO = _src.targetIsSelf ? _src.gameObject : _src.targetGO; + + if (targetGO == null) { + // Uses external target gameObject but it's not set + if (_src.targetGO != null || _src.target != null) { + _src.targetGO = null; + _src.target = null; + GUI.changed = true; + } + } else { + GUILayout.BeginHorizontal(); + DOTweenAnimation.AnimationType prevAnimType = _src.animationType; +// _src.animationType = (DOTweenAnimation.AnimationType)EditorGUILayout.EnumPopup(_src.animationType, EditorGUIUtils.popupButton); + GUI.enabled = GUI.enabled && _src.isActive; + _src.animationType = AnimationToDOTweenAnimationType(_AnimationType[EditorGUILayout.Popup(DOTweenAnimationTypeToPopupId(_src.animationType), _AnimationType)]); + _src.autoGenerate = DeGUILayout.ToggleButton(_src.autoGenerate, new GUIContent("AutoGenerate", "If selected, the tween will be generated at startup (during Start for RectTransform position tween, Awake for all the others)")); + if (_src.autoGenerate) { + _src.autoPlay = DeGUILayout.ToggleButton(_src.autoPlay, new GUIContent("AutoPlay", "If selected, the tween will play automatically")); + } + _src.autoKill = DeGUILayout.ToggleButton(_src.autoKill, new GUIContent("AutoKill", "If selected, the tween will be killed when it completes, and won't be reusable")); + GUILayout.EndHorizontal(); + if (prevAnimType != _src.animationType) { + // Set default optional values based on animation type + _src.endValueTransform = null; + _src.useTargetAsV3 = false; + switch (_src.animationType) { + case DOTweenAnimation.AnimationType.Move: + case DOTweenAnimation.AnimationType.LocalMove: + case DOTweenAnimation.AnimationType.Rotate: + case DOTweenAnimation.AnimationType.LocalRotate: + case DOTweenAnimation.AnimationType.Scale: + _src.endValueV3 = Vector3.zero; + _src.endValueFloat = 0; + _src.optionalBool0 = _src.animationType == DOTweenAnimation.AnimationType.Scale; + break; + case DOTweenAnimation.AnimationType.UIWidthHeight: + _src.endValueV3 = Vector3.zero; + _src.endValueFloat = 0; + _src.optionalBool0 = _src.animationType == DOTweenAnimation.AnimationType.UIWidthHeight; + break; + case DOTweenAnimation.AnimationType.FillAmount: + _src.endValueFloat = 1; + break; + case DOTweenAnimation.AnimationType.Color: + case DOTweenAnimation.AnimationType.Fade: + _isLightSrc = targetGO.GetComponent() != null; + _src.endValueFloat = 0; + break; + case DOTweenAnimation.AnimationType.Text: + _src.optionalBool0 = true; + break; + case DOTweenAnimation.AnimationType.PunchPosition: + case DOTweenAnimation.AnimationType.PunchRotation: + case DOTweenAnimation.AnimationType.PunchScale: + _src.endValueV3 = _src.animationType == DOTweenAnimation.AnimationType.PunchRotation ? new Vector3(0, 180, 0) : Vector3.one; + _src.optionalFloat0 = 1; + _src.optionalInt0 = 10; + _src.optionalBool0 = false; + break; + case DOTweenAnimation.AnimationType.ShakePosition: + case DOTweenAnimation.AnimationType.ShakeRotation: + case DOTweenAnimation.AnimationType.ShakeScale: + _src.endValueV3 = _src.animationType == DOTweenAnimation.AnimationType.ShakeRotation ? new Vector3(90, 90, 90) : Vector3.one; + _src.optionalInt0 = 10; + _src.optionalFloat0 = 90; + _src.optionalBool0 = false; + _src.optionalBool1 = true; + break; + case DOTweenAnimation.AnimationType.CameraAspect: + case DOTweenAnimation.AnimationType.CameraFieldOfView: + case DOTweenAnimation.AnimationType.CameraOrthoSize: + _src.endValueFloat = 0; + break; + case DOTweenAnimation.AnimationType.CameraPixelRect: + case DOTweenAnimation.AnimationType.CameraRect: + _src.endValueRect = new Rect(0, 0, 0, 0); + break; + } + } + if (_src.animationType == DOTweenAnimation.AnimationType.None) { + _src.isValid = false; + if (GUI.changed) EditorUtility.SetDirty(_src); + return; + } + + if (_refreshRequired || prevAnimType != _src.animationType || ComponentsChanged()) { + _refreshRequired = false; + _src.isValid = Validate(targetGO); + // See if we need to choose between multiple targets +#if true // UI_MARKER + if (_src.animationType == DOTweenAnimation.AnimationType.Fade && targetGO.GetComponent() != null && targetGO.GetComponent() != null) { + _chooseTargetMode = ChooseTargetMode.BetweenCanvasGroupAndImage; + // Reassign target and forcedTargetType if lost + if (_src.forcedTargetType == DOTweenAnimation.TargetType.Unset) _src.forcedTargetType = _src.targetType; + switch (_src.forcedTargetType) { + case DOTweenAnimation.TargetType.CanvasGroup: + _src.target = targetGO.GetComponent(); + break; + case DOTweenAnimation.TargetType.Image: + _src.target = targetGO.GetComponent(); + break; + } + } else { +#endif + _chooseTargetMode = ChooseTargetMode.None; + _src.forcedTargetType = DOTweenAnimation.TargetType.Unset; +#if true // UI_MARKER + } +#endif + } + + if (!_src.isValid) { + GUI.color = Color.red; + GUILayout.BeginVertical(GUI.skin.box); + GUILayout.Label("No valid Component was found for the selected animation", EditorGUIUtils.wordWrapLabelStyle); + GUILayout.EndVertical(); + GUI.color = Color.white; + if (GUI.changed) EditorUtility.SetDirty(_src); + return; + } + +#if true // UI_MARKER + // Special cases in which multiple target types could be used (set after validation) + if (_chooseTargetMode == ChooseTargetMode.BetweenCanvasGroupAndImage && _src.forcedTargetType != DOTweenAnimation.TargetType.Unset) { + FadeTargetType fadeTargetType = (FadeTargetType)Enum.Parse(typeof(FadeTargetType), _src.forcedTargetType.ToString()); + DOTweenAnimation.TargetType prevTargetType = _src.forcedTargetType; + _src.forcedTargetType = (DOTweenAnimation.TargetType)Enum.Parse(typeof(DOTweenAnimation.TargetType), EditorGUILayout.EnumPopup(_src.animationType + " Target", fadeTargetType).ToString()); + if (_src.forcedTargetType != prevTargetType) { + // Target type change > assign correct target + switch (_src.forcedTargetType) { + case DOTweenAnimation.TargetType.CanvasGroup: + _src.target = targetGO.GetComponent(); + break; + case DOTweenAnimation.TargetType.Image: + _src.target = targetGO.GetComponent(); + break; + } + } + } +#endif + + GUILayout.BeginHorizontal(); + _src.duration = EditorGUILayout.FloatField("Duration", _src.duration); + if (_src.duration < 0) _src.duration = 0; + _src.isSpeedBased = DeGUILayout.ToggleButton(_src.isSpeedBased, new GUIContent("SpeedBased", "If selected, the duration will count as units/degree x second"), DeGUI.styles.button.tool, GUILayout.Width(75)); + GUILayout.EndHorizontal(); + _src.delay = EditorGUILayout.FloatField("Delay", _src.delay); + if (_src.delay < 0) _src.delay = 0; + _src.isIndependentUpdate = EditorGUILayout.Toggle("Ignore TimeScale", _src.isIndependentUpdate); + _src.easeType = EditorGUIUtils.FilteredEasePopup("Ease", _src.easeType); + if (_src.easeType == Ease.INTERNAL_Custom) { + _src.easeCurve = EditorGUILayout.CurveField(" Ease Curve", _src.easeCurve); + } + _src.loops = EditorGUILayout.IntField(new GUIContent("Loops", "Set to -1 for infinite loops"), _src.loops); + if (_src.loops < -1) _src.loops = -1; + if (_src.loops > 1 || _src.loops == -1) + _src.loopType = (LoopType)EditorGUILayout.EnumPopup(" Loop Type", _src.loopType); + _src.id = EditorGUILayout.TextField("ID", _src.id); + + bool canBeRelative = true; + // End value and eventual specific options + switch (_src.animationType) { + case DOTweenAnimation.AnimationType.Move: + case DOTweenAnimation.AnimationType.LocalMove: + GUIEndValueV3(targetGO, _src.animationType == DOTweenAnimation.AnimationType.Move); + _src.optionalBool0 = EditorGUILayout.Toggle(" Snapping", _src.optionalBool0); + canBeRelative = !_src.useTargetAsV3; + break; + case DOTweenAnimation.AnimationType.Rotate: + case DOTweenAnimation.AnimationType.LocalRotate: + bool isRigidbody2D = DOTweenModuleUtils.Physics.HasRigidbody2D(_src); + if (isRigidbody2D) GUIEndValueFloat(); + else { + GUIEndValueV3(targetGO); + _src.optionalRotationMode = (RotateMode)EditorGUILayout.EnumPopup(" Rotation Mode", _src.optionalRotationMode); + } + break; + case DOTweenAnimation.AnimationType.Scale: + if (_src.optionalBool0) GUIEndValueFloat(); + else GUIEndValueV3(targetGO); + _src.optionalBool0 = EditorGUILayout.Toggle("Uniform Scale", _src.optionalBool0); + break; + case DOTweenAnimation.AnimationType.UIWidthHeight: + if (_src.optionalBool0) GUIEndValueFloat(); + else GUIEndValueV2(); + _src.optionalBool0 = EditorGUILayout.Toggle("Uniform Scale", _src.optionalBool0); + break; + case DOTweenAnimation.AnimationType.FillAmount: + GUIEndValueFloat(); + if (_src.endValueFloat < 0) _src.endValueFloat = 0; + if (_src.endValueFloat > 1) _src.endValueFloat = 1; + canBeRelative = false; + break; + case DOTweenAnimation.AnimationType.Color: + GUIEndValueColor(); + canBeRelative = false; + break; + case DOTweenAnimation.AnimationType.Fade: + GUIEndValueFloat(); + if (_src.endValueFloat < 0) _src.endValueFloat = 0; + if (!_isLightSrc && _src.endValueFloat > 1) _src.endValueFloat = 1; + canBeRelative = false; + break; + case DOTweenAnimation.AnimationType.Text: + GUIEndValueString(); + _src.optionalBool0 = EditorGUILayout.Toggle("Rich Text Enabled", _src.optionalBool0); + _src.optionalScrambleMode = (ScrambleMode)EditorGUILayout.EnumPopup("Scramble Mode", _src.optionalScrambleMode); + _src.optionalString = EditorGUILayout.TextField(new GUIContent("Custom Scramble", "Custom characters to use in case of ScrambleMode.Custom"), _src.optionalString); + break; + case DOTweenAnimation.AnimationType.PunchPosition: + case DOTweenAnimation.AnimationType.PunchRotation: + case DOTweenAnimation.AnimationType.PunchScale: + GUIEndValueV3(targetGO); + canBeRelative = false; + _src.optionalInt0 = EditorGUILayout.IntSlider(new GUIContent(" Vibrato", "How much will the punch vibrate"), _src.optionalInt0, 1, 50); + _src.optionalFloat0 = EditorGUILayout.Slider(new GUIContent(" Elasticity", "How much the vector will go beyond the starting position when bouncing backwards"), _src.optionalFloat0, 0, 1); + if (_src.animationType == DOTweenAnimation.AnimationType.PunchPosition) _src.optionalBool0 = EditorGUILayout.Toggle(" Snapping", _src.optionalBool0); + break; + case DOTweenAnimation.AnimationType.ShakePosition: + case DOTweenAnimation.AnimationType.ShakeRotation: + case DOTweenAnimation.AnimationType.ShakeScale: + GUIEndValueV3(targetGO); + canBeRelative = false; + _src.optionalInt0 = EditorGUILayout.IntSlider(new GUIContent(" Vibrato", "How much will the shake vibrate"), _src.optionalInt0, 1, 50); + using (new GUILayout.HorizontalScope()) { + _src.optionalFloat0 = EditorGUILayout.Slider(new GUIContent(" Randomness", "The shake randomness"), _src.optionalFloat0, 0, 90); + _src.optionalShakeRandomnessMode = (ShakeRandomnessMode)EditorGUILayout.EnumPopup(_src.optionalShakeRandomnessMode, GUILayout.Width(70)); + } + _src.optionalBool1 = EditorGUILayout.Toggle(new GUIContent(" FadeOut", "If selected the shake will fade out, otherwise it will constantly play with full force"), _src.optionalBool1); + if (_src.animationType == DOTweenAnimation.AnimationType.ShakePosition) _src.optionalBool0 = EditorGUILayout.Toggle(" Snapping", _src.optionalBool0); + break; + case DOTweenAnimation.AnimationType.CameraAspect: + case DOTweenAnimation.AnimationType.CameraFieldOfView: + case DOTweenAnimation.AnimationType.CameraOrthoSize: + GUIEndValueFloat(); + canBeRelative = false; + break; + case DOTweenAnimation.AnimationType.CameraBackgroundColor: + GUIEndValueColor(); + canBeRelative = false; + break; + case DOTweenAnimation.AnimationType.CameraPixelRect: + case DOTweenAnimation.AnimationType.CameraRect: + GUIEndValueRect(); + canBeRelative = false; + break; + } + + // Final settings + if (canBeRelative) _src.isRelative = EditorGUILayout.Toggle(" Relative", _src.isRelative); + + // Events + AnimationInspectorGUI.AnimationEvents(this, _src); + } + EditorGUI.EndDisabledGroup(); + + if (GUI.changed) EditorUtility.SetDirty(_src); + } + + #endregion + + #region Methods + + // Returns TRUE if the Component layout on the src gameObject changed (a Component was added or removed) + bool ComponentsChanged() + { + int prevTotComponentsOnSrc = _totComponentsOnSrc; + _totComponentsOnSrc = _src.gameObject.GetComponents().Length; + return prevTotComponentsOnSrc != _totComponentsOnSrc; + } + + // Checks if a Component that can be animated with the given animationType is attached to the src + bool Validate(GameObject targetGO) + { + if (_src.animationType == DOTweenAnimation.AnimationType.None) return false; + + Component srcTarget; + // First check for external plugins +#if false // TK2D_MARKER + if (_Tk2dAnimationTypeToComponent.ContainsKey(_src.animationType)) { + foreach (Type t in _Tk2dAnimationTypeToComponent[_src.animationType]) { + srcTarget = targetGO.GetComponent(t); + if (srcTarget != null) { + _src.target = srcTarget; + _src.targetType = DOTweenAnimation.TypeToDOTargetType(t); + return true; + } + } + } +#endif +#if false // TEXTMESHPRO_MARKER + if (_TMPAnimationTypeToComponent.ContainsKey(_src.animationType)) { + foreach (Type t in _TMPAnimationTypeToComponent[_src.animationType]) { + srcTarget = targetGO.GetComponent(t); + if (srcTarget != null) { + _src.target = srcTarget; + _src.targetType = DOTweenAnimation.TypeToDOTargetType(t); + return true; + } + } + } +#endif + // Then check for regular stuff + if (_AnimationTypeToComponent.ContainsKey(_src.animationType)) { + foreach (Type t in _AnimationTypeToComponent[_src.animationType]) { + srcTarget = targetGO.GetComponent(t); + if (srcTarget != null) { + _src.target = srcTarget; + _src.targetType = DOTweenAnimation.TypeToDOTargetType(t); + return true; + } + } + } + return false; + } + + DOTweenAnimation.AnimationType AnimationToDOTweenAnimationType(string animation) + { + if (_datString == null) _datString = Enum.GetNames(typeof(DOTweenAnimation.AnimationType)); + animation = animation.Replace("/", ""); + return (DOTweenAnimation.AnimationType)(Array.IndexOf(_datString, animation)); + } + int DOTweenAnimationTypeToPopupId(DOTweenAnimation.AnimationType animation) + { + return Array.IndexOf(_animationTypeNoSlashes, animation.ToString()); + } + + #endregion + + #region GUI Draw Methods + + void GUIEndValueFloat() + { + GUILayout.BeginHorizontal(); + GUIToFromButton(); + _src.endValueFloat = EditorGUILayout.FloatField(_src.endValueFloat); + GUILayout.EndHorizontal(); + } + + void GUIEndValueColor() + { + GUILayout.BeginHorizontal(); + GUIToFromButton(); + _src.endValueColor = EditorGUILayout.ColorField(_src.endValueColor); + GUILayout.EndHorizontal(); + } + + void GUIEndValueV3(GameObject targetGO, bool optionalTransform = false) + { + GUILayout.BeginHorizontal(); + GUIToFromButton(); + if (_src.useTargetAsV3) { + Transform prevT = _src.endValueTransform; + _src.endValueTransform = EditorGUILayout.ObjectField(_src.endValueTransform, typeof(Transform), true) as Transform; + if (_src.endValueTransform != prevT && _src.endValueTransform != null) { +#if true // UI_MARKER + // Check that it's a Transform for a Transform or a RectTransform for a RectTransform + if (targetGO.GetComponent() != null) { + if (_src.endValueTransform.GetComponent() == null) { + EditorUtility.DisplayDialog("DOTween Pro", "For Unity UI elements, the target must also be a UI element", "Ok"); + _src.endValueTransform = null; + } + } else if (_src.endValueTransform.GetComponent() != null) { + EditorUtility.DisplayDialog("DOTween Pro", "You can't use a UI target for a non UI object", "Ok"); + _src.endValueTransform = null; + } +#endif + } + } else { + _src.endValueV3 = EditorGUILayout.Vector3Field("", _src.endValueV3, GUILayout.Height(16)); + } + if (optionalTransform) { + if (GUILayout.Button(_src.useTargetAsV3 ? "target" : "value", EditorGUIUtils.sideBtStyle, GUILayout.Width(44))) _src.useTargetAsV3 = !_src.useTargetAsV3; + } + GUILayout.EndHorizontal(); +#if true // UI_MARKER + if (_src.useTargetAsV3 && _src.endValueTransform != null && _src.target is RectTransform) { + EditorGUILayout.HelpBox("NOTE: when using a UI target, the tween will be created during Start instead of Awake", MessageType.Info); + } +#endif + } + + void GUIEndValueV2() + { + GUILayout.BeginHorizontal(); + GUIToFromButton(); + _src.endValueV2 = EditorGUILayout.Vector2Field("", _src.endValueV2, GUILayout.Height(16)); + GUILayout.EndHorizontal(); + } + + void GUIEndValueString() + { + GUILayout.BeginHorizontal(); + GUIToFromButton(); + _src.endValueString = EditorGUILayout.TextArea(_src.endValueString, EditorGUIUtils.wordWrapTextArea); + GUILayout.EndHorizontal(); + } + + void GUIEndValueRect() + { + GUILayout.BeginHorizontal(); + GUIToFromButton(); + _src.endValueRect = EditorGUILayout.RectField(_src.endValueRect); + GUILayout.EndHorizontal(); + } + + void GUIToFromButton() + { + if (GUILayout.Button(_src.isFrom ? "FROM" : "TO", EditorGUIUtils.sideBtStyle, GUILayout.Width(90))) _src.isFrom = !_src.isFrom; + GUILayout.Space(16); + } + + #endregion + } + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + // ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████ + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + + [InitializeOnLoad] + static class Initializer + { + static Initializer() + { + DOTweenAnimation.OnReset += OnReset; + } + + static void OnReset(DOTweenAnimation src) + { + DOTweenSettings settings = DOTweenUtilityWindow.GetDOTweenSettings(); + if (settings == null) return; + + Undo.RecordObject(src, "DOTweenAnimation"); + src.autoPlay = settings.defaultAutoPlay == AutoPlay.All || settings.defaultAutoPlay == AutoPlay.AutoPlayTweeners; + src.autoKill = settings.defaultAutoKill; + EditorUtility.SetDirty(src); + } + } +} diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs.meta new file mode 100644 index 0000000..d2d7eee --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenAnimationInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0203fd81362bab4d842d87ad09ee76e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs new file mode 100644 index 0000000..73d8a6b --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs @@ -0,0 +1,265 @@ +// Author: Daniele Giardini - http://www.demigiant.com +// Created: 2015/03/12 16:03 + +using System; +using System.Collections.Generic; +using DG.DemiEditor; +using DG.DemiLib; +using DG.Tweening; +using DG.Tweening.Core; +using UnityEditor; +using UnityEditorInternal; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace DG.DOTweenEditor +{ + public static class DOTweenPreviewManager + { + static bool _previewOnlyIfSetToAutoPlay = true; + static readonly Dictionary _AnimationToTween = new Dictionary(); + static readonly List _TmpKeys = new List(); + + #region Public Methods & GUI + + /// + /// Returns TRUE if its actually previewing animations + /// + public static bool PreviewGUI(DOTweenAnimation src) + { + if (EditorApplication.isPlaying) return false; + + Styles.Init(); + + bool isPreviewing = _AnimationToTween.Count > 0; + bool isPreviewingThis = isPreviewing && _AnimationToTween.ContainsKey(src); + + // Preview in editor + GUI.backgroundColor = isPreviewing + ? new DeSkinColor(new Color(0.49f, 0.8f, 0.86f), new Color(0.15f, 0.26f, 0.35f)) + : new DeSkinColor(Color.white, new Color(0.13f, 0.13f, 0.13f)); + GUILayout.BeginVertical(Styles.previewBox); + DeGUI.ResetGUIColors(); + GUILayout.BeginHorizontal(); + GUILayout.Label("Preview Mode - Experimental", Styles.previewLabel); + _previewOnlyIfSetToAutoPlay = DeGUILayout.ToggleButton( + _previewOnlyIfSetToAutoPlay, + new GUIContent("AutoPlay only", "If toggled only previews animations that have AutoPlay turned ON"), + Styles.btOption + ); + GUILayout.EndHorizontal(); + GUILayout.Space(1); + // Preview - Play + GUILayout.BeginHorizontal(); + EditorGUI.BeginDisabledGroup( + isPreviewingThis || src.animationType == DOTweenAnimation.AnimationType.None + || !src.isActive || _previewOnlyIfSetToAutoPlay && !src.autoPlay + ); + if (GUILayout.Button("► Play", Styles.btPreview)) { + if (!isPreviewing) StartupGlobalPreview(); + AddAnimationToGlobalPreview(src); + } + EditorGUI.EndDisabledGroup(); + EditorGUI.BeginDisabledGroup(isPreviewing); + if (GUILayout.Button("► Play All on GameObject", Styles.btPreview)) { + if (!isPreviewing) StartupGlobalPreview(); + DOTweenAnimation[] anims = src.gameObject.GetComponents(); + foreach (DOTweenAnimation anim in anims) AddAnimationToGlobalPreview(anim); + } + if (GUILayout.Button("► Play All in Scene", Styles.btPreview)) { + if (!isPreviewing) StartupGlobalPreview(); + // DOTweenAnimation[] anims = Object.FindObjectsOfType(); // OBSOLETE + DOTweenAnimation[] anims = DeEditorCompatibilityUtils.FindObjectsOfType(); + foreach (DOTweenAnimation anim in anims) AddAnimationToGlobalPreview(anim); + } + EditorGUI.EndDisabledGroup(); + GUILayout.EndHorizontal(); + // Preview - Stop + GUILayout.BeginHorizontal(); + EditorGUI.BeginDisabledGroup(!isPreviewingThis); + if (GUILayout.Button("■ Stop", Styles.btPreview)) { + if (_AnimationToTween.ContainsKey(src)) StopPreview(_AnimationToTween[src].tween); + } + EditorGUI.EndDisabledGroup(); + EditorGUI.BeginDisabledGroup(!isPreviewing); + if (GUILayout.Button("■ Stop All on GameObject", Styles.btPreview)) { + StopPreview(src.gameObject); + } + if (GUILayout.Button("■ Stop All in Scene", Styles.btPreview)) { + StopAllPreviews(); + } + EditorGUI.EndDisabledGroup(); + GUILayout.EndHorizontal(); + if (isPreviewing) { + int playingTweens = 0; + int completedTweens = 0; + int pausedTweens = 0; + foreach (KeyValuePair kvp in _AnimationToTween) { + Tween t = kvp.Value.tween; + if (t.IsPlaying()) playingTweens++; + else if (t.IsComplete()) completedTweens++; + else pausedTweens++; + } + GUILayout.Label("Playing Tweens: " + playingTweens, Styles.previewStatusLabel); + GUILayout.Label("Completed Tweens: " + completedTweens, Styles.previewStatusLabel); +// GUILayout.Label("Paused Tweens: " + playingTweens); + } + GUILayout.EndVertical(); + + return isPreviewing; + } + +#if !(UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5) + public static void StopAllPreviews(PlayModeStateChange state) + { + StopAllPreviews(); + } +#endif + + public static void StopAllPreviews() + { + _TmpKeys.Clear(); + foreach (KeyValuePair kvp in _AnimationToTween) { + _TmpKeys.Add(kvp.Key); + } + StopPreview(_TmpKeys); + _TmpKeys.Clear(); + _AnimationToTween.Clear(); + + DOTweenEditorPreview.Stop(); +#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 + UnityEditor.EditorApplication.playmodeStateChanged -= StopAllPreviews; +#else + UnityEditor.EditorApplication.playModeStateChanged -= StopAllPreviews; +#endif +// EditorApplication.playmodeStateChanged -= StopAllPreviews; + + InternalEditorUtility.RepaintAllViews(); + } + +#endregion + +#region Methods + + static void StartupGlobalPreview() + { + DOTweenEditorPreview.Start(); +#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 + UnityEditor.EditorApplication.playmodeStateChanged += StopAllPreviews; +#else + UnityEditor.EditorApplication.playModeStateChanged += StopAllPreviews; +#endif +// EditorApplication.playmodeStateChanged += StopAllPreviews; + } + + static void AddAnimationToGlobalPreview(DOTweenAnimation src) + { + if (!src.isActive) return; // Ignore sources whose tweens have been set to inactive + if (_previewOnlyIfSetToAutoPlay && !src.autoPlay) return; + + Tween t = src.CreateEditorPreview(); + if (t == null) return; + _AnimationToTween.Add(src, new TweenInfo(src, t, src.isFrom)); + // Tween setup + DOTweenEditorPreview.PrepareTweenForPreview(t); + } + + static void StopPreview(GameObject go) + { + _TmpKeys.Clear(); + foreach (KeyValuePair kvp in _AnimationToTween) { + if (kvp.Key.gameObject != go) continue; + _TmpKeys.Add(kvp.Key); + } + StopPreview(_TmpKeys); + _TmpKeys.Clear(); + + if (_AnimationToTween.Count == 0) StopAllPreviews(); + else InternalEditorUtility.RepaintAllViews(); + } + + static void StopPreview(Tween t) + { + TweenInfo tInfo = null; + foreach (KeyValuePair kvp in _AnimationToTween) { + if (kvp.Value.tween != t) continue; + tInfo = kvp.Value; + _AnimationToTween.Remove(kvp.Key); + break; + } + if (tInfo == null) { + Debug.LogWarning("DOTween Preview ► Couldn't find tween to stop"); + return; + } + if (tInfo.isFrom) { + int totLoops = tInfo.tween.Loops(); + if (totLoops < 0 || totLoops > 1) { + tInfo.tween.Goto(tInfo.tween.Duration(false)); + } else tInfo.tween.Complete(); + } else tInfo.tween.Rewind(); + tInfo.tween.Kill(); + EditorUtility.SetDirty(tInfo.animation); // Refresh views + + if (_AnimationToTween.Count == 0) StopAllPreviews(); + else InternalEditorUtility.RepaintAllViews(); + } + + // Stops while iterating inversely, which deals better with tweens that overwrite each other + static void StopPreview(List keys) + { + for (int i = keys.Count - 1; i > -1; --i) { + DOTweenAnimation anim = keys[i]; + TweenInfo tInfo = _AnimationToTween[anim]; + if (tInfo.isFrom) { + int totLoops = tInfo.tween.Loops(); + if (totLoops < 0 || totLoops > 1) { + tInfo.tween.Goto(tInfo.tween.Duration(false)); + } else tInfo.tween.Complete(); + } else tInfo.tween.Rewind(); + tInfo.tween.Kill(); + EditorUtility.SetDirty(anim); // Refresh views + _AnimationToTween.Remove(anim); + } + } + +#endregion + + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + // ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████ + // █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████ + + class TweenInfo + { + public DOTweenAnimation animation; + public Tween tween; + public bool isFrom; + public TweenInfo(DOTweenAnimation animation, Tween tween, bool isFrom) + { + this.animation = animation; + this.tween = tween; + this.isFrom = isFrom; + } + } + + static class Styles + { + static bool _initialized; + + public static GUIStyle previewBox, previewLabel, btOption, btPreview, previewStatusLabel; + + public static void Init() + { + if (_initialized) return; + + _initialized = true; + + previewBox = new GUIStyle(GUI.skin.box).Clone().Padding(1, 1, 0, 3) + .Background(DeStylePalette.squareBorderCurved_darkBorders).Border(7, 7, 7, 7); + previewLabel = new GUIStyle(GUI.skin.label).Clone(10, FontStyle.Bold).Padding(1, 0, 3, 0).Margin(3, 6, 0, 0).StretchWidth(false); + btOption = DeGUI.styles.button.bBlankBorderCompact.MarginBottom(2).MarginRight(4); + btPreview = EditorStyles.miniButton.Clone(Format.RichText); + previewStatusLabel = EditorStyles.miniLabel.Clone().Padding(4, 0, 0, 0).Margin(0); + } + } + } +} diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs.meta b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs.meta new file mode 100644 index 0000000..53780cc --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPreviewManager.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22292a5f27a9a644ba9e6ad1bf863531 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef new file mode 100644 index 0000000..086d099 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef @@ -0,0 +1,11 @@ +{ + "name": "DOTweenPro.EditorScripts", + "references": [ + "DOTween.Modules", + "DOTweenPro.Scripts" + ], + "includePlatforms": [ + "Editor" + ], + "autoReferenced": false +} diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef.meta b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef.meta new file mode 100644 index 0000000..e60b065 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenPro.EditorScripts.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b79b05b376d4f2240b9397472b1f0341 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML new file mode 100644 index 0000000..ad80aef --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML @@ -0,0 +1,18 @@ + + + + DOTweenProEditor + + + + + Custom colors + + + + + Needs to be overridden in order to initialize new styles added from inherited classes + + + + diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML.meta b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML.meta new file mode 100644 index 0000000..f37a133 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.XML.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 753a4f4ed73b17143923101226957756 +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll new file mode 100644 index 0000000000000000000000000000000000000000..27b6bea17bfc386d0be23c572f43110e3774b2fd GIT binary patch literal 35840 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%0DCoH940D04;m%> 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 Demigiant > DOTween Utility Panel) if it doesn't open automatically, then press "Setup DOTween...": this will run the upgrade setup +4) From the Add/Remove Modules panel that opens, activate/deactivate Modules for Unity systems and for external assets (like TextMesh Pro) + +// GET STARTED ////////////////////////////////////////////// + +- After importing a new DOTween update, select DOTween's Utility Panel from the "Tools/Demigiant" menu (if it doesn't open automatically) and press the "Setup DOTween..." button to activate/deactivate Modules. You can also access a Preferences Tab from there to choose default settings for DOTween. + +// VISUAL SCRIPTING (PRO ONLY) +- To animate a gameObject, select it and choose "Add Component > DOTween > DOTween Animation" +- To animate a gameObject along a path, select it and choose "Add Component > DOTween > DOTween Path" + +// SCRIPTING +- In your code, add "using DG.Tweening" to each class where you want to use DOTween. +- You're ready to tween. Check out the links below for full documentation and license info. + + +// LINKS /////////////////////////////////////////////////////// + +DOTween website (documentation, examples, etc): http://dotween.demigiant.com +DOTween license: http://dotween.demigiant.com/license.php +DOTween repository (Google Code): https://code.google.com/p/dotween/ +Demigiant website (documentation, examples, etc): http://www.demigiant.com + +// NOTES ////////////////////////////////////////////////////// + +- DOTween's Utility Panel can be found under "Tools > Demigiant > DOTween Utility Panel" and also contains other useful options, plus a tab to set DOTween's preferences \ No newline at end of file diff --git a/Assets/Plugins/Demigiant/DOTweenPro/readme.txt.meta b/Assets/Plugins/Demigiant/DOTweenPro/readme.txt.meta new file mode 100644 index 0000000..6a87c35 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/readme.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: aa8f07903bf128e44a7d0b91a63dedab +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib.meta b/Assets/Plugins/Demigiant/DemiLib.meta new file mode 100644 index 0000000..edcf2cc --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib.meta @@ -0,0 +1,21 @@ +fileFormatVersion: 2 +guid: 5a499e4809836274eb38cd99b370a2c1 +labels: +- Tween +- Tweening +- Animation +- HOTween +- Paths +- iTween +- DFTween +- LeanTween +- Ease +- Easing +- Shake +- Punch +- 2DToolkit +- TextMeshPro +- Text +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core.meta b/Assets/Plugins/Demigiant/DemiLib/Core.meta new file mode 100644 index 0000000..86e5075 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 03513cf143bb144409fbb3a51ec77b1b +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll new file mode 100644 index 0000000000000000000000000000000000000000..1024e34ba693244779b3101accb96e39de50cc32 GIT binary patch literal 14848 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 az3)~}g7JS12CzNDrjIA~pRYf;2>d7gZ~LeK literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll.meta b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll.meta new file mode 100644 index 0000000..1ed9199 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 54be29b67d0d29a478da2c6e5c62f091 +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml new file mode 100644 index 0000000..6322fe3 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml @@ -0,0 +1,231 @@ + + + + DemiLib + + + +

+ Class attribute + Sets the script execution order index + + + + + Sets the script execution order for this class + + Script execution order index + + + + Set when calling DeGUI.BeginGUI + + + + + Stores a color palette, which can be passed to default DeGUI layouts when calling DeGUI.BeginGUI, + and changed at any time by calling DeGUI.ChangePalette. + You can inherit from this class to create custom color palettes with more hColor options. + + + + + Converts a HEX color to a Unity Color and returns it + + The HEX color, either with or without the initial # (accepts both regular and short format) + + + + Global colors + + + + + Background colors + + + + Editor background color + + + + Content colors + + + + + Toggle button specific colors + + + + + Various Input utils + + + + + Returns a number key int if a number key was pressed in this frame, or -1 otherwise + + + + + + Extend this to replicate Unity's Scope system with any Unity version. + Thanks to Dmitriy Yukhanov for pointing this out and creating an initial version. + Expand this class to create scopes. + Example: + public class VBoxScope : DeScope + { + public VBoxScope(GUIStyle style) + { + BeginVBox(style); + } + + protected override void CloseScope() + { + EndVBox(); + } + } + Usage: + using (new VBoxScope(myStyle) { + // Do something + } + + + + + Contains both free and pro skins color variations, + and automatically returns the correct one when converted to Color + + + + + Used by DeHierarchy + + + + + Returns a list of all items whose gameObject is NULL, or NULL if there's no missing gameObjects. + + + + + If the item exists sets it, otherwise first creates it and then sets it + + + + + If the item exists sets it, otherwise first creates it and then sets it + + + + + If the item exists sets it, otherwise first creates it and then sets it + + + + + Returns TRUE if the item existed and was removed. + + + + + Returns TRUE if the item existed and was changed. + + + + + Returns the customizedItem for the given gameObject, or NULL if none was found + + + + + Returns the color corresponding to the given + + + + Must be univocal + + + Node position in editor GUI + + + Ids of all forward connected nodes. Length indicates how many forward connections are allowed. + Min length represents available connections from node. + + + + A serializable struct including a min and a max int value + + + + Min value + + + Max value + + + + Creates a new Range + + + + + Returns a random value within this range (min/max included) + + + + + + + + A serializable struct including a min and a max float value + + + + Min value + + + Max value + + + + Creates a new Range + + + + + Returns a random value within this range (min/max included) + + + + + + + + Returns ONLY the Components in the children, and ignores the parent. + + If TRUE also includes inactive children + + + + Returns the Component only if it's in a child, and ignores the parent. + + If TRUE also searches inactive children + + + + Returns a HEX version of the given Unity Color, without the initial # + + If TRUE, also converts the alpha value and returns a hex of 8 characters, + otherwise doesn't and returns a hex of 6 characters + + + + Returns a HEX version of the given Unity Color, without the initial # + + If TRUE, also converts the alpha value and returns a hex of 8 characters, + otherwise doesn't and returns a hex of 6 characters + + + diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml.meta b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml.meta new file mode 100644 index 0000000..473a9b5 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.xml.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 9bf2564c9817bb34988453ae948954d2 +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor.meta new file mode 100644 index 0000000..11f8e33 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 77fbbad1c51d68f4c844d26743104b07 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll new file mode 100644 index 0000000000000000000000000000000000000000..8012e1eee8db06fdc5df33d30ee83bab5105ac9e GIT binary patch literal 193536 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll.meta new file mode 100644 index 0000000..aa20ddf --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: 202f9ddaf2c1a8a429504f7f3cd7b84f +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 0 + settings: {} + Editor: + enabled: 1 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml new file mode 100644 index 0000000..a3452ab --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml @@ -0,0 +1,2370 @@ + + + + DemiEditor + + + + + Utils to use the correct method based on Unity's version + + + + + Encodes to PNG using reflection to use correct method depending if editor is version 2017 or earlier + + + + + Returns the prefab parent by using different code on Unity 2018 or later + + + + + Starts an editor coroutine. You can't use normal yield new WaitFor methods because + those are Unity runtime, but you can instead use . + Other than that, you can use normal yield null/etc. + Returns an (which you can use with to cancel the coroutine), + or NULL in case the coroutine completed immediately. + + + + + Stops the given coroutine generated by + + + + + To be used inside a coroutine as a yield instruction: waits for the given seconds + (replaces Unity's yield new WaitForSeconds because it's not available in-editor). + Example usage: + yield return DeEditorCoroutines.WaitForSeconds(1); + + + + + File utils + + + + Path slash for AssetDatabase format + + + Path slash to replace for AssetDatabase format + + + Current OS path slash + + + Path slash to replace on current OS + + + + Full path to project directory, without final slash. + + + + + Full path to project's Assets directory, without final slash. + + + + + Returns TRUE if the given path is an absolute path + + + + + Returns TRUE if the given path is an AssetDatabase path + + + + + Returns TRUE if the given GUID refers to a valid and existing project folder + + + + + Converts the given project-relative path to a full path + + + + + Converts the given full path to a project-relative path + + + + + Returns TRUE if the file/directory at the given path exists. + + Path, relative to Unity's project folder + + + + Validates the string as a valid fileName + (uses commonly accepted characters an all systems instead of system-specific ones). + BEWARE: doesn't check for reserved words + + string to replace + Minimum length for considering the string valid + + + + Returns TRUE if the given filepath is within this Unity project Assets folder + + Full file path + + + + Returns the given string stripped of any invalid filename characters. + BEWARE: doesn't check for reserved words + + string to replace + Character to use as replacement for invalid ones + + + + Returns the given path with all slashes converted to the correct ones used by the system + + + + + Returns the asset path of the given GUID (relative to Unity project's folder), + or an empty string if either the GUID is invalid or the related path doesn't exist. + + + + + Checks if the given directory (full path) is empty or not + + + + + Deletes all files and subdirectories from the given directory + + + + Returns the adb path to the given ScriptableObject + + + Returns the adb path to the given MonoBehaviour + + + Returns the adb directory that contains the given ScriptableObject without final slash + + + Returns the adb directory that contains the given MonoBehaviour without final slash + + + + Returns the adb paths to the selected folders in the Project panel, or NULL if there is none. + Contrary to Selection.activeObject, which only returns folders selected in the right side of the panel, + this method also works with folders selected in the left side. + + + + + Sets the script execution order of the given MonoBehaviour + + + + + Gets the script execution order of the given MonoBehaviour + + + + + Precisely returns the last controlId assigned to a GUI element + + + + + Framework used to fix missing monoScript reference in GameObjects when a script's meta guid changes + + + + + Retrieves the GUID in the given meta file and returns it, or NULL if it's not found + + Full filePath to the meta file + + + + Fixes all wrong Component GUIDs in scenes and prefabs + + objects to use for the operation + + + + Fixes all wrong Component GUIDs in the active scene and returns the total number of Components fixed + + objects to use for the operation + + + + Finds all MonoBehaviour/Behaviour/Component in the given scene/prefab file string + that contain the given + and replaces their GUID with the one passed (if different). + Returns the total number of Component GUIDs that were fixed + + + + + Dispatched when Unity has finished compiling code and updating the AssetDatabase + + + + + Utils to manage UnityPackages import/export and file mirroring + + + + + Stores all file paths (excluding metas) found in the given AssetDatabase directory and subdirectory + into the given AssetDatabase file (which will be created if missing), + writing them as relative to the given directory. + EXAMPLE: + adbReadFromDirPath = "Plugins/DOTween" + file "Assets/Plugins/DOTween/aScript.cs" stored as "aScript.cs" + file "Assets/Plugins/DOTween/Subdir/aScript.cs" stored as "Subdir/aScript.cs" + + + AssetDatabase path ("Assets/...") where the list should be written + AssetDatabase path ("Assets/...") from which the list of files should be retrieved, without final slash + If TRUE ignores ASMDEF files + + + + Parses a file list created via and removes any files not present in the list from the given directory + + Label to use when logging the result + AssetDatabase path ("Assets/...") to the file containing the list + AssetDatabase path ("Assets/...") to the directory to parse for extra files to remove + If TRUE ignores ASMDEF files + If TRUE only returns a report log and doesn't actually delete the files + + + + Utilities for Editor Panels. + + + + + Connects to a asset. + If the asset already exists at the given path, loads it and returns it. + Otherwise, depending on the given parameters, either returns NULL or automatically creates it before loading and returning it. + + Asset type + File path (relative to Unity's project folder) + If TRUE and the requested asset doesn't exist, forces its creation + If TRUE also creates the path folders if they don't exist + + + + Check if the at the given path exists and eventually if it's available + + File path (relative to Unity's project folder) + If TRUE also check if the file is available + (file can be unavailable if it was deleted outside Unity, or if Unity is just starting) + + + + + Returns TRUE if the given is dockable, FALSE if instead it's a utility window + + + + + + + Sets the icon and title of an editor window. Works with older versions of Unity, where the titleContent property wasn't available. + + Reference to the editor panel whose icon to set + Icon to apply + Title. If NULL doesn't change it + + + + Repaints the currently focues editor + + + + + Prefab utilities + + + + + Behaves as the Inspector's Apply button, applying any modification of this instance to the prefab parent + + + + + + Returns TRUe if a prefab instance has unapplied modifications, ignoring any modifications applied to the transform. + NOTE: this a somehow costly operation (since it generates GC) + + + + + Completely removes any prefab connection from the given prefab instances, by desotroing the original object and recreating it. + Returns a list with all the new elements created. + + Based on RodGreen's method (http://forum.unity3d.com/threads/82883-Breaking-connection-from-gameObject-to-prefab-for-good.?p=726602&viewfull=1#post726602) + + + + + + Completely removes any prefab connection from the given prefab instance, by desotroing the original object and recreating it. + + Based on RodGreen's method (http://forum.unity3d.com/threads/82883-Breaking-connection-from-gameObject-to-prefab-for-good.?p=726602&viewfull=1#post726602) + + + + + Returns TRUE if Unity editor is neither compiling code nor updating assets + + + Calls the given action after the given delay + + + + Return the size of the editor game view, eventual extra bars excluded (meaning the true size of the game area) + + + + + Returns a value from 1 to N (2 for 200% scaling) indicating the UI Scaling of Unity's editor. + The first time this is called it will store the scaling and keep it without refreshing, + since you need to restart Unity in order to apply a scaling change + + + + + Clears all logs from Unity's console + + + + + Adds the given global define (if it's not already present) to all the + or only to the given , depending on passed parameters, + and returns TRUE if it was added, FALSE otherwise. + NOTE: when adding to all of them some legacy warnings might appear, which you can ignore. + + + to use. Leave NULL to add to all of them. + + + + Adds the given list of global defines (if they're not already present) to all the + or only to the given , depending on passed parameters, + and returns TRUE if it was added, FALSE otherwise. + NOTE: when adding to all of them some legacy warnings might appear, which you can ignore. + + Defines to add + to use. Leave NULL to add to all of them. + + + + Removes the given global define (if present) from all the + or only from the given , depending on passed parameters, + and returns TRUE if it was removed, FALSE otherwise. + NOTE: when removing from all of them some legacy warnings might appear, which you can ignore. + + + to use. Leave NULL to remove from all of them. + + + + Removes the given global defines (if present) from all the + or only from the given , depending on passed parameters, + and returns TRUE if it was removed, FALSE otherwise. + NOTE: when removing from all of them some legacy warnings might appear, which you can ignore. + + Defines to remove + to use. Leave NULL to remove from all of them. + + + + Returns TRUE if the given global define is present in at least one of the + or only in the given , depending on passed parameters. + + + to use. Leave NULL to check in all of them for the first occurrence. + + + + Returns an array of all defines in the current . + + + + + Sets the gizmos icon visibility in the Scene and Game view for the given class names + + Visibility + Class names (no namespace), as many as you want separated by a comma + + + + Sets the gizmos icon visibility in the Scene and Game view for all custom icons + (for example icons created with HOTools) + + Visibility + + + + Returns all components of type T in the currently open scene, or NULL if none could be found. + If you're on Unity 5 or later, and have DeEditorTools, use DeEditorToolsUtils.FindAllComponentsOfType + instead, which is more efficient. + + + + + Shifts an item from an index to another, without modifying the list except than by moving elements around + + + + + Expands the given array and adds the given element as the last one + + + + + Removes the element at index from the given array, shifts everything after by -1 position and resizes the array + + + + Nothing is being dragged + + + Dragging + + + Dragging concluded and accepted + + + Dragging concluded but item position didn't change + + + Dragging canceled + + + Dragging concluced but not accepted because too short + + + Automatically determines if dragged elements are horizontal, vertical, or both + + + Forces vertical drag + + + Forces horizontal drag (useful to avoid initial wrong drag indicators + if the users starts dragging an horizontal system vertically) + + + + Manages the dragging of GUI elements + + + + + True if a GUI element is currently being dragged + + + + + Return the current item being dragged, or NULL if there is none + + + + + Type of current item being dragged, or NULL if there is none + + + + + Starting index of current item being dragged, or NULL if there is none + + + + + Retrieves the eventual optional data stored via the StartDrag method + + + + + Starts a drag operation on a GUI element. + + Reference to the current editor drawing the GUI (used when a Repaint is needed) + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Optional data that can be retrieved via the static property + + + + Starts a drag operation on a GUI element. + + ID for this drag operation (must be the same for both StartDrag and Drag + Reference to the current editor drawing the GUI (used when a Repaint is needed) + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Optional data that can be retrieved via the static property + + + + Starts a drag operation on a GUI element. + + Reference to the current editor drawing the GUI (used when a Repaint is needed) + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Optional data that can be retrieved via the static property + + + + Starts a drag operation on a GUI element. + + ID for this drag operation (must be the same for both StartDrag and Drag + Reference to the current editor drawing the GUI (used when a Repaint is needed) + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Optional data that can be retrieved via the static property + + + + Call this after each draggable GUI block, to calculate and draw the current drag state + (or complete it if the mouse was released). + + ID for this drag operation (must be the same for both StartDrag and Drag + List containing the draggable item and all other relative draggable items + Current index of the draggable item being drawn + If NULL will calculate this automatically using . + Pass this if you're creating a drag between elements that don't use GUILayout + Drag direction. You can leave it to + unless you want to skip eventual layout calculations + If TRUE (default) automatically reorders the given list + to reflect successful drag results. + Note that will be different if you apply the drag to the list or not + (in the former case it will reflect the current index after the change, in the latter it will reflect the desired position) + + + + Call this after each draggable GUI block, to calculate and draw the current drag state + (or complete it if the mouse was released). + + List containing the draggable item and all other relative draggable items + Current index of the draggable item being drawn + If NULL will calculate this automatically using . + Pass this if you're creating a drag between elements that don't use GUILayout + Drag direction. You can leave it to + unless you want to skip eventual layout calculations + If TRUE (default) automatically reorders the given list + to reflect successful drag results. + Note that will be different if you apply the drag to the list or not + (in the former case it will reflect the current index after the change, in the latter it will reflect the desired position) + + + + Call this after each draggable GUI block, to calculate and draw the current drag state + (or complete it if the mouse was released). + + ID for this drag operation (must be the same for both StartDrag and Drag + List containing the draggable item and all other relative draggable items + Current index of the draggable item being drawn + Color to use for drag divider and selection + If NULL will calculate this automatically using . + Pass this if you're creating a drag between elements that don't use GUILayout + Drag direction. You can leave it to + unless you want to skip eventual layout calculations + If TRUE (default) automatically reorders the given list + to reflect successful drag results. + Note that will be different if you apply the drag to the list or not + (in the former case it will reflect the current index after the change, in the latter it will reflect the desired position) + + + + Call this after each draggable GUI block, to calculate and draw the current drag state + (or complete it if the mouse was released). + + List containing the draggable item and all other relative draggable items + Current index of the draggable item being drawn + Color to use for drag divider and selection + If NULL will calculate this automatically using . + Pass this if you're creating a drag between elements that don't use GUILayout + Drag direction. You can leave it to + unless you want to skip eventual layout calculations + If TRUE (default) automatically reorders the given list + to reflect successful drag results. + Note that will be different if you apply the drag to the list or not + (in the former case it will reflect the current index after the change, in the latter it will reflect the desired position) + + + + Ends the drag operations, and eventually applies the drag outcome. + Returns TRUE if the position of the dragged item actually changed. + Called automatically by Drag method. Use it only if you want to force the end of a drag operation. + + If TRUE marks the drag as successful and applied it if set so, otherwise simply cancels the drag + If TRUE changes the list contents to reflect the drag result + + + + Abstract dynamic class used for every node of the same type + (meaning there is only a single recycled instance for all same-type nodes) + + + + Used to fill + + + Called when the node needs to be drawn + + + + The connectedNodesIds list will be automatically increased/decreased when adding/removing connections + (otherwise connectedNodesIds will have to be increased via custom code) + + + + + Requires only two connectedNodesIds (no more, no less), + uses regular CTRL+Drag to connect connection 0, CTRL+SPACE+Drag to connect connection 1 + + + + + Like , but with an extra connection as a last extra index, which is set when pressing CTRL+SPACE+Drag. + Must always have at least one element in connectedNodesIds + + + + Layout, Repaint, LayoutAndRepaint + + + + Stores cloned nodes for pasting + + + + + Returns a list of pasteable nodes, with their GUID recreated and their connections adapted + + + + + + Returns a deep clone of the given node but doesn't clone UnityEngine references. + A new ID will be automatically generated. + + + + + Always connects a node from BottomOrRight side to TopOrLeft side + + + + + Always connects from BottomOrRight side to TopOrLeft side. + If ALT is pressed shows the delete connection button. + Called during Repaint or MouseDown/Up. + Returns TRUE if the connection was deleted using the delete connection button. + + + + + Always connects a node from BottomOrRight side to TopOrLeft side + + + + + Always connects from BottomOrRight side to TopOrLeft side. + If ALT is pressed shows the delete connection button. + Called during Repaint or MouseDown/Up. + Returns TRUE if the connection was deleted using the delete connection button. + + + + + You can attach to this + + + + + Use this to add a content group to the Help Panel + + + + Regular note + + + Editable note (activated by setting to TRUE + (but you will have to save the result somewhere yourself) + + + If TRUE shows the textArea + + + + Add definition. Supports rich-text but also these special tags: + - [b][/b] + + + + + Add key, automatically formatting these special keys: + / + + + → + + If TRUE and there's other keys/targets, adds the new key on a new line preceded by a comma + + + + Recalculates all rects based on the given Y shift + + + + + One per . + Partially independent, mainly controlled by process. + + + + TRUE when read-to or dragging nodes + + + + Resets the interaction state + + + + Returns TRUE if the given node is currently being dragged + + + + Returns TRUE if a repaint is required + + + + + + Main class for DeGUI Node system. + Create it, then enclose your GUI node calls inside a . + CODING ORDER: + - Create a to use for your node system (create it once, obviously) + - Inside OnGUI, write all your nodes GUI code inside a + - To draw the nodes, loop through the list and call for each node + + + + Distance at which nodes will be placed when snapping next to each other + + + Full area without zeroed coordinates + + + Position with zeroed coordinates (used by all node GUI since it's inside a GUILayout(area)) + + + Contains the nodes passed to NodeProcessScope ordered by depth. + You should loop through this list when drawing nodes + + + + Creates a new NodeProcess. + + EditorWindow for this process + Callback called when one or more nodes are going to be deleted. + Return FALSE if you want the deletion to be canceled. + Can be NULL, in which case it will be ignored + Callback called when a node is cloned. + Return FALSE if you want the cloning to be canceled. + Can be NULL, in which case it will be ignored + + + + Needs to be called when loading a complete new series of nodes + + + + + Call this when the layout/size of one or more nodes changed because of external intervention + (if a whole new range of nodes has been loaded, just call instead) + + + + + Forces the refresh of the area calculations. Useful if you need them before the first GUI call has run + + + + + Shifts the visible are to the given coordinates and repaints on end + + + + + Shifts the visible are to the given coordinates and repaints on end + + + + + Tells the process to repaint once the process has ended. + Calling this + + + + + Draws the given node using the given T editor GUINode type. + Returns the full area of the node + + + + + Opens the Help Panel + + + + + Closes the Help Panel + + + + + Opens or closes the Help panel based on its current state + + + + + Returns TRUE if the given area is visible (even if partially) inside the current nodeProcess area + + + + + Captures a screenshot of the node editor area and returns it when calling the onComplete method. + Sadly this requires a callback because if called immediately the capture will fail + with a "[d3d11] attempting to ReadPixels outside of RenderTexture bounds!" error in most cases + + Screenshot mode + A callback that accepts the generated Texture2D object + Screenshot scale factor (only used if screenshotMode is set to ) + If TRUE (default) displays a progress bar during the operation. + You'll want to set this to FALSE when you're already using a custom progressBar + and the screenshot is only part of a larger queue of operations + + + + Removes the node with the given ID from the list and removes all connections to it from other nodes. + Doesn't mark things dirty nor prepares them for undo + + + + + Use this to encapsulate node GUI operations. + Automatically manages various operations (press F1 to see them). + Sets GUI.changed to TRUE if the area is panned, a node is dragged, controlNodes change sorting or are deleted. + Wraps all content inside a GUILayout Area (nodeArea). + + The to use + Area within which the nodes will be drawn + Area shift (caused by dragging) + This list will be sorted based on current node draw order, + and changed in case one of its nodes is deleted. + IMPORTANT: this list should be part of your serialized class (MonoBehaviour or ScriptableObject), + so it will be stored as a reference and modifying one will modify the other. + Usually you want to pass all nodes to this except the eventual start node (or nodes that can't be sorted nor deleted). + + + + Set automatically when a selection ends up selecting a single node, + reset when deselecting all nodes, selecting multiple nodes, or resetting the + + + + + Returns TRUE if something was actually deselected, FALSE if there were no selected nodes + + + + + + Returns key modifiers currently pressed. + Requires to be updated at the beginning of every GUI call. + + + + Note: ALT isn't correctly interpreted as OPTION on OSX, contrary to what Unity manual states, + so using Command instead fixes that + + + + Call this method to update data required by softCtrl calculations. + Automatically called from within a . + Returns a object with the keys that were just pressed and just released + + Required to have the correct for the given target call + + + + Returns the given as an int, or -1 if it's not a number + + + + + Used code from Celtc on StackOverflow: https://stackoverflow.com/a/54044197/10151925 + + + + + Gets all fields from an object and its hierarchy inheritance + + + + + Perform a deep copy of the class + + + + + Does the copy + + + + + Returns by . + Contains properties and methods to manage non-layout scrollview better. + Remember to use or to increase or set the full content height + + + + Area used by ScrollView and its content + + + Full content area regardless if visible or not. Its height should be set manually based on the contents' height + + + Content area currently visible (scroll bars excluded) + + + Current scrollPosition + + + + Returns the current open, or an empty one if none is open. + + + + + Sets the width + + + + + Sets the height + + + + + Increase the height by the given amount + + + + + + Returns a Rect for a single line at the current scrollView yMax + + If less than 0 uses default line height, otherwise the value passed + if TRUE (default) automatically increases the height of the accordingly + + + + + Returns a Rect for a single line at the current scrollView yMax, as wide as the max visible rect width + + If less than 0 uses default line height, otherwise the value passed + if TRUE (default) automatically increases the height of the accordingly + + + + + Returns TRUE if the given rect is at least partially visible in the displayed scroll area + + + + + Contains both free and pro skins GUIStyle variations, + and automatically returns the correct one when converted to GUIStyle + + + + + Plays the given clip in the Editor + + + + + Stops playing the given clip. + + + + + Stops all clips playing. + + + + + A stopwatch whose time can be changed manually via + + + + + Start or resume playing + + + + + Stop the watch and reset the time + + + + + Restart measuring from zero + + + + + Pause the watch + + + + + Send the watch to the given time + + + + + Util to determine Unity editor version and store them as comparable numbers + + + + Full major version + first minor version (ex: 2018.1f) + + + Major version + + + First minor version (ex: in 2018.1 it would be 1) + + + + Assembly extensions + + + + + Full path to the assembly directory, without final slash + + + + + AssetDatabase path to the assembly directory, without final slash + + + + + GUI extension methods + + + + + Clones the style and adds the given formats to it. You can pass any of these types of values: + + Format:Rich-text, wordwrap + FontStyle:Font style + TextAnchor:Content anchor + int:Font size + Color/DeSkinColor:Font color + + + + + + Adds the given formats to the style. You can pass any of these types of values: + + Format:RichText, WordWrap + FontStyle:Font style + TextAnchor:Content anchor + int:Font size + Color/DeSkinColor:Font color + + + + + + Sets the border of the style + + + + + Sets the border of the style + + + + + Sets the border of the style + + + + + Sets the background of the style + + + + + Sets the background of the style + + + + + Sets the contentOffset of the style + + + + + Sets the contentOffset of the style + + + + + Sets the X contentOffset of the style + + + + + Sets the Y contentOffset of the style + + + + + Sets the margin of the style + + + + + Sets the margin of the style + + + + + Sets the margin of the style + + + + + Sets the left margin of the style + + + + + Sets the right margin of the style + + + + + Sets the top margin of the style + + + + + Sets the bottom margin of the style + + + + + Sets the overflow of the style + + + + + Sets the overflow of the style + + + + + Sets the overflow of the style + + + + + Sets the left overflow of the style + + + + + Sets the right overflow of the style + + + + + Sets the top overflow of the style + + + + + Sets the bottom overflow of the style + + + + + Sets the padding of the style + + + + + Sets the padding of the style + + + + + Sets the padding of the style + + + + + Sets the left padding of the style + + + + + Sets the right padding of the style + + + + + Sets the top padding of the style + + + + + Sets the bottom padding of the style + + + + + Sets the Y fixedWidth of the style + + + + + Sets the fixedHeight of the style + + + + + Sets the stretchHeight property of the style + + + + + Sets the stretchWidth property of the style + + + + + Stores a GUIStyle palette, which can be passed to default DeGUI layouts when calling DeGUI.BeginGUI, + and changed at any time by calling DeGUI.ChangePalette. + You can inherit from this class to create custom GUIStyle palettes with more options. + Each of the sub-options require a public Init method to initialize the styles, which will be called via Reflection. + + + + + Called automatically by DeGUI.BeginGUI. + Override when adding new style subclasses. + Returns TRUE if the styles were initialized or re-initialized + + + + + Extend any custom subpalettes from this, so they will be initialized correctly + + + + + GUILayout methods + + + + + A button that triggers an immediate repaint when hovered/pressed/unhovered + (which otherwise doesn't happen if you set a background to the button's GUIStyle). + Requires to be activated. + + + + + A button that triggers an immediate repaint when hovered/pressed/unhovered + (which otherwise doesn't happen if you set a background to the button's GUIStyle) + and also assigns different GUI colors based on the button's state and the given one. + Requires to be activated. + + Content + Default color + Style + GUILayout options + + + + A button that triggers an immediate repaint when hovered/pressed/unhovered + (which otherwise doesn't happen if you set a background to the button's GUIStyle) + and also assigns different GUI colors based on the button's state with options to eventually auto-generate them. + Requires to be activated. + + Content + Default color + Hover color (if NULL auto-generates it from the given one by making it brighter + Pressed color (if NULL auto-generates it from the given one by making it even brighter + Style + GUILayout options + + + Shaded button + + + Shaded button + + + Shaded button + + + Shaded button + + + Colored button + + + Colored button + + + Colored button + + + Colored button + + + + Draws a button that returns TRUE the first time it's pressed, instead than when its released. + + + + + Draws a button that returns TRUE the first time it's pressed, instead than when its released. + + + + + Draws a button that returns TRUE the first time the mouse moves over it while the mouse button is pressed, + even if it was pressed outside of the button first + + + + + Draws a button that returns TRUE the first time the mouse moves over it while the mouse button is pressed, + even if it was pressed outside of the button first + + + + Toolbar foldout button + + + Toolbar foldout button + + + Toolbar foldout button + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Begins an horizontal toolbar layout + + + Begins an horizontal toolbar layout + + + Begins an horizontal toolbar layout + + + Begins an horizontal toolbar layout + + + Ends an horizontal toolbar layout + + + A toolbar with a label + + + A toolbar with a label + + + A toolbar with a label + + + A toolbar with a label + + + A toolbar with a label + + + A toolbar with a label + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values. Auto-determines object type from the field's type + + + Returns TRUE if there's mixed values. Forces field to accept only objects of the given type + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Vertical box layout with style and color options + + + Vertical box layout with style and color options + + + End vertical box layout + + + Horizontal Divider + + + + A text field that becomes editable only on double-click + + EditorWindow reference + A unique ID to use in order to determine if the text is selected or not + Text + Style for default (non-editing mode) appearance + Style for editing mode + + + + A text field that becomes editable only on double-click + + Editor reference + A unique ID to use in order to determine if the text is selected or not + Text + Style for default (non-editing mode) appearance + Style for editing mode + + + + A text field that becomes editable only on double-click and can also be dragged + + EditorWindow reference + A unique ID to use in order to determine if the text is selected or not + Text + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Style for default (non-editing mode) appearance + Style for editing mode + + + + + A text field that becomes editable only on double-click and can also be dragged + + Editor reference + A unique ID to use in order to determine if the text is selected or not + Text + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Style for default (non-editing mode) appearance + Style for editing mode + + + + + Creates a Gradient field by using Unity 4.x hidden default one and Reflection. + + + + Scene field + + + + Draws a dropdown for choosing a SortingLayer ID + + + + + Draws a dropdown for choosing a SortingLayer ID + + + + + Global Demigiant GUI manager. Call to initialize it inside GUI calls. + + + + + Default color palette + + + + + Default style palette + + + + TRUE if we're using the PRO skin + + + + Call this at the beginning of GUI methods. + Returns TRUE if the styles were initialized or re-initialized + + Eventual to use + Eventual to use + + + + Better implementation of GUI.BeginScrollView. + Returns the modified scrollView struct. + Must be closed by a DeGUI.. +
EXAMPLE
+            Rect scrollViewArea = ...;
+            Rect drawArea = scrollViewArea;
+            // Decrease the full drawing area to exclude scrollbars if necessary
+            if (_scrollView.fullContentArea.height > scrollViewArea.height) drawArea = drawArea.Shift(0, 0, -11, 0);
+            // Begin scrollView
+            _scrollView = DeGUI.BeginScrollView(scrollViewArea, _scrollView);
+            // Increase scrollView area correctly (or directly set it with SetFullContentHeight
+            _scrollView.IncreaseContentHeightBy(...)
+            // End
+            DeGUI.EndScrollView();
+            
+
+ Visible area used by the scrollView + target. You'll need to set its size to the correct full content height + (either within the Begin/ENd ScrollView calls or before them) + If TRUE (default) resets .height to 0 + after beginning the ScrollView +
+ + + Closes a DeGUI. correctly + + + + + Exits the current event correctly, also taking care of eventual drag operations + + + + + Removes focus from any GUI button/text/element that has focus + + + + + Changes the active palettes to the given ones + (or resets them to the default ones if NULL). + Returns TRUE if the styles were initialized or re-initialized + + + + + Resets the GUI colors to the default ones (only available if BeginGUI was called first) + + + + + Sets the GUI colors to the given ones + + + + + Opens a panel that previews the given texture (if not NULL) + + + + + Gets either black or white, depending on the color that would be most visible on the given one + + + + + Gets either black or white, depending on the color that would be most visible on the given one + + + + + Sets the GUI cursor color to the given ones + + + + + Sets the GUI matrix to the given ones + + + + + Wrapper to set serialized fields with multiple sources selected: automatically sets GUI to show mixed values when necessary + and contains a fieldInfo which is set within the wrapper. + Note that you must set the property within the wrapper so that it's assigned correctly when closing the scope. + + + + Multi property scope + Name of the field so it can be found and set/get via Reflection + List of the sources containing the given field + If TRUE validates EditorGUI.EndChangeCheck before calling it + (fixes an issue which happens with advanced Undo usage in DOTween Timeline and ColorFields) + + + + A button that triggers an immediate repaint when hovered/pressed/unhovered + (which otherwise doesn't happen if you apply a background to the button's GUIStyle). + Requires to be activated. + + + + + A button that triggers an immediate repaint when hovered/pressed/unhovered + (which otherwise doesn't happen if you apply a background to the button's GUIStyle) + and also assigns different GUI colors based on the button's state and the given one. + Requires to be activated. + + Rect + Content + Default color + Style + + + + A button that triggers an immediate repaint when hovered/pressed/unhovered + (which otherwise doesn't happen if you apply a background to the button's GUIStyle) + and also assigns different GUI colors based on the button's state with options to eventually auto-generate them. + Requires to be activated. + + Rect + Content + Default color + Hover color (if NULL auto-generates it from the given one by making it brighter + Pressed color (if NULL auto-generates it from the given one by making it even brighter + Style + + + Shaded button + + + Shaded button + + + Shaded button + + + Shaded button + + + Colored button + + + Colored button + + + Colored button + + + Colored button + + + Toolbar foldout button which allows clicking even on its label + + + Foldout button + label (not intended to be used in toolbar) which allows click-to-foldout/foldin + + + + Draws a button that returns TRUE the first time it's pressed, instead than when its released. + + + + + Draws a button that returns TRUE the first time it's pressed, instead than when its released. + + + + + Draws a button that returns TRUE the first time the mouse moves over it while the mouse button is pressed, + even if it was pressed outside of the button first + + + + + Draws a button that returns TRUE the first time the mouse moves over it while the mouse button is pressed, + even if it was pressed outside of the button first + + + + Toolbar foldout button + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Button that can be toggled on and off + + + Scene field + + + + Draws a background grid using the given grid texture + + Area rect + Offset from 0, 0 position (used when area has been dragged) + Texture to use for the grid + Eventual scale to apply to the grid + + + + Draws a background grid using default grid textures + + Area rect + Offset from 0, 0 position (used when area has been dragged) + If TRUE forces a dark skin, otherwise uses a skin that fits with the current Unity's one + Eventual scale to apply to the grid + + + Box with style and color options + + + + Can be used instead of EditorGUI.PropertyField, to draw a serializedProperty without its attributes + (very useful in case you want to use this from within a PropertyDrawer for that same property, + since otherwise bad infinite loops might happen) + + + + Draws a colored square + + + Draws the given texture tiled within the given rect + Rect + Texture + Eventual scale to apply + If not NULL, colorizes the texture with this color + + + + A text field that becomes editable only on double-click + + Area + EditorWindow reference + A unique ID to use in order to determine if the text is selected or not + Text + Style for default (non-editing mode) appearance + Style for editing mode + + + + A text field that becomes editable only on double-click + + Area + Editor reference + A unique ID to use in order to determine if the text is selected or not + Text + Style for default (non-editing mode) appearance + Style for editing mode + + + + A text field that becomes editable only on double-click and can also be dragged + + Area + EditorWindow reference + A unique ID to use in order to determine if the text is selected or not + Text + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Style for default (non-editing mode) appearance + Style for editing mode + + + + A text field that becomes editable only on double-click and can also be dragged + + Area + Editor reference + A unique ID to use in order to determine if the text is selected or not + Text + List containing the dragged item and all other relative draggable items + DraggableList index of the item being dragged + Style for default (non-editing mode) appearance + Style for editing mode + + + + A textArea that becomes editable only on double-click + + Area + EditorWindow reference + A unique ID to use in order to determine if the text is selected or not + Text + Style for default (non-editing mode) appearance + Style for editing mode + + + + A textArea that becomes editable only on double-click + + Area + Editor reference + A unique ID to use in order to determine if the text is selected or not + Text + Style for default (non-editing mode) appearance + Style for editing mode + + + Divider + + + + Draws a dropdown for choosing a SortingLayer ID + + + + + Draws a dropdown for choosing a SortingLayer ID + + + + Draws a Vector3Field that can have single axes disabled + + + Draws a Vector3Field that can have single axes disabled + + + Draws a Vector3Field that can have single axes disabled + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values. Supports using an int as an enum + + + Returns TRUE if there's mixed values. Supports using an int as an enum + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values. Supports also uint fields + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values. Auto-determines object type from the field's type + + + Returns TRUE if there's mixed values. Forces field to accept only objects of the given type + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values. Supports passing int values as bool (1 = true, 0 = false) + + + Returns TRUE if there's mixed values. Supports passing int values as bool (1 = true, 0 = false) + + + Returns TRUE if there's mixed values. Supports passing int values as bool (1 = true, 0 = false) + + + Returns TRUE if there's mixed values. Requires a SerializedProperty representation of each UnityEven field + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + Returns TRUE if there's mixed values + + + + Returns a new color equal to the given one with changed brightness + + Color to evaluate + Brightness factor (multiplied by current brightness) + If set applies this alpha value + + + + Returns a new color equal to the given one with changed saturation + + Color to evaluate + Saturation factor (multiplied by current brightness) + If set applies this alpha value + + + + Changes the alpha of this color and returns it + + + + + Returns a new color equal to the given one with changed alpha + + + + + Returns a HEX version of the given Unity Color, without the initial # + + If TRUE, also converts the alpha value and returns a hex of 8 characters, + otherwise doesn't and returns a hex of 6 characters + + + + Returns a HEX version of the given Unity Color, without the initial # + + If TRUE, also converts the alpha value and returns a hex of 8 characters, + otherwise doesn't and returns a hex of 6 characters + + + + Replicates parts of DeExtensions.ListExtensions for internal usage + + + + + Shifts an item from an index to another, without modifying the list except than by moving elements around + + + + + Shuffles the list + + + + + Replicates DeExtensions.RectExtensions for internal usage + + + + + Adds one rect into another, and returns the resulting a + + + + + Returns a copy or the Rect expanded around its center by the given amount + + Indicates how much to expand the rect on each size + + + + Returns a copy or the Rect expanded around its center by the given amount + + Indicates how much to expand the rect on each horizontal side + Indicates how much to expand the rect on each vertical side + + + + Returns a copy or the Rect contracted around its center by the given amount + + Indicates how much to contract the rect on each size + + + + Returns a copy or the Rect contracted around its center by the given amount + + Indicates how much to contract the rect on each horizontal side + Indicates how much to contract the rect on each vertical side + + + + Returns a copy of the Rect resized so it fits proportionally within the given size limits + + Width to fit + Height to fit + If TRUE (default) only shrinks the rect if needed, if FALSE also enlarges it to fit + + + + + Returns TRUE if the first rect includes the second one + + If TRUE, returns TRUE only if the second rect is fully included, + otherwise just if some part of it is included + + + + Returns TRUE if this rect intersects the given one, and also outputs the intersection area + + Intersection area + + + + Returns a copy of the Rect with its X/Y coordinates set to 0 + + + + + Sets this rect to the left of the given x position, with options for margin and width resize + + Distance between this rect and the given x position + If greater than zero resizes this rect to the given size + + + + Sets this rect to the right of the given x position and resizes it so that its xMax remains the same. + + Distance between this rect and the given x position + Extra offset to add to the resulting width + + + + Returns a copy of the Rect with its values shifted according the the given parameters + + + + + Returns a copy of the Rect with its X value shifted by the given value + + + + + Returns a copy of the Rect with its Y value shifted by the given value + + + + + Returns a copy of the Rect with its x shifted by the given value and its width shrinked/expanded accordingly + (so that the xMax value will stay the same as before) + + + + + Returns a copy of the Rect with its y shifted by the given value and its height shrinked/expanded accordingly + (so that the yMax value will stay the same as before) + + + + + Returns a copy of the Rect with its X property set to the given value + + + + + Returns a copy of the Rect with its Y property set to the given value + + + + + Returns a copy of the Rect with its height property set to the given value + + + + + Returns a copy of the Rect with its width property set to the given value + + + + + Returns a copy of the Rect with its X,Y properties set so the rect center corresponds to the given values + + + + + Returns a copy of the Rect with its X property set so the rect X center corresponds to the given value + + + + + Returns a copy of the Rect with its Y property set so the rect Y center corresponds to the given value + + + + + Returns the value of the given property (works like a cast to type). + Improved from HiddenMonk's functions (http://answers.unity3d.com/questions/627090/convert-serializedproperty-to-custom-class.html) + + + + + Returns TRUE if this property is inside an array + + + + + Returns -1 if the property is not inside an array, otherwise returns its index inside the array + + + + + Returns the height of a UnityEvent serializedProperty + + + + + Uses code from FlaShG's GitMerge: https://github.com/FlaShG/GitMerge-for-Unity/blob/master/Editor/SerializedPropertyExtensions.cs + + + + + Uses code from FlaShG's GitMerge: https://github.com/FlaShG/GitMerge-for-Unity/blob/master/Editor/SerializedPropertyExtensions.cs + + + + + String extensions + + + + + Returns TRUE if the string is null or empty + + If TRUE (default) and the string contains only spaces, considers it empty + + + + Compares a version string (in format #.#.###) with another of the same format, + and return TRUE if this one is minor. Boths trings must have the same number of dot separators. + + + + + Converts a HEX color to a Unity Color and returns it + + The HEX color, either with or without the initial # (accepts both regular and short format) + + + + Nicifies a string, replacing underscores with spaces, and adding a space before Uppercase letters (except the first character) + + + + + If the given string is a directory path, returns its parent + with or without final slash depending on the original directory format + + + + + If the string is a directory, returns the directory name, + if instead it's a file returns its name without extension. + Works better than Path.GetDirectoryName, which kind of sucks imho + + + + + Evaluates the string as a property or field and returns its value. + + If NULL considers the string as a static property, otherwise uses obj as the starting instance + + + + Texture extensions + + + + + Returns the full Rect of this texture, with options for position and scale + + + + + Checks that the texture uses the correct import settings, and applies them if they're incorrect. + + + + + Returns a clone of the event + + + + + Utility class. You can either use it as is via its constructor, which automatically retrieves all serializedProperties in the instance, + or you can extend it so you can add as many public SerializedProperties as the SerializedProperties you want to access + (their name must be the same as the serialized field they refer to) + + + + + Automatically retrieves all serializable properties on the given serializedObject, + or only specific ones if propNames is specified + + + + + Draws all property fields. Remember to wrap this within serializedObject.Update + and serializedObject.ApplyModifiedProperties + + +
+
diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml.meta new file mode 100644 index 0000000..d199425 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.xml.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: d4a42b2e4e6f64d4ba01d35c5a3dafed +TextScriptImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs.meta new file mode 100644 index 0000000..24b1340 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1efb03f507a60b949a70ed828ac18eb8 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..6fbcc5130cedc76f7566a958195e3703ada2eab4 GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMkesKB zV~9m>a!NwNkMjanMkesKB zV~9m>a!NwNgp>sg28IC~ZoCqv30E2pCNeNHGpw>anMkesKB zV~9m>a!Nu%K=J|x1H%9gH(m+TgewgP6B(G98SdR+aC^Gv{4tanMkesKB zV~9m>a!Nu%LBawC1H%9gH(m+TgewgP6B(G989d|}5-xj9E&?iL@O1TaS?83{1OVO4 B8T|kN literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png.meta new file mode 100644 index 0000000..2d94303 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f7ff421f40d548444864a01cd7f47112 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png new file mode 100644 index 0000000000000000000000000000000000000000..700b9debeaead0d7b26b31ed60c7e84dbf788ae6 GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMkesKB zV~9m>a!NwNiu45x28IC~ZoCqv30E2pCNeNHGq@`;%)dF?xDTk5!PC{xWt~$(69Dad B8jt`0 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png.meta new file mode 100644 index 0000000..e3040e1 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: aa1d42dc6ff3e894da2208c6929d2165 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png new file mode 100644 index 0000000000000000000000000000000000000000..f4a47c3701daa735d11da1c8e1e3c6f752d222c9 GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMkesKB zV~9m>a!Nvi#bF1=gro%mJyHf)2UajPA7)@anMprDMW zi(`n!#N-r@>Vpnk2}ufqJy{Z04MI!|3>X;nS1{&fnF;m*)iHRw`njxgN@xNAT}&7% literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png.meta new file mode 100644 index 0000000..490a921 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 05cfe010378336646ad6c721f66543d1 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png new file mode 100644 index 0000000000000000000000000000000000000000..3ed059a404fad33f34ed81321288c886dab0c6de GIT binary patch literal 455 zcmV;&0XY7NP)pGc}YY;R9J<@m%&QIKomt^ii;xRPP(g9TCLFFH;B-M`aR;lD{<2g zaNAFCQxLzQ1aTvR-H6szv2H3p?@gkK1x;I%c?T{t5IXl}I!xa4WKL9d4Z{(10PR7W z&_?`t1U*0l=nA^@JnvQV0LI(U1vJt5nZ&=T{l~Zrok3Gwo@u;Bc~SEQG|>FuTD5u2 zeQ2cl!!`XZ^Ljz%=@47Lne#snw0P+8eI`n&3>~N?#nXztLc)6hiRu_`p%rn%JG6tl z;{Iy~PQ;x#q1P!V9^QT(<0G^xZh3<$+<`-JZ%*iW%m8h%qs;)m*x@rkRqUwp5USYm zQ4(Vq;92Z=VSu67F=T*1>_&^{M@cpt!bMS9|8sBDvMf)9U}KVJh0L`YvIrWTiF37R&1Ql$b@}GBnYI2R x?Ky8uw&(kjwC9!h@slL&`L#st`8a!3kxvBIUpIp~UK{`b002ovPDHLkV1h6R(RTm< literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png.meta new file mode 100644 index 0000000..bc2ac36 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: af28470bd0e2e9543a6dfa9a1a4b348d +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png new file mode 100644 index 0000000000000000000000000000000000000000..f8294610e43490599de063ef2cf1c11e2d17279c GIT binary patch literal 673 zcmV;S0$%-zP)pHQ%OWYR9J<@mraO`VHC&DohD7vZSoa0U0Gn^Yi6M)BV~b@WMOP< zgtBF0DaMouF|!fP#$6Ci$;LuaiX=*;Ff}zOMNN`4rknEko$mkEd#}d*d>{Y%%`?x} zIp=-mdCz;s>QM+`CtQYS@CAOssOILuN!SPTEe&CKCX{Oy&T4LJV%*nVftAfT>wt^! z3A#153l71C%BQ5?rn$RNP$1rRHR5~~OeCJByUzW~VFd0&wqEDGFfHd#Js4|JIytws zzS_do@Kw(9ezB|t!p;fV^asoRYvG_4j#&$(`*BOQ-}wESYvBUe;~T8S3dPs-xq=w3 zoXkR>r7Zo4f56Ski5rS+v!yJ5ealXmPN&{iPb!@jLCP_GrOp98{cVdRe4Uoh0Y8d< zjYkUreN?-{1Mv6qH$1X|MqVI6oD{9tjkAC5tXpTIp0_FFs+sD0qau@I)< zj71QBmL*bu)?y2%r<4P(dcQ3(;U{q%7N;A6OwB($g$t4k_MCKW_J z1^eeqk6w7g!SH!)wZd?Hy^?MGE z!jc98cr52{VU0B+HeQnvKap`bSQ$(xmRMeJ9)U5~r18Bl6q@;GRVQ#=0hBbEaQrI# ztqZl<&(smfBAVT>9p3Tz9@d4L0MBUe;UzqTJIw#AZq@7$@4LV9X(+GG00000NkvXX Hu0mjfCz(G_ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png.meta new file mode 100644 index 0000000..0055f30 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 522b0133a9838674ca9a12e0c6e5a59c +timeCreated: 1625322295 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..63ef49a76b220d4de80807510b94f406c525e5cb GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F5he4R}c>anMprDMW zi(`n!#N;V^PaSgLN=Q-=?8%b2Y7k;#V8Fnje2P&lc>$vzP#uG(tDnm{r-UW|fY%uC literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png.meta new file mode 100644 index 0000000..774d702 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 789ef07ba2573f6448fa8b5dc5224c44 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png new file mode 100644 index 0000000000000000000000000000000000000000..5c2feae19dcc914919ab80fb84485e00a07e4699 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1SD0tpLGH$&H|6fVg?4j!ywFfJby(BP;i2$ zi(^Pe~gvJ1Rc= z?Ot!qiO>2DOF9@gq%oXjn8j$qoWXX1X90@9arT z#W5tK@$F4Rt^*1J3(_vMzVA+9hCAwRC4IicbTxXen@yoZH)$TLp zrW-e;F`Q+X#c0Bu!FGXXfusY9z&d`5^RH({?s9+MdcCA?-!-jS@BSaK$Ep;j_wA>K a4t9SLo(F6Gt~w8N6@#a%pUXO@geCx~6HWdA literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png.meta new file mode 100644 index 0000000..9baf726 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d542f997a51000946873268e3546b6ba +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png new file mode 100644 index 0000000000000000000000000000000000000000..9242a22984b08edaeef4a97ca09251719599f746 GIT binary patch literal 540 zcmV+%0^|LOP)pG&PhZ;R5*>TmA^{@VHn4s_q;MC!-&SVNGQ<|XQe4zN*5>Bi0B8_ z(B#-6L6L|M{Rb{Vi#3V6gP0CRo1=x1WNCN4J&&ne`ihtMh3DS)?w;?*_nzm@7ewNm zNBRGBF5)l&co~PsW->XW`d^7=YV2ZK$Vt}(`*N5OAf<+A_H;Q-!fjD$0z5v=(< zNJ~q12;bJ;lls6LIQZ+Qr@Fvx59U!mYOCWHBylcbJT}v5{$er>gjS;ah<3I)od2#FpCA|3k6_{i&xm(Fx7bluOHSUk)dF{B0q6Z`^053cwF=zqZp!gO@D;0000anMprEOz zi(`mIZ*qzP(;s%G5<@oyhKoKtB29tJD-syEdm8mueQ3PsAj8w}ant&b^`}8BSioJ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png.meta new file mode 100644 index 0000000..dff6533 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8b6b31f71cd528243b053cfc488e73f5 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png new file mode 100644 index 0000000000000000000000000000000000000000..3118ab10593c1b69d6e1d48975d2ada785dd2902 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmC>Y@B z;uvDloBZYD$DijNTn`*^NIk%moO5$i>qMdE1iPiXxZQbWObf0!Br$N?c}}jZitt`! z>^Z&Q*>6FKwhHez;*R|ry1ds+KAfpAHTJ{-1_rYXzK^{pYK?$qGkCiCxvXqMdE1iPiXxZQbWObf0!Br%-sUf`b4<~c#m vYh|(8OQFchYLzxcJqMdE1iPiXxZQbWObf0!Br$OBl=6M{a^aL9 seF?e7mlI{$mQ1^|!N8e4q)d^SnPH0pZ@U)rX^^c9p00i_>zopr0Qs6O7ytkO literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png.meta new file mode 100644 index 0000000..c3dd648 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: eeac3acbf7d1cd54fabfb1c4a12f9fc8 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png new file mode 100644 index 0000000000000000000000000000000000000000..c5f85ccf8c0fca414c90e664cda7f5db110bf004 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmDCp(s z;uvDloBZYD$DijNTn`*^NIk%moO5$i>qMdE1iPiXxZM{t>ikggefBcZHz<9Q-ou^) w7d<3f*dFz!)@FVdQ&MBb@035_LApigX literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png.meta new file mode 100644 index 0000000..75090ea --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8f0cb66458819764b94b93250bae94b6 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png new file mode 100644 index 0000000000000000000000000000000000000000..39e15460bcb8572d222b8c9f81b7ea7042045945 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmC>Y@B z;uvDloBZYD$DijNTn`*^NIk%moO5$i>qMdE1iPiXxZM{t>gYGgHA<>ER%x7k?sG|X zlTxNh5Zl5=9ii7x4)AzwmgDJh<9eE~Vfqao9tO^d0!J#qMdE1iPiXxZM{t>O9FZnYp}u(w#U18>Y*P xCmM0^s#s4uuM+EYa@FF<{;Grx({J$bFz|=+F9@hFv;-Q<;OXk;vd$@?2>|{=G4B8X literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png.meta new file mode 100644 index 0000000..6223c1c --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6f504a3fa8848264bb4fb9bb7d582dd5 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png new file mode 100644 index 0000000000000000000000000000000000000000..dc638a7f4794363ae5117c54dbd4656672539c99 GIT binary patch literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprEU# zi(`mIZ*qzP(;s%G5<@oyhKoKtB2A6v4XnowJom3j5U6;#Y5m9gm`O)Y1ioRaPanMprDnf zi(`mIZ}N^e*?;6)Bu}vT@Q5&pl{Ef$XwW;x!LoyA!41~K2N-%Bj)*7RV5nUrC@;}_ ftg+vXjg8^anMprEs- zi(`mIZ*q!)aLhN;fBcJPN@%d?{80JN%(zQJSwP{lX4ydl1BQHsMeGu04m-IwxQf~t oNcGNWXq~a*5W7YRBQrCD=nbx>q?xC$0*zzvboFyt=akR{0RQPILI3~& literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png.meta new file mode 100644 index 0000000..884fe5f --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 727ba41e4cc95fe4a98b07301e3ebfc8 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png new file mode 100644 index 0000000000000000000000000000000000000000..b4397c60a97aaf24c2506005053933d6469f947d GIT binary patch literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprEm* zi(`mIZ}Ofu*?;CYG95T#@Ptvh=c7D_fl6b;1ev3W20T0ojfM%0PFfPYM;gr=8W|a! Xt+|SMR787$+8I1u{an^LB{Ts533wwe literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png.meta new file mode 100644 index 0000000..30bc025 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: b4785ec6d937dab4fa59da70b69afc9d +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png new file mode 100644 index 0000000000000000000000000000000000000000..de6a933ded8177badee0cc96a9aa1a2fbbf3f089 GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmC>ZAH z;uvDloBZYD$DijLnD=m0wS>kb&6Uy9V!Z literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png.meta new file mode 100644 index 0000000..0d20edc --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 0f79253104349f44cb73978f6c8e93de +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png new file mode 100644 index 0000000000000000000000000000000000000000..627b907d345cf01adac7228639ef5ec9126558dc GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmDCq6! z;uvDln`|<3`S?L|7swrOvz3R3LGvN^CyAfE+CXC&JYD@<);T3K0RSeKFSq~z literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png.meta new file mode 100644 index 0000000..cf3e9ab --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6efe1c8569d975640ba0c9f2ac4a9d61 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png new file mode 100644 index 0000000000000000000000000000000000000000..6a0d89d4ab8ee1f7bb014545e12b133563639a3e GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&dmDCq0y z;uvDloBZYD$DijN*eV3SaICfvW}eE(-LoanMprECv zi(`mIZ}I_lz28#**%NEBW=LqT^t@pD-^j3@O~K(=@SCQ@1co?=`57uAxh)4WOoSLp dI^5XU7;GfO7!~URp8*YF@O1TaS?83{1OU0VB-Q`` literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png.meta new file mode 100644 index 0000000..52134bf --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d1d45eadab0e41c4a82cdffb6396b1d7 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png new file mode 100644 index 0000000000000000000000000000000000000000..f1465163efb49c68c56e9ba1105e270d1f95f79b GIT binary patch literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^+(695!3HFgJ}hYlQk(@Ik;M!Qe1}1p@p%4<6rf;( zr;B5V#MER5_W%F?e`kFp9`L4HFOq-iiuO__%H znoN1md1U*78^W=L?2}%eU{JZn7^=*0q}!oq{{KSe33KdEyj9>+?nqD&GBBLL;Luh7 za3cH3ql_Qf4ftPlabCFKz^<^7Gr&{`XyJVZhG}PS7ZpG4M{{nR2Y?okUwsNPz=U-&>$pGlQm0E&;jvafB_CrG0+>(T%ot< z-i>x(?}B=UDB`~qiM=aBNQ4AMQD5yyVL+(;27Z3_XUm3g6H!X<6h--L+x8x~2R@`} z`gJL4n&w)Tbudk{!Ps$}A`HVbh#_s;&c{h$I%ZkM%Cck_!(`TV9YZ1Uef9GA5d>ju zmSuSt1i?>T*Bla7*1>) zsplTR{8j8PRaJE%`fj*?cSQN#q5%X~1DT<1wGmEJc=Z4P002ovPDHLkV1jVXlTZKv literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png.meta new file mode 100644 index 0000000..234280c --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 358cddede8023574191e0aae610a4645 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png new file mode 100644 index 0000000000000000000000000000000000000000..b7f481e9d866280ded3971b2fa8d5c7ffad6c8ec GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7BevL9R^{>eBfcF0TApGDoI2^R2Y?GW`Kg2n3z^kQPFj>va*-t<>ggXR8&q|Sy}O4zI=Hv zNS+C%@csMuamB^O{My>un?Sg*u#g`p77deU3=R&?`19va4$vfxNs}fqzj^ZpEFmHy z!jPAj_xJJR$2VA5Sf((zxVU^+w{G2kpyL0vwYAsH&CL&jFo+Ej1IdBZFflSRX71d% z^Ec2M1|a?JC*4wvlPiF)MOUI{ApQ02L6r?6hn1I_eFyQ6o z^=QkME&tQg)Bk|*wr$(~dwY97hFc9|0IgZt-`}74`}glC5dY4dJIf>_B$hyA85jUh Wy^gC3zEAG}0000anMpkR`x zi(`ny)MSRn|NsB*{?p!YJmb%DA0B}Owx#?FKk^?Cv2c3%SfXZup^w8K$*d)EQ~nDc zOK;%%*Un|6_|b9J42Q5Aj=k1LPn`I{-&xOegk5t(3)h?WODk$7Twma}E8&x*1jEX* Wyo)>cM1}xuWAJqKb6Mw<&;$SlB|xwM literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png.meta new file mode 100644 index 0000000..1e64e47 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 622fdb780ae13e840938631c5ed708f2 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png new file mode 100644 index 0000000000000000000000000000000000000000..d61a35d12f89898b1bb6a87f416d2a361fc9df45 GIT binary patch literal 426 zcmV;b0agBqP)pGTuDShR2Y>lkilxgKoEvE8+S1qdrBSz(Z+Tuo@I4L}>6}4;Jg8U@aoq#-#rS2Zo*5{bv7}5y;M})vAjl4Nt-E zf*@E@N*}^7WXS(0hbomyW)Ify_j9#cjRG?B`TR|*)k-&;O$EqH1S*PhUMiJ-dF;Aw z$QZLXn~hd3mr1wV{ls;T?v$?@jYe!Xn-N)-zvA)uK1@j_lf*Pl5em-{h+Yg`*N+^> zA(AA$ilV5a9WF`c^Lb`88aW({;o+oMEXtiuhb2%7r+wD6TpQ@^Q zipIZrwQbwX^Sqw#`xm@F%d$Qo`?gc1m#7Zb>or-eRvvy>0zNDh3Z&g``(U0T5Uv}B zksFW4B#}rAG0Yh@5bbv|nWRu;@mSC_jgK!0f*?cY777Q*@8Nu1KZC*Gm=Hq#0Ta-T U6;Ga>XaE2J07*qoM6N<$f-3^I)&Kwi literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png.meta new file mode 100644 index 0000000..2f10151 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d98b8847646169c4fb5af28dd84c4179 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..85bb2483c4ab2d98a3c48823b1d38c1d34308331 GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqoCO|{#S9F5he4R}c>anMprEs- zi(`ny)Z`!k|L^AzkY`BBWz%5TxG+hHCxDG(Pn%bU^G$_<21efpwjzg36{I;QH)yhW o8yN~Pv8+`%HnC#Q&v+Jwhi|t0e|4ql7|=KdPgg&ebxsLQ041|4GXMYp literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png.meta new file mode 100644 index 0000000..31ad788 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6b1f9e1e1c2cf004b8e3bdd3033a8e75 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png new file mode 100644 index 0000000000000000000000000000000000000000..3445065c4b6b03dfa8849bcbb2bcfa2d4b2e2c70 GIT binary patch literal 605 zcmV-j0;2tiP)pH4@pEpR5*>5Q_pJ?K@|RGH*N#jG^J~^0YM@X2)zi>o?1O92%fwY zPoj8`sE7Oo9zFGB6>L?g=s`Sq@gPMHD(Xo+`lA(;Dyb$d{#wU0-R@?5Z_*9BjTL;b z%=_NV_syHP?+I+OLZL7$gs6~vNGY|0V}zGzc|iC|y~kz`%wevX&1Rsod(n%aFjA?&3S3+)E7L)Tc8XI)`XLee}Vj{OV9vd1->_wQkH7?#9 z1Jm;ohvIl?wVv3kHNQmeeZ%+t8Sb#$(anMpkRWh zi(`mIZ}Ofu*?;CYG95VLz{^m?YBpU!*>5Aa#D8YSE(U>yjHIKQWd{um8d#^ZXk17L zT)O+GjanMpkTSD zi(`mIZ}N^e*?;6)Bo{oePZT)Vz#=ixw7KEjGGm?}2PVJMYU6J&Klsy!X9|emq_GlszP2N)P?_LrFKH{mS>I)TB{)z4*}Q$iB}C&NWd literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png.meta new file mode 100644 index 0000000..50dfd23 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 32eaa0efb2b38774ea9705b40fdcc00a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png new file mode 100644 index 0000000000000000000000000000000000000000..ed34625f97e77dab025300deffeb49f096398fbb GIT binary patch literal 838 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE-VXMsm#F#`kNVGw3Kp1&f6fr06V zr;B5VMQ_gOgPaWpBCH21C#VH=ly*#QyE4%!$LUAh9*&!zb8=R#YU5Vt`_g|mVupn0 zy!(CP3=IGOA2Rsx|Nno5=3V9S|CjFh^~S%gd3&9q&Ho?#I_f9SA4yn$?3h5-nR5?T zoh+N)*tl@Y#EFHrF~-cy%s{vN|KBA2~wbpq5D!Cw`O%YJli)GTZR^#N7L-`-1HaYJRX43MwibIC^A*Wpu+qx7MxQ6DMw* z)7aR^2sWJwZ2Erd_5brsa;x39BpNUneJPnL(A=f5*MV$r1K%)ZrQvW z`~UOs2yXr;t)_b53{c4j9Zyd_MpG0}cksX&W90AO7|EM{L^S zL#KdB3;3W)ci3I(VRkh-HD_|7?=A-CZ=3vi6pihTbnF~0L|tYV8yOfFtN|su|NogJ zcbs!=emk$1OFAYfdQxlRv4#0O`u2a7Ul?_~zTx2cOpclPFf<|-Z9!F*3wKbLh*2~7aw$Y&P- literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png.meta new file mode 100644 index 0000000..9d3c5d9 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 4dd24a9f658e7a3438d4fa08fb85aba3 +timeCreated: 1648211899 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png new file mode 100644 index 0000000000000000000000000000000000000000..b71eefe4f8ca86bf8b5f34072ab4d52fa6be39da GIT binary patch literal 475 zcmV<10VMv3P)pGjY&j7R5*>TmCtIzKoG`fV--CJ^&m!XMGzlA=vh377bTbWF+}VIz)j$g_qya>y zop}kHp=;!G064)3@C^E9OaOch77Ct$IF4ZbmQ5x@=4$06Tv|4m;WJ;1!nK;)#0GOV zQ|b_g2v@6sjVzXJ_U-5$&d8VMa0qm_FI~T=ef_V&+Q&>wCjV@(KK}&}eF3^_XtWu^ R>+Apk002ovPDHLkV1l}g)4%`# literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png.meta new file mode 100644 index 0000000..3580f68 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: a248c8288afb9184f953d9aa07a696b0 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png new file mode 100644 index 0000000000000000000000000000000000000000..f4525da66a574728188a6a2a06bc798a8bfa3803 GIT binary patch literal 167 zcmeAS@N?(olHy`uVBq!ia0vp^AT|#N8<337)>#0gI14-?iy0XB4ude`@%$AjK*2~) z7sn8ZsmTqE|Ns9#-ekaR#}KlB@kso_2n)x|NsB@I-K$EJNDOM4`avM4=a<8EEDXk=IHn>At`CUXmzsE1BMA}xi{YQ z^HBCX;N&2;Jh(8EMUy4d;)sKeg0&T!c0vLJ!+BG+jF~?Te*w*A@O1TaS?83{1ONcS BGUfmP literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png.meta new file mode 100644 index 0000000..fab01a6 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 301c130dbb4bbba4e87072804939c861 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png new file mode 100644 index 0000000000000000000000000000000000000000..50a913a971a434d3144fd70243f25abeee47e062 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xa&H|6fVxZVz5N14{zaj-F7~|>U z7@{#TS%R@aaOUU#|NmDhJZ*4(%jo8I%uS-5)3=C8p#I3Bm&zf1jH}%ibSkj^jWGG< z{8XagCdZ{30S{RRAu9$^WuAt*r|ge-1J0ax;9|(yz@FG9$SonkaDh*WN!Xr08fXuL Mr>mdKI;Vst05vx;wEzGB literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png.meta new file mode 100644 index 0000000..cc34f91 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 18a5a7cde794cc04b9b446f0feedb3a0 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea0c06f4746fde06696146f5fc58c0bd2a4705c GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7BevL9R^{>ytLPfU_N>xK}dN*#rXpV6b>{n zCna{u>aU14wYq1NoD~D zm^$_=Ycg%r-C)I{A;@#2exZfL`qhnGMGg|7QyLi=n7I$IoRxdH4Co#PPgg&ebxsLQ E0P#aag#Z8m literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png.meta new file mode 100644 index 0000000..072d281 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d173388c1d9c32a418b5b777dd89d71a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png new file mode 100644 index 0000000000000000000000000000000000000000..a53308482c1c4eba9d0d1029a8ca2efecf1d5546 GIT binary patch literal 307 zcmV-30nGl1P)pFMl_cq?D9T1v)q7DC+rIA~x~?DU zx>nen+P2*h%d+-C5YVpcC=`Zai-AW5h7O9ivMecARaL`qf!Vfw6$z6p%Y;kQG%^+# z>k9(&Q5?tQpWZAY>@hRfbuW3I(_bM2LuWX}_FQLdk&vvS@a=_E)L!3HEN&baUbDb50q$YKTtzQZ8Qcszea3Q(}X z)5S4FVrnu&CR${#usG2zMNh8rRs{)bs+ lOi=mRxP!%unUR^9Vf*65*esbtbAfgpF)=5M`R2Y?GWB>vK0|Qq=H|Zl=FOYpbLYcKQg#~|NehVOUv6#K(>mq zvN8iQkd>8X0GcAg^!M-IeS7xo`GYLEWXY1BEG#U08ML*vh3xI^U!6L23Tz~Z2J&A3 z9Vq}-sjshZ7!nfl2P7FB9Q+697(EnwfDZc&l5})*{0$RhfiXUR{`}w6)RcjlnHg?B q6O6&m&VH1QjqN9p-VYIBU;qGV6Kn1Qa9Ml+0000_o}_+Lvyv%WI`uW@8dYxngml%7+dnComzjliO;w-JtD?B; zu{7`9V>>@xzdqA4{ol;}x4%BR6vcj_S@%w^>F)!RQ+SPc91xgwpL5)(?L0_geb8ifvwV9VGnOl3`K%X*ry85}Sb4q9e05qY0+W-In literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png.meta new file mode 100644 index 0000000..b7bc6d4 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e3d0592dad579e141924133869455c53 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png new file mode 100644 index 0000000000000000000000000000000000000000..be8544366616d44dfba55c5524d3f756ad308cbe GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0vp@K+MO%1|+}KPrC%9I14-?i-BT?L74G){)!Z!;B`+I z#}JK)$qsD)|Nl>Ceq^MukMD?m;}0=`>kUUFH!v<>;TFhee01L74)>8xhdVq+2ZPkyRh;F7Hb7t z;SN^Lj0fzGq8;Y&ZL0cL|K@=x-^ZT{&o?fZ`HR2fu7srI(S|L?0{FVdQ&MBb@03Tp9dH?_b literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png.meta new file mode 100644 index 0000000..aabc040 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4aa34055b1d36ef479af3d7b5701b28a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png new file mode 100644 index 0000000000000000000000000000000000000000..b4d864a5b768bfbf4595d3b76ff9ff5d676a2b38 GIT binary patch literal 715 zcmV;+0yO=JP)pHeMv+?R5*>5mCsKTQ4q&xmn{jc7L8b-{%C16#;aP3L5PXoBs4{g zMB{-NjUGIZ22B3~V+rvOFvb&HM4C4EBS?allu&An9y}OB<%briURu~SX4|ea>vq$w zyQNMtncbQ9{p7v3@69rxW0E9s82soybPsx~Qd&n(qDRof48!ELT1E#(ppiL##yypr zfCV828F5{%*-Wj_Ztj9^Yaeu4E-Ybc2%%wJAc9y7_gBQ!@KE|DEbuX?X6=?P7_mPB zhshPf*C2w6THu4^ulVr5stn#7?L%mkRX)JO!1o*f1>4K*lOt(JOAKPszV*%vv#z8NuNijIdDDrT9<)R9Ww#~!1=e=jeCM@vRuoIn zPrpAvQ=JVO7&FB9*Kp@sKNO^b?#xc(-lM%IVAyBv|7So6x?S9YAGpW2*7`t{L@+Xc z<5dbz8RcMqzO;N!_bfJXHiU1Z3x+T{8PA+=Quug`Ra(&C=z+)bHPYJ8e5NXlG^8a4 zvE;8zcM$Jlh%UMwv>J>wq$LLB%8yNuy2f+YqTHHxG8#i;NkiIF-l)NjzU8OeUgRdL xHQ2A13K%w64Yd3h;6-m%N}K2jF#H7o`~gtZ6gst;c2NKT002ovPDHLkV1lxxN7euU literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png.meta new file mode 100644 index 0000000..029aabf --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 34f39b5a760ddbb4d8b8749852868335 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png new file mode 100644 index 0000000000000000000000000000000000000000..1d89e2aff67e6b03ae1ebb542f654799b30f9ba8 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~o!3HGD9`RZNDb50q$YKTtzQZ8Qcszea3Q*9} z)5S4FV`B0G5rapQ|NQ^|-*(R|Ny(`RT%R4gCKlM8)N9CMdf4eOS$)zICKG25rYoGy ffexGr2@DK}AFAEl?xoNRG=#y^)z4*}Q$iB}Ky4`= literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png.meta new file mode 100644 index 0000000..560af25 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 62a48d93e78c63b4ea9b46537c7c0091 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png new file mode 100644 index 0000000000000000000000000000000000000000..0608dcb7ab4d0a1a5d2e56b3e7affa340ee4d695 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k&H|6fVg?4j!ywFfJby(BP;ir{ zi(`n!#Hm4!T+IdoF+Tj2&H5kaJ@PIRX3^it@z=+0!u<{pTkc<7_iR*NM~Q@a-?B1j zJYz8XjoJogLDi3rIi2f!-!AifprEK~XV`buyYgvWxf936fd6)#(`Ky>4Si_hyD?xd zo7Fmvr3UAVw_JNFW<$T%X&MBcEjH{|{-0xuic+ORkMZ}fy zn8bun1{WVLez{4fQ0Dl0-+1ZQPur8v{{3jmAeR59;KbVEH5EYDGkCiCxvXpGG)Y83R49>^k}+$8Kp2L<>f+`ggtSveOC}W@9EARWZf*^NOP7M; z?{IW04ia$@obne0hoTM{>X5;yTc~5j>gCRwgS11*3y0qOKHul@oi{LRwOVn4AUxyO zC%o=w`yH?Ncs#x~P4h*JsX&sXJBDF)x~|Kc%?3nKoanl)VY}TzmSyEQj*nGUeN3Gd zMJa@_iq5T}OSw z5SGD570+irYZwLy!w?L^fIQD9Z)QXW{t<3|v1fjUQD2xW%Ytc|kR%Ccnnou^9;6_Q zqKLxl^%~+h2HUoQ<2dTiOnCKJ*|u%Jm&@g@D2fOC+1tfp0X)w`-}kWJ@4@ptNYiw> gIGlf8`D*~20Kj|d@@JyvGXMYp07*qoM6N<$f*&fV3jhEB literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png.meta new file mode 100644 index 0000000..e57aa67 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 45e128e1cf00555479ee7934ab11cadf +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png new file mode 100644 index 0000000000000000000000000000000000000000..7e5397545d7a45641ad23338850e6cb0b88f03dc GIT binary patch literal 227 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7BevL9R^{>pF{z*hZR2Y?Yk-ch#Koo?JKZT7=Dr<|Ru+S*cI!};iN$D#HVr47% z0zx1*7Pq-w2&A%zsAaIwG=d62H#-tT;F5ubVdmSzSymt}!!WKCMR^oO@j=tH8)RMA zy>Hw0v@Ax^2p$zK-1YJrzYkS(eeduKR&Uh7OF(FTb^IdmDx!sj5nnB%z=f4aTa()7BevL9R^{>$+Q-p%fJeONQYMtD+`qRv0zM#G2+ELR(T@C*1i yf7-ktN#oik#*bPGVQxafZCx7;4Gatz7;bn?UAF3X!Zn~n7(8A5T-G@yGywo>oJJ1- literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png.meta new file mode 100644 index 0000000..59f2768 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 645aafe2260b2884a9df05b4bc01b1ec +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png new file mode 100644 index 0000000000000000000000000000000000000000..4615829ffcca351f0e09b4b4287cdc14d2044f1c GIT binary patch literal 323 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7BevL9R^{>)M{{R2qJVSfp(U}u0Sy@^6Vq#)0-MMq;l7iVL z8RZMJ0@Bjbj=#UZ|FuokmlHeIt?TRV?Ce~)Z{NSwd-nXX^z%EXUH|{z-SZP>&%T|L zo&CH1`nuTv^7eIq)X8ka=i3vN z|L1da37PP;Ic7OlIaD2NgB!)v{t#%^-@5yIcYj>CQuFZretAwdZli=}&(kN^*UoAT zjl4O3;>1E>u)RqwZU@dDFDvu9-zTSf(m>+Drfq2xY)f9qF*7$?fmJa5w0&{=-`^Bz zHYSC=3dRx=5`Q4>V3L&hk@+%c6K^x)21y>Cg)q^KPk%2ccJcnHd&0pCG(`|%O6&Y1 z^TqW8RIdL2r+R9_>@#NyzRgcR4>V0;2}I)|ANwf`Y;2%N0fqjp||mt zk50nGNl6I_2^An&uq4m&xw1#~9&gzQ43-27c8IX#j(Pe1l;XP%eV~E6A}d4z4oR69oM;; d3+P6O9%hDpu_`PY7uyel_@1tQF6*2UngG<66KDVc literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png.meta new file mode 100644 index 0000000..6f04add --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: c561c878c05ceb1448966fe706740008 +timeCreated: 1648211899 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png new file mode 100644 index 0000000000000000000000000000000000000000..afdcff35bb27ff174e62435029f72e3767458eb4 GIT binary patch literal 223 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4aTa()7BevL9R^{>QNTh{iU<7c&ovDsNyG-pFXZWAl?kyu6|u-FzmI#H8}* z^_TBTj@Dn`_Sx{kQ}dxkU*eUhjk&ikyeTw$;QHP+GCMMeqjAeM=gr3@Hz!Q87o8fk zV;%S2@;T2rHJ`qJv}>J!(*cQQ3FSG(_a}dOwlDwI_qkEo^4&$}LcAoaK0Q1j9IKVF Uz+qRVG|+Jjp00i_>zopr0G3Bs*8l(j literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png.meta new file mode 100644 index 0000000..0d3bf2e --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: cb46e1d925af22d43a6f8bf0e1d459e6 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png new file mode 100644 index 0000000000000000000000000000000000000000..6613a3d325a527ada017fedeaa3447d3728e9eba GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$1|-8uW1a&k&H|6fVg?4j!ywFfJby(BP;jfK zi(`n!#J!Ug`C1GFT>tAy=rt%l~V#R=!D_zopr E0AM_3LI3~& literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png.meta new file mode 100644 index 0000000..2ee6aab --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c0c40ceac3c6df146a0fcd4e6b226540 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png new file mode 100644 index 0000000000000000000000000000000000000000..56a1324846d22c617d1340eebbd88925cced18a0 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^0zk~e!3HF=pW8M9Db50q$YKTtzQZ8Qcszea3Q+Kl zr;B5V#>8X?_W%F?e`k5*>QKYpvES*V?1~xc%z6w{uCP41{GXF~f|TzJJGT{S+6r5R zJMJ@mEK<0~e&l>Z1mmiAi~`<_8-)ejnKl{->^3$sl4H&kV|=vRVGi#RodD*$jX#tp ztyS1&9n#0TN^FTci^>JAQpPjdOc}E#@;-D9N@qTD*2m#n_=aGC11udsH?RnMoZ)#_ z?siPs;gz+pSgQ?>3d01(niFvhP0S8|IJ=`J+>n%Df5NJ8l#~0&?pGAxT6*R49>klD$d;K@^2&C2VORq!1K*fna4~2mvceC2Xs&;2TK5 z!Xn8_SOwohEKRVq5{*AtstJfTJATL9)n%Q%@a@msnR9369;fi$$8Z5(un#LRhB>^! z4V=NAaxN4kYVZyz>_Q!8{(nrNQC!@H4QRp#yhy-u+Rdg_AHf4Gppz|Dr8`LMUm~CI z3e~_)D{ut2KSg*9f7Sjbo!EAt%FfJq7f$ujFPU&|B3G^?$Q?^P4JD%}I^;EhZHbkM zNMN;igk0>vBOK^hh3Z|c&0nG}rV`j@)h<*Q+qAL7*3`2}9c#@!46J4AIT00kwidUn z N002ovPDHLkV1mOvm^uIe literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png.meta new file mode 100644 index 0000000..a0db454 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 0c0132429106c8a4d89d9d0a6b723ec3 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..c272180edf95f9229ae13d1eb1c0362d92759ab5 GIT binary patch literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F5he4R}c>anMprDke xi(`n!#N(E8hH(Gnn1k=)1;xK#l381?e NJYD@<);T3K0RYm0RxJPk literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png.meta new file mode 100644 index 0000000..eddd2e8 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e2279677842a8064fbae0bc889fb85ab +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png new file mode 100644 index 0000000000000000000000000000000000000000..90c521249c6777aaef0ba7a53c81f9744892bc82 GIT binary patch literal 338 zcmV-Y0j>UtP)pG1W80eR49>SpcP=lCBcYGLS0>bnzOUB$=$nmpa1>)_YX*H&z?Q4 zKW_m;x3Y8lPUfcI`8W5fKq_?B&aspZ@*($BwK3mqu|_RaG7k zW7e!$CO}Of+ZY4|1^408XbHr2KwEx-I4f4Hc<}l2=igAdZCI^QP*9k#dGqFnPoF;h zdhz1Lw;+FMX=%*^O4$Ih3=Y>ZIPKfF?igP)pGyh%hsR5*=e7;wOdM@|`tO@R0(5O0Ul7=Rgzm=O@i@i>Hc%ZiId zO7L;|{Qv*o@B8=f-+ZI7zKTe>(l-zB+JC`?;nHEy`u~g=hrhZy}bMJ z<;$11U%!668K|xan+uE-6cjS~S^g`CzPiTqmz9Izhp-&OcVR__*II52KPA*SxPO1; z{Qu@L*RNl{E&in(*|TS{f`WoCj_uigll{hF7O8tjco`U(7`_QeGyMMX{qt94 zGY*Yc=M-MNc<~gd{t&v~YyLyQ&!0d4u3x|Yfr*L9F#!RAqk<9T?-*v>{mNy75FpRP!^4u5mBsLbjaBeH$hkkiF#P@d_cxIF8K#zrfds(v z<1+)ug+S(CY%X{Y1V4dcz>chmk&%&w_3JwZg#%L%#14U#J4L~u4HCn zV&d1*(h^{2XJ@{5@80JfJ9e<}eS5{t_Ui7>w{KqG28u2D_wU~_p!$!vT&gA}Cf3!~ z)^=&ts#W)tm6ab#OG{q@8r;eNNu4MFUs9F>VowG{Qhv!W2mu2F08Rp}xKNEjp#T5? M07*qoM6N<$g8J0>{r~^~ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png.meta new file mode 100644 index 0000000..66ef715 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 58676a985ae875646b7be748cf4499fd +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png new file mode 100644 index 0000000000000000000000000000000000000000..fd589a0f316096bff8afdd0b9fbe51b3138d5466 GIT binary patch literal 406 zcmV;H0crk;P)pGNJ&INR49>S7%;$$Ma)P_N~-w(|NnNse*L<~!^2Y|A|m4T`Sa&D zK)L6H46J$i^5wVFr%%7Csj0aDqCtF+I6h5sK%5a47Pjy2-@pHn0f-M02g+vxu>yup zet!Pet5>hS`}60|Kahrt7cah@K7INP5Dnsk#IIeu_8z1TriTU200NLAW@cu_%a<>| zGd4D!2-L6*DC~9a+_`*RU0tDnKmbyQ&Do-bg@tE82F#v4`zDZY4iz^C@j>D_IXS0+ zd_fGIz))>Dd-m*WkfKYMF1-a>PzMw?0ns2nNc_r`D{qB`g*!2v&Bw>bAuTP<4Rjd; z$caFM@{b)m7G-5+B?{t$0*w&}fL{57&DlmkToVxyaR5(fXD~ow1t%ano*A*Z0GPs} zK7IQ1Hok0944~0%+A3JOBUy07*qoM6N<$f=el@ A5C8xG literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png.meta new file mode 100644 index 0000000..fa51749 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: fb605a2688b31194887f2e7a6769235b +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png new file mode 100644 index 0000000000000000000000000000000000000000..a34a3e8a0f23b3390c7b578fa3b0db5b4157e266 GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^{2anMpkRxq zi(`n!#AFE*hqn3i_w%|4YxV^sBqVHj@bmNY`=?HwI>-34Euhd@KwgD!((x>Y6Dbp# z{yTj5{{H^|0A?RYlMa3+g~}D&2Dxrw9E+~6jsDIsliyTe`DNaTybX*hy=^=!4Nsq) zoh`4F&GympQH#l>T;rd0%Ph8>>`R})_+*(u6%!j9gI(_3o%sQ3VLpGHc3Q5R2Y?GWPkz*2?=i?RSLvLP@!``-2LLki>)9IGl&ou7jI@_ zVwxes&!o_m$;a+x!NGp&`fr8rzZjypxw%=se*L>OK3}WmXZ3a#~{He%CPhKL53fHe|}*B34XG$Wca433081#!+HkYAG{3B#t@4XxMdh7 z-kit41oGW~7G}5||5;cV*qPbkd{!n_a0oC1ef5t0<;zG0U_f!*yv4xz-~q$SA8#1m z{Cv;w_}g=a#Shjp{P^=Tj}a+&Y8bG9fB*iqynOkx7HlUdoPZ{S0$2)&g@O1N5TE$} i|9>7((F_I#1_l6)Drz~&RO5yK0000anMprD7R zi(`n!#N-r)Cg0g+f71^z{`vFAK}6ZiQjLv^LD??)BjbYZBM~1oKYaaqRQ+$4QTl&& urcEYBMnPf;i)VSVEHL>!-)1cj55t^we1F}Q<{1OcWbkzLb6Mw<&;$TUXf4VB literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png.meta new file mode 100644 index 0000000..e0a5072 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4f2c4b43188596b47866d41e1dc13c8a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png new file mode 100644 index 0000000000000000000000000000000000000000..9ce1a4de4485e5d4ab57c8f94b8523f6b9c46436 GIT binary patch literal 465 zcmV;?0WSWDP)pGgGod|R49>S7&L&92sOfvj*io%q@*MsKYslD(4j-AK(S8*H32a{ z5C^QX-eF^7v(?hll3u=i`MJ4s=U({(1i)Ak z1j)U6_3FE*s3`l37caho_&_h304W8SUgRi_Yiw+sz{SPI0Wtt+C~JItJgb0!0F$h& zZ2$A;&tK{3>8W14crh8|MP+5>Y@nVcAdM_YhHP(cZdTIP*0%fb;luN9-@d&ADzpG07*naR49>S7%;$$#@AL2C2ox#U20gKydEdxi=gf9E~6v#0QCkDPZGFn|91TgZHnJV+geW=BWIHUH7T=g*&iqlDm zAoD@;Aa&UMY_M$Evb+EBfTc^9-T|q@rWs^Y%b7E0USZP+5(mjM-~r5%l9GKur+q@! z2;zgp88D+31BmMC>dt%f=FNAIMi33+gTxt#1PV@0PV3&id-ub|#bqOi&p;wj5*8Nj g0MQJC3@|VN0AR)IPx# literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png.meta new file mode 100644 index 0000000..ead0de6 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 20794834c0a413f408b80110d0fc73b8 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png new file mode 100644 index 0000000000000000000000000000000000000000..5a4b7eb1bf282c87f82b1f2ce362cb37312ff6ff GIT binary patch literal 355 zcmV-p0i6DcP)pG6-h)vR49>Spc`OB<1+)Xr?9Ya0xvJG&Mv~hz(7<`P!KG5{rdISYuBz_@#V{xLYPKoBuze+mX_6~rlz8*s;Ugi z%E}Dl;^GWKLPFd?pmg!##p^&dw?GP6U^;+KikFd*0ox!cDaoLzsR=g?$QBh76N?8r zbu)<11d{+dO$MLmfwsZr;WmB${{0Ei-RAG#zh`*<{5f1Phz%0^^y$+R3{7v}zFi2E zw0rdEktm4&=FJGjL`r9002ovPDHLkV1i2c BpN;?k literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png.meta new file mode 100644 index 0000000..8e57f77 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e02713e10d7aced44a7a651231f0adef +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png new file mode 100644 index 0000000000000000000000000000000000000000..42f1f236a8149ffa2b1cc8a076f7e4449356632e GIT binary patch literal 380 zcmV-?0fYXDP)pGE=fc|R49>S7*HU^#KcsmqocD0L<9K}=n5E-IqdB0ozBkA?)LWf zssaK6T<_n%|9a@qp*wr`?%nzG=g)GOI%XJylaq5|WMrg2P?H9b%?1@?Q&(3P2O1#p z?AbHbZ{NOcN7f{zsi|23l$1Gm@Zjw~fBt+E6cpsTc=6)nU%!4m&d<-6`u+Pi&++5O zw*b|CW`Sz@2qO4_Ku=Fk_xtzn-xe)ebaLCaZ6*>D5{e)>ph5qE)H@KH30p`2oyBEr zY%B=Wz=cg7rs*rty`TR90bBwIU~FI@{C)oX`DY;W2TDKyL+b3EJ9qxGu&@XMUCGDH z%>35D!9j5D+_|@-qN0``J9exEsO&XJEh84&jetQPAucYi|MlzFb8p|iT@4gF$1nhZ afdK$^w{jgtX~#DJ0000pGpGibPR49>S7%;$0KwcDxzX7of5QhV?8W2AM;-BaWH8?mp8hChk znt^O1Cnu+!jg5^LfnpshDk?jkKY#x9=FOY$#l*zAFsx8eP?-4U&71G<-@pHo0^)gdwF?@ZQHi( z-S6MO|LN-LUVr=c?XP3Uj`d*kpHX07;Lga%$YVfuO;J(Nnb)shf8V-w>mz1n=8f6e z*{4Cy#}`0>7cX9X1JZc!-n~ySr&d>2UjWeu4<39DRO13u%!H;{{lbL{?;k&Y{A1Im zO;11qmoHy_w`|$6i(9sAc{FR*touNrYgjc01O#{hLs^2CmzM=-+Xe{A8CT{P{P)z1q>tt jCm=2cVgrUj02mkmkjv85ZQi$C00000NkvXXu0mjfR!rc{ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png.meta new file mode 100644 index 0000000..560f0dd --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8003873ab749935489bb11f23f830856 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png new file mode 100644 index 0000000000000000000000000000000000000000..c441add0cc7487b51a19627c59917815d371bcb9 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^JRmj)8<3o<+3y6TI14-?iy0XB4ude`@%$AjK*4TL z7sn8diOCD(A3S`RIc@6Hx9motA6F)~8H$LAIO)agnDFoQb^Y6qkN4ZNbKPZrRButb zYUN7bzx=G}=jK%A=H=~^&{*R=g-zhc&(F{AcM7Y=F?&t;ucLK6VN2Uk!4 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png.meta new file mode 100644 index 0000000..2bef6e5 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d8306b1e159c72c4ebc9a4fc31debe60 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png new file mode 100644 index 0000000000000000000000000000000000000000..abc435323589096e2a85aec7d8960643efc53863 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@)1s;*b3=DjSL74G){)!X^21ZU# z7sn8diOCWH3P%qe3VQzb?Os+F=AS|pp`Sm0F28o=N=(JCFE6kEclhw*<70gVI}e%F zY=wm%JG;g8_kDhTet!M`i3}b46Am`rcKGROu=R|A`qJgg!&z8ZPWa5X`}+-~%+uSu zIQPzuk00B3rRAzCD?R`I`r7>*Xk2tdmi=LqVsTN?xvew*{rUNMeO_K3yQ7JZj=uhT zo&Z^P4?|(I`PCvKSA87ZhSFd(4En4n3w<^}rF_9@CPI}n{!S1(iNl8h94r};L{@%I0 lJwKfJ=s80khJ*wLhVlgy_8;k}Y5;~5gQu&X%Q~loCIH(^ly?9C literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png.meta new file mode 100644 index 0000000..47f7775 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ed3789262161efa4fa33c85ca534590e +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png new file mode 100644 index 0000000000000000000000000000000000000000..c79b66833bb38b3cfcaf1efcc4ec2e967c4e7067 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^f*>{r8<6y`Y?T61oCO|{#S9F5he4R}c>anMpkR}y zi(`n!#AJyt2RuSUOQpEEy=^;~7dh5Uu-M3ULQ+CPr{d?Qr`vOHZ?jEHPR?e!s9@(I zqvF4X@qc5&$45uY8iW`Q}D}Sb9lNz@<`{|2@AZZ>+NOL+*A7c8oPqMkguJP z3g0C5mCP%b&-8X^cw}(UpySSsM#iqoCmk5r*ci56nAf>4>xd7~H4L7velF{r5}E)W C9Y0fhdEP)pGElET{R49>Spc!C9;~Q!V80V|{QCX$%LAuB|9CqGD1H|t z$%3R%ug+-7G9TkijW2>s44(uT7+$h{u+6TJ{Q2k4j|LRQObjdm7OtskkAxT)X74FJ z%Pb_w${@hS0#tYmrUtI~AH$zd_hf(k`6J24Ce7+AwR2JJxu+M7Oae;nf~jFfa>n~t zY#*(7y`3cfnW^$=#rUdm@-rDfJaF_lQ0@h~V)B;3EGl1gf7-$R_ Z7y#{EYeavV3rhe1002ovPDHLkV1h5QtNj1~ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png.meta new file mode 100644 index 0000000..1d860ee --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f252c69cd0163714eba038403f61b09e +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png new file mode 100644 index 0000000000000000000000000000000000000000..22930f4dff4fb6b1a715519097b639c0214e6677 GIT binary patch literal 368 zcmV-$0gwKPP)pGB1uF+R49?nQay@;Ko}i^41#Q%Gz!~Ut&Ng9q{#qHiKe5>XW8pyLLIjyimz zo~Lmf|29p-ilVr9c3GATI_mI=!W7eVT{rCe{_i{t4*fW7N*=)UeSg6Rv^frN0}lP# zI1q&2_%nBDnr=aGgG0YIiZ+b!&6=yKI@B~x;l1v=u3Pg>`y?*{LjD0_ZSpkwGZC%; O0000anMpx|Xs z7sn8diOCXk8rs{Jx9arj=;)NP^UKxnE%MxEqN@7zNxcHYMFl&Kr4ssH!qr+B1sN5AfsnHN}ldU`@`+_*90 z-{0TI3!a^sd0j#32z#gSl{G6@t}J?WWo7ugckf>N`1($EFzHyoaN)uu4jdmof8Nfd knQxMqzv9ON1|A-Ulj|3ped&L9JJ5R!p00i_>zopr0A1^Qv;Y7A literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png.meta new file mode 100644 index 0000000..f872413 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 21820ec6fc9dd0b4fbf42a3b93fdad4e +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png new file mode 100644 index 0000000000000000000000000000000000000000..750996d613ae7009e2760d9c4d8789612e9702dc GIT binary patch literal 309 zcmeAS@N?(olHy`uVBq!ia0vp^0w6XA8<1SE`<)7q;w2AI7y-w-3hMR0zr8&_RXhA%S7+zf zrW^kkDyXSF;|SoCxBEM7wt0RX$K?sLW>pp4-BtQM@efd7AN#7#150O~K72U&@%{bv ziLd_KSATo+x?5a--(PnoPft(vhAh^Nk^)Rc-|Cqje0zIaej?M%M%H5t$F?4AV&#@& zn8`1}!2ncu@OZy`^Ua=&A{(9-Mh$`ah5_sb1`G_E#Y+NQ;_7vQUS{xg^>bP0l+XkK Dah`nL literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png.meta new file mode 100644 index 0000000..946cabd --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4a091a7609ef2d34bbdfaa1a886deb18 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png new file mode 100644 index 0000000000000000000000000000000000000000..6aae96483f84bee1755eeed1b1ccb872539b13bb GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@)1s;*b3=DjSL74G){)!Z!;0aF` z#}JK)$qMWSi#}FfxDh|$N4$ZFq_nhtK}pG#){p1sSblzgYiqVofo%M~n1A2iMl*Gs zWfFb7VcWKAFWhD|01=Nzy8^W$Uv z!-o&^6NTQqd9z*M!7V>PNjU{YK6;Q{02{q_GJ)CB|uRqf8WsAOSp zZ~y<`!^7?Nli%8O{rU3v_4W1Pa`tsR{pM+D&-O1}x|Bch&tmufIL4LC8&7%(rZBLv ZG3=K0P3}1Foe1<3gQu&X%Q~loCIG7cdr<%Y literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png.meta new file mode 100644 index 0000000..c18d4ea --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3e6b96a975eba1c43b2bad66fb7f8b4a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..dd219ac3778c1e3f6361c363ad6d5f6856c76813 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F5he4R}c>anMprDMW zi(`n!#N?Q@#q%3Q4jge%lDKNHDse?dLIMLro;2e%hOPfU0o5^hy85}Sb4q9e0KFI- A82|tP literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png.meta new file mode 100644 index 0000000..96df50f --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: dc0ca9b32ae9fd049911671cf1a480bf +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..798457f49eef9b7e8c27d20db55a3570fd2c4074 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F5he4R}c>anMprDMW zi(`n!#N?X8Cr>(XB_t^b_GC$1H3%^=FkoP?Wnq;2uXyMdP#uG(tDnm{r-UW|hN&5< literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png.meta new file mode 100644 index 0000000..299f17b --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: fbdd7ecf39c13bf48a5bd02a1159c90b +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png new file mode 100644 index 0000000000000000000000000000000000000000..51afe67326b5bbb4358d880a8eec9d5a10cc769d GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprDSY zi(`mIZ}K0079J4>F@eHwZz4CDNJ~o_8yE&~xbaGuCR}0QSYTjnY{0;anMprD$k zi(`mIZ}K0079J4>F^#o;%l^&w;Sp&HWOn0~FlAuUICGANhk=EGQanMpkSG& zi(`mI@7u|STnz?149RRC*_Zz8viO-(Dzrc71^*i7zopr0L67hu>b%7 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png.meta new file mode 100644 index 0000000..32d19bd --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4896b5aa9d63dec498136c21ffce735b +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ed49d445d61396bf5e07beee7ae57f73a6d825 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMpx|jw z7sn8b-nWwv@-{1ow8>X|RN!mid$4hKMA*vW8=3qE*yFR!<+w>I3vJGOX8UH&y4Nbu zoABe*hsE!II~Vwego>)TecE;KWO^b?^}&YL2T5y}-gvMwLGi@2)K0M<(&>}x&ctuv zj0-we9pIBc&3R@8%;d`;VQPAAyZRt1X8*cN}bWtEMVj*aM977LTh&(*zsT&!pJ bDn&8Aja;eBwVt^Y=q(0MS3j3^P6;G|$ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png.meta new file mode 100644 index 0000000..180331a --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ff88be84254fb1f4b9a81a27ae0b2e81 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png new file mode 100644 index 0000000000000000000000000000000000000000..2b313e46258bbd042a3eb1048f101f8cc698c393 GIT binary patch literal 336 zcmV-W0k8gvP)pG0!c(cR5*?8lQD{eKoo}GM9?N1(8?32rR|;~30^_%LpmEfI}_Me zkD!DcL>$3lJ%RR{LTx7R5jRx=%C`H%@Md(rZ$|JjnBuzbmN9n3VdL@xUgt*$!EwZC znqHqzJLZ^JM)RaJdzng*(>f+R^VLHg9Xt|3VhXxsLL_3PQr*j;-p ihdJ$x^^EWZ0N@Uw6N6qYJeYg{0000anMpkTSD zi(`mI@7u{6xeh4sxCrmw^5{vJ#*hE=pFVk}vMu=Xl8_e}1z#U1G~StAanMpkSJ( zi(`mIZ}N}-|M!asyk~nf|9>aD{lcmxGbAJ=#27zjDm+V95o)-?^f7Wn+yc$}jWe1X zT^KGg7jbrcoZslfaOw0B2So|fgewd)80}B^o^p64exhNqLyUWuV!&2jhng9O-u#K@ aVpvkPqanMpkTMB zi(`mIZ!$yU|NsAu84Ilh=CePV|G%(#et@aMR-Y5IrZawIR_J3%a%7WXP+<@K%&@Ax zlQHX-vw~Qnf>6U1r>{$l9p;K0b5LS<)yeRZ)o>s4Mg~bXj)pHy68|Mnu>60h=*cKy z%8+z`zi6@G67iG+yb5K?hl|WN#AO8S^Y;u|reo}=dg9DE9v%k48O%2poxC~+=qv_L LS3j3^P6anMpx|sz z7sn8b-nYSyT!$3|?(lMcv2?VVHs{xiOExOYFQuy}Hon#ASvfsO^*Ucq*SVgqbrxrI z8p;c{-Jh|N_vD@C)mIPO?q%anMpkSA$ zi(`mIZ?cb<*QBJx#K<52|JPf)xw)CKDKP}R)n9PSx&GguPWD%+kxyQ}eEH__#{cyM_8UjPhKR+;*eEaTkEK|kyY}5V^>;=vqM~3(gJ}VDT6GA zGY#?ww)k#xn;;jkj7hSfgTe~DWM4fq-Ic^ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png.meta new file mode 100644 index 0000000..db7c113 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 25da15ac84743244ab4c860cf8798ec8 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png new file mode 100644 index 0000000000000000000000000000000000000000..4ddd37ad4450952bb5dd03637b99f6e8afcc5281 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMpkS4! zi(`mI@7u{6IS(iZxSm%IJ1LTB<8~)FIO3=*tJ&TQkWnE^Zu!b#Q u<*Gj&xY4SW`DFF~9+z8&8?7tP3D~RGm`MM&30nws1%s!npUXO@geCyThex9T literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png.meta new file mode 100644 index 0000000..a248e7c --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f536c51d3da3f2e4ca93ac8773ec2ad8 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png new file mode 100644 index 0000000000000000000000000000000000000000..188ed94dc5c375d5925ddcd7fd22b51cb1dbc595 GIT binary patch literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprDGU zi(`mIZ}K007M>{#UOWshQanMprDGU zi(`mIZ}K007M>{#UOWshQanMprE#= zi(`mIZ}K0079J4>H8w6r?w*4jEK4$4cFsu>?~yXdI`F_CVL`DnGc&_Jb{%V(} P+88`t{an^LB{Ts5H+UYQ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png.meta new file mode 100644 index 0000000..b2dcd93 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 29b0e8156f6fb774faf129c83bc9ee33 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png new file mode 100644 index 0000000000000000000000000000000000000000..ca376a89c1bc8fe52bea75c4d9312d7d03e7d85d GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprDSY zi(`mIZ}K0079J4>H8w8Bqih=#iX|EwBz#ZYldI70kuuQXk@z&TvyqYEi~^4&*Vda$ Qf%+IcUHx3vIVCg!08kDdzW@LL literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png.meta new file mode 100644 index 0000000..e9f14fb --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c0a56b88a1b449045b3fe5f561aa12fa +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png new file mode 100644 index 0000000000000000000000000000000000000000..ec9ead73db0edfdbe31bc68ee6b8b2f164137618 GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprE#= zi(`mIZ}K0079J4>H8w6r?w*4jEK4$4cFsu>?~yXdI`F_CVL`DnGc&_Jb{%V(} P+88`t{an^LB{Ts5H+UYQ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png.meta new file mode 100644 index 0000000..89331d1 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c456d5ac01d2aa843a63985497b04931 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png new file mode 100644 index 0000000000000000000000000000000000000000..ca376a89c1bc8fe52bea75c4d9312d7d03e7d85d GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprDSY zi(`mIZ}K0079J4>H8w8Bqih=#iX|EwBz#ZYldI70kuuQXk@z&TvyqYEi~^4&*Vda$ Qf%+IcUHx3vIVCg!08kDdzW@LL literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png.meta new file mode 100644 index 0000000..7365c26 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 7acc6bd588627b046bc1c9b3cd78a6c7 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png new file mode 100644 index 0000000000000000000000000000000000000000..38dc1bb8015f9a79cc3209cb6d4f0dc26efc98d9 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprE;@ zi(`mIZ}K0079I-*Wr2o_nyeWT8Z08x4Ubr7Oy*=vv1NYG+QlnTVIakwk=USU$zmkT a%*anMprEOz zi(`mIZ}K0079I-*Wr2o_nyeWT8Y~6k2Xd6f4txoG)0CKS;6U@mj3sGt2edqY-#KxB Zfk8H0fpdrTc0r&444$rjF6*2UngB35CO-fG literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png.meta new file mode 100644 index 0000000..7f51fb8 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ca2f91cc405eb144dad970eb23db2f72 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..8e17561d53740055d922d1c24df9d17e43f6853d GIT binary patch literal 236 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4j!ywFfJby(BP;j27 zi(^Pc>)UINTn!2$EEg=dZs|~naaq2Nho$>Va=f(C-B&-@1V!}h!%~jfT^e* zN!VYsf_J}mLhFYJ;r(I;OA~eF#1}kR=#X7=s`aA8^iRtk&p)gyY%c5nL|xI|`G!OD zYJWbcz6*~wPq4o$8FH-K-Z6^-W|B ZusuG#)AVYPb|TQF44$rjF6*2UngBkaQPThb literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png.meta new file mode 100644 index 0000000..890be39 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d1278357b25e10442b6ca6c24edc9781 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png new file mode 100644 index 0000000000000000000000000000000000000000..c8cfc7fff7801ff59d70a57f7721f9e2828ae25b GIT binary patch literal 285 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4j!ywFfJby(BQ1HB` zi(^Pc>(OZ^IS(5MFqmg5w*S`GKekfwVgk>x9~a^-9cZ#U-DBspJ>Kz6PpaDSe+A__ zyPu}YU271qWcPNMA+v>XVbKMameUK(6kPdC88eG^aCuBU9OgTe~DWM4f@ZM@O literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png.meta new file mode 100644 index 0000000..7edd20d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c99a391f381fe534c80a193fe9f307a0 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..776309196aee7c5b4c5d5fdc8b19fd8e71cb8f62 GIT binary patch literal 266 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4j!ywFfJby(BP;if@ zi(^Pc>(ObJT!$Ta7^ZGf{Qv%w=i{o)!4f?mH?A&rSm1VMO4ZhDb&JwpZkBqtKmYK? z$a~Kh^A=3poWXSGiGlP3t@fD=<(55cEhiFH6nyyn85b7q;O3ZqIMks_<{ZanM1_nlZ zPZ!4!kItl;FE1|Evk5h{hi@w4jh2FfL{XUPI|fq*)C>=)gD|ICcK-k4RVvGtDnm{r-UW|@z8kW literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png.meta new file mode 100644 index 0000000..7b24e9a --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: 9371f432d5c714b4eadd3477be06f0f3 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 11 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: -1 + aniso: -1 + mipBias: -100 + wrapU: -1 + wrapV: -1 + wrapW: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + applyGammaDecoding: 0 + platformSettings: + - serializedVersion: 3 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spritePackingTag: + pSDRemoveMatte: 0 + pSDShowRemoveMatteOption: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..c745068069d056de1fea32d17179ce4c6f8ab2ab GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprEj) pi(`mIZ?XjI;slW%CWC|o1_l-Z2F7h=jf_BP22WQ%mvv4FO#qDR6tn;U literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png.meta new file mode 100644 index 0000000..cdc61f9 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4d338c631fa36f345b72a36f1c91ff9a +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png new file mode 100644 index 0000000000000000000000000000000000000000..768a2da31056ae9e904f3987d24054a50562d5d4 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqoCO|{#S9F5he4R}c>anMprD(l zi(`ny)MSRn|NsB5X8vfU@Q>xF!Zs_PAl{Dq|BtgM7>cs3$cjmjRi5yJ$E2g3(fY@s sBMuA=B5#f<@1H$E`6@@nY`kL{fF?3{y85}Sb4q9e0HxC}A^-pY literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png.meta new file mode 100644 index 0000000..afcc984 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ed7cb8f9a27664e48896c904189f0e2c +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png new file mode 100644 index 0000000000000000000000000000000000000000..705c72b68d0556f94b5f925f92a5b1705dd36d7e GIT binary patch literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqoCO|{#S9F5he4R}c>anMpkS}3 zi(`ny)Z`QfCRCSvfE$zna!EegGc4~5eJ3_kvI3YUi>`1jZP@GR48iDiCse|`M^{{BOjJ(Vxj81DZrT*FzgM+xXK N22WQ%mvv4FO#pS3SUCUy literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png.meta new file mode 100644 index 0000000..2758634 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 27df4ca974a8eaf40803907859421506 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png new file mode 100644 index 0000000000000000000000000000000000000000..2a081f6b2ab16c16b320321417083ca3aee328c4 GIT binary patch literal 176 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqoCO|{#S9F5he4R}c>anMpkR`x zi(`ny)MSRn|NsB5X8vfU@Q>xF!Zs_9KF$*X%$M35en<$cb~5a!<Hq)$ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png.meta new file mode 100644 index 0000000..8bfeba8 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 039dc89c76661c344b7776f8a47cc5a4 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..afc2459caaa4d1c9fdb4366d6e09313f89bb081c GIT binary patch literal 103 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F5he4R}c>anMprE9u wi(^Q|oa8_M|JyTbHgu|7T`c8h%A?845Sq&@Ya68K3{=G6>FVdQ&MBb@08(HWlK=n! literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png.meta new file mode 100644 index 0000000..2a4aa36 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: dfe6e0ac3e5f24740a17e14b65e08406 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png new file mode 100644 index 0000000000000000000000000000000000000000..6480ee22a955b1ab75ba087e81c747a94a62cdfc GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprEX$ zi(^Q|oa8_M|J&;`vo>@Jon6eCIS^Qc)I$ztaD0e0stQU B9U}k$ literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png.meta new file mode 100644 index 0000000..1134262 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 93b68213089b05943a651574eb7e2fb5 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 0 + linearTexture: 1 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -3 + maxTextureSize: 32 + textureSettings: + filterMode: 0 + aniso: 1 + mipBias: -1 + wrapMode: 1 + nPOTScale: 0 + lightmap: 0 + compressionQuality: 100 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 1 + textureType: 2 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png new file mode 100644 index 0000000000000000000000000000000000000000..e6f3c427d4cf110df50530e7da40f311824d3a74 GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMkesKB zV~9m>@}K|z_e(LeHgq;R8Dt$;!MK=>hmTo8g5hrxv-7Tm-Nrzr44$rjF6*2UngB%K B9GCzA literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png.meta new file mode 100644 index 0000000..8dfc149 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 5510cdd48a6aaaa439c95ef5b2fe9e28 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png new file mode 100644 index 0000000000000000000000000000000000000000..5219f2a0fcdb4ad7dfefa5b057bc22afdc753bcd GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprEX$ zi(^Q|oa8_M|JSQ9vo>@Jon6eanMprEX$ zi(^Q|oa8_M|JU0xvo>@Jon6eanMprC@M zi(`mIZ}Ol2|Nl#}aWM!pwanMprDhd zi(`mI@7tb(f(!~AhgT`@kg+z{y}_wfa7sUa(e-~q6QQk&T=WnM6{yLex}w&TewplJ-Au6{1-oD!M<#m_AD literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png.meta new file mode 100644 index 0000000..8a6304e --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 070edb62059c27b408e16f28cb87f941 +timeCreated: 1604057757 +licenseType: Store +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 4 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ed49b005c6aff08c0586d66c4bb87d4f88a749 GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMpkRTg zi(`mI@7u{6c@HS?u*hn$ot)PZ8_}vdsl)fdV}6lLCDk2gJ^MBOsGEy19msAanMprEOz zi(`mIZ}Ol2|Lx70SsPe8Ts2J{dV-i;+V?RoPIO3=XqfaV+>7^ze35@zthVZO@Ib4c)I$ztaD0e0st)ZB(VSh literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png.meta new file mode 100644 index 0000000..27a1460 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: a40dc0d6372a9084fb45976308087290 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png new file mode 100644 index 0000000000000000000000000000000000000000..c41f635d6173527df46ed81874904da9d02e1052 GIT binary patch literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|oCO|{#S9F5he4R}c>anMprDMW zi(`n!#N?XdmdTAG2aY%>NnABpmAE1!A%TIRB8Kti3H`P6f$A7MUHx3vIVCg!0K2#w A?*IS* literal 0 HcmV?d00001 diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png.meta new file mode 100644 index 0000000..54af05b --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 517a5bfe18f2ee04d9925db10be034e2 +TextureImporter: + fileIDToRecycleName: {} + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + seamlessCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: .5, y: .5} + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spritePixelsToUnits: 100 + alphaIsTransparency: 0 + textureType: -1 + buildTargetSettings: [] + spriteSheet: + sprites: [] + spritePackingTag: + userData: diff --git a/Assets/Plugins/LubanLib.meta b/Assets/Plugins/LubanLib.meta new file mode 100644 index 0000000..e030402 --- /dev/null +++ b/Assets/Plugins/LubanLib.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e037cde050f786f48a35fc4e775dc4a4 \ No newline at end of file diff --git a/Assets/Plugins/LubanLib/BeanBase.cs b/Assets/Plugins/LubanLib/BeanBase.cs new file mode 100644 index 0000000..74e956f --- /dev/null +++ b/Assets/Plugins/LubanLib/BeanBase.cs @@ -0,0 +1,9 @@ +using Bright.Serialization; + +namespace Bright.Config +{ + public abstract class BeanBase : ITypeId + { + public abstract int GetTypeId(); + } +} diff --git a/Assets/Plugins/LubanLib/BeanBase.cs.meta b/Assets/Plugins/LubanLib/BeanBase.cs.meta new file mode 100644 index 0000000..e08a56d --- /dev/null +++ b/Assets/Plugins/LubanLib/BeanBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a1978c3ede87404e99b5429f92b2eb9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/ByteBuf.cs b/Assets/Plugins/LubanLib/ByteBuf.cs new file mode 100644 index 0000000..ead9cbd --- /dev/null +++ b/Assets/Plugins/LubanLib/ByteBuf.cs @@ -0,0 +1,1568 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Bright.Serialization +{ + + public enum EDeserializeError + { + OK, + NOT_ENOUGH, + EXCEED_SIZE, + // UNMARSHAL_ERR, + } + + public class SerializationException : Exception + { + public SerializationException() { } + public SerializationException(string msg) : base(msg) { } + + public SerializationException(string message, Exception innerException) : base(message, innerException) + { + } + } + + public readonly struct SegmentSaveState + { + public SegmentSaveState(int readerIndex, int writerIndex) + { + ReaderIndex = readerIndex; + WriterIndex = writerIndex; + } + + public int ReaderIndex { get; } + + public int WriterIndex { get; } + } + + public sealed class ByteBuf : ICloneable, IEquatable + { + public ByteBuf() + { + Bytes = Array.Empty(); + ReaderIndex = WriterIndex = 0; + } + + public ByteBuf(int capacity) + { + Bytes = capacity > 0 ? new byte[capacity] : Array.Empty(); + ReaderIndex = 0; + WriterIndex = 0; + } + + public ByteBuf(byte[] bytes) + { + Bytes = bytes; + ReaderIndex = 0; + WriterIndex = Capacity; + } + + public ByteBuf(byte[] bytes, int readIndex, int writeIndex) + { + Bytes = bytes; + ReaderIndex = readIndex; + WriterIndex = writeIndex; + } + + public ByteBuf(int capacity, Action releaser) : this(capacity) + { + _releaser = releaser; + } + + public static ByteBuf Wrap(byte[] bytes) + { + return new ByteBuf(bytes, 0, bytes.Length); + } + + public void Replace(byte[] bytes) + { + Bytes = bytes; + ReaderIndex = 0; + WriterIndex = Capacity; + } + + public void Replace(byte[] bytes, int beginPos, int endPos) + { + Bytes = bytes; + ReaderIndex = beginPos; + WriterIndex = endPos; + } + + public int ReaderIndex { get; set; } + + public int WriterIndex { get; set; } + + private readonly Action _releaser; + + public int Capacity => Bytes.Length; + + public int Size { get { return WriterIndex - ReaderIndex; } } + + public bool Empty => WriterIndex <= ReaderIndex; + + public bool NotEmpty => WriterIndex > ReaderIndex; + + + public void AddWriteIndex(int add) + { + WriterIndex += add; + } + + public void AddReadIndex(int add) + { + ReaderIndex += add; + } + +#pragma warning disable CA1819 // 属性不应返回数组 + public byte[] Bytes { get; private set; } +#pragma warning restore CA1819 // 属性不应返回数组 + + public byte[] CopyData() + { + var n = Remaining; + if (n > 0) + { + var arr = new byte[n]; + Buffer.BlockCopy(Bytes, ReaderIndex, arr, 0, n); + return arr; + } + else + { + return Array.Empty(); + } + } + + public int Remaining { get { return WriterIndex - ReaderIndex; } } + + public void DiscardReadBytes() + { + WriterIndex -= ReaderIndex; + Array.Copy(Bytes, ReaderIndex, Bytes, 0, WriterIndex); + ReaderIndex = 0; + } + + public int NotCompactWritable { get { return Capacity - WriterIndex; } } + + public void WriteBytesWithoutSize(byte[] bs) + { + WriteBytesWithoutSize(bs, 0, bs.Length); + } + + public void WriteBytesWithoutSize(byte[] bs, int offset, int len) + { + EnsureWrite(len); + Buffer.BlockCopy(bs, offset, Bytes, WriterIndex, len); + WriterIndex += len; + } + + public void Clear() + { + ReaderIndex = WriterIndex = 0; + } + + private const int MIN_CAPACITY = 16; + + private static int PropSize(int initSize, int needSize) + { + for (int i = Math.Max(initSize, MIN_CAPACITY); ; i <<= 1) + { + if (i >= needSize) + { + return i; + } + } + } + + private void EnsureWrite0(int size) + { + var needSize = WriterIndex + size - ReaderIndex; + if (needSize < Capacity) + { + WriterIndex -= ReaderIndex; + Array.Copy(Bytes, ReaderIndex, Bytes, 0, WriterIndex); + ReaderIndex = 0; + } + else + { + int newCapacity = PropSize(Capacity, needSize); + var newBytes = new byte[newCapacity]; + WriterIndex -= ReaderIndex; + Buffer.BlockCopy(Bytes, ReaderIndex, newBytes, 0, WriterIndex); + ReaderIndex = 0; + Bytes = newBytes; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureWrite(int size) + { + if (WriterIndex + size > Capacity) + { + EnsureWrite0(size); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void EnsureRead(int size) + { + if (ReaderIndex + size > WriterIndex) + { + throw new SerializationException(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool CanRead(int size) + { + return (ReaderIndex + size <= WriterIndex); + } + + public void Append(byte x) + { + EnsureWrite(1); + Bytes[WriterIndex++] = x; + } + + public void WriteBool(bool b) + { + EnsureWrite(1); + Bytes[WriterIndex++] = (byte)(b ? 1 : 0); + } + + public bool ReadBool() + { + EnsureRead(1); + return Bytes[ReaderIndex++] != 0; + } + + public void WriteByte(byte x) + { + EnsureWrite(1); + Bytes[WriterIndex++] = x; + } + + public byte ReadByte() + { + EnsureRead(1); + return Bytes[ReaderIndex++]; + } + + + public void WriteShort(short x) + { + if (x >= 0) + { + if (x < 0x80) + { + EnsureWrite(1); + Bytes[WriterIndex++] = (byte)x; + return; + } + else if (x < 0x4000) + { + EnsureWrite(2); + Bytes[WriterIndex + 1] = (byte)x; + Bytes[WriterIndex] = (byte)((x >> 8) | 0x80); + WriterIndex += 2; + return; + } + } + EnsureWrite(3); + Bytes[WriterIndex] = 0xff; + Bytes[WriterIndex + 2] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); + WriterIndex += 3; + } + + public short ReadShort() + { + EnsureRead(1); + int h = Bytes[ReaderIndex]; + if (h < 0x80) + { + ReaderIndex++; + return (short)h; + } + else if (h < 0xc0) + { + EnsureRead(2); + int x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1]; + ReaderIndex += 2; + return (short)x; + } + else if ((h == 0xff)) + { + EnsureRead(3); + int x = (Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2]; + ReaderIndex += 3; + return (short)x; + } + else + { + throw new SerializationException(); + } + } + + public short ReadFshort() + { + EnsureRead(2); + short x; +#if CPU_SUPPORT_MEMORY_NOT_ALIGN + unsafe + { + fixed (byte* b = &Bytes[ReaderIndex]) + { + x = *(short*)b; + } + } +#else + x = (short)((Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex]); + +#endif + ReaderIndex += 2; + return x; + } + + public void WriteFshort(short x) + { + EnsureWrite(2); +#if CPU_SUPPORT_MEMORY_NOT_ALIGN + unsafe + { + fixed (byte* b = &Bytes[WriterIndex]) + { + *(short*)b = x; + } + } +#else + Bytes[WriterIndex] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); +#endif + WriterIndex += 2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteInt(int x) + { + WriteUint((uint)x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadInt() + { + return (int)ReadUint(); + } + + + public void WriteUint(uint x) + { + // 如果有修改,记得也把 EndWriteSegment改了 + // 0 111 1111 + if (x < 0x80) + { + EnsureWrite(1); + Bytes[WriterIndex++] = (byte)x; + } + else if (x < 0x4000) // 10 11 1111, - + { + EnsureWrite(2); + Bytes[WriterIndex + 1] = (byte)x; + Bytes[WriterIndex] = (byte)((x >> 8) | 0x80); + WriterIndex += 2; + } + else if (x < 0x200000) // 110 1 1111, -,- + { + EnsureWrite(3); + Bytes[WriterIndex + 2] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); + Bytes[WriterIndex] = (byte)((x >> 16) | 0xc0); + WriterIndex += 3; + } + else if (x < 0x10000000) // 1110 1111,-,-,- + { + EnsureWrite(4); + Bytes[WriterIndex + 3] = (byte)x; + Bytes[WriterIndex + 2] = (byte)(x >> 8); + Bytes[WriterIndex + 1] = (byte)(x >> 16); + Bytes[WriterIndex] = (byte)((x >> 24) | 0xe0); + WriterIndex += 4; + } + else + { + EnsureWrite(5); + Bytes[WriterIndex] = 0xf0; + Bytes[WriterIndex + 4] = (byte)x; + Bytes[WriterIndex + 3] = (byte)(x >> 8); + Bytes[WriterIndex + 2] = (byte)(x >> 16); + Bytes[WriterIndex + 1] = (byte)(x >> 24); + WriterIndex += 5; + } + } + + public uint ReadUint() + { + /// + /// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets + EnsureRead(1); + uint h = Bytes[ReaderIndex]; + if (h < 0x80) + { + ReaderIndex++; + return h; + } + else if (h < 0xc0) + { + EnsureRead(2); + uint x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1]; + ReaderIndex += 2; + return x; + } + else if (h < 0xe0) + { + EnsureRead(3); + uint x = ((h & 0x1f) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2]; + ReaderIndex += 3; + return x; + } + else if (h < 0xf0) + { + + EnsureRead(4); + uint x = ((h & 0x0f) << 24) | ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3]; + ReaderIndex += 4; + return x; + } + else + { + EnsureRead(5); + uint x = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)(Bytes[ReaderIndex + 2] << 16)) | ((uint)Bytes[ReaderIndex + 3] << 8) | Bytes[ReaderIndex + 4]; + ReaderIndex += 5; + return x; + } + } + + public unsafe void WriteUint_Unsafe(uint x) + { + // 0 111 1111 + if (x < 0x80) + { + EnsureWrite(1); + Bytes[WriterIndex++] = (byte)(x << 1); + } + else if (x < 0x4000)// 10 11 1111, - + { + EnsureWrite(2); + + fixed (byte* wb = &Bytes[WriterIndex]) + { + *(uint*)(wb) = (x << 2 | 0b01); + } + + WriterIndex += 2; + } + else if (x < 0x200000) // 110 1 1111, -,- + { + EnsureWrite(3); + + fixed (byte* wb = &Bytes[WriterIndex]) + { + *(uint*)(wb) = (x << 3 | 0b011); + } + WriterIndex += 3; + } + else if (x < 0x10000000) // 1110 1111,-,-,- + { + EnsureWrite(4); + fixed (byte* wb = &Bytes[WriterIndex]) + { + *(uint*)(wb) = (x << 4 | 0b0111); + } + WriterIndex += 4; + } + else + { + EnsureWrite(5); + fixed (byte* wb = &Bytes[WriterIndex]) + { + *(uint*)(wb) = (x << 5 | 0b01111); + } + WriterIndex += 5; + } + } + + public unsafe uint ReadUint_Unsafe() + { + /// + /// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets + EnsureRead(1); + uint h = Bytes[ReaderIndex]; + if ((h & 0b1) == 0b0) + { + ReaderIndex++; + return (h >> 1); + } + else if ((h & 0b11) == 0b01) + { + EnsureRead(2); + fixed (byte* rb = &Bytes[ReaderIndex]) + { + ReaderIndex += 2; + return (*(uint*)rb) >> 2; + } + } + else if ((h & 0b111) == 0b011) + { + EnsureRead(3); + fixed (byte* rb = &Bytes[ReaderIndex]) + { + ReaderIndex += 3; + return (*(uint*)rb) >> 3; + } + } + else if ((h & 0b1111) == 0b0111) + { + EnsureRead(4); + fixed (byte* rb = &Bytes[ReaderIndex]) + { + ReaderIndex += 4; + return (*(uint*)rb) >> 4; + } + } + else + { + EnsureRead(5); + fixed (byte* rb = &Bytes[ReaderIndex]) + { + ReaderIndex += 5; + return (*(uint*)rb) >> 5; + } + } + } + + public int ReadFint() + { + EnsureRead(4); + int x; +#if CPU_SUPPORT_MEMORY_NOT_ALIGN + unsafe + { + fixed (byte* b = &Bytes[ReaderIndex]) + { + x = *(int*)b; + } + } +#else + x = (Bytes[ReaderIndex + 3] << 24) | (Bytes[ReaderIndex + 2] << 16) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]); + +#endif + ReaderIndex += 4; + return x; + } + + + public void WriteFint(int x) + { + EnsureWrite(4); +#if CPU_SUPPORT_MEMORY_NOT_ALIGN + unsafe + { + fixed (byte* b = &Bytes[WriterIndex]) + { + *(int*)b = x; + } + } +#else + Bytes[WriterIndex] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); + Bytes[WriterIndex + 2] = (byte)(x >> 16); + Bytes[WriterIndex + 3] = (byte)(x >> 24); +#endif + WriterIndex += 4; + } + + public int ReadFint_Safe() + { + EnsureRead(4); + int x; + + x = (Bytes[ReaderIndex + 3] << 24) | (Bytes[ReaderIndex + 2] << 16) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]); + + ReaderIndex += 4; + return x; + } + + + public void WriteFint_Safe(int x) + { + EnsureWrite(4); + Bytes[WriterIndex] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); + Bytes[WriterIndex + 2] = (byte)(x >> 16); + Bytes[WriterIndex + 3] = (byte)(x >> 24); + WriterIndex += 4; + } + + public void WriteLong(long x) + { + WriteUlong((ulong)x); + } + + public long ReadLong() + { + return (long)ReadUlong(); + } + + public void WriteNumberAsLong(double x) + { + WriteLong((long)x); + } + + public double ReadLongAsNumber() + { + return ReadLong(); + } + + private void WriteUlong(ulong x) + { + // 0 111 1111 + if (x < 0x80) + { + EnsureWrite(1); + Bytes[WriterIndex++] = (byte)x; + } + else if (x < 0x4000) // 10 11 1111, - + { + EnsureWrite(2); + Bytes[WriterIndex + 1] = (byte)x; + Bytes[WriterIndex] = (byte)((x >> 8) | 0x80); + WriterIndex += 2; + } + else if (x < 0x200000) // 110 1 1111, -,- + { + EnsureWrite(3); + Bytes[WriterIndex + 2] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); + Bytes[WriterIndex] = (byte)((x >> 16) | 0xc0); + WriterIndex += 3; + } + else if (x < 0x10000000) // 1110 1111,-,-,- + { + EnsureWrite(4); + Bytes[WriterIndex + 3] = (byte)x; + Bytes[WriterIndex + 2] = (byte)(x >> 8); + Bytes[WriterIndex + 1] = (byte)(x >> 16); + Bytes[WriterIndex] = (byte)((x >> 24) | 0xe0); + WriterIndex += 4; + } + else if (x < 0x800000000L) // 1111 0xxx,-,-,-,- + { + EnsureWrite(5); + Bytes[WriterIndex + 4] = (byte)x; + Bytes[WriterIndex + 3] = (byte)(x >> 8); + Bytes[WriterIndex + 2] = (byte)(x >> 16); + Bytes[WriterIndex + 1] = (byte)(x >> 24); + Bytes[WriterIndex] = (byte)((x >> 32) | 0xf0); + WriterIndex += 5; + } + else if (x < 0x40000000000L) // 1111 10xx, + { + EnsureWrite(6); + Bytes[WriterIndex + 5] = (byte)x; + Bytes[WriterIndex + 4] = (byte)(x >> 8); + Bytes[WriterIndex + 3] = (byte)(x >> 16); + Bytes[WriterIndex + 2] = (byte)(x >> 24); + Bytes[WriterIndex + 1] = (byte)(x >> 32); + Bytes[WriterIndex] = (byte)((x >> 40) | 0xf8); + WriterIndex += 6; + } + else if (x < 0x200000000000L) // 1111 110x, + { + EnsureWrite(7); + Bytes[WriterIndex + 6] = (byte)x; + Bytes[WriterIndex + 5] = (byte)(x >> 8); + Bytes[WriterIndex + 4] = (byte)(x >> 16); + Bytes[WriterIndex + 3] = (byte)(x >> 24); + Bytes[WriterIndex + 2] = (byte)(x >> 32); + Bytes[WriterIndex + 1] = (byte)(x >> 40); + Bytes[WriterIndex] = (byte)((x >> 48) | 0xfc); + WriterIndex += 7; + } + else if (x < 0x100000000000000L) // 1111 1110 + { + EnsureWrite(8); + Bytes[WriterIndex + 7] = (byte)x; + Bytes[WriterIndex + 6] = (byte)(x >> 8); + Bytes[WriterIndex + 5] = (byte)(x >> 16); + Bytes[WriterIndex + 4] = (byte)(x >> 24); + Bytes[WriterIndex + 3] = (byte)(x >> 32); + Bytes[WriterIndex + 2] = (byte)(x >> 40); + Bytes[WriterIndex + 1] = (byte)(x >> 48); + Bytes[WriterIndex] = 0xfe; + WriterIndex += 8; + } + else // 1111 1111 + { + EnsureWrite(9); + Bytes[WriterIndex] = 0xff; + Bytes[WriterIndex + 8] = (byte)x; + Bytes[WriterIndex + 7] = (byte)(x >> 8); + Bytes[WriterIndex + 6] = (byte)(x >> 16); + Bytes[WriterIndex + 5] = (byte)(x >> 24); + Bytes[WriterIndex + 4] = (byte)(x >> 32); + Bytes[WriterIndex + 3] = (byte)(x >> 40); + Bytes[WriterIndex + 2] = (byte)(x >> 48); + Bytes[WriterIndex + 1] = (byte)(x >> 56); + WriterIndex += 9; + } + } + + public ulong ReadUlong() + { + EnsureRead(1); + uint h = Bytes[ReaderIndex]; + if (h < 0x80) + { + ReaderIndex++; + return h; + } + else if (h < 0xc0) + { + EnsureRead(2); + uint x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1]; + ReaderIndex += 2; + return x; + } + else if (h < 0xe0) + { + EnsureRead(3); + uint x = ((h & 0x1f) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2]; + ReaderIndex += 3; + return x; + } + else if (h < 0xf0) + { + EnsureRead(4); + uint x = ((h & 0x0f) << 24) | ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3]; + ReaderIndex += 4; + return x; + } + else if (h < 0xf8) + { + EnsureRead(5); + uint xl = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)(Bytes[ReaderIndex + 2] << 16)) | ((uint)Bytes[ReaderIndex + 3] << 8) | (Bytes[ReaderIndex + 4]); + uint xh = h & 0x07; + ReaderIndex += 5; + return ((ulong)xh << 32) | xl; + } + else if (h < 0xfc) + { + EnsureRead(6); + uint xl = ((uint)Bytes[ReaderIndex + 2] << 24) | ((uint)(Bytes[ReaderIndex + 3] << 16)) | ((uint)Bytes[ReaderIndex + 4] << 8) | (Bytes[ReaderIndex + 5]); + uint xh = ((h & 0x03) << 8) | Bytes[ReaderIndex + 1]; + ReaderIndex += 6; + return ((ulong)xh << 32) | xl; + } + else if (h < 0xfe) + { + EnsureRead(7); + uint xl = ((uint)Bytes[ReaderIndex + 3] << 24) | ((uint)(Bytes[ReaderIndex + 4] << 16)) | ((uint)Bytes[ReaderIndex + 5] << 8) | (Bytes[ReaderIndex + 6]); + uint xh = ((h & 0x01) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2]; + ReaderIndex += 7; + return ((ulong)xh << 32) | xl; + } + else if (h < 0xff) + { + EnsureRead(8); + uint xl = ((uint)Bytes[ReaderIndex + 4] << 24) | ((uint)(Bytes[ReaderIndex + 5] << 16)) | ((uint)Bytes[ReaderIndex + 6] << 8) | (Bytes[ReaderIndex + 7]); + uint xh = /*((h & 0x01) << 24) |*/ ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3]; + ReaderIndex += 8; + return ((ulong)xh << 32) | xl; + } + else + { + EnsureRead(9); + uint xl = ((uint)Bytes[ReaderIndex + 5] << 24) | ((uint)(Bytes[ReaderIndex + 6] << 16)) | ((uint)Bytes[ReaderIndex + 7] << 8) | (Bytes[ReaderIndex + 8]); + uint xh = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)Bytes[ReaderIndex + 2] << 16) | ((uint)Bytes[ReaderIndex + 3] << 8) | Bytes[ReaderIndex + 4]; + ReaderIndex += 9; + return ((ulong)xh << 32) | xl; + } + } + + + public void WriteFlong(long x) + { + EnsureWrite(8); +#if CPU_SUPPORT_MEMORY_NOT_ALIGN + unsafe + { + fixed (byte* b = &Bytes[WriterIndex]) + { + *(long*)b = x; + } + } +#else + + Bytes[WriterIndex] = (byte)x; + Bytes[WriterIndex + 1] = (byte)(x >> 8); + Bytes[WriterIndex + 2] = (byte)(x >> 16); + Bytes[WriterIndex + 3] = (byte)(x >> 24); + Bytes[WriterIndex + 4] = (byte)(x >> 32); + Bytes[WriterIndex + 5] = (byte)(x >> 40); + Bytes[WriterIndex + 6] = (byte)(x >> 48); + Bytes[WriterIndex + 7] = (byte)(x >> 56); +#endif + WriterIndex += 8; + } + + public long ReadFlong() + { + EnsureRead(8); + long x; +#if CPU_SUPPORT_MEMORY_NOT_ALIGN + unsafe + { + fixed (byte* b = &Bytes[ReaderIndex]) + { + x = *(long*)b; + } + } +#else + int xl = (Bytes[ReaderIndex + 3] << 24) | ((Bytes[ReaderIndex + 2] << 16)) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]); + int xh = (Bytes[ReaderIndex + 7] << 24) | (Bytes[ReaderIndex + 6] << 16) | (Bytes[ReaderIndex + 5] << 8) | Bytes[ReaderIndex + 4]; + x = ((long)xh << 32) | (long)xl; +#endif + ReaderIndex += 8; + return x; + } + + private static unsafe void Copy8(byte* dst, byte* src) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + dst[4] = src[4]; + dst[5] = src[5]; + dst[6] = src[6]; + dst[7] = src[7]; + } + + private static unsafe void Copy4(byte* dst, byte* src) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = src[3]; + } + + + //const bool isLittleEndian = true; + public void WriteFloat(float x) + { + EnsureWrite(4); + unsafe + { + fixed (byte* b = &Bytes[WriterIndex]) + { +#if !CPU_SUPPORT_MEMORY_NOT_ALIGN + if ((long)b % 4 == 0) + { + *(float*)b = x; + } + else + { + Copy4(b, (byte*)&x); + } +#else + *(float*)b = x; +#endif + } + } + + //if (!BitConverter.IsLittleEndian) + //{ + // Array.Reverse(data, endPos, 4); + //} + WriterIndex += 4; + } + + public float ReadFloat() + { + EnsureRead(4); + //if (!BitConverter.IsLittleEndian) + //{ + // Array.Reverse(data, beginPos, 4); + //} + float x; + unsafe + { + fixed (byte* b = &Bytes[ReaderIndex]) + { +#if !CPU_SUPPORT_MEMORY_NOT_ALIGN + if ((long)b % 4 == 0) + { + x = *(float*)b; + } + else + { + *((int*)&x) = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + } +#else + x = *(float*)b; +#endif + } + } + + ReaderIndex += 4; + return x; + } + + public void WriteDouble(double x) + { + EnsureWrite(8); + unsafe + { + fixed (byte* b = &Bytes[WriterIndex]) + { +#if !CPU_SUPPORT_MEMORY_NOT_ALIGN + if ((long)b % 8 == 0) + { + *(double*)b = x; + } + else + { + Copy8(b, (byte*)&x); + } +#else + *(double*)b = x; +#endif + } + //if (!BitConverter.IsLittleEndian) + //{ + // Array.Reverse(data, endPos, 8); + //} + } + + WriterIndex += 8; + } + + public double ReadDouble() + { + EnsureRead(8); + //if (!BitConverter.IsLittleEndian) + //{ + // Array.Reverse(data, beginPos, 8); + //} + double x; + unsafe + { + fixed (byte* b = &Bytes[ReaderIndex]) + { +#if !CPU_SUPPORT_MEMORY_NOT_ALIGN + if ((long)b % 8 == 0) + { + x = *(double*)b; + } + else + { + int low = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); + int high = (b[4]) | (b[5] << 8) | (b[6] << 16) | (b[7] << 24); + *((long*)&x) = ((long)high << 32) | (uint)low; + } +#else + x = *(double*)b; +#endif + } + } + + ReaderIndex += 8; + return x; + } + + public void WriteSize(int n) + { + WriteUint((uint)n); + } + + public int ReadSize() + { + return (int)ReadUint(); + } + + // marshal int + // n -> (n << 1) ^ (n >> 31) + // Read + // (x >>> 1) ^ ((x << 31) >> 31) + // (x >>> 1) ^ -(n&1) + public void WriteSint(int x) + { + WriteUint(((uint)x << 1) ^ ((uint)x >> 31)); + } + + public int ReadSint() + { + uint x = ReadUint(); + return (int)((x >> 1) ^ ((x & 1) << 31)); + } + + + // marshal long + // n -> (n << 1) ^ (n >> 63) + // Read + // (x >>> 1) ^((x << 63) >> 63) + // (x >>> 1) ^ -(n&1L) + public void WriteSlong(long x) + { + WriteUlong(((ulong)x << 1) ^ ((ulong)x >> 63)); + } + + public long ReadSlong() + { + long x = ReadLong(); + return ((long)((ulong)x >> 1) ^ ((x & 1) << 63)); + } + + public void WriteString(string x) + { + var n = x != null ? Encoding.UTF8.GetByteCount(x) : 0; + WriteSize(n); + if (n > 0) + { + EnsureWrite(n); + Encoding.UTF8.GetBytes(x, 0, x.Length, Bytes, WriterIndex); + WriterIndex += n; + } + } + + // byte[], [start, end) + public static Func StringCacheFinder { get; set; } + + public string ReadString() + { + var n = ReadSize(); + if (n > 0) + { + EnsureRead(n); + string s; + + if (StringCacheFinder == null) + { + s = Encoding.UTF8.GetString(Bytes, ReaderIndex, n); + } + else + { + // 只缓存比较小的字符串 + s = StringCacheFinder(Bytes, ReaderIndex, n); + } + ReaderIndex += n; + return s; + } + else + { + return string.Empty; + } + } + + public void WriteBytes(byte[] x) + { + var n = x != null ? x.Length : 0; + WriteSize(n); + if (n > 0) + { + EnsureWrite(n); + x.CopyTo(Bytes, WriterIndex); + WriterIndex += n; + } + } + + public byte[] ReadBytes() + { + var n = ReadSize(); + if (n > 0) + { + EnsureRead(n); + var x = new byte[n]; + Buffer.BlockCopy(Bytes, ReaderIndex, x, 0, n); + ReaderIndex += n; + return x; + } + else + { + return Array.Empty(); + } + } + + // 以下是一些特殊类型 + + public void WriteComplex(Complex x) + { + WriteDouble(x.Real); + WriteDouble(x.Imaginary); + } + + public Complex ReadComplex() + { + var x = ReadDouble(); + var y = ReadDouble(); + return new Complex(x, y); + } + + public void WriteVector2(Vector2 x) + { + WriteFloat(x.X); + WriteFloat(x.Y); + } + + public Vector2 ReadVector2() + { + float x = ReadFloat(); + float y = ReadFloat(); + return new Vector2(x, y); + } + + public void WriteVector3(Vector3 x) + { + WriteFloat(x.X); + WriteFloat(x.Y); + WriteFloat(x.Z); + } + + public Vector3 ReadVector3() + { + float x = ReadFloat(); + float y = ReadFloat(); + float z = ReadFloat(); + return new Vector3(x, y, z); + } + + public void WriteVector4(Vector4 x) + { + WriteFloat(x.X); + WriteFloat(x.Y); + WriteFloat(x.Z); + WriteFloat(x.W); + } + + public Vector4 ReadVector4() + { + float x = ReadFloat(); + float y = ReadFloat(); + float z = ReadFloat(); + float w = ReadFloat(); + return new Vector4(x, y, z, w); + } + + + public void WriteQuaternion(Quaternion x) + { + WriteFloat(x.X); + WriteFloat(x.Y); + WriteFloat(x.Z); + WriteFloat(x.W); + } + + public Quaternion ReadQuaternion() + { + float x = ReadFloat(); + float y = ReadFloat(); + float z = ReadFloat(); + float w = ReadFloat(); + return new Quaternion(x, y, z, w); + } + + + public void WriteMatrix4x4(Matrix4x4 x) + { + WriteFloat(x.M11); + WriteFloat(x.M12); + WriteFloat(x.M13); + WriteFloat(x.M14); + WriteFloat(x.M21); + WriteFloat(x.M22); + WriteFloat(x.M23); + WriteFloat(x.M24); + WriteFloat(x.M31); + WriteFloat(x.M32); + WriteFloat(x.M33); + WriteFloat(x.M34); + WriteFloat(x.M41); + WriteFloat(x.M42); + WriteFloat(x.M43); + WriteFloat(x.M44); + } + + public Matrix4x4 ReadMatrix4x4() + { + float m11 = ReadFloat(); + float m12 = ReadFloat(); + float m13 = ReadFloat(); + float m14 = ReadFloat(); + float m21 = ReadFloat(); + float m22 = ReadFloat(); + float m23 = ReadFloat(); + float m24 = ReadFloat(); + float m31 = ReadFloat(); + float m32 = ReadFloat(); + float m33 = ReadFloat(); + float m34 = ReadFloat(); + float m41 = ReadFloat(); + float m42 = ReadFloat(); + float m43 = ReadFloat(); + float m44 = ReadFloat(); + return new Matrix4x4(m11, m12, m13, m14, + m21, m22, m23, m24, + m31, m32, m33, m34, + m41, m42, m43, m44); + } + + internal void SkipBytes() + { + int n = ReadSize(); + EnsureRead(n); + ReaderIndex += n; + } + + + public void WriteByteBufWithSize(ByteBuf o) + { + int n = o.Size; + if (n > 0) + { + WriteSize(n); + WriteBytesWithoutSize(o.Bytes, o.ReaderIndex, n); + } + else + { + WriteByte(0); + } + } + + public void WriteByteBufWithoutSize(ByteBuf o) + { + int n = o.Size; + if (n > 0) + { + WriteBytesWithoutSize(o.Bytes, o.ReaderIndex, n); + } + } + + public bool TryReadByte(out byte x) + { + if (CanRead(1)) + { + x = Bytes[ReaderIndex++]; + return true; + } + else + { + x = 0; + return false; + } + } + + public EDeserializeError TryDeserializeInplaceByteBuf(int maxSize, ByteBuf inplaceTempBody) + { + //if (!CanRead(1)) { return EDeserializeError.NOT_ENOUGH; } + int oldReadIndex = ReaderIndex; + bool commit = false; + try + { + int n; + int h = Bytes[ReaderIndex]; + if (h < 0x80) + { + ReaderIndex++; + n = h; + } + else if (h < 0xc0) + { + if (!CanRead(2)) { return EDeserializeError.NOT_ENOUGH; } + n = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1]; + ReaderIndex += 2; + } + else if (h < 0xe0) + { + if (!CanRead(3)) { return EDeserializeError.NOT_ENOUGH; } + n = ((h & 0x1f) << 16) | (Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2]; + ReaderIndex += 3; + } + else if (h < 0xf0) + { + if (!CanRead(4)) { return EDeserializeError.NOT_ENOUGH; } + n = ((h & 0x0f) << 24) | (Bytes[ReaderIndex + 1] << 16) | (Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3]; + ReaderIndex += 4; + } + else + { + return EDeserializeError.EXCEED_SIZE; + } + + if (n > maxSize) + { + return EDeserializeError.EXCEED_SIZE; + } + if (Remaining < n) + { + return EDeserializeError.NOT_ENOUGH; + } + + int inplaceReadIndex = ReaderIndex; + ReaderIndex += n; + + inplaceTempBody.Replace(Bytes, inplaceReadIndex, ReaderIndex); + commit = true; + } + finally + { + if (!commit) + { + ReaderIndex = oldReadIndex; + } + } + + return EDeserializeError.OK; + } + + public void WriteRawTag(byte b1) + { + EnsureWrite(1); + Bytes[WriterIndex++] = b1; + } + + public void WriteRawTag(byte b1, byte b2) + { + EnsureWrite(2); + Bytes[WriterIndex] = b1; + Bytes[WriterIndex + 1] = b2; + WriterIndex += 2; + } + + public void WriteRawTag(byte b1, byte b2, byte b3) + { + EnsureWrite(3); + Bytes[WriterIndex] = b1; + Bytes[WriterIndex + 1] = b2; + Bytes[WriterIndex + 2] = b3; + WriterIndex += 3; + } + + #region segment + + + public void BeginWriteSegment(out int oldSize) + { + oldSize = Size; + EnsureWrite(1); + WriterIndex += 1; + } + + public void EndWriteSegment(int oldSize) + { + int startPos = ReaderIndex + oldSize; + int segmentSize = WriterIndex - startPos - 1; + + // 0 111 1111 + if (segmentSize < 0x80) + { + Bytes[startPos] = (byte)segmentSize; + } + else if (segmentSize < 0x4000) // 10 11 1111, - + { + EnsureWrite(1); + Bytes[WriterIndex] = Bytes[startPos + 1]; + Bytes[startPos + 1] = (byte)segmentSize; + + Bytes[startPos] = (byte)((segmentSize >> 8) | 0x80); + WriterIndex += 1; + } + else if (segmentSize < 0x200000) // 110 1 1111, -,- + { + EnsureWrite(2); + Bytes[WriterIndex + 1] = Bytes[startPos + 2]; + Bytes[startPos + 2] = (byte)segmentSize; + + Bytes[WriterIndex] = Bytes[startPos + 1]; + Bytes[startPos + 1] = (byte)(segmentSize >> 8); + + Bytes[startPos] = (byte)((segmentSize >> 16) | 0xc0); + WriterIndex += 2; + } + else if (segmentSize < 0x10000000) // 1110 1111,-,-,- + { + EnsureWrite(3); + Bytes[WriterIndex + 2] = Bytes[startPos + 3]; + Bytes[startPos + 3] = (byte)segmentSize; + + Bytes[WriterIndex + 1] = Bytes[startPos + 2]; + Bytes[startPos + 2] = (byte)(segmentSize >> 8); + + Bytes[WriterIndex] = Bytes[startPos + 1]; + Bytes[startPos + 1] = (byte)(segmentSize >> 16); + + Bytes[startPos] = (byte)((segmentSize >> 24) | 0xe0); + WriterIndex += 3; + } + else + { + throw new SerializationException("exceed max segment size"); + } + } + + public void ReadSegment(out int startIndex, out int segmentSize) + { + EnsureRead(1); + int h = Bytes[ReaderIndex++]; + + startIndex = ReaderIndex; + + if (h < 0x80) + { + segmentSize = h; + ReaderIndex += segmentSize; + } + else if (h < 0xc0) + { + EnsureRead(1); + segmentSize = ((h & 0x3f) << 8) | Bytes[ReaderIndex]; + int endPos = ReaderIndex + segmentSize; + Bytes[ReaderIndex] = Bytes[endPos]; + ReaderIndex += segmentSize + 1; + } + else if (h < 0xe0) + { + EnsureRead(2); + segmentSize = ((h & 0x1f) << 16) | ((int)Bytes[ReaderIndex] << 8) | Bytes[ReaderIndex + 1]; + int endPos = ReaderIndex + segmentSize; + Bytes[ReaderIndex] = Bytes[endPos]; + Bytes[ReaderIndex + 1] = Bytes[endPos + 1]; + ReaderIndex += segmentSize + 2; + } + else if (h < 0xf0) + { + EnsureRead(3); + segmentSize = ((h & 0x0f) << 24) | ((int)Bytes[ReaderIndex] << 16) | ((int)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2]; + int endPos = ReaderIndex + segmentSize; + Bytes[ReaderIndex] = Bytes[endPos]; + Bytes[ReaderIndex + 1] = Bytes[endPos + 1]; + Bytes[ReaderIndex + 2] = Bytes[endPos + 2]; + ReaderIndex += segmentSize + 3; + } + else + { + throw new SerializationException("exceed max size"); + } + if (ReaderIndex > WriterIndex) + { + throw new SerializationException("segment data not enough"); + } + } + + public void ReadSegment(ByteBuf buf) + { + ReadSegment(out int startPos, out var size); + buf.Bytes = Bytes; + buf.ReaderIndex = startPos; + buf.WriterIndex = startPos + size; + } + + public void EnterSegment(out SegmentSaveState saveState) + { + ReadSegment(out int startPos, out int size); + + saveState = new SegmentSaveState(ReaderIndex, WriterIndex); + ReaderIndex = startPos; + WriterIndex = startPos + size; + } + + public void LeaveSegment(SegmentSaveState saveState) + { + ReaderIndex = saveState.ReaderIndex; + WriterIndex = saveState.WriterIndex; + } + + #endregion + + public override string ToString() + { + string[] datas = new string[WriterIndex - ReaderIndex]; + for (var i = ReaderIndex; i < WriterIndex; i++) + { + datas[i - ReaderIndex] = Bytes[i].ToString("X2"); + } + return string.Join(".", datas); + } + + public override bool Equals(object obj) + { + return (obj is ByteBuf other) && Equals(other); + } + + public bool Equals(ByteBuf other) + { + if (other == null) + { + return false; + } + if (Size != other.Size) + { + return false; + } + for (int i = 0, n = Size; i < n; i++) + { + if (Bytes[ReaderIndex + i] != other.Bytes[other.ReaderIndex + i]) + { + return false; + } + } + return true; + } + + public object Clone() + { + return new ByteBuf(CopyData()); + } + + + public static ByteBuf FromString(string value) + { + var ss = value.Split(','); + byte[] data = new byte[ss.Length]; + for (int i = 0; i < data.Length; i++) + { + data[i] = byte.Parse(ss[i]); + } + return new ByteBuf(data); + } + + public override int GetHashCode() + { + int hash = 17; + for (int i = ReaderIndex; i < WriterIndex; i++) + { + hash = hash * 23 + Bytes[i]; + } + return hash; + } + + public void Release() + { + _releaser?.Invoke(this); + } + +#if SUPPORT_PUERTS_ARRAYBUF + // -- add for puerts + public Puerts.ArrayBuffer ReadArrayBuffer() + { + return new Puerts.ArrayBuffer(ReadBytes()); + } + + public void WriteArrayBuffer(Puerts.ArrayBuffer bytes) + { + WriteBytes(bytes.Bytes); + } +#endif + } +} diff --git a/Assets/Plugins/LubanLib/ByteBuf.cs.meta b/Assets/Plugins/LubanLib/ByteBuf.cs.meta new file mode 100644 index 0000000..86e2fd1 --- /dev/null +++ b/Assets/Plugins/LubanLib/ByteBuf.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07bfa7e432cf1334ca285411f9c97a9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/ITypeId.cs b/Assets/Plugins/LubanLib/ITypeId.cs new file mode 100644 index 0000000..2b8d71a --- /dev/null +++ b/Assets/Plugins/LubanLib/ITypeId.cs @@ -0,0 +1,7 @@ +namespace Bright.Serialization +{ + public interface ITypeId + { + int GetTypeId(); + } +} diff --git a/Assets/Plugins/LubanLib/ITypeId.cs.meta b/Assets/Plugins/LubanLib/ITypeId.cs.meta new file mode 100644 index 0000000..5ca1ea0 --- /dev/null +++ b/Assets/Plugins/LubanLib/ITypeId.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08eef6b77ab6ede4997166dc812a918f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/LubanLib.asmdef b/Assets/Plugins/LubanLib/LubanLib.asmdef new file mode 100644 index 0000000..da6c53d --- /dev/null +++ b/Assets/Plugins/LubanLib/LubanLib.asmdef @@ -0,0 +1,14 @@ +{ + "name": "LubanLib", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Plugins/LubanLib/LubanLib.asmdef.meta b/Assets/Plugins/LubanLib/LubanLib.asmdef.meta new file mode 100644 index 0000000..e3ccd5e --- /dev/null +++ b/Assets/Plugins/LubanLib/LubanLib.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ed1b300e696ae6e46a63f47366f445eb +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON.meta b/Assets/Plugins/LubanLib/SimpleJSON.meta new file mode 100644 index 0000000..bc7a627 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 01830ef12a97cf045bd989f2484f73ce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt b/Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt new file mode 100644 index 0000000..9a78f25 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt @@ -0,0 +1,111 @@ +/* + * [2012-06-09 First Version] + * - provides strongly typed node classes and lists / dictionaries + * - provides easy access to class members / array items / data values + * - the parser now properly identifies types. So generating JSON with this framework should work. + * - only double quotes (") are used for quoting strings. + * - provides "casting" properties to easily convert to / from those types: + * int / float / double / bool + * - provides a common interface for each node so no explicit casting is required. + * - the parser tries to avoid errors, but if malformed JSON is parsed the result is more or less undefined + * - It can serialize/deserialize a node tree into/from an experimental compact binary format. It might + * be handy if you want to store things in a file and don't want it to be easily modifiable + * + * [2012-12-17 Update] + * - Added internal JSONLazyCreator class which simplifies the construction of a JSON tree + * Now you can simple reference any item that doesn't exist yet and it will return a JSONLazyCreator + * The class determines the required type by it's further use, creates the type and removes itself. + * - Added binary serialization / deserialization. + * - Added support for BZip2 zipped binary format. Requires the SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) + * The usage of the SharpZipLib library can be disabled by removing or commenting out the USE_SharpZipLib define at the top + * - The serializer uses different types when it comes to store the values. Since my data values + * are all of type string, the serializer will "try" which format fits best. The order is: int, float, double, bool, string. + * It's not the most efficient way but for a moderate amount of data it should work on all platforms. + * + * [2017-03-08 Update] + * - Optimised parsing by using a StringBuilder for token. This prevents performance issues when large + * string data fields are contained in the json data. + * - Finally refactored the badly named JSONClass into JSONObject. + * - Replaced the old JSONData class by distict typed classes ( JSONString, JSONNumber, JSONBool, JSONNull ) this + * allows to propertly convert the node tree back to json without type information loss. The actual value + * parsing now happens at parsing time and not when you actually access one of the casting properties. + * + * [2017-04-11 Update] + * - Fixed parsing bug where empty string values have been ignored. + * - Optimised "ToString" by using a StringBuilder internally. This should heavily improve performance for large files + * - Changed the overload of "ToString(string aIndent)" to "ToString(int aIndent)" + * + * [2017-11-29 Update] + * - Removed the IEnumerator implementations on JSONArray & JSONObject and replaced it with a common + * struct Enumerator in JSONNode that should avoid garbage generation. The enumerator always works + * on KeyValuePair, even for JSONArray. + * - Added two wrapper Enumerators that allows for easy key or value enumeration. A JSONNode now has + * a "Keys" and a "Values" enumerable property. Those are also struct enumerators / enumerables + * - A KeyValuePair can now be implicitly converted into a JSONNode. This allows + * a foreach loop over a JSONNode to directly access the values only. Since KeyValuePair as well as + * all the Enumerators are structs, no garbage is allocated. + * - To add Linq support another "LinqEnumerator" is available through the "Linq" property. This + * enumerator does implement the generic IEnumerable interface so most Linq extensions can be used + * on this enumerable object. This one does allocate memory as it's a wrapper class. + * - The Escape method now escapes all control characters (# < 32) in strings as uncode characters + * (\uXXXX) and if the static bool JSONNode.forceASCII is set to true it will also escape all + * characters # > 127. This might be useful if you require an ASCII output. Though keep in mind + * when your strings contain many non-ascii characters the strings become much longer (x6) and are + * no longer human readable. + * - The node types JSONObject and JSONArray now have an "Inline" boolean switch which will default to + * false. It can be used to serialize this element inline even you serialize with an indented format + * This is useful for arrays containing numbers so it doesn't place every number on a new line + * - Extracted the binary serialization code into a seperate extension file. All classes are now declared + * as "partial" so an extension file can even add a new virtual or abstract method / interface to + * JSONNode and override it in the concrete type classes. It's of course a hacky approach which is + * generally not recommended, but i wanted to keep everything tightly packed. + * - Added a static CreateOrGet method to the JSONNull class. Since this class is immutable it could + * be reused without major problems. If you have a lot null fields in your data it will help reduce + * the memory / garbage overhead. I also added a static setting (reuseSameInstance) to JSONNull + * (default is true) which will change the behaviour of "CreateOrGet". If you set this to false + * CreateOrGet will not reuse the cached instance but instead create a new JSONNull instance each time. + * I made the JSONNull constructor private so if you need to create an instance manually use + * JSONNull.CreateOrGet() + * + * [2018-01-09 Update] + * - Changed all double.TryParse and double.ToString uses to use the invariant culture to avoid problems + * on systems with a culture that uses a comma as decimal point. + * + * [2018-01-26 Update] + * - Added AsLong. Note that a JSONNumber is stored as double and can't represent all long values. However + * storing it as string would work. + * - Added static setting "JSONNode.longAsString" which controls the default type that is used by the + * LazyCreator when using AsLong + * + * [2018-04-25 Update] + * - Added support for parsing single values (JSONBool, JSONString, JSONNumber, JSONNull) as top level value. + * + * [2019-02-18 Update] + * - Added HasKey(key) and GetValueOrDefault(key, default) to the JSONNode class to provide way to read + * values conditionally without creating a LazyCreator + * + * [2019-03-25 Update] + * - Added static setting "allowLineComments" to the JSONNode class which is true by default. This allows + * "//" line comments when parsing json text as long as it's not within quoted text. All text after // up + * to the end of the line is completely ignored / skipped. This makes it easier to create human readable + * and editable files. Note that stripped comments are not read, processed or preserved in any way. So + * this feature is only relevant for human created files. + * - Explicitly strip BOM (Byte Order Mark) when parsing to avoid getting it leaked into a single primitive + * value. That's a rare case but better safe than sorry. + * - Allowing adding the empty string as key + * + * [2019-12-10 Update] + * - Added Clone() method to JSONNode to allow cloning of a whole node tree. + * + * [2020-09-19 Update] + * - Added Clear() method to JSONNode. + * - The parser will now automatically mark arrays or objects as inline when it doesn't contain any + * new line characters. This should more or less preserve the layout. + * - Added new extension file "SimpleJSONDotNetTypes.cs" to provide support for some basic .NET types + * like decimal, char, byte, sbyte, short, ushort, uint, DateTime, TimeSpan and Guid as well as some + * nullable types. + * - Fixed an error in the Unity extension file. The Color component order was wrong (it was argb, now it's rgba) + * - There are now two static float variables (ColorDefaultAlpha and Color32DefaultAlpha) to specify the default + * alpha values when reading UnityEngine.Color / Color32 values where the alpha value is absent. The default + * values are 1.0f and 255 respectively. + */ diff --git a/Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt.meta b/Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt.meta new file mode 100644 index 0000000..1e87cf7 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/Changelog.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 35336dcb5aad4cf45b523dbf1482a514 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/LICENSE b/Assets/Plugins/LubanLib/SimpleJSON/LICENSE new file mode 100644 index 0000000..c41ebf5 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012-2017 Markus Göbel (Bunny83) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/Plugins/LubanLib/SimpleJSON/LICENSE.meta b/Assets/Plugins/LubanLib/SimpleJSON/LICENSE.meta new file mode 100644 index 0000000..0d770a0 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4615d3ebbd0d7ae4fa8c107f727bbab4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/README b/Assets/Plugins/LubanLib/SimpleJSON/README new file mode 100644 index 0000000..e69de29 diff --git a/Assets/Plugins/LubanLib/SimpleJSON/README.meta b/Assets/Plugins/LubanLib/SimpleJSON/README.meta new file mode 100644 index 0000000..07995b5 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/README.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0b3e755f11799b5458a47d6b897a9393 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs new file mode 100644 index 0000000..4777724 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs @@ -0,0 +1,1434 @@ +/* * * * * + * A simple JSON Parser / builder + * ------------------------------ + * + * It mainly has been written as a simple JSON parser. It can build a JSON string + * from the node-tree, or generate a node tree from any valid JSON string. + * + * Written by Bunny83 + * 2012-06-09 + * + * Changelog now external. See Changelog.txt + * + * The MIT License (MIT) + * + * Copyright (c) 2012-2019 Markus Göbel (Bunny83) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * * * * */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; + +namespace SimpleJSON +{ + public enum JSONNodeType + { + Array = 1, + Object = 2, + String = 3, + Number = 4, + NullValue = 5, + Boolean = 6, + None = 7, + Custom = 0xFF, + } + public enum JSONTextMode + { + Compact, + Indent + } + + public abstract partial class JSONNode + { + #region Enumerators + public struct Enumerator + { + private enum Type { None, Array, Object } + private Type type; + private Dictionary.Enumerator m_Object; + private List.Enumerator m_Array; + public bool IsValid { get { return type != Type.None; } } + public Enumerator(List.Enumerator aArrayEnum) + { + type = Type.Array; + m_Object = default(Dictionary.Enumerator); + m_Array = aArrayEnum; + } + public Enumerator(Dictionary.Enumerator aDictEnum) + { + type = Type.Object; + m_Object = aDictEnum; + m_Array = default(List.Enumerator); + } + public KeyValuePair Current + { + get + { + if (type == Type.Array) + return new KeyValuePair(string.Empty, m_Array.Current); + else if (type == Type.Object) + return m_Object.Current; + return new KeyValuePair(string.Empty, null); + } + } + public bool MoveNext() + { + if (type == Type.Array) + return m_Array.MoveNext(); + else if (type == Type.Object) + return m_Object.MoveNext(); + return false; + } + } + public struct ValueEnumerator + { + private Enumerator m_Enumerator; + public ValueEnumerator(List.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } + public ValueEnumerator(Dictionary.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } + public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } + public JSONNode Current { get { return m_Enumerator.Current.Value; } } + public bool MoveNext() { return m_Enumerator.MoveNext(); } + public ValueEnumerator GetEnumerator() { return this; } + } + public struct KeyEnumerator + { + private Enumerator m_Enumerator; + public KeyEnumerator(List.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } + public KeyEnumerator(Dictionary.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } + public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } + public string Current { get { return m_Enumerator.Current.Key; } } + public bool MoveNext() { return m_Enumerator.MoveNext(); } + public KeyEnumerator GetEnumerator() { return this; } + } + + public class LinqEnumerator : IEnumerator>, IEnumerable> + { + private JSONNode m_Node; + private Enumerator m_Enumerator; + internal LinqEnumerator(JSONNode aNode) + { + m_Node = aNode; + if (m_Node != null) + m_Enumerator = m_Node.GetEnumerator(); + } + public KeyValuePair Current { get { return m_Enumerator.Current; } } + object IEnumerator.Current { get { return m_Enumerator.Current; } } + public bool MoveNext() { return m_Enumerator.MoveNext(); } + + public void Dispose() + { + m_Node = null; + m_Enumerator = new Enumerator(); + } + + public IEnumerator> GetEnumerator() + { + return new LinqEnumerator(m_Node); + } + + public void Reset() + { + if (m_Node != null) + m_Enumerator = m_Node.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return new LinqEnumerator(m_Node); + } + } + + #endregion Enumerators + + #region common interface + + public static bool forceASCII = false; // Use Unicode by default + public static bool longAsString = false; // lazy creator creates a JSONString instead of JSONNumber + public static bool allowLineComments = true; // allow "//"-style comments at the end of a line + + public abstract JSONNodeType Tag { get; } + + public virtual JSONNode this[int aIndex] { get { return null; } set { } } + + public virtual JSONNode this[string aKey] { get { return null; } set { } } + + public virtual string Value { get { return ""; } set { } } + + public virtual int Count { get { return 0; } } + + public virtual bool IsNumber { get { return false; } } + public virtual bool IsString { get { return false; } } + public virtual bool IsBoolean { get { return false; } } + public virtual bool IsNull { get { return false; } } + public virtual bool IsArray { get { return false; } } + public virtual bool IsObject { get { return false; } } + + public virtual bool Inline { get { return false; } set { } } + + public virtual void Add(string aKey, JSONNode aItem) + { + } + public virtual void Add(JSONNode aItem) + { + Add("", aItem); + } + + public virtual JSONNode Remove(string aKey) + { + return null; + } + + public virtual JSONNode Remove(int aIndex) + { + return null; + } + + public virtual JSONNode Remove(JSONNode aNode) + { + return aNode; + } + public virtual void Clear() { } + + public virtual JSONNode Clone() + { + return null; + } + + public virtual IEnumerable Children + { + get + { + yield break; + } + } + + public IEnumerable DeepChildren + { + get + { + foreach (var C in Children) + foreach (var D in C.DeepChildren) + yield return D; + } + } + + public virtual bool HasKey(string aKey) + { + return false; + } + + public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault) + { + return aDefault; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact); + return sb.ToString(); + } + + public virtual string ToString(int aIndent) + { + StringBuilder sb = new StringBuilder(); + WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent); + return sb.ToString(); + } + internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode); + + public abstract Enumerator GetEnumerator(); + public IEnumerable> Linq { get { return new LinqEnumerator(this); } } + public KeyEnumerator Keys { get { return new KeyEnumerator(GetEnumerator()); } } + public ValueEnumerator Values { get { return new ValueEnumerator(GetEnumerator()); } } + + #endregion common interface + + #region typecasting properties + + + public virtual double AsDouble + { + get + { + double v = 0.0; + if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) + return v; + return 0.0; + } + set + { + Value = value.ToString(CultureInfo.InvariantCulture); + } + } + + public virtual int AsInt + { + get { return (int)AsDouble; } + set { AsDouble = value; } + } + + public virtual float AsFloat + { + get { return (float)AsDouble; } + set { AsDouble = value; } + } + + 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 long AsLong + { + get + { + long val = 0; + if (long.TryParse(Value, out val)) + return val; + return 0L; + } + set + { + Value = value.ToString(); + } + } + + public virtual ulong AsULong + { + get + { + ulong val = 0; + if (ulong.TryParse(Value, out val)) + return val; + return 0; + } + set + { + Value = value.ToString(); + } + } + + public virtual JSONArray AsArray + { + get + { + return this as JSONArray; + } + } + + public virtual JSONObject AsObject + { + get + { + return this as JSONObject; + } + } + + + #endregion typecasting properties + + #region operators + + public static implicit operator JSONNode(string s) + { + return (s == null) ? (JSONNode) JSONNull.CreateOrGet() : new JSONString(s); + } + public static implicit operator string(JSONNode d) + { + return (d == null) ? null : d.Value; + } + + public static implicit operator JSONNode(double n) + { + return new JSONNumber(n); + } + public static implicit operator double(JSONNode d) + { + return (d == null) ? 0 : d.AsDouble; + } + + public static implicit operator JSONNode(float n) + { + return new JSONNumber(n); + } + public static implicit operator float(JSONNode d) + { + return (d == null) ? 0 : d.AsFloat; + } + + public static implicit operator JSONNode(int n) + { + return new JSONNumber(n); + } + public static implicit operator int(JSONNode d) + { + return (d == null) ? 0 : d.AsInt; + } + + public static implicit operator JSONNode(long n) + { + if (longAsString) + return new JSONString(n.ToString()); + return new JSONNumber(n); + } + public static implicit operator long(JSONNode d) + { + return (d == null) ? 0L : d.AsLong; + } + + public static implicit operator JSONNode(ulong n) + { + if (longAsString) + return new JSONString(n.ToString()); + return new JSONNumber(n); + } + public static implicit operator ulong(JSONNode d) + { + return (d == null) ? 0 : d.AsULong; + } + + public static implicit operator JSONNode(bool b) + { + return new JSONBool(b); + } + public static implicit operator bool(JSONNode d) + { + return (d == null) ? false : d.AsBool; + } + + public static implicit operator JSONNode(KeyValuePair aKeyValue) + { + return aKeyValue.Value; + } + + public static bool operator ==(JSONNode a, object b) + { + if (ReferenceEquals(a, b)) + return true; + bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator; + bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator; + if (aIsNull && bIsNull) + return true; + return !aIsNull && a.Equals(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 + + [ThreadStatic] + private static StringBuilder m_EscapeBuilder; + internal static StringBuilder EscapeBuilder + { + get + { + if (m_EscapeBuilder == null) + m_EscapeBuilder = new StringBuilder(); + return m_EscapeBuilder; + } + } + internal static string Escape(string aText) + { + var sb = EscapeBuilder; + sb.Length = 0; + if (sb.Capacity < aText.Length + aText.Length / 10) + sb.Capacity = aText.Length + aText.Length / 10; + foreach (char c in aText) + { + switch (c) + { + case '\\': + sb.Append("\\\\"); + break; + case '\"': + sb.Append("\\\""); + break; + case '\n': + sb.Append("\\n"); + break; + case '\r': + sb.Append("\\r"); + break; + case '\t': + sb.Append("\\t"); + break; + case '\b': + sb.Append("\\b"); + break; + case '\f': + sb.Append("\\f"); + break; + default: + if (c < ' ' || (forceASCII && c > 127)) + { + ushort val = c; + sb.Append("\\u").Append(val.ToString("X4")); + } + else + sb.Append(c); + break; + } + } + string result = sb.ToString(); + sb.Length = 0; + return result; + } + + private static JSONNode ParseElement(string token, bool quoted) + { + if (quoted) + return token; + if (token.Length <= 5) + { + string tmp = token.ToLower(); + if (tmp == "false" || tmp == "true") + return tmp == "true"; + if (tmp == "null") + return JSONNull.CreateOrGet(); + } + double val; + if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val)) + return val; + else + return token; + } + + public static JSONNode Parse(string aJSON) + { + Stack stack = new Stack(); + JSONNode ctx = null; + int i = 0; + StringBuilder Token = new StringBuilder(); + string TokenName = ""; + bool QuoteMode = false; + bool TokenIsQuoted = false; + bool HasNewlineChar = false; + while (i < aJSON.Length) + { + switch (aJSON[i]) + { + case '{': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + stack.Push(new JSONObject()); + if (ctx != null) + { + ctx.Add(TokenName, stack.Peek()); + } + TokenName = ""; + Token.Length = 0; + ctx = stack.Peek(); + HasNewlineChar = false; + break; + + case '[': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + + stack.Push(new JSONArray()); + if (ctx != null) + { + ctx.Add(TokenName, stack.Peek()); + } + TokenName = ""; + Token.Length = 0; + ctx = stack.Peek(); + HasNewlineChar = false; + break; + + case '}': + case ']': + if (QuoteMode) + { + + Token.Append(aJSON[i]); + break; + } + if (stack.Count == 0) + throw new Exception("JSON Parse: Too many closing brackets"); + + stack.Pop(); + if (Token.Length > 0 || TokenIsQuoted) + ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted)); + if (ctx != null) + ctx.Inline = !HasNewlineChar; + TokenIsQuoted = false; + TokenName = ""; + Token.Length = 0; + if (stack.Count > 0) + ctx = stack.Peek(); + break; + + case ':': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + TokenName = Token.ToString(); + Token.Length = 0; + TokenIsQuoted = false; + break; + + case '"': + QuoteMode ^= true; + TokenIsQuoted |= QuoteMode; + break; + + case ',': + if (QuoteMode) + { + Token.Append(aJSON[i]); + break; + } + if (Token.Length > 0 || TokenIsQuoted) + ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted)); + TokenIsQuoted = false; + TokenName = ""; + Token.Length = 0; + TokenIsQuoted = false; + break; + + case '\r': + case '\n': + HasNewlineChar = true; + break; + + case ' ': + case '\t': + if (QuoteMode) + Token.Append(aJSON[i]); + break; + + case '\\': + ++i; + if (QuoteMode) + { + char C = aJSON[i]; + switch (C) + { + case 't': + Token.Append('\t'); + break; + case 'r': + Token.Append('\r'); + break; + case 'n': + Token.Append('\n'); + break; + case 'b': + Token.Append('\b'); + break; + case 'f': + Token.Append('\f'); + break; + case 'u': + { + string s = aJSON.Substring(i + 1, 4); + Token.Append((char)int.Parse( + s, + System.Globalization.NumberStyles.AllowHexSpecifier)); + i += 4; + break; + } + default: + Token.Append(C); + break; + } + } + break; + case '/': + if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i + 1] == '/') + { + while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r') ; + break; + } + Token.Append(aJSON[i]); + break; + case '\uFEFF': // remove / ignore BOM (Byte Order Mark) + break; + + default: + Token.Append(aJSON[i]); + break; + } + ++i; + } + if (QuoteMode) + { + throw new Exception("JSON Parse: Quotation marks seems to be messed up."); + } + if (ctx == null) + return ParseElement(Token.ToString(), TokenIsQuoted); + return ctx; + } + + } + // End of JSONNode + + public partial class JSONArray : JSONNode + { + private List m_List = new List(); + private bool inline = false; + public override bool Inline + { + get { return inline; } + set { inline = value; } + } + + public override JSONNodeType Tag { get { return JSONNodeType.Array; } } + public override bool IsArray { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); } + + public override JSONNode this[int aIndex] + { + get + { + if (aIndex < 0 || aIndex >= m_List.Count) + return new JSONLazyCreator(this); + return m_List[aIndex]; + } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + 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 + { + if (value == null) + value = JSONNull.CreateOrGet(); + m_List.Add(value); + } + } + + public override int Count + { + get { return m_List.Count; } + } + + public override void Add(string aKey, JSONNode aItem) + { + if (aItem == null) + aItem = JSONNull.CreateOrGet(); + 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 void Clear() + { + m_List.Clear(); + } + + public override JSONNode Clone() + { + var node = new JSONArray(); + node.m_List.Capacity = m_List.Capacity; + foreach(var n in m_List) + { + if (n != null) + node.Add(n.Clone()); + else + node.Add(null); + } + return node; + } + + public override IEnumerable Children + { + get + { + foreach (JSONNode N in m_List) + yield return N; + } + } + + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append('['); + int count = m_List.Count; + if (inline) + aMode = JSONTextMode.Compact; + for (int i = 0; i < count; i++) + { + if (i > 0) + aSB.Append(','); + if (aMode == JSONTextMode.Indent) + aSB.AppendLine(); + + if (aMode == JSONTextMode.Indent) + aSB.Append(' ', aIndent + aIndentInc); + m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); + } + if (aMode == JSONTextMode.Indent) + aSB.AppendLine().Append(' ', aIndent); + aSB.Append(']'); + } + } + // End of JSONArray + + public partial class JSONObject : JSONNode + { + private Dictionary m_Dict = new Dictionary(); + + private bool inline = false; + public override bool Inline + { + get { return inline; } + set { inline = value; } + } + + public override JSONNodeType Tag { get { return JSONNodeType.Object; } } + public override bool IsObject { get { return true; } } + + public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); } + + + public override JSONNode this[string aKey] + { + get + { + if (m_Dict.ContainsKey(aKey)) + return m_Dict[aKey]; + else + return new JSONLazyCreator(this, aKey); + } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + 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; + return m_Dict.ElementAt(aIndex).Value; + } + set + { + if (value == null) + value = JSONNull.CreateOrGet(); + if (aIndex < 0 || aIndex >= m_Dict.Count) + return; + string key = m_Dict.ElementAt(aIndex).Key; + m_Dict[key] = value; + } + } + + public override int Count + { + get { return m_Dict.Count; } + } + + public override void Add(string aKey, JSONNode aItem) + { + if (aItem == null) + aItem = JSONNull.CreateOrGet(); + + if (aKey != null) + { + 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; + var item = m_Dict.ElementAt(aIndex); + m_Dict.Remove(item.Key); + return item.Value; + } + + public override JSONNode Remove(JSONNode aNode) + { + try + { + var item = m_Dict.Where(k => k.Value == aNode).First(); + m_Dict.Remove(item.Key); + return aNode; + } + catch + { + return null; + } + } + + public override void Clear() + { + m_Dict.Clear(); + } + + public override JSONNode Clone() + { + var node = new JSONObject(); + foreach (var n in m_Dict) + { + node.Add(n.Key, n.Value.Clone()); + } + return node; + } + + public override bool HasKey(string aKey) + { + return m_Dict.ContainsKey(aKey); + } + + public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault) + { + JSONNode res; + if (m_Dict.TryGetValue(aKey, out res)) + return res; + return aDefault; + } + + public override IEnumerable Children + { + get + { + foreach (KeyValuePair N in m_Dict) + yield return N.Value; + } + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append('{'); + bool first = true; + if (inline) + aMode = JSONTextMode.Compact; + foreach (var k in m_Dict) + { + if (!first) + aSB.Append(','); + first = false; + if (aMode == JSONTextMode.Indent) + aSB.AppendLine(); + if (aMode == JSONTextMode.Indent) + aSB.Append(' ', aIndent + aIndentInc); + aSB.Append('\"').Append(Escape(k.Key)).Append('\"'); + if (aMode == JSONTextMode.Compact) + aSB.Append(':'); + else + aSB.Append(" : "); + k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); + } + if (aMode == JSONTextMode.Indent) + aSB.AppendLine().Append(' ', aIndent); + aSB.Append('}'); + } + + } + // End of JSONObject + + public partial class JSONString : JSONNode + { + private string m_Data; + + public override JSONNodeType Tag { get { return JSONNodeType.String; } } + public override bool IsString { get { return true; } } + + public override Enumerator GetEnumerator() { return new Enumerator(); } + + + public override string Value + { + get { return m_Data; } + set + { + m_Data = value; + } + } + + public JSONString(string aData) + { + m_Data = aData; + } + public override JSONNode Clone() + { + return new JSONString(m_Data); + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append('\"').Append(Escape(m_Data)).Append('\"'); + } + public override bool Equals(object obj) + { + if (base.Equals(obj)) + return true; + string s = obj as string; + if (s != null) + return m_Data == s; + JSONString s2 = obj as JSONString; + if (s2 != null) + return m_Data == s2.m_Data; + return false; + } + public override int GetHashCode() + { + return m_Data.GetHashCode(); + } + public override void Clear() + { + m_Data = ""; + } + } + // End of JSONString + + public partial class JSONNumber : JSONNode + { + private double m_Data; + + public override JSONNodeType Tag { get { return JSONNodeType.Number; } } + public override bool IsNumber { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public override string Value + { + get { return m_Data.ToString(CultureInfo.InvariantCulture); } + set + { + double v; + if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v)) + m_Data = v; + } + } + + public override double AsDouble + { + get { return m_Data; } + set { m_Data = value; } + } + public override long AsLong + { + get { return (long)m_Data; } + set { m_Data = value; } + } + public override ulong AsULong + { + get { return (ulong)m_Data; } + set { m_Data = value; } + } + + public JSONNumber(double aData) + { + m_Data = aData; + } + + public JSONNumber(string aData) + { + Value = aData; + } + + public override JSONNode Clone() + { + return new JSONNumber(m_Data); + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append(Value); + } + private static bool IsNumeric(object value) + { + return value is int || value is uint + || value is float || value is double + || value is decimal + || value is long || value is ulong + || value is short || value is ushort + || value is sbyte || value is byte; + } + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (base.Equals(obj)) + return true; + JSONNumber s2 = obj as JSONNumber; + if (s2 != null) + return m_Data == s2.m_Data; + if (IsNumeric(obj)) + return Convert.ToDouble(obj) == m_Data; + return false; + } + public override int GetHashCode() + { + return m_Data.GetHashCode(); + } + public override void Clear() + { + m_Data = 0; + } + } + // End of JSONNumber + + public partial class JSONBool : JSONNode + { + private bool m_Data; + + public override JSONNodeType Tag { get { return JSONNodeType.Boolean; } } + public override bool IsBoolean { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public override string Value + { + get { return m_Data.ToString(); } + set + { + bool v; + if (bool.TryParse(value, out v)) + m_Data = v; + } + } + public override bool AsBool + { + get { return m_Data; } + set { m_Data = value; } + } + + public JSONBool(bool aData) + { + m_Data = aData; + } + + public JSONBool(string aData) + { + Value = aData; + } + + public override JSONNode Clone() + { + return new JSONBool(m_Data); + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append((m_Data) ? "true" : "false"); + } + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (obj is bool) + return m_Data == (bool)obj; + return false; + } + public override int GetHashCode() + { + return m_Data.GetHashCode(); + } + public override void Clear() + { + m_Data = false; + } + } + // End of JSONBool + + public partial class JSONNull : JSONNode + { + static JSONNull m_StaticInstance = new JSONNull(); + public static bool reuseSameInstance = true; + public static JSONNull CreateOrGet() + { + if (reuseSameInstance) + return m_StaticInstance; + return new JSONNull(); + } + private JSONNull() { } + + public override JSONNodeType Tag { get { return JSONNodeType.NullValue; } } + public override bool IsNull { get { return true; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public override string Value + { + get { return "null"; } + set { } + } + public override bool AsBool + { + get { return false; } + set { } + } + + public override JSONNode Clone() + { + return CreateOrGet(); + } + + public override bool Equals(object obj) + { + if (object.ReferenceEquals(this, obj)) + return true; + return (obj is JSONNull); + } + public override int GetHashCode() + { + return 0; + } + + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append("null"); + } + } + // End of JSONNull + + internal partial class JSONLazyCreator : JSONNode + { + private JSONNode m_Node = null; + private string m_Key = null; + public override JSONNodeType Tag { get { return JSONNodeType.None; } } + public override Enumerator GetEnumerator() { return new Enumerator(); } + + public JSONLazyCreator(JSONNode aNode) + { + m_Node = aNode; + m_Key = null; + } + + public JSONLazyCreator(JSONNode aNode, string aKey) + { + m_Node = aNode; + m_Key = aKey; + } + + private T Set(T aVal) where T : JSONNode + { + if (m_Key == null) + m_Node.Add(aVal); + else + m_Node.Add(m_Key, aVal); + m_Node = null; // Be GC friendly. + return aVal; + } + + public override JSONNode this[int aIndex] + { + get { return new JSONLazyCreator(this); } + set { Set(new JSONArray()).Add(value); } + } + + public override JSONNode this[string aKey] + { + get { return new JSONLazyCreator(this, aKey); } + set { Set(new JSONObject()).Add(aKey, value); } + } + + public override void Add(JSONNode aItem) + { + Set(new JSONArray()).Add(aItem); + } + + public override void Add(string aKey, JSONNode aItem) + { + Set(new JSONObject()).Add(aKey, aItem); + } + + public static bool operator ==(JSONLazyCreator a, object b) + { + if (b == null) + return true; + return System.Object.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 System.Object.ReferenceEquals(this, obj); + } + + public override int GetHashCode() + { + return 0; + } + + public override int AsInt + { + get { Set(new JSONNumber(0)); return 0; } + set { Set(new JSONNumber(value)); } + } + + public override float AsFloat + { + get { Set(new JSONNumber(0.0f)); return 0.0f; } + set { Set(new JSONNumber(value)); } + } + + public override double AsDouble + { + get { Set(new JSONNumber(0.0)); return 0.0; } + set { Set(new JSONNumber(value)); } + } + + public override long AsLong + { + get + { + if (longAsString) + Set(new JSONString("0")); + else + Set(new JSONNumber(0.0)); + return 0L; + } + set + { + if (longAsString) + Set(new JSONString(value.ToString())); + else + Set(new JSONNumber(value)); + } + } + + public override ulong AsULong + { + get + { + if (longAsString) + Set(new JSONString("0")); + else + Set(new JSONNumber(0.0)); + return 0L; + } + set + { + if (longAsString) + Set(new JSONString(value.ToString())); + else + Set(new JSONNumber(value)); + } + } + + public override bool AsBool + { + get { Set(new JSONBool(false)); return false; } + set { Set(new JSONBool(value)); } + } + + public override JSONArray AsArray + { + get { return Set(new JSONArray()); } + } + + public override JSONObject AsObject + { + get { return Set(new JSONObject()); } + } + internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) + { + aSB.Append("null"); + } + } + // End of JSONLazyCreator + + public static class JSON + { + public static JSONNode Parse(string aJSON) + { + return JSONNode.Parse(aJSON); + } + } +} diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs.meta b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs.meta new file mode 100644 index 0000000..5df1a06 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSON.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c041f301d0633aa488c390e2574f6584 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs new file mode 100644 index 0000000..df72f13 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs @@ -0,0 +1,301 @@ +//#define USE_SharpZipLib +/* * * * * + * This is an extension of the SimpleJSON framework to provide methods to + * serialize a JSON object tree into a compact binary format. Optionally the + * binary stream can be compressed with the SharpZipLib when using the define + * "USE_SharpZipLib" + * + * Those methods where originally part of the framework but since it's rarely + * used I've extracted this part into this seperate module file. + * + * You can use the define "SimpleJSON_ExcludeBinary" to selectively disable + * this extension without the need to remove the file from the project. + * + * If you want to use compression when saving to file / stream / B64 you have to include + * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and + * define "USE_SharpZipLib" at the top of the file + * + * + * The MIT License (MIT) + * + * Copyright (c) 2012-2017 Markus Göbel (Bunny83) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * * * * */ +using System; + +namespace SimpleJSON +{ +#if !SimpleJSON_ExcludeBinary + public abstract partial class JSONNode + { + public abstract void SerializeBinary(System.IO.BinaryWriter aWriter); + + public void SaveToBinaryStream(System.IO.Stream aData) + { + var W = new System.IO.BinaryWriter(aData); + SerializeBinary(W); + } + +#if USE_SharpZipLib + public void SaveToCompressedStream(System.IO.Stream aData) + { + using (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData)) + { + gzipOut.IsStreamOwner = false; + SaveToBinaryStream(gzipOut); + gzipOut.Close(); + } + } + + public void SaveToCompressedFile(string aFileName) + { + + System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName); + using(var F = System.IO.File.OpenWrite(aFileName)) + { + SaveToCompressedStream(F); + } + } + 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(System.IO.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 SaveToBinaryFile(string aFileName) + { + System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName); + using (var F = System.IO.File.OpenWrite(aFileName)) + { + SaveToBinaryStream(F); + } + } + + public string SaveToBinaryBase64() + { + using (var stream = new System.IO.MemoryStream()) + { + SaveToBinaryStream(stream); + stream.Position = 0; + return System.Convert.ToBase64String(stream.ToArray()); + } + } + + public static JSONNode DeserializeBinary(System.IO.BinaryReader aReader) + { + JSONNodeType type = (JSONNodeType)aReader.ReadByte(); + switch (type) + { + case JSONNodeType.Array: + { + int count = aReader.ReadInt32(); + JSONArray tmp = new JSONArray(); + for (int i = 0; i < count; i++) + tmp.Add(DeserializeBinary(aReader)); + return tmp; + } + case JSONNodeType.Object: + { + int count = aReader.ReadInt32(); + JSONObject tmp = new JSONObject(); + for (int i = 0; i < count; i++) + { + string key = aReader.ReadString(); + var val = DeserializeBinary(aReader); + tmp.Add(key, val); + } + return tmp; + } + case JSONNodeType.String: + { + return new JSONString(aReader.ReadString()); + } + case JSONNodeType.Number: + { + return new JSONNumber(aReader.ReadDouble()); + } + case JSONNodeType.Boolean: + { + return new JSONBool(aReader.ReadBoolean()); + } + case JSONNodeType.NullValue: + { + return JSONNull.CreateOrGet(); + } + 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 LoadFromBinaryStream(zin); + } + public static JSONNode LoadFromCompressedFile(string aFileName) + { + using(var F = System.IO.File.OpenRead(aFileName)) + { + return LoadFromCompressedStream(F); + } + } + 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(System.IO.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 LoadFromBinaryStream(System.IO.Stream aData) + { + using (var R = new System.IO.BinaryReader(aData)) + { + return DeserializeBinary(R); + } + } + + public static JSONNode LoadFromBinaryFile(string aFileName) + { + using (var F = System.IO.File.OpenRead(aFileName)) + { + return LoadFromBinaryStream(F); + } + } + + public static JSONNode LoadFromBinaryBase64(string aBase64) + { + var tmp = System.Convert.FromBase64String(aBase64); + var stream = new System.IO.MemoryStream(tmp); + stream.Position = 0; + return LoadFromBinaryStream(stream); + } + } + + public partial class JSONArray : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + aWriter.Write((byte)JSONNodeType.Array); + aWriter.Write(m_List.Count); + for (int i = 0; i < m_List.Count; i++) + { + m_List[i].SerializeBinary(aWriter); + } + } + } + + public partial class JSONObject : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + aWriter.Write((byte)JSONNodeType.Object); + aWriter.Write(m_Dict.Count); + foreach (string K in m_Dict.Keys) + { + aWriter.Write(K); + m_Dict[K].SerializeBinary(aWriter); + } + } + } + + public partial class JSONString : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + aWriter.Write((byte)JSONNodeType.String); + aWriter.Write(m_Data); + } + } + + public partial class JSONNumber : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + aWriter.Write((byte)JSONNodeType.Number); + aWriter.Write(m_Data); + } + } + + public partial class JSONBool : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + aWriter.Write((byte)JSONNodeType.Boolean); + aWriter.Write(m_Data); + } + } + public partial class JSONNull : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + aWriter.Write((byte)JSONNodeType.NullValue); + } + } + internal partial class JSONLazyCreator : JSONNode + { + public override void SerializeBinary(System.IO.BinaryWriter aWriter) + { + + } + } +#endif +} diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs.meta b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs.meta new file mode 100644 index 0000000..01e39ca --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONBinary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a777a4fe93c78c246b61a8e9c42ae35e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs new file mode 100644 index 0000000..9c24e13 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs @@ -0,0 +1,516 @@ +#region License and information +/* * * * * + * + * Extension file for the SimpleJSON framework for better support of some common + * .NET types. It does only work together with the SimpleJSON.cs + * It provides direct conversion support for types like decimal, char, byte, + * sbyte, short, ushort, uint, DateTime, TimeSpan and Guid. In addition there + * are conversion helpers for converting an array of number values into a byte[] + * or a List as well as converting an array of string values into a string[] + * or List. + * Finally there are some additional type conversion operators for some nullable + * types like short?, int?, float?, double?, long? and bool?. They will actually + * assign a JSONNull value when it's null or a JSONNumber when it's not. + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Markus Göbel (Bunny83) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * * * * */ + +#endregion License and information + +namespace SimpleJSON +{ + using System.Globalization; + using System.Collections.Generic; + public partial class JSONNode + { + #region Decimal + public virtual decimal AsDecimal + { + get + { + decimal result; + if (!decimal.TryParse(Value, out result)) + result = 0; + return result; + } + set + { + Value = value.ToString(); + } + } + + public static implicit operator JSONNode(decimal aDecimal) + { + return new JSONString(aDecimal.ToString()); + } + + public static implicit operator decimal(JSONNode aNode) + { + return aNode.AsDecimal; + } + #endregion Decimal + + #region Char + public virtual char AsChar + { + get + { + if (IsString && Value.Length > 0) + return Value[0]; + if (IsNumber) + return (char)AsInt; + return '\0'; + } + set + { + if (IsString) + Value = value.ToString(); + else if (IsNumber) + AsInt = (int)value; + } + } + + public static implicit operator JSONNode(char aChar) + { + return new JSONString(aChar.ToString()); + } + + public static implicit operator char(JSONNode aNode) + { + return aNode.AsChar; + } + #endregion Decimal + + #region UInt + public virtual uint AsUInt + { + get + { + return (uint)AsDouble; + } + set + { + AsDouble = value; + } + } + + public static implicit operator JSONNode(uint aUInt) + { + return new JSONNumber(aUInt); + } + + public static implicit operator uint(JSONNode aNode) + { + return aNode.AsUInt; + } + #endregion UInt + + #region Byte + public virtual byte AsByte + { + get + { + return (byte)AsInt; + } + set + { + AsInt = value; + } + } + + public static implicit operator JSONNode(byte aByte) + { + return new JSONNumber(aByte); + } + + public static implicit operator byte(JSONNode aNode) + { + return aNode.AsByte; + } + #endregion Byte + #region SByte + public virtual sbyte AsSByte + { + get + { + return (sbyte)AsInt; + } + set + { + AsInt = value; + } + } + + public static implicit operator JSONNode(sbyte aSByte) + { + return new JSONNumber(aSByte); + } + + public static implicit operator sbyte(JSONNode aNode) + { + return aNode.AsSByte; + } + #endregion SByte + + #region Short + public virtual short AsShort + { + get + { + return (short)AsInt; + } + set + { + AsInt = value; + } + } + + public static implicit operator JSONNode(short aShort) + { + return new JSONNumber(aShort); + } + + public static implicit operator short(JSONNode aNode) + { + return aNode.AsShort; + } + #endregion Short + #region UShort + public virtual ushort AsUShort + { + get + { + return (ushort)AsInt; + } + set + { + AsInt = value; + } + } + + public static implicit operator JSONNode(ushort aUShort) + { + return new JSONNumber(aUShort); + } + + public static implicit operator ushort(JSONNode aNode) + { + return aNode.AsUShort; + } + #endregion UShort + + #region DateTime + public virtual System.DateTime AsDateTime + { + get + { + System.DateTime result; + if (!System.DateTime.TryParse(Value, CultureInfo.InvariantCulture, DateTimeStyles.None, out result)) + result = new System.DateTime(0); + return result; + } + set + { + Value = value.ToString(CultureInfo.InvariantCulture); + } + } + + public static implicit operator JSONNode(System.DateTime aDateTime) + { + return new JSONString(aDateTime.ToString(CultureInfo.InvariantCulture)); + } + + public static implicit operator System.DateTime(JSONNode aNode) + { + return aNode.AsDateTime; + } + #endregion DateTime + #region TimeSpan + public virtual System.TimeSpan AsTimeSpan + { + get + { + System.TimeSpan result; + if (!System.TimeSpan.TryParse(Value, CultureInfo.InvariantCulture, out result)) + result = new System.TimeSpan(0); + return result; + } + set + { + Value = value.ToString(); + } + } + + public static implicit operator JSONNode(System.TimeSpan aTimeSpan) + { + return new JSONString(aTimeSpan.ToString()); + } + + public static implicit operator System.TimeSpan(JSONNode aNode) + { + return aNode.AsTimeSpan; + } + #endregion TimeSpan + + #region Guid + public virtual System.Guid AsGuid + { + get + { + System.Guid result; + System.Guid.TryParse(Value, out result); + return result; + } + set + { + Value = value.ToString(); + } + } + + public static implicit operator JSONNode(System.Guid aGuid) + { + return new JSONString(aGuid.ToString()); + } + + public static implicit operator System.Guid(JSONNode aNode) + { + return aNode.AsGuid; + } + #endregion Guid + + #region ByteArray + public virtual byte[] AsByteArray + { + get + { + if (this.IsNull || !this.IsArray) + return null; + int count = Count; + byte[] result = new byte[count]; + for (int i = 0; i < count; i++) + result[i] = this[i].AsByte; + return result; + } + set + { + if (!IsArray || value == null) + return; + Clear(); + for (int i = 0; i < value.Length; i++) + Add(value[i]); + } + } + + public static implicit operator JSONNode(byte[] aByteArray) + { + return new JSONArray { AsByteArray = aByteArray }; + } + + public static implicit operator byte[](JSONNode aNode) + { + return aNode.AsByteArray; + } + #endregion ByteArray + #region ByteList + public virtual List AsByteList + { + get + { + if (this.IsNull || !this.IsArray) + return null; + int count = Count; + List result = new List(count); + for (int i = 0; i < count; i++) + result.Add(this[i].AsByte); + return result; + } + set + { + if (!IsArray || value == null) + return; + Clear(); + for (int i = 0; i < value.Count; i++) + Add(value[i]); + } + } + + public static implicit operator JSONNode(List aByteList) + { + return new JSONArray { AsByteList = aByteList }; + } + + public static implicit operator List (JSONNode aNode) + { + return aNode.AsByteList; + } + #endregion ByteList + + #region StringArray + public virtual string[] AsStringArray + { + get + { + if (this.IsNull || !this.IsArray) + return null; + int count = Count; + string[] result = new string[count]; + for (int i = 0; i < count; i++) + result[i] = this[i].Value; + return result; + } + set + { + if (!IsArray || value == null) + return; + Clear(); + for (int i = 0; i < value.Length; i++) + Add(value[i]); + } + } + + public static implicit operator JSONNode(string[] aStringArray) + { + return new JSONArray { AsStringArray = aStringArray }; + } + + public static implicit operator string[] (JSONNode aNode) + { + return aNode.AsStringArray; + } + #endregion StringArray + #region StringList + public virtual List AsStringList + { + get + { + if (this.IsNull || !this.IsArray) + return null; + int count = Count; + List result = new List(count); + for (int i = 0; i < count; i++) + result.Add(this[i].Value); + return result; + } + set + { + if (!IsArray || value == null) + return; + Clear(); + for (int i = 0; i < value.Count; i++) + Add(value[i]); + } + } + + public static implicit operator JSONNode(List aStringList) + { + return new JSONArray { AsStringList = aStringList }; + } + + public static implicit operator List (JSONNode aNode) + { + return aNode.AsStringList; + } + #endregion StringList + + #region NullableTypes + public static implicit operator JSONNode(int? aValue) + { + if (aValue == null) + return JSONNull.CreateOrGet(); + return new JSONNumber((int)aValue); + } + public static implicit operator int?(JSONNode aNode) + { + if (aNode == null || aNode.IsNull) + return null; + return aNode.AsInt; + } + + public static implicit operator JSONNode(float? aValue) + { + if (aValue == null) + return JSONNull.CreateOrGet(); + return new JSONNumber((float)aValue); + } + public static implicit operator float? (JSONNode aNode) + { + if (aNode == null || aNode.IsNull) + return null; + return aNode.AsFloat; + } + + public static implicit operator JSONNode(double? aValue) + { + if (aValue == null) + return JSONNull.CreateOrGet(); + return new JSONNumber((double)aValue); + } + public static implicit operator double? (JSONNode aNode) + { + if (aNode == null || aNode.IsNull) + return null; + return aNode.AsDouble; + } + + public static implicit operator JSONNode(bool? aValue) + { + if (aValue == null) + return JSONNull.CreateOrGet(); + return new JSONBool((bool)aValue); + } + public static implicit operator bool? (JSONNode aNode) + { + if (aNode == null || aNode.IsNull) + return null; + return aNode.AsBool; + } + + public static implicit operator JSONNode(long? aValue) + { + if (aValue == null) + return JSONNull.CreateOrGet(); + return new JSONNumber((long)aValue); + } + public static implicit operator long? (JSONNode aNode) + { + if (aNode == null || aNode.IsNull) + return null; + return aNode.AsLong; + } + + public static implicit operator JSONNode(short? aValue) + { + if (aValue == null) + return JSONNull.CreateOrGet(); + return new JSONNumber((short)aValue); + } + public static implicit operator short? (JSONNode aNode) + { + if (aNode == null || aNode.IsNull) + return null; + return aNode.AsShort; + } + #endregion NullableTypes + } +} diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs.meta b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs.meta new file mode 100644 index 0000000..73eb2e6 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONDotNetTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f1bdd2f47e2a0a4d9f9974a50ce6666 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs new file mode 100644 index 0000000..ee8a912 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs @@ -0,0 +1,462 @@ +#if UNITY_5_3_OR_NEWER +#region License and information +/* * * * * + * + * Unity extension for the SimpleJSON framework. It does only work together with + * the SimpleJSON.cs + * It provides several helpers and conversion operators to serialize/deserialize + * common Unity types such as Vector2/3/4, Rect, RectOffset, Quaternion and + * Matrix4x4 as JSONObject or JSONArray. + * This extension will add 3 static settings to the JSONNode class: + * ( VectorContainerType, QuaternionContainerType, RectContainerType ) which + * control what node type should be used for serializing the given type. So a + * Vector3 as array would look like [12,32,24] and {"x":12, "y":32, "z":24} as + * object. + * + * + * The MIT License (MIT) + * + * Copyright (c) 2012-2017 Markus Göbel (Bunny83) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * * * * */ + +#endregion License and information +using UnityEngine; + +namespace SimpleJSON +{ + public enum JSONContainerType { Array, Object } + public partial class JSONNode + { + public static byte Color32DefaultAlpha = 255; + public static float ColorDefaultAlpha = 1f; + public static JSONContainerType VectorContainerType = JSONContainerType.Array; + public static JSONContainerType QuaternionContainerType = JSONContainerType.Array; + public static JSONContainerType RectContainerType = JSONContainerType.Array; + public static JSONContainerType ColorContainerType = JSONContainerType.Array; + private static JSONNode GetContainer(JSONContainerType aType) + { + if (aType == JSONContainerType.Array) + return new JSONArray(); + return new JSONObject(); + } + + #region implicit conversion operators + public static implicit operator JSONNode(Vector2 aVec) + { + JSONNode n = GetContainer(VectorContainerType); + n.WriteVector2(aVec); + return n; + } + public static implicit operator JSONNode(Vector3 aVec) + { + JSONNode n = GetContainer(VectorContainerType); + n.WriteVector3(aVec); + return n; + } + public static implicit operator JSONNode(Vector4 aVec) + { + JSONNode n = GetContainer(VectorContainerType); + n.WriteVector4(aVec); + return n; + } + public static implicit operator JSONNode(Color aCol) + { + JSONNode n = GetContainer(ColorContainerType); + n.WriteColor(aCol); + return n; + } + public static implicit operator JSONNode(Color32 aCol) + { + JSONNode n = GetContainer(ColorContainerType); + n.WriteColor32(aCol); + return n; + } + public static implicit operator JSONNode(Quaternion aRot) + { + JSONNode n = GetContainer(QuaternionContainerType); + n.WriteQuaternion(aRot); + return n; + } + public static implicit operator JSONNode(Rect aRect) + { + JSONNode n = GetContainer(RectContainerType); + n.WriteRect(aRect); + return n; + } + public static implicit operator JSONNode(RectOffset aRect) + { + JSONNode n = GetContainer(RectContainerType); + n.WriteRectOffset(aRect); + return n; + } + + public static implicit operator Vector2(JSONNode aNode) + { + return aNode.ReadVector2(); + } + public static implicit operator Vector3(JSONNode aNode) + { + return aNode.ReadVector3(); + } + public static implicit operator Vector4(JSONNode aNode) + { + return aNode.ReadVector4(); + } + public static implicit operator Color(JSONNode aNode) + { + return aNode.ReadColor(); + } + public static implicit operator Color32(JSONNode aNode) + { + return aNode.ReadColor32(); + } + public static implicit operator Quaternion(JSONNode aNode) + { + return aNode.ReadQuaternion(); + } + public static implicit operator Rect(JSONNode aNode) + { + return aNode.ReadRect(); + } + public static implicit operator RectOffset(JSONNode aNode) + { + return aNode.ReadRectOffset(); + } + #endregion implicit conversion operators + + #region Vector2 + public Vector2 ReadVector2(Vector2 aDefault) + { + if (IsObject) + return new Vector2(this["x"].AsFloat, this["y"].AsFloat); + if (IsArray) + return new Vector2(this[0].AsFloat, this[1].AsFloat); + return aDefault; + } + public Vector2 ReadVector2(string aXName, string aYName) + { + if (IsObject) + { + return new Vector2(this[aXName].AsFloat, this[aYName].AsFloat); + } + return Vector2.zero; + } + + public Vector2 ReadVector2() + { + return ReadVector2(Vector2.zero); + } + public JSONNode WriteVector2(Vector2 aVec, string aXName = "x", string aYName = "y") + { + if (IsObject) + { + Inline = true; + this[aXName].AsFloat = aVec.x; + this[aYName].AsFloat = aVec.y; + } + else if (IsArray) + { + Inline = true; + this[0].AsFloat = aVec.x; + this[1].AsFloat = aVec.y; + } + return this; + } + #endregion Vector2 + + #region Vector3 + public Vector3 ReadVector3(Vector3 aDefault) + { + if (IsObject) + return new Vector3(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat); + if (IsArray) + return new Vector3(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat); + return aDefault; + } + public Vector3 ReadVector3(string aXName, string aYName, string aZName) + { + if (IsObject) + return new Vector3(this[aXName].AsFloat, this[aYName].AsFloat, this[aZName].AsFloat); + return Vector3.zero; + } + public Vector3 ReadVector3() + { + return ReadVector3(Vector3.zero); + } + public JSONNode WriteVector3(Vector3 aVec, string aXName = "x", string aYName = "y", string aZName = "z") + { + if (IsObject) + { + Inline = true; + this[aXName].AsFloat = aVec.x; + this[aYName].AsFloat = aVec.y; + this[aZName].AsFloat = aVec.z; + } + else if (IsArray) + { + Inline = true; + this[0].AsFloat = aVec.x; + this[1].AsFloat = aVec.y; + this[2].AsFloat = aVec.z; + } + return this; + } + #endregion Vector3 + + #region Vector4 + public Vector4 ReadVector4(Vector4 aDefault) + { + if (IsObject) + return new Vector4(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat, this["w"].AsFloat); + if (IsArray) + return new Vector4(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat); + return aDefault; + } + public Vector4 ReadVector4() + { + return ReadVector4(Vector4.zero); + } + public JSONNode WriteVector4(Vector4 aVec) + { + if (IsObject) + { + Inline = true; + this["x"].AsFloat = aVec.x; + this["y"].AsFloat = aVec.y; + this["z"].AsFloat = aVec.z; + this["w"].AsFloat = aVec.w; + } + else if (IsArray) + { + Inline = true; + this[0].AsFloat = aVec.x; + this[1].AsFloat = aVec.y; + this[2].AsFloat = aVec.z; + this[3].AsFloat = aVec.w; + } + return this; + } + #endregion Vector4 + + #region Color / Color32 + public Color ReadColor(Color aDefault) + { + if (IsObject) + return new Color(this["r"].AsFloat, this["g"].AsFloat, this["b"].AsFloat, HasKey("a")?this["a"].AsFloat:ColorDefaultAlpha); + if (IsArray) + return new Color(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, (Count>3)?this[3].AsFloat:ColorDefaultAlpha); + return aDefault; + } + public Color ReadColor() + { + return ReadColor(Color.clear); + } + public JSONNode WriteColor(Color aCol) + { + if (IsObject) + { + Inline = true; + this["r"].AsFloat = aCol.r; + this["g"].AsFloat = aCol.g; + this["b"].AsFloat = aCol.b; + this["a"].AsFloat = aCol.a; + } + else if (IsArray) + { + Inline = true; + this[0].AsFloat = aCol.r; + this[1].AsFloat = aCol.g; + this[2].AsFloat = aCol.b; + this[3].AsFloat = aCol.a; + } + return this; + } + + public Color32 ReadColor32(Color32 aDefault) + { + if (IsObject) + return new Color32((byte)this["r"].AsInt, (byte)this["g"].AsInt, (byte)this["b"].AsInt, (byte)(HasKey("a")?this["a"].AsInt:Color32DefaultAlpha)); + if (IsArray) + return new Color32((byte)this[0].AsInt, (byte)this[1].AsInt, (byte)this[2].AsInt, (byte)((Count>3)?this[3].AsInt:Color32DefaultAlpha)); + return aDefault; + } + public Color32 ReadColor32() + { + return ReadColor32(new Color32()); + } + public JSONNode WriteColor32(Color32 aCol) + { + if (IsObject) + { + Inline = true; + this["r"].AsInt = aCol.r; + this["g"].AsInt = aCol.g; + this["b"].AsInt = aCol.b; + this["a"].AsInt = aCol.a; + } + else if (IsArray) + { + Inline = true; + this[0].AsInt = aCol.r; + this[1].AsInt = aCol.g; + this[2].AsInt = aCol.b; + this[3].AsInt = aCol.a; + } + return this; + } + + #endregion Color / Color32 + + #region Quaternion + public Quaternion ReadQuaternion(Quaternion aDefault) + { + if (IsObject) + return new Quaternion(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat, this["w"].AsFloat); + if (IsArray) + return new Quaternion(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat); + return aDefault; + } + public Quaternion ReadQuaternion() + { + return ReadQuaternion(Quaternion.identity); + } + public JSONNode WriteQuaternion(Quaternion aRot) + { + if (IsObject) + { + Inline = true; + this["x"].AsFloat = aRot.x; + this["y"].AsFloat = aRot.y; + this["z"].AsFloat = aRot.z; + this["w"].AsFloat = aRot.w; + } + else if (IsArray) + { + Inline = true; + this[0].AsFloat = aRot.x; + this[1].AsFloat = aRot.y; + this[2].AsFloat = aRot.z; + this[3].AsFloat = aRot.w; + } + return this; + } + #endregion Quaternion + + #region Rect + public Rect ReadRect(Rect aDefault) + { + if (IsObject) + return new Rect(this["x"].AsFloat, this["y"].AsFloat, this["width"].AsFloat, this["height"].AsFloat); + if (IsArray) + return new Rect(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat); + return aDefault; + } + public Rect ReadRect() + { + return ReadRect(new Rect()); + } + public JSONNode WriteRect(Rect aRect) + { + if (IsObject) + { + Inline = true; + this["x"].AsFloat = aRect.x; + this["y"].AsFloat = aRect.y; + this["width"].AsFloat = aRect.width; + this["height"].AsFloat = aRect.height; + } + else if (IsArray) + { + Inline = true; + this[0].AsFloat = aRect.x; + this[1].AsFloat = aRect.y; + this[2].AsFloat = aRect.width; + this[3].AsFloat = aRect.height; + } + return this; + } + #endregion Rect + + #region RectOffset + public RectOffset ReadRectOffset(RectOffset aDefault) + { + if (this is JSONObject) + return new RectOffset(this["left"].AsInt, this["right"].AsInt, this["top"].AsInt, this["bottom"].AsInt); + if (this is JSONArray) + return new RectOffset(this[0].AsInt, this[1].AsInt, this[2].AsInt, this[3].AsInt); + return aDefault; + } + public RectOffset ReadRectOffset() + { + return ReadRectOffset(new RectOffset()); + } + public JSONNode WriteRectOffset(RectOffset aRect) + { + if (IsObject) + { + Inline = true; + this["left"].AsInt = aRect.left; + this["right"].AsInt = aRect.right; + this["top"].AsInt = aRect.top; + this["bottom"].AsInt = aRect.bottom; + } + else if (IsArray) + { + Inline = true; + this[0].AsInt = aRect.left; + this[1].AsInt = aRect.right; + this[2].AsInt = aRect.top; + this[3].AsInt = aRect.bottom; + } + return this; + } + #endregion RectOffset + + #region Matrix4x4 + public Matrix4x4 ReadMatrix() + { + Matrix4x4 result = Matrix4x4.identity; + if (IsArray) + { + for (int i = 0; i < 16; i++) + { + result[i] = this[i].AsFloat; + } + } + return result; + } + public JSONNode WriteMatrix(Matrix4x4 aMatrix) + { + if (IsArray) + { + Inline = true; + for (int i = 0; i < 16; i++) + { + this[i].AsFloat = aMatrix[i]; + } + } + return this; + } + #endregion Matrix4x4 + } +} +#endif diff --git a/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs.meta b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs.meta new file mode 100644 index 0000000..ba159a8 --- /dev/null +++ b/Assets/Plugins/LubanLib/SimpleJSON/SimpleJSONUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0794c5fece7ec984192e57c9ecc88720 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/LubanLib/StringUtil.cs b/Assets/Plugins/LubanLib/StringUtil.cs new file mode 100644 index 0000000..c91f2a1 --- /dev/null +++ b/Assets/Plugins/LubanLib/StringUtil.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using System.Text; + +namespace Bright.Common +{ + public static class StringUtil + { + public static string ToStr(object o) + { + return ToStr(o, new StringBuilder()); + } + + public static string ToStr(object o, StringBuilder sb) + { + foreach (var p in o.GetType().GetFields()) + { + + sb.Append($"{p.Name} = {p.GetValue(o)},"); + } + + foreach (var p in o.GetType().GetProperties()) + { + sb.Append($"{p.Name} = {p.GetValue(o)},"); + } + return sb.ToString(); + } + + public static string ArrayToString(T[] arr) + { + return "[" + string.Join(",", arr) + "]"; + } + + + public static string CollectionToString(IEnumerable arr) + { + return "[" + string.Join(",", arr) + "]"; + } + + + public static string CollectionToString(IDictionary dic) + { + var sb = new StringBuilder('{'); + foreach (var e in dic) + { + sb.Append(e.Key).Append(':'); + sb.Append(e.Value).Append(','); + } + sb.Append('}'); + return sb.ToString(); + } + } +} diff --git a/Assets/Plugins/LubanLib/StringUtil.cs.meta b/Assets/Plugins/LubanLib/StringUtil.cs.meta new file mode 100644 index 0000000..612d9e9 --- /dev/null +++ b/Assets/Plugins/LubanLib/StringUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef82068810e5599439c5346fba3b0f97 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR.meta b/Assets/Plugins/SignalR.meta new file mode 100644 index 0000000..c1e0c18 --- /dev/null +++ b/Assets/Plugins/SignalR.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ce8d719e5ad9264ca957efb27225ed6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll new file mode 100644 index 0000000000000000000000000000000000000000..d11ed6d57a25c023cb2ea299ce14742fb3abf2cb GIT binary patch literal 42144 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 AssI20 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll.meta new file mode 100644 index 0000000..243e1d8 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 41129fe21b7cd4af4b05d3f4856bd1ee +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll new file mode 100644 index 0000000000000000000000000000000000000000..c898fdfe9d9ae61eeebdf09575d762938c034722 GIT binary patch literal 122120 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 K+V@b@`u_!E3=hTt literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll.meta new file mode 100644 index 0000000..848668c --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 6df1adc61feb9fe88b257532a28a1cbe +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll new file mode 100644 index 0000000000000000000000000000000000000000..87e4873a782d051b44ec1cac848072226fd3920c GIT binary patch literal 200464 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

Z~tDC|6_& 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 XZuSb%9mhYpaZ|57nrrrK*RlTt+{&MS literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll.meta b/Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll.meta new file mode 100644 index 0000000..cb40e61 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 59ca156503575e962b8d9707349eef6e +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll new file mode 100644 index 0000000000000000000000000000000000000000..479c5feb3baf1f01650205246f1b6c102470e45f GIT binary patch literal 64160 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 +yd;^8YayY#=#iwyNj>EAWzTKDT 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 CS|WG= literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll.meta new file mode 100644 index 0000000..52185bf --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 4de563b62f4b777e2b28542e018250cd +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll new file mode 100644 index 0000000000000000000000000000000000000000..4f9e147b7aa3a4b2c801396c9c3892e19af43304 GIT binary patch literal 29872 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 a?;csP9d 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�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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll.meta new file mode 100644 index 0000000..90af26e --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 4bdee218fd42e996bafe6cdaaf740ab1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll new file mode 100644 index 0000000000000000000000000000000000000000..77fe4f93e39394667316be7a35ae15d0abef1b58 GIT binary patch literal 54032 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 T$X0n7x*UlzqCX>g6utfr*{M>D literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll.meta new file mode 100644 index 0000000..3f84d98 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 77a451de6d335357ca7321fe3222496f +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll new file mode 100644 index 0000000000000000000000000000000000000000..cea49fa08e80f37a90f892955ce281a3af468294 GIT binary patch literal 68768 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll.meta new file mode 100644 index 0000000..851c485 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 4788591b316b2ed649343331b2ef1e44 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000000000000000000000000000000000000..24f500cfeeea22bde0a52c8fa795b72a7fc06922 GIT binary patch literal 49936 zcmeFa2Y8g#)-S%_GBwGh7t$E|5RyrwN)ZSxbV-n62_cz~NRkON6C^YfniUlVj(RKz zHWU?m7Z5#mJ=i%%`9MLzqX#@ey4;4{m!}fd;a%%{x>@7-D~Z&*Is+=wbyR% z3{&P_Ei@s7j?Ztu3Gq0d^f!{>?}JukJGwsU5D(j4@AkMd`Sot)wRL`Hlh3=rSJ~jK zs%&iZ2AuOfPG57Qv#!xOW?GrE!CUQd$Hdrs8ltC<6=JfY3E#8-^+2$;gQB}LN+}TH zN>J>QT5~U+PJDLbBSajhRjD@-%mnyP5d!p<*$UbBN@kG=xzi}UTZsCw z5Fu^=UtiD<3K5M*<_;ms@%(T9IfbxBFk697h``+e&yoP}`t<a>ocU zyHW@nQ-xS_yAWxx%Z>L4(Q43s?~$##^3Z8Hr#{b@bTxH7YEpWoXg97vN9j3d7BD4S}ORb6m4vt2d2@=+$w1Ucp$EoZBg*~JI>O=;^hSbueEuT*WTtAN_7 zYOX?hJ}Mcrn6XPc#$IW9h*@_P5%(*SyBl+-ci`^T#S|`KaurjN`?TENvQ(B?b}udy>6-JH5l~y}CFeYA`u;*I+93 zpq|^uP+beFuD4TNcMTy{EobFQc%0rVFQxZi(VeR643Pap0eZDkMvmKOL052ZAw4Q0 zy(uF7NkrPF1o_d|)aPk!rjGtjL z#wnBe878AWOg5f!u!OVWfSk?G@R%uOpVPLkh@$*3JEN$ZpG!kS2|+-|NRy@Xtt(=v z)Y!u zxD+q*Qe<_m5)_U~P<~B;Su(r`r*^yQ!qj0llaWb>oPYhds^_LfN_CB;X3pI=)kD$>w(8OT00l~DBHrNw{<{F0@bK`U=vRt+!HAhb|k|{Zf1-fW} z3=Eoh$tA1eE-}q1w5TSwe^4pAp@}(YCj&Rlc8y0}F3b)=7E_Q#cfphGsuW?GExVrk zKo`sLL`;a+^OPLjI}v>L4r-W54Rbp+qKs-STt{?*8dNJn4c#>f;$jjEx6-77lf$Z* z4OPgFh`tdvfDY8rQRW1N4beX-K{2!MXk{u~PBsDa#tdi=8)`iNB7($gXoqY7Mg%n{ zwK&&sPAMr{YHCPJ@lF9xdzqj}nP)>Mgdd|{?2%%m>^X(es!XwQG;T0_H&_MtNJN7r zZ>R%E@42YM7OF!QWJPr{x-N~*o-A7>Jvxnk;1WipDORGeS+3+1zWi zw841R#YK2xHZb(oW=Hf$+Fa+0zx{TR3(H-*YdV0P1Fx9_uQ4DZ!wo#&!ZBD5N{-3V zs%q(#sB@T(kBHFL+-MeNP4S)u$vGTbXibL61-ei;x2wM{h#1b!^0w!i(j1+s0Imhis&zM`8ngJVPju4ok;#2Ho4SSxILan`b zs$ImYFyKreSD>g8bs)Vr79(Da3Ht$?IoITZ9Q%hZ;N~1lj!-foNF<2(9wG|1R8*uh z-EtXxwwk&Et3F*Sfw>2~JYy1(r$kPm9g3iK;1jR9Dj*p#)HNIRP~_)APil}tIV&fk zY_Gi3-YXH?^k2=IBFz3dVC~gPIjReblYTk>RP!udqg~&jfQD2Ir__}&u`G*TMA>L6 zi-Cx;l%x62p(+=5T2|Bj=Nbxi121dO3FuAhB3MuQq@N7F0$pe{o9d5}^=m7-gPdaT z*Hv}ZKsB@XJn(wGNak8$s~#j6Q4W2``QG!9UGz2?feLcGL!E}5E8AIfyHUQWmLHqg2YZ5YN;c4m9nQN+GRSVa(R> zr-x7vmM`ePDk@3Am~4Q6MX`Jy6f|;7A6*Vs)n5tH3erjSBSzU*IFUrmnJ#OwMwn(u zBxxl!AG+#oLM1UqTTr1r*J|@tr^HwjG;Ws6p)I66S3NLB82AF<2V#03 zu-kIYR#}mmHH%6~)cYk`;&pE=SXk+JJ#}`X9mGW^B9$v87b7~Ml;5Vw4l5fs-eGfXuVlOHN zYw>d(Wo5~%Wj&FTQfN+d{TRVHU&{jn4Je2)=Dx+iPFJ&wGi7XDh4v(}Z?vFu8B!vWEkc)^b#NRPs>B|oFFiEc z`k6J?MA8M;)pOp{a+7o^Z9tSMsK7ugb?IGXHA8?d1(;+h_#ufUeBXHVtjEtmTwVW$8nK8(mX|$F`ge;=X<`o}y0UhMH5KQbjAIqw8 zbqs|#?18unZBDvtJIjca6wH$aKQ#&_YAHprY;}FM{80jKIne;BJtUKkD3NZ!X{N=yNjBsbq86EZ;*Pp1WKk$vz zPMk}p^+0=3*Z-%Y{L85%_hSkAk=EtOcEjd_us)$tG|-&RgT*9Kea=90h8#T@v1`Gg zxil=P?B$-4x$ zu$zqfkDsFX)y?0IAQ8#Y}@2lOK5W6|?Y^9)l7)sKjWl z)3pKV);`G1`J1|oYRI#sxPAr^D?h3zCEt?j`bFYYA@DSbr?`G4GS=wP+A^w7lC@=2 zXG;DlL{cDJHdU5QU)c|2>~eDHffG6?V8_&w2UOKpxQU86giv}ieg=8%PSotWn5qw> zmlL`)B3P=f2S5U$6%Q}skv(T!I=Q6Xe?KU#RCfmThk>&aH-~3ltoUulQi;v9B44Ui zK<_589UhjFV{R_R(ucMMW|s*g=*qerdn!qGy+GyC{g{O8 z7#-w0n6^cFM0qY6Wyv*Zc@9gCIoBpdXgB1z{=&7p%#fIJ1359N(huvl-vq=?{vCB8L>cNLZ^>xzyhLw2H+Y2@dr$(Zbtan!82NPNn#I!#8H@^sgm zR9#|$iO)zn(>2DDqUjLqT7#M(dI0Sm9qdUM0#Uw8apdktNVYH4uB_ANq=Iw{kua-) zqz4;k^v~}-aHvb&?N2tm>RqUI1-y;DDvYpgRKEPmim(l$5PZZiuoDW$V3T7@b({Oe zrbhQeD{i16W{>WtrbJuOZDez%aBR}VFv!h@Jb2_DRBXqHpl1}EPs_37;S$Phna!v0 z(Xqms!iI}gumK_%F`>Eb5|Oq`fKyn)580^nUE7Sx}UU=tRXWW^JoQ zir{_^%D|>ylQOiB3}Xa^WLQ$vts0^l%ZZRN6nZ!#+C!m(8sx@U!eo*ai^+sWPOKuI zu1jE@Tx9aBVlMhGIk-LqOO6|kLkaR4%nZ~jNdU%83SqK^%$zgP;A9R-0{hdD6TwdC zDePg=KukbSg&44q31d=~$jV1Ysv@&Bu1$)k(jm!4=?Gm=I*d{F2&~(FO`)cGu?V&2 zOl*%!7Da8((hesU8IR_nFS@Z$#7mp3#O$t1y)+I^c5`lw%rd(Up~X2`(3K6c#dTPc zNu%5(?RI)b%OX}OiO%mefr&$4>JG)upqz808>SZbQd79&c?9&zi|Z{ja6m{aVY{(_ zO^K!>fh;S|1a9b+r}s|jXX2GD9p;#$Lx%$hI3ET_(`jXm=8(wtZKZ}oPgP)k5g*Vs3RU;f!TlMKMXfXSD^%l6Hzb6%NY=Qt#aH@hYyks2Lu!f}Wx-b7+vq6;CcO;o-RqB#$@)n-2|Z(kZj)*8rf zC@o_lau~USa-?5izt8vFGDmX_K$hL?XO5sCk{YUlq!JR6D(B0QkVAj!SeTJkY5Zb= z15c`fX0LwPu4HJE<4R$e$`DNe1rsd}Octx6Dd&t>@oP$-P{Z7Q742%pyh{rfUe4rn z*HY*djOGkgz`aE;>cikt2OB6mmO59`!?fZmJT&jsfV7pv+Ke`lbdE*yGnZRN1q_a5 zTxuB=@?HaQz-kowFh`z+MT^9)@-+awzLuEfIFUTo2f5}c)( z=^DIWl%;*9#q5sqErCU4SK^$6xtWPBy8HFYQ+ww~L2mzzklRYaaULE;2A>{j@NCU{ z6XgZ%jc$xrwMDc#UojhuF!vmKB#2*=iD-7kK?cr3=8_cYXZdK4EVm3vU6#{$4flJ6 zu}D3KgwXPh6Y#uP2)}~r!SOw8WfE9`P=CT!q>VfZNK}_m?FQ*07`-rF#h_sYEvz8+ zwOl}5#@aK#>t=9bV^tg-Q4%L+1|x~Yxf(s@@GeER6l0y+no9b}_dmF;r!ffe41mrG z`A#tQ#^E;mT+-OQ;(R>%B?6}era6qLeljm*1sq?;l&A4J#l`Cs_7}top7YgZ#DQID zKITz%8A-%yuZJ0{k^V`1RY>`&#e4%xPt8%2StgieLS06+(yZKWBkn0G01ZQ zADn=^(e>W>#Ed_%DzhrKMq$?|#E(ibZEmS{SVUmiCo1vj4ni6}=}1FMewXJMp2SBn zgQ8h~d`92{@xqA@1I5a`b=&W@^0#R+RP!Id!tzqRG0CW^Nx4vK5+ zU1QB+oNaG{StLdi+-182JkLeH6K@u`#Fipm8com>L%DY{&r4C1u4A~4;gw9EZYTP~ z2_w3g#f~U~>up1`&BAA+dhd-PnO)Ke-f1KF2&bncQ;k|8!EVfRFo|+^SP6a>PjG>q z;LlvwY|!oEL51MmfM|t<;M<%Yo$!joEZ$8ZiZvz&GM6*`X{LN;rra~tH&wG3$S^T^ zex^fY*shCnh(Y%2;>=!>nwB8-og}uH*&on za;}?mKj*X#%bP`}o!}~#If3CmhL3UEJ+UPDeQwcJneX5X;AZ8ME_N{|t`v8Hd0i;? z2Ig6rNo`4uC%Bng-8Gfc|LRhknj$JJWOEOP|}%i*l#S@0iBJ@ahy(<(#QS@0ji$e-iHA@nL?8e?|5#B|1v!`~{whrJ~@2XHx! z&bxpWa-NRqtQFYJs+QIO&$SuYJMj`D&g1scsNEtmxSSd#F$`qn-DBisF?PVfFi?@# z)8OpN*eJ%Vv-A>1M*{qK$jjOv+O?kUUeE`*)Uc{`H)aSdqQTnLF1 zISH|_M20v=v_Z;1#3vu?u`zp60&x$-+7d8qT%KeZOo3;ViBF2Vh z5Y|U5V<`_NQ@MWPUd}rRYy(>GC}aOjC9F_9#hP8loW(r=Z%G5Z4fg=3}aYb0GkQSj&c@6qYYwqJM3JM z%$zr%!y80}$YkthI8lR`C$b}Im?xY{Z;_w&t+}^&!SN&Dy=lJyuEMEdp_q~Wi#cAL zm#kU3i97XQ%t4r;f1z~~&oc%4&`_>SpMhLOOf(ZbjHyf!v-DWNn@qo$&E{>Yu$Iupr>tVf{m=xC+^xw?6fQM2G z0c*^}^Ra0tG$DRPe333dPt7Jc$nk|XP?TklMeafqX^udHw8ccVbTv%`T%%6}WtwRk z;A&Gj;2;O_$D}7&sO%i1e@g9Z3F<#O`Fv>pWjevnV+n4`B$&zY*9=OZp?a4}0$v(696e?7Je^sX5MFVhHK%#^gOD(G{uT5CyxLp4CFSCh8F zCe6t^0ME2NqATK6i``Tx?u*Md5$9rX_7lr2W-&VX3(YLPgk{X)b8O_z!T}8_y(mWki$=we*at1D=)u^v z;=c5FMHiDpSgK+cOG8+;ViWg5-UB$K2JP!dE@2pgfKh}sY~LCFxC zBxWs5e%z8R9xEyGBMx4oGBT=7D^1dd~V4Tt3sGbxW&B& z=R>g@lzj1sfjt{*!kqG~fgQ-&pcIH#B__VlGKm6l%)nkSpG3_1HiZ2EtPdt)vdjAT z-z-I9Fk^oalVYF8qPfAyyRM7LS}d9+CccYz0DCZmrCIxnS3_7gV4sGte%1lvX9KHD z8fYCPMxrZFpO}$3+B!r$9l}bj!^9YDgN3qA+-#m^9U<0)usFP{^#Ng`O}v~LCq{~4 zv_OZHo6QZ{C~;c|E4P-2q`twtbF5><62c(!i+GQ9oOlA56;l3$8pey)4D6ju6L#UV zv417b{Z<9D>l(tuW-;CBwU&xoBxZfw+-#jB?qIBqW7Z^bA7h^?RBn>k$(S5*lf=`E zT`O#HOHr;TmNL*9-K&lcYs<>q8>64?0WQtfTl=Ijh$(TtHU`>bd8Pb_y6 zr?kZR;wr{AqsNX~&!-Ih{UwHE&f_#;WQh=FqV~-bJGdO_X~LVFf03A#yu3=hVPOA& zmsg1s5U(yVAPamWqO6lDQe2eQnFdP{xRJ zpzR_tmN1NtU1>vYt>Qw){vwJk84RIvdd4=0e?3jJ1iJ^yh4Mh#zGh&+pqs)F7(w zTI^?DwQU!p4eVa=F0hr1ZMH6mJ7~LGtTnK`R>H1ejN;j+z_v=v`bpvm+YWKJfo)Fy z7TAM~eX2ZQ{TbLE1KX8mw%;fIYGB2dIQvdFKN;BO_)_cB zLZ_1}lv|IyXT@M(R;(O{r#@rZB}P%65m9!Da>m*a-=0@?iKUFe%QIgD=M_d?U&o7< z-C{Rmhm>WGpS0cLH6!maV0%Q@Gf3tk<)0Xh&k47I^-Mb3zE=!ptW8t{dqMo!$UCma zi5JCI1M8kyYJEv;H?R?ofwot~P6Mk+H;GrpV+OV`NfED!XBk_EUOCVHnt0X78=g`H z>;nU%UU^L%WsE$z9(jX@lAfEzE$M#y>!LM;U1Wb#JRia?v+om_@R@U0+9vzkVw%Jd zLpIsp6|)U257_&nnlXw*x7ha!U#Q$2_P>eN5O$yaLvdw@bD-^jxHXjbsQtgh{UL0Z z{g8Mj#QBo_6Y*D>huZJ69~K7;EDzYH;&>?U4*OB@ODOLS`{%+joZEnMyX;?xOasdU z_D_))%6rs)LJSS%J!=1#m>kM`!+uhn8_Ijb{;lwa^4_z5FD?q@y=VVXY-CKv@}K3= zB>aq`@Gs&|bWmx`x4($H7`s-aCCRQ6*2{55t zZD6k@p0F#*O$K%yFjd(R!oIU>%4-HzohYJA%6^B6m1+nli!rz;JT zlh=yLN|S-j$=rlI9Pr@pQ|0gJ3b3Axtws&s=*fzQF{*DuREiQXIH_E!@~Xs8`}0bw z@-}0#zEtJ!5>uXr%v9xLqa3YNQF$4Fg>Gfhz$lXgi{ z?2JhZrYR}y^0FCQE&e6G(dlem5!S3ARK@wRl)fXK&gbW zi6oF5e2a*4Po?OFw9e@!LuO>Ilzb$H z1*xo)C0N-9USeB)&vv+qy*)B5?J0Z8!L2(rt%#pf!}`c{Bt`aJctpstK#_||y%~Qh zR1u3*ag_CpOiNBFC$f~3FD-B$+jbGo45e0b43e$rc1CIy*|VohOaJ+w$UU9R|7m)- zAA|i>!{b-N9NZo#A`Dd_Bkk#UBwfa?j?sgn5F!lA9E}@S>8q-c{&Rx;P4<_Bkv>zM zo-S^}8;-3w!)(P#q8T4MZlxUfB;a^31)pzlFV!8NY`1ayiz zrYvIE!my3ur3^PPyq@89z~15kKt(*ka35f<_=?lPfMOH8~{8V}BE+YPW1%DOFb_*a7KGonR`% zY`|O6dvjXm=5cxe!x0Q8D2j5-a+Y!kGA|Z$)WxyqE6c?!tsXEXW3jSE{Fc53kj_}@ z)W4ZGA-z8SPQVAvk1PB6bcc9e0;MwPW2S!xSe>M*YsBHWJ-{Q?`Ew9 zOi$VXxGU{$Z9nfJ7O6kR-VMrE3?FkmgHm)JvPgXh=_^pzN7^3scJpVTmt}vU?Nf>^ zKLIX?6Z$@7uT|*V)jp|q{bkgsh<)J6&`TkIpuSIiF6&Ia5OnxI!%}rpb~$qM;1&D% zZ0Z4(_Az}qcR$0!d`oqhZ>bLRE!7vW?Q{BJLF@dJZ0Dc(7U^f)Sbd@Y%yzWO? z+-Dt9KUZT-hxu0PnCi9kF&)FrR)3Su7Oqn+!mZEGZ0Ezgldy{EBFb#VcUj{AXNzRO zzcS?=rhLGZ4@ElY2Sr!F!=fkPQPCIh3*iPlA&LP{iot;2i{XGji_w5W84su{lL4*D zS%7g0)s>`BU1woVkkARh;%9Qm(bEX3A=&tYykJrfg%%HgS(gkG&lc z^K#2W$o%h2%UA-iN71Cdm#OjqlZpqd+4u<193g{x5Y`or^GLDBbjFu!xAo4!ki`eJ`6lT zCk;zb>Y?~j(0_7NGG`TYRxxL_PWrSmeKnWb#x-u^+-(Mhuf<#O+gaMn z`dmecCFqDf$Px~-G{r=%=*F-I!;uU}F|1@*#juUxYKB`F-pX(r!`%$`F#N<+1Pcf= zNp>>qYwiv!jpTF*!%|Rwa?Im&9j9A4eW|%haVKoy^lpX+843$Y8-usr(i5ufRCW!g zciV~nJf|z8C|!-OZ=PTx)hRoR>_sv@+bna5qDd zLUbp?-6^E)L57F%#$|fK!8D>A?m~VzCY|7xY~tU|@L)E{7hSm)h9eoyW4OjiK6$Vk zl{(msN{Q|Sdv+&^=t0_Au_`><{F9ig+^6hUzEon=e08uoTAi%UQk&JK>Pq!4)vCqf zOTSYzk9M2(wsu_mMlhI}_X}k%?YWT$h3%xmn zRiOW;kqwtn&G*+DseDf?3tI1TXP1CUQ%n(l8t9QeH-SJ-!+(`Grs?Cji+nHPdqYc09HK|^ z$h4F;G?{8Vl1`FkErkxEq&i5#EAh7iE{wYa@I@=ZUlMl!?n-_T@cRrZRhUJbuK33R zUt#z{#xqEJGxh?$z%7#LSJG;uR9IcZZY>#S7%D7p0Zc`I&~JK00d~Rfh^VlBEMRx^ zl!_feB48hsp!d&H0rSA6qBk-C3q%$m-UUMc76Gc5eY+vuACTVr?Sb?_Ko#H9>4o%Q zKoxUyAEbu?VlRZZ2vqC^`T>?ewu<-E@&V64!wNwaJMos7ik-zQz&*GtR>gBzGpJ%OG{RXJpekN~MyiNaDnW?@R7Jc} z1(>FI0J|s)0JD@jSkR{o0t_fa(E2sXnSkq*QGk~yC4ifiv4A%y;{k6}N&&YhlK{6W zQvh#MrUBleoCSE7QUo%4e_q{ zP#h6o3Xifvaj7?|_o;i-SJb2G3H1lHt2SKA)o;+B(BIHM)Xy~Ot@67J^87%EIupI; zrxR-YO*K7-a{x)BeLwxpGQEg%g;V+7!RdpfX_UaoZ>iihwZucWrJae=3#vc7(PW!1tF^Mm=s$&Aw)B@1OSVMJ9$#h5yOQ+;JiNqwc?KVSgK zE3fr=FDz|bTv=aNJ<7MBxxv#I@Q+wfQ8C^VIF&qhNtLH5Q0Hx2F3Wb1IPiZ%B9|rY z2X$;_xp$$bF|w`90}bVi>1S8gH+u}7BPip1-iA>=UuDbk!XYHHQ~rtGx<*g+=}Hxf zam|fY^9n`j*hZMfS2@4l!`Pzc%7B4z71O=mdSuM-R8~)GtZyl6s%!)*dw{i<{pPDA z^C4$cm60ed@z&RSLRe5hduoZdp{dg6@dc}{uM4!aqerwBGFW2(2y(^GXph+0|^c$FBHS3c&nT1JtM?0S#HF1 zQ8oh(&sar;Sl|g%OslE!djjQNY1A<=lxXl*d42VD^C6>3l(oQt8{FY0`rYF_jUHcJ z72EH3^4$^E8fJ)*wTy6&s;=hRCsg{S*{i8Z9v^;Db)lzPlz5w3@U?`hg)I=~4 z%w1LsyH<L8I4)xa04HWriov>}%wvb<`xJ=xOphDAQ5IWKZLQKy635 zp<2fb?#_;6Idtm$-o}o3qnm4LJidf4S& zA|i#qV=jj5e2=e_3^~*~7AR@<`4GrEW{hnN_*$kT=5>-6oLW59K}Dzgyh~a-2r2i~ zHH>Yn7UMBi{Vj1U*+E`cAKFY^0z$!vhn0;Lb!0 zBa!2Ud#=pe>;qE;euO$SkRmfe^U(~CU$SDT$^-->5Y(37m#TyDWJYsipsvA#xYN*7 zSMTwad3=kZrQbcX(O+5P3B>?}3XZmr&T}ln$YRVtkyC&urHRz*r^bk>UT;$b3U`RW z#x^tsS|ad@>Tp3rAsTKIDjTaI3R)9J6PH0b+e`5SSqosx&=8{GEHER4M?Mt|PT!nM z{1Jm+AovCY0X1+wW<9|pkt&p-kiX>BX*3Xs=M^0WXgFGkDmEF7C>Cc}Pr=YTNqJHwwS63 z2^LeEF`u-fbg)a9`4roPGlG^VuM0#9pElp`t;bXnW*p=7_@{a?L@BP9)`T<4D}8XV zapZs(dVLGS8B;1-=6guXFbM*PP+DUo!Z|Xmbs&$b$Hd!S1{?)5)Tz|c#t2!#if7e& zBFP*%jVjt_ja?G(H2Sd|3kwMvW*qwdYy{j+GfNw5yuJpW)hp{eaFuzgnz0mUnNAMu z?_9zdkH5-S$1CY@-R*20LH5*CHrEHFslw!-rekFGsQS7}e>fMuRECfiXqkbvS_IwT z9)sR!X!803Wu8i3Rqgc3Ky3t*^nGL1QeU}*QxW;WsxdiKH&+G1wFWb2spYF%P#cj| zGP#VzLd(Vosu7>0E@3%ACol10{k9~6Kj`ZeHn58cm*Bw2>+mowC}n!{d`w2PC=chA z`h$z%FfFV-qJLuqvk|5_rUmNe*U{oTTr8*)#XX)b!&#$S5L+k?bDX6JEkme8DI;RR zBz)n;Q~O{q*+bDjTpAOcL~4TxRKZq|??F z8>>A_rqu{q5e3t*CMe_TD;ETH!KM=%B`i3DgsHT-s;lz5Y0@S-S*OE<)A=+Mlo6cY zjUh==V2@zbmBK`DR}$_GQ7wm%!BEyb-_H}FDEGCXeA$I{fvQ^8C$#uSI2qgMZC+3- zreNrZPKFcn%jGI7Z6v8x!C4wBBlJ&QwOqm(4E4Oi#U7#BKdTO+F@gC4GU=UvfsiYe z;5x1Sq7r+j$ddtHCk5AWqRKcYptY1dF_?_4kdRwJW6EcpjX7FOsjKpN{oa~@I}|4U zZr)E}4(WR^oYibdoLl#km4Y8j#vzQ#wagBlwNQ5z_FjoBNQl1eECy?7)mKk}(A%gRu zJm?5o855In*deCPzW~P`#tN`Hw3NqkIzXFl%ub#N>J*ww8y8HeY^!Y3MdA%^(Fdn)!9xq$HaMCmwQPyt_DR}H)=m?&+;JYR)l75e#!(am-Bl*^M_ zd(wO(i>xR&@S;whtQgpQ-qmx23%U+m32Shl@K^YZO=FPa4b*}jsVM@CpJph*y*I&A zkIt4;0`~}z$i51pWu66eoGN<|RM~$>U>6P;4A@3twh2yxd~zgmit9sz>#C)1(HR3* z9C_#pax@O1#~|3dVlr>>*ZCu6=yqfpPn{lMvCDOyQ`%Tn-;72D7Ylwd7Ki2a zes)`$|70p+cJkAtgP_3!Af#(J+JugWe{a1?Yk&Pm zvKmJUh~t&@!S&u~Pm8y)db$_AfioXD?rE0f)QrjtDefT;jWB3(v*tHqUZi!yYPo5T z8H{)#MP#`03&TTYr11+{6$jH5eh=*h;P8GC+H1)DxL?MnQ?G5rOqx1_o;u0X;z!VH z?m+v!(BIkWN$wCv1uzLUR#gVDfsx)VgSj!k2dy93o55j?Cb*%MC%}f3>tGxO@$G@A z_tZcn?IMM@sRCO>Y~tzyq72V~7`p^u20|;B3{LBvt*G0D96<|98IvKxxXTKbrh$SO z51E}9B2s1JZ1s=WXzT=8Y3UbCSKxer&SqJ4Oa#VpERU!Nl#3&31u$z6q=h2y281-w zG@rz9w&m+oW#dZaG%MdmzX!#pV2d{uTkK$4$|;So9P|~&$1cH<28{?BV#I(YYA_iY zt2m~eUFW$FJ%eimpNE#_FuA-yVZ>P65}gi@v3*)1xBRW=%iFCS$pnvk&@8y4VSsAv!#y!8;ky9lLtF2>D& zJ>G@D%^Kd0sKMJ0IMT&?$;7h&sahe*{?n3WDDQ)8l2itX3qo~^DJ7`437;zD2Sf|B zAxb0u^8znHy@V}5sZr1>fTs`dR**DGljKTZl&;246?T+1mF0|OdCic6b`+kDYbLiE z7k=OlpavhL)f@E5JeRZUQe>LMTJ>@N+1jQYmzD;hlfG?x`(TP1%|BX=>J! zV|xnCNxxg9C{`0dd@>~+Ca0=69F$a7P3gGL_yVmsW|AdhaYV=g_R-YHd;X5r(|*VSI8#a+hR0}LTz+7OhQ#1_+2!B zEc_q`9+~)&I>1Z|zJ-T}L>&$bs0k|^nRuC+pP4pck_nJFD+>u~NPJsgh{rF+L2?|o zrBKoEMKd(2kkoau?&jq9)=i2QEfh{93N#39x5mUNN?f*JVz$umn_4IkhsN40sza8E za;iods})5YaV+C{$PSV%QmAHkDnV8hx60xm2KkT-rsFKS)nGvG^`tRnApz6z6OFRM zW*TWioWx_1;x((?q8X*Fu@;jxOUu&0f(B-3u&T{wGx|)`ElQRKQ8u$hRTElo!h1(5 z-u#Jg8yoFZt|T;(3*8EnKSGJSD3RpU z6r>+Ox|K5%@h%;eyi3Uz#I=WVkbsXM0dIt4XaZ=pTJ%iS3YE}vN@g6|n9%wRxNg#g zqGX~~2}^<$@R7SgQL9r+Xnnz9g#q+fZLEVn(Af%~P-5|)&0@iun`0gDRTZWK1aFie z32Dee=NW-tjvyY-Op{m1Q}##ln7E=$f6-Z zEyE~*YSF@^B(&98>0`CPc;Mp7h|_A#qLP4+XC=Q;Gp!cQk%f{QtrinYvVt+o;ehQd z*7$j<)d8I>)GxBf5`~Sd%$;f28)L+bCIzXw6WvQg+9-1?#sEvWi6p!P%o6M;dJ+Me zpuJq=CaZ-!kb2k*U}Ym)z5Bpx48g-c?{qU6wwtxTaftxBW8a`u3kHeR}kfwa~;U@dD zS7&XTl5_LWyZ@e)p8Dd-uV3(dbp8?3qz!LYJvHot$ItZLbH@G0hR5!GuK(qWr`^Bv zf!+S$N0R2;ch9)l+L~QA1)l%7t@^RoKOX=6h9@nTX5Msh&Rb7G4JfD(AnkOxu+WL9 z!%2irZx8D9&Y(^&`{@W~_zhSBc;8j%(FE|FWd7Q+Xua93w5~a2F&4QKbq7~y;oWIy zbC>H3zCM-fG!9~i)33JTzg%YtE(e=^p5cx1k~!BY@4K)>=I!+G`GW>k4yYP1uy9Cm ze^0^SA<0U)8dtWkt_hNGi;ayNR`!UeStiwt|5ep&)yxTtKyYa0_;bk#+JI>A84g{@ ztkum34XQblGM`{~ljV~IRz%dtu^W%hp za3nyKPsNCo+2KG>g`=oeBgWf#$-!NOx2zGP@jrS>%Ev>)8o_8hf^Re;FLL?+{ouib zaET2Kl?3F<6d3kXD05&oQz-`GHEtuvENCs`hzib{Kx7)ykwz&8%tbs_6s8AR55}W8 z0S_?18<9j9N6+Aat^=Ee%3PhLK|Ynj1NeTdQKbH`KNPDrf$TFh#r_1;F(AO z<={@mF->q~Pm?RrGLM*`{zh~Kp!^@2A^}A=I%Lv8X=zbnfjY!sfr+JjGWAA$TSA44 zBSi^3$oI+Vi4Q2&ZK?{F+NeV?4>|a7{&quQdb*KQkX1)7>VI&6%Nfs|A>UZKPip@3V_k*qR|MN z)#T#A=Q0K#m8nH8T;C3w;lsL%h7Gb>ui(7>T>coyurD!R0#TXxwG4{N__sZ1CMj1_ zX89_crbgV(@X5Mg0UyP7Y|0e;Q=wDGmWSSH$qj~D{6h9XcM*g*l0uor8wm8KRT7nQ zhH{+Djo%Q7GLDt$P**Sa;Ub=XStM$@k6wN&ZJh62Vo-Z3qU#?V9&;=-c^dQZquW?u z&`aqgtJF`YLJbi$P;Dm05X=fB~D;y>n&Je>OPavPTuSbHlXdN8Kg zqGI=e;=%&_1{&FoCam|40LDhqX46LdiJgC2Cz`$b9 zfXb@E{@hD(p+-G-pObtAzh$n7m>C|NCDXM<%S>N=x7t9U$$v(E{sLV3H_vzDqA0)G z8))eKmc%e_LtFwx*5Na=SB=qT6c(TZ;bthgb zsddtgD7|)wfo8l9>vv*QIUBtJr$2ZFj#1+b)Ykc(i{<-hPH&B~1@E{z;Uj!IEf&-phr?E&jZbIDj3WR)zU|1DmPHs>_C4Xh2FSQ;XYgxvvLR-kK zmj&PQarFgdydp-2#^7lJOJu0%7m0)qwS&u11#Sz2(ITG{ye<{uB%W`)a{O5`>7&Nb|GyPK_@}`{wGSEs>!J`-Aca_{!$IK1h>J?;O&O9lD=Q#ypX0B3KH~UkXtzucRo%Jzl9g( zL>-c?&$5CQeIiVfE5lcxWrZNq)uLM&CvS^FtDLZu3oHE`gK6o4m5g!8a)y(I=5h^K z=m3Qy?iujC>=afeHPhXel?v&Af zcz3C8cV~XE2A-zEW;TphHX~>YSOedVs`XYo{rJ*XdlQewON1VbqYl^OuD;zd7^_=` zclQUH=XZBT+BjTwKGiKdJU`guK!@cUt{{WwrhY#u=Rddp`1d<)C)W-*@%{t1d^>1V zk8i&?{Lelmy&rz=(L1jk8ohYHBOe?;^LSm)W7-XGUMhahzS6P&%-cU)^ud+|4_!Os zmxiIuPsP>^?Y_l#-o+0*asQ6~t1msV?UCepmyODMZsyU^_w7sh>DIMreTR*k;OhHM z>ZiX=T-GOd=mQhK|I@`sZre&)WIey(pirhvrzv1LK21CDxsr0^A7T@Z4Ef)_5?>(i zi-B)^WkmYDOmByuPk~z{BkOn_^lU&oN9_lS^t-$>EBG@e?zym zy+U%4SAfmjsdU08;4^zS`a0rE(Q#&MVZ_-NmIHPc0vMOjn=SkRQ5th@$m&G-M!KUDQPUPK>fxgC|z1M zfUglPq0-IZkkaU$x(R8jhptqsz|o9)Jov4l82mm3eS&(1%Lf-4PJH<`SYGl^fs`uf zLsy<&Xc>S8`1Sox^y;jwZuCOrJ$X4~EaVoE9{;OcDH*fP4hrhcW%W4cBUdtWVjN(p)G7;XVsybio!uFhosJ3S$| z|HJj1je799s^M3p^I-IB0X{{d7;pe!A#fa3;I9@Vi2n5idiQ|JHL|tCE$-Ofe@8br z{F5&GDVX3|p5N?Pz%`J~=+yzT2E88<0MB;Vt7CnqvoF0gFp8x+Bc#yipz%ke#>eBb z8Z~1c<91FnIBEQlR|Vq$VX}ui*8iWicO;^#!cl@=KWN5C3;cl}-3QIx;2DdND)1X0 z`5nri+OxraEx@l$4B&npfL2rQR^s3G2R#Q7r0~Rjv~teW5B!VQfK+**0(81jVE2s)8SmKG$sTXI6A& z)gV>Tw@fXVT#y<;i7l{cirAuWRa-?t;VETxXYrydTK7*Kp**@x&1ri*%5}RZ@z6hJ zToLO?9sTOlf4TgYEvsUV6s$5=6|B-HZP9T3swQGq(w4vc?bBac=G@0O6xwnUYbdKk zL#364Q3W=$Hd8kzsx!+96AR)Au_oGQ$u9*4yp4r%1r8!w5-l@4)wp4(F3c{-B#J$; z^ZSlMS3z&e*Al~*EV!Mh_BhM1A*2JA=_R9_MFoY01=*=FMa2aJ3JVK|6ciU1%>~-O zU_ilO11+ffAJH$SAWG_|)8#q9D&;D4t#X;VN@){soVfJ<=;c3WeY|jj z`?{a+ZX5f-yTgU2+tF=>SGN7|+;eyR++*?^ElvLzakXRZYZsPp8*|ZT*Ux|Xo5}W_ zZO?sT{m{8a{B6xE-&xzvocDN7@!>Vk%=d0Im0w)-*xZB99{B6oN6vj}$+Q3bSFfq5 zDJG@Fo-Xh%I%~$U2Oe#mFzDN&XEXcuKJt05>Vq@xy|60hf&P=%N0p~M ze8IWr#BQ57_S*+mJ~(jl#AWH<#D01EEB_q*v44ER6@hgJ-}kLlmrNWp&X%k$uN<~> z>4~>Kzo%gCKSv)wQjs~ZVqr$*n18gIN5-E0{M+T1T)wjVTji_noshb4*&}a_dv>AC zF?{ID=Os>Ed&Z{|H!e%-o44g?P3{-7)>RI_>*BMOGyb_N{H@a3q}`Ep7@68VZLF{b~({zXN_{RUug77mbV z^dL1_lO{A)ADM1?d)3{kg9defq~Wetn$=AOMHw~Sp^LN`vhaJulq z3*8N&?|Ra`Q`5paZ<9a2%2!YOaf}p<6ATd=Ar%Dj3I^pB40a>GpfcD{MbT##lojBY zRAs{p)OBP3umZe*?*D@-0tL~ec%q{GrmNV$wGSBDDi#0Y#DsB~?<}kyyzGX!Pp0g@ zZrtwFcgv5}e>ZpLw;#@Y`p(klDpId_{hip?WA?q#``NW+NAI2c)ok0=#^p;LA0Az{ zbHt0@HT&m2Sa$3Ai^?)RIem_AIrqfDuA3j-d)-NA;M12cP1v=%WMY2f2j|S2lXm2y z-dn!i)${43@?BpK>(=AZ#oG_Kdv@#f{Hxzxzt;EXWxam6U zJ!fgxYu<3YFyQB`S^IL2yZe3rk@evFe>;)xIl64#`wf#XxMJtg2}ieW{=PNt-qPdo zk8c=J_4%_(l~|EIVB&9Y=D+{gONHh~?@YE#e$V9n?9q)s`}6ue_w%DyC+@rM!;60{ zOuWEy`>b=FKUa0@JAULfQD6LhOpj^r4g2fRy05y=I8&|paNf85{`KnjlP)~^xb?F` z$)Epi?rYV%-@MCpN8j1kj2$)Dw%}#Uy4BatN-r#Wam|Wxx4*IKWYi~?orCI&R?aMm zdDZ@T&K*m}eg4Di`-)>8c*qw>J<`-=r1g`pe{f$t;K!wZd&XAjIbnM0tl}?sf3xq) z*h@dZ|J$mEo#qn@7L_$T9NXC6>>2XQz_SJ~Ix*~tCCU%CUH;QutqVU(?bH07GCtGW zzcqWxw@+pDom9By_^R!b|2gU(_e_59p^LUpe5Lr7J!=L!UzzfL!79trf>oyZa+ahdLWKWMyr zRos;RPyXxC+1+j#osqNf*xc!NKW-kJu9rS}(cb9nj|MILOTq_HCk8)vy?N(LL*7-A z3P-sf#Q&80UUt3Cg%|N3*;gZA9L_wV1{@4ltB``_O@=aqTsreigW zj~317osj?8J=W=OJ~ZaB^FDaqtu^0M`}M00U!QUAttltRJ$Z0&^^V5s0ZZ=KQWcx` z_Q-3$|Kxxr=G}8!ZZGZoS#@^ed$C_79KB=u+|6Rq2zs}fo#m0-D-rX(Gt0K+y z=xcpkgL_>!Wa7X#mp^dLeVIM(++OoVW!DQ1xk_)Uxa8wr=e^x+(uf()KQimgp4y3h zOV7!Fx5p<<=f$2i?!t$@7l)qSp{}a<`|jk2p2>J;=A_St+!}kVN9ogPkB?bC_VAv) zzNH6!pY{B&UE{8Q;rMfzv;Mw%{TEY83+}w<%K!S}oLlby`JVcc5p4`0i>2X`?uY2p@dzV}h6`TXV z#2k36AkJ(vR+7nzj>VpcnDjcGjJkvhB&m9IwjC#U&DevMh*7*0%8J!V%({ZuQ0zAq zXqW=pO>@4yGt|PXOP)wFO+EDaoi7&d>v3uSg1K^RXiwHU0S$*!WHxT2_tC%f~5lN%|(AprrEXWs?? zT6g<(2g_U1-EV&oSkV2?QJdorRb6xa=*=tMYKgvjkEg<&JL3DjzI_d=e|`4MqxM&Z z?i#;++t+n}uiDjp!0mrJ&$H(06_<~jKJ$aoy-=eRB6zUyti|;OC)#eP+P%|JB`jM@6xuZJZf03~|Vk zGYHr-WN?TQC1=S9l0mYF#32YGAc6!@q6EoNl$?V|k}DD=s3a9plq6vrOkD51yWgJk z?YVpQpE*-ScQw=9RnPnU-s);sj?&jKNjKq-cTy#MdpSZSO@JTQ`q*R`ZvUk0hU+dK_gN>61 z;pLV>OT*P|30tbvKhMPl(O;wtP{{XrEyH^ur`=5Fd_+5gwMcTr%*6WEN2;vbTyy=o z$wRAV*0L{6aPM4|!nuSqj8oywMA2krRkJqLbpoqtMz))nd-cVIQ*VB`5T@g*aOmp^Nw2IB%d!cM+H~I}>@QQwq zG+hjUri%hCCJ=J#?-s7VbeYGDZ)Qj-01iOkd?!980`?a~n=CAtn@oonyF%}vUEPRezyJ;@w?slw93b|V0r6-?_hClHMr`h5(nyq;e z_LHs)3Evc%iPVPx#u$K1jjy!uff zx_$~Mz-+I4R-(r8rgClD+2P5B`#P`KdE*+|*!^<&Vlzk56Dar#HA{ zbop#iq!y2K66UjUGgnjwh2@UJm)z5s6J*`Qk3Wv`iBiN}-VE)z`k>oP&yX>$^`vGQ zdDZi0=CEkKk37u958uTJh&(V{h^&_P4T(+3I*2GlD#{lIn!QlCU@Wtc+U=SXjp_Sp z`URA&J=6OtPLT%QJyQ=*Jy$$X}@4z$$0(8J9ou7c@i%hw%GdND3ktG(;A>wkS|i#lhb6 zt?96H;OqVV1i$^hJ-pV7kl-x*8I);)25bfS>}ve@0wL6!EP+%;W9p zfvY+4>v~zaxG{g5YnzEC17i|gX3!Ae{p3!N;Yt%3ZfAj~3Ly2yfD9k+QHRdJ|37jD zI05#yK)x3Lw=NK9A^y3wNL8B<5}&IY zcQ>1W&MtVp#<@r>kyg$gnOxo}G1|cU>}F_gsn|5#(-S*NYtB2StTe-*k+t3oT?iaM$C* z9HO1H8xT)?Y%eu)EEkfwHIg-WU|ii3YKw7oT+T7^$&Q{Plb06ef5_&H^4Q!}XHc?j zN9I-A5AR1_oud(uZhRt8^YS|0XFMXkLKvF`OHMl+hd$bHdV{d0-&BfTS>9%#!|Cz| z7S;9IR~Gq+OF++-41UzI;@z}YgU%vLA7zzKHj+nNXlM&!;?&f>jD?jesVo}vLh(Q= z)xTDI(f?^QF_vah{KzR~7OR~CXnDS;JO%!Vk~``v6yqx~VF62dw-$Oo>$TQ12Ed+3 zjn3cUG#k?AxUDPg74%TTw@{w*YE!*YpFb~4{@9FYIE%PGG<2_MvUAS$F$2>owMv=B z4Z>HW39xC0TUgbIu_rfS<0n)2+j7zm{6>;8J-c!0t*%|FtJ>~$fIkU~NQWD+BveSU z<4ICkxU!zW@L8A|WQl8hENcfA^(J~FzvDjU~w2yGhrD4 z27q3sPNr6b#$T!IFWBqr+GiX{;Af8o3t*oGKf%5Ua3gq*Oo8+Fpc*sXK(eM;A#1E9feopqpWR}gP~$V&CX-BY zhs@uCqpZ15HL?Y>045b7#D(?Vq(R&kK!50%tJ&*MD@j`QtuWZkp{S-{RkcMr&2o{u zy;_d%bMu^ze%@Nj1(jC;ub3Zi_gR*nc zDIJ=ol6pkXD1W(Y{(I=zSHT29nIM1=Ln4vFpkN9DUyFi=#lKn3|CPYKn#)sLtoC3b zyqw+loc(em@iX+u-s&A(+^6@QHN1Ns3ma}gf}B-n=NlhMQCkWgm}++0Zr;*$H=Ykv zHQs+HVi&H+2CIpI4_-pHkkTw!1~}@3o~g}?Rdm9oSnu@t9HBMUdZx$SR2w0hNg(DL z^X@sx7^kkkxE0i|qj1l|p^TxZctfN~nA2t=MY4|WieO2wN#J!-`nx*&50=hzOgWMa zntj@j)g2st8*ZTfe!3y%-ply7N^w5zJIihkM2|)I-C_|v!rYB7tFN-R&-TUz*677e z?O^MtxY$eHR&0ECuhfr6w7Bn0sKTP6>tp1zmI%O9lW+cfW&fl3n8;U2#Sqo{CinZ) zCU%xDwr<8VGNAUD2R#F1Z!3EDcUTBblShs2Z8Wgy3fcyvL z0ofV$(ci$p`3Fyf9wv@>^L6%ZI&L?i<4-FJ^9+(6oWfc?ri_0oe5Qxm!2B&K1N(;O z)ItM5n=bqBp`y{jLv%Ud$X$7BaVu$#=Kdz{_9e{sc>;(?Tgl8tW#PC_yYAy^~+yvjAeu z*ARQ7OlC9f19EaQGZfdXOp;jf<~C1Mdjoa3UbtM+w4uAE{|jJ8>=9O zDtb2Kp3j3AP0m1KjcMbZh%)YRPubCOv)758z3uviMbF7mflTTChuYGfr6_aFyHAJI zd}<8!@GBf3X9E4Rzy;^_3F_a<+M*ox`dVdG0s|A8`nDur)lxQB4@l)Aw8I*jp{?lb zE7S~>Q88}&i#0>sbWwzHA`^9L+i3>`%R*c1!geQTi5@OoPaU0OU0LIjLvbW7czKyP z4yQ}K3(Q0a1~l|7UuhO|J2QOaLr;;!H3_`)LE~=Ly6Q2jXqQ}U(pGmIN78BreLcJPjOb}*=1m6q%n|1nFDj8$|P;88)HwxVVD-FqaU;>CEkqBYqZxvvg{aXca2|)d% zGguJBDR4|7_}0K-_JaWYfI^7^pkT%V_vky^;p+x(la&rP5IMFx^l*O456XCmd!U&F z0N&wln7CQYS>L}yA~OFlrhuy-KQP@2C1D_FWWB(IP$I2C>6@}k?piNz=I!a!@1(he4xj9+rmRt+$Pe;6FELBOX z81TwIM>S$NY`e{-Wd0&<+n!30N#Zifi1J2peL;{xd>0`+!M8WS$@Y%bl??}i7^a&K zO5%LGTj0s4o0i_yq6x5I1J3G9O*)DDZUSa*WcW75)iL->#EKP)VxAvdvu9&;t;=h+ zT16!1{W=uR3q`I9Vnkn=z`R7OHmGIUok_(y#z;qSerj_C8Bv8Lnn84Xbd4Ztz{O!PYn z_y@w=V9m3t70#(imqU6wMo~9HOxyo_4{3#WWpO3D$+H(FK*-Lq2B4=9AuB-0A`tQl z2x-J(e$rrd8H!QA{cgZnk#109;d4>g8do7DX5hWG$jDt>7!Z>3U(gr-{KSEH-Lcxh zay1b9ASWURv%L31L*(1jbNY4s3QpwkRx2YC=3jaQ78;5n_mZd8Qkpg_151I4^<~t# z%st;=;mvpq&Wiheef%FnpBskAJXv?|^WX7|tmP-rzFB^-sX&q~(Ld1} z-ep^xmM4PUq;lRa5m%j%obb}@8^6M zJ3a;%tU{eQ-DsPb6YUEgp;Gywt#NbJ!_r8Nvn>5~n&-)4D#k*>7S3CDH`tofnb-w* zPg-6-(eBs2%lt6hN~v|*MD^yinl3@AM{ayv^2=O9w)A2jI%kQD0s5vhjZFF8(rh{( ztrayIQt-exY^p4UyQO|$mhKmsd?=38h1caOo!#_Vtww}*!6u=A1DAE56_*m>ASmHH&YCiqVzLP}x>;gU=QAfrz<=QC40}mA=p!+@vm~oOoh~ z`AMEuKkq_Ev4>ChO>tYF-(8NS;@K6)7T}aCl96S;-`r5+;xm|E_a;autF$A*L_4z# z!nR&aI3daD`+g}EM~SH{4WDGalR|m^amYkxFLwMHdBIZiXV?Wh+vKulm3M{6qe5VulSUhr%#X3p3% nruEj2E8Kn4Yn$YSLv*lj>B*`?ercuEEn13oSG51@`}h6<-eEQ| literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll.meta new file mode 100644 index 0000000..3b109f5 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: be80a2953ff700124a1b0a8adf21bf3e +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/System.Buffers.dll b/Assets/Plugins/SignalR/System.Buffers.dll new file mode 100644 index 0000000000000000000000000000000000000000..f2d83c51416e90dbc31154545b16df3b3f7a7909 GIT binary patch literal 20856 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 VSA1A~Xq)uh0^wu(F;p2s{|B2kf;9jD literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/System.Buffers.dll.meta b/Assets/Plugins/SignalR/System.Buffers.dll.meta new file mode 100644 index 0000000..9addaf5 --- /dev/null +++ b/Assets/Plugins/SignalR/System.Buffers.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 9333f9aee763248c38594c56c3f039e5 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll b/Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll new file mode 100644 index 0000000000000000000000000000000000000000..354f5f554725498d7f7f7f4622a0fad5dc7a9d65 GIT binary patch literal 189088 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll.meta b/Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll.meta new file mode 100644 index 0000000..f580881 --- /dev/null +++ b/Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: c29f68d4427cea49fb03785dcdf2ba31 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/System.IO.Pipelines.dll b/Assets/Plugins/SignalR/System.IO.Pipelines.dll new file mode 100644 index 0000000000000000000000000000000000000000..003bcd00194ea58b71cc854602314b874d0fd54b GIT binary patch literal 84744 zcmb@v34E2s^*%oHzVBUf6O!DUodlAQg_rDMD~k&V?x>)s;06e&pmLQ!U6PB5;99k! zh%LU2;#MpQF1S{0tC*rvmujtbU*qq2&dj~J0sPkg=kvdsGjomX^6>Z5Pf9(6l%H_||8LLEVWNlm3 zpo&c0qExX~Dr~4dBap8^ejHMzawYE=yGaNV@Y4xC=ubYR(XN^2P?Z1orWPd$pWC7L zAZDOk>ykC-5q)Zp-Fz|iS$~7&Td-@{aULouSPudE* z(?1ocy=h_F!r35-ZLm=q+8=4!XB@0=S~&NlI0R`cZDt>+iXG(kAUpl@5B4iQw9Qcg zm6cHHbc{rXP?cIXM60JG7$da5)6)L0WT4{@P%2WFOph_RQ*`kxrF2c9dtCw*dUazg z-Q6CA-RWHTW;zNt_3HXB!9aO+s^*z*Tb`dK4gDboFSkgh2S^p*(tRV;Fs+fZvt6**E& zfGbw`m`P$vjihxq@62i!R;L?MOWB8aX10;6Dehy$V2ZzP#0T}UyH~uXBs;B!K(^=m zEcFMkVX!sb?KR!&W4h-Lp{QH8WC^CRSJPNn`x1uJ@iA_Zwt9e?PBQA67KShsGFr%w zNXws^mcK78|9)D&ME90GIxT;3TK<8w{J+!kgPq>8v(xf7q~%{u%SYW_`CZfUbJOz6 zQ+fCy{jnG++&{W-6F4#DH=yN>ZehI+c8bF%=hV-oy>klPdv<0WST>KkmDvK19{AHLy!yz(Ii1KAjFac$<*a2*Yg|ce#bbCnF|X%bxKZ-!}+U}ILkkr;-uXEJutH-3fkm;?W_{9;s6x)UXNEv`BT zI^Ype7dHGVWrJ7PQn>ISpx#BtVMzS~RMa+{bvtoPu?UpqJModo!7{&$To@BM(-m4~ zsIk};xyD>knkEr!%=8h3gKcPJ1RHX|W;Pff2if{!e>{t{Q+Hu}4^vz!is_yL zOqJ4*SnCv;_Qaf?0`z@p*qF7K(Oc6Psx>;;Dy&P!c_o8cK8YHiWvNmOrDg$4w%|f(&xK_}(-om4S63PEic<#c&cQf#ujkRfCYw zWJ%e7u0s12Mg`+ZV$pOA9fdQ4p-bldD&Xc%DXepXQqT%7gSFP1%FGVr+~1i zPIO^nrs+!8G`uJjbp1O~a4qGXV9_*V48~^x2lErBgVh$B+Ao=Rgzq3+7|fWKUfddM zb)aVusJ!^oRFp)XOGlnbN1jbbo=-Zv@>xolMhb*P@;LIBke| zkp#t^g82yq1y90Y#BB_g_?>7irrb*?*ESy@fzqDSfe!b23I?+mIuK2eN5>Lqov75N5cA&A~!{iS&Wr!J69w}`}ClXv~IAluC?G)>A27;-capH3ao zfY{R=2{i<7YbqzZ!}B)fwE<}k>ywG+e<)>IptjLLWc#_XG7Rwq#AObsjHj6l z?aja=pfh#ascf3egCg{#p%*+fbhLyPU~9-InWonRmDN&3$4 zU5)Sj8SP?=-1*bY95+7fPBY$XDslaTFM*wqYRm9AylznEb0j@j`9b{Y1Lp`K9$S3|<4u6}Dk7U}(XH zeojX#oA2KX@jADs0DBGx&ctWxg{V6()%X1h^Sq3hXWHY_npzXvT>lXu7)mNaW2h-@ zkh8io5jBDtrpe(3xW(0w2sLDx=7;P7gy8>%W!WxIy{;Aa@zEG|3U{;d4TXV*JlEsH>Jbnt zoZlSqFNNOx%$UkgpldyD+t@Q^WYfE%FfV|hH5xL*va->`Tt9j=hz+MY?IVB`&L4Wb z$x;82(4U8C%o&jvikiAEVH*rB8k{b3%L&L%EZc)$QcE=C_!y7i(9+~=BG!!IqeH|T z>2-JXmFOy`osqmT;$H@}Z+)DipfRpA#tXKyO%jxc9bx9XAvHxD4B+k1TtC@NgvPqG z1*vfWHouGxW?Gn?Y^uaS?EP3X_I_MF>$Cgf(Llq{w8gNo#yE`3{rcjNY*zEaq4>e5 z-3j?;BZ-DHLk$@rW81JT){^(Z>Elz5zX&As0jCkhcs!>7nvFOt$AFJvyv2!t)34#X zs$l1SZKCE!(9-~i=HA6;b;jk4quV)%8D<=P7=;*ee#X&*baWaRw2m&uYHMuL&-Xdl zm{^KEDmLt@5cXkPRcy9Z5>GMH1$YiEY))%nZ%VK{mp zPwqSKhu&V_Nk4eXfnOA}A9e^RIr3nLsP6fAn6Ga`REX5YRC)|ZkM0uryd_nzB^i|2 zk-h}w!yN?8>(QZR;=1#jV<0qRZZ1`lAZTY@2c0^KPEQr z;7;z(^h?yi;>do(q62J!nyTpO&=GQD?x95%PDo=cQZpSs^6g7S3<6 z>zx^zOsp2PpeU;wp-F}e>jAg)XEP$3`Trg$SQoK!I)z#3dxvb}EF=sB;q)~NAXw5+DrpHD?y<*19h zxC*!yHyxEocieQO8Q&Q2&lhK<`(k-`2$g1XO}?Hc<)v-CU?#>WvIRUwp9U@_GeHnP z(-?FIvuWrgvkp1fb?<$+xpm|7)48w>HYI!NF(}6>Bva-=sZll^S>cAdm>YK5xdAY{ zBC{j%XQ3h&OLXf!~X<=hsv>F)M4~e z!LK11zx#|H*SS+*Gx`tvJhLlizp_8suV~9o`!%ID*{|rW)vVd%umxI*MsmZ=9R(sFjV;OwOJZ{u&v@KxgHDtOSu*a*}yJ+UYb}?cH_tJ}J z9xU_8Q&{Naxg%{SWltc|3-&84YC9GhWcOc}wwk&B$1_TyoLk_51|>1JyK)33Alp)w zqs?iCKbssYAlc*YWf=E`;2i{pcu* z94nXtkeQ_;NjGBT_zBqL0kpGMD4H!#R}1d(5g8j8=svA>j1p?eI*me>L zToRKKLg4zDl#trE=*oG`Zm=Z_ZFJ3J)Pc}}!(XmhhB6Gxxmk?tabnP{Q07$84a!3p zdu>l@G;91G(n5qqS8n=>JV^%5OpJpJR=x2iffydXCIZ?JmY={B#gdCNph!aW;Y65a zN|OiYM9jfC?^g~+J?J)`TP#442HdG}32YqdzbQ>G%j=-+v4=8WRIM^o_&BJ~npyndQ$l%V@IPPm08H{6KGa7VaEi)~zgB8KF8ZGVPD{MR5m z=2-w|C{ie&dsxlAfx@&$f2@O`IUr>{Vh9E+7>u8W!np0B4?FZ7g{S}@W-ZvqJNb2( znndt$mnzw|frbqNhorg%3+Lieb>V3MrlN~5SG9Quq)Bd6I@u^*VDy;IAm#b}o1|o#c3a5Ur%Gzf>RMLAt)bQQvu@j~verrSv)Sejs8U`~Q51 zBrX78|6eGnoA`~SUg9E21Br_zEl6AtF@zz{8D<=|hrs7&700qAp_o<d{eH; z7SAYd3i!*=F9`pXsrUiiJHv?YW@%Vwr1*hJneTgLupc2$mJnW76M=m_ns5EAfYFF> zM}p>fKHaTuq2qsnv=L57a=!Q(mVqnSJ_O@PA^-2+wi5W6eG^QpqfkWN1d>d!?pQd} zKzlds1=_FyjQHQO8u1Z_&m5{5{av)RC#R_GDzGy{d;^d&4H(@*URFf*t}8$Ru8Vs@ zzJ>lT#wDN7!|_)k&lU9=NH-QDb1gFQ>j3be!e{YFeF)UwA(QEZTwl}a`&w@?))U~_ zidn1WslqIv!T1d*p6z7^_%a6Oj_XJ0p7eFLqZM}bZSE?O_Yp|NxYaK?v)n-Z zZFXb-B}W58atsq(GRDb_^s6I0pu6k$hOo(9i(oD{2yp=4om*jjo z`r>*w3z$qy$(Tuu+59t80QRT9Yj+3Q*Y{n!pD*`wbLURz=reaP1UX>)8vO!;ZWw$TE%*m61tGuzgrZ)kyGj z6mN1P4Q0sOiwxt)Y#4`wovWaYPgT5AZlGrB{T0gLFSQQ63qv@r+axVWyd!CcA^SOI z9Eq86+=zgCEHFHTqZTh9uU;{SMSzKU7mGPO!!hCTu>hmDkdu#=M9iZl9wXm{#n5~L z1u==-I6_CT?mfpJ1-o&A)Ip9+W?uQ>ZpB%0KT=b`F>HAdv7|9h$9$A1^8W~_S}Y6g z^ME$!I-D0XmtNeg_Z*{9?C+S0|AqaBQ$(ngZ;&Xv2v(c;szGyOfI_LD)VY0Rm0+8#t_)np||2yb^~Vq$WJs%kLj zJ1;o?L8y;GY#K_*6+ZIQk;mfDOLELD{+_gr^YIys+Zfp4Hn;)Yr#S7Wpfa2;@y^>I z5jPXLQ$a@5$EJhtJGHmbr0EGJaQ{U}a0ajt$*=;vq-e78>IR{onNR*g@c%jBh|1UuO4ScDmD8a04bbU@R)6@_#SLs1qn)qX( z1VZtm^`INdOTQ+ z{GULZ(HMg&uKBn#wYv*EyUOHt+T-kr{;^;T^AORlG{a8xsGaGK8^lW>Y>|n}-23c? zHX+Q)y7&dkGk$(4shjv(QZMn9qy>r3CG9X`ey)k9#7sPuaiPxL({%Po87J|Rr1*A= zW*uGvTQQ^si64zlBj#g7xQ{1hb#iY}1D&W1>&NzUEnnu=&)soF`kC%3EBJdzfCWOpQGv(4IUK{oY=B}MXY4_=_ngShJDIKs7 zPXtq8fSFrHqs&Z%0#494LI-Tz9U{%8Ru-p@WChJhf6$0SFZcDAAl-xd{lics;?iZs zQNxbED=65#yW*rcvy?DK2g+i1!EdWVpU0X+L8E`Yu75W42QnhtX1 zO+q@f%P8gbdri2H+I}vun2*A zDM?;IQw;B;x?X**e2by&2{6wz$4m(d1RxNAKmY>2<+mQJfQM5jD3U{;E=dE4vypNM zWI?7hg(>Bj(g>!MXPT6!C3Sn`7Zem0wy|ZM9VGN!H!lUL&$$`4}@W0kg`s_0F z6+d?4K*f$IxvA#;a~!{y|A@iQTiIM?LclfBp!_Toh9bv}beYhb^`Syp1AZE`QR1J3qX@g#MCRAPWy$R;r&V`s0N27#F$_cNO}9V zC9`<(ZKm3vMs$Hcv3Ekk_9npM3q9;;Gl4rGZ8@o=_>4VIoh4)WP*U zps>;5nF8X@$znn~dpXk$wUnZ9G7@gcKMAa~$blE_%xlP`XPLN>{u*-7yoSuKv2!c! zJ>+%{{r`#~9NwRgA>{UrA*9$Cg2%&O!z`ZE(C-mbx<)Yn*m7 z1>D;Dfd6NVlG9F~!kNB*99z!aPw#u*xhktnmPT23cZc@9Onlk^u|!1HS0|Avshh~M z>n$G6(V`B+<~KvR-V)=9c%<$|1_w$XN z#LW4g#K|?#Jy!geF7^wYQ2abnKO${wcsLqa*yFe}@cM-GawxuuO}zmP!9Dr{CPA46 z!N#Xen~ivKP@aY~Hp4Pc^2MReG_fy*7RrpqLyeqmnqyycCVwSIKRsICofeF95sX(- zAdt8U3Bw9erYy%)=wtE=3fs(R(q>=a%52OmyNEa9q*5*{f-xyML8tGy~8k9!*ts(VKBP}Hnf=OOP;>lrT+e@s~9}kF4KLUS5wl6s1EVQ_h!-?k_ zSiyTHPo0E%_GLZED#~_VMf~M-<(QUMIW*4!f(M0={|Ykl8i=V;gjlS*pBNP~-^trz z&jLrO+GEUFAlnYdOi_Zq3D{$gvqI17jT)o8v^k&0XUnfQQ}A(E(+dG90! zN$Mu5BrQl(NZMi8bU?-}V&*vkPiz(Z$pViD9_eSh`y1UiQg^B7a1v#bx`_djdWnIO z79?G}m;JgD{9$Q18DEN-d|Gd>0RW z%e}xXq?2GvG7cne#(c%`#Vtr&9@s`2Vt9hR6=a4$vFfF1 z!eXB)iX&+319~N|Nk^_DVwJkMERA1lO3Ky`t+~UR%hZj-yF?GMI96U+nPISSy*M_F zVuKMrw-1K>Wg73yK3F?3G(^zdl0MaOqyo^bfg zW!O-6Q3d1pO;Xq*7*JH|E<%KL;!hI6VEvKBIEs=1;lU(9GD(H-L+(eob{;@~Y<~!1 zxa8l>>3A5qLcbfn!Kc1|AmtgvR-}!)IE6Kl1V!;?*dt8L)f=8b5UuOGk8s*a#bXqc zo&roe?G)G|Q1T9x*eyk7cL@%C%6p79Q4{re&KK#mbCOrjMlS`#9SqgeSLz0DI z_#7!76`08BQsN6kU?NvbJjmh8Dol8Y6TutaW3Pv?woo(r0#6jYoN{=o16wE>!?(!3 zMml;EL}Nk!8|39|Jf)}pC8zyc%C~<97{v}<+WtL|yhtok=>Nc6W-QbHk(rEGhTnrs z<9MeCE+LJNX7ETT+4>B}FJ9{>Fef;sv^iBXozzn> zhA!Sgd6OUY?T?*X9Gu^w3a6b6d~vITX_{}c95m54^8(QT{hcSC za?pwS0fSzI1i$m)CeJTjb35u~;9CbF9DO3HMeH@F+?k9TkI{o4px?wQu_l_~2iTnw zDtgIbAKx=zf0}nKvelnoO2vxJsMzIVOg{SxUBh!U^wn!%!89zt?5oKkxes;PvG&>y zL+{uQqqlJ;%aoQ5+f6!*D){}}H<+4x;eh;#M}7B+PCKdiGH(adwBBMNL z&GmsQ={#GRn)_2Y&pxiZNO`9<*=c9q0>%k9-9WwW_T~z%<%D;I{a`Rk!tHALx914}dY1^9xfxxiC`}>j~CFv>8jO$MvLwZ9dj%Cl!kc zle8wY2$V3IW`(%`rnMKo7hoGjt>}ve(%RTdHf=O>E~HLBE9G~zp-;Q`t>CHBF08z0 zSJB7=QeQvlz}oAX*Kk{%b|OnY1(2OKmO$*Z--jQ_tIjo@Ty2(i+7SlUL0 za8QLQiu~yF(2elu-O<}dIKB&1j9vk&x|aTY|3-^*$)e$UmM ze$U<)w>PUfTZG<6P(bfvKOwzeNv|K_us$*{08G-Ho~59NPG4(ml4aD39|B9PkqaRs zhgh6)>9k2`o{xEqDQL)IKUd;^vB>{rJXh%Cq~&rf)<+}h=3~N$`8dF`=5x;M%>Ia( zw45`Tr&#qoxmqyifYFdW0~AJ$ba^y{FY>lQE*iqOy@XMehy$-b!s+-3skt#bz$&Ap z>6ScB_($mSS+RaS1(?vK(SEox%SyX4lP$;Nkm>QT_xKYsGsdjuoZUCi))haHoogHp z(=5_Z5Y3L`EGiO(06nh_2U7T@AJdKNDUpH4GI~|L)6>5@=}o-zaoS0?hO!BA^^@6+ zAHZnFcX8;IJ%tqr%kgp0vn4NwQ%ZVUoFtl)wvzRdLuMr#j}hi)F8*ThqSNrVFYdJr9Wk~V5sBMz~O_%&mhpv z-`KbZx(}7P{5h0h4fzsDCMMuXA#<}9k}KQ?LUAycG{B@O3nChfnk2v)*?jr$2`Z0lX60GotF5Hl5(fk58Q>LHo|JB9UEHM zLY|!OaWTvAap(x^#X!y&d1By9v%!}8R@uOEnUiR1mN~YX%iQ-&&2=c2xj~%pcuxhD zk-=q-XGhq4h`gi>>uLY;RGH*lI_E7c}?$ZAOpMk4yI|dLE0Bi&IX#eli9$b>pL5S zlAH|@`nwpApPcidoNY-^H)mU{ z3VTUx@6d;MqQZBG9lsW1*qy-7E&|8d7L&Ai<M5!c2_Rb`L@Dst#>`gBP+lc%if# zJnXK695ty?s)`1AW@*m|ddYqV?Oj9azp{JZ!S7k;wUbAM0mwP~#Dml#<--=2fL z_B81~Y*N{Oyll%17LPoIol?Q5)`9uk8%u~R2?NO5%hBlxev09+YcDw_mh=nBtu?ON zLUNI7_IZYA_Ie?6SB&j2CI|+ncw`i}6LX+UHl+!Keo*&>h3aPf9fzStO$?KWWAxc5X8PIkH!*Ouvqm}g~U?Dobc6#+AjqyFH)G78I553zdyPK zWiJ7-I~S8PGn&~DLSV##5W!FAh+7lK0n?s>`s6_l%V8eiLM_rS17}FQVJi&Fw@tWDa5{L^ zW)8VfG7`2AOa6HDpOu#14&8#MNkm97L#mI4($2nm$)Vn}FNu*6b@}zlt_rC;?n}i; zv=)7nb`EwQ`sN7fn+mW@-|U9pm!!dR$;PV>F7`Yck+t3|6O?vBiE1Y1HWELdfEZoh zeZ137Dt@McNt#Qu2$aC#@YO-Olx=Pm==NH+yGYKIM7e0qNIP!nrP_tttOpTw+$p_n z?K)o-SwEg9oO3$P*Tr&=DiI1&5>xoyQl$!hhO|dEr2K+F+VB_{vL5&;P^I5bRzD(>VbCX zA!_PH#^ycLA7B3^WXZcCFBy`=#YL=Y(o9-)vE}`K~<5*vhP&%co9|O zW;I9DHxA*^ZnQF@4h0OVFY*W%45Q@7LkZ6rNT>lL>RHqqQ4gS0wz^*QA6QGu`_(M9 z9vZUM8O^inv(*a?v+Gfd=>IcHWvfxnY*=+f$+LAqbx|?p4|FF4g6gbV7xZh;KiMi* z+VX((%mp50&d(!#8Cp@V|Akg$t2Z3B?zp07>$24sXm7S!0?O{f4XT3&ll$*Vwy^+h z464i+?cZN|ELcNJ=84Sh$OqN;0?W~gpc*at-K8JqK<8=N^xGE$sNo@@e|Qdan?&+3XF?#N&TOLO+z|VD z_i}nyy^O_I;?XJt*oQ5|Dik6Zu%8CMS-)0Q;>>O}*7v{X zy@{q(suQH#V*@E!spcyU$*thc#cu_~g?CJhym9Id!S<;lwwGEb*jodL?W_JQHQd<9 za{J@gO*Lw`sEODC_-;ZMuuRlG7wi3Bq}+@7EO&&$sXywwtK!Z2dl4f)7RgGVl1D37 zv)q&+#Acv9lzdSnXX2mVVEf*b_8rTc3-sU*4R4|c=crbZ+)(>w{Z(jPtL}p2D6!>4 zHClMD3-3fVM$^u#gm;EILU^U9?-snXJ4bkr3vY!wLw7>U(_-1xYKhc$6M8g+t9FO$&sBG-XM~6SF3R1dUI3=lJ^45xQuhd!tB!)Z%~gN2*ddrCPvPH&`AeFX zN7ZYhB@0vSDfK7ZLbHNPi-{ZcO{9FwXxK?5|Q^w*FkO zt>}rTRDb=YV1tBLp}$VkQlr1swd#|GNOr9nS(Xj>V`CK18?-Xes%~$NW=GXKgY&a1 z)tY|M6#Ox(82R-=$;d5D(M`UrUoke!V{-{#%q|BU-LDGpnVe{LFqj!w891!7xUxL^ zu+CRJ!utTVdc+?Lc-Zg=;m~Hlo1-hyyk9#sZ$*ZvxQt9n-8xsA+UG4M#h_`sQfV+H0991D3}F&BDT2hRiiWXJ-*|1`A$ zz7d!J?gb5}1D+vpU927XcLdI>>O}rOk0rF{$Uuc{VW_s{+4o5YKN2ZpL)WC z$ZQ!t4D_?Yq`Z@V4)TA>zYy@^D%uk)V7&{5{uXe{pcQ~CE0?21=L{#kR=96AUX9VY zZQvTfGEgcNDV1tk?OoYZI{#V99vGC%R-Bc~@%n4l>45hLyghqmpi_jtmrA9DI|NXx4=dJ7jZcAIIGA4;o(!2*HNk%tFvoup+z%`M0`5^m{)RlcRchVf z>oTfjL^#UX7}-sElL4oP2``Fpq+X3)hmiC@2776bp(_K2bZ+TS_%)zbUq#;n-Ehwk z8Pm5AV-3hpBy9$UQ*X zc#*)Z{n#6(2WWq#dS4)WBi*V>H4l2U8XuBTmXRGXg5!9#jN=`Em1<}Od$L9(O)CcC z_Nh|6*4%61bCskR3nxP|4_18)$~>{B*OKHMiIn~q{q}SN;r#;%KW!pBElRkLz|F19 zw+w0$wT* zUu#7EUiaS_y?PFV&U8Hy84F4#z46krr(pA({)7h(cnWPy+Aveft_Q`~uxT*ISIVYj zjGcdjOmpmgD@mCX(8j)&P_lpdDbn`sEj0Rv4n6}lR>j_eo=E8uNS@+yzJKm=UQj1{ z>|FHKRy{Vm5MKx&>;&w!+1NupMrZ3F&cw@H&Y-`DwwWG1HsJhQ`sz23OtyE&vhV*) z*9=bDrz8HDx_Y_v0b|>+M#`+JK>Sy&fg4io^}OX6WneRjLzMlq_-#tKQ}V8#Mt~GY@Vnd&6!+*1y!9}{6HPz zg__m}o0-C%fMutru#LdZOJU@#Okt(aa#IQm0J~qX%hlD*n<4qAV9Ql>z)QfsNnx+$ z;8#d16+V}%7n&DfFFrAaEy6B+VG3)<>HJM8?0D>WUru2cV*mAh3cC#Z-?~9bo!8=5 ze`lt!oACU6vBAPG41P1GQr&5>YwETFTW7KIN@7o0?3D@Q^jU~gHhCvT|Nr2c8K zf%y|vllsJBnRV5=S$$=(vbs_{DgGqbuVWn|j1z7q`v;_ME}ge}>P^-Cb=>VH(}7)Mc`F8N(0i!0#Pqr0TN{XNG(2_S&>6XVs2_!Q zxw>J%*|`%`43Ftb6T2vPZ&gmrM!x;jV1tGIsuj8W;dx7V;m`6PaQ0WfvRMCN*XQo9 zcDL9SL)QS?+hFj|TY(*y!XC~&NG-RL`-H3Y6!klcWk-nJF4#sjA#Z)|6m`E~8=O{P zhp5Mlr1<=yGz6cG{bEC(%k9O=hQ18!sgz^@@2I?Cu<+-t8}wmno59p|wSUb$Ots)i zkbOOSz>M6(RUBAYb*aH+GjgY?+lAK^er{;Bo~|CU*bAi_fIVfgW1^dYy<)K@!Tw>f z>3(aqfO)_=5t<+{|k)}L~Z zQClo__=rGshMI~)7xH3dSyybwuuLb*;r#WX%Bfq+mQCi#<@=8a+|n zmcm9yPf{NU)}Kruqv+zQ7{xF06ka1A7O?_aoC~hwot6gv$M9C9y z0kK$JYOyttT&zB|*fW8nqo*l^1Ccx?a8mRPb&thHht7HvN6=zrT*4(53sugTdL-w++)z{S=c z->^xar%n;9OTE|f7$jRmHBRTr}gl=x@|Tf_15U+>%_P zwpy%3u;IH=^4#!kwa?{VqIR)Z?vR&(O*EKd1iM6CC74+^FH!t=Pyc4_(7(QDLJi#-zlI(n_j+50N*mdeuVrV-pyIyrz>?Xl3GMKu%pfq;9ddOlg52%j)PJK!YI= zQ=i}tb*+4rn>Bn=vTtmynlzF1tqj+-Opo2HrV7T0G6Pucp5&b?(d|yvWHH9GJJm>w zF`nJ2cC#2G-<@hNi!q+vsSdOlW8IzVFpGUy-WI!49V6J%aDGKK${lC1zxAh<1s3~U zuwM&iT6-tW!e?WE^RE}<+`LQuMkLQwoVRzYRf0XK56eF~dao&latmrZV)vzCOJnz| z&qZ>h-db^S?2joP<g&$Pady%kFpAc9Pdq~Z(7~{)2b(~-;)iwFo#~x9q zr?6XNk176cDa$<;cp&yC^->CZBKCx;*qgjAwO9W0u?>npj;ho$S;sc2WrAIi4}IN8s>O)Vo7LYewo53Gw^@B*v9C%t=oeM> zzHCvKT3p^Q??ts(u#M`ifkk;QsSb^<~ndEV>lev4g* zf9mW_^{ACRCQuyQqCOU^OC3-?Ja4NSx1XtRQ_Eg?@2G8pZB&m1jtXy6-wU=f{8{-S zdG9N1gz#AzekhNa`D_eu|MI@d5Z(rt`|Fl{cm-emE@}S@029h+yA66uFRjNFzy-to5Hwf_)MK)wQzQPu6{2V zy?lD!7iyj5aqaj@y(HLE`tHCJv2Rq>Br4jNaRAnw?^K;&rhVV>-%h}X(PnPmcWNKO zjGz6WjuFiG#EtqvKW1^N1bai z`e2W`)L`OgKdE~xMnC&WJ!modlA|BD7=6jpPYd>*dbyxHFQ7lQ*dqn2!x8aqjGYSj_AFPN<-TkNvHNRomZjH7K~Qkl2@hwY$Rod*XS25 z_EsI9KJ^xh6=LnE(H~mu62ZQ*SOK1-YP369>I-x2sL{ECog4mB#UJu&bg^KjeKoq; zN_Iyd%B$6x=2>fET<_6B{4#n|=+y;iU;byj}0Zqy%G9($ru z2M%VrCl%L~CY>)>m%2XiIDV+`1Hl*z9*7OqyBuO_cntGlxV}^{=&aOgq<+<6?7@-x zT`S4n9jU*uyoKejIHm>#kyfOMJdDJnx^s)L; zi*c8}tNw?@xJ%zv2M#kjFU1=UyXkzvE>~yi&+>NDaltr#S@{!mX9_FH-&^M$&T{95 zIbxG^sbEXP9I;8d%JQzqsy#{9TZ|(%Ne{Ca4;rLHaR^F`iA<9|+c^YDWar z6uoG==?Omd9IUrkjL$iT@L>v{F2x=^R99JyJ$R_zSFnxp{BW3_Vz4md?qPbW<EC~Zoy1nAFCf1>~eK;&6NCO z^+sTPdRbO8Eq}It!}7iYZ;pP)^4_SKl|NU1CA^hte%ZF1X+r#p{%Or1K%X=o1yhAPT zYT+Gac_#?(1j}1d&2n+eJF1%H+AZ(PD)P>@y!)!iyTtP5;GFL`eTC&U){(c`^6nc# z-Yu4Q+7R;Yx4audly);HhJ5Uk5sXonW!o3zp~4)1O+bBk;TY6ZJ_mD7jqyI&e?^0{x(1jNXsrpQ4`@ z>~bi3Hor}m&ZML{arw30S1|e+PPX+_!IlDhJO6b3gkbMwtj6h2yMD%E*AK7O?fPYl zadm3f-4-j#doRkmh@w!V-vOKPaOZAZ{Y-wznKFMNS5zf_TSd6pyTz#I! zxYs{VuN3S({o7`@-~zqIVqdmI3NF<5SnSG-Xu)sv6M`8#f2&^-Y@?#iOLe!!xOZEw zKQfrakmdRl%j4c{x&F~&j2f5g%wyRvCf2RcB^G0>yFw4P7-QW^Jwh;J=aqU7i+$Nr zQE-($$YQkfYCY4GlSp*EKG|RriLTcjf|)pRgFas{;{`Y9O9jI@1@4q@(AQh+54yHs zmA=hlU2bi`YW<)o7v>q@jrva(yJu*9!HxQ9i}AE@jef~u&BKNktkHirn0VbvnSrx*XHd9><@w&J8#mD3uf%RNpBQvDW2#?7u=*@ve@hDpn_X;{v4x) zI&ar&kL%TWyT0FI1`Gx?_s^ZqnG!venBu} z*(3T5!Hi{(=xu^6#XC^71$--1tD}b}p`%6)V18pW-~K$^?VESio1mCax{RTFYP8oY z-_*$bzJsZU+Fa3=EW173>!W$++lTg;wGVh^w!*!IQP|~sV z4w2tqJeyJU6T1LD|2(%V=R^4>h$~;w9!%b$^13+ZA~mStb(I+vY(sl z;w~vS*HfoOb8`b~AHbmcsWdk?1Zz!8DQ{XA0o_UEsoBtvl`$gZcu{_{wQc7X{!41V z2OgF5*w>;BI=_f(VIIW5#l5CdoohWTgpG}*D>tZIl>PPqt&iG_z zk>aRtq?D20xum0d%X-qo0qbLCUTlj-@RhtP&!-edo}uYO6-n4a(3pQbGa_Qz-@J%Rb8 zJmZyXo8)Vn5dlS3QkY$+Ppz%;F8uOgd*V z=UqU3R!5sJOKWvspCPwz45#JESl!$9^d3m}qE(`~HPG9`t1zRJQDwf^V|?sEnRh$F ze~E@ogL^e3DYPw_@8xp7J9rm~+#SdFBZ>dyx_DEGGRfJ*yjh(Y$z7Sn$+h({*#j8( zUf%Yx&a54#|NHuk=^tuNkF?2EhV=CKPr8RygY@_Eb}UPZsb$A8`XxHk$0dEuGWqm) zczYggFj45(5$p|9?~W8B`G3P5>q?h5+;mEM{;}pde1C70x)}fBLImF`$X4T24c@S* z(G&2uC;s-r-`@D!2Y>tFZ-4w9fWHIrcM$$2<1a(;2|EfHz_<69uLR_`8y=|3#drA# z#{(ANt$*gH2%HXBs^$S!s8fY|gpB zq3og#to%+-cfT5v>r8iRT8f-GiYKFURBr1qXAwcIrM`4mYr`=q@2`y}GPa!~kQ z=LHURUf{ela7|#d)UsJ>*(|lpLVLBEg+44*^cjtBpFB|aSb*>~!2eck2`p0caGJG9 z4K4p6@Tz#=7V*GE>InGZEX|w3U8K}Dk@;9^`B-ZCSZe7&&u`Kl${ji_E?- z0(en$PO!^8y|x4J^@0^aSQ1zhn5B7RM7TaURWzR@Hk>3iR_ZSX{yq4z&T0Ax8ZIC4 znP~eyc!9e|EF4-btyt~w^qB3!cORf(i~d6Giksdq)JWL;gHV33dD2%q^hVC6T(#O^ zsdeb#r$g(c_tv5JUJdP{mX3HMl!dwTX=s+_?d&u1Uc$>#>Ry4%-Tj7VggrfOcs1ZR z%^PrEMjzOQ8ZUNcY2J%1!+e|&o`pN{qr%^!)R*qn?lt*~!>irzDlQFIYMvGj(fh|% zBOhtGCA=>pz}?|n;XhxxQ}mS?4}?oJ&k$RkNXyINDNbO>-@?-!mfEZ?%IHR(v0}3t zUHe&hv-+uJ3+Rkptq#Yr74lBTsUnl5=^B$=a+b6q`0KjXfa6;_kg4gJFSzWQ3gY3f$M;rcGX3-s6h z0&0c65AZ7e0N{1{LD28e>j3Z3j{|NK$q)1fKkneQ<3b@SK0(idjHsD3hdw`cZ9|5j#K1HdkQ7VS-rxLCP zjHsKO9{_I!468exK(?dMXW*_AnI{0l>Pdl5iw&E_hL@z?S5b?DSaKia-xB$^1^!o{ zc3DdXAf8NJ_P`|fLBPrGm!RJ%+7`I>Ow68KMni#_T*L*NAh z?-lrfz~=?NCh(sEKNL71K>d}0Kz3Nw06J<&;6BvS2pCqo3U|D~DS@w{e>(Cpb+o`) z0_O=_EHD9xcO*s6InaQf6#4@KpAo2o)KDUDyubqh!|G6h(}i*d;9%^bGAah+Tb!ec zn^Y#es0r_;|4`7RN>!k+32!}D1Jv3)c&dw@DR~3R_%uT zk!mX7Y;`o?iRyH~HgyMJyE?k02`8p;z~87ffR~Ggv1(n(1a&QHpMV|R+J1-NJK~>| z;H^jGXA7lGC`*O1R47Z;8a0048lkKa${J8k7`Rp>Hwb-$&^Lho+ktNjE-GO37CvKdN}VW>2_3T39Q1AUgzXA8YkC|yEX3d-hzt3dgrWVKM% z2xYyo*+QQ!8fJq&qI?eWql%XbeW}ow3Vn^}TqBe< zpd3}cRwUnb=o_vpmbkRU0~}R6K`0Z1GEpeATp2acF@i#$jUU!u+i#w5yM()1;2M!x zBQj42WrJvY5|mF$-WH0Bf43QJ_oPOT{o^73Nl6vxgrrw__o=1jLxes-=o5rK0rXAf z`wD%w&}R#MHhx_m_DFt>=wBoGCq@4=-XPUe{w~UXQ0@k#_JGtP`6|gz4A7FJ6kBTg|bxgOC`Sy@RO3Y0@sV= zh9GrTgs8JB#2Uv*erAaJJ1rD@guY7P8iDHtZV1uBt&&$^u}xrwz$$^`1Wph*Q{ZfY zodTDJsbN)^HLeQNo;5<>An;v*ZU!}1W(-mz23ARag20KO^pwxU%hsccXA5PHP?k!5 zjllKbep2#;jgd`@X5%0J*xO^$?Htk(j{<}!1V&R3RGFrMuBq>ao6_i?8jP`Nq!abql(u` z{?>k+FV6^^lg&O^D^TZ9!?+yUGgIJdp*$h*$sFo@Tk<-Wl3p$;m69JXaF)P1xoq|N zTQdG_nYP^$L9 z*HUxEV6l8KXWx^98C5ELa<}4#aKIhHQsV@64%wiNEL#P5Rar&-2K5>sCCB04CjX>l zroc|2tP;3h;8uaEfsz#h#|d23zLQ{Z}ms#WL$I|Z&6sD=t%V5h+K0@W~~ z3+xoQei(aft3WkeV(IV=>ZSqXhO=GcgfbJ9_Xf-yPTM+#zE$#Sgjg$Z{b=U53RGj5 zuMpTd=3V5+jV0_9xL%;zMd$)M1jYboDqUL?i+`EOMCcn@7zyJU9-a~hG=FFKhXU@!= znRD*UT}g^WBbg;xD*0KmUvf%vNpeF{&cV;2wnKR@hHpf34lbn_~?RL8E6yV(4InjBM^M2=(&X=9bODjtKqz$ABX=~{~X`XbH zbb@rIbfI*$bc1xe^oI0}w4toCOedQq+b(-4letJ;WAP(bS6!uUS#De1p1Rd>Pjmml zeZRX4e1#r3uTY+=h?|d<;IFHUePtCussi!>_FQs=xDn4a#C^vAt_E(E$?+t;COmJo zxaPPg*Aj0siR1jSyKDg8TSM$G8{sBV0N0yS;M|OoOUIry8++10@C2H%D;L3dnHzCL^7XOh^cBrNYLa3Z05@xgWt-1W;I1dp5#n6)0C9ya3_-prr`oWkkW-mBLCvs}RbA z)**bZq*6zM2!8(qil=#PL>R=vzW!SgFJ$2cKcczZk8&H=2a&DpO}0Wv9K!Z3xVey@_Q(C z&Fc|Ddz_yb{{oIZ9ifc^zEIYl&+d%AeW``4H|K{?TLd|O;PVV|`%*$LQ;$n9j~wtc zqXOOoB*9#gBCLd)#}dpiH-uI2gHjUAvhoP4!M}~$%P1kiOsj~{4_Fe+xT*+iAV-2( z=ZCN+Qh1JyZwYL^+6e1l4$^PF)<+nCIViylZG=#PcLPZ<@0uVC!#tE=#s(v7ig%Vu zFmuBZwg3!gUJ*(#E1MzS8leRK^cIM>K`4Rk*b4Es2qo|ZMai1Z4i1+T`*(0o034HfoBK(7$;(Lrx0&nAd zNaiU*JROA%iRbkx`?u|qgU z-uH;N;eJ3onp=l>G~OK+j#0KA@fdC+;<4Oj#AETsv~Y~L?TEMIb|T)M+l_d8ZZF~; zxRZ!?;7%jnkvofcNA5i03EVZr6Sy0Qcj9g#-if<|cp`TX@kH)E;+?tQ5bw-ALOcL7 zr#VLMUG6VDbs5Ni!*AqI@d1)C5=V!@4!axs`0Gj&z^wKHvSEyJG>J0T%vve7$z3cVOWtmG$pe z_b{A?5MVsyMSoA+f5I6df>D~v5e$wW{83rUL9Hk5?s)bo{1MhP(B8_xsw7{n&v`Z^|T4UXh!lw;B(fG85j)}oaAB$DK9dt~4=$JTsI^fe0 zpLneF3HWrvClNZQGd^AD-D3C~%|*!RdkU9?a~T|Fj_|#UkC0F2ZUFuSv!Fn-gu{`BHipn&wCHRWUQ|Zi< z7#o^tstuqnL^|=+ku>xkjyq@R_trT^4$e_!np-=IL3|%9xPZCO17@YwT{+ zp}T-=twL;nvNj`It2a|^#FZ@>uQL(Uf-lqoK!(W}Q}c`}oQ*`c2M3kx zP5{h?fm*#F)s~^Dsel;SfE5$eS3z7#ZVn_JWNB`YwF;nHsz5Z_kPSSu);hg|q4;&C zXd1~`S`Co|0Haowl|t2ufHc;AF(FJ_CJY-HE(hgk;KdpZ*;cSJglnE-FzKiZs5Fu$ zK~`dlBok$h*Q!jIf9M~}Fbm;gbM@-}z*igeCX5}%S|~N0CYUH;A`;4VHK!}XgyGC+ zSf&pR*PsZ>jwo}^Av-vdCIr_!!N9Z>mz-}xuLQ;=a>+^DU>eb>shlV?G@-4^tm4#y z2rWqs!Lm(igE32&25M>xk!V9!mX-}ZQ(!wShLuju1_I;JLR9DouB1r0JQ`{OrcGP0 z;+ED~$k<67M6Ie@sLD>VTq?Dl`1EhbZ8W}2eVKJtNu2o|(6g$4G z`c+g&$WJwbLVJ8TOau%SeFjTFi4tip8rf!ToF3hw(7_Lq z+T@#=KIT#~jfT8`SAxgsIV4tJi=r#t>lw%HnOb89E`BV$5fd)J$SJN`p@p z%_Fmx%@k@OxGG|X+T_Pp0!<;nP_VtQMEvYhW%4yk+}!-;U;IQupSf}0o0o&LGx0MS*6P= z0ZJ=|A=I74h6ht#u{t72)DzPNU@FoYZZK&zsdy)~R+Sx{MF}odBZ9d^){|^*SoEX@ zK-&bgL5V1JjMf;X*RT#YwpW=_43M>`VTFp@Y0bj!qK!5kE2u3~7@_GlK&s9pvSlT} zmcFiflPX=CsJCGXY-)`*2+9h~*gzHrF=(UGG1`jf5XYr+67@n$isQzaY-vG--P+@XzPL9E7$;OUD zooh5=jkbmR!{=JlzL0X`U1VH*9`@`osHTY%xE@uFof;1Fcz|P=+ELn%t*6V zT-QtF37hJ&^RS%J_CV+c$Vh9-G-PR74oppLqf!rq{9<+5EUajqRk@~rf@M@?V|!%m zgs;*>;&o|8l`+5UOyNcM2`Zy0Q?p_TRwd;)HD%iI?lF%h6g5dYCI^`T^|VOov%*aYn+FYSLxE zWg<)v8!=`@U^_;>n_`H9Oo+8QD$-L@dLfq>gSN55W)?Pt75Ss5hfbf|Suy}SMF<5L!Ax)CAX<`vaZ8h=*04BL8eVF*l)KnA6{=KHDuqjJ1SUTdLZQ|_ki8t%c z&e{$;1PnJTaVQ2h)|rSfd4&YCP=#oe$poFAl@H&Sirf}aX8bl!S}qzA168kqWom;E zRb7_W$UGNlt6i2AsVmKQYl`cn%{3coVhT#Z6b~(sTMVPEHZ3Nbb&$H=j;@7??wQ5FY$+D2E1nfI z#H`huun5|SSmYOr{_BPnyv)ovJ?znJwic_h-ip;$Yf>9^%+F$@Ure?(uw`8_b<>%2 z=wduWuy%)qC2{Kzm8DaeY`IC=^kmq$=KLf)DzJmcW~nmll49Yu=#gx)?UJ=BqdK#* z%A9G3B#c|ut|V=iY6y$j*3R@^aKa=ImREM2;A#OR?0>SdE%b5VOu4gt3xIu(O>R|Gpa#jyn z3aoFiFj%M!_K^)hYEEbs8NBeB0!e_8;wlca+lSGPpA$z#NpN;?Ge;m-re(vjN*gnr zNP$&C%-AduE;U;ka}l0Te|Da^yrL|G*jQZ8b)Oqu`^{}QgrG2 z*1{6lqGz7A-pnn6EwJc5j2Wyo=9{rY%3wWNYI{=lrbQfIm>zm6DUugwOQ5I_DF@BB ztY`vhF2x{5NHXl#?Kq8SDvBxQP^7}*@TFZLA?NAL>P#j(PS{+FZe`{r;S!+9xH7aG zV>Mo@&pZHK~LY`=AoOVM@lWCdRWI>@ltraI3 zrbVK$v%zEoVaqK($E7YWX?9sl0u3C9dQa3WRKSpH{x@Z82Av&cZ3$a1NtI{KO;uYO zB2EHvw3?~;spMv7;(^4IwOS!gCIxhxiamf7axKn9mX$}3Us#OkG8SX%jK$Citj91e ztj~?fKMk6K0Vz6xgl#Vg#j-YHqF~~%4zhwUHprH-rWuMgC5#j6vjoCSfw3w)G!bIt z7`F`IxWqu}WU>QHftsu=E-pS^rym%YoSSAc>&(ntHU$pJ&SH%w9mXQUv|`CrQGEzP zv|_x~9m1vN5S0|n1o+e$HEdL@?$^|=dXh7(h;PRraob@~0n8o|pE8T5u(c5LsI4Rt zi~EIDA7^vNFoTmOp%o!Y^s>V!wlPePV!1B4+FUK%5614;7cvNnWs8F41S5#ik1}S! zw1+D>*PNK1M5b;k87i1EopQ4|deY6cp~XR^XXwdTkZIns?+hq(W=pdyp>yq?Sa8uO zR?O2ZAY+Kr16q4bW`#239wiQ13Dwpwc(EIvIF>gL#^VQdT0C2VU2)n|*dwccu`ymvw91jDG5U;cgTLfM6| z*TXa9VyrUBCE@uTI$B`0v=obFtKpN<>2n2K;n)DDVh?aFvkMzl@sY03eO4op(-^Q( zv(v3?;Mr8IFkP)rVW8rKCtbxL*vcDGpM5E{tp*x77-E~>q3;#A4Nu;mq_S3HZHU^c|JK2s;}lnu?onhk>On)tvTt0EoY;IP-SI4@HSqQ{7w zhr(lhvXWHTEs>oH9~+&JpJ8UBc`lV3o0BU_ye8==Rzy`1L0*_3( zY`0c?6p6WZqez6XQ6$DKqsWppzWb01lmvB>xE_dOPb|xt`qqgFp})PT=nKcD1u_<0 z*}|HLBsCqg+WHVlFr@4O?^Ecahd0F_a)$>LCWG;PEBsqZ5j$_mVuwOG;gl+ufG5y6 zt!i1b+v-#qdRQ|$H4fH;1a^4E9(-}RB>^RDL90qi#%2glTuc_q7Gsg^)eSjs%ch$f7b`6<2JFn< zR~B=|<|koCCxp(iU(B$BPq#Z;A@1tzF{~0QiOS?%yflF@UE0xsj$&j}b4#VMA!A4X z1jaPk}NTib^ zl8EWxHpecHow73mq@tjC%aBy4Je{@c?1o%mG`b-QkE`-c$WPFzjRun;-CP`OQGgbU z*2L5jv8zh_Dhv)rKj?y3(G}q6j)_^J$RemV%K%r7~k-6%>ZBClQ<= z!p4=@5o3Z=3fnQP4{SOmrl(WXAbf$8a7vpkg`6QL6|QbLqjhHN(h!iu#5InHGX4{d z7KkZTBlyI)6jXp|#qhEiEcsPTt<912PjW*yR zINC`er7`G?W)Aj{kc`vk{==cYm zFv4!m4rEb=)ksmL>YUg?K8nR;+3X z>Wfuk*P`THHMUl!beN_2&}^2CuBI5A7!#Mo5@&iWdosZuV8q2J@h(Q~kC%%e3{bKc zGz*a$K`0 zgc*Qj16PlGrHP1Bn9e0J8X176;!c|u|8Q;-rA$Z>J{J{@6xBlX=ys}5J_j))%F-QG z$|rmSQpv!}!9S|k%&2j}v0N6QCft9GwsM@s@)A+9Gbj+X?kJ&SWx%nr9Ux|Kr$xD3 zlsDsso)-KPT^zc=cQ#596|t7+;_Z*Y9emu$07X4;aD*G>gq9FJl7pq4RHx7euF1P; z2y(H*uU{O$7pNM+SsUELC9a5j73$%_6S*{Q08(ne+oCoTlaL7zoa2Jbuv#J{1Mt=&rPFB(z68CN{pQ|4X(LvTbB3FUThfV}xWc^md6cQolHE94J!{ zb_TWqvNfU{wp5^L;ou+83?+G{LyE!(ryjNR|2yVHLNdmPiE)~ZyX?dl%~hIXG@ng? zbw!8+T6TCPu{t83sBkXS8z$Tn=PJ{8J~+ZXBSuG&{xVi(wC6* z@Q?!Po$KK%1DL*jT{tHp0uamcLlIQuRX73EB_JvB@RYdAC0+%E;A|Z4>+2*1U!Ob4 zIfO1!zM@ybmwa{3(G>xhEtrpQ7dgkkK7feXa=a%2CA|x#P#FQuQ7Vy0oaGL@hpz`j zB#|*{n|LQ@l){&rT*4wgoJ{7)QBB);AELYoU#<{^2w_nYn-53g`K9;3B{Dy+ zf*UTLyoC4ktIo-sTp^_!0w3pq;U;zVm3U`*XUe=YAywYjQ{u?+ysslS&2FG$*M8h*Q_I z;YD)yE;vPU@yc?=ix<2L_IVc^^OZ>*1^G#-p{TzcSS?tEVTlGJN9rVjctQCkPhENmIrIo4`dT1|G*LxL7@CABlQD^U z6;Lk=9m2pgzkRFVJpibOO_@R$OeV%}VFf95GfgJ%f>*48hrF`b>^Ou1-UWvo<(zlE z6!_lx-uVo)kI@(-!{jXV@-DbZ3Zfi_*mx>d=;ccC69Fh&a1&w{PzaaMglVpVDMA_|sRA}?I(io@hCDI906~PtCrANm$zEM%_G+eg z3T03=B;djr3~rWkbVkC_*}GttgEQWUM6Hu277>TpY#T7j-kRhQ>AsH8v z&Z2e_CrHVlpJ@KcJfx(JFa(6q8R9C>)9my_ZWY_8W}}i?^CgoNQy4VcX!Ok|5KRS^ zS6=SOU@|{Ud~oF8%F6^Dcol?!g)hcZ1th={Q!0fOX!Nk5?dnxgp;C&X-iD%!g?thE$zY=Q+p>^*DJG9O6kp8sOI?N@{%-*6J$ma`ep0q0fH=&P*>iSwZWh9;?Lp%EFRzjRVS1a1PqaR zNS&dLX;7mIfvZ9}!xSai}U1FRRK6%@?EimH~;hz$(jJqQqTKxr4-$zF8lEbmg}w5LdZ_j{_-7 z9|OMpYbx7p6tBI6a6)P^zV{MlA)7;tJSG$45}FcgsW`hLWO7kk%>`qpik#Oij|ng}G=Y?P(E_3DYGX5CWi}AW}rU3Y)uQ z|4^)TB#G7@Y@1PNQ6%n6!H8PL5nFs-_T$h#-KvIM87Dh9%;)bzjW2a6n1{EWagGHX zepZ3woFxd5PD+ka(tD41{OdS&=Yb(9vqRRetJbUvcdgl*wQKH2a%RVhVT-OGIQLh+nzrOZ5vSCHDMILV!ZThBG)_@7&uJI=vo>yo;P`|NO&oSRdw5zUv zI_Tik1*+!UPk(Ap`yRe>;O1ksV&A+PQKPzk^})kB2OCu0ea`3l!l>Y;eop5$A8!0_YD4q!h>~z+wP1hyphRyrbja zfB*fV3<3M2)ZY%yeohi+{FgX5d+Q|59suCu)dR_VwkiA>wg%QErj{^a84MdmiL)_Gg zBJ2Yx`z8eoSml>^CrZpifkID;T?Bt-iY%vKF@nM_6x&I`Y6=b#@skvrLct6Q3MhEQ zGzsmkh+0(&8UtSFSXJ1mm9ZVP=9JnAGS$xZqa-Za9Jn-Qe z1}t*Uk6HH;585M2{0QRJgEGB(l;<3n2{1;SH0~U>Rudp7hzUkItowoqG8k{wvFc8+ zY@R3BnR5UOR?%u&^Fi4=lPG&w`>Qxw5P7cN=&@Puv0^}pcLdC=^`)I-~;nJy5oAP6S?)f5(X@v-zg z+jK#Z024EUY!^1PXx=d!0xK*z3&@z$@ ze|%xGIkT@-&K@>B1AUBH2SwmaN|x+LpdS*x_EogXq1eh`2emPcH5i&$22JeGN$~M- z^oJfs;MD_xcRoNeiew_*WHjZ3V(3Jc zTp*CcfMS@dDJ<;5;wxml__E0AwAD$GRO*gXpSa0vJzvBgdYX9P(dL8W3J3CBAs*w3 zFYU5B6P1F4wWa{MaD5Js8(Sz8K_LqI3yEM~kwQwL2vYCNexdG+hy*PFJKygoZ0aLsb!xK@nP&DkxH$mab7M)#+(zDot>jDqNvW*Q&zP zG^*gBpfGiqDnb(+u26-jHNlGD^l)WJNJLm#m^Muv6cid65vmFcjtB`?YQwbYpsQ9# z2B|{Al)-9+A}u0a6&9)q15m3~sMEBe>A_*a!3uSxN})^-QAPxZhDN3<)3oV9A!>C{ zq%vF`rioMrYlBsxXnk<7N~uwVY9etfI4CGBI6|GqaS1%<8`vo(#d>!(K)ff=VsJ=c zSRj5aF2$pQHB-FhNVncAP${`JN6xS-@|>G^B92aQIi?tKSCAtp-W-E>?ZxTS3`0a{ z6`u1cqmwxfzkcSV)i>^%j7Ot1WLWt)Q;JcSooz>z#tZE_@d{e5qV)`x92d`VjZ`@9 z&*A6G0=F-bmzf(V$Maq}yA*1Y<6H<`iqPO~qy;N^u3$+r4liVBGDWmIoEQoc$S@Qz}-$cjwxv5^vVHK({iq5G?k6)x913l zo!*{LCtq-&lk>u_AV&l$0)v7BLovjIIo51~C>n)^28U{cm8x)MP;f{vhE{s0CR`I9 z8K%}mgokKD!-BP;Dm7l{M?&_r%4z#|a_U|VKla3xOVZ}h4F$Z5v8yqwW~SMkV`|!@ zNd``GWgwe&VNjU4ZIKu6@u^#(KY#M|hdtpZG>ZQC5Obt>-EJ_sL2aj*wLZ&jr7YRRO6{neU9`Qt;yKcNes@@t?n` z@U1;(J2Yq+W_JC@Mi<`b`?hX>e_?ccJkPZ&t2w0$m+?~85^qy{>pZa$vx&C!%Rb*a z1WOmU9l^67KX_#(UbW3NdwY9gEUzRmHELe+#g-&asGUyuY0-a1;Gev%l5^wPJE38I zaU6bmeKa11SoW;yFYFp@qx0TrK5!r>o z7HQ$(s!(-km@+arM5~C1tX;Y?VfC`qi6dmhvo}8U*Ey;!{WsTNF}BW(>66cSd3`Z$ zL$`S;8#XNIH){C0)h7Mkzn^y4AGojEsU{QaT={Ot;k!-3d;IlhP`F?Cv;MV%`rdES za#>O6w%~&FSyPte?}4*qEyzy9cMiVWpso*sd^eerN6Es_W%Y^|dE05SQ9zCOPY;HjLE)zV`Pr~P-(UP)$HROv z2*dufvv4g@RAD(@^iL0$^+TbSmO^yG>EE9(`xGP^T1e30sSFT#`w_EKK(ALE{cWer zTrfjJ{*%LF4ND&buma+UD*IE_39hlAy2Ad2@E0TC}7 z2l7>gd$EJHa@=jl4GGvlgL3KJx`BLS98MPBtO}?~gZ;8mo<~cpNv<-Y0QT4>%d1!e z`2e=3kmq4nu4Xsdu^q?0I~T`}jam6HoEV?t{*e#BDpcPr$BA0#TBvQ{;r&1$oQD@y zfDIj}SYF!@$R|)UEhn0-+{?3b(J*ZDaXSNRj1g^A>4`~p+*WQjutr->N?VHs@*T@2 z2ew7Kfw97<31ZU@*0I+MmgXUlPaoih~xM5DB)<0fqeTm26HB>9X&yI7#k`^HYCA0y2--4hFXF&neh}g z(qU?0fZ|qAARj~|sp%L5j6LBkwsIA{?ATHR8)vo=Qp2u{Wdi8*G~(IS9Y~}2oiqz= zy8#?TWAm-mimfSLEyulq=6tweOLM%HV<3JiqMWN--drWVi%m`^-u3X3w5V0ahPaj- z{vftpvE*8I9i~8bwShce77$$uvKAOjFJEd=%M79|5+VqJpH5wHeo^W_+|G$E{)tmN4kH>wP+ym4a-BUXH& z;s54>V=W9sdIds@S^|r;(B!wMWiscc)soxG)mC*As$1yTCYGK>vUwA+%dsiIpX@^DR}5-n3tjzuX_~t}y4ka!Ab0Eqm^&`~O+zdSSV>nLl@S+CR5j zg-v^IERM_Y%g8$MVa%4iv(cMf>b^6uEw!`B%`l$lEbSXiF7oRY*L91mi&S7Q#t_vb1n_QgQ|4;otBmo$$ zXl)g^ev3DnIiGQEzBHWh+T+usHGX3bHkjqFtrI+{TsNGSPemBRB_S4v8y=mIjzbuW zIQ?yMeE5d!efk|O!;#ADo8YY|z@H;NG?(rF+9E-}Q>VhNHx}pm>81?X7j%P${_3z& zDafTeL?-0h-3nkBs~i`AFb|&Sc8aj|ElsI_;V95<;a>=Dlt2bt7QYl_g&PBwTSq3q z>1F_JqKO|ltXaBwp~0;Hy7gcL#8fO_ja=eRxUoa|X}H}$_d6(NySX68-2-Ze3Y4|% zb`RZB3dFAuy0VXj52BU@3UW@kU7WQQ73$p-03d?T&tO+>5d5*FLKs1ctHu$ zGy<&mLC~rSpk?XjwydpGmhNcTu&5vH@2}9PwMoP#B^aA%pN(EO(4$*v;(aUd7J+gK ze1f=OgrNwPNW(pdzs{Ita1x?D!i^s4-z>Y9{WBf{F}||!k0xdy=*5GF3`U7YMGo3Q zt;@jeG&69PKsNteUi3S$QH;9Wj*1CTBaGq zZ|8%?&Htf41)iBvRbl^!>ihrI{Ew1=3=Vt_&lMC!{;!-}8jfv0_IWv8Dw$X0{{W!7 z5}sFaS^(bHG<-DSDHx)(BYDJM_ z$9WEP^^i+5dQ0gO1(rWNrTBEG4@Fj?=PuWk+mHvu)l<(kE!}>fJPt`SAc`^(v zvXVPTN6CW}N~NND<#Iv6icqCe8L0>k4(f$uh$2)GAtn{-{}TSnDcl799O)UgqKN<6 zUM}b=ha!Fwx|aV$Qp6W>haZhw=|23G-?f45182QjS{QToR0~d9^UgQQiG?q>Z(sbX zcKqS|oL^f`_84<8FXfxIAKv~vZQs*)*HwkvugfmVM|0;#?|&{UY}Nm#I^4yno6-!^ zol-th|Jduw=3kC>yV+;Mkj=mSQMXg&N=|&VYr|d=UFQ#GOl|ynN7hVzlPL+!W(}I; zk-qeF|JPN%O7aQ3=iW-Ykar z5Q*QaTDnypX7`T=%L8jo%Y2>Oy26E7ewo)AEWZ|aDsa!QeHM2~y1RN^LHqD$L7ROW z)Vq1FuI5V8iad40)gkc{+)^t2FrZKG^51lbdA54w_hIoJhE;o7{=vfizqPq$YUe%P zJod^N<4DPn4sByyDoTc{ny(uA==i;5ieA69d3ZC`H!OAF2dcKe7C5&q-)-lKl#f3h zS?hR8(Tet!2M$|%Ja+Ry7mpUr_VxAYG^XjT4%3HKY0!Ayo%DeF-N&k0e0;k4>?h?H z|F$_NvC}WLzRtNgr+1U*_+eCz|E7pHp+^jg8t6K|x{g&8m8_E|UdB7iFtwa;5zay3 zM+hE{l^iQ1Eg7I{*FLsSbgk-n)$+LuyrN~CB8IZP99t@yFKCK^CXQvdw~ggWiV8GV zoP5fKgoOkJ1vd)Cze63^}GIYGYOtOc=}*%o9uznjxtaG**N+ zRzw6MU!k%zl;<70Dv}jlENO*gY|MKr&>CTNzq<;v!krlR;rYKECD^|gR~QaO5}xyD zAM1N^peAD27oOJ>&drM5TKQDU-K^)mx<0$ub>pJA?WvW=A39n7P`P7=>unyBd}l?k z-+Q=xtsg$rdoA+!>osAVzwmfcLv-Y~dOMVHgQ?u^Q1J6GnW1Ky#?(1(~Zu)ua z;i)%#9(Mm!K6GY$G(XPQv)rirVXAglq9;80VsN`rn`+fwICA+m-xm6BDlU30eKT_N z)0;cSf1%&>toP6wQxALW3Vr3*{aC=mz(y}F$*!C^|EQYw&anPxvf~GgUv;Pboo{Bo zDDYen_t5L7DJ|9aHuGw3MD@@Pe;;Xb=EuEC=XHxJO5;yE8E&te{>s$2(e_vCCi@(l zb@8J&N}mDJh28teU#V+0XxDnG+x-h|YbTy=ezckH_gYDDO3nNzj3?E2%Efs;f39D06}i%R>*X+xLb2V0*Wdr*Gd zy_L_@KggXQWeiHr{-L}+#915pI;=~?phwMr9>Tv|@abQR3kKeJDO>4WbCCDrq8a(kJq z^N}@ef9!j9XP`swvdqT^vL83?Gr!W4*!5Q;G|Tmx&>`Q>QF*ME_gJJlzD zVO)dTm9~Uc%J&`XwsJP(?8m{wWhglY8C%=2kZMs)SVUCA?(QT)l9WZ2I72*N(R%=a;`*J8ol@pV|(Oxv_1Bap)D}?K+pY#D2c(;dbBd7e-CE zpAe^5v~1$#`@O$f`RdZD^lRHbD;)OV^n;GK;~FgT@&9(wh>U_;pQH^*{l3ZQGu`L( z*^=k)|NDdN9sZL7CbbSv+;(+L+i^Qx;&+`~7~RA?6`sy6;!d(6?}*JFXSe8;xfoTo7N{U` zbgxbxja=AM(OeYU3i*|HBr;4hES z)Ude50_A@8Dgg?Wt-cw5j9obEN=kmUz!PW98MS7+&Gfpep89#4nIn$pyHDPxO$`ia z`C^ChSoWwln_Jy+-QR3WyCvT|)?H95=SL^8exOtmT zla8)>J@9%!ioAjedF6?C7S@hx)qT-CSA! z!O=^PJyw41|Jkerj}~r!$i|(nu_LI;wMV-eAMQQ(hqy@B-LBhrulVlf_vbED{J2X@ zkBFc_^{aij`bqs4zXUXu>t=o5b6lq0u;@qgj@C}j-|`LpTNbtQNl16wx+dZ2)kz=v z8Y+&6Sv2@&>xSBIcJxh38@t0#9roGS%jX}z_@mPNFX~@CwD7Z|zx7o|UGFWO^HEFZ zJm+K1t8;5q*sM~meROg62acOBNA2VS?=`w*iAhjf40!2V|&lf z3u+wY8thsQVs59-#beazN2`(_XB?OM=&;OqRawr$GJ9{6(;;;%!&u?6JC+B{>;Txip=6%tOkw=R-O`26B~=bgC|vev(bp%(X>^}A zy1i@Xw+R!^>^gV-V$Dgb4<<=Ixm&MX(~gl%>V>+^N!=6K-E=s5SK5mJW#1c9L$7kL zbg35#GA4yb^=UDvsOszOF|nE5zHI3D%h?f&$G@CkRC&6hsPbfM=Q=p>%A(2zfDN~f z5c0oN&IU*);T=l*UyAr7XE)0z^n?qhh>t?ww!o4aiPrKk~in;>hL2bbed*v}}k42J)gNT8mg4mHie$Im7KJB~%KlfvS43JO(5 zDuaST1g{fqK!oJ~T^$4y;@zgj4-=P73;#HD*H7JDj<|Qf-D$(Fh9=|e?1d{noqcJQ z)A*AuYjpMBeC5=g{sbdLMs`!y5#y*&8z zx?zsK@5E2qF0FYdSM$ZszH_hLe&FP{JdyvXTULh+QB$uz-gy7)2ldCq9xRx$Z^onN zHw>Fh&Tk^(&vbdkr>$xD`IC9uzCF2f{E!O=x}-lpY5sg@{D&c4jr+a)@|(?_x+gpd z86xZFKd67ZsfBHnBfgJpn(4mmX|#*$;FZt+_T zH%_cvTyIvxWkaU*8-MKbaKkCDtHS~=oLqX#DK;<7rG5VcD}Gv`U$S=J(N1+zecHOc zk?gwOlRN(`ULEdxW_~S|+0$u$ULUvk!FO^8&$t)=_^9WDgKNHeDg9%`#0tw7>?xo0 z#9$cNzQ^UIFSe}lku4dk+g>H*x4qXJnx;D*-!L}Zq&(L9&pj{tG)@0(_v)k7rgf-2 z?e@ddbsit}ow+dV^FfbKO*y^jTA?ZD&y+U@E~jaCREgU&c=^D@$lb3iH*YyyS#fR8 z`73o6(;^OfFviZ1IKD?d_NNNmi|6B?-}>OOtL}&E{nCor179tw*q7^<)_2sCo5!__ zK1dF&de^8(r7d+0#~zAqij;Xt^E!|1^tM&DgxgDa19sgYg>A+nfjNs1b5r53Y`~0y zEX$@EMnQi?KX}ze*B^|6&hM?uVi)|g+DbaZDpBL=l55Oe;cBVZLB<^9e&q=cGfG-e zLff%zd+W3wJ?6JE& zTckerS@wc!-|uzLE9Y8!-CF!CuJ8RLw|6Z5WkzFd)m013QGVl8#zhsLbe+_1?x8u8 z9){=F*dDNXkE3ziFR8bt`1Vy+QAhj`^lQh%O(rc!KlYP^yfX`o%XcyT8bG z`#!Dy`UlPpSDl;NZd$jD8-F;SIIt)8fazJykHR`ntW|f+_Mhv0;(E1Tv-pPl_cYk- zHMzsk&^~;JU&el~zw-3+hMv1x4S2ZaQ%*HmUuSW(9zGKstL^*LGxNFgDG$$ZhY8h| zaP8|Q8-lcRb<(1kg$-(*SfBjGCtW{Qf1GqOcI1vMlRHLUwxojjeQlABkXK3~^;)j)r4-R()| zzv^0amrrrbc~&$+QRDuts2TYSe`@=1S+`d0&kl0?#^sb```no0wg0}>_mlLt3;ud+ zc8zse{P*|=lZJizbnfrjt5?_bZ`ms9M9hf%1EY@(sdV_9SHfQZSARH6j7?m=t%W9Y z;mP6sha8TG?00ui+{Pb&S~Do>*3P@i@EpkxFJGR$*`Zx#JME5-Hekyx9fUQqr)`bo zD(<>HaIR!_+~>@DRc{zXI0(ax; zxAC`sFxGU-|N6k0I{BMCP8FSa{o5R=^!SpjPPu#chjxF)f0)(b%C${Dx2)Vh`0qZ6 zd(xlJNFLPd+Q<&Q-ux7nF($UQ``QUUNAiNUdRDp9f5d>KQEh+xc4F*6X@$qT20tC! z`Qo;=dk6LDq70ws8lj)?;7s|m^^%82sw6{qE`4p(t@K;A{8`xM(0ZElvzo21HY|8W zLGO{{J$=7Sdb93MTHT8S${*?b6Y;D(#8o3u1}ftePlqFId^k(<@Sd) z&Y7s(8|uI5`VSw~*>Ppxq>*b=CSCl~sq3ul%w}K2ZhElbyP*xjmmm0bRLt#I{r;d+ zTgNK;BnDhd`~J|+*Cu>?W9D+c!-ma+mQ?PY(f^khQ>Rq-Yw=os#55x6i`d*lJ5xh0 zd5=5&dZB#8$XDm)##~-!Y;s{lYQg#oOGk#?4~u`+NWa*-%bhJw4&NLzeVY(&p6(k` zRQ{3YA3wIM@?g=O&xf~)zp%33_Q$8rnp#A6+7=ucKT)!=O=h6yz0qA_uN~Voph_o^S&Kbvu~=xJZ1Xyvp;u!={8RF zILtY;%IJ0%E`D(A_4g-zcMW{jC#g$c?+bO;uk7qJG;5capYh>@mq|OvRGzlAdBqFW z!uQB3R%tb4ScN53o>{iAy7rs8UHps#E`HPqnCVgf z&Xv@bTuHV&v&@y`!&aUW%g+B6uimL=-40B;^L3xJ%wsL4Pwsu@@E28fD!K`)c%lN2 zujb+LmG#-uzx3+S<15${VU2OMm>ysCvMicdyy*dW2TK}@cguGz-eq|7iqkfiP@ink z{j%$bR}EKO4XBa9E9>;WI@j3o)e^(KJ{8ur?9@&(WVQ3O&sr#h*G8V%J}9i!c}>>v zqq&jU8_FwhY@hU3*0K51tJM1KZhA)301T345@H;%J)lpUyl36?7s2-l!D_eZgpsx-Yjv$*gu1+ zotyb&(z7Z2v%|a1ub;&m4W7$#6}v)K4L#fWjcboft()&j$^KGpZXd9^Q@h67DmV_> zqIp?ovnhN3M3+r#`0jBjnscTzA6D<(mY>+G>Xd=yzFOdaF{7$~o%InNztI0xGiBg_ z7_W9qe*f{iy?4g-OZ@Wq(fGk@yQjFU*70pe4xf)71bO4S;eJ$l3*GAj+oIw|j-0mn zz>8)#eyq6Vhr=xwD!Yu{xJ9z9=<8vX{VI-|kn`sD+N1u}#<@)jJHI~ug0q8zZGRKbn@Ib$a#S04}M*Pd#stClm5s2B8LRnKcUQ5_HzFJh35Cy zwOyfLq|Q!_JRBs|94c~2d$KPocSM~WtyuHN*(nvz-=7$_Y95@~g#`;n{x`4Fc8`+b z1CTgzcYe*Qq^MP;ywzb66dDv9(Mts2F}qR#D9nncHt&ohuMAK$RJe)+=;?`iQJCkz5?8-{$aEjH%NWLD)JXeK`$~#Es%ja9-{MdP=6bjFCwbB>64h#Lw zcjIrr&lvjb=Gw$w(=U{p{@u+bkthF}l~jAn+{22RDdGA3C-qJ5e|zwafbS;WYBn>l z=k?j&R*}mFJiWL!uI)-*jcGr>{148S_oQJAWSA;r{im zb#odWTzYcPU)>X*E5Dt3@#VMEJ8W6!-fGtCx&wMl{$xmPlfCP?i0`1NW_1w4_gt=+3$T=X zd1AR0bE;fA`PC7}UE>yw4es{ADNS&WgWLM?u?IZ9eRv{CQTV4F0Z9{O;XOs+ZAIY? zMd2n#`PB3$_jX?SEwM+r4w>E7tlOe*^~0foxUHGcDHW+ps&YodAx0> ze{zpb%c=$bKJR>Br+uHa&ApvitIliRISqp*7A$WO`ZW0E7UkWO&(05AIq7WG)NuoM zmfP{s(Q(Sy_^q+2O$Lp=()X*HH^(3S+ebAh_tT3V4NK4c-7F!qP8a_1xwv!fWY>rF zdOWRNSV)Kb6}6n5J{o^ z+ac%5>dwo*>$}bT!%xjl8;aI-Rk=KD_3LM;%U2GryEu99Xup1KBP*P2W^Ddvy_tV> z^vGQKliReA7U6s6e|^99)SsjsR~$d^^_Z*~%P#I~Izm76Y0`*GE2~GI*lnyhc3QPy zk1<-=)V^I}vW5&A*S%Y>BMTy))IK<2jjUc9L&pKfJ5I~>bBvw)GWNxK|5sCLTr+K2 zJG0%a#dSaZ{?lpG@~$Sexie>r^B)Igr@vfKHRR0Ns6l^*uIJsq+TOfP)`HX%sq0_H zyx4ST;-ASCd=hgy1$_HtS(fhr;I7UNvj-`e8*5V?t_t*!tCPJsZqERJiPu hpJ%70Mttr)v+}wwgD3iBpL=uPqI|bUQEUdj#r|a z{=%oSfJposyi7&CcD{;0>0k3HgA|3o1>n7bUVwL}K`-)8SCyZ65#D#IN(K*qP*qlk zX&3S=M5Hscjqr?_efa|j|H!|ij!5IWa@CqZh+e3iSUzzWQA`_XR7?cEhdi;r zok*^nIC}3A0Et$jSs`3%5+UF&r{wtGTZpgtBidBOP@XIGD9`IO^n)NnE%jUPqNk&pz6EXo?jezReOcd-3yh^pkXs=45B2~66r}<9(DnVw z*&L)vT`B@%IiNyD{a#8MT`o}wko^?g?caios(%B1m&*dqrG$!qYb+`&vQ`AZkO)mk zM0pCf6bXr@B1b6c#0k{uKL2*$^A10D4Js*$n-Vanw)xQICxG-mzfNV!_%))GX#wR? zsN&ZMpemx)il_szsEb6@ow2C(9CZRI_bp4R&}zVSVkQ;^PEynr6tz*H2iK@XCJCTa z9WaQZ?jZD%SzrP&brS&;)!dv9j+?pSZuRUC_&ugYF&k7(_rZwZA!_Rz(bfxw0N#lH6O&954}zW zzKp=9sY_b{zRAi9pqzL>22ci?PR%tYTGFzUngW)Sy>!(@uW(4aW^uvM%!2ad+qN}s zKRzel?mS+6Lr#782;|)dX{P${UCq~{;cM|d>cbS!{B3|KjR~l{2=$8WBD4YQBmO`d z$j-UyHIAv((yBFQnVStuJ8Km40AU!kKeQMy_k%ak68};nK>V8iWl=!DYsxJl&XYt- z0iiPo%33by$wP^V?08gKRT(UQ=oCRCL=gEy=E5m@L73{CKV&VOqL+}SgTP9Evc8Ps z{FN5`(71?BOc5N?xJXVXHh~A4@?Jbm;(@;xFHSBU=vKa#wzP@#pkfiMv#0#`mR6mQ zg5J#Zbp%yUTe+!zMCa=Q&f8M?8$=B@qt@@q*PhuIOsNkKqmJvZ&e!G!l^jERQ~UDi zAm0hiB+!)m)Z8h`ga?d(9+sZlCv4pg&<&dgy7v&>rvDCAG1I31PCPPJ;T+Pcy&9BO z{N0u-TIF85>_jn;#oHhW*-2e_6SNA(&K*?F4v{3N{?)*lR!>s-8Ea3u&(2+z2T(3E zJ3z4BnyIz9B9v%5;H*8R0Z_LdT-)PK)_rJ-Y3J)1J2#m^THW^kVrtH0))$_5;)#*X zzZVNsx0*t7kn+Ul_r(I$f+@s|Q{Eg4R8gciGj&E5IWzr8z87pnT(x8k*Y^zHQNGw) zmDK}>TGG|?^{kE@lU3c-%ijP=^i*@bsnYI2CC~HF zzYSEeT-*5?YC5IninjN)$&1js52MyPRRAf!21IQ2%H0{|(t+GC==O(^H zPz*qlO**M7kU_=aI_EU9M$TZ*pz2-e-wfGytm3G;s4dO|m|&r`!p3@qBgZxR@vj6U zR1S)Fyw=oM8igGbEapF$FvrXva&-Obe0|O=ZcuX*ntHUTl5QBv@1jxCtY>5&$S69Q zTsEcp=!VTKB&j!WQu%tXn?g-fgQ}bIp_&fFt@8C$Ox=npbU{0jk~LDUQSY@~!@mM3 z7M)aXYHv&8=~WO5*T~m@+}n8?mYm<;RQGlqIC4Den8#g*D+#8g{9V8q;;O+8lg_$& zs$S2UVC-(9(sHfBLXV{{RVWX@}qiWcy9ojD@;P>ux46+|1E@t(F!{vnd*VlIr!>z`ty->Glrx_*a1s zj%$q`mWUu?IuxP)W7$55s1Jzx1fm=#Mu>(OQNQW-hltE$1?pT6lqSr=IjCi$W*+m> zhw}#-wd{a9U~XLH4&;x-*g3$KXuz=wX914xB{w-?c~4bcb8StE;btS>aDvMbJ89(b zHfvf(y>u;KqgHo!1D%D(hbkAv!}s=k-61ULMg;N6{pIUQt5-K@?3)@`fJ2m7$-B zqKUD^>(z(hlQ!>iS9P%8-OU9tjn76W1tOV5_cJ`FF|~r z4W_qFyogNcTqYQSHDRN%2UgrQQzD&hu~(h`YLvq~u>^-yD8*y9fmG@(ouwBu+7qv$ zw1?RQL%AL5^};mo4p}x20GK{8_JdFAYGoVV=^(sQ^nquG;M=wYCJi;5-dh zj``OT&g<|~GJI6a#3<)_gwUbiKo9K=$4>FV2lcW_u#2G=JE@0kmK&ji{bOu}y zkP_Q`$WB>589lBp-$YDZM286hcksAbJm&CNhHyK@O^Afg7u*jS9^I5d{0yRbCW;4pX7`iAIjmBE>%xbvp)z$ z?^*AZhg2Ve=%fdG&gP&jV?w}8^&|^LtjHx~aEd2>0YchDzEnqKoD?C|^90KDOoE;P z&?8_R*e4=Cty!DQypQ^#AQnO{POF((eHrvR>}$Z;?VNYU)GaM)+ynyMEFjmJ0}BET z)9_n}!5A1cP@QrUfhh9=^-sOcj>Nrx7vviT9gS4}q-^&N7eCY$D{i%Ib1uRn_5Ad_8)j)WE55M_`2>LuQ zheH@m`FG%fh(tVD6XQvo7fUb%D{)~q&IPA*i8?^tmgC<` z;M)4kgA`Tjx8FrijBowpl#nZaNK{l~DXoIdR2_|ftNo(Z8fzJJnCFc&Wi!e}FNd}v z)xgj|GD}Vm5dsk5FXAZ>gdu+kQN?xY*dev19V~9e+`)Z_(fJp>pnpGQ(U|a4CkS?H z7$<`06e-$YrnG6508Of)34K(RK+=_Sf>r%UcmPm){Ri<|>NE53VPVH!iqP~|DfMN9 zBeDThADNu5x95jwX#Mk?k98mc$r_4k@Drss|FDL-f@S-LS0}%~cHCg^&CCe|# zJhAfQdBd{5(ONdRg|fjAE?ZNe+H8-Ya<8CDTY^DF@S}u*`fx-~e~%@YQ(;HTLI&o` zSAry+PbTSvfo;XlypPd+q2+{idOBVw;@^fQ|8fz%+=e7)iB^1$CT6H_ejW1A-_vji zWS??PvQH`SJY_&`MS#lEV-Ki)2wd_9N!w#tTe_n#D{xa*dh89eu4O|(b6$ZK#`Ph< zbmD2w>WvCo^2&GNd+qvRt& z%3_kb`Mmi^oihtXo2*FD!$f`9a!q-}B*%Y+JPyapisW%LCL1r5Ji5)2q}V6a0pW3#-j@+kR8kR9bQ&c~R)LHcoF{zgPY ztfM-gzrpopKk@nd8&P?Q>Vz7?dVPL>gOPBrm0+Cg#~6w9HwZFOQrHPc{zlAC6aMT< zd=ol58SiJ#%Qu;)yPp=d+l7=*m80?_K3+iioCoDo9s!y-i1ZpJ-I2{IzZ z0a{a_g;vX+{vGT`Sw00+SiaKq<mN8>0$^2n@>p~`{Jufmj#}7;<=SKU` zm>uI!1%}>LmtO@6G1;T}uO?Ers*s-7;LTrymZC+BA3;F#$0>xF9S-TfM?o6LzX5n) z!$}Wb3&3&;+3BT3GfXk%@e9b|_-pYyTCJG=V}L;(HaqJOIlnnCBjo^@Bafcdu$9B~ zA8$f8d`fA|Zyu4+0zQluImEd7E8S=_^xWJEg_F}%bF5xM_Zh?#ctTm+Uh+v;KpHQQ=E1qllCG~xvl zUg5YA4M}^-T>UY;jg`$YnjkeH4!Vz~rCnv183i!O%*Gx7pO z@81HIu;Jmnt1QCbiF60sY5V|KdsEM4G=9q(uJK$}x3NyIXRY8)*W8Q6X=`sb<=Sql zI_R3i*gN4`__b)ZHrS3m8wcy&$PBh{U=1F?sW6NvYWoXI~)C2b4l^iHb!I_YaFKaWorXMRG32rkxrMTu=s+y44v}x%}KMAT> z#_mX#SCQpmPE}wRg-l|uITy;`%aQkj3wnYILK!5_u$8oj5qm7r2c8`w9ioxt1j^)P zH&raVy-m=jE4w53tX7h4MKdEdQNk`c(K=)kk2XB-za2>e03HWpBpP((x(H`ZD{FdJ zv@>Zv%)UYidWf3q2ivX`n)O59N%h0dQKEDCr>I&?!%PI1te42pS}z$!H3SC1%k2@4 zwt6JcbgBnDIz~nP3Sq9o9SQHC2kl6BCtiwYwQ|d@00yVc1??;Sj6oL| z43VGK<~u~g3;bV%o?Je34W#NIi5~Ebo#mgUwCtoyn``mRj+4zodL114G$`y1);`nk45Hk7zMpF33kq`f)VP6?sMmJfugzizliGd{h|Lebtkcsbx)` z(!w=)Dwo&f{h!0z$_w*^N-(wK!u-!883tRFEvn-G0wEPd(84?u19t!m^F&0vzRT|+ zP+IJuHo{6W=>g+%VH`tM^V5g)gJ*YJ<|Tm|VP zovWZHdBFD)6dkx2q=Z!#FUMz8JGNNQYw}b{jaf@;@c5cz9jDI1O?mg4ERc&8@HoYO^VbE1{$gbCaQI(WcOvLzMx5x zzl!%#e{=th--kW}Td_hcy1=qZkfkkuIHGG_4NDMdxHRMO|^f!V8K7J9PK?vgEkK#uF`J0-Fz)5m>g~TmTm#Px$st#DY;49{y z<3efVK_dsJZ1@Axx6>7nL;D|KGl_H>XP_H((k2ZWOluR5;(rq{8KnFcp1mo{Ht9%6 zkT3q2$fR-BDzlRTZ_PYE}07Gems4VUJ4jePI zy#u0Du^+0cTJYAmysdzuk%yfV0L#A(9K{oBdOGYaqq@d>GUBzSKspo*yux;jd@OE2 zjRgq}MR~P4wiHw2nbtBHezMn^GK2gvIUqMjLU%#M7<7q2v^RL9fM>Ej%I4|cA@l;z z<5{Q>8Kh%~<4!>Ap&`1d+#f(TU>t}DG7_vJc%m0&V?oc*SbS2x!zlc3O73D54pLgv zCO`|=Cgek#KrhRmVjz<38tCpNe)C>aN-UBIp;}(pUQ^f-qB684zen%Fmi#^yLT$2$ zGB75Ee;@N}(aln6c9CXlskoHf+N!RwwN+EG?Nk~HE+mwQHyk5zU~>j>Sm5fhJUkrL zuhot{@49xed7W!7Z65RBLTnymS#^rpCv6_*C7UNo5NY};j%K?Qvv~v(**ro*Hjf}X z+dP7hHjjW-w0VS@Y#w8U&1=I7&FF+LvU%JNu)7L|?a&Xx=a}W5qPa+0t1*q}e;QF~ z4xC+mC+2eU^#i4=WQloEV(*~Fwi_D_{mr~a*RfDKDHM?3V)?TKC3>4OpZo~s1@`?7 zE--7TY)$FpM?i-daJpeDV;0ej3C@h=Z=qPwPqMt+qtMtWUJoWbU%eJam-6g^Sz=zn z1`@B}kTT_#=|72J7jAJ@7HXV*9mlZamtMbjVB)|FK%OxQ)WJ|ICRCG4oc=5B zI}d|7iN2HU?u(l3p|N-+yH4sdyL6o-iy{kmodhZS*s$w7BpOpRr4Zg&Um?ypR8W4? zpK0Asyhe%{^^IxkIqZg%Xhh$LW2^1^u8FP{`$hr?4WXbdw1mt6?i)!6BV*XoH&TA? z8<_+3E~prT9-33OIX?I;`bNsx>>DYR>>CeJ@v#3Y_vxZRhqDbW6#MfzZR(+Ib|HOI-+@zC$)aaa*SVOrS^}?Knn{zar1q!N` zS<4^E^s5+QtOg7(mz~XFmTGM2GsuaPX{ueskt!TPtT};>^)bw!O?}$D3(O&2*MV;m z_zW6S=zAPJPv^CQG!9#3a=lurPN&*jJvTL@@=2}$v$MRVlB9j8;^FXCtyjfiFV1G! z{!ZjBsi`8OdV`M-p%^X)^DYYhi*knOTxmgt@uRZ#XpAspn;UK0u?KogOyJO&Q)Bwe zkv&7d+>(DZmY?=vA^((W^BG6v{3_3R>dG&wIOm0OH7Do)AsCX@`H}HIi@=sY2UgvG z8n46iJ3fzq%4c+raTKh3FTbSfVOZpyeGee*asPA3moc%`dKcAV+n>VZB9!O3I~n&` z5jPx<`?QD~iO2n}h#QT^{icW;i^u)Ch+7?x`(+WgCLZ@*#Ni+~%_634-UL7X?5@4A zgd#Bd?B<8;(bfu#3Pgzt^oh7c1#A(QsDMfZ3i8vzxSems4U>g~!Eu6e&(3^Nw8GC& z8WVX;-~MIZnDulXJt8Yfw=a&^geI;s`W$-y9N_-H|gHsYfX`XjuS z`YdiZQED(Cu_6^UHETt|3lTf>zL0{6Rn6i_VluNIJA3ZjP*J8A!vzIi}%oKihacEv$UTV1v;s z?8_Bs86%YDO$f9|Gb{(y5&9vkCCp9ltOMATkl|i*u)E02XLab?wl_gqEj)h&PZcdn zhBlu5a+!V~r^f|T ziS%)qp5yema*FhfOvg<=)YDP*GO4g1`5Uyd2#h{^C8pz)lu(lv9^DJ>5s!`#$2;%{ z^M{;%EvL8h2)pq)9fKX@Z|4zKMnoO)L}$h{2Jkyr@LOnkjx-0fkS&v>$ofFlo)Tj6 zQA!gXkFgyNnqtUMC>B!LdSy3cVrvVTT`Rav3I{71ov6l1bLx`tV(|+dPY<#w(LrG) z8K>e!2PG9w&^{o`L#pVY1d~PV%-ciSCRQ~GqYkQf_7JO`OfQD47M+Qm=%7M2%CtlW zWhXkQP-rA%qJsi&sE_(S^bT`^@U8T;krA5L+b8;ytS*@P8Z-`~NWajPyn>oC>0;qJ z1XeyXpOA1LX1IiYGTi$m+`A>*PcvLXPZ{nl z67Dex_rnaA&{u|gNWz_va1Dk_=qfBW}y+NUbSzoh3~Mwco*03Po6ZsQYgV$@~H(3U%+(w_|Dtaw@~2C`yILwH{K_ zrN-Na2&aOhQY?k$J1*{25Ss6}c2n~aooa@%X<-L4gBdq1?Ldl^K-OS>rPfOT>RKgad63%L>lPx$61q}OO z(fKC(;5}%Xs1Ig~-eLv}kqVa*Bgz%};c(og+6n3BUilwc`t@ypjc2D`@3&?8M>sv9 zjhz3@GX3?Op3rJeKPuDj;Piylayt37)XPk8dP4d+Jtfn7I6YylIGsk2l>b>glm5m> zWD1S-MB74*yY|E3(5_Rj`DTgf^;||fjYnlV?j-BjYhzMV)REKUJ`WD8P)c=THjTHi zA4YG)?qsq)e*<-+n*MpDgw1{!6N`}>dLhU~aAoRZG4XbMT#vzMQY2H3f0H(7S?>`nje9W(XILwdYlmK}0y$4r*G*)g9+ zsI6m`$)u8IQYG7Z=g3PAjl-^HU;VJ`s~?bk^}XCzxA$?oCER5aZWF^Lw3Pd}0SRYI zIJ)mhm7PP}N1(o(`Y!6rsW*6%v@SGyG5UU1!u^zlqdvKlkFY4=$ag1v?7N2sHimCj z!jTV7aO{I8yq7)+VM>Uz;Qod6&XK3xp&nlb7OL;(@uYH}!n0F7-YwyNTEhJ}!zHW{ z^Z7mrcaMalJ~`=y?UoQU97c)NEwdZ(*6f`_8<5O3Aal_)649w}9`2%=y)zjIp=8kt>BB$5Vi!%5mR>3b`CN-D~VlvX>8=5}Lf6WWk>b3+9}%V9p78vGgVI?vXh6 zREM#a+m7Xn`EbvIN^{c+c4UbA2XU6ALDw?j9zfgwGhj?x95=4^Old@ z2AEGlKC;;~d$gJI>!Lj}2y4c)W&}MN&t-)3*MfE2I${#LG%xx`(K?&1jdx*aofua! zui4T%KS?|lVocSOQ^lf9PKrWJfPD-8}3EI*1KBUFr1wdl@iPx-v8{CA4h>=Q1UjsiB$iqDB#&E zU&|5n&O%Sq8dsBqUqe6F;zw_d@c#n90d(AfXmZAZa#XQ8xJS zet}0&mW*Ug-uOOInbE1cC5&_|N!d5woG9a0RBO@v!3fue{TEEkj3Gf^He_WN9FEh6O?C^X|%mJ2;=**Ad`RRH4n14Nrgj+Mb zAJY`XTUW316LAA-FsqN&2UL5nwhd-Tv4?ATW2bbO5F)@cMI$os3j{Mtfs8&n@yUR$ zaum5C_>?=N=O+J77}C>rYU4vGyFQGyeJVF!zpHWJ*nm1{X#QUz9PDv1w{rui^KZlt z=0?6wmA3|Qg^-Uf(JAFbyNco%2MP-YY?E*v1Jp$<>nQTqP*$HP3nk1hpywGX5;@U- zkw@%DqB+uS5$~9D8B_9ZU&Ol?$9dP}6xAN;7INfUTyM!9m}1GoPthB=M>B?TP7Na~ zqW>pFhn(8-MgmS<@gw|b=NCrg%&%J_cGR)_L7NXQjCu8ps1q^Ib&XWWz4amYe$Gy9 z>a#^WxOc7Ko(LCZd>%_kB4#*x8-Ycqwd7`ha1$Exy#2u_`h$z({Xv_Z(s8{r+6Z=P zDzsCyr$E@ku#EHALMmlLXbZ)i$Yke6oWN1NftaEDRFR;2n!ep}awDG{quFtF`w#JX~?D)y#HKVE^D zMg0a%7h!Xin@i8W2RwyqLUJl(y}!pin`_D&u9H^!)kM@A5rtL%TK7y#?U`=pOxOw4 zwWQ11GXTS>TU9J&!RCUcnf9!o=!`U@H+Ik%Ei+c zWO`h+BBNTE>!XKe@0EH{J3WjPsijTr#IUnp888jg;Vz(;ne*Ug=kPp z2)hyV8i}wALFKzvpr(8kC3YmGv@Y1du31-zGLA(}etD><7g5=wj&27u7IkzxV15w| zR74|UqKka3KZp6c401F}4uk>cUQ>;D3u9k%qFedpcB9B^=|;TSTQj}9Jrgb6sYYBD zS~Klv&s5?}aRF(~L^JqFZQc59R7^GEjntayGbB05j_0GCDc*9enP`Q*CDWsvDK1~F znfAA5dNF5ewsdP2j1ODO$s)=a-+nzgTBAG8LCg%uA{uU`N@C)o70(|bN;Ouhag$5iZ9>jr#v61cQ6n8j9Ss!aDhxn!QQY2+rK94Z<`kX1x| zieN+$=K_k5uObAq2#JQcv%G&B&I-%>wUCrPGHSZom#}HA4e*I}_vU>RmF&LXhA1Ff zNefQ2BRbHI=vskjCC#|F9g*9P=qxEqAGE$JBe(u>ySC8xL|Ur$O9IhK!bRKel8v(U z!FEK41frD$j`q*BAbL?dqE!OX3PQM*J*=colZVw(wNH`qVOh1Ccy4`XyY{`Y9nHgt zf-G(SMfSEvchH(WI4@*tCBD%%nwIKb+K#@6C{Vc)-)Osc3!;A{-AxMVmq~Z~5^6bJ_s=rmZ~~U5^cGLL^qs9AqXuVXq`{nvYNqTlRnx?(`H-#o+Krlh!NOV zm=D_WTMQnXKhsv4Oxr?|uZB}O0{aT{YFo&mQ_a|{nidbVRh3pe)o?OMU|(UjZ3{_! zY_{!;aLi~V&~OX#+hpnODJW1Q7>zTYrw2((!<*T4?n9XNJr)rS^mu(cO2$Ag|B?DN&J z+wU8|<=+Afu8|1Y{@)`7-+r(cabXpG17h>XiXr7~wDz}UD#ffhWY zahNdB0y7qe2?H%KtK%?Xpao`493~7jVW_U-^R;Z+&EW87#?2UX`1A8nQ+oa0f$g+t z_y3-4L?#$TWa1!cCU{YIlDPE<5JyX?KGUD)F_gG}WG8e*N>eqj@jZX@j>;3>=5saP z9#GW6iw<$(oMy?bFk$rcKOk5f!}QYY!4>E-_AQ|Qc9y=0A8{Qc2fu|NUkT^`6W$zi zmH2*>W)5Jt7(;wJnE``dXX#(?gY$jX(s%HZv6uc8kFsko{TrS>=5EcBp6~ri&RX&) z;fr5!tdeOhjU({oTrpKtdIr!^%1uh?6n}<@{b*W;x}58L2)jW>tN0wG=Knh(d=fuJ z&HpYQjybe=;CNciSsZIxi&%_Dtp}7~97!8>lN2{f7fB2SEuZ-_VT&~7E|hge$Fi^r z+@UOrWh~ZWCMd=WvYY0iHwCH)(zX_BnW)guahqxiSjBz)>Hna51RiWN85RFl{G1)a zDj$5L)$|biP)tpRz6WrB8+cm&48?6Gh$yZUp}CFGP%6+c5Ur2kQ>bTGW7k5*EST{@ z$&`vL3?#FR#|p@Ybk+f#Yupm{kfCU1_6-}LO; zz!(*`sq%Wxex~V8NI=w?#-n718IO|gNIXjVAMq&ZR>Y&E9}$m|?m;uka%6qir|~6P zG{V+>SSOaX3gb%GzmVjkNKwlOy?dGW!L7Q_ojM5Dhwjb-UbCSZs@Zd}{C;nmB-wla~MUCSZ=a(_+z}0db zIxZrQ&kIEOi17U=zc{*#nO!kk!OmBny~m1qlTq!3Dh{<0POm*yTRWFik30A;jBMHaYZKw`zY@G zyAm?F%JHuOgt~-PCdc`Tw&5#^R?1*8nD5UlsT#i8M|KOss`L#g8sxa=ZCYuqe=TyA z2GtXvQTm*XOl&GCYA|M${>ONC2*3 zz>x&t`e8i+)_rJ~Q+!fDuVv`bHt6*uMl*-u>r}w#>6cK|r%${d#KP87BTb)pHXc~7 z#!?=M2e7HWndb}ffTqP#w#5TK6c2nn9{87dV2d6@aI_h?{Aq)X7q&q;XP9y^=hBZ> zz@|o*zC-1W9a(Tp{u~whksi9onC@kCeFGK7r6Xr^u!cQ+i`JQYsq*+3o~9cZqnpH$ z4G8%by}cS|@v&nSw-)0b7?d!UE7Es6Qiyt#g85>FbNUWJqbx&tEy~)1vicSJV5^@- zf@9?-s^$Y0G7M@<*yQJwc5ApYk284S!5j&T@YZTCSm)K{=?OeT}QG8nv`%O%CgU~3Luyn#3 zxK;mlbQ*MVA9m`Ie5m9{@ZSnZ8WPLm6g4-Mg658)VmCQo{HGOA0K+QKu}R(puKMV< z0*xJ3{{T_*4=ZG*@+tQseMz}3D?W@x?LmIZHQ<|C9^$(|#m6M+S|s>VxLFOKRAkbv z$EX73)$+z7k|e>i>mY8ph<-(TznjwvONChYdAhZWoqwpajgL`TNUI<`By4OgpH4 z2spVNzUUy7M^1kMwZ;1|-p%Ea=Yi{F0@r8^*BIkkO}OammFR7P`>E2rM-&>(zLYG# z40YwgqdSJ+LejmwOx?p+VkAn5Iv+g;q=aN7hJ(sw98_o<4oVGi5I}@OQ_$cm@X9}e z!XUz=W=#dBw#12>F1LV5Hg$ye07mGsuG|3rLWF@2+xFnhrd8Mv zTpf-j45vhnOcQNyYN*n$rW%%yO=Tfog+8~7!HAg-{`a7Mc8ChW7E^A2lJn~sw~q|C z#)VsD3NuPnIaz~YQ3H|*Dhf4`H{*lQV}el9)1ANtT0=UC${tB&AS=(;H@_N<0aQ%X zU_W&ktN@n)HTe7c%)>F@x-p{b^N*8e(=~6HvvvFi%H+92jrJmA1cfqlO97Io280ag zsUo-!xyR&7{OJmRN?0lZs)&$DH&u$eX5iB+m>6@l`&Uyb{VL}L3MOkOa;5P-cgrs$ zD=MH1gchS3#5U#%6)eGXQ!eT)iXwur@A3oiH?U=wE~m^dp=-wQ6?1Y~Yrq}7OMQ3-@60FlVT>omD^dWB<7s>g4?!S&l9G!j=pzt1+U*oYtLWWD zh!cffJAt~cqq>%M8KuiKqtd4>%>vlq-^r4;v;`rm%~m}1&0|I)qEFwP(u^t&S?Lot z{0F)RG@#qtvH8$U7VUpHisJG=rQyo&jJWhi%lRLPQkhl_mtguIjp8`RS*_HUxa7@3 zK^sXd@oden<1}SUev(OAV#lPitC285(vE}P(u-7lXyap1VN8H&*){(+qBtgiJeEbu za0Ol7!0Rj_kn3`&#ru&UlFV-G|vW>k9?J_oK4q71dB_IU% zYC#@Nm1g4n-;5|@YAFu%Vxn1co#_?uEH!6`Ot_3fY{Wb1yQy3betB=^im8?Bzv-IFfB}@o5 zw5f}1?N}`{2uPbw!_wVuI!;8TbRT0XCq4Ua!UB)c@Gs`nB@CNzO+`vW?t0$83?Y(8 zA}E`}3t0}#7XqY`cO5RBjvhBL2Df2evEI-ptXzYuH`qe}`mq|9AIxIEcte}8hD2%$ zd6byQs@q{swrTzj5W;?fq0lliCNPMfAuC}&h*Gj6L})t6T53Ly2WzR(M6HsnMNO(3 zOw7B|XA|gtHDZft*B77E9hmup74`eKdF zK82WFORKqdc;{HyinzWZY(+4$p-l#Es-=l6Q$vbup)9(kH0sREQB%ZIHV9dq{|=+c z1{n%0i*hS?29qop)$^ZWRJD~+B-LTNySiCl)VKc{I3*=v_80IjIK&c5Tq7=7f|JZO z;v(cT$uUe-W0D&O++&S488o;)dR!uOiX4q=1!GroY~1i9u4NZpB|Bq{iC#Du_aVzN_I;ou z{80>^o5hH)r*qHx*g*_~#l!)oT(IYs?~GPYvRYnE!9`MKgFXyns<>~Cl~h~9^rpbf?3Wk{dQoMbc*fj!@HK5tET`aqk+G-I4yH^TSO>NO z)JFI~2(?(!Fj(bdrqFR5GO#P#U4yM7$u0~7x(w5B%^b@ImyaGuSYaHdNzv4X^C*?a zcey3fTpjnlT_2^t4vk~l6@k*qSBG`;fmO%|cBkrmM?d2UjyBoadb8pNYoxjk+0e#4 zoX!6ja6U%e8s8f(5L^rh%>9fl-GH*GuMnVEvUm9MaE8Ljk8Fjmd=Jn4#OtOngv(0P z0>gfkJAU`3SLof#M7R9->wLe6v$>Lf#oG9?}72<~-bDk6r!A2t-YqRQ(!JAU_Rbvf>(%{n1&JQWmAuF%?7| zEqx89VN75P0FMB0Y*1PsF#rn#yF)1D{Nn5{3HP7l0p6UP?CVI-<+*1}~rW}h9 zSsXee;HEi;y~ir1a9cuyA2;i)=bG{^)D<%rq3lTlqfR^Q*trQ}!iILJj_G}%OSh{T z&6u$@bF*$(oAwLpV&!U}4vTks#&FMypYS zc5uJnsPWg28bY?gHwE28*xuBx4({j_hPu=*=jB%2gxxWiQ1JXkp;iX5q=#VjMLg&R?0rAC#YLiDTaa|tTQxZjk=I*3-+wfb3&7EUfd{X4+C zd^6zB%;5(g?Z_?Q^Iipza%KVcOH&@j>mlMTuX>QXfz^-T)GdI{k&kjKUU~z%Rr)r( z;c_-y6xkFN~KZo30pz|o;=yM{JK;IdmC(ZX@QHH)!kG?{s z?`_dsFz)&$PLY#%C)!1@I1C-cf*B`k{7au1A%1H7%grGC3i3rU59f|QceWp!dQ|_@ zC+h3x=zzd484)i&^3>YVJA47|Ilk2Ua7%Q*{aM1rM`-1JC7yQsTu6e_iwt zMQw=e6wPKGrn1Cr7Vwas&!~!mxl8Cd&;^+6MCTsh>vFtSf$b@z!ZhLEo8!yWWx|%< zhr4|GanPK5<1G-ytl5XJoaBO@(X5rr+9})rI;t>jV<3y~-vyVZM)r@+<7FeAz}%>dviP93uGAZiiBSO?~veP>oRq$*oy*@b?xa-xr}TlOao0zR5N}0mScFI zUBr)RkJiPN&DoS`kA&}zX%C0*Xk@7LK7VO3#(R3a8ju{7U@DQRLFLQ|Y zH@VINLK*MU$}Ip(ORzNFGx8lbrL8`My)b|x(3G3zM{dU#z+ZIzBlSyv4sTKIQnA_v zFLl#EeM16uh%UtQMuBIzK6$8##2YyL%svFM@t2vI8b{d0j&B&+wHWnJ-;Sd5^~s5r zER-YUsx6zcItd2Pp|3?38OE_u?9&h6+ch!`UjUVF!_nIa7QgY?8Sz0`b@=eeJcN{F z>Sbt>W2in#Akl%k<}#)^e0X$zC(M^(Zh@G%s+dimZ9THmN{CVekz4u+4@Gxj9TAJnNjOoDO{ByVQ71tA)Aj}H&ebt=BV{C zI-}M{$Tb%bve86W0nCzMxE&0;|wqgQ9f?s6uL-JZ-ZKxE=UOS7!OS6lW^3NYBu>e_S}fDy z!*>;i#Y;vV5ih;ioy#?GaLEn7U|mzZWHhNEy(YNgU?%ub+FpGqW2P1y%U(dwv4Gp@ zA5yVt0hGxiG@??LqCK-u*ep%Kf{W7VW@F+8#x7vv_<_j*)b8)eept|7bcLxD2^YQM za}GJ|e9T&>-@vwqxA28S)xPwagvAgm_IG**`Lm3-m|p8O^GbsgCmp-{~M#%bHf{ zdQ22-a7}SzJ}S$#gbGOQ(wSK>rkUX47!+5l6BNu_Z{WuunfcuyF&p`LteKs(Y~eC6v_hLkpp-E;t$l@UW2AG~P3Zy&VTcFoTWM%@Bk+O37j?0+6I= zM~$m{!-p2a@*pu%FOub5cri`P1>m|An5iC9c*lR#WBd@|a+)NMHfh8+z(E%BU8>M8 z<$kiDKs_F(UUdD_Pm*_VIr{T6)VF#&A147{|1=t3Mw8eVE2od3?a#cO-pOx+Gp%5q z1bsL;MVM|uA5V@@S;a1BR6O*>;5*>^3_*WCb|h>=A>QOZa@$QQOw)hOuo~@AQFOvr z_$J;CjAFM+|AAWJwQ$TZEMvs`a!bd)W8A4+r-QPopDF~-dq- z2IxG_#L^7SA(PXZ zl!YqCY4^NIL3#`2F~a|>i7Q4o{9)b$MEP;KiNpEn=p-@ELE>#v1g~lD1zn^wL>Iwt?iEk88G)i^n*%i}u%N~Z98}{4>QqoPeu9FB zc!w4@VXr3PDjdNC9Oh=wRU!)DxcNpz0lKjX&J3c)DaPw>Y+|7eb^CRIApP&xygmLu zlL=5uf$8n3_G^Ws51yFwaeu5?UKQM7diPfE;J61ku5^t)3R6s=`BAAy8#il(<$DkA z_HoL`3`QwSF-jZbw7WR1zh_kF<p@m47WTTLn-b+4pxRb5yzy>OW-*C;G2 z3dKvJJ^}Nr3I_SEmvuDG;ok$Au&)CmitVAn|d`8BR-59zgceC8)uJcu8BZ?EXvfrY>Rd z0Rl*ggFbjW=t4rJ?#OZ>!+SEo#0< z;+5KmPt@eASQPf8yv=jdu-|ht+J<}uZ#6KJL~q6}1^9TU--~$A{SczwiauKO;U>EE z@goQdNr-|%z!B{484=`^@G9GYWtdp4$u{VbZBW>E`hB7lYN34nt?)xcZQzAi<3|wm zQjD${7LCMS3N)grBh>gBw!5(U^mtMcBK6UvA^@Wl&q#eVZ zs|AETo~+j%dY2r%j^0-bdgk`&-Wu|d$%b_0?=Swh@b~@yAM^L_7=Mq)`1?SUzlH+$ zS;2HD`cBa+rO<``A(U!Bll_%rdRNu2f+wN;GX6L4AJe~>Up*=!e+mKk?uvo`v(MoN z*~s@6Q;=zY9`EAA#I)-*jd>3hD{$}tOg!LVn3zHrVzZ}g5BB6vjez6WuZPoq=(jTX zyeAY}WaA-#nZTctp`d3tYYbwF<|JmRF`(pG19MQ<@b0In0~|C%G$xnc14>dL zV%h;~kw9Ppl*Sd$_)e@RCA&=XJTC+9R4x^R4yq4*5)P~6C#fDhC793Gj1mqC)^Jd; zh9PY&9P!%|!c^pFz$!A7`ulrQn9r46RCyov0r7;PvxgVZS0$1s_hCLDfOFE!;+p%! zJU2!US#+&a2ji(;1v#wX#WAedY*Su?AyEtmhD9z-DrfPzw!aPv@g&!l=!r$NS<0CH z)p&ZJj%m2uG)4+dlDuGFkfgf|prctM0W=8#ZRWvL6egl4;lj7Z-odfDE$oA?z}PD< zKYtsTxhc)Wsm)kZtkevsfU6S=#7NF7?=y3g3oVh8`+}PW;RL`HK=WYwt9*%>s`KIac- z60LFs&kb{=B@zvDD@2^9#LzMj({d40TbPN@WmC+wI11Dr%;(8#8%=|LJYIrpL0FND z<~66^lPVobCPSmpEL+T@d<3`?Zh1=7O#^oe^{zwuZBTV2t?RQ+`A=!4IZxZ9uw51I zb0A;g0rDPrP5BfAzjii9 zt6NL(MzKi{7VgLKA`g(CL@%EfpYhJvvgM|vSwkbUoC^;GOV|$s81wXU9nPNqst_gi zap|_klUyh7N*=>yZ12h${9Ilc!&{{JXaMq z_?O_B@d{30Ny5!%k_74IGjrznVaI%?G!%2l$Qe5Y%HT93k$S0}sO?~ndg|NM`Ad&# zPp@_IUlG=Fg+c+_>%W5@!8-XJiW!c_{0qg5#$*1OVpca}ATPrqRu~reJtAN;TDEBj5aR(ZuNtqhyq-86nbQrV0*=*mk?Z?Uq? z^j==s9W;RK4DI7$Vs5MIma+5wp(k1XY6R4$A%#Ow#v4StyNF!UL7 zV6@X1Q%FZKb))H~;a^0#$+v$MVCWAMNsWz;dK^yQ21@f!LmkJfDVlE>=c2@>$w^Fm z0sKs3+EI@o4OcFL^0msQqn|wY>9=j0ycq9KzHJ+Yr-xDOG-D_-)KS2D{1(RJ)>h=E z_yWD%2`V;n2Bv|^X8b6Se7zUrIYfP3Zekl(#fSOCT(dMWv^O22zR;{duW5#A4*N#( zW^<&PCxP&BkrCBjZ|oY!!7|w(tqN3rhm7IyG|J;O{ z!^c|0A{-`mfxzah#LsVqK4 z5a|i2Y+Ol59hf$bHj#{sckEYYcfLbqPm4{7jvYP5DtB}kbkO&6-8$=b@JlrmZDC+a!&T}ANlRPA8 zj(FApeOEJmJunK6q%4I^1dpJ@3VKYM+ow4|Ya&t`Yfdj)C;k%K`vc>IWhnP$Fkr`S z11il{k6~d^y2a`!);4%;P9oWi&)A5zx)r|hBPbW^8;8aEhUv|T`TBKu!y3UV?02i= z$kt%@#sgKuJKS`G$7z*;Ca1G~ZXbG@HE!Qg`8rrQ^M78fWY+%WAHC({e~ilY2ICUe zKZ6WnzICwQ{~ox|>-HbdV4?ygRc*U8zJ}a;7{IDQZ~b;Dv&P0k*I9t_m+4E`g8&O% zOXHp<1OLrbuCWONlkE-c@Fs*Di*qk@as^3!81o~|7HQZ;MI&4svZ560xHpW`J>REX zsbOq4a?n@9CAz!nxM@suVCk|>S1{p5ramHR1UCw&^SH%l0Q;P%pU!41x~``dvI1<- z>BcLm%9b2z>egH?+bdZB7#gqj((o*rk8v}(sj5r8PcQaBMQTPNKqbMcO>}Q7mdGmm zT)6fCN++_U+p>6DF%&;epu=%UY@KMqO@L-+Kv&OAU6P~(1VA%Ueyj(j5YP%4)9B0s z|E+m^ftTFT7s@4fn#c}g|0s&3=~pi!fj<{T(|mLk{fANX`|*Y?xY)?)rNkE8#R4z; zW0nBx`%guHpCmw9ub;x)0{t1KK?A*PuYt8F9N?s_n|wq(3;7(~VF8M^lJ0;u?SUqs z?ZUtVRqP<;oj*v~M=4?8M0I<=!dromatoz|fd{MW`W4&)E-g;D$=g0An2D>?O1BM4Xx%M5Awq zzVKxlyU;e+QiW}+w3PTL1>tLYg+c6ZXanj=0O8OvHbZYCOc^YeQC4;%QuzuLxH_)E zQalbLpqGO2BC)um`+rwtmKqqA1GdU;yEk{(~5N7+E8%JM0q9IU%4xEbON6a znnS&IGKc7lr2(Tx`O1lueg&%~LN*JP)|6Eu1?%=f1zY3FZ2&_uD|SCyz!VBLg4lQG zrDja*%}Z@cphY}3Lfe>PR&;EFjWrneh04)42|2k?>k z8h{=A_Ob{#vVcMt24I>+$Oww;0|l98u;1(!@8BQ4~Dlb9z<#tu4@cHZxjalFpD&A zG~fcw*M#3S?`S2>JnCSBCJYa)f1ArcjNj!~;pb68{gvJgQ7P%KsCj%}gzxC1TP?;K zO7E3`$xfz}t)L73KAr#MLsNYw484ylma$W=&k4yi`>Z~@FV*J=4UVOd?v4QuxUXPz z8^bf)#3PQcpuui&K#%D7S;fLPrmMDHpe1x zRWQcjt2gJ&MO@|a8We)LpeDTG<-zGFd!NpnZ-zxnL}Atc5nw1=r+*J#M_`=(eLT`C zeW0*_eId%cJ-WYUq7VlC`qTKQvLQE*Bm>SM+xFz?O+gsz6S z$RuncY)Q-}!j{BrI&4YIq<1qVt?1p(W&{O=hOt~}&C@i0!hpn#UEF@OW`k*A+X1pe zgV+go%si6Sh?&Q@)o4R5Ee2WC(EiPJpgeB-$XLW|U))%&|j_}ih6Y_+~pt~Bs z8FvkSO?SLgMTU9P;=DV;TNBacjq-*=yo`zdum&8|A+AAv`HsLp@Oyaj(DdLzOcLOf&8{vMSwFz`@jPx>Jq`cK~6F!&24XF6mv{`P? zvU<*-iKmc|wH=fkyI`U|*#nuOhJafI*JFMZI`PA!hAm)`7I{L=+1jaLy(a#(fGsqG z>)f@Be_bd1YYG24tdlltN}M{|L(9xvE4+5j7?!?YT6sNe+-qYtZp}mn9E|$O$iQg_ z$>EhUMHQ0rMBb{DC7K$*ws!bw1K8o78pjXLDq(rMP5t?iL8>tIFbs-hXlD#wg8E~ASZ>6{B!5q5}7 zb;gCMh8==gZE2#cbiG%xr5R#NlVhJa^i|uMEN-~-C^Kfbhh3O#lmnaCQcj+f53@kz z1&3A}SSd%Pl3+55RjKe|HAB0A|9rFtIo$a+r_PPZ#8fM;I z&1N_30kSdk51GYeV`zmDB4a1@0-*xzHe_|2Wz{2DEi7c$x@!w_*X?QHY09QEX>_Xy z{&Zn_6Ra_H|8=nYNq!mO9z#R<2t*l^Ij&JE8R5o>JmSXipPojzaROsk#l(Ml1~x20 z29|+lrLYSo;AI3MU{92wSu**4MuNc6FTNXqtPl~i}gd4DUM_F@2 zoCK$P?BF$uNfpA%`K1qOvVZ=1)B_U|Sdra{;!9(i`I1|;>;2cG{-unz4umVW%3LZ! zXC9%SbNKnhIn)EYN`m62Xq+IjV@#o5M0phDn~#Jq=j6-3Q4WlGC2w!_ zSkx_fi`Cnsj>)^LdPCGTdB>_aO%Zkki`AK?mwc@1H*Nm|Rk%uF@BWHvAFht$+e`b5 z@tBK{+JO;eY?`rLeOZ%+z12pOhQ;a~O&ad1-q@t!SoMk~4U5%HO&X3>v4uRO;ejfg zwa|5VMYSJy=1GFQRFk5SX;dh*6xUOQLgR3dDipeY*HeWInSTV?X{6c#lb(U(?-#6E;%p%?Y%g zV3BAqt#onJ>UyOmkwk!~#Rd<)vyfO=Zh^7K+jH@$OU$&F+mqnSgcxZynAp^YakM?# z3K+*Cg!&7O(0HK{Qtv^n-d1JEKnq{B62@P$+PEAu*=o2SXAWQeBni0(LI5E#p27Sm z35m%ZsSnrYvQit&{Db@YNY3(VwTB|6akJ2*n8OSfg8 z@gwxJLS{Q9YL_8ctbUP2J=W7DTdH7GAc)07!NuG=5!R#nDCUoNDF02B_@eBB$ z=nB8_kr*+8gU35#-grwJF;Uoo@K|bb_Dm4xjG?j}5xr@c(ruIeVt7ob4iu(keh(-q{@PY~voX~KOVRuT zqqisM<^&u*+J;-YZrc4P28}L*$7HiEa9$ zvtLC65JrnJO7=2F96Di)SdnFn(BKw~Heo~y&@?WtF`51?{A5$Jk8+!015h|A(!iu4 zZYl?LSX^aXsU|KfcUGm1MdOXhem7mRU1v?>tO_R5r`|HIz7~y3e;LdPH3OLa%p52+ zIV9`o5JmD(iLB#}`|GP@5FG<)iee`l^s@;F+pAP= zmR%@@>Fs7EVV=EG)z6h!pAC)W?I%bIE>qI-&_(`g+ogsQbhePoz2M z&%Y*7cj`r{4;^gf3w2uO=gU)xT6f~hdlC>-%ev&tn>z7j*DG7#OK?SyX_ut`t{7{$ zQ;N9rkr#|Rt(_O~XLT!oz7IOj&z~)b||4lm0r4`}W4hAeXj|K`@J&9D|I}804043{nqY!toyV z6hz~_7q(37oE2lu`S2wi=b^{{FDmo4u&DjvOE|v6`u=}WnYFN}+ryV|Scf$nS*EJ| z721-{07U%^HasY}Kq&0^aZQ~iT*(h0!J-iv-5wFHo9=oCVw=E7uRJH=$$vt)o{7V6 zd>{ray!}Iz?m70nMI*9Ih1mP$XqTb*}dD{LHIu=6(%*}3MeJQeVdb%lR{d3p{X zc03a5MS~lhxe!AVFFUaf>%~})2q%I6FMDqST~(2_4Oi7UN$$-YGS9go zgpi3OH!~imfQxsI-cpg5uQBwm71qqM|K| zGb)b!&)%o*5CQe=xBqW_|5|@m&QtZ&-Zc-WPTf;=ppE?o(6(XolHrF(5WF3G{v^D% zY3*>b{1rT3x)EuhBZvF)k;AUXg*MvrZAFF+*&hEmT_V7>hdH@N!QSK^;l6xYvFGur zjo&EYbmFi>%c}$BMSrnHJ^b8uXGoY|ymxjug?M`vXRP9Z22WEucLle2o*gJBJhr`q zbaxxucEiEDAL4x$XFS!GE0~H~py5@an6Zq|Lpav|P9Dw*FZ5Q%6M-LmlvzHq&+}Bb zH9Y6O1TH|5817 z8we=xG%T+68V3fv{kwUmyKDEn<8yKd%GX-)p;>shMp;3xu6TRUnIEGwzrg11pGD0c zyEVp*K_Q$!2}knNv^+5Dj;QWo(+vD{4L-#!>ek>rV;K*L=-gBe*hVI<_9}(MhGqQQ>`_oYqhMi_h_P8eO zt#gfQu2JV%UPXzXa(^U<%7QTyX6BNclpHqk@BIL&*{pCex3jQ^6?5mmrq>5^KmGj zGk&vt*c*S&Q5O-Ce(EB6*sF+mqDEyDe(EwppZnc1f{we4lJY934P~FY4cV2wIK3ED+#VPgmj;}fVO)T5Y0NM zd>kmBYrOlIrz`$O0eO`C+Fac%IrKN%kuD>2ZAx6*srnh-+xe|_qzlO_1YJtWp#}d; z4n;ZPos(1bG+j>Q(Y1sS;x&D8rRP^Y?g6jTf>)%C)&n+T-j1;|3|qp-=n+D1t~U7S zD?aGlz082QS5|JI9X}MN8PR;Km-kwrQ}4=lEeHnrp^1fid(Ly>{6f#-q4Ry$GNKc^ z7p!gQQDcm#B{*rq#M%XBcNnJdDzsi~J3Jwpk z<)mkY8H*|5z0QiBSRWRGxn4+Eh+kj4#Tn*)Q#|*eUs%Y*WT$N+&Ti*q;$_aTkg!m9 zGJ9aIy95d4)Y`&AaVos77iSNAZVRW!>-ynDcXP2Pztcc(qp>8|j2=Vz@QH5F9^B!$ z&ho)3fu~@za&1(vDbeBGegQtIPRUONy~YxN@59l$h%0pLmc?3ocCNwixt*Vaa_l-k zETC;d-ynkt7kXBKtB}G1Ce~-AxwL5+jI<}}o#!5{3H6*G1Q(v?hwo1af$0yf>>KBkULJCX zfP<|(Q}A3o;?VI^uDuC(+0t9r9TbkU`)>t>gYf=aLHYg9gUUTk25ktch1x{7{Bv31 z)qA|oNuMt?GNzuaqT6_Gx_d%}sVjzJ*Tk#5d+lIaMRO`Yu^8k1TC@lHpi32<@g!8V zneiA!K(A?1eMM#ZE(*o5Kmops@YIg8%g`F7EQ+^h*O67o+$PJ(dI>rnAu?A*F))>s z{T_vu<&;}j`lCgpRQ>2KXitHLVwKWE;C{Y~0uT$mw`yfHu#|t)jI!K)7vYy7NL?~| zzfya#M81oHx+(Bnznf>Rp+m@;e+uuui-IW-mrA|gDFU!`Tq^me4aIj6R?$qCp1V*3 zZMx%AJs6@E`Jg`^oMI5-lZ{u32IVG$;2;CMIn+#BlBeZH``{o0UN~+>1@Q|*O)kqc zvS3O1&(`85-OK-p@bKaR`ntOp+YD?j;8S_rEh7&{o!~`fw}kq?Utn|)O>bST$I>a{ zhgCjaA~D~sZ!KNA*DamT*<&Ww_#)~wTyeNUaoKTUJ7mqeTEzUa!N%F9-N>F}f%Kd)SI_x&-fR!f_Y(%=`>7o7`IB%mb~W}C`Z{i$f77i!xBqmauYa&R6kkr# z`I7=|4#Y@*UBURko41M$4if{i2KYK!E^9vbU@Z>*KScmuKUa{xw~C!Y3<$=DmuN5J zQcAv_U-*eLPVS$0pZkyW&lr1l5p_EB&uZ>`GIv7hJK!Kv%G_4&d9oku;cNGB5+q^8eE+ zw2EvT9&|pUq!Z&^I+3h{g>f&P8NbrOkCO-oKSp}#%>0!OmPMh1H!8ez+J2=|!#eoI z&`XDk!aF?%>tMywONWZd(osAZEG8Wz1IrmMCA(n^=B(AZ&aS6HL+jyj)=TfK49XsV zB!I>@FFic6cXG#RNIjC?AE`$x zUdk@&vB~Otm~v6y3zhWEL)=lbyaZHHmH@XSZvoYgCAhx3fU3k2pp$$1pn9+b=(XMg zN{uBzSM?TnQgw58fhSe#y9+$2x~03old28f1)fxG>@M)6>Q;{+=X7O70#B;E%8CS@ zRC$#Z2|TItDk~CrQsq@vB=DrltE@Y026$w14@+vD5 zcv8h>g@uVjaTA6nM@&gM;fI?`=6P@!+Ge?8?IuJt(5+!|CibPUV)B%zUyRH%@hQQp za5GSmOR)K#KCg;TOQ2XW11~%JbC}n_ zf-u(*KPgOdwZbH|jGef7a+vIHg~|RGkweC{6b7YpEiCvD=5@q5OhY8VL_5XV;N*&} zC2A3A;VfO;k>lIfkt)sYlA#AbVbNEH!`qW!y#$?k>;wQ8Vy* zwr>~SFZPdOKV45iIpYTKE<7OkXHM0hEH#$g2sf2+6L87R0FDnk)dZ>@=^`mU7mKgO zh$xiQfWC#_b3a-%M7E$eBxV4y9_z22d5vey~SOduF9Tg`d|r z6w8wis2m;&Hb-GPv55R;#&uwR?0;c_MORXwuKFlJ8qo@M8k2u<#;8S<0nUmuKt)+e z#Sv#w9UI|}Hn8Ycm`fZ?|S_0yElgCyl?7!1c{2DtEProbb&kpNtIr z!0OvEn#$0ccPHt(ap`1-&@trWO?|b8RzZqo7T>xe97w4DU zO#gA@c`Uq78!c&XsxfHultVJ8%vgK==;7?~J zsm1hEn(;Ws=^%To(+U?0P1tLKmZ12#*-lfyCG-SsV6jdurpMIZ^AXz32R)Pij*p~n z9_YdIcRW}ra+OGKGUb*_kCzYJq+I8TGemt9?8HonxA3;mlGNQ)$vBE_Xr3WSdAZI!XMP#E_|W&{L|3N}J^v)cQJ8!B!Cu!nx3z6r z2Wf2GDnzyq+{V_4gMYUkT6+!}JER)2qu|GSLsmJny@{0Zr|>v2{+-*h>@-;YAf5EV zHHy6r*Dzf4egm3=*oOxKdH_aqrF9lzz$86NV;HWDxMFb)!ZjS14Hv~3gp2f$BsSw= z(%y57eEjV({L+&|a`aE}c+}b~U-3{h;i4GA?;@+S!o|O{NxCa?eKz*NMs4cpEApcW zTNs;S$o?AJzhHckbv|bdi1{SRS2RSDPILTxgn4x|VZWYvxxOMYn((iYH}>-tS42{b zcd@=-0r^S^C)^}IN%9xPk<)?cQPbhFB%Rz}Vrf%3*^Okv>LkL>D8fslsu7x*@n)&7 zxITvL4#r7}q_2fh8j_JaUlG8XmmwBk@w0ry-&b78;eV8#jx>+p9Nic-KPy=DR)x@y zRiyJ&I_2oW3@VesX@upR^3EU%XB?O0S`O`oFmhRuIU6}$8b){r$2gZ`T<;)h2j_Qj z53(-}Cj2Y=`b!$w;}Z#&MH3F~MHs?3kJI@A>lDS3dkVXJ*OTlmY%hSchqxz%%J#f? za$j!}M)oC_LmbP~obp~icr)*w?pQs`qlp zA#e{C_#Q8GzR96ddWU@tw`8VXc1t;&0;MlJPYZPPf zCF!M*CFc^W!$)06^A6Um7mqRf7izvmOb{L+u-slM}V1rn8$WF5J#ZYF&eFw!gVjOFflumon z{H#XoLTqLhtJyRZcc^$2HINC}0+t2k`u1(axU^W(ScBOhYNt&slS?r!JpoOUU5W)E zAx7l;_FalEC|)Tk?+uW(;9F%^a_qxGNOQh;h+}9)D2-yNc$`BS$ZQ!xBY%q#N(=4} z&vAT1!YIB!W6uV~{u#H8Ka1B{Gr9+9{#m@ip}fs$xl+8vsh(;6yR;EIasSP+AIu}R zT71nctuL{S;uvctXA-*&AJL(bAHlM1B2Q5%z1D|hPl*C%7v$W5mi3%yRcKJ+FKC~{ zHmYUNT+@fxt6=_MpJKMt0=CJE9YAXcf@~?4IaJ-q1X0qKyM;0Ywe8WoxLcT$+{__@3o?{LoWQZwzP=6qS!!I@ z{Rtn0kL&7FO1L+c@aZzb3&IGW??Whi624kM_-+y5V8-`Zb2(#cIl1?bAUvA!L3mx) z0(+Lq7m4CXc)rLLp8~Ud$Ue~L%W&KW!jJ~BEOwD?T$hT=Lh;@pzCrOktO(Z{ggs5d zhZuu>$bKK=3yghy$z>U%js0$6e1Su_mqRFIzwa={vag+tZ!(T$zXPmz84t4G_u212 z_Vo$lSk~Xo_%q`q_FK)q9%X!&{eHxLYuMKpj0;%*X-37q8W^XsuO}GO+1ICxXR)tu z7?-fGy^Lw>YYO8`_;S_eXJuKa)B6&#)ab5j63JfFZ-wC$_To!?PS&Z@I+MfZL3(ci z>5yNCIN4=-`DZ?(yMB&29zMEjWAEdLaeVBLsJkuxKbXGa_8cP^cm8-n-!j7Uf{ftN zU2TbkQy4!l$WmeA>5LPo_k}@bM6sw1pmhEmOKl@L@H&52JAA!|En-~PpOOeK_9wgm z=n%f85BNL8Il&M37mFSJJ`Eh#wE}q@*Y#J%Hy8&qe!@7O@kvG};{%MnfDS=9a)`40 z!FU|_AZUew78Nua_Gf}71&!<4k@^i+1$=|@IT}x?T9Hm6O!Frkj1b0kZ3!l@~7O5KDm5o%5?s72JacbA2ZH((0 zk2W^0>oT^V$@cTu9?bR*wx_fGX10%G`{isO!1e~Vhp@eq?Y&_y7H4u9E{vcyGar~Q zelSy!!VNyD5l(r)Hy!whkp*1umj@io_E=d2`!k{(_^san;1{Brq&9L%whaN!5hH+q z^CkSs7=X4Ek@^;%I<5W^k@|t#K0fvb(;@!Z=ey8iad!41Td_D7?W9;Z(1WBH8cCy5 z&ypWZeCHXhSBhfvFU;szZBjDkpq9gK$+G z;f{WFXi?V%4G$wtBN#0|;vBfY2gD3Ls1Yd9)6v%$pHpPN1GVfca!|{@Vh3Xnj1Ruz z?~E@qj=(74i>DgG`xswgzYnnAGWK zNqzhRgD}M;+{PH-Lv|X;eZ@I_jo?u!xEYB{V~%IiZ1lI-1h?jFl*4q3iGSy>#4K~R zX2&x2f-PY7p?ovvf(S$0#O!JDX3pXWQ#`3zTgYBKzrDxo8d2M8X@rmX7|e#5OlGeY z$iXjK=HF{ogrC4bz_KH0SAzwD(Ysg&0j3jbsD0YzxA)i$Pj;1<{c6GyT-Ez3b!2Z%{p)*EFVAR1Y=R*X;I1U6H%^7OkR0>z&+ zd!yI3h+uIUv(@6^Ue88^iNkK$TM-fBQ@8AJM3e~aN%>nVuIzO*B1Xh8TP+%UeHjre zvNdb<{VpO-jAwR@xWM<9hy<}nv!9huWTLoJYo5_BC^A{>)3OK=5$O;=Y1vx^5s|54 zavH_AS_}w?kL)R4V768~(K{`&m$@3Z$&fANZ5hhqnv|}Z^fB;HW3qRZ7t44 zk=0_0o2`hf5zo5W7^7Ak(CqGh*F_EzpE0}Cc2E3XtQ7sE+28vu0t@A*Z7bD-#0FyW zQV|fc0saoU+5Eu4A}x<)wndJ4>MZdEF+8U|mVQ^{SpqjWW;@bn7(+#=X46u)MGg}K z3oO}?@-x&haSk(UtQ#h7*RnTrW*Ec8%UVVw-v|-yB!8>LtJz!R2$AAu3yo2tFEc8^ zyCUmEm76^hSue&|%=TW+8EUL(V769#m9!^vteB};Wa*yBablBZt-*UD$BRR5&Ha%R z#20SO{gIPI8lHcs)wKrik32`5quEzU??j#_W@;8$`cC9zvCpmfPGpnFE3*8(75ru7 z6fuRETr0}reu!)lKe?G-)HE?0Yxg88f~-~8Xu+PDU(^h-ShHbCF;TO`PsEUx&FOwo z?P6Q0rCAo&Cu)uuM(dRvLvd7x*riz!Wb?#?a!XbeR~$88?9=R~@bOyJXX%E*1;i?1HFE#7Ayc9Cf)k=L}189m2dq>~gblQL9AWnJ$@M z)YW2>n@x*aBWzeQrr6h&Ul4VjSm0*GQ8$XCnhi@@5p}beIndJFoL(Gti%6@m*b@mc zQ5(f3H(L>Pn@Fp)WZNOTU2Ju;6;XGH{#B5n1Vba&MQs*05ku@gskcSlB{sR))~LJ1 zy>9k+)V<;#ZuUad-^5RD_FmL|qP*G)^M~?pqPB@jH&fAn7en1FH2NVi*3FWm9}#oh zEH8S8xXsNfqaPKAi6Lc=rH_r?B}9#jHAg=oLNq&)8xyrhB)Zw0=%+z z3@ty))natc*U<;XguzzqKB+%Oza<(qJDOvUc}H|=_9obSVlOfHYlw)8`9Qpkuc1~+GB*A?Pd#Ol-x%QrTatq@)#d^ z%+0Qh@s*{+U9#(9Y_f~lYN3j8jIP{nF}}+L$ft{;$~GUQ1%%?GP+w_hgSv$ z65~<-)|ei0u$$c*6E3G{c6YzWVj|>)%&c)fLSCjBjq?%mCT7++A0e|xa_kuACk95y z>2B5>7%3mN7{>WHpJ;j6D2m-0=cDBo&1jsDkuPXQ<9w_v9fH8 zC3`cc(TJ1NnLRCNoR62@<9xiln`JcWFEkS6BgEt~;Y^roPmwQLq40eyRlcDacW`=wlQy|~e z?6LGi$|;X(wj=#xRVcH^lIB`lJ#the>zP^gS0axSA8y%kMN>U65py%M+GAF5PnJH=aYWQR$Y;9?Yn8zeXtD zrQ5$->7F5zv}TL5*f>L`yV;4DGi9}AclQg49Uvz$qtcB5n@&uZ?f|)u*)<|2@;q~( z96Z4#t5TKn1vh(9*2ut#B%{8vR}GSB%&4pr`=LGk|o=e zw83wvj6TO=R1d>shGtX`!{sz)R1aVKjF2leYjIv9N69;xS+z1+Mx2XKxK^h5kCydr zwpERh>xk)Esh9g$X4Oi)3^_aLuSz>Sa7Ln&});^)k=RX84SiH5TKU&Nw-o z7)G#1;$Dj$Cug&aSZeG9xl6OMxSZItaUv(hM|b<2*akUWvvpw2a)V}NaV4?S3-r@>nK{#A7od^t(qN*nHsxNzU-DwjlEJH)66Gp zM(iqSTi^<1UhGwJ<#a$G8jePb(ixq*bl`)I07*_UP5qrIy;AT@}Z;*>MTL9UO za;KY3jlD@8B8GI9#jTFLSq@v`V(Vi!$~_lZ?56U~v76+>7rWSlv3JT%m%7;M*n8wh zniV0G`{b|{maHgleeB<5-sKishfp4tDJxy#$u19?~mOlJJ*7tg;WN-9s7dZP7HZCJNtv!7v(NytHrnBAA?Q5&XQFJ zeG&VTeA&&ui+x27UT4V`Wq%j@njCh$#rkFc68pN`cLNw|b5fE|+?(4lt{Mj)|R%^cap(lu-7L(HjJCuOx}Z z59I;h#`RF!G%E>^@!?8suw)Y>gX1IB0L{il#>Ypi#hUdj4~>phUuf2tlM$bw`fs%S zHRhDWC#p+{A@(22YvYsD8qEfTjEhfJ2i&YVK1C(mYH8k4Iy>H>E_1W4_*C^3vkz^b z#O@V6)%O+?RYiY^@2RXch{NJUM5IVlX}3`*R)6TFvWX#onQ=G9_fm^lwpv_QbYpyP zbwJA=OWzvbN2P5df2+mgMO(4%KbzTF%pjhO&r$1$A(V-cFUIGpgIe>FqW9zJH%ayTg=(i!V(9Hrug?iY{9*L}0 z&)&hBm~CGXP@`ftyV!LBgVeCQTx?Uo5Oww4E*6t8RIPWjw1nYmvzz57j8xl*@m%A~ zgwg6fHyf5vr+#v4PDrR%)mtb`YmPEjy~d1YU0Fe6)jOKK*VE=dR(1)uPf&TpFcZHtBP#H0wcuW2OT{%AUx@Qm*WWDGBk`$#^OS9?H7ed)FUn=NVZx$(bG3zruv2$!aUkzWZ+yCeLu0);?c4b{&Q6Zv!&ud zQb9n6TA*2b*E+*#!awas3NwJY_(V)+7PhB zi%kvaQVvVTW7aZNKn!jEjgqEF4=W6Aid^oNeF@nmszhrJf$UN@dla%2Zp~Q8E_2K7 zfb4QN^MUNoY9Pl>ZK*lo3iVHm+06X5gq7+Q&1gMqrFu)V*UG;TE7b?gmfPMdehwm#GznbeqX{`HA}O}VC&rD z%e2%W;|4cdk}AcGE*A7!d0XI(>O%HMCBGx#Mzz{vwj+I3`K(vhGqc8?_38k#r|sl# zy(<)-z|?ul!zexvqxf!7-;+PNTzp!-A@UZb9(J+$fg4mHG4Yh7)_SXoV)m{)im~oC z9fLL2-PWy+HmMBOTq|;XpGnxHS|6b>*NXY^O_7@wz3NP*`#|u)gu9g3NwU@A!jK~g zTh#fQmF0YyaIacP44VBB%2xI8qolc3T!T>lu3jJp*>l0i6CPA|K1Q)?6zh3xg9MSE0Kol(pj3+~~yJs=sDA zu_=j9sK017F)ugqX>~}m*38_*XVtLXmcNO4rHTJg>oi-GSDCm^1wLWPTEPCLsx`Yk zczEKAYO1ZoeV%Q#Jiri@k5ZJMl~P z>~j|Tx9#r4V+ubI;*Vn3p7@=bvd@wo_WMWTkLsg;T5OK(jYMHg`Ip6Bu^mY?ji+89 zM*hA_^fO*?GvA~D;~=xu;)0UMq!454ewSu?Qn)enWfv<+iZ;f(S#46hmuzfOveD|6 zO-btMCF@A)Z7g!jE>6laE_bulNqvnqZnh!GX>1~fwsgDsx1lKT&`#ql2-`J$t z3Fp3~fkx4*mh466fut&9lx8yTKvJ!-NwfZW`;vwjKM_OewioV88fMIV&0;r!jWj|J zSfLEDKb|zkDAep)b9K@3)Z0uu3wHcGV)W~~>WqfzK#JG+add>sRt3oa@HhIY|HFhyuEBqq+BwuQX zcgY{IlH@-dhuv&Y@+xE4dmN@HE*zhHwXyDfi`{6OntZL%`Ju(mFIbp-y%G3t7h93M z-l*4XRgdeFHyc|uYwU4n@_okEk1Wk+?T;isVyyYpV&B^Tnf#cM{S`4v%Uj7$7{}b~ z)8wa(0bjdhKPLaf=w!B9Oepy=`FW%Cm=#J{i9O{-W79V-&7_nAM&P%W?9cYxl!Hdv zcNY5~{EU=$jA7rqG)Ja~gb(DPJ1>f3!k*#&1Q+H%8Y_ z7Q4!CP0Dd2;}?tN`E5-3(Rdc`15n*g_PaOb7h?_5u}JoUgqhhkm+ZBaNOOameUK7sM%b-T zUiJGrCDF9u9Sw@%B0u3sG0(wf17azDL5`m0R=g2JY=B>!Bi%fVjR3^%uz#J>$9w^A z`4gLH7mjRmC*C0;_Jb|R(bs&KUPA|qwZ}OM%w0V!HroH|lp^yG-XJ1bg}-o=nr5WM zLj8jr{meA_x&dS<{&9{o&3Zam2<-XZy&V;%8E3IwwsJ?U8IfSIV83$55c8%)VpI}C z9K*~nn5`D)^$c>1GWYTO>Z`?a$3#b+xh>i9w+x|7GJj5C#=YZQGlveLLGSo`-)W9> z%{(`o={V1@%sVw3?zqI! zV(!!I+LTp}spc1&eVKBdW11O(`2eLX$+5vP-7M8?YRYCut9g!QPo&)MIN$8j>@3F) z#|-mM&8|*)+A+&~L9@?N_B-0m0m8CMR!pEHcwHTakRfW3f3{Ge^n} z#}ae4W}}mzc3fnx(`pQztk(t>6-aD!cwm^mugnzh)=!Byg{=iDZNrxn-6IAdP?8aYs`I`O?H%} zUTc1!*_|m>sn?mmXl6Qwr(SPHr(0<$aEwpA(ah8A!j#6;o6RAby_zy3^%k>9volhD zc5E~kX*Mg_FZDKajb^VTho#l6$3YHs8@~V{+fryUpX8m8X=Y z-eZPgrJCBy`N>tOe={>Rdog)<>V0OFX1*!oQy(zT(X2SRG4=1}Jk8c8&q#g9Tty7M zYI5ol7l}tr-waC2rMBpj zZ(|-cW0{fWA@!J{Z1cJP=NH3tjH?a(Zzp;RJk)N{LqkNax)m3hn(e>>v_@VLz2iYdPuk zDJ7}5-Ey(;s3M&&ffT+Al{ms_BNuObcb)r!N&nN{q_aNPvQrAJa4dK4Fv&%VSMo^z zx)QSg&7bTK1HJ8rIEyts;aKVKo(oTo3~@iF_Gku$=541ux};RvR%y6gCT)tl?u3e7^i8U>wSqY~RWkK}%OJH6Rs z`NgS^r?k7IR#{o0{SmvB3rpYI{zv?J>(J7yf!zn5bb4G&aRbW4mBRKMkKLo=l6qYJ z@9^baCf;`My#K!aboEe=-KAr-Pft7dZvQTwKN8Ng5Q@cW!`}9jYv0yK zp*El8R{ck$7le80)Z0!aV~FQ@l(WL|mU`P=nl!#8#ZhS9`L+C7I{kTU^rXrVzjkr8 zC8{r%RQgfgeSt2icW9o{fPMt&cwD^gr;?s7ZQkKajL#T7fUa8h*j+XFM|6JO5?p?N zdrbRpjAm3Xeek7j*LdhX?pfoZl{Tv#o-UoVTig{wBif7-e?uFya)AK^e^PvoQnLPB z{`;R@$sox$b&adQMIiwS-gMJ1ln(Dq*$!WZadk(lE5k z$GDR!@kTtA3AGyeUa_Z`Fr?Y$a`e$)>lj8i7e0A~ccLm>5Zpf$b@8%hZWq+DyEFQZdHt}5L*Dj{W z@<(1Jv`)oG~;A_kM!iw=>A1_F7j)Yp2R46D!b=C>*|A^k&0rcaJ*ey_E4-S?d8(m zij^PNU2;O~sqGRg4^$?U29I5e_i&GPrRqIAw<*5!8qlG5uPdQg^1SdZ9V1DtXPKZxSUCGL$)q1T_%d&T3q)g!+%GiL5V2UT!!w9>p}PL5lwA4%m7vfJL4HmBocJQo7~evBHaK@COMM`@>F_sa1y5>RiuRR%x81^YiT4>D&tl7Kw zh~aI2np5JRN#XSBK{e7CMs3e>_ih#UCs?_rShn)0GQ^j1+L}Xoe>H$grZ_b;)JOct zW18jnR`g%gHK#BJtyBpIKle$mUfIg-LwtWb9P;~cJn2}W^7;YA zi?xoiGuIWu$u*0TMvtJJQVOlwv{Lv#b*H{Vql#5Kt{Ab3avFD6_#VyEyLi%Ot#x=b zO>UD|=i-t-wbZq8;_+pb!+)N4>e2t3vT~)wldu1*%>UmG=ZD1Zb?VbC*EAZOs>WTZ z`Xe>_zt#EuG<2^imp+g4SnKoAeY|`5|8Gu_Y8UG#}B9mh6jhLt*r|!*S|Z ztbYB+(e=bGvxo@ZnX#Ra2-MPIcR7k)l?EcxqClVS@(;d`6|KG}a@cmnaauVP@d! zgR_(Ru(?hY;n>4+k&f$2T&cK@;QCbbgHAu#?Sl4ogaLg-EZZGGe|(|ucxI?5W2|5t z!Z@07B4ZgH>u^EVSa~R(RI&u2q@ys$23k(%~fCEH6 z+eZUy#6q@{PAE>RBfq@+d1CdIQ!#qv72{9?&cE&${-CD6|6Ia?W5W5aAT+-dz@%w7ebsB$2f;^ zA-m%QHoWoMDd>IS#ez-%_?~gOpgnR+RiCUvxe{-t&&C_7w5M$)+;5eatLD@#?0&zz zUX_*agyxApPeJE+=8Mw7>37IE!5_-qYF_@QaG4YQwR}#|o4MrjgWN5KhKHyxg-?$d z;N*TOY7L*(wT92DS;J>EtwCtHYKw@)PQ@*vvS6>+BCagii!UP4$p~MHdiF)<4eVCe z#$BS`Rn8t1{+9eJ5E|`{-6QDz+nq@NRz-Q)0Zq!|PDuB{ox<6P{nLklw3}~_pf_|Y zJp&I(TLQ7(<6 zTpCBYG>);9@Q6WJr4F;pVb0evLFIFh>+Udzzf|2;@C$O(GtO>O?s_mrn)uz8U8 zRPI)9=Cqr;)m!27fn{+wn1PbYZMPbmdB6EGhdf92j@S zda&oqW(2~#PF=5V@c+V0kaUjLQdJT6i@A;KdK=gEHm>V!oMyr*wGC;G^CA0ns26H= zX$WVpN|RJdWUqpqYAsDtt))q-k!@V^gj=9PXMCke+8aylJQOb}Q5j|fXZWN^I{T|o z(s@T|lFkJC5;~UwzrlOm{dGDw6x`smlWQSO((c%uyhnDa>fhr*Xx8`J>$4la-b6Tb zdeTnL#ZI)zuVJUSsu35pD~f9;pF9?3V2_&bQY8bc8Hf1}lXQ|&f}rT8*!N7W8m@&EE zdBA#LtZ}K??stxSFKGpk!knn?OJCzR1!>y=X=LnQ{bsT|wX_?2W^y>ML+2peNoT1l z4-mGQ9PdnyHv+A_)V3WuLu{1h$+o4+me^wJlysJq!#J3JmF-J$Cw9(#DdNHxiF_k7 z{5rV&oU};vF~(=Dw=Kpfw@xg_xVJ)FFJJLr1bn+kh@$e@Wg~nFA^Z2f#3#(Sw&&}% zGK2aNAnL#}2U?`%!Lnom`J(&sCcci;vhO>CCGLNxREea!XjQd*xRF>+Hw4eI69F zSNfo!-MBRR?M3e+m&5F`l3liNi`s@TG3GGt;qdDrl^AuYwXc-4$7UbgH~6iTwAW~* zq@6Y7J^)C&mJVW+nC4G?x!8DF(!QyeCGD&_%%cb4{j#18*mIMF#`{Cjt)!ODRfxUZk}yO`9#L% zz&*GVwFRz$%X~;_U)2_r62>&xbAfaw-cQ_X4x<%i1sy{x`T}Ql(z{-!qIai$l62nP zQAy|B9hG$6-BC&B-A&~2xkB~}TqG*wWmqX+gOHa75ndUzhfC~xSsr^hNUF+$pkS#+ z_Xr181HVVVNDa2DeWr5l-w)7@tMBEr#%#VB9@rXmTp_pUF82`~IA4*uTvt z_lx=x)^j)uf(HZ-F-|1b0M9KLijYZvIdZ*K*;RC6eQ+%9l@A2(R$t}r2qyPw{$Hwx zW4|yjSN>&NaR1HDI)=1$aN3S%mWF&UzepVbJf1lvM544?8UGYwSFa^(k#^P8`zqLv zXRd)eg+I~wOFtR99r}@>D|tL`H0o0p*|H^_8ka5U)VMSr^V2YT+$yW#{y}IpyYJ+= zL7<{@`S9FeCf}*qI5)_>#m!Rl;xdf!g zM=gS@DesN6FiF3y!oj!M%`-rLN zOgS4)oK5Xv6A_{}Fh*np6GT2RMHB%sL-29%cN3rN;J_1!XSOqAbp#W4*fu59nv3RWQE&Bj6t<SC)wF>W&`?++Wr(A)#5T|8^# z!Ec1w8#zrdi;&I~vjmuCmH{)&evn>iI|I1iMq$3f_&Qwh>y4c>EBtTn(L>DfPX*2c z+QdSj5*z(XptB!n6JY@qS0vCT${1^aJ;YMR)r=b%k1+NLBxxDrM8;Oeg^ZUoUeCCh zaXaI4jIT3>1*i5fM6ck=a6=R^)-XnfkV`MdBF0&a8yW9o+|9V3u_Bc8M>94u&S5+w ztTMbecC`2Ikt+fi!^N7OxguWN4D2a(0<*+ZK&N;C*pIP_aj1A7E_LD;;MpQ6Ef=R$ zj{(jQQ-B>f**sS)5|NDgjDvv7#JRny#Epon3TJlr?$ONlX0|V5`!cp~!1>Knd+lO; zQuKhPkmO>Qd&S4SQ`p`t<0u4qw|G5$nIxTMa)&7By-YqSM)iJDQjXqd_xIWTeRek# z`7#vwGVpanvcDvz_BPZGoJ40R^6PE4vrbR;)subo)Gp+!C;RHjzP#uY^2j=e?YYN8W>2W)WtY3h~k~h*ce11bg_K{<1WTSj3SscQy2#_PG;<4 z+`zbt@erd3VSUDdjFTC=7&kEPVm!nsLRp`2Ame1l#!yZb+n2I^1KT&UeHYsgF{1NP z3K<77PG;<4+`zbt@erfHSO|T_fsB(GyBIex?qWQ|D8gBvaUkPl#xBMUjJp^QF$$d0 zi0~N)GEQdfV%)&Ei}4U+N+jtIWSq>nf$GbyxzIiHBD)4TeT%PvNdNA?uPfu*D~ znX!v;1LH2nLyQCaQM}8~c%MS6B>QB>4UC5vH&s&_4l}0JkbMf{CdRZ{a@jDL^LrMD zz}Uq&WhhDaFdnvW7`dbjC(T`qhZw~Oa;YA{;WKuz%W}4FVEZn{fg?E<#x6!Nid<3{ z2QuzrJj5tQleCL*1LH2nfnzuv#x6!t$KfyzWZcDgh*8v&bl2D{j0uMrQ^t{fAme1l zF2)U(eLR)_2FAnVDPNneBV4|Y(1ta>8oX;e5KD>Jnt-{O5O`Uizgkj?wL`p$fti-X zOpOk(lk{aKe6193>%bfYvk>NBm;+%Bf%yf@vtZKyP{1gd!{8|YwDP)H0BxGjGe{{#+Swq zMqjhbycIiJ_Ly&&ADMnWp+1>Dve#Uv`zQM7<&frPGGlLfgUln|J@UGy02Ja6( z5d3cN&%u!)X(59{8baoT%n!LFfB z$jn(l%N}1c7xws)MZnhLrNA4DFZGgA$a(pH#_v``&_fmavk!16dZiNM(JJuUCwih1 z6VW=9I2SDiGi$UHC7wiEQDTpX1U`kd9U?9?o*Xkv{s!;~} zP}vVSMxFtzlLLVDvI00(RsqM!8sK<22sl9w0Zx=dfs^EL;MsB{@EkcBc&@Aio+rlw z8{~N40yz?Mb zqLgqVyu{fNb6|g3cEJ7&5G5w(0skTA1NX{>z*p4 z_o)@Y2h`=jhtw6oN7R+To$4xt{3x&wo}A7=Z#>V3aI((;V3SV;aEebAaH>xYaJtVR z;Q2m7(8Gse#(y?u`ZF-YzexN=+$sJh9uhBMJ?ncBEzg%eDo{nJB6YUK8Ei(zPI{z`Cae#q+f?^v+aIcFZ*cwh4w$& z_u1dIe`NpM9_-)czsdh@|A+j43g{VB6!dAR2nz|z4tp5SWY3A?z<-G25hxQeI0|JV z21nC3u1jO^ijiUlC>(y;p$#fU==GQCHY= z{JsaQ`mZJIKDybkmdEWAyxT=?((T?BHVwb^T6*M8e{Eq`(yfSf46@*FK7RwpvXj=| zvITxm^T+rYit#ZFqh~noyx|x@>FY(|_+2aW|=HMnYV4Z<}T*AQH1;Tno-7%uvY5y70NIBh0rGew)J+Dy}CrZ!8p*;No8}scoJ_43o%!_cWUzjZ7$H}h1y)K z%_G|UM4O*#^K)%}sm-so`HeQe)8_Zu{85`fYx9IQG0))gGqmZWO+Rg7#=-IcZ3byG zM4MsS4A*9)Hlwu}tIc?ACTcTTn+|RE)MhVj_SR+}ZDwgRN1J`MnXgT!HjA`bqRldG z_S5DW+8m(G3T;+tvqqbPU{bvelIMp}y$#WPh_vc)sMZ^<-G^(vk(!UxdZV>ooi^i@ z6>hw;!cEjXQS*`D6yIoV)@gIBHpgpoqBhUg=DFHz&}O4Ho3+`Z&1u?f)#eOsKBLX& zw7FNC|I+4um{cD7)n>eZE5u8hzohvqtQR9**XEnrd`p|}u!-4*=I?9s1MU8AZ649) zCtCig`VQwS#E4JT?RX0}MtrXM=gcv$*7`qc^Ji_I&?Y{mVYP2<;u9LolTFK926HOD zh_z6hi96Cca)o$aeuQfwRxuwHPpJL)73m|DZ>(UG^lmT~;>#eT)T`oSTqAHz!ZiWc zDEX>rf;k1(7+m$Z#^E{#*Lk=mvq3HHnA(nnWY`qoD^>DXs&42UIOgo9%#l2=>O%H{kvT z+~0uv8*qOE?r*^TAlwha{UF>A!u=rJ55oOzxW5hex8eRa+~0=#+i;IW{m`>WBJQC{ zxRPe>{))V@`=LPvYv0D+5;_T$#ACaAo7l!Ig`vFRnaX`M9k6vOn(2 z!MHEu`<1v#aFya34!4nb62iSr)We(ra}utzAv*`xxw!BJKz#SlUrff;h^q+~t#?kr z)q)H6KYU>?NzB330hdl(^Ke~&YXPo>xR&7h6RwMJb>UhHe;4Dr4Br!^F-24^>}<)) z6AexId2EMK-O@aK-b`3J8s<*BpmAn#;i&fcEpxR)%YxY+hlZvC^6LaN)O9v?wl-JH zo!hu@NLy=X{leKTb*&e+oKa9nDhx#kyxLh&Q(IF}U7251U7TN3>&(k9DJgc=<`)&0 z=9iS!*3=Xi=2eoHJb}pPwOHxO!#AFq^7E}UlD&YyNl*ya(#o>pyvmxgg0h;D%8JUe zyo#EFDnwLJSX^3FR9sbERG42_m5;AO)K=!_=NHwKI*aq1H6=AA`2~fA6~(m$)rHQQ zf`ZDDvb@To>U>e0S6Wz9SX)+{UsF(8T2WY9<18#LF0Lvo%ySl0)>PNjRy)heYA{n8 zUY{?<<%|CH?KN%lX0^<1Y?|3}=9Gp8=j41brloPp$hMga>ssc_YiVn4fzyb2GiQjjqDeKA)b(!&6(HOsTH|=N42-lgn;eCTV}P-U8r5$@y%{*gMuX+ z-q_YStz|BSWI2qS-)2!OQp;XBZ|c;Rx#Q=yc3NB~p|hPlj%#VQETdZHQpJv=is^vB z9ih%(UCXptEp45UaN<1l*NW9GP4lLWYi*ei)jFisn_H>$c5(T(B=CZ^V6~2XF+E?* zw%SEr0l61gZG`Lv1kM7aavE@YD_~|jVC;~#P8ewD6;q~I_S3iDLJEZ7v@N`-Ksc+a zD@qCr%PRAVN{cHhOG}(pB}G+vg_US+)rF1(=Db2m1(sqkZooj`1WtlNz-h~<7+xAXT410ufEZz%1q+-7_3a=P9aaOQ zdI7DUyRf!>?ySbnUvo=5jw9m~;FBt+k1`*^CIBau>;(i)g2EyUZc`c;cGR~IZ*S|I z?kp}6<49m>=M}@6Urb2_QYv8ldNizDs2#mWM0P|>2;j6u;dD~)428d?S5QQec1tCB zEVgo9LP;bjAaD{C5|mitQdsi=r%goxX)ri{ORbR97)q(Xv`=ZNo!dTZZ0FQcQPW1W zzMaWDa^agv8O2OcK;R@OEECnvg6h@_hPO}2uK{Uk_K=3AGSMG`c^EcD|50;WFKFy+ z88U13%oZ9+a8GH+;LzFFI(`FS&S{$*VU@GAvZ}DOsKQx*v8A#E!(B;rWoc1ONnTN2Nl9%5X6d0Z7A?*ZD2gZ^H7?qSE5K}c$_HQ zy6KH`q1@5XVOhvcPs>_6X18}hW|cCRCvxoKgB#~gnGe4e&CM+{Dff^dqweusD^|>% zhP1VHHVhiy+BtpHTvSqrRU~!uX3uV)OWv%abZL5uP?rd}wGerz<sY&7@zZ1x}1($PL| zZgUG|R#w(dJ<1=mKXi#&|Rd{*4>e(``w)yI=sTGpW8Z%!mXG+y9EYCJ+u`T*AT=6 z1z?HlFw=mw!!oS7g21y!Yr9pTo>|C{wox-1n_Id~MqF+~I>t}O;|%WPQ0PD+wknvKCfd?OQ-93ZA=TEl<09zz|ljf zpLsv*33mYqtEx$TaAU{xDomU7WJ;%7)Xr^baSdsx%TCUO^B;s(GNL$9^%yy65s5 z02UBtHQ_0|y}ErK$t-F;y}KO;RSm{12~ypbcvR``MB|QjL9--A6MOAq^?pqnrdwgv zVSqu9R16~;XQ8XiZK)%Z99-R)$=J?jH^-gQYAS9QQXkfia&)^)(UUT|t#((oS_Gz4 zEpunjZRtb;;Hj~qgZ@6C5i$)V$H1^&SH8GaN7|Z)x`OcBQujL2^JECLl&a?aG6PDxx0cWZTxA){hesPCvodm6k{)0Pxha&GENNZH(kS@?O8EjU zKBlvWB`4?VhGa1L3J4+P3r{L|M~o;jT1_lpVUAfK1X*baLJSqZ{I5kz5 zY6&4Q61itmEXhrls2+N>DkCj}T0qRh5)-YzDzUS%pUoHR<#uI9ifQO^O68dtxjrjEvH!F#{8;vRo=iA9=8Y z7C_+0hQ3l^31Gn~xfx8Rx6~c3OH0C}0QCfgwggK}5~IViGLnpz*vPD;bStlzC_F0* zGBX6>I3~BmCYc6WB@%Fjp?-H=R?<*m5?IQVYK+Z=T_wd-KBB!Lryw^YeV|oT`z~=* zEE=b`3Y8#FGbIaC%Z$LF4@ucf>a&CqT@hp;OPJIYMkVxC1&FMPg_|;xGqM12OE#%q zBB|)bP^%~+MqM-XG>fu@7t@kCVhSc*mn5Sp(vYW5B@I*zi_FNi4g_mpk-ZJMY-J-R zEk556Z|DekuyDy7$vi`t>6T%c$Oq$CHs%R3lAm-8t^;J#9OeQn zGP3is1xY{(vGOsnB@ML-F(zi0@{{_M3qdlHs5ljFqz4rhlg63l#x#yV%rp%IhY{b9 zBv;5Hq<|ZJNy-JAB$g|YCPB%7j3YU63lJ-MQiX{l`r`7EjZEX`0BkS`DhWJ+Ua3qd zB3C;!G8YRgB-NJ@5G{gh4CrQ7QVwQZx}Ma{t{KMcBoi`}k`DhtdIFwVG<;{Ngh9|~ zj03s2EP8gutmP`0$pjbR3#E8IweGGL#kFITkHe3_+_bu9)OOm=&Pzxl&-NQF5ixToaQD zRwM#fT9zT-DzIr#1%due%LKA%T_!9sOMnt|Nh2vhP+rjr!AbC8q5;OBz!;?$+}UK{ z$Cg4v@*u7q5e8%Xfx47TOh|_3%=iIODW^bi!HSc~rWeYHN$W*E0WDEu*CbVcllw zOKIwsV6jD(0M;gpH=F8W7)7!;CrQR#VgDWozf`K|%VWBSXiF=ra|jkTa}iAF<0ONK z;4@q6z|-_J5rOzw5U-4o=^68amK6sx9U3Co^@RF;QxO7Ao+S{xg6w2N7AFx4!3SZQ zl^7>@jlzp5^JH{l86l5kiv>d%&dBECY0e2zMq20uVn8HG(sPC!%rL={BN_PwBo?gF z7*eoDiV@6cAozg+Wuu4(Rv5wZR2V~9sGg=lWeYRcQ$9+pr+kD|Px%AB0_aKwTfwbVxL9`6pi-eyPs#*K z?e=e4J~h=@CR{ALOsG`0b+8^tM01Z8nFyN%b%PXIDI^Ypn8_Sql42;6wV^YyeUe^p zFu}B))xlz1iqW%T{vxrcmW2Q35dT^4dOmGp`FjBuD zeREJ9b-5-%QZeX>#IdePRw@`l^|aH0OV*|1X@Jy;S0^wSu7@7h5lMbxnaoBP<}))~ zp_5D_wWNqPSlrZ8$Q+gc@H&epF-Niv(fo#?JGVe;E{KVl1aT&qR(rru8zGVu0GiPz zi6(W(G9;5=BnFCF0ttBrJ$U`laM6wt3Cki2lN4`h9L*7WQZre9!i?s?G$|Vz2@wc- zoluHM5g})ZD;?AeEITlbiNpoWC`mdq6Jc`z;?3?Hapi#%7`UkYqQBzmL>WuHC0xW$ zTBWeYK1%`!RwSRnUYwBzh)P1AC4o?aG@=#Q<4TKU6(tag5Cl)NRnby|XhDGi{N0%u z4;yT4K;I%HY?^9)N|&{rfmlXMr``R z%3sQw2%V6&UyzK>Fgpi682!z@3AZG)c-Hw&sYdX;KKV6Xi%kEZhIaWefY@h+=|w>tNR7u*fSo45oqR zzL!B}tjwhfL2)qK!U~6k6`^%S>C(ZMBy6uJ9+q+l+?iA&FjsU6hW(DZEEqnoRM)CrDwgYbr_&H$?fSptP+=Wy_TL01#Z7P=f5ktkN$ z@JMd6s!(oW-&aZo7_^FSjrD%8J~BD5GAhVtmA*`3U)s;e`KGWJ$`SUTaU|5mnsT`u z{AlbtVu_X;NRKch7nW?~lJFBN0tPcNP^)T(nN}p<;CpFg4~qKs1x?*Lh%$A zG|fdwD}98HxrQ8Rp-(DNilza!UI-ND=sRh1A{e02ghd7bW_FxCNJrzeg1quHpA>e%LDs{j$`l7-yYVj@RkGPIOhdm%ea>45T+R9I*d*g*`lr(;aS zH{?~c8q47lC(Ffp6h@JFwNU^jAsvt=zEliZ3@9SZn39npBqlQwEP(>3h;d>pMHXtt zGqL~DqNzZ20aCV9U_!l82qBi_CY4EY3nW+a#YyDNT!BO~d&1$nbs@T!Q2q1#8I>kg{3~XbTAPdz)4IbfdwIwo+QQycp>zexxtLYs8k`8 zm>_VTD4|IJk!TYmIt<-g*s3nX2t#iUB2C_UD+gPRpxx@`6xiFrcDft6*sMI7mwG(S zQZ$5k6a1+#LvlSxF_OquXB|S&D6CYFhLltB)O4OwrolQ=54r!V@1 zM2tbO#R`bSdZNW6iySdg;Kn;#%NGvU?}&>eV3 z(w#^esM!EuSqdV>5`JTEDjRAkjL}C%T%{1nViS{ADwx(LN(Ioe1&%NfNtd!>=^Dm5 zEE_ZOBnT2_j~E!CACi%4U@Kx^@kz!!?Brn!Zegi|@{A^$Nm4jd_^g7>I=eIjILIZC zgpq>{w|Vf{PTPFRlvWWf5x47_rFzg5lIq1hxfSKGrapg>>>ULY=>H;@b>Y@YTeS{I zOcbHYRzy2y2$;Qhd!-OsO1&)`DUNyBV8Oy=-s&k7WZtMKcxj15aFHcgbP<~E%;ZucWVG-EGVU3Z2gjokTw$8}>v?G>rbmr)a#WUs*Ma_7M72TqM z=gYzpu@B3{Y`(C(Gnuy=AI_Y*u!2w;OI`YDg#gt>!~Q$3K(VX~qP zwPf)oEXg5V9NX{QHDD%8N!=I^w7%I*F`d|5zHoIFt#! z3!&LKEp1&>E8O^~#cAc%I021Yq~Yq1OSqCau1)DY-H|s5C!k}{$E-4~t+0%if1N*$ z%Rza1+>KH}{f$fK{mZmU>Oa>Z8t?+S0lZ)lW>BQwrs5oTdsYt?zz|RFEc}bW+3h^$ zhVFn?NHuWX{#`j8P=^WkwIl($*bIX@QV~+B#6C2_>8LFmF?ys<#AxX;Le!EBq>l$Q za}d{yVaY%?_8BZCjXI5M#XaLf%9k9Da%h|>zkmsZlkq44hJ3V;u*<}8Ue*{8j?_j5 zGdjzj%5jZj&{`07{Ah$yS!wAwF|QLbk@}IsYT}xeZ$mreO2u6^R97}@1wmJsC21&& z;c|!a`8rrZpzN%ACk$GaFUNYkV^KfB5W8yeE;CbcTCwcNlusqVt_v$C9VKw>%jb$= z^DP(SnS`E(v2jfYjHD6o${;MjA_b$sHI86#rCDxG8-!j8GmX*-qtOFt>0SW=h5}Z{ zAtc>gzJx(sT~*IZUO{Jdnn-!ns&W3#x!~*0@a}7&j?2!z~IS=wmxz zdpPD%B*#^lA_){Q1$aO>Lw`>r`V_9Ozox^NzcpX5U~2IJPOiZve;S@wEAeotLQY3| z$dnox@94-vBiOU6O%>M+-o>4HvRO0|@w{t+4P`A{#^Sv>RTbC5HN5cNAime|ZY+F* z_+E-|)GVX4M-isb;GQM~cv8R}1lVdgF-oc7Tnite>=9z#`NA7bDV(X~WHL`rrAp@F z?uqPb{2XQ8oWc&}t5tjzmsVl}rU@0=sZlNh-8dT|POjqZ6)KsntwP1SB&b!gDlXx? zQmte!^vl_eQ!7<+2U~kvmC_}_NvW2pZJlMjvp4>8Dm$4=f=l7JDk@uNmjofJty+3h zY~eVU1mu_5Qju+WrJV*fv_<`Dbv2cXJ<=jjE&SQqtMSj?kwd#F36(>T;A)s<8V*TU&SQxL|(BL}n`Jv{}FBY7Mh z(QO6`EnYG<4z2}qFANrkadj!mPyxWM1+E1$+}>iNMpm98tGE;{Kn4sAd}@uH0@Z3q zJM@hTvVt(eX&5NfRwZ*3y2J*7`i4QE7jVf@t+wIhj%Xf618$V*iM|Ts;l?=VMR`CccO?gKx&y>ACxRDvc8MhfSE!l8 z4voX;<3Av#pqHAa9}SW>!B|U~fEH|&XgH`8G{T)Sx(hiK_;9Nl_~VYs)%37)x2H-0 zcbd#LqP9atVINhMAMIn|89Q%Q@dUCsI;w;&$yEX-5SqKYt669( zUXEON0%ne=!4db!VI~4!Id2`Gf_V_2yOHb@Lf*#sp@K@J9Wahz$)Sz|=Jrg$>~ zcnTwq3mnmFVFJ^W2I4s00xGf)j5=W~A@yy%Wj2hcI)M{+o&_H?&b*{CU&=#q*=S1Wzu*b;>D)`Rwo|mRW+@W3Td2#hKp%2<^qusMiV#&#tUKt z9s-t&Myp*^4rq}KXrZ*XwmQ?!K4ZppLZ?%7XM|$ zc8X>}q9FF;T42YdfIDDb->Q+!>^MpxD9qj#<=cATVeg?*DeP_SoRy$dN|(a(0KJEY zTJT&JUe^I4r5!!gAbup}I6B%87xeN(YVaNvryvgGiC9}q7?;8;pfY$;|Hq<_)ies3 zGuknYhD2>~*#pm5QtMF(5j-|&{t$#Z7tk3rlYEsS>$tnP3n{4W6bRzv;_gWOa&bp*iCW4)q>&B5 z)JmZ^;w>m%%1xBen`oavY#1RzSBT!CT>zKsP`nrorG%)AUf_pJ-owc9o^a=&GGP=z z*lb+f30O1=?kd8IrErNLW-J-t1MdQT6QZiC?5Q_uwWp_;jrARQJb`Cw>JEo8#W+tj zL<&LtWaG>M6y_*97mX81a2R3$5g8$Of@FBoKQR$zxd0rh6I>p$r7gYe?d`o(j%AWs zr?od1Y-d-=;&ySjcxZ?;xRM*Sktl}RNo;j@&?s0_;70>pRYWDIf$SxRXyrtbnN^Sy znZ4u$(8ovy^yLYCDGO#aM%1~~D5Kc=D)i5#@EKANG7G?$UJMlk-bZi~lCcpd98oio zjk(lJ@Y5oYg^`1C02Im4hgwVtg|aHEz=O&T86-k!@KiQ{tf!~FnjCoB6KH7kDuXv! zGK#Iloc3g-l6vWblD&kwP#Ob*RC8(13nV67n}oN}Hv$*|j$*)Hc&Qkg_Y_7F9Yal- zjh&s!Mh;pu(^f5zlbJS9R0?MjeNlp3fgsD37UO;Gwp*$g8pe!-vCF<%~{}UImUs5q9<jg7B)U%H)O0QtA(2wv(ZuJm#&8 zw?jhWD@95Ic#%>@lNfIZMYdkZYe(!-Mjb@bBHMbZI;=@d)`ykb}6bNB(x4M z<91LfT#6LZfKbN@#{pgrRAVLPy+RWSVzbKLQDYAU#fHHY4@eqnAp*Qpp~M4x%Z|5! zLv4$PojrVZP8d3ZE_#7~G8zc-Bg)=R1@Mz@D`FoehDxdQQnKL?oX`T)HB>GPTUdXo zL(rNfe6a`aDB-7G0X1EUD#>KFtl6)rA_U@Phd=bm20wbMNUIX%ZKkaW>I$hT5dL{m zeR-K14{$>;1z*8kuL2Xs%x3(N@MTfW({>0t3Av2w-zFDzrN$spblbhLfIV1nQa>q>l&f0y(EpOhzTmO9U@fk~#T5(^# z)SdJE?)tGiPgAr9MfJFLjSMtakW<+pT3`fi1k07j~a+-251tfd=yQpw=k> zCQd>n>GAgM+tJW|l?u5G zdZ$9XKb(p!#N#ceaE6nA%ct<6iq~)7Ch{$KAHE6i%Qxozc#UH8Cv!M8*Hm}#?a@zL zD!6YxZKV;$OKAKqEd6AKV)uMPqrcNK4+^ktra7r+)f(s1NX`6>s;p1h_ahVx8C)Bw8h?g-|Kl2gDxHE9P%)^Aw`fDfw?3J zRAL0#{Y0md*mQ~DCvmBgU@(NP2HTMXnOyK@4>{CQi;ua$v4o&XfG5Z+3E>dfEgniG z1TfxB8Uh7~$;oL>P97oF5#To$#^M!LUR;nb#0$C2@sihEouxonI0VBTt65YQpfOQF zLZjhH`CuH|K(m2=QWo+SQyx3Q?mk43tbCb6`10!=e&}@+F^GK6y)(ZxtYx zZylnhB6*Z1G{oYgMARH}3#q@(tOPbD5;UFF)D01Uz-cnTRdSX|A>O>Bv&;(IyqKCn zuT*LVU@0~8z=lUEKkztK=s3ZSI_?Y=g&_!g!0rY_vI;;n+9TnW5N#D;6&;R=ShyXz zrDy~I=~!k*OcKGNw&Mg8g?7SXVWSgb$sxotmzqrzLUU=F2pWQAnvkC*B6ck$A~zc{ zaW0Wx5a7ua2R%fvsXIxAT)&FgZx%_>akr7g#$Bfy0)gaQwjq z4H*)-OROzsKFWphifDj6yn;{3%0U5;WvLuF1XL-h3b=_%Xh878EMRrRDTOmb0I(F* zk&}7t38&ztER>FHnk+v|QG9frY&|sW zgp@)B-mEmrNq)o#Pf{rXx%q^nU}*#gGQ9}eIgK>|LsZtK@~JJD!BQF`v>Q9lHW zf*qWaTbO~8>MYiUMHV@JP#YmqDS>HFk>z&mMa`89A&!u>NqH93(V1}3dJkK^fxJ=~ zR+_>>N{$hs5d#v)u=>CPnIAkJ6BJ?!!+f;^Czs-oRE$&tzva$UJxCJTjEoKteT5>S z{kQTHQf#a_Kx(}u z04k%H2u&uXQS`9_u<|JM7U`WhB}pe@fKo{nTKOrr#Y>S6mb~PxWbp!p6twhXE?cPV ziY0(DNG(C#x{wX?)hC+)1F@p(0wozxI~ zm_a6`CAU2YY4r4N-#`5fQ_wXqSJEHD+2uhIovDc!9?_+6l|vR=yMG;I)KsX zIG#S}cag$bW;MixuS=D4;a+Ha2)DNgjax56TD82AD<=!AggN zNlhR`JTMvf1qWu5;1JadII8_#>t;Gq6MC5ihW)~z8G0e{F zQkh-0W*6l}?U=QcS8!2Y!9{rm7v&XPlvi+(0nU~TPxj3EJXhTuwSTR~H##C- zgL6jNx_m=!CdUQxobUcs8gmls+`bxIeXL=pNQ@e6W5p${x>R3|bHPV1gM6F%2KonT zoBQIkC0yYuo-15p9j0kZr>#xx3R-AVvJ82tI3Q?h(mcpNFgP$ZEk(=zkR}&5(GF~Z z!f{g4sPhZ(^>5NOu6uh;+qm2mI{w!}GtgwpF}CpY!?D_ddC9&hhHSr7gGsM5`Qesq zUD{AT6Amc)1qR>-ewau?(vnmC1A@~6wfKmMe+pgX-aOeKpK(YI(glVDH|IDdL7b}r zh!H5vkdW?h1FWm?oV|EXm5w(m;&XAU84JaI8#uTbrB5~t6+>x&*hs=b1~g%$!Xw)C zz=u1#;&Y3_5yb`#H3q%Ld|(1w&NcZsz^6&d%E$RB4NhMg@-+z5N!L{PYOrTn6B??) z)gvaH)B@Do@mwf2@=7N@|9z3H?`UBJzCLT+EIQuz@0-(t=Yq>M=bsdX@8R-Xn25pB z`Cptvu|6K`D_}NGi_=X_jVt`{3_eH6b*Gc4Ml{|uP(wEorsA$KAd_^uR)fRI8r&VD zG2+@ccH=hS320{+HP`@8w;pN?X_^8Y(9-~~*a2i;jG`Al4OVJ~na{=z0ImZ)oQGpK zIXg|#prKE0QvOH|-`nIA><%VEt*Vlt5RfgE*AE{A7UQIi`evlS7HaGl*Of}&1TA4F z|5|8DoozQQGABSAMD6?99jT8aSNX=^WBOSEzq z@RbhGBEQ3;t(?AmUGrsKniQcu00nN(z#T1s6*w>&<;!a$ z^r@&{_<9BdGj%3c_=bii6?gWcR2|?aes#l__Y_zqjuoPMBjBskYlJIAA*=D7%Q1SK zz%DI_lmi$OJq$QGMR$%^i6DIQiuwKDm&iB86}}|k0U!`4E&MrI2NcnX?G>;F%^{hG zzEI%HyIZdQ))D&W_xA&dUxYYPzidW-(W_gRs!%km%@NAjgG8gA7wfkLo zG>O;`ce`nRGQBZVI8V&*a94bB`x#`DxbV1V$8yuhbxiECd&G)SZt+(jrz5^aLQ+B^ zN#6k#QEacKDGy#G=o}#$WVomPJry2Hnen@Z%!&}1GVG- zhQA4J1TEojF}XF8uk?GSRXUDKgl2=QX1n4lcaE*7>U8Y(Ov>}N9?EbIYllx|MRw>I z)v0rruF)~E-MYuc_vqQHcb~pV$tkJ2wDf@)gEF(S^@g0mxWYAWNdC}*VOsxyz@Xr! z&6DmbSTC{8xD&~R(Uar9254EkGeI*A+CubK|x5`zjR&)0d5>&6@ z>E&HhQ>%8Jy7k_x-=JZm#y(Aa{iq55u-gA@G5}Js=V*;7pKZx$ymHN<1?Oh9cT`Sp zxbFMqC*DTY9J>GI?-xIqI_%yLC6(tLs=9j9FY^QH%-y@jY24LGKNcSCu;b&q%g?Ml zv|YAzWwpDb8!xK5b=sbJ_LJ@(CRf{Y z?&Bu!EaE4$E){FzZf&3uI5_okH%ZapEUFvTXggG zlpekIe=~K!jjjiG&zyDlz|4?{HQpOe==P1;5I4g0t4%+KEUW+1=#^VMY%_NZI5c~8 zT;A*7Wt%6IoY6hr8QlK2gSU64j)**Yp(4zTQ@1y!7$)XPe@lJ{b_dYX72`>KeP8AvRU+QyRH2WdOI)s z{yx1M-5X0PPT@1n-7R>R_^(R5_3d%t&;ExcIiYqxENOKuX7X&k>lk01$Iaf=wws$Oj!fVBg}8WF7<%DrO7R2paJ^9m z7l*r3=ue@tb9AZfUc%$!kvZrs12XTf6iayE6bu}qhy<8Kgzu2aqBa~qA8iHUl&&Lwy)`oKwiRq| zD}oT(lZ(UI)Sfug*B!1XE(Rx0>8xrr&iKVpR&JN#mp8Nt$%casmFq%kEc(qroP(s3%cRn!;p`**)kRqxPN>ouXgy9t(iuwgS!tGHy&@b*c(loc zRCKa6y@HZ7ER7atnT3BrIDZHjux~)~>||~>C!NPMBE0lTNo!S$WQTX;aCFZ&FvMGYRa2|w3bwV-JTXO zN?6M12?)}eR`I+!>!UB`lrM*G)8ePa2~A%-VHCn&IKFYsGlajO7>e-0O4q^5JSS$JDYF)|;WV5XMR z8TM4vOyfa)h!Il?XPa?5Icg_tq8`!6{uK-@eTm06$9Z-dn9geFVH`o1%q3JbwrkNU zU!;iumTFKdjW5-g&&C?YYA%akTCU8pqZEWPDjFjV*Or~~r@olrD&Sh6mK695XdP$| zYNC_aO)#oKY6_QW)Ynorc&s{GeL+>r|a;A^Z>NMA0>4K_IJl9 zQl2=ZN?{{PXLTtTji(9NX@t)Y|Iz_x6GHPaqkNH;W`!SGK&R5_WU>i93Z>f8Kx6$7 zLT;)t5OpS_-65zq1ilcYNJd^dQ5+06VQUb6gt;kr1~Year13|7f5cI49m^RE2*6T> zB?=g7(K_lA-LpWq5okbRO3w;{x0dzS7j^wF`E!>Ar(XI61D z8Ludb)^^cWvkGz2+RAyZM6p;_$Z7q{vW~olBYQE-*a`@W1x7Q5)?4_#s&+D6h zI{SR*l%a12&#PZj?0}k;Z?(npdnMRVEt9zcHD%pD3jF-VtfwKDsCTmNRIJ!o+Tx`h z46wjufbJQ+3y+LKaK)_ttt+h@D%- zYl{92wC_>8+^weds$r^5Ll@(d5hu2Nm?l8$@2~Z)<`Ceo4bcYp;~Uk%A${QufY)F2 zYEA!<_KEG6zoY%yV!pODpfGmwV%`a3&D+U}d7e9Y`^3~u&;L|hT6eqVvpTC+I;o!p zeZ2Df&(F47@>Q{-*Wjb|jpb}_aloRP1vxtezmoa6NB5X{&@M#4|X?sb-L2S zTZ4Bm-_%uOGubih^Y!gxlc&}m-t_Ucr|p7A8lwGnf4D7Tl`-o-@cYrW~-76--UId+BP{*(!ZJFAfWs zFs(}5SUWwpcg?a(M|KYg&#U{hdU^cUw?10;?dXA#xg7=`JNNDMhD!pU+zgC9ul*_e zK-R71!}*k2ZgJlh9D^bJUc>b+I23e!@WR@3W@v3T6 zv+X{qUD_snf2r;4^~pPneE9SMiGAn3=+MW1{KW(5`e)B4pUNNN^RPd7jNPr}Q~f(qP8LnkO4gIqKhd_Zs&pMa|#;Wb>cjoq6>< zKH=iRM^itKihlF#tIq9ixp$b4t*H;U{&RMzjxmeko0DV-=oDn zT3pFIbZ*#z!w*vGFEqW9-Mseg&4@2;u7%Wc`Ff)=^_L;BFRQur8#`%t){OqSU8m&- z+`Zo1QTh0Dm!>stR_0w}emwl^3E$d>FBI%*6?NA+VC7lY3~jM$7}!9vzyj=&9H*UT zd`(^kS+qqH{v)I{K&z!GDR*mVA^qJASfOYS{1#55=rmz@xUZN#E@)-~U%T- zAzH=+nldkOhLFDh?M$jzR-PTmh#lZuAI-Vdk6-3Gd-|?9um8N*xogmlCtG{hTG*~e zqs$-s#(w^#P4nuCs2!sZRPw&kEc3AIdHcuB_s_LieKTyLKGg+4WS=<<>jrzU6Ge*EIrRh7fpgo0&J4evSZ zE^*7>Ju~!|KW{be>s+&I&jyQ!K2*5=>>OV=NGc##7ldt zY}!@h`yQR|g)DOVu};)Z_b~c6ZYgcXz=T! z>;ny^`b=%xEN0)0ap4mW+IBhg{j&Ccrdhx1Ukugs_HpY!VAiLtV*^F ztMMvBP#O14e=>gAoa^xg)qT&LH>KB}Xa9-Ijg%R4+kG({HI{w9#Vdbi$ju*9kA{a19aiV5+sNh9Ok*ZLJNBL|veEtzoxfVTN?B>% zqk%66`pzn8)TU8p@2HfTwi)`qb3VB}=GoqFu7+k;l z=nc>6zqsntLX$CPW1oow^@bJOOb6O3ZI<(m8niBMf}?P;hoGGfJ$ zJ8c{3mK^BcJ$d{Auau^<$6ven^u?2^i$1M?&TJK}WkA-5iF+e(PWCQLHWY z7zOoDTQuvxn{mBU1GG{~ON!QNL4ZV^&{pnW$t=V}Nrj$gQCaQ%9U*^O{8hAmmW&Gj z+6v9R={*z1zuXf)vqhCP@z)L&51;RGy=nAJ^=6X#+|s7rK_W zRW7Pt=>D!bZ9VOvm??^RuF2)EYZVQ-p0P>$-c0%WbB}esT0DLAbI8z!8?rX#+z4&s zY+u8FT^;^PZ)3Gtr+=M4e$9(zb6S0KB&2fnw*zkXKAzHZ;^0`<2k$L2RBkeOf;_r-Y?EQ@vLEzVUvqAq znoiLnu(^tRZuL=tY1+qsd}MRg;l$H9Jy*F7I&gBc;@3Z_&8ydZ zhm%tKOTA|S@=-H~|9UxXc6-0jtqoS3Tyf!}eJ{^++_JJ?bn`{U)hcO=tKp&>k@3jo zynk`k7uw>g&&(r4wu!2D5Of14Y|7gviuoQk_7WE0=toI09}d{I1xsrMY!-_i+s97M zS74m*8dY;&O2oj*y>iA!J@l**vOHDR$+YN&;m#cXiT|^^qhvP8nGp@!q`A8VXrbT- zYny8W1F$si+bl4suU1hgL9E3N zAfrs6HrO9V8Rq?8H%1WT|60I*RHyl2uUO^PoO;Xey#I0JSdW`EoSHnUvZ7@D!QLOs z=Z<)=ZEseq4fDUaGNMM!w-HBsj5sp=*i&`*?8Q+At+svU)zhwTi@)5UUOc8oWtZoD z?rP?2iGJSnQj^9}AI5czPIYcy6n6KEdUiT%ZE^7`yuetZk;Lo1$k1mFM@aKaizlF3exb~*j zklc|CcZ{y`_-d@O_m>@l_svbq`n_A`pT%EK`0)LCBhI|ZDdA^0Ci-ki!kJz~C?uDIqQ~Y^v zpV}SQG(2>D>+R`(RJ-2VCpTcz?-?DRZPu@KbL!&a{L}nq6EYQ{Qzx!DKDyG}jbVf4 zExmGRW5n9u-3NU8q5Fm!i`T#RN98fDMN#dT!ZWn0O&=fV#=&o1(D%r7>sgbiaE!*v}*BZcgK`hYUOU`bp}9>)*`I zIX)wNneDT?J=&h#R44aI=Y_?SKJroI8-6%9>3)MB+TBf^k)&WQQ?#= zM`CwRb(qJ3jhdysnJ#N%-hdy#TF+%)o zz0jia$nX76k59Nbd;N%=*JthtF=Y4dd#cL~-JeGWPivDM`a{A&M^FqfnId7{4+?pD^ z)AiEj&oe%Fa8Q-kvfk4%J*#&Zk{8vZT3S)>Lk-vLQ9bJz(@n+a&VK%VVVyr-H$UQa zZ?Npfi?>swnk+qd`dEQ`sBPNajrSYQ8uQ#~e$_t~{WkY<(ah%;wByHyPdDfybDa(* z*5B*nHhkvgnG0^kI4hdYcIfc>`pRv4BhGA1v~BxQq;cqmh;fr^t1|~qsdeSrn@ek_ zs8*O_zg?^}eSV-#lOb(3MAdy+V{7l#RoA$+9C2ppbA`**-_DKxbk~e~x;pQ1Roc4C z+BI1Gkz4eoFGJe<${hTL?rL3sM3ZHSvOD9~dp2FQx9+OxE7y6Conq=5;NgBNX^6}G z!1?h#Zrm;K+*M=s!nl%QA-fv)Tl_=HppTmjzrO9-udfH!`o7VbT9KW*}SN^ z%wSce4A%V5F<1!<61J&8t$*`?fPi2yNSL3QH;}yl&FuT{xY_L+%e&m$oLkGjVDYgZ z>K5#BJX?I`_0RKFs?)2oqVtY?6Wr@Jesor+>o<38Z(VIb;M;_luhV{?6*su=%~75D zzWK6g`nbqCm9|WFJCPr-*V+C4fRTf`j|tzld`e`ds`ArAL!OV1y}U2{$l!!-{>@74 zn(HS&`oZb^dvPN|l4QdUe*QW)W1ZLPFMeyfJNUiSi*s7;s6IS!O<})Llbk&lbbqt; zesaCbgPczEfA(fd+=+7!$Mx*`%axszm)@E_bz_K6xA{NjWH@}&v`Nks|0BT-cHP?i zLEQt_k4_!6C4TDVm&zV5-e(}zvF{MJ~%(zVM1{FI!c7C$0gZrZu z_vemi)8*2-_xC?Nd)^q@K6+nZNS7(Ho$UttI{!4bTjb4Cy9T-UP2!E;q%VH|hXzAr zHv`>se^{Y;y#J-E-47{-N=KWfe$=mI`IuV$6Sb!4GiRRP9{Y#=#H6Q9ZGzp$cDQu8 z#;MmEzxOZ(*wp)r6Osp>3Y|Hv-w)q?>V8n$Q()OKTC5nAV8zJ1obxXY zX|!UbZK7@3Bp{G+>b??_1gEC;;7*bsoVxX2aq0?;Xr;?Gl_8&u=`QFo@>QcXH+*WQ z^Zs@F-S{lG^Q%>cpAsr>Z5`bqb?640k7tMa2W|=ZVgKN!Z7!x}jX0SXlKqvF|Ly%# z|I9kIXr_DZpMOkCZxPq^%A6fry@#G}>N|f`aZgUZUb%bX{fz57Y=0hpZIEGi!(;mM zZ93-h7u>IA7gu_oT_^tb(73$1y|!Oj_;gC>;im(y>3&<<^Yhi$#+Lr9` z*y`%)(m%BR^|qfh|Kj&Q8csa0v)cOjaqTv}s`S}M9ux09wjWfqzsRGVNB6uBo9_2I zkYx1r$sDe4<6}Ft@{iLuuIhI!YKf`R&WF?VldkZx>o`=3SGi-=I^UwSF|J#6NK4&SO6g-_txN{M58xkF0L-VGDKg=nFY1 zaa||>T%5g3>AY{S%^>H^UOfVPZ(5X-_GD49>@<{}mdrf$YSI5rjeBt&JJ1+hG2Pfv zE~_rD!tEXPi+95r@@8Xvt~B~KrQgK`>%vEuz=T{>xOCKiGpn{*z*XYLFeP`lR>?2g z+U`zfGf8l8Kv1*3=712b5TMQ1hFWYg3f|ujWCfQRvjVUr1vkze%WOx>uuh<2ZkL~h z1ht@wQ1VYcm&kw;cyr&UunxoVMSk>uvbmspb(G+AC$#4Synx^}WD>iELL zkHWJ8?jBq;?&^bIrWM97db-Q!i$hhyUmuzG!H+Kn*8AX^vF2~v7cDKU|9$Ag(}#Z7 zK6&N0xmx}8y_fLwI)0(|cx32z^3=Y!B{reUQ%ansUe>M4x^{TZ)=Ea7N8j#R+N8J7 z<0kh9dwFm8&e?;TNQa;?a^V{LLR<~wPt zn+V1;9ygBcNupsZ^`i;3vVqv++%g<)4fymS;spid%WJQpYy?x)UDPC3DcRP zSjOGgX17V-T(hLv^NH?_?*-(0DN?RBe6zLDtOyKJxOAga8;|e($$_)tWa?Yn;x$IPxo-)raD@ zUejaSr-rKMrup;6QJ!_LOkA7t-5;yh z22Sa(`*?BEVr7Eie&nQXzg-KTboFWS&z}t&GvU>W&(Cg){Ho{HVUE{BYed~0kUw$C z+ZCsCiywt;8t8id<0TX3DOM~VoL}73@9y&3%8)7P3v0FB6?L)0=;Q4QlSVH*^wURg zcKUvJ=l3p=a{8TV{eU6*>xJp<;A`=s7fFOLQ< zJb!mzlj*y2M`zu!tq(#C8=kd3`pMCp?tZ7M1sLLzw@18w+~z^`x@}xm>}XzCxGSJ2 r&u#di;Muc|AG}cGyCZH}eHKq?f3~3Rj3c9looMpo(im-L(jWg1R`XX< literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/System.Memory.dll.meta b/Assets/Plugins/SignalR/System.Memory.dll.meta new file mode 100644 index 0000000..2232b6f --- /dev/null +++ b/Assets/Plugins/SignalR/System.Memory.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: a6e4fa57b30d538508f21240e0cb83e4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll b/Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 0000000000000000000000000000000000000000..c5ba4e4047a15b3adc61340c781307d9c6e89413 GIT binary patch literal 18024 zcmeHu2V7Ij()gYv^bRUTN+>EKgcA?}6{QMDm5zcKLVyS)m;@;*Lgb=Yu_1~|v7lb; zT~S2E-g_4-7Pz9qwd*(MB!S$k-gm$M_ulV)zwiAIp4pw*-PzgQ*`1v^F=%utq9TN7 z@P7M-&>l#M$DM?K4GN%G(`=t6+M#mRd=D0Q);uDWE2L)%_$dNb2A$2~@%SQoB8M)> z;?cQ0x_3x8J%gXbVQ6TmT1i=l`XCgDQPINyAxqX8N(ea) zA$3SfA#W@#`dbOTOLVfjGT?r44H+U%jtKB8y#PQNIaZKc{-Hzf41rL<1|lh&J7g5$ zHG)^}aR=!c0!}&~DiX31G81z^@`Xh9xFh5#%gfR&#Js{o$VNd5$h!|hLv;{RA*tOU zlrEXtZpx2y2@e^!2i)nG@^zo-qMNH%UdnN3(w{PA!Quw8Hi_^Dp~hubVA*Thp2Dx z1HLlapV|}TAMusaF;YEAzEF`0>q7$sMx#SfRkR_-DBB7Yvd{1Ft~Ji>o&!?%Nm(T` zb9rq*WeR3~NrF`YunNXkql`2HFHQ9rRi>0d(suAkVS^iR^|`y<-_ z9H&ww<+9@p^c9n=2eHE?574MTpee{`UF+VfnQTm~iA*nhk$Ne&´RVDkZYh5I? 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll.meta b/Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll.meta new file mode 100644 index 0000000..33706c4 --- /dev/null +++ b/Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 6f7e3a12a23e295868c60e49bf1c0cce +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/System.Text.Encodings.Web.dll b/Assets/Plugins/SignalR/System.Text.Encodings.Web.dll new file mode 100644 index 0000000000000000000000000000000000000000..3d16c7e9d86d760e037853648c40c16a1ac9860d GIT binary patch literal 79024 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

gacWUoJRrK};zW5@yjFDx{&Q9eKW?|X#u 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

xiOTL$g#4Stgy892&I-=$EFD`b z>0CvOnbT#LX;ac|96%?HoT8(Hm{HrMID$WzG3aLvONt;$Ehwd(I@JsY}K<#UpaDxYD- zYPr+i58bHpF>b9|p3oZ7s#W)D4SijnMdxE%=q&48Xg%eiX{WU*gljNq&^PUh(T18}^>5xZjYlMAN{e^ssu>yR0>&o=SYxRImEe(Z3!!*Q+ZEr-kjN z(&vXYQ0c#z8c=S%+DuPkXvW-VraXIeIcDOstP2W10cN}6D*Z#)cEvgRHNu!8Ix{hO z#WjbOO7jYihw)LeHS7ZRi(}fd(yziQ)#+i9_z{jOap|1q=P({SEquSq=c|cwU~y>p zVa(OTn3;!BdS`i8SVDMO343_kkdqYC58Tj zIRAD+38hRkm1z8H3MCq^OC=hwOC=ir7DBnkvumElvulyYbFW0>-%f~Cc?K@hcm|ee z{F@3D8fL7qbG(Mv% z(fEvx>Ph8RYkZv&OS9szRIQz}x6oF6rBh8M9u&O7xX8g(5ABbayU(Nf*(?f_0TZGk zV!hs-M(1o^8LMz%vC=ePj#k!@M4dp z$g=>YSE|FuUFmU1;_I(0TFHC#jK^9Xk5xLJR_Q@>{>*!K14gPDE!~fD_oLigiTCu? zlxL5g>s9WV_3HP1ExpEgy+BWOsX%UrwUNOidL=4chxN+6^gW>pnLJPyQ9Z6jNfJDJI3l&*n}s@pHOUOuYA{oA^xCj;(Tu_x3FzelE0} zc&_gv;*OXK;!Azk5?>p$k@!yEdg5=#>?HoBZv*j5G0ns+eus&tSXzkB^*c*^iRB{k z@!nU750X_cJ~Q|8;uR@`co+W&;?2TBe1d;GcnWc+e>(BK(RSi*`sWfq7g|Jot9J?U z<>BSTulmm;?uc1LJUgI*_}Z9i;_Cv|5`Q~pBk_{~TZmtZsVAP^X(#a%%WmRNbZQ{J z#L`UM)oDNRz0rq>_YQ0!elE0)`24`L#2qmgi8lpaCB8OBHS<-2pPARp5aQvTBZ$8p zVPBZTvyUm%w-9zgspY`4ADW5$-yUl!#vD?ghL<6>M zK-RG(yY!Nt3)=dBHSWfRCo;!QMtB$Snd5(Zm*xp?e$Z+ zy=`XxRe%Vb^R$`yw*ew>&&oo3I^Ffc5v_>$tEN`d@~{oDhmp@=u>9c0OnjS;@eq8@tI_@MA@-gM2nXjfVVyhyJpVwcc@$>qNG=5(H zMdWZ1Ib1{zMc7uQRsCl9DxSSoMEPv(f7Q$@Ml0PT`eT0y>ur&?-uEryyymOkd_+^d zxgS#KS#o=$(}8~8%tO5S$Qa?xM@EY`uRkd!e*V72oAW%3v2MXg9mXiPV2oNYMlBd4 zS)_|2@j>)!uwT)S#5%<>;tvp)#R2kt#9{F{Ig<1hVHZNPumeX+XNl)Z7YHXvm*NBH zH%@;d-Yjtr?;`zszym-{<{Y{Ldjm6o-x3B0Z$;4kSb8cSrCCa77WaT3Q`tEU{2ACq zV`ngMDzFmxJn%TMvx(D;0Zs+Z1}+A!25tks3p@?%?8RGU0B;4>0*?Vt1G{*0n%=;n zzyja`;3L4dfTw|7eK>s{@OQxVz*^udz(c?bz%IV118^?zao_=<=Eu=4z*yi=U>?J}U;&=itxA52W9l-ensox{EgmW9Z4p{6518!eo(<#rVe& z1I2KWVrRS+_%UI&I72v2m_`ny_XL6oi^V9yGBJSAex-NqjyI(B-FyMGmvwrqv+R8`n6h$ zHo@OxAV>F5v{Pj>y=!nb{#~SLMf9YBoaQ9be2M7ygqw3DiEF4x8^n;xV2Pb5I5BW~ zOVQ%-gk<8 z896PLPHbBRzY4w!&Pj4M=bVIdnvhCVIDbXq{A~)C=m3@}zQilRtB|G&X=>oq0_)({ z!Eb`IM+u^>PQpJ4zm0HnPK=6Hs9Z{{8ZG9m$cB>*$F5GJt;*n(!6{cy2>%sTaH`-` zsa&5rayIAG!Ks5&uWqLLw*g}`E+w0AGa;8%23}_HHIlNT3Tdj~)DWlf(&~gQr$*zp z*CASmXe0O@_$M`PR~z}%S0+xWn%Ic}w}9JB50g^^Yy|E>^dzv&gl)Ze+ZdqDi)&lu z#rafwakLRmvsbj}zQP5rn2{cs4Rn}&DSa7uIsHgS_Z3b!m2j$nwZJ-H6L1gEW#*o7 zfwuxr0wr%QMFB61Y+xC%5?BSS1=ax@DLu6Uya~7m=mNF^PXZMmvwrzbJ-}ArNuc7(c}DuyiJF`kaGNjJKO5WuUIy-@G^cZ_ zz^i?ErK%w(ZB!kcdN@tsdw|VwT$HAAR4bg5z&7}jA9@d{`f+ZN;8DOBpas4SJPVi& zbO6hMPGA+V23QAd1nvR4fG2^%ALRlgfib{jf8OJ4;MqV2ungz~Rsm~(wZJ-HBXAGU z<$FLT*4? zr#kV&=xlI1Ja|@?(NIY74FtBgbchmjNq*Rlqu+EBJfy@c77(I`JeS zwgNhUb->1uDk)%si+;+5Rta#?g}La$ek9P=#g|IV>cTlVz)QiM;FaJt;I-h5;7#Bz za1qKmM27NO5eXg@iu%B@!O4Q-fa8Eu3dae@38xZH4V)S{wV^T6_@YMeCU6&cE4T>b za-}d%6A2y#ZVTg@*x+QralmoFDTU*N6Bx8yp*)EI1DEQgA1DC3p>ZEqEh%6Sxb!6oonUjUMIpPIN+DUcY;@f*C0&|oLV^b-Fb`};Wxr>g5TWzC-PnJUGQ7s zw{=(O`c6ck2O?0b2+W5F%m?_9@T1@-!?(e=!OwzU2;Tvx6wX38PB@itHo&QYQw!&1 zIE`?c;Cuwf1*a9x_i#iH)UXF?*aJ1}ff~Y(gdYVz8NLm^4Sp7U2Y4yC6TA|<2D}!$ z5xfc91>OoSdZP56D7_~}4NfGSC^$AaHaJ;u9B>?PO5r%cE5U2PYrz}Ao4{S*t>B^; zO6-La!K1)!;91~~UYI9vO5r%+IN?;nsew}irxs2lcoVn_ycJwTqQpp)2p$D)iR3dS z8=NdSb~p|=rEtpOIN?;nsfM$GkX9}DweaiVzYM=IlI!0XStk}uXhfPOq-jQ)kC4Vi z(Zds3;kUsTQ5caZ)HaH1t447RBjHEFkAiQ3Z-Z}xp9S9z-vOr-PB|PWoJu&=aBASx z!l{ST2&Wm`1>Oe!Js};rqPbRTH0lGMOq|Y+zze}0(Q7EpLU1Q|b#$~SUaIO_E+?-+SUzp+o7enHtepAH|tdqo_ni>giBi=UE25ujMQpic4=73WU$4Sn{X-+uRaB9f; zW?BuLM&e_N8^K+~TZ&!aA~jAbE)l6Hk$7`SB)E-u>2w>ogZSgq9pL4u=p}M~n(l;C z4X1{j+h)|jsfW`@&f7B@;kbw|p6LP?X>ro2nIa7(5-)T_g4>8c>ac-3h=1a6fIErX zN}b>}#J?!50k2QvnlzF#WL6`bW;iZ#7SD3QX@et%#z`N|5<^iU@t$Ro;5OpUG8?#q z_~&H~a3}Hbawm8V@$&K-@J8ZW${WF5#D6Jwfs0{r(#+Xn80W7J<61?MQ#U&jjs=b# z=paA-MhAQ+@ju+?1g|09{iYi5M&fte)Cle(zVjv*xELNMUAjpOM=OXI&xr)L5r1=z z4ctLIX|4m@N&MNlPVnmCT&o&#Qf{t+QxB(+oY!w|gwqViMNa=)TyR8sob==^A{`|X z|MHeda2xUDc{Xqd@dxHPz@5a;%yWX*5P#v;8t_Kq=WlHUcM%_Vn+sfI&?w&~GLS#< z-`ySwZpq-<+Q?Dn+u+#YILOJH?|@Sd$4SoK`A#@B#4{GufHxA~xu6l;MLg#Y7r3y- zNgv)JtSFKAjSC~eZN$YQ8@QAB%tcP{8sY~R)qpn=@4vVa+(q2E*aa>!<0SK)A`^KM zuedW3+>*)bm5rl!+2A;czkZhk+(|rki4(krc-4{`@J8ZoOB%sl#K$jnf!pX|&1d87 zHomLi%BmABOCv|nx_Y;L1oxGL_&0Z#gI5D<$hm!4J$N(FMb1~t+Q8Lp%+l;SachMI z+?I{}!OMY8IMv`a;Pv2*;LYGJ@HTK^=Nwc!at616+raJM4)AhtCwMh@4R}3xBe)pJ zx!HhDU?Z??Bif#A*HZNU0*>^B43fKjFR`51(HIE%NpV0!e z1Ix#=Qw^*KwoO3F0;B|1Ph?&XYzDR!af`|)F;)W`Cvi)giPM=6P)tTIO=iai?f^Q0 z_3#_Po55Y+ZQ$Yt-nQn3Ix+5^`WrZhW?&nzW=fp&+&wi@xHlS!U%saiym<QR|D&T zjuO-s=mNHta2jxGuUwet7mYU8t{7XW}pjBUl)&Q#=(X=AfmvYZr zW-;1<)r2%gz-C~189UX$dSH1u9ALf9XJad1vyL~i(*{&;Vs4qkXa|-9>*uo5{Qoic zHUM%JRoZZMPtR|X$^7I$lgWf6Bq1RXNC+rIhWx-tLPBODpy1G%>13Mu=}C7_k`d79 z2`s4i!-}r#f{MzjE3C`Pu86KKDyzK8vZyF12rBxnySSga=%Nem_dMrR-CMW&P7=`f z{XWROx9+J^r>f35b?Vfqx;=7#R__FXK3IKE_5IZkRsVbS@2eYX=G1i6?5X)u&FtE9 zYA>zruN|$uruN3#TWUX4dspoPwGY=mQTv11f2;jXZL+SeZdTo^>pJTu>wZ-?uYOhi zIrZuK>+3&N|8)KAhKn2C)A0RIlXGerWsewxMRi- zW-MvEs`0apjWe?||JTfEO}m>u*z~KW3!DF{d1lL-TJC9ip=EaK!qz3ND_SR8Z*Bcr zYid^atjlKIFzbKMx_b5lv)@1Gujf2A=fCD`p4&C|Pv+h-_d|2dmV@ zyy|nSez59ytGZ8mKx$tr6dy zHsO2CW_;(~f-lMNH{S8RQN3A!oJD4)X-Do7qP^R^%G_*TjW4~<#+O~^p!R<{{`P8kqln0q-*x5OUVidZfR$jMVN~FcazQ zs=2sNu3CiqYty`cu9NqVU&;HabBTHPNlTIb{l%+r_i_IAR8s!iUf$1GPW;4$r{J!o zQd>44{mtHUald!R7Tmvc;%jmL_?BI`CxmkT{5?o(+irT}8<5ufS9bRz{qP&u=1-l! z59#-uJB0hMyGZ{}g~FsjlBW^p#Dxa{UoP!jb=e`LAClY)uecWJ?_55K`{Wg*pT7Ji zxxW|po8I^Vxqk$A=GNhRyd>nf7xyHjUIiKVLFP@SANM4rTn$JD(r+^Ra8E)TYH_C? zB+Xni4fh42EenC0g!G$nUkr^%LJMZ&z64lF=*WEBmzsspt!20;A@@bNpAXz5zAs#Y z`%dI1@jc;k-1nOmz#PCmX|m9vgt-d$q#1-BCCm`+_$nOwlrST>Cru98mNcXIst;e> zL&uV)HL(G?vv5!1Ow2~4=irVuC(c589_~rgmUuPNi*Qex_QW|zFUB1$PrL@{CAg!_ ziB6<(rV{DpiOsm5nAnQ@DT(uOKQ+;X`?|!1xSy8Tf&1x+oxop@d(w0!F2;R(q8pGM zxZ~G35_@nTOk9FH{&q0#xx^cAA5B~VoCCNgO+L|!bOHCIDJIfLkKvv)2NQirAHqFp z4kt25kK>*+?@sJT`exjd=1&t@q~C)(enU7hi1d4LPn!27hLQd=+##K04)?!L9>D#+ zWC8d4lViC5WAYI0-%O6<{#5d6+<%a~7Sf#rS67=|$qi<$c~g?#pI(zZ8DDJPkMtSl z^GI(rUqE^zD4dLO{UxN&G+#mbEb~uDpM~E)KN;hDUe#vY7gTM7$ApKf%rlen$+JW@hshzlQN?nZmxv6g4&r9vWeM{;R+_$AJ!~KHP8*qPZ>I&Sq zr+UqW<|5F!(Ch-8?PfR9+f5JBJIw2l-eE39`Xcjsq%Sg;BfZnS5$T=gN~Cw0y-4pe z{YYPI_91<-89;isxeDpsW(etSGlF!t8AZCsdx%!i#wFi;jV-6$zI`bx^UuUjC z`V#YIq%ScONMC9uk-pSihxBFUPmsRM+=%q+&D)TEJ|0O?-yA*8P~A4d90^HHSJ<}Z;>n~x*C*ZdXI zd(B-)-(+52y&Ct+t53!WvNs})uX2%or`e12J54{*?=l0`>u|rSdOz+%)mhv}st0i& zt=?#EF&_fvE#||({4?|S)f-^DKM(k=<|}~Tioa=lviWoKHKhOC{4b>c!h8eizcBxd z^lj!}kiN})6X_3_Cz1Yu`2o@&G|wRYLGvS|KV+Uo`a|ZYNZ(=p73n+7zajl$^BmG2 zHvfV2N6asf{)qV%(jPU?BmGhH8>H_vFCcxV`5n@yKsPr*YWvM$oHn}GJY-%n4T-sl zm5B|B1Bs6%9!RW67L%Vz{xJFf;7g>-s!COFt-7u1Z>#>bYC&pS>c3OxRKKPAt<{fI z|FZhjn(>;C)qJYv$2I>|v$%Fc?fJETTYFO76?HGvwbyT`KfnIc`r-P?`uEh|RsY5M zC+mM%-_o$E;i8894exIFWW(bPKWzAQ!@_CjP8*zd+q7>@Ynt9Y{if-+O#l1oKc4=p z=`&`WGUI|7SI#&%<4pNRN(E69H zf8F}c)+btDY;B%((ya4l6=!{I*7s&@oIPvK@;Phfyk^esIsJ3qHRr)O|9j3$a~99t zH}{&k@0dGt-jaD6=UqJSz`Psh-8S#Bc|V?K=1-qLfBuQ{H_U(S{MXOFdclVl{BpsT zg}WABzVK}e?^!s~HrDpBMW0%9-=fDC-PHcx_7Ak5wfL_We{b=R7eBXnbjjf*r6n^? zc=&|JPI&Hw-=8pVX~)u&mabpAap~rzJD2WWI=FOv=`~AlUHXZocP)K*>C;Ppw6u2F z!e#Bt&R=%LvMZOpW7&I`-M;K&%kEkB*=7HS zTeD_kOufGZr(9Www;#WiUEY=lD*C%-&6D`eg>t+m{CbAL{4)!qd%igpbJIH01|M@V zX8gtQGZ&i;@FdQ_wGr2uxX!}$DtI5S#&tHXb8v0K^%`8~;_Ae89c-WBYY(p1;kpFZrMND`^?F=yz;!vU zD{#FLS1+zBaiwwX#nlI|s2^7b-p@W<`*986%Hp~T*C4JTT*J6VaOH4~;yQpUkE?*I zh-(bjL0pG$9mX||>rJ?>#&r#@YjM39*IRH+;40yo#B~JMb-1p_^(VM)z;z?8x8iym zuD9d53D-Mty%X2F;1RqVp4ZK|{uI}HaNPn)ycd$dUpD2hHeg=ZfcfAY%me4Z{+|Q8 zzscMV&VK-${vbI0A#nN*aQegG^hdzykD}Lif-3*(H>+h#?K4C8iw6e0(Dxhd^KJHd zi+z5?KJT>8kJ;xpZ25n-&u`*y%#q%=@#LudwwYhg_wU&E@8F$U{vGrA2Ere=@W(Cu zalkn?9yk5dng2bT|2>=kJ)8eM1t zKd|^eu=qc)_&>1tKQNzctP%VV&Sbe~Y`JG_xo2#-XKcA=Y`JG_xo6A=XVyx&>zi2q zS(NAVr z{>qkn-sV4V^Pji*&)a@HZ}EO(@qT0Req-@|WAT1t`}-S<|ANJT!Q#JQ@n5j`FIfB+ zEPr0G<$h<&{mz#Aoh|n}TkdzZ-0y6;-&wx?&X#}CmVeQff6x-CE5mY;6RPq*c#Csg03TRJl=okmNi(b8$ObQ&$4MoXvB(rL7G z8WSp?MoX{B(rL1Enk=0rOQ#8R$fp*I*JANnEMAMnYq9mUpg!WyviP$s{w#|>%i_uIOb8NXew%i=suQ})!%g?j@T40}T_PNsX?IgU@j-F)S z*Vz2C?fWMCyuiXUXbSo{MP|A56mVEJ~y^1EQm6>PbJEmyGR z3btIqmMd6(7c9TWQJ(#}+S0iibohR)eZSVyy%ux{e~X2`#lqiW>w638V}8lzmu!B? z=9g@HN|rxIEZz}|cf{fyv3N&pyN_7@TyOEOxA@mv{Oc|L^%nnn+t2GQe{QhlZm{KU zu;p&B85f^5+h#M<21zJMHsh_W23>{G@%}ZJ(dA&wK3i)Aspy_W2q6 z{H%R`&OZOaKEG(657_oUVBf!N-@k18^JNQv(83?I@CR)_AGG;jwfSGQ`Cqm9U$uPr zs>OTA;yq;X9={#!bJZj&+W#7ML z>3++?AG7esEc`KB-(xoayEgy3HvhXe|GTz5-?ey8SiC1J-V+w@35)lHZTAxv|N9pI z`xgKE7XSMe|N9pI`?jCox8Eeg2PqCX(t$RM}^>eb(A%y?suz&l&bP z(>|N+v(-Ll+vi;SoNu2C?Q@ZRF1F7l_PNwPm*Y8RE=?T5b+dUg@hP)4`Dt9=GLI#n zHmj>pg=#M0^wiPNeVCbr|c6jy)s&4^`fPW%MF zar6S-Q#A_{O}N@>l8MzdA2q9MHYax0JZ-)J*c)rR5?9qOOdP~DiR+!X{v6j|*4~l$ z9G+jr^(|b_;`#-y7jZS#eL8VX-NM9;b)P}qpG$nAZbRZeTwkdBBHkZLJXiN{qNV=t zQPIO#R*bi&Njl z^ZWC6q<%ENJ5{sb;?y!+O{wnG$_3r2wF`FOXwHsQ=Yqki%NHz6+=S~MTo2%S7}pcH zezM?5YHZ<=)U6BeOnr0VVAZ^~!Ky29U4!fHwue&RY+F?IIMV-(t9j92)eX2Fz_p@1 zQGGtHkKy_|TwiD(tom{L!s=5OFRZ?B@v7>NFCMJAAJ?yOHFOMCU4-i@Tpz@BH?D8v zN-Y_zYQeP-*V}NtAJ-kYzKrV|xPH52tol_a3|5_c!lCLMu213mhZEjf{e_yYMB~zv zYtC6YSasdXOKQHo^0J!eS2iY}$MXv{rzaAtay3g=ot{{=>e`x%R}EI(itBH2J&fx+ ztKM7lOFYjwX|QVZNr+a0#@mtp7_KkjGOGux>T#{bwGr24xc1_@4%a(YC#s)Z{gax; zHJHlJ-aEE$Unak4LvQc8Q_b1uXNp@##)dQbbTOCT)Gxqvem}EzX9}5-{?5YqNFOs! z2dKN48x_FjTs}kKdI6^MMS*sWjDRx08vyPaIhY&F5HV6>BeK@^^|7|StnJiZ05+Y) zBvU&_6wLG``D`&HuxWp9uRywoa)*TEHKzrIy|N1H>+Ri=EsPGO$2Sk93x##-Ts3D% zD%ue=M8TWNik%e{lSEgcODeV;+dGtz#tP}Ol3K6~c;;zwsAnmZEI6I{yEA>6?7>Vw z8Q7ODW^>9C$t!Q*28E)mBp^+{ftJYu&ieJFuPoMd1wFy&F6J}o;m*S5fixsK6qO;w zuyaH)Hm67WGDDgEYtE2jl%gcM3Wc%k$o^;t6s3$KVYv-n(A%;XQIhnO313kf21BPWyZ$qr|7 zV^SRO-D4x0hjN9?)`OXmB9+tu`URqzs(6rW4h-!pW;D-YmxE)AfS-O1K^X@R3Uy=9 zmaD0XtE-q9E=Zl3w2tdgkrm?_w3Fpy@U1R{cvelf=W?T@DIDFE&-G;rg^28T0Fd6F zDF|(6Kg39^i!mr?02o>hqHP4^g7ip#VIV!Iri9Ql*O?w(7WsUk_c3BXh=7@G})Z32janisd3^ z?irHH)~;XgDqO#TDHU7gh!$3!K@4iG4tIfV1Z>;bNFN@TWYUAXGng|n80~o94ei-E zGBnWe+8YF zI~?V@f-T)j{7_y|$~#BNiGt6d?b$*R?~Y$PGQ+w2H~@4#OmAPhZvgWj%+)$mgcC8s zF}Sg}_fS4Pik6NPPe09^O)H!i>%(yY0OxzyVQCk2cmrTMgjD;T&w@X@>*iQj{LIr# z51_sDitw~nntEGI7c&-`bx*Xb0?`8UB4qngWD8xouMk0TZ=?Cl!EA1<5ZLq1BFK*x zU4G{9C=?0Vg|VTcrH~yN#q6U^rR744%PkZ=i7R8^Q-C+na>byprzJW~4Z&%4FpObH z1Lj7TfpyA?5#oP;hI z+iT|zN^|4srss5XcEK8*u6{BAfV`ViWdfp7*o*?Fc+5m-2B%zKm?#z_;z}sJL=IF- zQRL~p=QB{a5zPGgJiJ+L4s3+ZRGU?VAi6I*BDTf~P}=OIi5E(ckFq&t9bBU;W8hPO zH*hYALx+O{xR~Kjr{>rD^xpe4Dq z^&`}>l0nGG241b>B!GQ(=24WP?8qQYItRWj1Wto{TMzeT#FRKvg>Bh87dhP(peQZn<*4WtOZ;@}FFv2%v&;~DHDY1lp@DKo0H+>MUYHoB=N7$0ov z27ozBrHg$7oSAfW7xsCh=>bMXZz!=CIM;r0@O4zx7<>gwZ#KH#Y-DeUYkPxaXWwAZ zqSMYS8|Bgq04sYD3MDAL5s2Zu=Hduvo@siJK|?vD(<9z?;SIJB|$&dpB36i_4NvD8^Ix>6a5B2;g=25 zcYrrAj2Vc?X8^njms&C^G67|_>I_OW2EKtt=`0;=XR(RE*^%oXL;S&Xj~6fy)^_bQ zJFoLdC`_`97H)tufDez$4iC_eYyNlb}!rPstldn!rJpQi2P)c zg((3&w!_&$?JF{i4n#ZIlcWD9Y?gwW+8u_S46S0g?t|yYkWyG67+f|de3u~^zD{L@ zjF?$V&@xiq)R*L9Vy*918f|ts;LWz7vBH27a05q>LeozxZ)=E#RiZ$w3CuA^RSbqw zIoh;?#f**GnK)}pKaCEO5{iyj>56Noi}D$(axwB>TfT}oyJyqd$k;Y#A75B+Q$H}L z5*r1}m_uwFN=n)o7sidex{!^yha%9WCm?;!(v-yrL1^m>O*0R_vyFA=}bfR)PtwnCZ!XB-m~n4?44R_v1DU=-Yh%&dKp+9Aw_n%wWW_dw{=3IUv1l%^ zY>2J=1T__qtv6^k-fiVRXeZ=iB`OGE8kL7Hn2@mexG0D92iM|2MSx;xXfGl}Hoygt zwTU_kpqp#Cx+$#HrB7jPd4TL}i+^4&HQuiFzY`R0d{8tQoUP z;vxcNh_q41h1dxl%)`raCIPXJENo)PYQ!i8dwb7=ojdLQEKFtY?o4qkKO*s?%FLj#Q{)THePf8|+F`4q&Tc3~B{3jz7L@QqMI%G$S-u_> zJE$+7SmmBlMSXj`IEh9)Dp34kGZjjpgq7Vz7%kM%%51UCVPvJEcF0BMtpc_oD>5}C zT?vPlAIxGWs4^#zB(*0dACcg_FfEk@>BKUoR?!AKYAQ2!1)){+U^AxHVkJ&6c~a52 zr&mFqUC9Jne&yMh$*7hPzL?6bBlL<6_V$iq4$c-bJNJpk?#wfz7ts$71cc`&9DMRpmO+Av58nR2)c z)N&;EE-O;^vJ0By(p(*QuUqo)*t~bUAoL)vgYe)Tjb6-PE-eJ0E#hQ5V5oBr0_KJc z@PMkRm04=zD&dxL;1xPjwi(uWfd;vZK6Ph2h}tNZ-#w5U8|sg)gTpX`^;jITaJ39J ztlQaCl-=o({TaBNvIz$hIw0?sS7vH%tFt&lG zV@B!N2;Q*FC6c7WuC9($7R*ADDJ7gMq-H$ye#GE--jK<7d0V(x0tZZQKeoS_fHv&S zj%3W147Pn7_r*Qg0cVvU_@|L~*w|vmWwM_aXFnSYX0ChrqS|@vf0Q1xQ4XKtL^V762<@dFt`EJ&4xm zdfUx}8t;H4xX=oWYcyAfe zx=^uj9P=laL6UZBBC#dG3ucg=`8}ik#M1Z$tj17gKi?V8MJKS6XxqS;T~DqjlgEaF zBP)_Hj!XIm?}6UXenb(8wzWTtLmTH|XF6I{U$?;RS47N#MFG$IiB?A|f*4XcoTgyupBNntk1i+M#`ysQ93k2Ne2 zr1tRqTkvKg4oL{UC^J^X`WWggUT|SMq&OBSxFxf9Z2x}B(JN)oQ-zQ+k%t+sw>{aS zPhqo6jk@mQbm$j=K@u6*>8UIWCSQ&X$D?e?WeNzIsWtD~7naouw}F|v(#3%g-h+*; zOmQ2-5{Gj6!7u}A1~rCDmmUg%JJREOGdxWef>0X)UHfbz%(1=G{1DtZgm_|<1{@{u zqXH_N&*U%2LMcW<0zo4#8Hj+@@zCm`Sz8YmGl;F`JR(jm1FANw2{W4^kGSP z`HppP75m4qzZDE_m$5lFI-bw&AMmo=@kFqx$nEH$jChQl`FwgjggNA0aE7yeJQ5k^ zb>S3-9+M1VVZB%}jCjb_k7kF^iM?5#?F);YHx7eDJ1riwq;yc}yZT6BUf|m*C~$5= z3@ono1%~i^djeATdWAT$D`tPwI}itD_}KZTdgO)1Rb3RJC8oi57Q(=s%rr;Kw>oq* z6dQB~siA$?icRkiW(cl+voP_yB*^Ka%K`ez0ay*F`@xdX5dUBSB1&T;Bh0W3u!^+S z8VKf4aTq(}s^7BQzFz+CmzQqB<1t4b$>BjcV$bKa4qQ<_dLfIFrt!%1y zNRiQ8I8tL7p10zvsc&%S-m6RwSMMQrRBO=S_Pan=bpO$h3QAUcsQQNC}J`-UqlQ2|JP?x)W!yfnm63-Lm8zFf76*w*@yBQMv@?$I@yhY-rbUt)O(uKA(&4ADyL(L-{~ zk6mMx<0(b(s$#X}VY+H%*%SkhTU~i*$65+`sII24gH9_wq@bxWd5!=rzgOg_GlYkC zJadJI?#!|WLIc7TRA_yiv5aE6vmCLxTuieU!Tiig%`0!&%1vT7gO_2*;o6`GpVppsp?$=Rrk{T%6d0YbX;9Q>ptoYCz($Tn8)4IC+IC+4WZ)t54H-OP=6Xn_uSeT~DjQyticmivcmJX$WW10-8JeIyUTlb*(^ z@?PeStbB7fWroh+mDy~#ZZq;Ij+|$zL=tD2BOwR{%4UF9y%R`etF!`1_EF)GSOb^o zr%NUh@klw=%Um%9LSP`{^1H44D=0ak+|Ms289&ey+?vP#E8^L$MY>QvR4PB>&3EI0!bG)u^D8RG~S{;5Rc5x{6| zo|XGCus~AO!$S)wAWvqpOuyD0WLU-b%18?XF;GSN!E6r!o!Y}`E22tXen7jjQa3$$ z*s@^-%%D^_iFsHa+jx#I4yVsCnTLbA2eYI0Or9KGGmPkBIl-^hIfcsZ0rgK_upW+G zI=XmwXvG9wqu^+B8Jw|$JPt3Gfv1?odEDEd)pg|~izsM$cP29^Y3}hU&^hk{K}?`i zBLwn#(0$t}sNkhLJtNCW|D9{iP_L~T`v_#;Q4#j>ICa>Fpn-t|1wt}W2y5P%$B0c2 zd28>=bMR|j&?+7)Cf8fP$K=M;VE2&%WHv1@odN|zg>{usYE32720|(`vi4JTd)&fB z0ca_(hd5H?842*ieK#F`l_@7g2jt^^ZsOYW6FBFA4-4H3PQ!R_y?quPOZDxUgCI*c zC!UM;n*)DGZEgS1kg?Gk`j6&l&gIdmI%m^#d7ft&{tvPdWqBBG)dG1JMf-bM=8KvN&Wa$hVGHw4|*QV0kp zNZAB5+|-o~h`c3GP`C^qc%q^l^f+C-#2&X0kadu>q(Fjs%Y#X~D?C_tHkzbitcGPk zYv{=A#3>;}$zXcrI|vxD;q>SLwij_yXxLD7%+3*G&#S`Zq4x-4su|&-p30*@#`}&> z@G8!_Nk=Q8!2a5OS!$7BpdKAwd-(Fa+Kh~cQvsH=^gh$u&{yb=f$Bx$HgmtuNs1&i@ zIlFOw#yb@cBj7$vGgJBNGQ*)7Ur2Toc;eAUQ>k(zG17}<=VftXaWQu>W~T*hWb^!? z++Ktv-lRbN3d`h1d%MT>V%JPQ@Ab@vXSBCuM&a<|cM7oMe3gC&?Cd1=9PC&6*wxk( zi{UpdrpxYYdmxFLd+(yC!9*+C7TGNo{f=9J0%~u^tFqak*Nr z`)vhFBz{>FqtMQgL^Xlw2(`+~W%MxmsiK$J1y?P*&+V|X&0U+hVuq_!k<%9}izqS- zIN8nP)~`)L1HEG_a&|^hrd&G-vv=k6D+S?m@Z!RO0ibJVaK2TFg>UFK<6K*?_ZtEs zu=^U$I}QxTdWGSpPht`+eDCkcRqRDhnGJ+;CuS!2(+NIK|WIB6cK`^FkDb>y zw3dPovWosom+m+-rl{oii-1Z!gJk%GLR2G*s?FZ>ipO@%V?K3tY=8w>t6X?7GrIEKC|MNsFw$zUNq3b+B++B^|345UvlfED6>MHo}mHFAg0Kv_RBF+qKW4T56?Teo6le+YHnM+l+Tl!wkthQE6f9BRg(D?6+#tEq6& z>FikOKn358N531!SrUFXOfGr{n@K-%(wTrj8Qt$K;ZwWtAT&vM^~+Dj8U4vHvjd-t z2}$mP_w*GUsV&*`{*hb(j!eNVm--9B5o0Jws7>3}&@R?Kq_PT5PL9oeBF zd<>!`(Iz!c1#d2+v6RkAfM6fK&?r!gyf+fF);DOY+wKo0o~aPrAT7_=1u({3^m9eW z3k+gCi-v=VJbDI1h7<}=8-B@Y)mT~@q;Y&(fA7r^>DsxL3e9;+`MAq{dB#J!J`-Xl z{R)Fik(Lp_gpGqi7!yiwD>li;k3#x_VsUh>_3i!Iy){EjuGhBBfg@fB=}swNLJHUOt@%>e-vt_x2VC zvVm@RdJG$lbBPFzjTev~&d?FCgk7<*ZFL1t`G0>8gd%*n-)f#t+U7=z`S^zJl3>0~k04sbFZJNFPPR9|=RnAfpJ3 zi0FHljHl2TMDq2w9?CklHdFzzrT9WBv{iQKRH8T+rV=5T7ra7#NGfJ&>S1!$x3giS zAs&kTVKrNG*j5iE;^<5Tx4w>-T|p8`Urb{N=PPm5J@E>wUxT9^_NXIt4)!8H?g6yS zHZ0tu@L)lT)lJMEjMbwlGD9avOj0MlHMJjqNz|YaxEdNh@P|U!GGW!_kgC*UD?J+Nw_r>gcrXbuqlT+Ts*-yN`{)xqh|i35toeFWx( zXB<4DW)6t&9mVP3R;Gi|`ss>@W>LQN#1SzrQ3CT})rWf+quGoc^oK_Y>Dl0x^Lq}7LVBc*f2ar~qJSYe62OiKDuk2ELf zft>sR%Vo)IUtkmP+Yv@ra@O~T;bctB&~@w_E9Q7)xi9cC`TI3Izg`Z2oeM#f1jcUe zPzXX-oI8OZHd1d4(;kuCwfNG}k7%#-g zZ{z)4K~&ael1n(LYu{d`ge!i20t|j-l&CAVq(*)0OI{8QazTl33cd%z6d-OPx2!8R zNEi_#JakPwa~IuB!s_Q>7C-gCpc;P(3%f8##7Nu@Mql!-*WpANEu5@_t7@(MI zEOA|1ZrZfgesF%&N;{(q7cOUxQp_z`sGUba`#;wuD%0^)9Mi316!p92qjJ&fYCL<> zX}!ID`V&KOT&10{xiTawjyPxpyzKOWJ=nlWKQJU7Ok<+_&FtIdpHswDpM#ZsrUi9oeqTyluufxdER)9o~>bYqYM(d76zYN@KYPQ8-2=+ zT{+Ch$a1x-U!c06DKJe;@0XCe$NKmy_V{dN zXxwy;j60j8s~C8YHc|1}gk8^ICoHJUfxH7b4rJrK?v;!E$g)U2@bv8Z@ z5*K9zzc_*2E4+0TSQtMt!qA89ji!xh?!(VF4&nd3c=q8hfSQRf_uvmvEDvduKn!}$79Y9VV?*(}h zk8gyhaqmE>tdvyj4uKO(ark5{2k^&6*@hzStY=i}DWZlxTtk4Q(S|f=4dK2Q_YD4Y zt2xvilpT?lcHmEcZUHvFI6)3u;J0T)=nRA67+TNP<fl__NL2(ZVIr_4?xRS*X3 z7cq87nxdylQQaKo)NO$1CqB4Y3OKzAD<*-di&j>*7WkdQpRU*rN97uhj<9BSaUZ&| zAFQF?^;0(|-u}mLAXUIupyO`L!htE}X_jw>9I|LORWeTEU8vJcqY6>xhmD!3ibTbs z0-60}5p_bl&sNd2aFFWop>nb`Y3v6qYH+AGX)w?YR%(cv9$)*w(yA3EF>&V#K_9Y; z)-S3>Yola3#7?j&uJWQZYb2NVPx^C@Z_Y+MIu(Ed@G z$53t*Z+YngrJq>bh5Unn(eQ?&QmqrZv5LJ=>&pS8)=K-LV|5I4Y2y+TcXUfbL(`fS z{?UlB`js-QUxlH)78eINj*gjC$jN|k8Vw^M8r4InkcQcnR358&cakCRqtfw>zMA`} zv4>nvxd=3MU{!Y6)yjOf0-ayV&eMdF?S$<`3t5jEW?^8a2Q8(5n3J|ovYaKOa~Xv~ zy#2yZ)gtXNDZ1&1bl5ZHfNjadueF+^Ta2hJrG@A0MJtTc1j1Bj?85ocv1)~g=UQ}| zY@?B516f|Fu#;qp4yAG|GKSq%Z6FINayLKgd^2X*K@+RGA8~y$2jX$*iyh4d9*aZa;N?gQ zwGl#H+6D2_?jEI86Yq*5P1T%ZiRx8g_SGhy)y&x;LZDUcHy5Fy)WB=SDl6*?cw0q7 zzKC`_oCR4fbh=G%G}loMF+u@XTIgf-0kyA=(vQ}DzO;~xSL~-Iv&<-fxhJ+F&Z@dXmdn6L3(mrYdfI`I)gD5L5w}BrG0VO zbQHEgjgB=_I>Ua9NXLfqF|e`@~yli7qbUpU|)yU;{-owu%}$r!N{LgxhD1PjMf(? zDKqgul|?lmq2k7;fVQ!GR+_$Ji}?TN3))juap;>mzv4o$nBfm9y>4;z;K{)a59KYD z_#Fs{Xo-_yMO_)rkwRQholoxjT-;^*Z`PIPD1S$7emSQ>>(wDA-OzA> zE%wVrzPpiPe4CCt`_1*d$&{C%*Bh4M2+~qfe@utAPbpjpF&O6u6d~)^ge~-YrxLH^ z4{?0M20yCD3XTycx>@M5Nm?$?33RI_6mE9#BH!wm*8CkSDxVFH>$#e}E*G^K>L8Xh;kRG-% z7W&L5jZp24m=9keeg4HL-N{qaidhc5p&a{Y)F~^vcl3-Y33B)-y;@qy(WqAgAM`bq zIDRb!PXek>FFQPl4j1(3{Sgh$DC3QamJ8xiCIve5^8CA$+!|`Lx`_aykEP@FQyjp zCKZ#qe{63u#DxZwO#{Az&P^!xoqaQd<jmtCS~xXoKk$)KrGve=osG)3iQXzC2GnnM+a(C%t~2; z?;Fa?`_{4t{o|<7wz@YuH|3>Bn^t71O-AyalytvT9g~8EN45Z7fWP1mY7VWK31EMZoxr30ik5YojBeG=1rfdgMlB;UG<4dVdUBw;I92yO zAm;>x{$$ixnyuxfLeDXrBI!hgo?*E$McrZubqT6MS3~GSj$sH-?kVfB(up5f=Ja^% zat}QmU}$6KCEz5bsg$=tcKFB=wT4r_8@P<>m)C%)bWfB*XvUll<|EX?+Fd-bQmSaz zQe7rST{8NYVNBR$<8UhXZnmQom!)hE7n^&bxvaC?iDAp#8pYR2wC0p(A9sRY+(bl9 z=~=V4M+?w;(r<|?)L~pPw@8_4i%pL{Y=fxiU+j`0z%KDv%61W81{-qR5~exG+if`Y zL0BQr!jw`icGf?_xMGeicy>_Mqhv) zB-M(uT4>QjwIzpMemH>szcXp^ModHfq^_qJbOFwVZzp8sZ{?pSQgU;(3!&>#BQxoMRxQgxtOX%j+onSMMIcCu! zw)JRAr*`u5kKUEB=el-Ko)R!ooGq34F?P}Xq(X}lF z4@af#m-5_6q3)=4p%fPwIs&n~eW4qRu8*uqBk*n!aoja6_Q$i*^V?+7{@c`T);X9O zPcD1<%3D6Cas}XdI#-qdLaWZAMw6P&&4Y6H~ zxhR8``_%a5LxC*`!*^;Wr#|b&lRk`*E5=l{V363*TGVWCD42~$;~Ev8BKB8~ECq^k zRwynn#?igxmDIsK!DDRu&fQ(nKB_lDV=u2l9TPlS)QA67clY6q(<8@;e@<0T1w}jF z2@&YHXAG8Se^@38BSdE>s*`_4(=E|hic@lUdJ}B6+ataR%4?%?4xkiQN^Aug@Sl~O zanUjcmDxo#6kPlHrh;+1D6v=8{pfi6<1nKGLGjAPm6|EAYGWrxn(xS0@_-PI`f*TF zR^!b6#Lbn6~`LbwpuI1pe;ee^79A|KQ)V%^ObHpOw|N`p-E{UZwELa z{N^9|zukPbF5xN}jXyoU@tiCUgLz~@g_<6Ex$O>Da$O!peu%UeIE@nJ1GD>^#yJ)qOiX@ml%&1C<`#i{s>J{H)bKYkyh6r%>x zyycJ8-{|ae+QP`+wKfvwonVqUI{#hjYH*P)cD1{Nhqi-A^A;S{RL+Upg$~O}wCkFZ|bgM#S zGFRi)v;rChFZW@lu0rv-%u(GXW%coW2$*-&2K!4namc!l)?PPj`f(YxVY*CnmMgkk zGYi8>gxIt?9O1I;y@DZHx5@41W3EKV35qELT%G=3!SZZX^uVJk2d!-}P#uQOu;(yw zkMF6lA=Lix^dndP{KWJ4KivwOdpsv3bwip8;>MrfacvE!7`F+6Rq#^3JGu)|zWlQ; zBNq(pGrv65NESKk7XHU>9_KmzoXc+lhY)?J5wME1=@Rgms(y2-;R~{jvUV*%vrnNl z^_Swr^mRhJLd}-LBNLx4FQC)pAGUT6m#(h)>>4YadQ#Vc#wkj>sO?ZDQ03iD1v=?@ zt=bVM*Dlmi96654FM#YBTXgjmYS3740rZJ-5_pCd;9maO00d z(*4beT7(9YMlk#omlof--x|Z|h*_(vlgL5iH(V!5y2|@d2i-v3aG>S!hYUZxcdk9V zI3#g>8W85_hx;5>gqUkjF}>y#!1L(yDQF!(8RrJb5ZZMLVBthvkau-u^61kkpd03{ z4QdIgO&#Z23(7dou$T(K`Oj~E7kb7hHS%BM@{jeS15=cjqX_IL-HzjpG_%&wS@E3_ z-|g`^!@~yD6n^Q9Z;25r=VZsDKKQ|WkCrN+!6A^4Z~AdTKQLDS)BVhZ`@sb|M3s}N zDs}idLKjMxPXnQ>&1&aR((Pf}LeL#f29vm%PO9`4oe^}pHpYO|2 za&axCK1Nn6!H4-g%S-u0$EsQ3w;qeWX2cVZ>_YY}N^t)ol1Mtg__*P`8^6K$=>r-?6CX6vw~q4~oi-ZVO# z67cq8p=OL^m<`8N>I6-vU#1u$8}TXIcziE;aq~=QfS*D z3^|B_DS#6qjX+3~3Qxu28tu>AsGNE>ahBbA^>NmP3m5*dj&5N^7crDyvqq0=C z7Nn`v7)bmrf2?--$DGLwhSNe;xCK`pwv$XzEkykgNjYx7?sd$g72&)`TF3GSz-CG) zH2Aue?WQ4`?DC0-4I|qKC$mBm?Y8{c0N>C#Bg7J9rE8!vm(Kg_h^73_tsvKn+RW8y-E0)Aj_oF%Hk~oZG^*645-?XA; zFSK?E+Ddzp1^=Vr4ClkX!cQs5THRexHgKGAbh-!u$4>Yyg$9Za*~aM99vxw7_UKfj z1IP7ETe(27UGhr!NllF|MvrAKG-$=ImR$JB1t7^~8VEO*)6h&cKfWFLTqE6cuaGyUhV zlW%1c?TdDTFX%uLx!M5&YGyZ2-kzvt;}*4=y1JI8L=qKE-kE4ei;&fBsu~j2soF&I zftgK-D!}drY*9OKS@!Nk^-P1R#?V%IZ8d0COLlrKP{$L^*W&*JH73!LZ5}3TTe8){ zN;ITyW(U|x9Dy_sgC5_iQP;$M)i`@SaeM8liA18Q-BdRaR#TeVeM zX_>gYt$E@e`~w`~GhjTZHwu~0r)raJ$r_VPv^9aDc+3OKCm&3-46rq5tN}|K(CK!A zYNVo;iGP@mo?1Y=sb%W{tgl5sCmuu#>nSays5J^n8T6UpmWf{jJgpWz6V&DdXa`zU z2O<-t=E;Za4f{~SznTuS2#N>t1-2wihycB3gT(`= zfh;eLp-1m06DEHP9V#72HnvPWr#zp03GGhRv>Zt&OODi&C8e}z(~Wgt6JIkzQt6OI zN)X*Ejj|uOGksXnhb4WDq_2_mnUX%Ujx4A{&8o+20}af06;t@Pprfi4jgj88npQS^ zyo!m|gcO|)9MHqPt|OUjHBB(VtoFKT7(u@!Ykr<+6Jg*@g;BarFfM?-0IW^gae;uY zl=PL7E=sy6=?O_s$RPaLBIr~D7(hK*i6{6pabvQkv8rZK8`D3NA~#Br8<*Bj16m1| zvJUESeImKYCG@qft&w(+IW^F=nTfh-v}$;#HJwh=C}|j1C}|Ubtd{gR|2&*%tVJoZ z1KQd)t2Tw|QR1!0$AbpCZ5kC15F$}InWwOK1TZ2(t6LNGn0HE7(5#>}ZEcI%WOSCA zYw@7-Iq<2YrK+*$} z?w54Gq=zIuBR5YOiiaxhSNCC4X2GmTav~wpY)VvMX!-vh6jkC|wSl zh4Pc>TEBd2O|rdau25K07p2f%I~(Yg&^e@%sf$u+txdMqio`yoI=BcD)Y1A;D=j`L z1xzBCR>k+sI%$18kd~%I3Tl8`vMQ{*JYl&s**}@J>~G16tV)05%gTEr-zSFyzQfgH zw@dd%MHP7`!zT}T3~$Mbq)PXdOR5YaoF0pC8dIgz_xVaemC9kl;_)&Tw`4_5rGJc* zQw($-8-Hzmxtvri&6B5!SZLWenDm`IHo-X7M?LWN+p)Dt@V~N0?efT2PopZIab) zi+TBer%dzmJ;rbsB|5lWGe8kN#> z6{;GAROonXHOW=y17t`IQSGJrnQb0)Oi)uv4T3)uNMRT(iBICm^jhc)`Tvu zq0G>hs`JP zs6AHlH350(W|X|07U#w3=42&wA*(32*;+|$Pzkg&T8V1uWLvzJ#=;k|qDs52Rl%>f z8UuZeR#iu{+dO$DZ07WE(W1tmK-gd!f6$@Zt)`!FEw&yhP7{2lYOoruMKieQ5&Jtk zC?WYKk!-AkV|b(sE-DtqjYw71ChAad;vSTP!`6n?bo0bZnx-?{GD-KmWm4SciI?Wo zR@X7)GVxxla`Cts54gZsILZtBJ+wxk8Uc7OT0jWV8%|9o8IEacPfTxMh=V`|X5b%! z1|0R40i=^y=U@WD+8)$u+5pyfb{{SZUF$Z4fe`QFs+v<%(#8rnH7Q$mA*Fm{dnWk` z#*mLmGDc`CD`5hl4v1r&9mF>oh(X{8?71^h?MwJc zQ4fjdA&iIE!AsK(LT{ydkcK9%sBQ4uq-s&ti~*p!>YwpxKU3R~Y#C^tc;36eKMNzl}bk%Pw$Dqg^0sZel4m!)$YYzb=0&l6xJL4MIF>q0JV(h9s~E0a`UiIackH5(~hcX<7f{&ei;55`B9N!7!xx4<^jO zzBEWMZBoJpxC0fj-3~JY!>_SXSI3=zqG9z2K21DF?$(+V^4i)cX)!1=hGAH^qOOyw zM{T%a;(5jfCP!(g5Rb>Y6AMkKawC-Q)@g_+JI5aDODqbR(LaX<6J+f zVm=DiBZ964{bJ04eQu<3J(O%~T+rkqylAE$L7+_RkTF~D`XE}<^6SwI<0NDd!NrT2suwd5r07K%cjfkm3 zi8YJPAc}&a%|}YmrR&k3#=4HC6fuO0&RvXP)igkEjdcr}62ud3A~fmKL13&=u^LIT zvAwB^sKN#%89~P;4G7LP#BtmR8wFxB1fy+0>6m^XL2@_3IR+8^6-MqkGf5@)7Wn48r%o5l|gccx*u5WNfG4I{&}_) zolMp+U<2c#r8qITVoYCb;aIGNFSBStgDgv3t!|sl*QjNtv$8gu@X7gNg!v$cv{kT_ z0R@_C&hMIo;SYyWcBZKEHDVT}C(Q>K#A}&shF8gnSEN?zq)rUu=E-hNEgYxPCmI{i zsBI#mwH%(5CFl;@s=VWUN1{!Mcyvxhq!rGW<|;4RWFi3@+L}wJ+G^U`YHOuEmv?z*XeFuA;WaupYeqCK?U^qo1UPp;yYr>1C)g)S5DBPUnQa4sd#O6SUk z3mZjk!2|Oe+SZ8evnB;Jp+PbwG}c1{wCVFy2U<#ZsDC6)y%+a-*mZ_=7d1L|ZkeN_ zyj<9xC@(m(b_N*-9e7@}T%S82o#!z|5WUA7q!meas4<-Ue@!%W4oYMb7c(KfgsLFf zT-xqhv)!w9yX(ayTs(StK`$Kku8k^DgwD|dO#dyDUFb8kyQOp|fu$MPmvWlzDT+7; zck&)84Z`qrFHs&oMe_mf!8y(8*{VZDwLpYqy-QCm*oH@yJtcqx;5Zt2~*FdoYK9XT`Dp5 zI{{gtfoia2F$ZB7hVt`@)dMu<}T zFHc`RJUt9rO1bwt68(!*3v~=w&sRqVS7rWS8aTl!cV%rMr>!{_eBzLTl^b;bR!?~vb-x}cEhTKs%0MQ5P|y){@wdPSO<3=wkbEt=1;+myaa9K8rRu5b8X#B)4y>>a|37Uu_p8)mJt@cm`kY5rH z_wI$K(!;=@w3{|9*>)&;^O1X6j@&I8`4Y*nc@xX6NRBd%qODDlnGYM5YgHL^@|;p7 z0_H~a;YQbo8==D7FXi0+emq@N4@+C@9@!3Pc-IAdn1?S_C&^qC+j&Ssit)75J1N!ykNd6OAnY zMzDa=?K0*u+(2hN2+khv!h&gA{T_OeH@6SLRKOJM5N2`WHYQ>GQw?ylFM;h8Dfr+LTerQ z^rG-dgL87^0O2I+H=@5vh-bG{*JUKBhNl9~v;fuVyCR5U*Lm#0ddX9CMM{yQ(*r8x zcDQp%ZZ$>tHwO@3_mzk!_pCA|&I4*x;T2i5d0qu47XZDSlUhKOw=IU9SP;apQw!Bm z7ceaCFmC0BYh-_weOngk8;5OlA62(YLmC{8gq81>Hg_;es0M?JYaOv`D*DKAT)9Wu z+EG_ly0vx|+-e?5qgyU+30--v)K2B_vW`36WnWI#D2gfhblzn;L(C|;O0q=O>)3=3 zgI3EhXQVD%>M)?&YEHsb0%kJs3C_&sgY6NJHcFG0=$Sz9LddPAYNt%}o(ltlM&XzsD!koBU~XY=_uxn&10S~t-j*fsCQ!M=XxXgFHHzPv zU8omBOv9!L7a&bA?)(zY*wxj|lIa|-&11n#jWvQvG&D8Xxoxsv7dpUk{)L7r61QL8dqY;+69MwfC&!^cW4C{ z>wb^LZ+j885f^vQ55 z^o+v=r^2kWMH=GnbZ{*^c`gIPF+4#H9usb<`^=jzf8G4`&%Cwn8&|jf&%-A_b#dL@ zpB+DQ)l+|c<-~`~GGkH`#@u3zsY&97_ubu{>u@yGB=G-#zG_u!=O?~V&>@a#MHf8vGT{NVQ9x16*4uBFeu?ZJ78Uq1QXhA+H((MNWi^nq9Z z)%RyDnETZ?|L235r{4IJ>I-jvr0;WQUv=MW@}GRwr+#+M%rAdw{o4=j{M6sv^N)pd zelqK_zy9R5ORKK?;_bz+{HWCbnTLOL{tGwXU;Ea!+iy7Oo1aVIv?f|r_n|*Y;DNTv zjp-Cyn?m5nEc3tXi|aku`ZS4bE*uy0xKZ5tKvLa(pi_=XMS< z#x|%p3@S*o|B?B3^Y#^cMgiy;k0_5G5`G=}f30i{M^1K&`t7mgpob)fSTjpJC+(8> zJ`Pd=$TqtJR?;7h#tVxW2(MXOdN7HSr6u52)*f#HHzl$xCzt$CvmDz9V#|?ii377T z4O;V6&W?C-VL49Wf}bHN#)88)27~>AT~c)OE`5762zL29xSY!pFFt`b}@jbTHs)7qE?ro-Y3k{lEy*ELo_ zV)Nv6HWsa*jTi-`&rp#oSwgcgArbW+q48d>ZyCRI+p#?GS-M5!%rlfCt=S1eC$~!p z)H?AzUyE#?#PC@uW^~&j&LR_^Cz%f3maz?-YFXyoY8kTAF@!m2O#%a!o1chf;XGY6 zC4CgI6He)irdaTCz+u4b zqmic8&onqc`ibyBJfdTXw#Jm+Yp*$fTV<-WAv+pl`+~b(K9(fj|R#9E%N>W zyPQ~DDP5$S57;zFkOI!s3#Dp?k{-pL8GV|^U_2P{Q;4(=MniYwn8%tL1>AtMzKx)W z@h6`?@W47wFM`Go;jD40 z6Ac(-P1q=b$?``!ew;!Vn$y%LVkpvbeSbynxZu@Y17r;59u% zJ8kV0LY!oQSSm0DO_2L-v$1IeV~46?=wSL_2VwSFq(Kqre291Afkqz6be074BpO|r z(~@nQ-J$UeAR*chGf-O81_oGY0KmQ!%nh?@DMfGrO4gE1&O8+#b10)Fw<+=tKFu?Db%C%A(88>covampkzx{6hnv>XTP6$S45B z!Zm^U;2wkx^##%n(tyu06f=U#PSQMCs|rjYMqV>MKCviLMZ0NjN_vo=%eko8O;sN3 zC-$h*+@_QVeJVJ)G{33Zga6DsgtV}!#>@F(k=-*Pd#xZm(I~ROjVp zDo*pvDeEc52G6cGnXr^-0zP{QAwYtcUsNH<^0x9e`%j-~#|@G1DRtfUu&Bf&iOkW|YAI z#EA|CiXDMaWV~_kvJ22k7eAH8qpqezwTHqMLzFssYbogzj5wBE7`Xuqh_jm#T(|f@ zK<6~^TzM1<@Z6>Z!?_V;);6z+!JTqAGUhiW5L2tjKo0hq5uT~cK^D5>caTg##nHhk zD%_550OR16E;{jcU>R_C$14tKPRKBcnRd`}V5HsP^=}Jrx<%5xsA( zj*jZ6-j|Q+a=mY_UD8w^b`PN=f7GGP#XCV*DtfQ+U51EVH5Ub2Y zZo3<2F}cWI>;_w0Hu5>VkY&#sC`&l(FcLAPOCg?Dm<`K;Pg}@S^(8!Wsrm&xBJ9rWbDSH~I26e*=#0dhP-9(D(1#%ChFtFv| zC)e=}@E1{sc#K$QF&TmyrvYcF1q&KI~FW! zSL}+ein^<=s4Hu4|G6`hLd3Fu`#$gY{Qo~ZKxXFNbIv{Y^m}Il7c7`7AOXx3Q%(Q+ z5Oz>N5md+x(PvFw&mcr`FGQc(TbdKJ&4X!#3I`|%F8oM6T?DK4DTuGCCurvd`Uk(T zsgTiGh{e$^DfC*H8`sxHtB)ftmmwmoHhX{<1n4g{C5tc0?#R`u|rC5OI;b$k2a)sQD9j{Ew z774nM`GExC#Us$c^P~Rx(`N+XLwHdanET#d-drAs%Rw!v>*y2wrgOP`FMoo^OXvFw zeR+hyKaK0f;qv{tq_?lYkC(>t^@4vSk>D!|(2MU+a?|*HVH$_W;d6WizP@BSSK#gA zEfji_q&MNsOY`Rl(tWsTXjSi=rx9r! z0pZK#3Q2Dc&)c6*^3!-e-hKoZXii5%5%5SaKaLMC%~v2Ky?DOqe*T;^KH&@h1pY!l z050@OOT)0jp)d`~ADM>#&-{O#`F=QN8Yaof5h=Rx<(aPj-n?`lj!?+;OXG3{e7;wj zFV{!l%k}0GX+m!hR368d$K(3KOZ9QAVWLDS6OeTGWLb7Xra~c=2Y7mBh!mO1G!KC! z$5SX#h)IPfUoM4z0#Geag^VOUe;iL^95YKKWw{~&2v|00m?Tq@80G*AfEtNmgUU)J zGCtB!41;20y#z9wcI}p&SuL*8JP+>TSm$O2`Pk^|2X4Vb6W4& z=@J<`G%=ns9>^}R8M}aCjd0Au&x7#r^Wu4Mef$YO8W(k`{g02%5yxz`#Ob1fwG)w z7fH!%k(iWIpL)tf3R0E`lgH0#-?1ZgiV%m&^TmRojMP->N@BJokGe97=ZE#{{J~Nt8p%f`qB5UOWto#j&WL z0z?r>5r}A~z=0_LG+m*BEPDKiE|7q3I2QR+bR~fFiG>6OP9zQ zsROQidtq1)9P9oQplDeRm4{{WVSw3MVMbtmewuGl;#^4<*hIBzAZQ?C-xZCo%mRo- zZCD^?(Ky!mrv|JR4YlxlgLwQbVG3qK)v$bEQj>5j?k5NfS~6DIGEI*v@8f- zPl#KhC4wx9G;a(`z_FO0AT3@d5r6|@#wpj>JzuaY$v77O6Cjb@<0}N2XhsB7preHf z)+H6k`urA8-A5I_t6=PgbbzE~*FJ<+2;n9&7B+c}Gnck2U|6|M%gB7G0W!Ccc9kupEGdLb) zn$vJB<$nbEYlEXE!v|UapK>X>#6#@Jcz6n^F9Q0b9MQz1T3LyfWF!hCQnG!=&ZL5I zR}gR`*c`Cfxi~iHn;g-Aq*$r-ccDVQ6oOxQdxluu+W>z6r+vp5NiG>n4yL2K&^$f_ zo>P zuoN8Y^)Db(Ck&xfR4hkaLZR??XQxg!X;d40{TD3j3DXcMks(C6IwnP6DwIyw~3Ys$1aDRa@2NIt&}GLBXzz{x(Ck z=%R!LZR#A5j8rIPVzwe*O2TLpsIw$Ef#zVy|G{`2HN<>5SSV+peT2wj`X!JVBFKU% z&THvoM}-4=?Kwp+DiA1Sd}?C!xZ79#3-;9hGmk1EIbQ56Oe$$>xn`i zL8$Z*VN3n&-DLYlGmQ z#B9T0rU5ZnBcPB8SkYmhn5k4Kkje=qd14SjbtI}cf<~wvYNGWT;El}z0+I$d?Nzo& z&X(7LDO8edg#-*Fo0Q2UGCjanYQQMti9ihit_30uj`j&;jwBaRCuIzS4$o^FKs~T9 z^K?(`%tOA@0AQk7cBf?!k(Dk2!wq#82*YJmkyY!(faS=-=|OG~Ba+L3Bsz4L^@rj! zA{7oVwY0HyrVR;-mIn6sh^7(?p|(Ff28vnI;4vW`SW}b5Bw@%)X&cv)k*_0VCuNel z!kfpJvjt4dt~Xd~4N5JR;W%am6d^u#`6?2qV$(xm%c-n^4T_Y*=BI-%V+(-YQ08J& zcu~Tm&tfMvBeh6FQBNv60&CZZVThLDTE(K~@T+9$4Nrqe+d&ISH6Mp{MEdv&>$Q#l zebzVCu)Z$hAR=lEq#>tiTdVF0{H6?;-bm}AfEw%?I6zzIgB&hL3%AaI0u-5_4H=&> zAB2Uil#_ZOZMFSF>2^`#WLUbuF*|^c%t8>vlo}%n%NkP1;Yh7y{4*QspcaZ`F*#TY zMP^b6wQ33^)NPsoIDaljN`!U>2yQCw&`jr-9ZDfQ2GhR1TGmV~&6jO?AgmFz@QMa!RumXu({J zLfF2-edW4mDAW6PwSLqB+f>BThXi=IUng&_;w~Et&CpA+}RFkbqj3XUj!G5?~;Q z0TQPZnzUip83r|_MyZBEXM2eNgYKzXh-0l7R6=B~m0}?&%g#rHYJD_YKv_?AUM9p@ zY$;vqLrv5ir}%;v6e%_FU?-BK&MYDQ6OsxD$K-mWZcY(L4;|oX_@`DlSm$tNsDp?T z7As|d1f@n0ETNgE@sh}!L)Jh6E2y3D*=S(W{i!xEJuUziO)-cZ<3Fe|er0xGnUQWq z$q8iatr@D^)i-Dssk_r@sX7w*3Td|Lz7$YRSOUe|HVkpiHN?{ZX{FJ`?|RI%(zIsW z1qnvjl>z0glbY315=N}*lqfv}5bJ2NM1%_>8DK>KgMq7#gw){Wl#Bca@GaF47~pb$ z9DU~pJx|msACfuHGi?;8M`3++D_G)b4?U5^aG<6fj4CVz)fQ{L&UREoH3TgVaDi?B z2U-0uTp+;wBB}rvNL_|fp*!?JQs%8TB($&1rpnp+5yW?5d$pa>1p!5HSiPrEwAQ$B z@TS>piBbV0rjuN)7x_Z}G@atK?X`wp4z|#ffv=WUb~aR_HQdx=p*17YsOY6;q-qQf zUx7&z8LYm@*ni4X0I9Uc@L+>6rdR_SL#rz?|8PHm@F0kS9C_`u-$4znR$Izr)Rldy zigEawJDQN>Scw8c4I~eYQX!v(C`ls)e276P(*|V@F_<)&0=!EmiE3Hd`E>0Aau3=Z z@pHkf@zX@vB1OI)Ga3U9DoUtD9)y)p38W;GiwrIUN5|Nra20~k9FZ6*l)~DkL=S}{ z4H}k8nEoWSphF2V*iNWSQL@oeZT_iIQRaqmiE3TdgX^H~K)0p*BBPX`ld$5X)=7x< zen2PbRk(qplc5lj00TW&t}bUxEBFRYhW_qwt2F zQ9X24S`bWf43*h-03RI@>Onx_ueCdDv@VC@8eK2Xb{!fCPB@+qxC4ep!)BFOWlkC? zgPK@v$7jdDjMK@a5kRN}*w9$9aC*-W8r8psRRdBB5n)9|URboFj$X-BRSr##9I|aD zCDgHrT6^_HsmFuLDH&l$brMJ(Ku@Srv>pSR&}iuTkFL>Fjl?mij8iI@s7=t*P=chAmpLaCv!X5bPxb@F=EHl_1wqD-vR&f6C+`w*~A5^`HzA zl9-_pOfCzoRgeY9frH&b_7UBTCG%=sSBr#5L8VxrUrGonsQjF24{JYgLAQ(E3^u0j zC20tu)hra2!GU@dNjcUg9<+_A2*M&uZ7!qCNOKQ%#zZhYX#aHx>~EI>VVOb;Q4@Eo z#=%xLhB~xoLo3qA7SI%cj>?q+w9_G7iTFX+nP9nsxgV+kA(JZPumr_?qStF8viVXd zKcUd1fKAdTdc!o+03n5{^|0NEAthgP9mr6~M5G)f6mo1zM9IOK5Uijm;p>#pS>cZm z#MZ_Upr?BDp|S|g1oa>z)W{*_>H^fFql>1M8X+6@H-UdbYdU)U3m~+CNEIZJ3b3eE zA6b4luqVGj54j_?_6tO5fWVp<(-y*tC>l9tueq(kPLEy>9ExRYjfED^!LTg{ARz_o z^bgAn8i2^a)m3b8qGB?-*r3~(3aua%=*A!p{aM5y19jnbtP3wGq|l0C_ZEY;!`IMK z1|*8&c04Mv<$Iv@crEu`_2UkE9fY-;s^-AnBEW|Vy1LpWhEQClo)E-8we>-!Mi(_w z06O;@Jxvl%n7wH zsv#1p86c#Pu1LgGz{&LZLT4Z)X5wHWchQu`P;->xP$eaG{RyJ91O|Kv8aK=s zQ*%P;q7Y@-YRjwXi;O&6PefBM1WzERKj;mKE5G*%b{fnZ4ICv9$NRPd~Q{z!bg+LDqYE>Iy7ZK2b<{_V&Asx2U zc_@@35&wVBN*xuhB}oJZ4f+L4n@IN%K*HW4#gM;P9vE1$IzdGSnmd zJ}32Ns1`mtX4b+2#p*+&!w71r8cnr2m#24sP+N)W*zux=rlGn!lgAIhvAzssp2h^h zV-n15x_*;L4pNe^TajJ>Q=g&zGB(W2Szmk zwl@MURI^M4BM(K3Z?0{@Vm`#9lrSr$RH2OWY!Do?fl}Hnf@2cNVH*x&I5Jx4Bpm6~H)DPMNyS>usC~yEL24=hLytj*W%K27AKz30?IrApB#{;ilnTnx z6Fdp9>WJJhtP<0AhEY%OARnxn_;29$)4{F3-@gu8bhkjl#-&;`LDgdTzd(|oS1JL_ zU<8TUod}G8X_G0mB`U49GV&#-8Iy-&vVVgHm=Z(->{CTXjtWMp>0mC<;VH!oWzbAY3PLBJPn~#?;jbQW;?G|ND`2BlPlWO@(LV9`)buS7qk-7m82O(O!G|>#*xgSuM3aHOVU4T!A2e zV|NU-mO(|tOi(4GmUbbw%0o{#La-yJCW_iNqvwj~KoUJa2s5gkPt`1X=OMzJrlm@M zJTkSX;;Wg3>QQtk;zk8vD54di)oq%kYEqD&K$mF&(W9x3%^7Mw!>b=Py9WFH09`r* zubUjS1DS3F1b&sG=336giD6SQbE+9YGg?wj!7?$n)Ku+sql6gN8pn#WP)RI_WdYCT zO7dbL^c2DNOt@eYg;t$lnuMrXG?eXspczt&?=@=-?hQ5~g6QhvKv!Y8^~eG^+ARJJzsV{$WW;>M12O}fCFLv5=U*aO<;F1a_AUl0b4uO1$^p36vPYk z{zWrdyWxB6FsuQyZx(04cRf>mkQ%{f9BwiVsXONMu4QybbAy7WzCoQh(bH>8Ker3D zN>rf$BPA3mfO^gT$I&78B67|ymsPYc>^#j@9Pp}{BzBNZ)}5jb-B%vo=u>}J!n|qe zlkPe^9mvNzlq?=SEOlj#6kq;gwtvdUd6E@P%hT7+de-fI!_RMDA0E3hYw7NZe_YGD zv@m^$CVF$@t~IHULu zhR4Jsu1tns#XAz4K&YN6g9h(4nuAu&Ah;DacOfD48( z>u#*;IyGbxiC}o9dO|QEN{6bk+*6V^(DO&U3VOE3lX-^S6P}yr`FQIKiRG6dy3VF-dj57=?dC zjOD;uD?HEdA;$Y~c0i}7DvN9|Azw->m$3nrJu2q#8KKq399BHiER6p>gpt}JHbw$WF_sSRGDe3p<=m3sE+4MS;XWTzKs)rNWBS-+=nQ~S z$wUFIL~uQ$E=W`x0yZJgKRhgr+K|u-CJimANU$9EA)&VduwZZ{8(`7rY>FBgv7PycE=cu0yTCw4}2=I!5x@@Xi6b(Bc)o`U0?fKA)PvJmx$3S}l^pyZM3BXrq zph+p1x}zKd8(`3~1kIgrz$d5riZE#{UVI7D11Oe5t61ox&`|54N3BP#(V{bYREW-w zu#H)Zy9dCL0YokT{eT+;{QAL$1|Iz9!lJxCTtTbmLtyI*s>>suqJA`Yv|RYN>Ggnj zU1!4&I#fUls%(=mD`-y8n50-fP=V$t6DY#4)xh&FX;9Cq{yca<>re_lTL+39t|AGL zQzOiUze2!_VMWx~k$@2?%`Vyg)hxQ-`-XIg{AQ2qEF9g}}1Fhr2j{wHc2Z>38{QyW}1k`_T_)Nex zA@oCc{h>Dp?(pD;%j_KR1ABtjZsiombD(uL%qkl!NNvf~(t+gj|B>T4i+V^xg`PV4 z|HuDx9I!0|=?Mh4oQ8yjvB`kZU2xLCkcAsz zL_cHG_Qtp&UgXQd4NGH*Xu?kCN<+fL0LMxVm$FnCytJ!!UqiO=V&;(O9nA(hwDQ?_ z{BDCp_TcJOIqfD-m*+Okxbf%WtEEL24~QaT0a0Ywt<(VCK+dv;-Dn0Eb452*Pw=H- zXod_fBCrgxxH*tCoMT3q7#k!T8e6lH6FJs|6*{SJZQ2vw)C7s4LL%l^5)IHr_ztH8 zQV1`l5OSIkPUwoMb=~hr;L&ly1g{g|fW}4u@!FX92G^ z^MZr$^7iKTfm3h7i{sCn5`zB-eHMfnO`jop>k?6fFV*D>OqD?qJ_V*0AI~bn3$dkH zxA=XRPH8dum6`pd>Q<{(zCM+++Onh4_njuc z2Z?8xj=X<5@14_MUW;tvx2CUM67l(D%lciH$lmPc=E|%nfY!rYgWzNddXo(#ly)jy|&G| zxBb!Hm^4XQ>EWfvnnf&sb+AKXCM!AWjNP5;=j`0AgF<@*_srb8A+=tOpXVOd@zD80 zR+X&d_)R-K%I^G3{HcFJg43^8KEJ?4J+HKP%VgbBxR9+4`bI|Fu-xu@aNHSI*7zQ+ zrWwR;PUvf%zxbD>AK6_m%(7~9?8H6u>thO@Bn92LwM>zF)x*92gw0;vH=SsAXYxDi zbW9tT-G-y3`K*ExPRSvV#mA6(Ge>NU;z^RFFMzPnUw)e+9xcla> zyGHXxd!1`P~t4Q*mp%y@dG%JI>&BLUalx~B{a z8}$JvBG7Fs!yuyLvH-$QEz4$KlVw}N2FZ$%wFS?I=jFw15AsR)dC_FFLS(3Hx`>4j z;*BmAt+Dg;4ryo_CC^Nq#9OXx`y9rxyG< z?{udbp)OS(^rGd$FXI@Z*)3NdhxvKcY;SElP1z{m$gyVnzv(@CS)|cJ)#F`y^ z`eu-k)4>tDR?RxR)lyKp#rb`kbw}sUbIELX%IdoP?ERwM%W_O3&vcUJ&3Ms#axY0q zh52|vJDpj|aD8?dJ$iO)U%PT7I+DoiUBmw;ybgI%!u-S#{z9)#Po? zJqjkvpW7-VJA#h5Uh&PH6&HLsX+elhbk}#Oii*4(BEihz#HwML>8zb@@B3$V-aMoz zcJIJlA1731gzU-ibdTI>t_tP1YuvZ-$YH6hRWB}{Q7(ve$;u!0_ON5B15s3O2vKB| zM!OkPeuJqODF1JuD=cQ z4X4w^aTfW)F~esJaL(SiC~Co@%>EZ{&rjT9>UMbJ_0{b+3^Cbwbyn|_100MVrRP5M zN@(54^N+RloSJ}sOKks++;hiIxK1qe9=xJd(9r#2$n-b& zeyeA3xnKVBsJ4Gt>@T&>+dm`l+53C#`&c%Q>EXI`i0n?IfSpnOuT@uvm5jVTbj#4u zj@N@WPfU3@F0R<&#S+in_osGn-@xs4bZ5{fuZvp^0yl5jIL&YPg@r1&m$5xcT6nu0 z_7@9BB<@+zaJ_x2;!}U`F&I7Rb?Wo;2?r+57_;wS3x!K+6W1N5+qn9<%<=E)b8gt? zX&anctz4b{gx`GNUDv3Esbi~LQZBaW7L;&gd(U8JgXa}P`g&e&bx)eouzO_Q);HMQ zed}07sg(yCZ!L4Yl-%tP|0N9{wTjx;WLNmGi2H{Q%ZA*M{o#E3K;+z`&&r*8R*szX zBqoYjxpwmHCw&)h{BUbidex!Xg+r^aRCoI$s_jZ^*A*)ZGE~2hPaB-N#k2To&jtMs z3Rh@I#b&A`R5Z|~%cSnVfJ7N-j^wRP$PsPmF;x~iYz1*x*2F#on6vr*Tv1zQ` zZ;N98p0#OTWNG%C3wN%JooJ@^fz{vx9}$+uCQKyR7&nAq57Tjabvh$^O$Qs6p?Nb? zs7fdyp9{l6sZgkCLqh~+G|^CF`;7<#Z~?X4oXkCd#hDtm+r}vN?&Foeaw=Ml;}Lym zHwT`Gh%1dL?KV1!@j~FOzI1bxkAp4FLM5tIg8G8qg4TkvYMfmv!A^uc(PxlS@3Zif^BA#tnIGZS(K@^r~nB-wV6pkc<)#zBbE%#gK zknglGV;2wpQUc2k`qNh*{`B#=;}(o{Ya_vBD8K!qq$ zQyTMNH`O%>U{ERVoAF}w@;P^s@*O-bUQ=YWoNqSE>aJkg+)lF!F65g}Jw&E@xCOmA zEUU;F`DuUfL(`KT4s>4qOO2>faG<64^4Te5@zjC|k@3mb%%=^z;Ly#fremiG3FkL` z%(@p;&!g@9-vb?&U)tU@Z-#%>BjJhgz`;XW)mRs-n5q~#>F-mmS&{9^$6M}Qw%W*i zes$)%OplqR?Sk87^@?Qo2Ch$kBR!wYezm0EtZUenC6Q&lYi2Ju>DI+^uB!QYtnJaw^Opxl zj zHrD1Wdx0dq+>+nPSAoTaOrF1Car4V&_d4=F5S?_on{yz!EVWTJ`m*-8#6i{MYdWo~ zcHoH(i*Qx{I3M2{_Y0oel!x}rJ-0IV#%*I2v1O%bZ{m2~<8Y^o&0TEGqB4HFAC%kL zWPb0d>-_svY!;Uc6fJ1wp0a9zGH=*5L+;)Y?c921MZJy98Iyhg(1Mabms)R;4GA9O z{rqH-)1~$6dS<--wddHOZx?pCyQb)E_OqO3+t#zIQuYpxo_JhX)^zNRw+rfz5*>Wp zzkl;_dpn=&c=*cfGjG;DAwJBJ4D`*m4s0-{OYw(Qt?l6HDfyW>dx}Q7_Z(RD%U$;e zyxXJhs6?|`)NIWi)Gow4I>d)9jJ7*{$m7|ychxbbt6Nm?TZf%3Np5$d`pm48R&Taj z7tiYz6WC>a!SBJu%R|`BGZ#nPTp4=aNiZtMv5#+vYr^Nli+cGi^F6mqydhR}aPPCf zy2l^!9kDE6WR>s6z8_^JRo#7VDb~E7<$U~HX_%L}fPFK0oZb za&*J$gC5sp8?3jQjVH&%L>x8sn_qAsa8gxqRQdFVlUs@AJ1bT+@*qF13L17`!IC1o z*+h}ubj{=%7~q^DyOD5hghoP8{l!iSm$F&7!I$-yB0Ry^Of7}*wHT#Ecqq(mAh=Y2 z&?W|Sac@%typ96Q`!&|j?yW4hANSfK&uYutkvk_$@7(9lLbpb9Zr$i}b6-D}ar(?T zwiW%FSVQrGNBBY!gA1=*=XrSh`Su|URV@7P(!z>mg=dMvQ~!~$*oA0?!eTRPCv8|9 z3hxDgc$gh0MQ_o94FPga8^VQd)=Zq3DI&9l?4-m*c0^)q0GCT}-3jjq!adxd=gVQ> z8R)`8du`oe?^2EwHjh#-%q}gmf|#Tp8xn&0+PV||`}IzX9%F9`?m`6_!++P+D3lot z`;Ty-HQ|hgW?Z=Xa8IvYL>w@w0L~*p5yI^GZ)HOH!Bwxub6exEa6hfm{0FslrOB9 z1h0{w*_>rp^T}j)c#@H=!X;~)cQL;5M2l(F!@>@#!WQzj#Scv?c+~LpLxXYs47Lc5 za#nR*^K`gmdBjw#sueq@{Q9-ee??tCY1g>pzOt8*BT3<$(Vo-W#SDFRyiv`YBXM`4 zKKi!V?t6N~jHxfTT#flIWH-nOA4DH!G{;bnx}&_kOo<+Wn9q+3oJv)-_LK4_#Mo zJMlnf6z|&Qh1c8m^~}5T!hW~#^z`A|rg@*UGs*4qG4ZSnn!~#mXGyZIz0cK zu}}E00ZmW8tIpv+2b zN6Z;z^l2%7eEH-{QoAh;m8_%N)u}}k*ue;$MB;%VC%@WvQP9;M(QnQ6hRwTkvu9wf zd|>g)#wl3;w3Ly5Ke#}ybWHTNeKGCDCCkWqXfx;&<&4c6{vmUArz^ z_9@=5x|!Lw(Sh90H;+a*^ zfqms{p2B?Dx#FH1f@G)f-5KI9GFjxB)%DcA4%hGZ`t)+-p7~h^0-oAjA76ih@_J|N zzV*8P3*&Zl`K!`7+cfCCMcd^Uy?aewexQZRvUQm+@)L$nbGo_HcEYr%`a{5!|=pRm;2=xJ*Pce z)rXs&w4?vnsykKb@d{h7FwlTg_&rfXAOERo1>+^<@zp2{2bX*_NV`opd zn1lVsRNtLGI6dUzB2|mv28V?gD`vXvirFssu#eaO?WqAb&Ep$p?w<1e*UJ7eONW*D zI~Goy=U+7H+?q2Hxr0TY7Tp~6oM>~~WNq8F5#`U)&G*jS=lS79oTEj27d!`i!{ie5DHomom)-gI9Nhi8 zE296{CTn4qzx32q=lrq;my0fbe7c}sy$h?eW0l8GdiQ*VkI3$Nr>bmsklg_8=YDa& zroWz-v)Ffd_c_|6rRBeUw+)Ev!yIXeF4 zq448_`gP~{mYVvBCskiO4$dNT4WulEu*RFfzv){Y5@Wz}DdmM&x*Q@#t zpJ?f{FyYgVhiNW12R1yH^7p67iRZ378Py}^*{yw(mfb6vvc=!6`+`SOk;O?Lcj;u# zac|eMd)vl1AHH*9%JA(;Q*OR9N}iLG*H^^+gf4cgQ>|3sO~kD%TA6dEyiOs=atsqwWt67#aLhAzu;WtC-=$D{A=M^2N^1 zO{!NuoI5Nyx^iRx@|w%n1fugehJ-E8dbXN*%)s$B>SjUQ`xggZxfD;vYUReW8+E(-(TxDZW26rZN!e3 z&BpYxX;;n^}}GXUcQYBMTr+5B+DQq;OP9(tghhRZ6m^ zJdd8+`B$oXmtXZbHRa*bercH%fitG|y?S7TQ=A?JSil=s;cOJ+1_ z`SekGMnGcBtvP#kG#h-)$78|jq8^yRCZql19*XYlF?l-l_CU%0wx`6`g1ad3>rH;k zDKdYV(<j(2i6YR(R@!V`+VR@l_C;J5Dc%Sm7hxu|3x2&P!U^kP& zHjhfStnPa|>KBFiz9%KB3xU6P4NC72w|DeAFNf>1{+{xx1b=n*nBwEBXqm)vt&%v( z+ce}_{3p|1w?aDpnv}Cppy=YZIkvO=AsfR%2ZV2(_sermPBtmqiua645?+^I9nq|B zI6k?LeMy$Z;$^NkGwfZR_xN?2Cw|`|DQjSaRp-@z?c8wu;kf>B3oo3H&fVTK$z-z# z4<9~k2|ru@$#n0N(DXpj$5V$wqlOQkzW>yl4)=F9KCta<&~i@q;(Z5Lhl-XCwQJgV z+$8CzKenHDbr@$h#plMJ=(qDfn?B;barVw=f5&3i?-S=i*lA5Ssof>JkWAm(`0V1 ztxKfoFP0P;#6$k$N7c&SF8RMO{a)J26bwu~W25#B3|I~Zjj^g;=lk0%7L+Y%@4La^ zk|bboS?j%}P|Pk=EgSw{_R~5`$xs7e8DWnj`gsy9n>5rEOgKC*!ncq50$ipq5P3wP zwmM^ob3DPOm@)v+>W3-(VX;g;vS7uc9`)G<0(8_Ma{Wfsz(=P$3++$QR2fmZhgE7y z)JNS6>Mda}QGdoqmwsVWV9$EHOBqx8v_89ByxX8`h~>J2Tiv(4OZn8y=7ZO$!?L0o ztwIN`stGY_H%J+5AINqhMNW@RL4j8q1NhH5}Rf{bfnx1MB=u~!bvv-rIj&DS3 zrY4>}c;kH4yW`eu!`OpKr$%kFD0w(`@%hS(%Q>HxU2JiD&GdwQAF-NF&YM$DSPWcn zmb>PP(}QJ|*qQ>D&vrNGCXRUQlH7aN<&DQ@uh?9;ZdTogB+BWs+ z(P6_g2jRzFD*FswGvgc&$D90Bw&X@-?y9!kM+iz)joo9fdyH~lex~i=1?Lpw4y-L4 zu)y!0Ykw6{5VSUa@!N-?%PhQJ@{9SK{#?Jb>po7Ap#^L*GNE*8`hQoXsOocFwIHUS^Q#z%^Is#XS{G* zqVSy#0G21G@G(*N2T^#RC@eE%pWFM(=vB?Onq*4Y3$|`w+kZ)mF;iPAfo*oeOf0n;^R^PJ|gR@2+^Vr$)*vr0AO55(4%`avC%^9D*vm$znDef4r zIyKuy;rWq!&DFNwa+j$lz71P?v8|rF!EY-#E;C>&fO-T%0y4;ZTps+@@&{ zLUx^e&^NQp`I2Y7HxKu@6j+N}9$DRN{O*Td!6|Q#mPS0Ek~wzW_L`Cw7q=Z$bc;Fl zzUaXqUNb|BlPMebMfG><>9?bUTZ=<4ZC(9+`ouSrS}uJvF7B<%i>IF)PVUa@e>ZH^ zV(F`l#TTqw`xeF(#n+z_UU_A~KC6C7&;RN#7;4~UYya|b;CuIwQ%?e0 hPpV(nug+o}y?3EV+NTSjv`K4cKdpMC?KUcV{XY;{-dxc{;%$>K`{xQqa6|Ij1&D4`ihmHef&VK86dd`nZoN> z6hetw-amPBbWNwFjR5bUm(NQj8KMH*wK)Lb(S3z>>pvW5m6t-P5CM^HTYpI4j(WjQ z?+Jn7@={3BCiS)2Ri0#=={U+@uLV<)^ea4&|0!GU-NJD4*ib8w!xs0Dt=Fg}BMxDrE^gCHs zBe$#BGnhKdQiu+AV zd6F$z438#YQb1BdE7?OglX7Sddqg9Ub8BhmKEe?a-&s76Q9{LRw_MEefU#=sPI_8X zOavt&P`D+@P(q<>EA-tK#;PI9#selV3xt6GcXCXvTrW)tOl3nTN00| ztvA+pmakS-Y9$%8FjKP(G)klO>jBmc3RI^-UAi>bGgfRzk|760v*l13+XJd%d&ZI; z9C!l*s$=JXj+mZJNTvs@k}OX@2008<|QPcNkp5OeX+!NAhlJex4==u>`4F)E~mN&(D!V)@$5m?jk;Pqt?-;46%Q9N!SrWl}ffF5QD zxr{()8oV<>$R$Cgkjhe&Sb_B$Pa!Xi=dGRs@0Aa?J{sy`~!{BdGUG%nx=7t ztXS&au+U;gxDg9gFfq(Dz_5&THL^xo;CEQ)Ir-cG=rp%Jd7Z^V-3>5o#KiDA4O`Q2 zD+5!`({Mjc*+t7|kzyz_jKn1u8Y~8xL^g(fNenxgVAvGsY_!sFf(Z+J(PEZ4IzSvT zW}#k?wnC=twI=nEIcqV?0X;BTX6%GS=p{fI4aWd`itphfJ<}tC$0_+QDItDnf<^pDE zFa5K# zQ*}^XiziL#NR;d7>U4dR3epeFMwMiJ7~xeU3oT%60yu%ajf~?!C(vknJ0oltJ#^S! zl0ca{>>ywxbr|Lq>#!QgH&=%l0Jc(xSpc>}jTw~_$4C-Y>+wi*U5A|_8K_nx>1=w8 zG(cZ8n1p>1ForXNN8L^qGWiL!{t0XN6Xv4BYQQdi)R@s+gOgyfL3%tx6s5;ALS1w` z3s`yjYk0U1#wb4rz)u>v#_V zJFml@lji8DMiRH$0@do}gZW2er6`E?mb5^yAiy&fH8lN9S|M{9D@AE0KS*oTT7%7G zu^2W;ti#M1^-+-yb7V9?gef_h;e!t7urdZ8ou#o7`$k4{8NTSI zE*}BD;vtO{fM&~p_eziFhdyd}!N9{Fg+S{G3|oK~Q$rFdu`8h;m=$<&(?GT4F`6$_* zQP-#~zX@G?4&BZw=mm)aXo^0ZYG?=Z#}0IDjPP1v3D5xiHcmSOWW$I1Vc0*!%m2b2vk8s(Brkq^4bZi+n77Gp1Df;KR`z^82m*bwan=z?wmY>plS z@`%#6HH0&)P@8^r#h$ z{Qy{i{Ege8@lbC&7{v_?5uFxk(o<2Gu@rpeE_MM;$Fph!qX585Nkfm@PGQwnIxB7ni{Y8u|9%ehOJa~CKH?0d94gPe+nvYBK) zXtHRqDZv zO0JVn6evKSk=O(V%N1#Lj2J<-P=al@jsyi@LR7LQQO8k_^KazP^mO^)pUZ&xBKV!E ztE_vfMD`cO{>+LPqLRpzFo)`-wOx+{)prA{`y(?-mMm9f2=MF^r2i(>4%#MBXpJ*s zNTx!f{Bt>4!=Ow0y$#_KrAQ&ACwU$7r$MMAN6BFFL2H!Vq)I6aZ=$@87cWUp5F|@f z+3_&tm34Hrh0&GAOVR~H=#(B`tBW`VEEXbFT}CaVojfyJAx%luV`&#E=o*fo*X2>i zo7D5Nj!I9#P=!K}T}RUv5tk)Qmx?;e()D2u) zuTfWp^dBu9;`DTsn5vKuhUo#51og;B|NDF}G%C4Bo{pkAWC?Xhs$LrR8Wtj?)Vwtd z6UqXby4^_AUcH)h6GQ10F3FV0#1fe(J4!YH92eNUuD_DxbPXjcL82HW6@mW2_SHfn ztxLkID3}BGdN{LoV&D!&3=v6a`_`-bcRvIxYDNa+{G+eJrGtRBc%@djqY~F87AL?k zq)SwQ$WaFENl=u=zlCK<)5Q`6t-HDsv{X>y??nB^(*xB(lAZ}g=xIM(qL2=fh;h3# zJ{O8nJ7)#*5~<`E(l3qKgi8e}GPzPE6)9=!)2LFZQ?uH%amQ$f@Ec#d+#~hs4jl&X zE>Y?>4cJC?rRmiMC5k1XuxMl}rAj^R{zQ(FiPE#6G~EJ&ej92Hq0VTKrsKa!>WP5H zep4^jnVv}9c-ImCWRG5*75A&r=}GA|Rig!Z8&TH) zEj9J0X`!Xc)q6VH5HuSfjoB)ZZi!U;TeY=lEmDaD+U*cM*LC|AB?8^3w=mcwGQd1V zk+l0l?X#p}O)?yI7>TfeYEW!za-~$I#Uo@{85$OrN`S>zgW~mtt}9uh(2(#_6D~;> zWTmTq;UtOwNXA9tbzYMnw?z-_EX3=MdI3{Pe%ndYTdm)zn#l!QTD`&18$!(*pxLzj zS?1Sa)(UGijo0-EnK(`^m8t$b%6f}|PLN(V)H9vlr6Q&J6)#DV41whloFToT*DRQk zVAyg+_AljYsSz2Os%(7TXqJkykPspYa`^HfLlTG~sF0M#!hj=%uRvm;DnK+uva9w( zXl7V(>epiz+ReX<7#u_}IRs&30Kn1~C(R8wBw-E^2weK*9PR5_5G2sxKTLH(Og6BL3<+CH31KN^sb9EYYs54pti;9^ zB%zi!WJAVPRy|DEq^2gTK1P_f$trgn)R6-PF*$I$1Ynhgi@*?B<`%JVJ9CS0%Sq@B zNw-^Sv}I_YZVmXiii}om%MNIEeRcoba)<#TW-fdP14Xd#2@vr3gitR1g#?bKwL#68 zohvVf9NFL;H1+=Q!i|c6CS|~lnGD?qo#r}i-fcSXac|-!|9g< zK19i2NVEUUOoW^nzvQ%ufE-ys)-TScJ#8D}pNK{sp=xYK4zY9wY&BA_C;g1wzfYuNy|)tE(xGa{X$q>>5^GJpjGMWU;u;F$be+Qe0#h|-BCvE8 zBCG^f0*Gtim$?~Y&~LR#8*4C2X+6ZG>6TJ82jVRlx5_eCi&$l;>1-`(DYZ~%vC7is zvC$IL?bcKQO;p=9wqmQ?iFEt%YyxZ`#9|1D!J9KZpf`|!Z_3aYCJu{02vi-gaKc}F z63P1A6@tuIxlFgKqE{Lv0dm;T5sD#@qgQN1qVA;DLbLS?hEK+RUOrHWxs8sgiAvzZ zu?^0}(Q!Dmblxxm}5>AzfDy%Hr#m9hm#y`k?U$quF{A3lX2egORnRAUt7NBPhM z4d2(tm&fPwxLA^=;}raoc|3tnAjRh=3j)Rdd`c83H38c7U z0go^C5d=zjLV-Xm?0H+ls5{LKk}a_KQc>3?~DZL|2qu- z<--s_AT~aoNL6qmO!Wx#KG&bm=lLU) zLZEsHbd*M&9gb-6ct@xV^7c-F*in|yOC-THJt0V@b_(Wig7Ktdoxhz3XmN|56b$ZKCE=Z~UZ9Ei+t z=;ObV10fDL07}Gg1;mv=jn$DbPO@CV2~CKj7Y`g2<7fkm$cjK_0dPwtz=!X}^9!T` z)OFFM=Ks8R4GC1gu5tQR!HpLJx#)O*h;C{(bI2ds5-*{*yRgrKfpGmN0|D1p2xK6U zwS-GE$eloiY4~$nB56j)t72g9E6q%o0Kqs)mI`}r2;gC{Xt?zB55(|#{jbCf==&c4 z;enE|FZfqkKr9!6*#Allj0THgpQ6`#Ol|fjDz5n#SzM9FpDH4LEiwdJ|9j>tpyF2Q zRsXAM3FtYf2}S`civVB-{!q6y$KH{F<1RQsUz$Omqf1j7j&p8sLDixC0b$gxP0o#3 zU(OwC+}OS5hxPH&@2bHZ_V`8i*(+vj944IAci>^7S@(ka7g%BE7KDZF4Lu)A6&-i} z{*-Zec~Y00c*!03%R5q@v(Z5es+}z)1D2YqX2`@;jcOczJ0tIRJK} zFxlbPR$UCeX~(v#|AYfVK&b-Q-AB?VPYIMML&h1PD-pQ(K%j)JKR(&0&#JTl zTFb;D1hh#-pAckl)cC!mYj|%Az1IHY!}%9#Y5cEkngFXexpcEz0+d)lIII>`z zL$^i&?@*{E4tYVJBj5%(ht8(}DGt!3P_GPHmk#=Yd+_kBQ(Lb3Fp~|r1auv^-7z39 zg7)H*n;go=wcyj7fU16e8ld180CyYs@aDno%|M`lV}`msATJ(4d>U0~ zG*Z{|-~0W4(?&0dPo%>?1V-!y^+iKnDYWjf4m07Xi%+2`C>2_P;8qFe-_W-gNQcs; zbM#740u_(6lJ3#$O zHO0qkL!uwOmIUn>dh`w<8<7%L9I|CVT1t7o*?lUXC8F|~oyr*`L6X)y_*1U4gQVAT zpAie&;jv+y#l>nGOPE5FMsQ6iV-}+;lVweIP2gHnmKZUzW_O2UGkmau?{i!W${Z67 zt>OGBhVOl1t`p^mDQxRMA6B^@lso1#tQ+fgw{VyhtIwHGDkrX8D94B5aw#V}Gl)3( zz(e`?`to`K>Pz`>12rfm`fq8U8D*kw9}^#eseEFgzFuIc82Q8`7+PW+nNQ@Qg=yCX zy%$b$E`D#)VB&L^WlKLC&8W0!mbGVc*G?ICR-Tv`5j4q1(tcT~Nub5!*ap70>>sp| zO=B0_J2v>U<7=OJHgOx0S1gG5QPaez{hd|mPDEGy6NnO*w|{I*rj z=dHVwv-(5(nV%j-ux?$;ESy!8m$7PN17mN2WO!^-&J0{@Ssz~;`ddp5>m;oQOE6WJ%7a+v|(Uqx3=9=cdSk_tPSwqP96@OJ#<;g zN^ZcEW25X&O($Li#>YDzy71!-A?<#ld5cu?y2?%B&gdN(am8Yje^t?OGHqNpmnn?c zb@9DTv*#~b_>I%?OsS>S!6SD~FOSK2me}UX^$OLXi(W1JjbG=}W$h8qTg9KPS2|^X zh`-n8ZiT~(gDd;jFxw0D357xjvj`redg+7m)-7C6(`{V1yYqA%; zvtE0pIW>En+5O&E(uZYS8~@&F|NRW7i(c98KBK~{U5}CZF(k|jVo^S!gb|TbjbZ2- zxiRgj`nt&zZA7q)U}_l{7%~`CBP?Lftk1NGSu*X#g*y!&zuX^mxkZ=0!`qGeN>CA) zZOLpywXO)F0<^Yl@>jN8pR&QWVqk5?_v8Ec@S1~tQUN~dX1L&HlDrMF0t zj?Z>5Qy?A#Qv}bDBn(&?_+%~hSmmi(;bk?!3X`$0M zZQc|VJ7BHJl2HML5fvY19GqWsevjz>!0Hb35!iVSw-@vzLn)7~^L?jbKZZ8}cm>36mG zh^@h-zE^!B7dCo%;o#u?AB3%Do6bsZurKK2y-`2duH4>%&$~_g!h$0YD&EB5$g<(7$>f$6U;3rCUpF*AcE^CN-^O1} z3E7_F-7<26X>O>%)3!SEz<*_*S+v*yIQrDYHQRNXMifyy@=O63~})oz9@FrR#e z_WTTeV=)2mk~j9hW%-6r5qL^6tee%jmv}k+$#grgZ)vhr1mCGSp;@X_IfVDJb&dwy zjX$2bzJXLAb~Ju8%B3*+A9sZLWD|Yu(LRW*2R?{olX%Xpc=cIf;pnyMl5BatMGSxY zo6S9(=Z7`)OnclbZuwSLfCDpX`^aijr|bS{2dyrdyb9PilePA6;CaG^8+NwHEL%Kg z#I*jd>1*ai&3T;K@665F3G3M{s@GhuY`%J^@tTXJJ!|?q7(7lM^vEaP-OBsn3ZuA_ z8^X8ry|mwpk+mYV_Gm_JP@e_$-$rh~6(C+I6Z;NXQZB03@@&Y|k9Thvnw{^Hy*R4b zL$lrG)`NFX3x4_KZu4FijbplbEF7x1Wfim~s^6vO&)bz0TpqT5*yx6r+pL?=_fb*j zLWegCynEi8+^XejUXKG?+I;spyMYnBZvC1m0VB@L&28~6wp)p_uUmDXOgu7S`48dg6zqSEu6lOqe!iXO*+cEy>7l*7&%4~s>|3u(0+|FAy{e$e|5KfO4)_wa=pVg)_ukgy+v357+#l9_FyEC#p zea4wv7sgI7(fYvW-~%617A#}UPSTcO!e$TYIlVtRqXxPRHYC&3i49Q+^{s?ZdMnhZ z9upTcnyRN;`wb`txPYJBoT6nA$(`J8n~g#2?I%kQaZkGx@u^;FHwT`G>RcXE-f47{ z#tVVB`rXaZJ`Vmz2l(D1?TKLC!mNeKs&jTp6feoghjw=Tw9XBjT|5;>#cFYIc42?# z?7T%e1DDx?_# zMYbqY>6NO=ph9#7kQCp^hto(ec#;I66FD5ZacC+Vf_rcs2oCEwkb{F5IHcpnX{5g- zz=BG9-;_6_7tgqrnC;+o_L3^4$!wES%iE$UGs8-A&SaZT-YZG+YSHFnwc>O}!S~&5 zAF*p%?P*`Rs8)Jaw5N&h;*qmUg#|p;xon z4}u#mKDVjS;Aw$(9*d8J2M-zQQfr;FWU{JY;@hL{WTfZ5aTYr&Dh*6$KTrLf>NUOG zv#n=Zk0?=NW2vmyjM94rZ>uKNMmE3kwbiLzzAt5NtM9LA`ux=OTJtqCJ<4XpmQf2a`TU6B{2COB7r$?Low$?GpCRH0^-rb%w(ot@k6R~vA{SZ&dqUyf!!qL@@ zM1EzXZ(gbW_@@4XSxs*rUtD(TMPE_q-QI?C#e|7E%-uIb z51D(sxFPX=R`z~DpVCX{!h*CPdgB#e+PmbwoA+@~+Llgbcb;Yqad`H`e`dCQrymzKxTI!1So8Vo_@^ehPo%BZ ze5IZl46*ca9{Mtry{_$-WydP|?p-i;cK3nZVmm}s zg&mnas5d*eL)y3O`FnR|WDGbGue3HB8h4zV?=X?dcPN4*CY3k+Kkc~w@|3A}@GZ|< zO~C@BId>W}xTd*8%=Os*rr(qq zPx}^ibM_eL6ST6TnlDaV5w?;F)5~tkg~MgJO|I4NG06oEx%PiGr}d{Dcw%Ngk=yvy zoE~M=2fK6g@;xeFKEJ=5<$nG8O2V+Zq-pqsM`PEte@Qt`dlyc1KC>`p)#-}8>;0zA zDD2+H{>uJ2%&v#2FU=Ed4TOH|i)2j0nUJXCaq9n}Ue`{v!i=eyDgr9;t^REgMTKaQN6)w4#w4%P9iR!CW z_=~siUa$>5wl%c-U^RT#xkLSidLBxASunk0``#x;b$in5=odfID8KJ5bDO~CMv>mq z&uwGtKZ%;JxXZad{eeS#dCB_Kdty2s>2apiX-LG${!e`8OnPcCeGYGF#Hz?n+efD5 z#=CzV`1brZNx|`?&Yh;C74|BWI(>`ndI&(PL?EengdP^PSZ$or*_xO5IXsE@+>4so#$U`F3SgzTH&a;KJXu zar5m8fHqQRAvpeGmkFeFl3@HEf5|7}SteR5w15yyJ`oCI8w@Tr5N4C6=)#_C2Jwdg z%)MhvAEZ*QU5}cioOoQ8v~Ho*%qe-bA4M1UmmPhvD*Y?TN}k^HTB6e48iE&m${&Il zJh%x1S8^!7UKBHzB;JMz%f+NJ=A1zkSn!pXU?Z33}j57Od+R7E^ zO-lFjR?^a@o$I|hblvM5e@yM=mpKfj{6*3XtDQ?qzB~>rI>9}cSv0q{IOO~6%c7|} zTXSU32JAjG{l=4-aa$&2c8zchDSSO8VdnV;yN1t88FRSl{%5_0aie(?(@l$y`b=5N zsW9D}d2Lhv8WUHaC+#+`i{JZHYEXN9=H7$N#*P|zZR5KZAELL!J9Qe-Q8blXlh`-L zYyY`fj%7J!c~wHU&r7+7Hr~J8q++~vtK7r$f1KU;t;?Z#=lg!y*Qz?6-MH_;V{7J_ zxpnE*X8ZO%4fk8tFIfCzySYnv(rcqOHymfAIX`o`)^aEJ;N0N1e!G1S@gG+UgCxmg z3%{D~nEY~3DC>B?mxAEu@~a8E-TjvwU3|VxyALDV61ANwE6*Fv?tHh!+r-K74U!f- zUD8Jy7JIPtOcNjX)H??*R>u~nyqk}%Y_3Y(mQ`l6djI{Fwk;i(#g^~eKXB{Jj0Y9x zJSt9}J1T{A z)|}mSZSGmyJ4*_#KP_XdOyqm=3bx-F?R+lvgg=@5%_6O&EN1f;msg6O>!%!by&1VR za_-A_+M`7jtb-AH2Z@pqyrKg}gIuPuREM?fo;7 zr418&8$4D}Nq9@$nAwBsMkSWVm&c8c{VOl~OV~^O=Zc%!YZ*nSE;GU1xWfZaG+8?|Mys zc--@*aa+F5yxXU0!902I7Sy}F3x`F2&fYsle(G_~r$wqQamlTyMXv&vd)}u`pmFa4 zo>xzqHgVDRF#qz#f!CA1^juZ^?efLb#L!Qw0X0)*x8MxjzIs#ftxuh<-P?Wp@c8dZ z&1OF_bITgtH^0-p5##+7>-$U(ul^R1{-RC8w$pCEjyQOH%Ij$FmGv(TJP`Nx<*3p& zucHmeM$a}}a>_frW4`j`r9%N7JVRQ)u4hp=Wt#bg4Fk@!e?E2Y_^^G=jXXnM7}mzm zwC9hXa$4?dFL*sUWN7xg#qw=&mNQNYD)WwY?NjlNecygim(y?COkC9?vhq@7toez8 z4RQzPr!KT6{HKU$I-})vGR}6Iz8+LErF1yF#F_+i7&Wf4pF2TM-BuZ*|W|^BHIHG)8>)0qh`|4GuvOR z=Kr1Onc87Opo~Xx1K?AQFE~sdrAB!e{SUkIf92rr-Ch#?aHGQ6Bzxh}i>}$b%+Kea z{q|yxq2Zaz^w_M!HNM^76C=|*-nz4ETN}InydQl!A4>i(Jz-$4J0m*w`o7gKWmKe# z>86R+CkOjfS=c}7pEDr7AbiV`;>a{Zo7w||-i?mCwm1Cnz&>5L{^jfd*~I4;>s@kB z7#=7fhwfkgO(9*=XvNC+;A`B)S7x-@?l6qED!2ED2^NlX5s>sCb^Yu*L!90W=nhf=Sv^W9Nsqi>Y9H0YR_L%2Dgjd z%L|MyCU=IVdRaUv>=JqB^sWK+y#$1^CS_s2iyni>J3M>E#ig8A`#xK-FN)-*NBqR& zdzUXMaPFH#sY<3zyRWQxXYB4F3JP3GXt6j8)scSjl>_0JeS6Q7w@07JHMoLq;Ip67C*e1FZ4X)A01yG z>>D_mk20p3@LY634jj`%|GiLBI1VM%-F&4(N!GOI`Ni%0mqhi>zwdT*(xZiagsG>4 zr%mpC@x(0q{Zu!#7w=5L=c{t~e5L!g^lwJ>@aHS4CFR%Bhetc_URtLK&KrLK@2JJW zdAIpH=lzF>-p^&Lepxw_7w$A-Jx+Z_iV7`dTS}(#K|Vo7nc^A?sLE z%YwPQO@SBp4fJb!MVvnTR90Zdj(XgC`zC!!KfPd@eUlfDlT(5cVy@5FzS(KWB|on@ zmHFKeW39pNqDRtO+l^lgyE#Crnv8MR1dy7O5{?wQ~R z9orbzt0XCH^lrEe#_FCpHaIH>yeK3XBSSdm2?;IAEeDegPF$MulbhY~a9ic}q1 ztcz{ma<2_@;2!ZO*WJpDnquQ!8;I^viQ>!3izA(ShZDuU8kD4&&9CsdmeRn(b$dXk zS+XzAiD?5OEZbMU-m?1eqoRJD=bkwgJ!n(+MB{Z*B7DT~1@K4i-`P8!g(e3}za8Bh z8Z~0X)ZIrvwz{{)cF)EWZ5DI86z<$Z?#*8~%&w7b(ZtN}4>z6ia40gF^%B-*q(sQ@Y9oD zA6^kOF33nY@^YpqA!g!>{EWp07JCP>23Txt)Ros`!-CA@Hw*F^ad7?#pkrm97W@x9 zelK)k!vbT-GH7njARQRCXoYmlyZwQFE03J}7N2@aFz&+e)Ys(@%+AZL81WzW(?7=m zNCWgFqR|VgiG4k7z=Z41_2W^!v;+#SX0=V0`S)lHUJX-xR8V| z7KU`%x}jPiQZB;+etOwSd_P4OWyIkgvYbsB;cN`U1)K%iG%>pTw>5n)k+{)EDYX5|tp_8-wHI2=C5oA1h)Vz<`BX{Jsi+$W>nB(fw<~Orvq*f@7 zjCNUk?CJ6e6R*Wnt$E{-L94uj?f9j>PQe}QU6}hur8Ryx|Jdd1F*{nNjhmldbo2`` zY>5AOFT1VX8@HN0&TvxW{lWYzP0q9&zt73D>hp+&-z)ced)Q4_*wMa8*|@5AvGX{) zi;MgcDyN${?>I3in^Waf$gdw9ey&|vX_0kd{`hsv_I|p%WBe(;g&%k3^vqJH_f6TN zLH+u*ww_?IBmt}4Qdjo>+S$0g>xP`=``xI#8UGK=#Xl^g^GP&9cJ|em&MUe#H)&sGvG!$;MMWaVt_d5? z^ovpiLtJT94>G5U#eS2Koe^%dAHezQf{n%9XB^p@UZhJh$X) z^@hQQ>o##`4vMZ^wK-orb$8z73^KxOu>7nvJ9zq``0{28>Oc74UQQl5+3x!y^OoJ( zE}iwxu^?=iDb-~8*!J5}yPxebbiB+*N-3)n+a6u)K6vKI9erC2$Te%#!Eg91$1x*5 zWCm9rzOnn(;r^q`V{D&B97x^tE$vfr-up*Ko3k67KVQ3WMf{Ou8|&poQuf!8_g1AI zA5}Pk8M(Q2rSk-zH6t6{S#xUdYT>+BPVP%g<-@x2y;EL}S=2rIa6eh*_V(wLg&XBN zQQn3N_xv0NKc7+ZBrgBxl>3Nduyx(Mww52Cugxxzo-~?qV89w=^dRK5N9BbAyZb># z&*O?O-KeZ6Sl2V{#oImaM|GU{^b)UfgfK<4!oS|=pIrje_hHh@V-9|{;-nO z_QQ;Rot8aX-n>13k8@Iiqkq?=nET!9U3M%?p6;`5wih9tH+_slQej%qkZSt$`hNf! Cbji>F literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll.meta new file mode 100644 index 0000000..526588d --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: cb6fd15fc28add14c9e2096af0825249 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll new file mode 100644 index 0000000000000000000000000000000000000000..742ec691eacb79fb0710db94ab1fe848ea5d783f GIT binary patch literal 44720 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll.meta new file mode 100644 index 0000000..64252bb --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 124879e8711c7a2219de66502a8deb8b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll new file mode 100644 index 0000000000000000000000000000000000000000..d9bac0a7e1561ccd080d0d8c9adacf14d83d1c32 GIT binary patch literal 39584 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 literal 0 HcmV?d00001 diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll.meta new file mode 100644 index 0000000..fe32d2d --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 815fa3a81323986949947b4a82ee28ae +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll b/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll new file mode 100644 index 0000000000000000000000000000000000000000..6031ba1e94835abd1d276b9700394dbafeb2b46c GIT binary patch literal 26904 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