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 0000000..1ac6365 Binary files /dev/null and b/Assets/CoreLib/DebugLib/asap.core.dll differ diff --git a/Assets/CoreLib/DebugLib/asap.core.dll.meta b/Assets/CoreLib/DebugLib/asap.core.dll.meta new file mode 100644 index 0000000..c426cdd --- /dev/null +++ b/Assets/CoreLib/DebugLib/asap.core.dll.meta @@ -0,0 +1,77 @@ +fileFormatVersion: 2 +guid: 6cc76c7bd652be74bb4eecae879d9c3b +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 1 + Exclude Editor: 0 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + - first: + Android: Android + second: + enabled: 0 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: OSXUniversal + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 0 + settings: + CPU: None + - first: + Standalone: Win64 + second: + enabled: 0 + settings: + CPU: None + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib/Plugins.meta b/Assets/CoreLib/Plugins.meta new file mode 100644 index 0000000..77a4279 --- /dev/null +++ b/Assets/CoreLib/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4283d5a798253634689dfaccaba552e9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/CoreLib/Plugins/LitJSON.dll b/Assets/CoreLib/Plugins/LitJSON.dll new file mode 100644 index 0000000..b47e9a7 Binary files /dev/null and b/Assets/CoreLib/Plugins/LitJSON.dll differ 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 0000000..8f0984d Binary files /dev/null and b/Assets/CoreLib/ReleaseLib/asap.core.dll differ diff --git a/Assets/CoreLib/ReleaseLib/asap.core.dll.meta b/Assets/CoreLib/ReleaseLib/asap.core.dll.meta new file mode 100644 index 0000000..11b114d --- /dev/null +++ b/Assets/CoreLib/ReleaseLib/asap.core.dll.meta @@ -0,0 +1,77 @@ +fileFormatVersion: 2 +guid: f09db8f4c73f97540a96ebe183df5fd1 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 0 + Exclude Editor: 1 + Exclude Linux64: 0 + Exclude OSXUniversal: 0 + Exclude Win: 0 + Exclude Win64: 0 + - first: + Android: Android + second: + enabled: 1 + settings: + AndroidSharedLibraryType: Executable + CPU: ARMv7 + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: None + - first: + Standalone: Win + second: + enabled: 1 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 1 + settings: + CPU: x86_64 + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins.meta b/Assets/Plugins.meta new file mode 100644 index 0000000..bb2a372 --- /dev/null +++ b/Assets/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 83607d3558d16fd44868ee734e051f0b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage.meta b/Assets/Plugins/CodeStage.meta new file mode 100644 index 0000000..b16eef9 --- /dev/null +++ b/Assets/Plugins/CodeStage.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 52abdb4a4468700439c02356e8f3eb64 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit.meta new file mode 100644 index 0000000..ec998c7 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 52c313066dda63c459f7c826dbb8eed1 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt b/Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt new file mode 100644 index 0000000..37b7ad8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt @@ -0,0 +1,2 @@ +Please, check out latest Anti-Cheat Toolkit Code Library API Docs here: +https://codestage.net/uas_files/actk/api/ \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt.meta new file mode 100644 index 0000000..118d2e8 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt.meta @@ -0,0 +1,6 @@ +fileFormatVersion: 2 +guid: f4c375fd5bde53c42b0ebc6ee503f7a1 +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md b/Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md new file mode 100644 index 0000000..453358c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md @@ -0,0 +1,1191 @@ +# Anti-Cheat Toolkit Changelog +Changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +#### Types of changes +- **Added** for new features. +- **Changed** for changes in existing functionality. +- **Deprecated** for soon-to-be removed features. +- **Removed** for now removed features. +- **Fixed** for any bug fixes. +- **Security** in case of vulnerabilities + +_Please, always remove previous plugin version before updating!_ + +## [2023.2.2] - 2023-07-08 + +### Changed +- Improve disabled domain reload compatibility (thx KonstantGames) + +## [2023.2.1] - 2023-06-16 + +### Fixed +- Fix ObscuredFilePrefs didn't allow saving after removing a key (thx Tyle) + +## [2023.2.0] - 2023-05-31 + +### Changed +- Improve ObscuredDateTime compatibility +- ObscuredDateTime.GetDecrypted() now returns DateTime instead of binary long value +- Improve AppInstallationSource accuracy for PackageInstaller source +- Make ObscuredBigInteger serialize into JSON as human-readable string instead of b64 bytes + +### Fixed +- Fix wrong Culture could be used while deserializing obscured types from JSON (thx spikyworm5) + +## [2023.1.0] - 2023-05-20 + +### Added +- Add ObscuredDateTime (thx spikyworm5) + +### Changed +- Include ObscuredDecimal into the obscured types validation + +### Fixed +- Fix ObscuredDecimal might not parse properly from the Inspector +- Fix ObscuredString equality check against regular string (thx haeggongs) + +## [2023.0.1] - 2023-05-11 + +### Added +- Add switch for the ACTK_NEWTONSOFT_JSON conditional in ACTk Settings + +### Fixed +- Fix CodeHashGeneratorPostprocessor.HashesGenerated event didn't invoke on post build step (thx mhosoya) + +## [2023.0.0] - 2023-05-09 + +### Added +- Add AppInstallationSourceValidator to easily figure out Android app installation source +- Add ObscuredCheatingDetector.LastDetectionInfo property with detection context +- Add built-in Newtonsoft Json Converter for Obscured Types +- Add CodeHashGenerator.GenerateAsync() API +- Add CodeHashGeneratorPostprocessor APIs: + - CalculateBuildReportHashesAsync() method + - CalculateExternalBuildHashesAsync() method +- Add HashGeneratorResult.PrintToConsole() API for debugging purposes +- Add state corruption checks when API accessed too early (before Awake) +- Add Windows build hashing progress bar in Editor +- Add Normalize() method and normalized property to ObscuredVector2, ObscuredVector3, ObscuredQuaternion +- Add buildPath argument to CalculateExternalBuildHashes so you could calculate hashes for any build path from CLI +- Add migration notes to the User Manual to help you migrate from v2021 to v2023 + +### Changed +- Update minimum Unity version to 2019.4 +- Improve Obscured Types equality checks +- Improve how ObscuredFile handles custom path in some rare cases +- Significantly improve CodeHashGenerator performance: + - Utilize all available cores in Editor's CodeHashGeneratorPostprocessor + - Utilize specified threads count in Runtime CodeHashGenerator + - Make Summary Hash generation magnitudes faster +- Change CodeHashGeneratorPostprocessor API: + - Refactor Instance.callbackOrder to static CallbackOrder + - Refactor Instance.HashesGenerated to static HashesGenerated + - Refactor HashesGenerated delegate BuildHashes[] hashedBuilds argument to IReadOnlyList 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 0000000..7e3cf7e Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll.meta new file mode 100644 index 0000000..04bb8cc --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/ACTkSharpZipLib.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 5b329176be91acd49a93731a24aaf2ef +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt new file mode 100644 index 0000000..f4597ac --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright © 2000-2018 SharpZipLib Contributors + +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/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt.meta new file mode 100644 index 0000000..3ea8174 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/SharpZip/LICENSE.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7383ceffba693284fac4cf54c5767852 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures.meta new file mode 100644 index 0000000..207ef63 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 00101290d05d02446897e4ba15e3745f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons.meta new file mode 100644 index 0000000..a5b09ad --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9efb45cd993adc04ca803e6d37ab6045 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png new file mode 100644 index 0000000..7be3d08 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/API.png differ 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 0000000..1ff41f2 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Discord.png differ 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 0000000..40e7965 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png.meta new file mode 100644 index 0000000..28aea9a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Forum.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 29808f9bad076cd44bf828cd0f0aca23 +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/Home.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png new file mode 100644 index 0000000..a6c3e73 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Home.png differ 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 0000000..c254556 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Manual.png differ 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 0000000..149cedb Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png.meta new file mode 100644 index 0000000..c7da278 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/Support.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: ffbce22a5f4aa4748aa9bace9df0e956 +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_API.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png new file mode 100644 index 0000000..987ac89 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_API.png differ 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 0000000..adf4549 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Discord.png differ 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 0000000..d23a3cd Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Forum.png differ 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 0000000..3e0cf93 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png.meta new file mode 100644 index 0000000..55efa44 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Home.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 5f0296acda3f37e4a8286c7cd6d15234 +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_Manual.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png new file mode 100644 index 0000000..6ff52b5 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png.meta new file mode 100644 index 0000000..9f6bcdf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Manual.png.meta @@ -0,0 +1,154 @@ +fileFormatVersion: 2 +guid: 83751b678ac01e540b47cafc4e82dd20 +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_Support.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png new file mode 100644 index 0000000..033d22d Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Icons/d_Support.png differ 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 0000000..90a016b Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png.meta new file mode 100644 index 0000000..9d323dd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/Logo.png.meta @@ -0,0 +1,136 @@ +fileFormatVersion: 2 +guid: ab8f2446b2b4f0e4fba38f888517d7fd +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + 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 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - 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: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png new file mode 100644 index 0000000..30ef95a Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png.meta new file mode 100644 index 0000000..c4d2e0e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Textures/d_Logo.png.meta @@ -0,0 +1,136 @@ +fileFormatVersion: 2 +guid: 99edeaaa0eabb3c4b879f5515c702398 +TextureImporter: + fileIDToRecycleName: {} + externalObjects: {} + serializedVersion: 4 + 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 + 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 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + platformSettings: + - buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: iPhone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: tvOS + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Android + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - buildTarget: Windows Store Apps + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 0 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + androidETC2FallbackOverride: 0 + - 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: [] + spritePackingTag: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration.meta new file mode 100644 index 0000000..7adffbd --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f41dd8f84cbeb34cb39d3cddb7b69c3 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt b/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt new file mode 100644 index 0000000..1a8b9ac --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt @@ -0,0 +1 @@ +This folder contains packages with ACTk scripts for different third-party plugins. \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt.meta new file mode 100644 index 0000000..1e3968a --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Integration/readme.txt.meta @@ -0,0 +1,6 @@ +fileFormatVersion: 2 +guid: ba80bafc30976424784d71fb92e3f994 +TextScriptImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf b/Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf new file mode 100644 index 0000000..894fd4f Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Readme.pdf differ 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 0000000..5b50158 Binary files /dev/null and b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar differ diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar.meta new file mode 100644 index 0000000..87922bf --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/Android/AndroidNative.aar.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: a6f24aa125cab864dbbad6a8e142e96f +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : data + second: + enabled: 0 + settings: {} + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL.meta new file mode 100644 index 0000000..580a03d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d352dbbe3384463eb0709fd977eda86c +timeCreated: 1657112981 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib new file mode 100644 index 0000000..3316a9f --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib @@ -0,0 +1,15 @@ +mergeInto(LibraryManager.library, { + +GetUTCTicks: function () { + return 621355968000000000 + new Date().getTime() * 10000; +}, + +FlushFileSystem: function() { + FS.syncfs(false, function (err) { + if (err) { + console.log('[ACTk]: error flushing file system ' + err); + } + }); +}, + +}); \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib.meta new file mode 100644 index 0000000..2a641ea --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Plugins/WebGL/WebGLNative.jslib.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: 6cb512008d124241ba236034c229d146 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts.meta new file mode 100644 index 0000000..88632b3 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ca357de66eddf1240987b54a7440db14 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs new file mode 100644 index 0000000..15c7124 --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs @@ -0,0 +1,12 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("ACTk.Editor")] +[assembly: InternalsVisibleTo("CodeStage.ACTk.Tests")] +[assembly: InternalsVisibleTo("CodeStage.ACTk.Tests.Editor")] +[assembly: InternalsVisibleTo("CodeStage.ACTk.ManualTests")] \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs.meta new file mode 100644 index 0000000..3e5773d --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/AssemblyInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8902b6ccc7af4045ad3b40c92d52cc12 +timeCreated: 1588809569 \ No newline at end of file diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common.meta b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common.meta new file mode 100644 index 0000000..3d9808c --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 30d520c9ee427e34191bb784761ebe11 +folderAsset: yes +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs new file mode 100644 index 0000000..400f98e --- /dev/null +++ b/Assets/Plugins/CodeStage/AntiCheatToolkit/Runtime/Scripts/Common/ACTk.cs @@ -0,0 +1,93 @@ +#region copyright +// ------------------------------------------------------ +// Copyright (C) Dmitriy Yukhanov [https://codestage.net] +// ------------------------------------------------------ +#endregion + +namespace CodeStage.AntiCheat.Common +{ + using System; + using UnityEngine; + + /// + /// 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 0000000..0734619 Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/DOTween.dll differ 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 0000000..a5e204a Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/Editor/DOTweenEditor.dll differ 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 0000000..d06fc7c Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenIcon.png differ 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 0000000..7cd74c1 Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/DOTweenMiniIcon.png differ 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 0000000..e29d02f Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer.png differ 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 0000000..e48db5e Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Footer_dark.png differ 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 0000000..4d710d7 Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTween/Editor/Imgs/Header.jpg differ 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 0000000..fc08e61 Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTweenPro/DOTweenPro.dll differ 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 0000000..27b6bea Binary files /dev/null and b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll differ diff --git a/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll.meta b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll.meta new file mode 100644 index 0000000..62ab8c0 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/Editor/DOTweenProEditor.dll.meta @@ -0,0 +1,22 @@ +fileFormatVersion: 2 +guid: a6402d4311c862b4eb1325590d6466af +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/DOTweenPro/readme.txt b/Assets/Plugins/Demigiant/DOTweenPro/readme.txt new file mode 100644 index 0000000..9837c95 --- /dev/null +++ b/Assets/Plugins/Demigiant/DOTweenPro/readme.txt @@ -0,0 +1,35 @@ +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 (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 0000000..1024e34 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/DemiLib.dll differ 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 0000000..8012e1e Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/DemiEditor.dll differ 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 0000000..6fbcc51 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png.meta new file mode 100644 index 0000000..ca9400a --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 7ba4b2810f605d945af87e032ca2957b +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/blackSquareAlpha10.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png new file mode 100644 index 0000000..21afc7b Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png.meta new file mode 100644 index 0000000..488d14c --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha10.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8c9cfa1dbe00a1d41ae9d14f5ac543ec +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/blackSquareAlpha15.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png new file mode 100644 index 0000000..3097db8 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png.meta new file mode 100644 index 0000000..e907551 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha15.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 53d696c01f6ca524383f11fcc34dd13c +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/blackSquareAlpha25.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png new file mode 100644 index 0000000..521e6dc Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha25.png differ 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 0000000..700b9de Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha50.png differ 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 0000000..f4a47c3 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png.meta new file mode 100644 index 0000000..ce709e4 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blackSquareAlpha80.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 595b166389c8db546a199430284ebc9b +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/blueSquare.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png new file mode 100644 index 0000000..9d8a19a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/blueSquare.png differ 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 0000000..3ed059a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle.png differ 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 0000000..f829461 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/circle_dashedBorderEmpty.png differ 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 0000000..63ef49a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/greenSquare.png differ 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 0000000..5c2feae Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png.meta new file mode 100644 index 0000000..ccb4643 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_bright.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 93b1287b4a087f84c95c72f49ec94e83 +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_dark.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png new file mode 100644 index 0000000..5dc9a72 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/grid_dark.png differ 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 0000000..9242a22 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png.meta new file mode 100644 index 0000000..f84830d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alert.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 39cacc93c6c183f44992bf2421362f78 +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_alignB.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png new file mode 100644 index 0000000..c06e167 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignB.png differ 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 0000000..3118ab1 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png.meta new file mode 100644 index 0000000..b623d58 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBC.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2cdc0bc527f7a434496c6be9236e636f +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_alignBL.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png new file mode 100644 index 0000000..3ee1a48 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png.meta new file mode 100644 index 0000000..fd7ccf1 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBL.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: abf8a615f379ef44b9ac872a13b7712f +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_alignBR.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png new file mode 100644 index 0000000..ce4cf47 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignBR.png differ 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 0000000..c5f85cc Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCC.png differ 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 0000000..39e1546 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png.meta new file mode 100644 index 0000000..b0e188a --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCL.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2a8208d8e80f90944b8ff2978292b03b +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_alignCR.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png new file mode 100644 index 0000000..9ec5557 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignCR.png differ 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 0000000..dc638a7 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png.meta new file mode 100644 index 0000000..7f4d729 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignHC.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: b9e0e5a8836018e4c810fbceba55a1b4 +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_alignL.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png new file mode 100644 index 0000000..93c1812 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png.meta new file mode 100644 index 0000000..c7e801b --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignL.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d18ceface0c20014b8db4bba05a41b83 +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_alignR.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png new file mode 100644 index 0000000..c1aca04 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignR.png differ 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 0000000..b4397c6 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignT.png differ 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 0000000..de6a933 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTC.png differ 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 0000000..627b907 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTL.png differ 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 0000000..6a0d89d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png.meta new file mode 100644 index 0000000..bb1b90d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignTR.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e01c0b07c87513844ab88bb432bcf85a +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_alignVC.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png new file mode 100644 index 0000000..ec87ccf Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_alignVC.png differ 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 0000000..f146516 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png.meta new file mode 100644 index 0000000..e362a81 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 37639be6148186645bca3fce45d5aa22 +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_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png new file mode 100644 index 0000000..bab977d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_camera_border.png differ 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 0000000..b7f481e Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png.meta new file mode 100644 index 0000000..2a9bf06 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 7c83a08052c9e2f49b47897a637994de +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_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png new file mode 100644 index 0000000..30bdb8b Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png.meta new file mode 100644 index 0000000..d9323e2 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_cog_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6862027f2176eae40a3143c562466a1b +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.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png new file mode 100644 index 0000000..8735b7c Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment.png differ 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 0000000..d61a35d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_comment_border.png differ 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 0000000..85bb248 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_delete.png differ 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 0000000..3445065 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png.meta new file mode 100644 index 0000000..6bac83d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_demigiant.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 229d0d11465a822449f78a50dbf7104d +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_distributeHAlignT.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png new file mode 100644 index 0000000..90dc9de Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png.meta new file mode 100644 index 0000000..d5af1eb --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeHAlignT.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 1ccb12a4b0bf8f447b2cc114851732f5 +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_distributeVAlignL.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png new file mode 100644 index 0000000..a762110 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_distributeVAlignL.png differ 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 0000000..ed34625 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_doing.png differ 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 0000000..b71eefe Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_end.png differ 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 0000000..f4525da Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png.meta new file mode 100644 index 0000000..0708f25 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_flipV.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: c44ae4a96937e2c4b8be481648364682 +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_foldout_closed.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png new file mode 100644 index 0000000..df26539 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_closed.png differ 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 0000000..50a913a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_foldout_open.png differ 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 0000000..7ea0c06 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart.png differ 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 0000000..a533084 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png.meta new file mode 100644 index 0000000..f7b7f22 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_heart_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 669c487f3c9c5fe4abb6459f9c2628f0 +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_light.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png new file mode 100644 index 0000000..5a60bd0 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png.meta new file mode 100644 index 0000000..849e0ad --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4f69b96f9308d8f4ea239773ef5b55c4 +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_light_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png new file mode 100644 index 0000000..a29a859 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png.meta new file mode 100644 index 0000000..bd76a57 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_light_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 252f207d01ecc87419cdba1d1c0ab1ea +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.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png new file mode 100644 index 0000000..7b718a2 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock.png differ 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 0000000..be85443 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png.meta new file mode 100644 index 0000000..a870de6 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_lock_open.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8d60feae84bdb2d4eb16a0037056c588 +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_nodeArrow.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png new file mode 100644 index 0000000..e236c92 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_nodeArrow.png differ 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 0000000..b4d864a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ok.png differ 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 0000000..1d89e2a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_optionsDropdown.png differ 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 0000000..0608dcb Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png.meta new file mode 100644 index 0000000..483c5b7 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 2a563a43c33f0f3428d02b3a43886fc2 +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_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png new file mode 100644 index 0000000..db4ac28 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_play_border.png differ 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 0000000..7e53975 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png.meta new file mode 100644 index 0000000..8d4e226 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 01976ad42d31f494e8040d3e32e283dc +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_border.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png new file mode 100644 index 0000000..6cc1c5f Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png.meta new file mode 100644 index 0000000..ae28986 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_skull_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 6dfd924c0ba23844fb5d04ad1560de22 +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.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png new file mode 100644 index 0000000..d280684 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star.png differ 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 0000000..4615829 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png.meta new file mode 100644 index 0000000..955bf42 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_star_border.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 18f3a26aa87fccc4cb5e211d4c6de662 +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_todo.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png new file mode 100644 index 0000000..8214de5 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_todo.png differ 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 0000000..afdcff3 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui.png differ 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 0000000..6613a3d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_ui_border.png differ 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 0000000..56a1324 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png.meta new file mode 100644 index 0000000..8dced06 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 55c2b426022dac44f9b25f0cba28aa45 +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_off.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png new file mode 100644 index 0000000..e1a2c91 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/ico_visibility_off.png differ 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 0000000..c272180 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png.meta new file mode 100644 index 0000000..012525b --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/orangeSquare.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3e730492361eb6e45be5c5fdafac23be +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/project.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project.meta new file mode 100644 index 0000000..8ddc4ff --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 52bdbb53205da074d9937b996806e2e2 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png new file mode 100644 index 0000000..80dc387 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_atlas.png differ 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 0000000..90c5212 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png.meta new file mode 100644 index 0000000..30cc40c --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_audio.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e1af8927fb6f5634896d59aed409a589 +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_bundle.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png new file mode 100644 index 0000000..c418038 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_bundle.png differ 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 0000000..fd589a0 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cog.png differ 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 0000000..a34a3e8 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png.meta new file mode 100644 index 0000000..529d85c --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_cross.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 3b67e53c8c2f8114b966c0e70d452419 +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_demigiant.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png new file mode 100644 index 0000000..99d0cf9 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png.meta new file mode 100644 index 0000000..8276473 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_demigiant.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: f36ab42cc6fcdfd4187033279d3d14a9 +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_folder.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png new file mode 100644 index 0000000..9bba7d0 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_folder.png differ 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 0000000..9ce1a4d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png.meta new file mode 100644 index 0000000..996c26e --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_fonts.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: cf986943c88c2254780c17b2b5e3bc2f +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_heart.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png new file mode 100644 index 0000000..f7ebe72 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_heart.png differ 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 0000000..5a4b7eb Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_materials.png differ 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 0000000..42f1f23 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png.meta new file mode 100644 index 0000000..0195fcf --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_models.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 09a0cde07b4d75f49b4c817932791b81 +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_particles.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png new file mode 100644 index 0000000..3ffa475 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_particles.png differ 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 0000000..c441add Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_play.png differ 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 0000000..abc4353 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_prefab.png differ 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 0000000..c79b668 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png.meta new file mode 100644 index 0000000..2b2bbf9 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_scripts.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 96cbdf605b8ddb34da384703f2d0b849 +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_shaders.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png new file mode 100644 index 0000000..ed3b4bb Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_shaders.png differ 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 0000000..22930f4 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png.meta new file mode 100644 index 0000000..68df579 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_skull.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: d563d6ce25cd2ca48b185ec47a74a3fb +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_star.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png new file mode 100644 index 0000000..90483b3 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_star.png differ 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 0000000..750996d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_terrains.png differ 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 0000000..6aae964 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/project/ico_textures.png differ 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 0000000..dd219ac Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/purpleSquare.png differ 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 0000000..798457f Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/redSquare.png differ 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 0000000..51afe67 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png.meta new file mode 100644 index 0000000..50cd914 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorder.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: afd7d0ddb1d6c744b9cb87ae49b2ce62 +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/squareBorderAlpha15.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png new file mode 100644 index 0000000..7000d8f Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png.meta new file mode 100644 index 0000000..0488aae --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderAlpha15.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: dfd33662d9f6f3849bd92f6e159ca226 +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/squareBorderCurved.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png new file mode 100644 index 0000000..768cc82 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved.png differ 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 0000000..a1ed49d Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02.png differ 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 0000000..2b313e4 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png.meta new file mode 100644 index 0000000..dd83662 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved02_darkBorders.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: e3ae01f12865ad54ba365963bda55759 +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/squareBorderCurvedAlpha.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png new file mode 100644 index 0000000..e56d3b7 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png.meta new file mode 100644 index 0000000..44abb4e --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedAlpha.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: a1606d34a052ed3449da93edd229743e +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/squareBorderCurvedEmpty.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png new file mode 100644 index 0000000..bbd3158 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png.meta new file mode 100644 index 0000000..a156e1a --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 4578222ee7a511446b0c340551bf8740 +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/squareBorderCurvedEmpty02.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png new file mode 100644 index 0000000..57714a5 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png.meta new file mode 100644 index 0000000..72910c0 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmpty02.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 7d504312fad10f040b95bd8836dc6fc6 +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/squareBorderCurvedEmptyThick.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png new file mode 100644 index 0000000..47b177f Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png.meta new file mode 100644 index 0000000..e9a6d7d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurvedEmptyThick.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: fc3b86627d5fe1c4d865b80627e2e37c +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_darkBorders.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png new file mode 100644 index 0000000..b9450f2 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBorders.png differ 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 0000000..4ddd37a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderCurved_darkBordersAlpha.png differ 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 0000000..188ed94 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png.meta new file mode 100644 index 0000000..365f54f --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 8db54efcce998554c86b796b37a7cdfa +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/squareBorderEmpty01.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png new file mode 100644 index 0000000..188ed94 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png.meta new file mode 100644 index 0000000..c86a60d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty01.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: aa8dc9238ab21e54ca88fa22698e4679 +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/squareBorderEmpty02.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png new file mode 100644 index 0000000..ec9ead7 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty02.png differ 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 0000000..ca376a8 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderEmpty03.png differ 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 0000000..ec9ead7 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickEmpty.png differ 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 0000000..ca376a8 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareBorderThickerEmpty.png differ 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 0000000..38dc1bb Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png.meta new file mode 100644 index 0000000..17c7922 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCorners03.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: dec3ea647707588408ec0d11ab130b73 +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/squareCornersEmpty02.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png new file mode 100644 index 0000000..facdba9 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/squareCornersEmpty02.png differ 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 0000000..8e17561 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_empty.png differ 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 0000000..c8cfc7f Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted.png differ 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 0000000..7763091 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png.meta new file mode 100644 index 0000000..b26261d --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileBars_slanted_alpha.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 018a5623a46db1d49b1e6ff2482b07ab +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/tileCheckerboard.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png new file mode 100644 index 0000000..10755e3 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/tileCheckerboard.png differ 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 0000000..c745068 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/transparentSquare.png differ 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 0000000..768a2da Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot.png differ 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 0000000..705c72b Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_darkBorder.png differ 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 0000000..2a081f6 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteDot_whiteBorderAlpha.png differ 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 0000000..afc2459 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare.png differ 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 0000000..6480ee2 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha10.png differ 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 0000000..e6f3c42 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha15.png differ 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 0000000..5219f2a Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png.meta new file mode 100644 index 0000000..cdfa23e --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha25.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 511f6b24c50557a40a09633b12b8b8ef +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/whiteSquareAlpha50.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png new file mode 100644 index 0000000..ad90433 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png.meta new file mode 100644 index 0000000..103bbf1 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha50.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: ef40b00a83f7bd34f84851386b3321f0 +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/whiteSquareAlpha80.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png new file mode 100644 index 0000000..def9ea9 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png.meta new file mode 100644 index 0000000..4dd7287 --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareAlpha80.png.meta @@ -0,0 +1,47 @@ +fileFormatVersion: 2 +guid: 11848dd30e516d846a02cd302634d317 +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/whiteSquareCurved.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png new file mode 100644 index 0000000..fb54c9f Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved.png differ 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 0000000..c7ed49b Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png differ diff --git a/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png.meta b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png.meta new file mode 100644 index 0000000..45fdb5f --- /dev/null +++ b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquareCurved02.png.meta @@ -0,0 +1,68 @@ +fileFormatVersion: 2 +guid: 282d742ce2ddf9f458812ab84ea6fa88 +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/whiteSquare_fadeOut_bt.png b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png new file mode 100644 index 0000000..0f754e5 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/whiteSquare_fadeOut_bt.png differ 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 0000000..c41f635 Binary files /dev/null and b/Assets/Plugins/Demigiant/DemiLib/Core/Editor/Imgs/yellowSquare.png differ 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 0000000..d11ed6d Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Connections.Abstractions.dll differ 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 0000000..c898fdf Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll differ diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll.meta new file mode 100644 index 0000000..0ded403 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Client.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: e0bdb0901d5efed98aeb2f838106e5b3 +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.Common.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll new file mode 100644 index 0000000..3dcdc84 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.Http.Connections.Common.dll differ 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 0000000..87e4873 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll differ diff --git a/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll.meta b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll.meta new file mode 100644 index 0000000..0ff9f15 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.Core.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: b2e3957570c04141fac5d4d84953b2b6 +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.dll b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll new file mode 100644 index 0000000..4f0b5f5 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Client.dll differ 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 0000000..742ec69 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Common.dll differ 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 0000000..d9bac0a Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.AspNetCore.SignalR.Protocols.Json.dll differ 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 0000000..6031ba1 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll differ diff --git a/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll.meta b/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll.meta new file mode 100644 index 0000000..99cb92c --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Bcl.AsyncInterfaces.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 5545d47b730ea886b9dfd66705ea36b8 +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.TimeProvider.dll b/Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll new file mode 100644 index 0000000..5003e2c Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Bcl.TimeProvider.dll differ 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 0000000..479c5fe Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll.meta new file mode 100644 index 0000000..0ae0054 --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.Abstractions.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: d04c01d3a6a7e1f73b58811c268ddb0d +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.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll new file mode 100644 index 0000000..7f413e6 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.DependencyInjection.dll differ 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 0000000..4f9e147 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll differ diff --git a/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll.meta b/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll.meta new file mode 100644 index 0000000..68b390d --- /dev/null +++ b/Assets/Plugins/SignalR/Microsoft.Extensions.Features.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: abd0c150fc9f69f5d92ba01944d4ab46 +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.Abstractions.dll b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll new file mode 100644 index 0000000..9387bf5 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.Abstractions.dll differ 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 0000000..77fe4f9 Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.Logging.dll differ 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 0000000..cea49fa Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.Options.dll differ 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 0000000..24f500c Binary files /dev/null and b/Assets/Plugins/SignalR/Microsoft.Extensions.Primitives.dll differ 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 0000000..f2d83c5 Binary files /dev/null and b/Assets/Plugins/SignalR/System.Buffers.dll differ 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 0000000..354f5f5 Binary files /dev/null and b/Assets/Plugins/SignalR/System.Diagnostics.DiagnosticSource.dll differ 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 0000000..003bcd0 Binary files /dev/null and b/Assets/Plugins/SignalR/System.IO.Pipelines.dll differ diff --git a/Assets/Plugins/SignalR/System.IO.Pipelines.dll.meta b/Assets/Plugins/SignalR/System.IO.Pipelines.dll.meta new file mode 100644 index 0000000..d51ed25 --- /dev/null +++ b/Assets/Plugins/SignalR/System.IO.Pipelines.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 1a31243b3cf39446184bee92a0093d6d +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.Memory.dll b/Assets/Plugins/SignalR/System.Memory.dll new file mode 100644 index 0000000..4617199 Binary files /dev/null and b/Assets/Plugins/SignalR/System.Memory.dll differ 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 0000000..c5ba4e4 Binary files /dev/null and b/Assets/Plugins/SignalR/System.Runtime.CompilerServices.Unsafe.dll differ 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 0000000..3d16c7e Binary files /dev/null and b/Assets/Plugins/SignalR/System.Text.Encodings.Web.dll differ diff --git a/Assets/Plugins/SignalR/System.Text.Encodings.Web.dll.meta b/Assets/Plugins/SignalR/System.Text.Encodings.Web.dll.meta new file mode 100644 index 0000000..d962659 --- /dev/null +++ b/Assets/Plugins/SignalR/System.Text.Encodings.Web.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: b42ae5cdf004f3e91b523fa91a67bd6e +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.Json.dll b/Assets/Plugins/SignalR/System.Text.Json.dll new file mode 100644 index 0000000..81822f3 Binary files /dev/null and b/Assets/Plugins/SignalR/System.Text.Json.dll differ diff --git a/Assets/Plugins/SignalR/System.Text.Json.dll.meta b/Assets/Plugins/SignalR/System.Text.Json.dll.meta new file mode 100644 index 0000000..8c71c7c --- /dev/null +++ b/Assets/Plugins/SignalR/System.Text.Json.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: bccdebfcb02c5ebaba0ac38a335af659 +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.Threading.Channels.dll b/Assets/Plugins/SignalR/System.Threading.Channels.dll new file mode 100644 index 0000000..fee8f5a Binary files /dev/null and b/Assets/Plugins/SignalR/System.Threading.Channels.dll differ diff --git a/Assets/Plugins/SignalR/System.Threading.Channels.dll.meta b/Assets/Plugins/SignalR/System.Threading.Channels.dll.meta new file mode 100644 index 0000000..4ca2380 --- /dev/null +++ b/Assets/Plugins/SignalR/System.Threading.Channels.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 1db6e0ca1c11e792db7d8046270a6ac8 +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.Threading.Tasks.Extensions.dll b/Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll new file mode 100644 index 0000000..eeec928 Binary files /dev/null and b/Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll differ diff --git a/Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll.meta b/Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll.meta new file mode 100644 index 0000000..9303f8c --- /dev/null +++ b/Assets/Plugins/SignalR/System.Threading.Tasks.Extensions.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 4d209235961e00a8ba87598abb8f9811 +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/link.xml b/Assets/Plugins/SignalR/link.xml new file mode 100644 index 0000000..cf1f807 --- /dev/null +++ b/Assets/Plugins/SignalR/link.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/Plugins/SignalR/link.xml.meta b/Assets/Plugins/SignalR/link.xml.meta new file mode 100644 index 0000000..ec049fb --- /dev/null +++ b/Assets/Plugins/SignalR/link.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cd098c45d670243748845d24eaf29251 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/BACKUP_MANIFEST.md b/BACKUP_MANIFEST.md index 7976977..c147a2f 100644 --- a/BACKUP_MANIFEST.md +++ b/BACKUP_MANIFEST.md @@ -30,6 +30,7 @@ - `Assets/AssetsPackage/art/terrainbuilding/test01/`:`hex_build_01.prefab` 直接引用的 terrainbuilding 美术资源。 - `Assets/AssetsPackage/UI/common/btn_close.png`、`mask.png`:HexMapPanel 直接引用 UI 图。 - `Assets/AssetsPackage/Animation/ui/FishingMapPanel/FishingMapPanel.controller`:HexMapPanel 直接引用 Animator Controller。 +- `Assets/CoreLib/`、`Assets/Plugins/Demigiant/`、`Assets/Plugins/SignalR/`、`Assets/Plugins/LubanLib/`、`Assets/Plugins/CodeStage/`:脚本编译所需的最小 DLL/运行库依赖。 ## HexBuilding 核心内容 @@ -65,7 +66,7 @@ - 已确认 `HexBuilding.asset` 包含地址:`BuildModel`、`HexMapPanel`、`hex_build_01_info`、`hex_build_01`、`HexMapAct`。 - 已确认 `AddressableHelperSetting.asset` 包含 `HexBuilding`。 -- Unity batchmode 验证记录见 `DEPENDENCY_REPORT.md`。 +- Unity batchmode 已通过工程打开和脚本编译检查,验证记录见 `DEPENDENCY_REPORT.md`。 ## 远端 diff --git a/DEPENDENCY_REPORT.md b/DEPENDENCY_REPORT.md index ca3fa64..bc92235 100644 --- a/DEPENDENCY_REPORT.md +++ b/DEPENDENCY_REPORT.md @@ -14,6 +14,8 @@ - Cinemachine:HexMap 摄像机控制。 - TMPro:格子文本和面板文本。 - UniRx:事件订阅生命周期。 +- LubanLib / SimpleJSON / Bright.Serialization:生成配置表代码依赖。 +- CodeStage AntiCheatToolkit:`PlayerData` 等基础数据使用 `ObscuredInt` / `ObscuredULong`。 结论:当前备份是“独立 Unity 工程备份库”,不是完全解耦的 HexBuilding SDK/package。 @@ -53,18 +55,21 @@ HexBuilding Addressables group 保留以下地址: - `Assets/Scripts/` 暂时完整保留,因为它体积小,且贸然删单个业务目录容易引入编译级引用断裂。 - `LocalPackages/` 只保留 `manifest.json` 实际引用的本地包,以满足 `manifest.json` 的本地包路径。 -## 验证阻塞 +## 验证记录 -此前执行备份工程 Unity batchmode 时出现: +修复独立工程打开问题时补齐了以下缺失依赖: -```text -[Package Manager] The "path" argument must be of type string. Received undefined -[Package Manager] Failed to update project manifest: The "path" argument must be of type string. Received undefined -``` +- `Assets/CoreLib/`:`asap.core.dll`、`LitJSON.dll`。 +- `Assets/Plugins/Demigiant/`:DOTween / DOTweenPro。 +- `Assets/Plugins/SignalR/`:`System.Diagnostics.DiagnosticSource.dll` 及 SignalR 依赖。 +- `Assets/Plugins/LubanLib/`:`Bright.Serialization` / `SimpleJSON`。 +- `Assets/Plugins/CodeStage/`:AntiCheatToolkit obscured types。 -对照执行源工程 `C:\Users\13999\Documents\ft_3\Client` 后,源工程也出现同样错误。因此该问题不能归因于备份工程拆分,记录为当前 Unity/UPM 或源工程包配置的既有阻塞。 +同时在 `Packages/tysdk/Runtime/TYSdkFacade.cs` 为非 Android/iOS 的 Editor/Standalone 编译添加 `clientid` 兜底,避免首次打开备份工程时因默认 Standalone build target 触发未定义变量。 -由于 Unity 未通过 Package Manager 初始化阶段,当前未能生成 `.csproj`,因此 `dotnet build HotUpdate.csproj` / `Assembly-CSharp.csproj` 暂不可执行。 +最新 Unity batchmode 验证日志:`C:\tmp\catanbuilding-backup-open-fix-4.log`。本次未发现 `error CS`、`Exception`、`Failed`、`fatal` 等阻塞项,仅保留 Unity Licensing 客户端的非阻塞日志。 + +`dotnet build HotUpdate.csproj --no-restore` 仍不作为该备份工程的有效验证依据:`.csproj` 是 Unity 生成文件且被 `.gitignore` 忽略,当前本地旧生成文件仍可能缺少新导入插件引用。以 Unity batchmode 编译结果为准。 ## 后续建议 diff --git a/Packages/tysdk/Runtime/TYSdkFacade.cs b/Packages/tysdk/Runtime/TYSdkFacade.cs index e05e347..2867f87 100644 --- a/Packages/tysdk/Runtime/TYSdkFacade.cs +++ b/Packages/tysdk/Runtime/TYSdkFacade.cs @@ -426,6 +426,8 @@ namespace tysdk string clientid = "Android_5.00_tyGuest,facebook.googleplay.0-hall20587.googleplay.FishingMaster"; #elif UNITY_IOS string clientid = "IOS_5.00_tyGuest,facebook,appStore.appStore.0-hall20587.appStore.FishingMaster"; +#else + string clientid = "Android_5.00_tyGuest,facebook.googleplay.0-hall20587.googleplay.FishingMaster"; #endif list.Add($"clientid={clientid}");