首次提交
This commit is contained in:
21
.gitignore
vendored
Normal file
21
.gitignore
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/Library
|
||||
/Logs
|
||||
/obj
|
||||
/Build
|
||||
/Temp
|
||||
/.vs
|
||||
/copydll.bat
|
||||
/Debug
|
||||
/.idea/
|
||||
/update_unity_libil2cpp.bat
|
||||
/*.csproj
|
||||
/*.sln
|
||||
/UserSettings/Layouts
|
||||
/Release
|
||||
/Assembly-CSharp-Editor.csproj.user
|
||||
/Assets/StreamingAssets
|
||||
/Assets/ResRaw/Effect/Z_Test
|
||||
/Assets/ResRaw/Effect/Z_Test.meta
|
||||
/Bundles/
|
||||
Assets/Scripts/sync.ffs_db
|
||||
Assets/Scripts/sync.ffs_db.meta
|
||||
8
Assets/Plugins.meta
Normal file
8
Assets/Plugins.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3698f814f47cca649b4fb0cab847eda7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Plugins/CodeStage.meta
Normal file
8
Assets/Plugins/CodeStage.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cd0e9f4a4927f6145887bbb2b491ffe9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Assets/Plugins/CodeStage/AntiCheatToolkit.meta
Normal file
7
Assets/Plugins/CodeStage/AntiCheatToolkit.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52c313066dda63c459f7c826dbb8eed1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
2
Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt
Normal file
2
Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
Please, check out latest Anti-Cheat Toolkit Code Library API Docs here:
|
||||
https://codestage.net/uas_files/actk/api/
|
||||
6
Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt.meta
Normal file
6
Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt.meta
Normal file
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4c375fd5bde53c42b0ebc6ee503f7a1
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1215
Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md
Normal file
1215
Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a707e4914fc9f014790c02a3cd0b455d
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
7
Assets/Plugins/CodeStage/AntiCheatToolkit/Editor.meta
Normal file
7
Assets/Plugins/CodeStage/AntiCheatToolkit/Editor.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ac5220baa6a51bb47a5c640ddf6c0ce8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8ef82b58ed1acc8419a02b8a05286620
|
||||
timeCreated: 1554196096
|
||||
licenseType: Store
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ff6bc3cba85fba4e922af0d4a624023
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a9ee7d4a58674ac69c27bc7c29417309
|
||||
timeCreated: 1552925230
|
||||
@@ -0,0 +1,41 @@
|
||||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Use it to guess current directory of the Anti-Cheat Toolkit.
|
||||
/// </summary>
|
||||
public class ACTkMarker : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns raw path of the ACTkMarker script for further reference.
|
||||
/// </summary>
|
||||
/// <returns>Path of the ACTkMarker ScriptableObject asset.</returns>
|
||||
public static string GetAssetPath()
|
||||
{
|
||||
string result;
|
||||
|
||||
var tempInstance = CreateInstance<ACTkMarker>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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<InjectionDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + ObscuredCheatingDetector.ComponentName, false, 1)]
|
||||
private static void AddObscuredCheatingDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<ObscuredCheatingDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + SpeedHackDetector.ComponentName, false, 1)]
|
||||
private static void AddSpeedHackDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<SpeedHackDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + WallHackDetector.ComponentName, false, 1)]
|
||||
private static void AddWallHackDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<WallHackDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + TimeCheatingDetector.ComponentName, false, 1)]
|
||||
private static void AddTimeCheatingDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<TimeCheatingDetector>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e10289b3bdb7db64c8f2c624b337d331
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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")]
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1cc293465f841498ad940f7813ccedd
|
||||
timeCreated: 1588809689
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9e6164ee563b444d87cbe3437d6012a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14398b80f1b8c7e4ea405ef47a17e38c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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 "<color=#" + color + ">" + input + "</color>";
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b18cacce4700f664e8a56903e2090843
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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); } }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0262830fc851659438acad57bb020619
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47e5a8270a3c78c4191b11b026ac7c2d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<string, Texture> CachedTextures = new Dictionary<string, Texture>();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e42f0f68a093d74ea97ddfbd9a5ef4d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0c63cf6cabe3a547a0b46de95bff055
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<InjectionDetector>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6025f911d895a7e43a5d5c6229254129
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<T> : Editor where T: KeepAliveBehaviour<T>
|
||||
{
|
||||
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() {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b59c308aff5e054991de809a3b5985b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<ObscuredCheatingDetector>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8df36b70906d65d43bcb3ddce3fe36ba
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<SpeedHackDetector>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 199f39969debe8f46afc5f32b333be3b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<TimeCheatingDetector>
|
||||
{
|
||||
#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("<b>To avoid CORS limitations while running in WebGL, URL will be changed to the current domain, if it does points to any other domain</b>", 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("<b>Detector disabled with ACTK_PREVENT_INTERNET_PERMISSION conditional symbol</b>", GUITools.RichLabel);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2fb4c7beaf58d554ab0f85d86b53726e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -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<WallHackDetector>
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f88f8bd1134b464fa26c27d9979e6db
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b60780b31b4fac0448812d7db515e8a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0eab0a2d46900f5498873b929a503bad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ae78be353f2d8243b15efd15919c5f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// Resulting hash in most cases should match value you get from the \ref CodeStage.AntiCheat.Genuine.CodeHash.CodeHashGenerator "CodeHashGenerator"
|
||||
public class CodeHashGeneratorPostprocessor : IPostprocessBuildWithReport
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// Used at CodeHashGeneratorListener example.
|
||||
public const int CallbackOrder = int.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// HashesGenerated event delegate.
|
||||
/// </summary>
|
||||
/// <param name="report">Standard post-build report from Unity.</param>
|
||||
/// <param name="hashedBuilds">Build hashing results array.</param>
|
||||
///
|
||||
/// 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<BuildHashes> hashedBuilds);
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls selection dialog and calculates hashes for the selected build.
|
||||
/// </summary>
|
||||
/// <param name="buildPath">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <param name="printToConsole">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <returns>Valid BuildHashes instance or null in case of error / user cancellation.</returns>
|
||||
public static BuildHashes CalculateExternalBuildHashes(string buildPath, bool printToConsole)
|
||||
{
|
||||
return AsyncHelpers.RunSync(() => CalculateExternalBuildHashesAsync(buildPath, printToConsole));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls selection dialog and calculates hashes for the selected build.
|
||||
/// </summary>
|
||||
/// <param name="buildPath">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <param name="printToConsole">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <returns>Task with Valid BuildHashes instance or null in case of error / user cancellation.</returns>
|
||||
public static async Task<BuildHashes> 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates hashes for the given build report. Can be useful if you wish to hash build you just made with BuildPipeline.
|
||||
/// </summary>
|
||||
/// Will not trigger the HashesGenerated event.
|
||||
/// <param name="report">BuildReport you wish to calculates hashes for</param>
|
||||
/// <param name="printToConsole">Specifies if calculated hashes should be printed to Unity Console</param>
|
||||
/// <returns>Readonly List of the BuildHashes, one per each resulting build from the BuildReport.</returns>
|
||||
public static Task<IReadOnlyList<BuildHashes>> CalculateBuildReportHashesAsync(BuildReport report,
|
||||
bool printToConsole)
|
||||
{
|
||||
return CalculateBuildReportHashesAsync(report, false, printToConsole);
|
||||
}
|
||||
|
||||
private static async Task<IReadOnlyList<BuildHashes>> 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<IReadOnlyList<BuildHashes>> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c82c021ded9a49b44b3701f1859341cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 881ba0c65bee45139ca757895221c6ab
|
||||
timeCreated: 1680806941
|
||||
@@ -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<BuildHashes[]> 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<BuildHashes>();
|
||||
}
|
||||
|
||||
#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<BuildHashes[]> GetBuildHashes(string[] files)
|
||||
{
|
||||
var result = new List<BuildHashes>();
|
||||
|
||||
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<FilesProgress> progress)
|
||||
{
|
||||
ZipFile zf = null;
|
||||
|
||||
try
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var latestPercent = 0;
|
||||
var filesChecked = 0;
|
||||
var fileHashes = new ConcurrentBag<FileHash>();
|
||||
var fs = File.OpenRead(path);
|
||||
zf = new ZipFile(fs);
|
||||
var count = zf.Count;
|
||||
|
||||
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
||||
var sha1Pool = new ThreadSafeDisposablesPool<SHA1Wrapper>(() => new SHA1Wrapper());
|
||||
|
||||
Parallel.ForEach(zf.Cast<ZipEntry>(), 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9717d52c2bf842caaa8575f8f2947afa
|
||||
timeCreated: 1680806503
|
||||
@@ -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<IReadOnlyList<BuildHashes>> 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<BuildHashes>();
|
||||
}
|
||||
|
||||
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<BuildHashes>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02b38fd3639d4fd7a1a6732fadbeebc8
|
||||
timeCreated: 1680806778
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59e19c7338f04be697d7788c76f0cde6
|
||||
timeCreated: 1552927805
|
||||
@@ -0,0 +1,70 @@
|
||||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Describes assembly which is added to the InjectionDetector "white list".
|
||||
/// </summary>
|
||||
[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;
|
||||
|
||||
/// <summary>
|
||||
/// Assembly name, i.e.: ACTk.Runtime.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Array of whitelisted hashes for the assembly with given Name.
|
||||
/// </summary>
|
||||
public int[] Hashes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs new instance.
|
||||
/// </summary>
|
||||
/// <param name="name">Sets Name property.</param>
|
||||
/// <param name="hashes">Sets Hashes property.</param>
|
||||
public AllowedAssembly(string name, int[] hashes)
|
||||
{
|
||||
Name = name;
|
||||
Hashes = hashes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows adding new hash to the Hashes collection.
|
||||
/// </summary>
|
||||
/// <param name="hash">New whitelisted hash for the assembly with specified Name.</param>
|
||||
/// <returns>True if hash was added and false otherwise (i.e. when hash already existed in the collection).</returns>
|
||||
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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99e59ee643091664d874b8418be8b78e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdb8abbb3fde4da3aa210fccf74e9524
|
||||
timeCreated: 1552925592
|
||||
@@ -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<AllowedAssembly> MergeAllowedAssemblies(IEnumerable<AllowedAssembly> collection1, IEnumerable<AllowedAssembly> collection2)
|
||||
{
|
||||
var result = new List<AllowedAssembly>(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<AllowedAssembly> LoadAndParseLegacyWhitelist()
|
||||
{
|
||||
var result = new List<AllowedAssembly>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 682e4f8bd25b4b3f9ab90c2c080decf5
|
||||
timeCreated: 1552927820
|
||||
@@ -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<AllowedAssembly>();
|
||||
|
||||
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<AllowedAssembly> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ed4f862c6dc42a49c1f47d1e9ee2fb5
|
||||
timeCreated: 1552945114
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb730acf6c1569848b1187cd6c0e312c
|
||||
folderAsset: yes
|
||||
timeCreated: 1552913902
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e79f56c36f349f64995908c2bc571662
|
||||
timeCreated: 1552680217
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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<AllowedAssembly> whitelist;
|
||||
private static string whitelistPath;
|
||||
|
||||
private Vector2 scrollPosition;
|
||||
private bool manualAssemblyWhitelisting;
|
||||
private string manualAssemblyWhitelistingName = InitialCustomName;
|
||||
|
||||
internal static void ShowWindow()
|
||||
{
|
||||
EditorWindow myself = GetWindow<UserWhitelistEditor>(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<AllowedAssembly>();
|
||||
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<string> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd28be63d7a09224da0cac7e3178896d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1140a4b6184eae45916fdae3da40a10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7e1925e5a5f04349bee0d734c5705598
|
||||
timeCreated: 1621638102
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Class with utility functions to help with ACTk migrations after updates.
|
||||
/// </summary>
|
||||
public static partial class MigrateUtils
|
||||
{
|
||||
private const string MigrationVersion = "2";
|
||||
|
||||
/// <summary>
|
||||
/// Checks all prefabs in project for old version of obscured types and tries to migrate values to the new version.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks all scenes in project for old version of obscured types and tries to migrate values to the new version.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c7ff960ccd8a243ad385a3fe965e9e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dfff86e18b5565b499779c37590c4d83
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c48a363379404a3f8ffa0970bd1f7653
|
||||
timeCreated: 1653693062
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a0ae33a4804dd5468c37cee3d9e4a15
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d4822eb673254d3fa09b8add898e8445
|
||||
timeCreated: 1684493697
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b695953c62fb4e84aa3bcf20ed203871
|
||||
timeCreated: 1508363700
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f1f384feecf6f94e9229f7d2b8ea644
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68a1078367903c94bb9914b21b55172d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d720256b4500364ba597cd9f71f28e1
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98c9f8eb20d73134e96287318b713c39
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1cd362a81eab4155a2f1585c5d7ba876
|
||||
timeCreated: 1544725257
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eaf7a22e1b4319f40b23596cea6556a4
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db9197f5c028e5b4497f66a9b3217395
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 914802edc5dc95349a9903ac64be6343
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae392b1c42e591945a2aa46d35119192
|
||||
timeCreated: 1484857585
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user