diff --git a/Packages/r1_gameshield.unitypackage b/Packages/r1_gameshield.unitypackage
new file mode 100644
index 0000000..5c7b4a8
Binary files /dev/null and b/Packages/r1_gameshield.unitypackage differ
diff --git a/README.md b/README.md
index ec23bd2..45c592a 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,66 @@
-# GameShield
-GameShield - An open-source solution to protect your Unity-based games. Anti-cheat, time-control, data ecnryption and memory protection and other security modules for your games.
+# Unity Game Shield
+
+**Unity Game Sheild** is an open-source comprehensive suite of tools for your apps and games, including many **anti-cheat and securty tools**.
+This framework is easy to use on any projects and platforms.
+
+For an in-depth look at the functionality - I also suggest visiting the Wiki
+
+❓**Why GameShield?**
+🔸Easy to install (only 4 steps basic installation);
+🔸Easy to configure each module;
+🔸Reporting system;
+🔸Lightweight;
+🔸Event-based and modular;
+
+## Get Started
+**GameShield** installs into your project as easily as possible - basic installation and configuration takes **only 4 steps**. Below we will consider both **automatic initialization** and **manual configuration**.
+
+**Basic Installation:**
+* Download Latest Release from GitHUB;
+* Import **.unitypackage** into your project;
+* Run **Setup Wizzard** at Unity Top Menu (**GameShield** -> **Setup Wizzard**);
+* Check all settings and press **"Complete"**;
+* Done!
+
+**Manual Installation:**
+* Download Latest Release from GitHUB;
+* Import **.unitypackage** into your project;
+* Place Prefab with **GameShield** main script at scene;
+* Write initialization code at your game installer script (see how to here);
+* Done!
+
+**Dependencies:**
+- Unity Event Framework (Included);
+- Unity Crypto Library (Included);
+
+## Features
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+## Note
+No matter what wall of protection you put around your project - **there will always be someone who can hack into it**.
+I recommend two-way protection - on the client and on the server, including full transfer of critical functions to the server.
+
+I am always ready to help you develop a strategy to protect your applications - just contact me.
+
+## Join Community
+- Discord Community
+- Buy me a Beer (Boosty)
+
+![GameShield Wiki](https://github.com/DevsDaddy/GameShield/blob/wiki_visuals/footerImage.png?raw=true)
diff --git a/.gitignore b/Unity Game Shield/.gitignore
similarity index 93%
rename from .gitignore
rename to Unity Game Shield/.gitignore
index 58cbc82..caf2114 100644
--- a/.gitignore
+++ b/Unity Game Shield/.gitignore
@@ -10,6 +10,9 @@
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
+# Hide Configuration
+/Assets/DevsDaddy/GameShield/Resources/Config/GameShieldConfig.*
+
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/
diff --git a/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/.gitignore b/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/.gitignore
new file mode 100644
index 0000000..cf9cc57
--- /dev/null
+++ b/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/contentModel.xml
+/modules.xml
+/.idea.Unity Game Shield.iml
+/projectSettingsUpdater.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/indexLayout.xml b/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/indexLayout.xml
new file mode 100644
index 0000000..f5a863a
--- /dev/null
+++ b/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/vcs.xml b/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/vcs.xml
new file mode 100644
index 0000000..2e3f692
--- /dev/null
+++ b/Unity Game Shield/.idea/.idea.Unity Game Shield/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy.meta b/Unity Game Shield/Assets/DevsDaddy.meta
new file mode 100644
index 0000000..ca63d8d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3b3a34d879f91ff4a8c4ab3d45c50998
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield.meta
new file mode 100644
index 0000000..c6fbf9f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 20987485eb3687449a9cfce22e767828
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core.meta
new file mode 100644
index 0000000..2ae0c82
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 02cfeaae2aad53c46aae826bf37a76d8
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants.meta
new file mode 100644
index 0000000..94fd903
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 57bfaddfad38429caf7c6bbd332070d7
+timeCreated: 1709921114
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralConstants.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralConstants.cs
new file mode 100644
index 0000000..7956edb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralConstants.cs
@@ -0,0 +1,31 @@
+using System.Linq;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Constants
+{
+ public static class GeneralConstants
+ {
+ // Current Shield Version
+ public const string GAME_SHIELD_VERSION = "2024-03R1";
+
+ // General Worker Parameters
+ public const string WORKER_OBJECT_NAME = "GAMESHIELD_WORKER";
+ public const string CONFIG_PATH = "Config/GameShieldConfig";
+ public const string EDITOR_WIZZARD_KEY = "IsGSWizzardShown";
+ public const string EDITOR_WIZZARD_HEADER = "Wizzard/Header";
+ public const string EDITOR_WIZZARD_IMG_PATH = "Wizzard";
+
+ // Injection Scanner
+ public const string ASSMDB_PATH = "Config/ADB";
+ public const string INJECTION_SERVICE_FOLDER = "InjectionDetectorData";
+ public const string INJECTION_DEFAULT_WHITELIST_FILE = "DefaultWhitelist.gsa";
+ public const string INJECTION_USER_WHITELIST_FILE = "UserWhitelist.gsa";
+ public const string INJECTION_DATA_FILE = "ADB.gsa";
+ public const string INJECTION_DATA_SEPARATOR = ":";
+ public const string ASSEMBLIES_PATH_RELATIVE = "Library/ScriptAssemblies";
+ public static readonly string ASSETS_PATH = Application.dataPath;
+ public static readonly string RESOURCES_PATH = ASSETS_PATH + "/Resources/";
+ public static readonly string ASSEMBLIES_PATH = ASSETS_PATH + "/../" + ASSEMBLIES_PATH_RELATIVE;
+ public static readonly string INJECTION_DATA_PATH = RESOURCES_PATH + INJECTION_DATA_FILE;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralConstants.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralConstants.cs.meta
new file mode 100644
index 0000000..83a3c06
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralConstants.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1495ddd86c814a57bb01bb6d5016c9af
+timeCreated: 1709922405
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralStrings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralStrings.cs
new file mode 100644
index 0000000..ee7e5a2
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralStrings.cs
@@ -0,0 +1,27 @@
+namespace DevsDaddy.GameShield.Core.Constants
+{
+ public static class GeneralStrings
+ {
+ // Setup Wizzard
+ public const string SETUP_WIZZARD_TITLE = "GameShield Wizzard";
+ public const string SETUP_WIZZARD_HINT = "Welcome to the GameShield Wizzard";
+ public const string SETUP_WIZZARD_THANKS = "Thanks for installing GameShield Toolkit. \nThis installation wizard will help you set up your project in just a few clicks. And if you have additional questions, please refer to the information below:";
+ public const string VERSION_TITLE = "Current Version:";
+ public const string AUTO_PAUSE_ON_HEADER = "Auto-Pause on Terminated";
+ public const string AUTO_PAUSE_ON_DESC = "Automatically pause modules when the user minimizes the application or the focus is lost.";
+ public const string LOG_PREFIX = "GameShield:";
+
+ public const string DEV_KEY_TITLE = "Developer Key:";
+ public const string DEV_KEY_DESC = "Developer key used for encryption at different modules. Please, do not share it.";
+ public const string DEV_EMAIL_TITLE = "Developer Email:";
+ public const string DEV_EMAIL_DESC = "Used for contacts in Cheating Reporter";
+ public const string DEV_WEBSITE_TITLE = "Developer Website:";
+ public const string DEV_WEBSITE_DESC = "Used for contacts in Cheating Reporter";
+
+ public const string BACK_URL_TITLE = "Backend URL:";
+ public const string BACK_URL_DESC = "Enter your backend URL to enable server-side functional";
+
+ // Report Email
+ public const string REPORT_EMAIL = "iliya-sdt@yandex.ru";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralStrings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralStrings.cs.meta
new file mode 100644
index 0000000..b72b6a4
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Constants/GeneralStrings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1e1b2870f0ef4372930edc5dbf8e041d
+timeCreated: 1709982908
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor.meta
new file mode 100644
index 0000000..2e9e7bd
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 74f4b493242a4bcaa0bebd987ca8406b
+timeCreated: 1709982656
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AllowedAssembly.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AllowedAssembly.cs
new file mode 100644
index 0000000..b71ad85
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AllowedAssembly.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ ///
+ /// Allowed Assembly Class for Editor
+ ///
+ internal class AllowedAssembly
+ {
+ public string name;
+ public int[] hashes;
+
+ public AllowedAssembly(string name, int[] hashes)
+ {
+ this.name = name;
+ this.hashes = hashes;
+ }
+
+ public bool AddHash(int hash)
+ {
+ if (Array.IndexOf(hashes, hash) != -1) return false;
+
+ int oldLen = hashes.Length;
+ int newLen = oldLen + 1;
+
+ int[] newHashesArray = new int[newLen];
+ Array.Copy(hashes, newHashesArray, oldLen);
+
+ hashes = newHashesArray;
+ hashes[oldLen] = hash;
+
+ return true;
+ }
+
+ public override string ToString()
+ {
+ return name + " (hashes: " + hashes.Length + ")";
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AllowedAssembly.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AllowedAssembly.cs.meta
new file mode 100644
index 0000000..e22d6cb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AllowedAssembly.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b6d347450381406d98bb1eef4c59fe2a
+timeCreated: 1710081624
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AssembliesWhitelist.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AssembliesWhitelist.cs
new file mode 100644
index 0000000..b7a709a
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AssembliesWhitelist.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes;
+using UnityEditor;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ ///
+ /// Assemblies Whitelist Editor
+ ///
+ internal class AssembliesWhitelist : EditorWindow
+ {
+ private const string INITIAL_CUSTOM_NAME = "AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
+ private static List whiteList;
+ private static string whitelistPath;
+
+ private Vector2 scrollPosition;
+ private bool manualAssemblyWhitelisting = false;
+ private string manualAssemblyWhitelistingName = INITIAL_CUSTOM_NAME;
+
+ [MenuItem("GameShield/Injection Scanner/Whitelist Editor", false, 42)]
+ internal static void ShowWindow()
+ {
+ EditorWindow myself = GetWindow(false, "Game Libraries Whitelist Editor", true);
+ myself.minSize = new Vector2(500, 200);
+ }
+
+ private void OnLostFocus()
+ {
+ manualAssemblyWhitelisting = false;
+ manualAssemblyWhitelistingName = INITIAL_CUSTOM_NAME;
+ }
+
+ private void OnGUI()
+ {
+ if (whiteList == null)
+ {
+ whiteList = new List();
+ LoadAndParseWhiteList();
+ }
+
+ GUIStyle tmpStyle = new GUIStyle(EditorStyles.largeLabel);
+ tmpStyle.alignment = TextAnchor.MiddleCenter;
+ tmpStyle.fontStyle = FontStyle.Bold;
+ GUILayout.Label("User-defined Whitelist of Assemblies trusted by Injection Scanner", tmpStyle);
+
+ scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
+ bool whitelistUpdated = false;
+
+ int count = whiteList.Count;
+
+ if (count > 0)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ AllowedAssembly assembly = whiteList[i];
+ GUILayout.BeginHorizontal();
+ GUILayout.Label(assembly.ToString());
+ if (GUILayout.Button(new GUIContent("-", "Remove Assembly from Whitelist"), GUILayout.Width(30)))
+ {
+ whiteList.Remove(assembly);
+ whitelistUpdated = true;
+ }
+ GUILayout.EndHorizontal();
+ }
+ }
+ else
+ {
+ tmpStyle = new GUIStyle(EditorStyles.largeLabel);
+ tmpStyle.alignment = TextAnchor.MiddleCenter;
+ GUILayout.Label("- no Assemblies added so far (use buttons below to add) -", tmpStyle);
+ }
+
+ if (manualAssemblyWhitelisting)
+ {
+ manualAssemblyWhitelistingName = EditorGUILayout.TextField(manualAssemblyWhitelistingName);
+
+ GUILayout.BeginHorizontal();
+ if (GUILayout.Button("Save"))
+ {
+ try
+ {
+ AssemblyName assName = new AssemblyName(manualAssemblyWhitelistingName);
+ WhitelisingResult res = TryWhitelistAssemblyName(assName, true);
+ if (res != WhitelisingResult.Exists)
+ {
+ whitelistUpdated = true;
+ }
+ manualAssemblyWhitelisting = false;
+ manualAssemblyWhitelistingName = INITIAL_CUSTOM_NAME;
+ }
+ catch (FileLoadException error)
+ {
+ ShowNotification(new GUIContent(error.Message));
+ }
+
+ GUI.FocusControl("");
+ }
+
+ if (GUILayout.Button("Cancel"))
+ {
+ manualAssemblyWhitelisting = false;
+ manualAssemblyWhitelistingName = INITIAL_CUSTOM_NAME;
+ GUI.FocusControl("");
+ }
+ GUILayout.EndHorizontal();
+ }
+
+ EditorGUILayout.EndScrollView();
+
+ GUILayout.BeginHorizontal();
+ GUILayout.Space(20);
+ if (GUILayout.Button("Add Assembly"))
+ {
+ string 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"))
+ {
+ string selectedFolder = EditorUtility.OpenFolderPanel("Choose a folder with Assemblies", "", "");
+ if (!String.IsNullOrEmpty(selectedFolder))
+ {
+ string[] libraries = InjectionDetectorGlobal.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 Scanner whitelist?", "Yes", "No"))
+ {
+ whiteList.Clear();
+ whitelistUpdated = true;
+ }
+ }
+ }
+ GUILayout.Space(20);
+ GUILayout.EndHorizontal();
+
+ GUILayout.Space(20);
+
+ if (whitelistUpdated)
+ {
+ WriteWhiteList();
+ }
+ }
+
+ private bool TryWhitelistAssemblies(string[] libraries)
+ {
+ return TryWhitelistAssemblies(libraries, false);
+ }
+
+ private bool TryWhitelistAssemblies(string[] libraries, bool singleFile)
+ {
+ int added = 0;
+ int updated = 0;
+
+ int count = libraries.Length;
+
+ for (int i = 0; i < count; i++)
+ {
+ string libraryPath = libraries[i];
+ try
+ {
+ AssemblyName assName = AssemblyName.GetAssemblyName(libraryPath);
+ WhitelisingResult whitelistingResult = TryWhitelistAssemblyName(assName, singleFile);
+ if (whitelistingResult == WhitelisingResult.Added)
+ {
+ added++;
+ }
+ else if (whitelistingResult == WhitelisingResult.Updated)
+ {
+ updated++;
+ }
+
+ }
+ 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 WhitelisingResult TryWhitelistAssemblyName(AssemblyName assName, bool singleFile)
+ {
+ WhitelisingResult result = WhitelisingResult.Exists;
+
+ string name = assName.Name;
+ int hash = InjectionDetectorGlobal.GetAssemblyHash(assName);
+
+ AllowedAssembly allowed = whiteList.FirstOrDefault(allowedAssembly => allowedAssembly.name == name);
+
+ if (allowed != null)
+ {
+ if (allowed.AddHash(hash))
+ {
+ if (singleFile) ShowNotification(new GUIContent("New hash added!"));
+ result = WhitelisingResult.Updated;
+ }
+ else
+ {
+ if (singleFile) ShowNotification(new GUIContent("Assembly already exists!"));
+ }
+ }
+ else
+ {
+ allowed = new AllowedAssembly(name, new[] { hash });
+ whiteList.Add(allowed);
+
+ if (singleFile) ShowNotification(new GUIContent("Assembly added!"));
+ result = WhitelisingResult.Added;
+ }
+
+ return result;
+ }
+
+ private void LoadAndParseWhiteList()
+ {
+ whitelistPath = InjectionDetectorGlobal.ResolveInjectionUserWhitelistPath();
+ if (!String.IsNullOrEmpty(whitelistPath) && File.Exists(whitelistPath))
+ {
+ string[] separator = { GeneralConstants.INJECTION_DATA_SEPARATOR };
+
+ FileStream fs = new FileStream(whitelistPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+ BinaryReader br = new BinaryReader(fs);
+
+ int count = br.ReadInt32();
+
+ for (int i = 0; i < count; i++)
+ {
+ string line = br.ReadString();
+ line = SecuredString.EncryptDecrypt(line, "GAMESHIELD");
+ string[] strArr = line.Split(separator, StringSplitOptions.RemoveEmptyEntries);
+ int stringsCount = strArr.Length;
+ if (stringsCount > 1)
+ {
+ string assemblyName = strArr[0];
+
+ int[] hashes = new int[stringsCount - 1];
+ for (int j = 1; j < stringsCount; j++)
+ {
+ hashes[j - 1] = int.Parse(strArr[j]);
+ }
+
+ whiteList.Add(new AllowedAssembly(assemblyName, hashes));
+ }
+ else
+ {
+ Debug.LogWarning("Error parsing whitelist file line! Please report to " + GeneralStrings.REPORT_EMAIL);
+ }
+ }
+
+ br.Close();
+ fs.Close();
+ }
+ }
+
+ private void WriteWhiteList()
+ {
+ if (whiteList.Count > 0)
+ {
+ bool fileExisted = File.Exists(whitelistPath);
+ InjectionDetectorGlobal.RemoveReadOnlyAttribute(whitelistPath);
+ FileStream fs = new FileStream(whitelistPath, FileMode.Create, FileAccess.Write, FileShare.Read);
+ BinaryWriter br = new BinaryWriter(fs);
+
+ br.Write(whiteList.Count);
+
+ foreach (AllowedAssembly assembly in whiteList)
+ {
+ string assemblyName = assembly.name;
+ string hashes = "";
+
+ for (int j = 0; j < assembly.hashes.Length; j++)
+ {
+ hashes += assembly.hashes[j];
+ if (j < assembly.hashes.Length - 1)
+ {
+ hashes += GeneralConstants.INJECTION_DATA_SEPARATOR;
+ }
+ }
+
+ string line = SecuredString.EncryptDecrypt(assemblyName + GeneralConstants.INJECTION_DATA_SEPARATOR + hashes, "GAMESHIELD");
+ br.Write(line);
+ }
+ br.Close();
+ fs.Close();
+
+ if (!fileExisted)
+ {
+ AssetDatabase.Refresh();
+ }
+ }
+ else
+ {
+ InjectionDetectorGlobal.RemoveReadOnlyAttribute(whitelistPath);
+ FileUtil.DeleteFileOrDirectory(whitelistPath);
+ AssetDatabase.Refresh();
+ }
+
+ Postprocessor.InjectionAssembliesScan();
+ }
+
+ private enum WhitelisingResult:byte
+ {
+ Exists,
+ Added,
+ Updated
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AssembliesWhitelist.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AssembliesWhitelist.cs.meta
new file mode 100644
index 0000000..f8d448b
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/AssembliesWhitelist.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6910dbf3b4c8450b98ffba8ef3763198
+timeCreated: 1710084441
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/EditorExtensions.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/EditorExtensions.cs
new file mode 100644
index 0000000..61771b4
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/EditorExtensions.cs
@@ -0,0 +1,58 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ public static class EditorExtensions
+ {
+ public static System.Type[] GetAllDerivedTypes(this System.AppDomain aAppDomain, System.Type aType)
+ {
+ var result = new List();
+ var assemblies = aAppDomain.GetAssemblies();
+ foreach (var assembly in assemblies)
+ {
+ var types = assembly.GetTypes();
+ foreach (var type in types)
+ {
+ if (type.IsSubclassOf(aType))
+ result.Add(type);
+ }
+ }
+ return result.ToArray();
+ }
+
+ public static Rect GetEditorMainWindowPos()
+ {
+ var containerWinType = System.AppDomain.CurrentDomain.GetAllDerivedTypes(typeof(ScriptableObject)).Where(t => t.Name == "ContainerWindow").FirstOrDefault();
+ if (containerWinType == null)
+ throw new System.MissingMemberException("Can't find internal type ContainerWindow. Maybe something has changed inside Unity");
+ var showModeField = containerWinType.GetField("m_ShowMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
+ var positionProperty = containerWinType.GetProperty("position", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
+ if (showModeField == null || positionProperty == null)
+ throw new System.MissingFieldException("Can't find internal fields 'm_ShowMode' or 'position'. Maybe something has changed inside Unity");
+ var windows = Resources.FindObjectsOfTypeAll(containerWinType);
+ foreach (var win in windows)
+ {
+ var showmode = (int)showModeField.GetValue(win);
+ if (showmode == 4) // main window
+ {
+ var pos = (Rect)positionProperty.GetValue(win, null);
+ return pos;
+ }
+ }
+ throw new System.NotSupportedException("Can't find internal main window. Maybe something has changed inside Unity");
+ }
+
+ public static void CenterOnMainWin(this UnityEditor.EditorWindow aWin)
+ {
+ var main = GetEditorMainWindowPos();
+ var pos = aWin.position;
+ float w = (main.width - pos.width)*0.5f;
+ float h = (main.height - pos.height)*0.5f;
+ pos.x = main.x + w;
+ pos.y = main.y + h;
+ aWin.position = pos;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/EditorExtensions.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/EditorExtensions.cs.meta
new file mode 100644
index 0000000..53c03ba
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/EditorExtensions.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 0fe3c6b6c2fc43969d450fa5da7a8fbe
+timeCreated: 1709991741
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldStyles.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldStyles.cs
new file mode 100644
index 0000000..7390f35
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldStyles.cs
@@ -0,0 +1,230 @@
+using DevsDaddy.GameShield.Core.Constants;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ internal class GameShieldStyles
+ {
+ // Textures
+ private Texture2D switcherOff;
+ private Texture2D switcherOn;
+
+ ///
+ /// Get Header Style
+ ///
+ ///
+ public GUIStyle GetHeaderStyle() {
+ GUIStyle style = new GUIStyle();
+ style.alignment = TextAnchor.MiddleCenter;
+ style.fontStyle = FontStyle.Bold;
+ style.fontSize = 16;
+ style.padding = new RectOffset(20, 20, 10, 10);
+ style.normal.background = MakeTex( 2, 2, Color.white);
+ return style;
+ }
+
+ ///
+ /// Get Footer Button Style
+ ///
+ ///
+ public GUIStyle GetFooterButtonStyle(bool isBack = false) {
+ Color[] normalColors = {new Color(0f, 0.54f, 0.77f, 1f), new Color(0f, 0.3f, 0.77f, 1f) };
+ Color[] backColors = {new Color(0.8f, 0, 0.2f, 1f), new Color(0.6f, 0, 0.2f, 1f)};
+
+ GUIStyle style = new GUIStyle();
+ style.alignment = TextAnchor.MiddleCenter;
+ style.padding = new RectOffset(20, 20, 10, 10);
+ style.margin = new RectOffset(10, 10, 10, 10);
+ style.border = new RectOffset(0, 0, 0, 0);
+ style.fontSize = 14;
+ style.fontStyle = (isBack) ? FontStyle.Normal : FontStyle.Bold;
+ style.normal.background = MakeTex( 2, 2, isBack ? backColors[0] : normalColors[0]);
+ style.hover.background = MakeTex( 2, 2, isBack ? backColors[1] : normalColors[1]);
+ style.focused.background = MakeTex( 2, 2, isBack ? backColors[0] : normalColors[0]);
+ style.normal.textColor = Color.white;
+ style.focused.textColor = Color.white;
+ style.hover.textColor = Color.white;
+ return style;
+ }
+
+ ///
+ /// Get Basic Button Style
+ ///
+ ///
+ public GUIStyle GetBasicButtonSyle(bool isSmall = false) {
+ Color[] normalColors = {new Color(0.6f, 0.6f, 0.8f, 1f), new Color(0.6f, 0.9f, 0.8f, 1f) };
+
+ GUIStyle style = new GUIStyle();
+ style.alignment = TextAnchor.MiddleCenter;
+ style.padding = isSmall ? new RectOffset(10, 10, 5, 5) : new RectOffset(20, 20, 10, 10);
+ style.margin = isSmall ? new RectOffset(0,0,0,0) : new RectOffset(10, 10, 10, 10);
+ style.border = new RectOffset(0, 0, 0, 0);
+ style.fontSize = isSmall ? 12 : 14;
+ style.fontStyle = FontStyle.Normal;
+ style.normal.background = MakeTex( 2, 2, normalColors[0]);
+ style.hover.background = MakeTex( 2, 2, normalColors[1]);
+ style.focused.background = MakeTex( 2, 2, normalColors[0]);
+ style.normal.textColor = Color.white;
+ style.focused.textColor = Color.white;
+ style.hover.textColor = Color.white;
+ return style;
+ }
+
+ ///
+ /// Get Basic Field Style
+ ///
+ ///
+ public GUIStyle GetBasicFieldStyle() {
+ Color[] normalColors = {new Color(0.3f, 0.3f, 0.3f, 1f), new Color(0.2f, 0.2f, 0.2f, 1f) };
+
+ GUIStyle style = new GUIStyle();
+ style.alignment = TextAnchor.MiddleLeft;
+ style.padding = new RectOffset(20, 20, 10, 10);
+ style.border = new RectOffset(1, 1, 1, 1);
+ style.fontSize = 14;
+ style.fontStyle = FontStyle.Bold;
+ style.normal.textColor = Color.white;
+ style.focused.textColor = Color.white;
+ style.hover.textColor = Color.white;
+ style.normal.background = MakeTex( 2, 2, normalColors[0]);
+ style.hover.background = MakeTex( 2, 2, normalColors[1]);
+ style.focused.background = MakeTex( 2, 2, normalColors[1]);
+ return style;
+ }
+
+ ///
+ /// Get Switch Button Style
+ ///
+ ///
+ public GUIStyle GetSwitchButtonStyle(bool isActive) {
+ // Load Textures
+ if (switcherOff == null)
+ switcherOff = Resources.Load($"{GeneralConstants.EDITOR_WIZZARD_IMG_PATH}/Off");
+ if (switcherOn == null)
+ switcherOn = Resources.Load($"{GeneralConstants.EDITOR_WIZZARD_IMG_PATH}/On");
+
+ // Create Style
+ GUIStyle style = new GUIStyle();
+ style.alignment = TextAnchor.MiddleCenter;
+ style.fixedWidth = switcherOff.width;
+ style.fixedHeight = switcherOff.height;
+ style.normal.background = isActive ? switcherOn : switcherOff;
+ style.margin = new RectOffset(10, 10, 10, 10);
+ return style;
+ }
+
+ ///
+ /// Get Footer Area Style
+ ///
+ ///
+ public GUIStyle GetFooterAreaStyle() {
+ GUIStyle style = new GUIStyle();
+ style.normal.background = MakeTex( 2, 2, Color.white);
+ return style;
+ }
+
+ ///
+ /// Get Body Area Style
+ ///
+ ///
+ public GUIStyle GetBodyAreaStyle() {
+ GUIStyle style = new GUIStyle();
+ style.padding = new RectOffset(20, 20, 10, 10);
+ style.normal.background = MakeTex( 2, 2, new Color(0.9f, 0.9f, 0.9f));
+ style.alignment = TextAnchor.MiddleCenter;
+ return style;
+ }
+
+ ///
+ /// Get Regular Text Style
+ ///
+ ///
+ ///
+ public GUIStyle GetRegularTextStyle(TextAnchor anchor = TextAnchor.UpperLeft) {
+ GUIStyle style = new GUIStyle();
+ style.normal.textColor = Color.black;
+ style.wordWrap = true;
+ style.alignment = anchor;
+ style.fontSize = 12;
+ style.margin = new RectOffset(0, 0, 10, 10);
+ return style;
+ }
+
+ ///
+ /// Get Sub Header Style
+ ///
+ ///
+ public GUIStyle GetSubHeaderStyle() {
+ GUIStyle style = new GUIStyle();
+ style.normal.textColor = Color.black;
+ style.wordWrap = true;
+ style.alignment = TextAnchor.MiddleCenter;
+ style.fontSize = 16;
+ style.fontStyle = FontStyle.Bold;
+ style.padding = new RectOffset(20, 20, 10, 10);
+ style.normal.background = MakeTex( 2, 2, new Color(0.7f, 0.7f, 0.7f));
+ return style;
+ }
+
+ ///
+ /// Get Sub Header Style
+ ///
+ ///
+ public GUIStyle GetListElementStyle() {
+ GUIStyle style = new GUIStyle();
+ style.normal.textColor = Color.black;
+ style.wordWrap = true;
+ style.alignment = TextAnchor.MiddleCenter;
+ style.fontSize = 16;
+ style.fontStyle = FontStyle.Bold;
+ style.padding = new RectOffset(20, 20, 10, 10);
+ style.normal.background = MakeTex( 2, 2, new Color(0.8f, 0.8f, 0.8f));
+ style.margin = new RectOffset(0, 0, 0, 10);
+ return style;
+ }
+
+ ///
+ /// Get Warning Text Style
+ ///
+ ///
+ ///
+ public GUIStyle GetWarningTextStyle(TextAnchor anchor = TextAnchor.UpperLeft) {
+ GUIStyle style = new GUIStyle();
+ style.normal.textColor = Color.red;
+ style.wordWrap = true;
+ style.alignment = anchor;
+ style.fontSize = 12;
+ style.fontStyle = FontStyle.Bold;
+ style.margin = new RectOffset(0, 0, 10, 10);
+ return style;
+ }
+
+ ///
+ /// Get BG Texture
+ ///
+ ///
+ public Texture GetBGTexture() {
+ return MakeTex(2, 2, new Color(0.9f, 0.9f, 0.9f));
+ }
+
+ ///
+ /// Generate Texture
+ ///
+ ///
+ ///
+ ///
+ ///
+ private Texture2D MakeTex( int width, int height, Color col )
+ {
+ Color[] pix = new Color[width * height];
+ for( int i = 0; i < pix.Length; ++i )
+ {
+ pix[ i ] = col;
+ }
+ Texture2D result = new Texture2D( width, height );
+ result.SetPixels( pix );
+ result.Apply();
+ return result;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldStyles.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldStyles.cs.meta
new file mode 100644
index 0000000..ba1eef8
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldStyles.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 46e0ecc399314f41991caad516dafe8c
+timeCreated: 1709989219
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldWizzard.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldWizzard.cs
new file mode 100644
index 0000000..fca41bb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldWizzard.cs
@@ -0,0 +1,471 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Modules;
+using DevsDaddy.GameShield.Core.Utils;
+using UnityEditor;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ ///
+ /// Game Shield Wizzard Window
+ ///
+ public class GameShieldWizzard : EditorWindow
+ {
+ // Current Wizzard Tab
+ private static GameShieldConfig currentConfig = null;
+ private static WizzardTab currentWizzardTab = WizzardTab.Welcome;
+
+ // Window Sizes
+ private static readonly Vector2 minWindowSize = new Vector2(450, 600);
+ private static readonly Vector2 maxWindowSize = new Vector2(550, 1024);
+
+ // Styles and Images
+ private GameShieldStyles styles = new GameShieldStyles();
+ private Texture wizzardHeaderImage;
+
+ // Modules
+ private static string rootPath = "";
+ private List availableModules = new List();
+
+ // Scroll Positions
+ Vector2 scrollPos;
+
+ ///
+ /// Show GameShield Wizzard
+ ///
+ [MenuItem("GameShield/Setup Wizzard", false, 0)]
+ private static void Init()
+ {
+ // Get existing open window or if none, make a new one:
+ EditorPrefs.SetBool(GeneralConstants.EDITOR_WIZZARD_KEY, true);
+ GameShieldWizzard window = (GameShieldWizzard)EditorWindow.GetWindow(typeof(GameShieldWizzard));
+ window.titleContent = new GUIContent(GeneralStrings.SETUP_WIZZARD_TITLE, GeneralStrings.SETUP_WIZZARD_HINT);
+ window.maxSize = maxWindowSize;
+ window.minSize = minWindowSize;
+ window.position = new Rect(Screen.width / 2, Screen.height / 2, minWindowSize.x, minWindowSize.y);
+ window.Show();
+ window.CenterOnMainWin();
+ window.SwitchTab(WizzardTab.Welcome);
+ }
+
+ ///
+ /// GUI Updates
+ ///
+ private void OnGUI(){
+ DrawHeader();
+ DrawBody();
+ DrawFooter();
+ }
+
+ ///
+ /// Draw Wizzard Header
+ ///
+ private void DrawHeader() {
+ // Load Image
+ if (wizzardHeaderImage == null)
+ wizzardHeaderImage = Resources.Load(GeneralConstants.EDITOR_WIZZARD_HEADER);
+
+ // Draw Window BG
+ GUI.DrawTexture(new Rect(0, 0, position.width, position.height), styles.GetBGTexture(), ScaleMode.StretchToFill, true);
+
+ // Draw Texture
+ float ratio = wizzardHeaderImage.height / wizzardHeaderImage.width;
+ float w = position.width;
+ float h = position.width / wizzardHeaderImage.width * wizzardHeaderImage.height;
+ GUILayout.BeginHorizontal();
+ GUI.DrawTexture(new Rect(0, 0, w, h), wizzardHeaderImage, ScaleMode.StretchToFill, true, ratio);
+ GUILayout.EndHorizontal();
+ GUILayout.Space(h);
+
+ // Header
+ GUILayout.BeginHorizontal();
+ GUILayout.Label(GetTabText(), styles.GetHeaderStyle());
+ GUILayout.EndHorizontal();
+ }
+
+ ///
+ /// Draw Wizzard Body
+ ///
+ private void DrawBody() {
+ if (currentWizzardTab == WizzardTab.Welcome)
+ DrawWelcomeScreen();
+ if (currentWizzardTab == WizzardTab.GeneralSetup)
+ DrawConfigEditor();
+ if (currentWizzardTab == WizzardTab.Complete)
+ DrawCompleteSetup();
+ }
+
+ ///
+ /// Draw Welcome Screen
+ ///
+ private void DrawWelcomeScreen() {
+ GUILayout.BeginVertical(styles.GetBodyAreaStyle(), GUILayout.ExpandHeight(true));
+ scrollPos = GUILayout.BeginScrollView(scrollPos);
+ GUILayout.Label($"{GeneralStrings.VERSION_TITLE} {GeneralConstants.GAME_SHIELD_VERSION}", styles.GetRegularTextStyle(TextAnchor.MiddleCenter));
+ GUILayout.Space(20);
+ GUILayout.Label(GeneralStrings.SETUP_WIZZARD_THANKS, styles.GetRegularTextStyle(TextAnchor.MiddleCenter));
+ GUILayout.Space(10);
+ if(GUILayout.Button("Open Documentation", styles.GetBasicButtonSyle())) {
+ Application.OpenURL("https://github.com/DevsDaddy/GameShield/wiki");
+ }
+ if(GUILayout.Button("Check New Versions", styles.GetBasicButtonSyle())) {
+ Application.OpenURL("https://github.com/DevsDaddy/GameShield/releases");
+ }
+ if(GUILayout.Button("Join Discord", styles.GetBasicButtonSyle())) {
+ Application.OpenURL("https://discord.gg/xuNTKRDebx");
+ }
+ if(GUILayout.Button("Report a Bug", styles.GetBasicButtonSyle())) {
+ Application.OpenURL("https://github.com/DevsDaddy/GameShield/issues");
+ }
+ GUILayout.EndScrollView();
+ GUILayout.EndVertical();
+ }
+
+ ///
+ /// Draw Config Editor
+ ///
+ private void DrawConfigEditor() {
+ GUILayout.BeginVertical(styles.GetBodyAreaStyle(), GUILayout.ExpandHeight(true));
+ scrollPos = GUILayout.BeginScrollView(scrollPos);
+ GUILayout.Label("GENERAL", styles.GetSubHeaderStyle());
+ DrawGeneralConfigs();
+
+ GUILayout.Space(20);
+ GUILayout.Label("MODULES", styles.GetSubHeaderStyle());
+ DrawModules();
+
+ GUILayout.EndScrollView();
+ GUILayout.EndVertical();
+ }
+
+ ///
+ /// Draw Complete Setup
+ ///
+ private void DrawCompleteSetup() {
+ GUILayout.BeginVertical(styles.GetBodyAreaStyle(), GUILayout.ExpandHeight(true));
+ scrollPos = GUILayout.BeginScrollView(scrollPos);
+ GUILayout.Label("CONTACTS", styles.GetSubHeaderStyle());
+
+ // Developer Email
+ DrawInputField(GeneralStrings.DEV_EMAIL_DESC, GeneralStrings.DEV_EMAIL_TITLE, currentConfig.Contacts.Email,
+ key => {
+ currentConfig.Contacts.Email = key;
+ });
+
+ // Developer Contacts
+ DrawInputField(GeneralStrings.DEV_WEBSITE_DESC, GeneralStrings.DEV_WEBSITE_TITLE, currentConfig.Contacts.Website,
+ key => {
+ currentConfig.Contacts.Website = key;
+ });
+ GUILayout.Space(20);
+
+ GUILayout.Label("AND NOW IS DONE", styles.GetSubHeaderStyle());
+ GUILayout.Label("Your GameShield is now ready to go.\n\nDo not remove the GAME_SHIELD object from the scene!", styles.GetRegularTextStyle());
+
+ GUILayout.EndScrollView();
+ GUILayout.EndVertical();
+ }
+
+ ///
+ /// Draw Wizzard Footer
+ ///
+ private void DrawFooter() {
+ GUILayout.FlexibleSpace();
+ GUILayout.BeginHorizontal(styles.GetFooterAreaStyle());
+ if (currentWizzardTab == WizzardTab.GeneralSetup || currentWizzardTab == WizzardTab.Complete) {
+ if(GUILayout.Button("Go Back", styles.GetFooterButtonStyle(true))) {
+ SwitchTab((currentWizzardTab == WizzardTab.GeneralSetup) ? WizzardTab.Welcome : WizzardTab.GeneralSetup);
+ }
+ }
+ if (currentWizzardTab == WizzardTab.Welcome || currentWizzardTab == WizzardTab.GeneralSetup) {
+ if(GUILayout.Button("Continue", styles.GetFooterButtonStyle(false))) {
+ SwitchTab(currentWizzardTab = (currentWizzardTab == WizzardTab.Welcome) ? WizzardTab.GeneralSetup : WizzardTab.Complete);
+ }
+ }
+ if (currentWizzardTab == WizzardTab.Complete) {
+ if (GUILayout.Button("Complete Setup", styles.GetFooterButtonStyle(false)))
+ CompleteSetup();
+ }
+ GUILayout.EndHorizontal();
+ }
+
+ ///
+ /// Draw Modules
+ ///
+ private void DrawModules() {
+ // Get Available Modules
+ if (availableModules.Count < 1) {
+ availableModules = ModuleManager.GetAllModules();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Loading All Available Modules. Found Modules: {availableModules.Count}");
+ }
+
+ if (availableModules.Count > 0)
+ availableModules.ForEach(DrawModule);
+ else {
+ GUILayout.Label("No modules found. Please, re-install GameShield.", styles.GetWarningTextStyle(TextAnchor.MiddleCenter));
+ }
+ }
+
+ ///
+ /// Toggle All Modules
+ ///
+ private static void ToggleAllModules() {
+ // Toggle All Modules
+ List allModules = ModuleManager.GetAllModules();
+ allModules.ForEach(module => {
+ currentConfig.AvailableModules.Add(module.GetType().ToString());
+ });
+ }
+
+ ///
+ /// Draw Single Module
+ ///
+ ///
+ private void DrawModule(IShieldModule module) {
+ ModuleInfo moduleInfo = module.GetModuleInfo();
+ bool isModuleEnabled = IsModuleEnabled(module);
+ GUILayout.BeginHorizontal(styles.GetListElementStyle());
+ GUILayout.BeginVertical();
+ if (GUILayout.Button("", styles.GetSwitchButtonStyle(isModuleEnabled), GUILayout.ExpandWidth(false))) {
+ ToggleModule(module);
+ }
+ GUILayout.EndVertical();
+ GUILayout.BeginVertical();
+ GUILayout.Label($"{moduleInfo.Name}", styles.GetRegularTextStyle(TextAnchor.UpperLeft));
+ GUILayout.Label(moduleInfo.Description, styles.GetRegularTextStyle(TextAnchor.UpperLeft));
+ if (GUILayout.Button("Show Documentation", styles.GetBasicButtonSyle(true), GUILayout.ExpandWidth(false))) {
+ Application.OpenURL(moduleInfo.DocumentationLink);
+ }
+ GUILayout.EndVertical();
+ GUILayout.EndHorizontal();
+ }
+
+ ///
+ /// Draw General Configs
+ ///
+ private void DrawGeneralConfigs() {
+ // Developer Key Module
+ DrawInputField(GeneralStrings.DEV_KEY_DESC, GeneralStrings.DEV_KEY_TITLE, currentConfig.DeveloperKey,
+ key => {
+ currentConfig.DeveloperKey = key;
+ });
+
+ // GameShield Backend URL
+ DrawInputField(GeneralStrings.BACK_URL_DESC, GeneralStrings.BACK_URL_TITLE, currentConfig.BackendURL,
+ key => {
+ currentConfig.BackendURL = key;
+ });
+
+ // Auto-Pause Modules
+ DrawToggleListElement(GeneralStrings.AUTO_PAUSE_ON_HEADER, GeneralStrings.AUTO_PAUSE_ON_DESC, currentConfig.PauseOnApplicationTerminated,
+ () => {
+ currentConfig.PauseOnApplicationTerminated = !currentConfig.PauseOnApplicationTerminated;
+ });
+ GUILayout.Space(10);
+ }
+
+ ///
+ /// Draw Input Field
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void DrawInputField(string placeholder, string label, string variable, Action onComplete = null) {
+ string newText = "";
+ GUILayout.BeginHorizontal(styles.GetListElementStyle());
+ GUILayout.BeginVertical();
+ GUILayout.Label($"{label}", styles.GetRegularTextStyle(TextAnchor.UpperLeft));
+ newText = GUILayout.TextField(variable, 64, styles.GetBasicFieldStyle());
+ GUILayout.Label($"{placeholder}", styles.GetRegularTextStyle(TextAnchor.UpperLeft));
+ GUILayout.EndVertical();
+ GUILayout.EndHorizontal();
+
+ if(newText != variable)
+ onComplete?.Invoke(newText);
+ }
+
+ ///
+ /// Draw Toggle List Element
+ ///
+ ///
+ ///
+ ///
+ ///
+ private void DrawToggleListElement(string title, string description, bool toggleVariable, Action onToggle) {
+ GUILayout.BeginHorizontal(styles.GetListElementStyle());
+ GUILayout.BeginVertical();
+ if (GUILayout.Button("", styles.GetSwitchButtonStyle(toggleVariable), GUILayout.ExpandWidth(false))) {
+ onToggle?.Invoke();
+ }
+ GUILayout.EndVertical();
+ GUILayout.BeginVertical();
+ GUILayout.Label(title, styles.GetRegularTextStyle(TextAnchor.UpperLeft));
+ GUILayout.Label(description, styles.GetRegularTextStyle(TextAnchor.UpperLeft));
+ GUILayout.EndVertical();
+ GUILayout.EndHorizontal();
+ }
+
+ ///
+ /// Is Module Enabled
+ ///
+ ///
+ ///
+ private bool IsModuleEnabled(IShieldModule module) {
+ string found = currentConfig.AvailableModules.Find(mod => mod == module.GetType().ToString());
+ return (found != null);
+ }
+
+ ///
+ /// Toggle Module
+ ///
+ ///
+ private bool ToggleModule(IShieldModule module) {
+ string found = currentConfig.AvailableModules.Find(mod => mod == module.GetType().ToString());
+ if (found == null) {
+ currentConfig.AvailableModules.Add(module.GetType().ToString());
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Module {nameof(module)} is Enabled");
+ return true;
+ }
+ else {
+ currentConfig.AvailableModules.Remove(found);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Module {nameof(module)} is Disabled");
+ return false;
+ }
+ }
+
+ ///
+ /// Complete Setup
+ ///
+ private void CompleteSetup() {
+ // Save Configs
+ AssetDatabase.SaveAssets();
+ AssetDatabase.Refresh();
+
+ // Add GameObject on Scene
+ GameShield worker = FindObjectOfType();
+ if (worker == null) {
+ GameObject workerObject = new GameObject("__GAME_SHIELD__");
+ workerObject.AddComponent();
+ workerObject.transform.SetAsFirstSibling();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Added Worker GameObject at Current Scene");
+ }
+
+ // Close Window
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Setup is Done");
+ Close();
+ }
+
+ ///
+ /// Initialize Wizzard
+ ///
+ [InitializeOnLoadMethod]
+ private static void InitializeWizzard() {
+ // Get Config
+ if (string.IsNullOrEmpty(rootPath)) rootPath = GetRoot();
+ bool isWizzardShown = EditorPrefs.GetBool(GeneralConstants.EDITOR_WIZZARD_KEY, false);
+ if (!isWizzardShown) {
+ currentWizzardTab = WizzardTab.Welcome;
+ Init();
+ }
+ }
+
+ [MenuItem("GameShield/Utils/Reset Setup Wizzard", false, 99)]
+ private static void ResetWizzard() {
+ EditorPrefs.SetBool(GeneralConstants.EDITOR_WIZZARD_KEY, false);
+ }
+
+ ///
+ /// Switch Wizzard to Tab
+ ///
+ ///
+ private void SwitchTab(WizzardTab tab) {
+ currentWizzardTab = tab;
+ scrollPos = new Vector2(0, 0);
+
+ if (currentWizzardTab == WizzardTab.GeneralSetup) {
+ GetConfig();
+ currentConfig.ConfigRevision += 1;
+ EditorUtility.SetDirty(currentConfig);
+ }
+ }
+
+ ///
+ /// Get Tab Text
+ ///
+ ///
+ private string GetTabText() {
+ switch (currentWizzardTab) {
+ case WizzardTab.Welcome:
+ return "Welcome to GameShield!";
+ case WizzardTab.GeneralSetup:
+ return "Configure GameShield";
+ case WizzardTab.Complete:
+ return "Complete Setup";
+ }
+
+ return "";
+ }
+
+ ///
+ /// Get Script Path for
+ ///
+ ///
+ ///
+ private static string GetRoot() {
+ var asset = "";
+ var guids = AssetDatabase.FindAssets( string.Format( "{0} t:script", nameof(GameShieldWizzard)));
+
+ if ( guids.Length > 1 ) {
+ foreach ( var guid in guids ) {
+ var assetPath = AssetDatabase.GUIDToAssetPath(guid);
+ var filename = Path.GetFileNameWithoutExtension( assetPath );
+ if ( filename == nameof(GameShieldWizzard) ) {
+ asset = guid;
+ break;
+ }
+ }
+ } else if ( guids.Length == 1 ) {
+ asset = guids [0];
+ } else {
+ Debug.LogErrorFormat("Unable to locate {0}", nameof(GameShieldWizzard));
+ return null;
+ }
+
+ string path = AssetDatabase.GUIDToAssetPath (asset);
+ string relative = path.Replace($"Core/Editor/{nameof(GameShieldWizzard)}.cs", "");
+ return relative;
+ }
+
+ ///
+ /// Get Current Config
+ ///
+ private static void GetConfig() {
+ if (string.IsNullOrEmpty(rootPath)) rootPath = GetRoot();
+
+ // Load Configurations
+ GameShieldConfig config = Resources.Load(GeneralConstants.CONFIG_PATH);
+ if (config == null) {
+ currentConfig = CreateInstance();
+ currentConfig.DeveloperKey = Generator.GenerateRandomKey(32);
+ ToggleAllModules();
+ string pathToConfig = $"{rootPath}Resources/{GeneralConstants.CONFIG_PATH}.asset";
+ AssetDatabase.CreateAsset(currentConfig, pathToConfig);
+ AssetDatabase.Refresh();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Config Created At: {pathToConfig}");
+ return;
+ }
+
+ currentConfig = config;
+
+ // Generate key if Null
+ if(string.IsNullOrEmpty(currentConfig.DeveloperKey))
+ currentConfig.DeveloperKey = Generator.GenerateRandomKey(32);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Loaded Config: {currentConfig}");
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Enabled Modules: {currentConfig.AvailableModules.Count}");
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldWizzard.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldWizzard.cs.meta
new file mode 100644
index 0000000..4beab75
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/GameShieldWizzard.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2a18f6f7cb9d41ed9593d32aa38a1795
+timeCreated: 1709982672
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/InjectionDetectorGlobal.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/InjectionDetectorGlobal.cs
new file mode 100644
index 0000000..6381f8c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/InjectionDetectorGlobal.cs
@@ -0,0 +1,145 @@
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using DevsDaddy.GameShield.Core.Constants;
+using UnityEditor;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ internal class InjectionDetectorGlobal
+ {
+ private static readonly string[] hexTable = Enumerable.Range(0, 256).Select(v => v.ToString("x2")).ToArray();
+
+ internal static void CleanInjectionDetectorData()
+ {
+ if (!File.Exists(GeneralConstants.INJECTION_DATA_PATH))
+ {
+ return;
+ }
+
+ RemoveReadOnlyAttribute(GeneralConstants.INJECTION_DATA_PATH);
+ RemoveReadOnlyAttribute(GeneralConstants.INJECTION_DATA_PATH + ".meta");
+
+ FileUtil.DeleteFileOrDirectory(GeneralConstants.INJECTION_DATA_PATH);
+ FileUtil.DeleteFileOrDirectory(GeneralConstants.INJECTION_DATA_PATH + ".meta");
+
+ RemoveDirectoryIfEmpty(GeneralConstants.RESOURCES_PATH);
+ AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
+ }
+
+ internal static string ResolveInjectionDefaultWhitelistPath()
+ {
+ return ResolveInjectionServiceFolder() + "/" + GeneralConstants.INJECTION_DEFAULT_WHITELIST_FILE;
+ }
+
+ internal static string ResolveInjectionUserWhitelistPath()
+ {
+ return ResolveInjectionServiceFolder() + "/" + GeneralConstants.INJECTION_USER_WHITELIST_FILE;
+ }
+
+ internal static string ResolveInjectionServiceFolder()
+ {
+ string result = "";
+ string[] targetFiles = Directory.GetDirectories(GeneralConstants.ASSETS_PATH, GeneralConstants.INJECTION_SERVICE_FOLDER, SearchOption.AllDirectories);
+ if (targetFiles.Length == 0)
+ {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Can't find " + GeneralConstants.INJECTION_SERVICE_FOLDER + " folder! Please report to " + GeneralStrings.REPORT_EMAIL);
+ }
+ else
+ {
+ result = targetFiles[0];
+ }
+
+ return result;
+ }
+
+ internal static string[] FindLibrariesAt(string dir)
+ {
+ string[] result = new string[0];
+
+ if (Directory.Exists(dir))
+ {
+ result = Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories);
+ for (int i = 0; i < result.Length; i++)
+ {
+ result[i] = result[i].Replace('\\', '/');
+ }
+ }
+
+ return result;
+ }
+
+ private static string PublicKeyTokenToString(byte[] bytes)
+ {
+ string result = "";
+
+ // AssemblyName.GetPublicKeyToken() returns 8 bytes
+ for (int i = 0; i < 8; i++)
+ {
+ result += hexTable[bytes[i]];
+ }
+
+ return result;
+ }
+
+ private static void RemoveDirectoryIfEmpty(string directoryName)
+ {
+ if (Directory.Exists(directoryName) && IsDirectoryEmpty(directoryName))
+ {
+ FileUtil.DeleteFileOrDirectory(directoryName);
+ if (File.Exists(Path.GetDirectoryName(directoryName) + ".meta"))
+ {
+ FileUtil.DeleteFileOrDirectory(Path.GetDirectoryName(directoryName) + ".meta");
+ }
+ }
+ }
+
+ private static bool IsDirectoryEmpty(string path)
+ {
+ string[] dirs = Directory.GetDirectories(path);
+ string[] files = Directory.GetFiles(path);
+ return dirs.Length == 0 && files.Length == 0;
+ }
+
+ internal static int GetAssemblyHash(AssemblyName ass)
+ {
+ string hashInfo = ass.Name;
+
+ byte[] bytes = ass.GetPublicKeyToken();
+ if (bytes != null && bytes.Length == 8)
+ {
+ hashInfo += PublicKeyTokenToString(bytes);
+ }
+
+ // Jenkins hash function (http://en.wikipedia.org/wiki/Jenkins_hash_function)
+ int result = 0;
+ int len = hashInfo.Length;
+
+ for (int 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;
+ }
+
+ internal static void RemoveReadOnlyAttribute(string path)
+ {
+ if (File.Exists(path))
+ {
+ FileAttributes attributes = File.GetAttributes(path);
+ if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
+ {
+ attributes = attributes & ~FileAttributes.ReadOnly;
+ File.SetAttributes(path, attributes);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/InjectionDetectorGlobal.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/InjectionDetectorGlobal.cs.meta
new file mode 100644
index 0000000..c34fac6
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/InjectionDetectorGlobal.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 295ad4c7b4a7408eb995eff75ecd7941
+timeCreated: 1710084079
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/Postprocessor.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/Postprocessor.cs
new file mode 100644
index 0000000..3311b7b
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/Postprocessor.cs
@@ -0,0 +1,290 @@
+#define DEBUG
+#undef DEBUG
+
+#define DEBUG_VERBOSE
+#undef DEBUG_VERBOSE
+
+#define DEBUG_PARANIOD
+#undef DEBUG_PARANIOD
+
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes;
+using UnityEditor;
+using UnityEditor.Callbacks;
+using UnityEngine;
+#if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ using System.Diagnostics;
+#endif
+
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ ///
+ /// Post-Processor for GameShield
+ ///
+ internal class Postprocessor : AssetPostprocessor
+ {
+ private static readonly List allowedAssemblies = new List();
+ private static readonly List allLibraries = new List();
+
+#if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ [MenuItem("GameShield/Injection Scanner/Force Collect Data", false, 45)]
+ private static void CallInjectionScan()
+ {
+ InjectionAssembliesScan(true);
+ }
+#endif
+ ///
+ /// Post Process Assets
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static void OnPostprocessAllAssets(String[] mportedAssets, String[] deletedAssets, String[] movedAssets, String[] movedFromAssetPaths)
+ {
+ if (deletedAssets.Length > 0)
+ {
+ foreach (string deletedAsset in deletedAssets)
+ {
+ if (deletedAsset.IndexOf(GeneralConstants.INJECTION_DATA_FILE) > -1 && !EditorApplication.isCompiling)
+ {
+#if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} Looks like Injection Detector data file was accidentally removed! Re-creating...");
+#endif
+ InjectionAssembliesScan();
+ }
+ }
+ }
+ }
+
+ [DidReloadScripts]
+ private static void ScriptsWereReloaded()
+ {
+ EditorUserBuildSettings.activeBuildTargetChanged += OnBuildTargetChanged;
+ InjectionAssembliesScan();
+ }
+
+ private static void OnBuildTargetChanged()
+ {
+ InjectionDetectorTargetCompatibleCheck();
+ }
+
+ internal static void InjectionAssembliesScan()
+ {
+ InjectionAssembliesScan(false);
+ }
+
+ internal static void InjectionAssembliesScan(bool forced)
+ {
+ if (!InjectionDetectorTargetCompatibleCheck() && !forced)
+ {
+ return;
+ }
+
+ #if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ Stopwatch sw = Stopwatch.StartNew();
+ #if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Injection Detector Assemblies Scan\n");
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Paths:\n" +
+
+ "Assets: " + GeneralConstants.ASSETS_PATH + "\n" +
+ "Assemblies: " + GeneralConstants.ASSEMBLIES_PATH + "\n" +
+ "Injection Detector Data: " + GeneralConstants.INJECTION_DATA_PATH);
+ sw.Start();
+ #endif
+ #endif
+
+#if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Looking for all assemblies in current project...");
+ sw.Start();
+#endif
+ allLibraries.Clear();
+ allowedAssemblies.Clear();
+
+ allLibraries.AddRange(InjectionDetectorGlobal.FindLibrariesAt(GeneralConstants.ASSETS_PATH));
+ allLibraries.AddRange(InjectionDetectorGlobal.FindLibrariesAt(GeneralConstants.ASSEMBLIES_PATH));
+#if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Total libraries found: " + allLibraries.Count);
+ sw.Start();
+#endif
+ const string editorSubdir = "/editor/";
+ string assembliesPathLowerCase = GeneralConstants.ASSEMBLIES_PATH_RELATIVE.ToLower();
+ foreach (string libraryPath in allLibraries)
+ {
+ string libraryPathLowerCase = libraryPath.ToLower();
+#if (DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Checking library at the path: " + libraryPathLowerCase);
+ sw.Start();
+#endif
+ if (libraryPathLowerCase.Contains(editorSubdir)) continue;
+ if (libraryPathLowerCase.Contains("-editor.dll") && libraryPathLowerCase.Contains(assembliesPathLowerCase)) continue;
+
+ try
+ {
+ AssemblyName assName = AssemblyName.GetAssemblyName(libraryPath);
+ string name = assName.Name;
+ int hash = InjectionDetectorGlobal.GetAssemblyHash(assName);
+
+ AllowedAssembly allowed = allowedAssemblies.FirstOrDefault(allowedAssembly => allowedAssembly.name == name);
+
+ if (allowed != null)
+ {
+ allowed.AddHash(hash);
+ }
+ else
+ {
+ allowed = new AllowedAssembly(name, new[] {hash});
+ allowedAssemblies.Add(allowed);
+ }
+ }
+ catch
+ {
+ // not a valid IL assembly, skipping
+ }
+ }
+
+#if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ string trace = "Found assemblies (" + allowedAssemblies.Count + "):\n";
+
+ foreach (AllowedAssembly allowedAssembly in allowedAssemblies)
+ {
+ trace += " Name: " + allowedAssembly.name + "\n";
+ trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n"));
+ }
+
+ Debug.Log(trace);
+ sw.Start();
+#endif
+ if (!Directory.Exists(GeneralConstants.RESOURCES_PATH))
+ {
+#if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Creating resources folder: " + GeneralConstants.RESOURCES_PATH);
+ sw.Start();
+#endif
+ Directory.CreateDirectory(GeneralConstants.RESOURCES_PATH);
+ }
+
+ InjectionDetectorGlobal.RemoveReadOnlyAttribute(GeneralConstants.INJECTION_DATA_PATH);
+ BinaryWriter bw = new BinaryWriter(new FileStream(GeneralConstants.INJECTION_DATA_PATH, FileMode.Create, FileAccess.Write, FileShare.Read));
+ int allowedAssembliesCount = allowedAssemblies.Count;
+
+ int totalWhitelistedAssemblies = 0;
+
+ #if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Processing default whitelist");
+ sw.Start();
+ #endif
+
+ string defaultWhitelistPath = InjectionDetectorGlobal.ResolveInjectionDefaultWhitelistPath();
+ if (File.Exists(defaultWhitelistPath))
+ {
+ BinaryReader br = new BinaryReader(new FileStream(defaultWhitelistPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
+ int assembliesCount = br.ReadInt32();
+ totalWhitelistedAssemblies = assembliesCount + allowedAssembliesCount;
+
+ bw.Write(totalWhitelistedAssemblies);
+
+ for (int i = 0; i < assembliesCount; i++)
+ {
+ bw.Write(br.ReadString());
+ }
+ br.Close();
+ }
+ else
+ {
+ #if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ #endif
+ bw.Close();
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Can't find " + GeneralConstants.INJECTION_DEFAULT_WHITELIST_FILE + " file!\nPlease, report to " + GeneralStrings.REPORT_EMAIL);
+ return;
+ }
+
+ #if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Processing user whitelist");
+ sw.Start();
+ #endif
+
+ string userWhitelistPath = InjectionDetectorGlobal.ResolveInjectionUserWhitelistPath();
+ if (File.Exists(userWhitelistPath))
+ {
+ BinaryReader br = new BinaryReader(new FileStream(userWhitelistPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
+ int assembliesCount = br.ReadInt32();
+
+ bw.Seek(0, SeekOrigin.Begin);
+ bw.Write(totalWhitelistedAssemblies + assembliesCount);
+ bw.Seek(0, SeekOrigin.End);
+ for (int i = 0; i < assembliesCount; i++)
+ {
+ bw.Write(br.ReadString());
+ }
+ br.Close();
+ }
+
+ #if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Processing project assemblies");
+ sw.Start();
+ #endif
+
+ for (int i = 0; i < allowedAssembliesCount; i++)
+ {
+ AllowedAssembly assembly = allowedAssemblies[i];
+ string name = assembly.name;
+ string hashes = "";
+
+ for (int j = 0; j < assembly.hashes.Length; j++)
+ {
+ hashes += assembly.hashes[j];
+ if (j < assembly.hashes.Length - 1)
+ {
+ hashes += GeneralConstants.INJECTION_DATA_SEPARATOR;
+ }
+ }
+
+ string line = SecuredString.EncryptDecrypt(name + GeneralConstants.INJECTION_DATA_SEPARATOR + hashes, "GAMESHIELD");
+
+ #if (DEBUG_VERBOSE || DEBUG_PARANIOD)
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Writing assembly:\n" + name + GeneralConstants.INJECTION_DATA_SEPARATOR + hashes);
+ #endif
+ bw.Write(line);
+ }
+
+ bw.Close();
+ #if (DEBUG || DEBUG_VERBOSE || DEBUG_PARANIOD)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Assemblies scan duration: " + sw.ElapsedMilliseconds + " ms.");
+ #endif
+
+ if (allowedAssembliesCount == 0)
+ {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Can't find any assemblies!\nPlease, report to " + GeneralStrings.REPORT_EMAIL);
+ }
+
+ AssetDatabase.Refresh();
+ }
+
+ private static bool InjectionDetectorTargetCompatibleCheck()
+ {
+#if UNITY_STANDALONE || UNITY_WEBPLAYER || UNITY_IPHONE || UNITY_ANDROID
+ return true;
+#else
+ return false;
+#endif
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/Postprocessor.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/Postprocessor.cs.meta
new file mode 100644
index 0000000..9b3be11
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/Postprocessor.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c956332624184a29a40b98acedc67bb0
+timeCreated: 1710081775
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData.meta
new file mode 100644
index 0000000..7a7606b
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5cefdc3bd3ed46d7b07ee47b95180806
+timeCreated: 1710084375
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData.meta
new file mode 100644
index 0000000..281e0d1
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 45ad953cc77246109eb7b283bf302521
+timeCreated: 1710084396
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData/DefaultWhitelist.gsa b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData/DefaultWhitelist.gsa
new file mode 100644
index 0000000..df0eb75
Binary files /dev/null and b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData/DefaultWhitelist.gsa differ
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData/DefaultWhitelist.gsa.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData/DefaultWhitelist.gsa.meta
new file mode 100644
index 0000000..b4ad7f1
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/ServiceData/InjectionDetectorData/DefaultWhitelist.gsa.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: cbfb1a1d4970ec145a4d36a491d10859
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/WizzardTab.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/WizzardTab.cs
new file mode 100644
index 0000000..3ba5d9e
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/WizzardTab.cs
@@ -0,0 +1,12 @@
+namespace DevsDaddy.GameShield.Core.Editor
+{
+ ///
+ /// Setup Wizzard Tabs
+ ///
+ public enum WizzardTab
+ {
+ Welcome,
+ GeneralSetup,
+ Complete
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/WizzardTab.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/WizzardTab.cs.meta
new file mode 100644
index 0000000..b5bb4c0
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Editor/WizzardTab.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: ef90ec6f48424173ae4b4567140b70f0
+timeCreated: 1709983217
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShield.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShield.cs
new file mode 100644
index 0000000..cf18535
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShield.cs
@@ -0,0 +1,353 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Modules;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.GameShield.Core.Reporter;
+using DevsDaddy.GameShield.Core.Utils;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core
+{
+ ///
+ /// Game Shield Worker Class
+ /// Used for Modules initialization and provide
+ /// MonoBased Events
+ ///
+ [DisallowMultipleComponent]
+ public class GameShield : MonoBehaviour
+ {
+ // GameShield General Instance
+ public static GameShield Main { get; private set; }
+ private static GameShield _main = null;
+
+ // States Flag
+ private bool isQuitting = false;
+ private bool isPaused = false;
+ private GameShieldConfig currentConfig = null;
+
+ // Loaded Modules
+ private List loadedModules = new List();
+ private readonly Dictionary currentCoroutines = new Dictionary();
+
+ ///
+ /// On GameShield Worker Awake
+ ///
+ private void Awake() {
+ if (Main != null && Main != this) {
+ Destroy(this);
+ return;
+ }
+
+ Main = this;
+ transform.SetParent(null);
+ DontDestroyOnLoad(this);
+ gameObject.name = GeneralConstants.WORKER_OBJECT_NAME;
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Worker Awake");
+ }
+
+ ///
+ /// On GameShield Worker Start
+ ///
+ private void Start() {
+ // Get Configs
+ LoadConfig();
+
+ // Application Started Event
+ EventMessenger.Main.Subscribe(OnRequestCoroutine);
+ EventMessenger.Main.Subscribe(OnStopCoroutine);
+ EventMessenger.Main.Subscribe(ProcessReportingWorker);
+ EventMessenger.Main.Publish(new ApplicationStartedPayload {
+ Time = DateTime.Now
+ });
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Worker Started");
+ }
+
+ ///
+ /// On Update
+ ///
+ private void Update() {
+ if(isPaused || isQuitting) return;
+ EventMessenger.Main.Publish(new ApplicationLoopUpdated {
+ DeltaTime = Time.deltaTime
+ });
+ }
+
+ ///
+ /// On Fixed Update
+ ///
+ private void FixedUpdate() {
+ if(isPaused || isQuitting) return;
+ EventMessenger.Main.Publish(new ApplicationFixedLoopUpdated {
+ DeltaTime = Time.fixedDeltaTime
+ });
+ }
+
+ ///
+ /// Application is lost/has focused
+ ///
+ ///
+ private void OnApplicationFocus(bool hasFocus) {
+ isPaused = !hasFocus;
+ EventMessenger.Main.Publish(new ApplicationPausePayload {
+ IsPaused = isPaused,
+ Time = DateTime.Now
+ });
+ }
+
+ ///
+ /// On Instance Destroying
+ ///
+ private void OnDestroy() {
+ EventMessenger.Main.Unsubscribe(OnRequestCoroutine);
+ EventMessenger.Main.Unsubscribe(OnStopCoroutine);
+ EventMessenger.Main.Unsubscribe(ProcessReportingWorker);
+ EventMessenger.Main.Publish(new ApplicationClosePayload {
+ IsQuitting = isQuitting,
+ Time = DateTime.Now
+ });
+ }
+
+ ///
+ /// On Application Quit
+ ///
+ private void OnApplicationQuit() {
+ RemoveAllCoroutines();
+ isQuitting = true;
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Application Quit Process.");
+ }
+
+ ///
+ /// Add Game Shield Module
+ ///
+ ///
+ ///
+ public T AddModule(IShieldModuleConfig config = null) where T : class, IShieldModule, new() {
+ T module = (T)loadedModules.Find(mod => mod.GetType() == typeof(T));
+ if (module != null) return module;
+
+ // Create Module
+ module = new T();
+ module.SetupModule(config);
+ loadedModules.Add(module);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Manual Module added: {module.GetType().Name}");
+ return module;
+ }
+
+ ///
+ /// Add Game Shield Module by Name
+ ///
+ ///
+ ///
+ ///
+ public IShieldModule AddModule(string moduleType, IShieldModuleConfig config = null) {
+ IShieldModule found = loadedModules.Find(mod => mod.GetType().Name == moduleType);
+ if (found != null) return found;
+
+ // Create Module by Name
+ Type mType = ModuleManager.ByName(moduleType);
+ if (mType == null) {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Failed to Initialize Module {moduleType}. Type is not found");
+ return null;
+ }
+ IShieldModule newModule = (IShieldModule)Activator.CreateInstance(mType);
+ newModule.SetupModule();
+ loadedModules.Add(newModule);
+ return null;
+ }
+
+ ///
+ /// Get Game Shield Module
+ ///
+ ///
+ ///
+ public T GetModule() where T : class, IShieldModule {
+ return (T)loadedModules.Find(mod => mod.GetType() == typeof(T));
+ }
+
+ ///
+ /// Remove Game Shield Module
+ ///
+ ///
+ public bool RemoveModule() where T : class, IShieldModule {
+ T module = (T)loadedModules.Find(mod => mod.GetType() == typeof(T));
+ if (module == null) return false;
+ module.Disconnect();
+ loadedModules.Remove(module);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Module Removed: {module.GetType().Name}");
+ return true;
+ }
+
+ ///
+ /// Remove All Modules
+ ///
+ public void RemoveAllModules() {
+ foreach (var module in loadedModules) {
+ module.Disconnect();
+ }
+
+ loadedModules.Clear();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} All Modules Removed.");
+ }
+
+ ///
+ /// Get Developer Key
+ ///
+ ///
+ public string GetDeveloperKey() {
+ return currentConfig.DeveloperKey;
+ }
+
+ ///
+ /// Get Backend Url
+ ///
+ ///
+ public string GetBackendUrl() {
+ return currentConfig.BackendURL;
+ }
+
+ ///
+ /// Pause All Modules
+ ///
+ public void PauseAllModules() {
+ ToggleAllModulesDetection(true);
+ }
+
+ ///
+ /// Unpause / Start All Modules
+ ///
+ public void StartAllModules() {
+ ToggleAllModulesDetection(false);
+ }
+
+ ///
+ /// Toggle All Modules Pause
+ ///
+ ///
+ public void ToggleAllModulesDetection(bool isModulePaused) {
+ loadedModules.ForEach(module => {
+ module.PauseDetector(isModulePaused);
+ });
+ }
+
+ ///
+ /// Get Paused Detectors Count
+ ///
+ ///
+ public int GetPausedDetectorsCount() {
+ int pausedCount = 0;
+ loadedModules.ForEach(module => {
+ if (module.IsPaused()) pausedCount++;
+ });
+ return pausedCount;
+ }
+
+ ///
+ /// On Coroutine Requested
+ ///
+ ///
+ private void OnRequestCoroutine(RequestCoroutine payload) {
+ if (currentCoroutines.ContainsKey(payload.Id)) {
+ StopCoroutine(currentCoroutines[payload.Id]);
+ currentCoroutines[payload.Id] = payload.Coroutine;
+ }
+ else {
+ currentCoroutines.Add(payload.Id, payload.Coroutine);
+ }
+
+ StartCoroutine(currentCoroutines[payload.Id]);
+ }
+
+ ///
+ /// On Stop Coroutine Requested
+ ///
+ ///
+ private void OnStopCoroutine(StopCoroutine payload) {
+ if (!currentCoroutines.ContainsKey(payload.Id))
+ return;
+
+ StopCoroutine(currentCoroutines[payload.Id]);
+ }
+
+ ///
+ /// Remove All Coroutines
+ ///
+ private void RemoveAllCoroutines() {
+ currentCoroutines.Clear();
+ StopAllCoroutines();
+ }
+
+ ///
+ /// Process Reporting Payload
+ ///
+ ///
+ private void ProcessReportingWorker(ReportingPayload payload) {
+ if (payload.Data == null) {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Failed to Process Reporting. Reporting Data is Empty");
+ return;
+ }
+
+ // Send Report
+ ReporterWorker.Send(payload.Data, payload.OnComplete, payload.OnError);
+ }
+
+ ///
+ /// Load Configuration
+ ///
+ ///
+ ///
+ public void LoadConfig(GameShieldConfig config, bool cleanupModules = false) {
+ if (currentConfig != null && cleanupModules) {
+ RemoveAllModules();
+ }
+
+ currentConfig = config;
+ if (currentConfig.AvailableModules.Count > 0) {
+ foreach (var module in currentConfig.AvailableModules) {
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Trying to Auto-Initialize Module: {module}");
+ AddModule(module);
+ }
+ }
+
+ // Auto-Pause for Application Terminated
+ if (currentConfig.PauseOnApplicationTerminated && loadedModules.Count > 0) {
+ EventMessenger.Main.Subscribe(payload => {
+ foreach (var module in loadedModules) {
+ module.PauseDetector(payload.IsPaused);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Toggle Pause for Module: {module}, In-State: {payload.IsPaused}");
+ }
+ });
+ }
+ }
+
+ ///
+ /// Load Configuration
+ ///
+ private void LoadConfig() {
+ // Load Configuration
+ GameShieldConfig config = Resources.Load(GeneralConstants.CONFIG_PATH);
+ currentConfig = config ? config : ScriptableObject.CreateInstance();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Configuration Loaded. Available Modules: {currentConfig.AvailableModules.Count}");
+
+ // Initialize Modules
+ if (currentConfig.AvailableModules.Count > 0) {
+ foreach (var module in currentConfig.AvailableModules) {
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Trying to Auto-Initialize Module: {module}");
+ AddModule(module);
+ }
+ }
+
+ // Auto-Pause for Application Terminated
+ if (currentConfig.PauseOnApplicationTerminated && loadedModules.Count > 0) {
+ EventMessenger.Main.Subscribe(payload => {
+ foreach (var module in loadedModules) {
+ module.PauseDetector(payload.IsPaused);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Toggle Pause for Module: {module}, In-State: {payload.IsPaused}");
+ }
+ });
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShield.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShield.cs.meta
new file mode 100644
index 0000000..2aca064
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShield.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f05d3eb23171492a86a7f158566152f0
+timeCreated: 1709921129
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShieldConfig.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShieldConfig.cs
new file mode 100644
index 0000000..e76c924
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShieldConfig.cs
@@ -0,0 +1,26 @@
+using System.Collections.Generic;
+using DevsDaddy.GameShield.Core.Modules;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core
+{
+ [System.Serializable]
+ [CreateAssetMenu(fileName = "GameShieldConfig", menuName = "GameShield/Config/General", order = 0)]
+ public class GameShieldConfig : ScriptableObject
+ {
+ public int ConfigRevision = 0;
+ public List AvailableModules = new List();
+
+ public bool PauseOnApplicationTerminated = false;
+ public string DeveloperKey = "";
+ public string BackendURL = "";
+ public DeveloperContacts Contacts = new DeveloperContacts();
+ }
+
+ [System.Serializable]
+ public class DeveloperContacts
+ {
+ public string Email = "";
+ public string Website = "";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShieldConfig.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShieldConfig.cs.meta
new file mode 100644
index 0000000..1338433
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/GameShieldConfig.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6d97d9ba471946eb831b3dea61bea50c
+timeCreated: 1709969547
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules.meta
new file mode 100644
index 0000000..891abff
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 8a9a9bc20ae04523a56314b8525dbe2d
+timeCreated: 1709921108
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha.meta
new file mode 100644
index 0000000..d6ab5b6
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 454f4cb55ad9477db6e2d92a785a6c79
+timeCreated: 1710016871
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RequestCaptchaPayload.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RequestCaptchaPayload.cs
new file mode 100644
index 0000000..87bc098
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RequestCaptchaPayload.cs
@@ -0,0 +1,18 @@
+using System;
+using DevsDaddy.Shared.EventFramework.Core.Payloads;
+
+namespace DevsDaddy.GameShield.Core.Modules.Captcha
+{
+ ///
+ /// Request Captcha Payload
+ ///
+ [System.Serializable]
+ public class RequestCaptchaPayload : IPayload
+ {
+ public int NumOfImages;
+
+ public Action OnComplete;
+ public Action OnError;
+ public Action OnCanceled;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RequestCaptchaPayload.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RequestCaptchaPayload.cs.meta
new file mode 100644
index 0000000..f61ee8c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RequestCaptchaPayload.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 0cec48f5b0bb40eda2488e85f5164760
+timeCreated: 1712760881
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptcha.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptcha.cs
new file mode 100644
index 0000000..52cc909
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptcha.cs
@@ -0,0 +1,165 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.GameShield.Core.Utils;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+using Random = System.Random;
+
+namespace DevsDaddy.GameShield.Core.Modules.Captcha
+{
+ ///
+ /// Rewarded Captcha Module
+ ///
+ public class RewardedCaptcha : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ private RewardedCaptchaData currentData;
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ // Fire Disconnected Complete
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ // Fire Initialization Complete
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Generate Captcha Data
+ ///
+ ///
+ ///
+ ///
+ public RewardedCaptchaData GenerateCaptchaData(RequestCaptchaPayload payload, int availableSpritesCount) {
+ // Check Sizes
+ if (payload.NumOfImages > availableSpritesCount) {
+ Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} Number of Required images is larger than available sprites count in captcha.");
+ payload.NumOfImages = availableSpritesCount;
+ }
+
+ // Current Data
+ currentData = new RewardedCaptchaData {
+ RequiredOrder = new int[payload.NumOfImages],
+ CurrentFieldOrder = new int[payload.NumOfImages]
+ };
+
+ // Generate Required List
+ currentData.RequiredOrder =
+ Generator.GenerateUniqueRandomRange(0, availableSpritesCount - 1, payload.NumOfImages);
+
+ // Shuffle Order for Clicks
+ var rnd = new Random();
+ currentData.CurrentFieldOrder = currentData.RequiredOrder.Select(x => (x, rnd.Next()))
+ .OrderBy(tuple => tuple.Item2)
+ .Select(tuple => tuple.Item1)
+ .ToArray();
+ return currentData;
+ }
+
+ ///
+ /// Get Captcha Data
+ ///
+ ///
+ public RewardedCaptchaData GetData() {
+ return currentData;
+ }
+
+ ///
+ /// Check if is right clicking order
+ ///
+ ///
+ ///
+ public bool IsRightOrder(List providedOrder) {
+ // Check Length
+ if (providedOrder.Count != currentData.RequiredOrder.Length) {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Failed to check captcha order. Provided order length must be equal of current required order length");
+ return false;
+ }
+
+ // Check Values
+ bool isRight = true;
+ for (int i = 0; i < providedOrder.Count; i++) {
+ if (providedOrder[i] != currentData.RequiredOrder[i]) {
+ isRight = false;
+ break;
+ }
+ }
+
+ return isRight;
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Rewarded Captcha",
+ Description = "This module allows you to create client-side captchas when you suspect player cheating with a reward for completion.",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#rewarded-captcha"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig { }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptcha.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptcha.cs.meta
new file mode 100644
index 0000000..aa3c2c8
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptcha.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: af4a33fe1db64838908286af345857cb
+timeCreated: 1710017774
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptchaData.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptchaData.cs
new file mode 100644
index 0000000..7c23591
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptchaData.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace DevsDaddy.GameShield.Core.Modules.Captcha
+{
+ [System.Serializable]
+ public class RewardedCaptchaData
+ {
+ public int[] RequiredOrder;
+ public int[] CurrentFieldOrder;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptchaData.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptchaData.cs.meta
new file mode 100644
index 0000000..808f952
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Captcha/RewardedCaptchaData.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e1098f1a657342ad9d14e20c978d9a64
+timeCreated: 1712816572
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves.meta
new file mode 100644
index 0000000..05e2560
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 563e79d6f3744de4a7b2889c48208b24
+timeCreated: 1710016878
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/ISaveObject.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/ISaveObject.cs
new file mode 100644
index 0000000..5db69e4
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/ISaveObject.cs
@@ -0,0 +1,7 @@
+namespace DevsDaddy.GameShield.Core.Modules.GameSaves
+{
+ ///
+ /// Game Save Interface
+ ///
+ public interface ISaveObject { }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/ISaveObject.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/ISaveObject.cs.meta
new file mode 100644
index 0000000..644d514
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/ISaveObject.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 885d9a7d7f5844ab971c84408514a2ef
+timeCreated: 1710070787
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads.meta
new file mode 100644
index 0000000..d289cf3
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: d4f098b911a84c2d872d12a04a67900d
+timeCreated: 1710070652
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads/SaveGamePayloads.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads/SaveGamePayloads.cs
new file mode 100644
index 0000000..9f86b1d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads/SaveGamePayloads.cs
@@ -0,0 +1,26 @@
+using System;
+using DevsDaddy.Shared.EventFramework.Core.Payloads;
+
+namespace DevsDaddy.GameShield.Core.Modules.GameSaves.Payloads
+{
+ ///
+ /// Save Game Request
+ ///
+ [System.Serializable]
+ public class SaveGamePayload : IPayload
+ {
+ public string Path = "";
+ public ISaveObject Object;
+ public Action OnComplete;
+ }
+
+ ///
+ /// Load Game Request
+ ///
+ [System.Serializable]
+ public class LoadGamePayload : IPayload
+ {
+ public string Path = "";
+ public Action OnComplete;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads/SaveGamePayloads.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads/SaveGamePayloads.cs.meta
new file mode 100644
index 0000000..a02580e
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/Payloads/SaveGamePayloads.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e14877b2bfc542f2aa46c9a1c80c5eea
+timeCreated: 1710070662
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SaveGameData.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SaveGameData.cs
new file mode 100644
index 0000000..2cdbc2f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SaveGameData.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace DevsDaddy.GameShield.Core.Modules.GameSaves
+{
+ [System.Serializable]
+ public class SaveGameData : ISaveObject
+ {
+ public DateTime Date = DateTime.Now;
+ public ISaveObject Object;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SaveGameData.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SaveGameData.cs.meta
new file mode 100644
index 0000000..0e2dab8
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SaveGameData.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: df69e6efc1854e13ab4c375e472e8f80
+timeCreated: 1710070987
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SavesWarnings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SavesWarnings.cs
new file mode 100644
index 0000000..dd2f5a2
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SavesWarnings.cs
@@ -0,0 +1,8 @@
+namespace DevsDaddy.GameShield.Core.Modules.GameSaves
+{
+ public static class SavesWarnings
+ {
+ public const string NO_DATA_FOUND_IN_SAVES =
+ "Failed to get save game data for this file. Please, try another save file";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SavesWarnings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SavesWarnings.cs.meta
new file mode 100644
index 0000000..fe2cd7d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SavesWarnings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 854013dc1e604884a4bf486737d7d632
+timeCreated: 1710071865
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SecuredSaves.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SecuredSaves.cs
new file mode 100644
index 0000000..6bcfa54
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SecuredSaves.cs
@@ -0,0 +1,228 @@
+using System;
+using System.IO;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Modules.GameSaves.Payloads;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.CryptoLibrary;
+using DevsDaddy.Shared.CryptoLibrary.Core;
+using DevsDaddy.Shared.CryptoLibrary.Modules.AES;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.GameSaves
+{
+ ///
+ /// Secured Game Saves Module
+ ///
+ public class SecuredSaves : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ private ICryptoProvider _currentProvider = null;
+ private SaveGameData _currentSave = null;
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ _currentProvider = _currentOptions.Provider;
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ // Unsubscribe from payloads
+ EventMessenger.Main.Unsubscribe(OnSaveRequested);
+ EventMessenger.Main.Unsubscribe(OnLoadGameRequested);
+
+ // Fire Disconnected Complete
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ // Subscribe to Payloads
+ EventMessenger.Main.Subscribe(OnSaveRequested);
+ EventMessenger.Main.Subscribe(OnLoadGameRequested);
+
+ // Fire Initialization Complete
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Save Game Requested
+ ///
+ ///
+ private void OnSaveRequested(SaveGamePayload payload) {
+ SaveGame(payload.Path, payload.Object, payload.OnComplete);
+ }
+
+ ///
+ /// Load Game Requested
+ ///
+ ///
+ private void OnLoadGameRequested(LoadGamePayload payload) {
+ LoadGame(payload.Path, (saveData, saveObject) => {
+ payload.OnComplete?.Invoke(saveData, saveObject);
+ });
+ }
+
+ ///
+ /// Save Game
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void SaveGame(string path, T saveObject, Action onComplete = null, Action onError = null) {
+ // Create Save Data
+ SaveGameData data = new SaveGameData {
+ Date = DateTime.Now,
+ Object = (ISaveObject)saveObject
+ };
+
+ // Convert to JSON and Save
+ string jsonData = JsonUtility.ToJson(data);
+ bool encryptedFile = CryptoFile.WriteText(path, jsonData, _currentProvider);
+ if (!encryptedFile) {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Error thrown at game saving process");
+ onError?.Invoke(SavesWarnings.NO_DATA_FOUND_IN_SAVES);
+ return;
+ }
+
+ // Complete Save
+ onComplete?.Invoke();
+ }
+
+ ///
+ /// Load Game
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void LoadGame(string path, Action onComplete = null, Action onError = null) where T : ISaveObject{
+ if(!HasSave(path)) return;
+
+ // Load and Decrypt Save File
+ string decryptedData = CryptoFile.ReadText(path, _currentProvider);
+ if (string.IsNullOrEmpty(decryptedData)) {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Load Game Error: {SavesWarnings.NO_DATA_FOUND_IN_SAVES}");
+ onError?.Invoke(SavesWarnings.NO_DATA_FOUND_IN_SAVES);
+ return;
+ }
+
+ // Parse Save Data
+ SaveGameData data = JsonUtility.FromJson(decryptedData);
+ if (data == null) {
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX} Load Game Error: {SavesWarnings.NO_DATA_FOUND_IN_SAVES}");
+ onError?.Invoke(SavesWarnings.NO_DATA_FOUND_IN_SAVES);
+ return;
+ }
+
+ _currentSave = data;
+ onComplete?.Invoke(data, (T)data.Object);
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Load Game Complete: {path}");
+ }
+
+ ///
+ /// Get Latest Save
+ ///
+ ///
+ public SaveGameData GetLatestSave() {
+ return _currentSave;
+ }
+
+ ///
+ /// Check Game Save Exists
+ ///
+ ///
+ ///
+ public bool HasSave(string path) {
+ return File.Exists(path);
+ }
+
+ ///
+ /// Set Crypto Provider
+ ///
+ ///
+ public void SetCryptoProvider(ICryptoProvider provider) {
+ if(_currentProvider == null || provider != _currentProvider)
+ _currentProvider = provider;
+ }
+
+ ///
+ /// Get Crypto Provider
+ ///
+ ///
+ ///
+ public ICryptoProvider GetCryptoProvider() {
+ return _currentProvider;
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Secured Saves",
+ Description = "This module allows you to save game states simply and quickly by encrypted serialization/deserialization of save files.",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#secured-saves"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+ public ICryptoProvider Provider = new AESProvider(new AESEncryptionOptions {
+ cryptoKey = GameShield.Main.GetDeveloperKey()
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SecuredSaves.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SecuredSaves.cs.meta
new file mode 100644
index 0000000..09912fb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/GameSaves/SecuredSaves.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6e64383818314081b0060f0a886fd595
+timeCreated: 1710017659
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModule.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModule.cs
new file mode 100644
index 0000000..a46a29a
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModule.cs
@@ -0,0 +1,35 @@
+namespace DevsDaddy.GameShield.Core.Modules
+{
+ public interface IShieldModule
+ {
+ ///
+ /// Setup Module Configuration
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false);
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect();
+
+ ///
+ /// Pause Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused);
+
+ ///
+ /// Is Paused
+ ///
+ ///
+ public bool IsPaused();
+
+ ///
+ /// Get Module Info
+ ///
+ ///
+ public ModuleInfo GetModuleInfo();
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModule.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModule.cs.meta
new file mode 100644
index 0000000..213242c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModule.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 213634e4aff34bee93af6a49a84ecae2
+timeCreated: 1709969453
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModuleConfig.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModuleConfig.cs
new file mode 100644
index 0000000..f730e1d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModuleConfig.cs
@@ -0,0 +1,4 @@
+namespace DevsDaddy.GameShield.Core.Modules
+{
+ public interface IShieldModuleConfig { }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModuleConfig.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModuleConfig.cs.meta
new file mode 100644
index 0000000..2257a51
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/IShieldModuleConfig.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6c87f7f5095948fea55dd12588ef0e96
+timeCreated: 1709981804
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection.meta
new file mode 100644
index 0000000..741a247
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b7852654c94a406b9c2b9247aab63254
+timeCreated: 1710016780
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/AllowedAssembly.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/AllowedAssembly.cs
new file mode 100644
index 0000000..5ce4d37
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/AllowedAssembly.cs
@@ -0,0 +1,17 @@
+namespace DevsDaddy.GameShield.Core.Modules.Injection
+{
+ ///
+ /// Allowed Assembly Class
+ ///
+ public class AllowedAssembly
+ {
+ public readonly string name;
+ public readonly int[] hashes;
+
+ public AllowedAssembly(string name, int[] hashes)
+ {
+ this.name = name;
+ this.hashes = hashes;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/AllowedAssembly.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/AllowedAssembly.cs.meta
new file mode 100644
index 0000000..35e100b
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/AllowedAssembly.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: ce2ecfbf767a497483212c64b13494f8
+timeCreated: 1710081274
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionScanner.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionScanner.cs
new file mode 100644
index 0000000..2d970fe
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionScanner.cs
@@ -0,0 +1,470 @@
+#define DEBUG
+#undef DEBUG
+
+#define DEBUG_VERBOSE
+#undef DEBUG_VERBOSE
+
+#define DEBUG_PARANOID
+#undef DEBUG_PARANOID
+
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+using System.IO;
+using System.Reflection;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes;
+using UnityEngine;
+using Debug = UnityEngine.Debug;
+
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+using System.Diagnostics;
+#endif
+
+namespace DevsDaddy.GameShield.Core.Modules.Injection
+{
+ ///
+ /// Injection Scanner Module
+ ///
+ public class InjectionScanner : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ // Private Params
+ private bool m_SignaturesAreNotGenuine;
+ private AllowedAssembly[] m_AllowedAssemblies = null;
+ private string[] m_HexTable;
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ #if !UNITY_STANDALONE && !UNITY_WEBPLAYER && !UNITY_IPHONE && !UNITY_ANDROID
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX}Injection Scanner is not supported on selected platform!");
+ return;
+ #endif
+
+ #if UNITY_EDITOR
+ #if !DEBUG && !DEBUG_VERBOSE && !DEBUG_PARANOID
+ if (Application.isEditor)
+ {
+ Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} Injection Detection does not work in editor (check readme for details).");
+ return;
+ }
+ #else
+ Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} Injection Scanner works in debug mode. There WILL BE false positives in editor, it's fine!");
+ #endif
+ #endif
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+#if !UNITY_STANDALONE && !UNITY_WEBPLAYER && !UNITY_IPHONE && !UNITY_ANDROID
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX}Injection Scanner is not supported on selected platform!");
+ return;
+#endif
+
+ AppDomain.CurrentDomain.AssemblyLoad -= OnNewAssemblyLoaded;
+ _isPaused = true;
+
+ // Fire Disconnected Complete
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+#if !UNITY_STANDALONE && !UNITY_WEBPLAYER && !UNITY_IPHONE && !UNITY_ANDROID
+ Debug.LogError($"{GeneralStrings.LOG_PREFIX}Injection Scanner is not supported on selected platform!");
+ return;
+#endif
+
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+
+ if (_isPaused) {
+ AppDomain.CurrentDomain.AssemblyLoad -= OnNewAssemblyLoaded;
+ }
+ else {
+ AppDomain.CurrentDomain.AssemblyLoad += OnNewAssemblyLoaded;
+ }
+
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ // Load Allowed Assemblies
+ if (m_AllowedAssemblies == null)
+ {
+ LoadAndParseAllowedAssemblies();
+ }
+
+ // Check Signatures
+ if (m_SignaturesAreNotGenuine)
+ {
+ OnInjectionDetected();
+ return;
+ }
+
+ // Find Injections
+ if (!FindInjectionInCurrentAssemblies())
+ {
+ // listening for new assemblies
+ AppDomain.CurrentDomain.AssemblyLoad += OnNewAssemblyLoaded;
+ _isPaused = false;
+ }
+ else
+ {
+ OnInjectionDetected();
+ }
+
+ // Fire Initialization Complete
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// On Injection Detected
+ ///
+ private void OnInjectionDetected()
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = InjectionWarnings.InjectionDetected,
+ IsCritical = true,
+ Module = this
+ });
+ PauseDetector(true);
+ }
+
+ ///
+ /// New Assembly Loaded
+ ///
+ ///
+ ///
+ private void OnNewAssemblyLoaded(object sender, AssemblyLoadEventArgs args)
+ {
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} New assembly loaded: {args.LoadedAssembly.FullName}");
+#endif
+
+ if (!AssemblyAllowed(args.LoadedAssembly))
+ {
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Injected Assembly found:\n {args.LoadedAssembly.FullName}" );
+#endif
+ OnInjectionDetected();
+ }
+ }
+
+ ///
+ /// Find Injection in Current Assemblies
+ ///
+ ///
+ private bool FindInjectionInCurrentAssemblies()
+ {
+ bool result = false;
+
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ Stopwatch stopwatch = Stopwatch.StartNew();
+#endif
+
+ Assembly[] assembliesInCurrentDomain = AppDomain.CurrentDomain.GetAssemblies();
+ if (assembliesInCurrentDomain.Length == 0)
+ {
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ stopwatch.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} 0 assemblies in current domain! Not genuine behavior.");
+ stopwatch.Start();
+#endif
+ result = true;
+ }else
+ {
+ foreach (Assembly ass in assembliesInCurrentDomain)
+ {
+#if DEBUG_VERBOSE
+ stopwatch.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Currenly loaded assembly:\n {ass.FullName}");
+ stopwatch.Start();
+#endif
+
+ if (!AssemblyAllowed(ass))
+ {
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ stopwatch.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Injected Assembly found:\n {ass.FullName} \n {GetAssemblyHash(ass)}");
+ stopwatch.Start();
+#endif
+
+ result = true;
+ break;
+ }
+ }
+ }
+
+#if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ stopwatch.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Loaded assemblies scan duration: {stopwatch.ElapsedMilliseconds} ms.");
+#endif
+
+ return result;
+ }
+
+ ///
+ /// Allowed Assembly
+ ///
+ ///
+ ///
+ private bool AssemblyAllowed(Assembly ass) {
+ if (!_initialized) return false;
+#if !UNITY_WEBPLAYER
+ string assemblyName = ass.GetName().Name;
+#else
+ string fullname = ass.FullName;
+ string assemblyName = fullname.Substring(0, fullname.IndexOf(", ", StringComparison.Ordinal));
+#endif
+
+ int hash = GetAssemblyHash(ass);
+
+ bool result = false;
+ if (m_AllowedAssemblies == null) return false;
+ for (int i = 0; i < m_AllowedAssemblies.Length; i++)
+ {
+ AllowedAssembly allowedAssembly = m_AllowedAssemblies[i];
+
+ if (allowedAssembly.name == assemblyName)
+ {
+ if (Array.IndexOf(allowedAssembly.hashes, hash) != -1)
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ ///
+ /// Load and Parse Allowed Assemblies
+ ///
+ private void LoadAndParseAllowedAssemblies()
+ {
+ #if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Starting LoadAndParseAllowedAssemblies()");
+ Stopwatch sw = Stopwatch.StartNew();
+ #endif
+
+ TextAsset assembliesSignatures = (TextAsset)Resources.Load(GeneralConstants.ASSMDB_PATH, typeof(TextAsset));
+ if (assembliesSignatures == null)
+ {
+ m_SignaturesAreNotGenuine = true;
+ return;
+ }
+
+ #if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Creating separator array and opening MemoryStream");
+ sw.Start();
+ #endif
+
+ string[] separator = {":"};
+
+ MemoryStream ms = new MemoryStream(assembliesSignatures.bytes);
+ BinaryReader br = new BinaryReader(ms);
+
+ int count = br.ReadInt32();
+
+ #if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Allowed assemblies count from MS: {count}");
+ sw.Start();
+ #endif
+
+ m_AllowedAssemblies = new AllowedAssembly[count];
+
+ for (int i = 0; i < count; i++)
+ {
+ string line = br.ReadString();
+ #if (DEBUG_PARANOID)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Line: {line}");
+ sw.Start();
+ #endif
+ line = SecuredString.EncryptDecrypt(line, "GAMESHIELD");
+ #if (DEBUG_PARANOID)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Line decrypted : {line}");
+ sw.Start();
+ #endif
+
+ string[] strArr = line.Split(separator, StringSplitOptions.RemoveEmptyEntries);
+ int stringsCount = strArr.Length;
+ #if (DEBUG_PARANOID)
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} stringsCount : {stringsCount}");
+ sw.Start();
+ #endif
+
+ if (stringsCount > 1)
+ {
+ string assemblyName = strArr[0];
+
+ int[] hashes = new int[stringsCount - 1];
+ for (int j = 1; j < stringsCount; j++)
+ {
+ hashes[j - 1] = int.Parse(strArr[j]);
+ }
+
+ m_AllowedAssemblies[i] = (new AllowedAssembly(assemblyName, hashes));
+ }
+ else
+ {
+ m_SignaturesAreNotGenuine = true;
+ br.Close();
+ ms.Close();
+ #if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ sw.Stop();
+ #endif
+ return;
+ }
+ }
+ br.Close();
+ ms.Close();
+ Resources.UnloadAsset(assembliesSignatures);
+
+ #if DEBUG || DEBUG_VERBOSE || DEBUG_PARANOID
+ sw.Stop();
+ Debug.Log($"{GeneralStrings.LOG_PREFIX} Allowed Assemblies parsing duration: {sw.ElapsedMilliseconds} ms.");
+ #endif
+
+ m_HexTable = new string[256];
+ for (int i = 0; i < 256; i++)
+ {
+ m_HexTable[i] = i.ToString("x2");
+ }
+ }
+
+ ///
+ /// Get Assembly Hash
+ ///
+ ///
+ ///
+ private int GetAssemblyHash(Assembly ass)
+ {
+ string hashInfo;
+#if !UNITY_WEBPLAYER
+ AssemblyName assName = ass.GetName();
+ byte[] bytes = assName.GetPublicKeyToken();
+ if (bytes.Length == 8)
+ {
+ hashInfo = assName.Name + PublicKeyTokenToString(bytes);
+ }
+ else
+ {
+ hashInfo = assName.Name;
+ }
+#else
+ string fullName = ass.FullName;
+
+ string assemblyName = fullName.Substring(0, fullName.IndexOf(", ", StringComparison.Ordinal));
+ int tokenIndex = fullName.IndexOf("PublicKeyToken=", StringComparison.Ordinal) + 15;
+ string token = fullName.Substring(tokenIndex, fullName.Length - tokenIndex);
+ if (token == "null") token = "";
+ hashInfo = assemblyName + token;
+#endif
+
+ int result = 0;
+ int len = hashInfo.Length;
+
+ for (int 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;
+ }
+
+#if !UNITY_WEBPLAYER
+ ///
+ /// Public Token to String
+ ///
+ ///
+ ///
+ private string PublicKeyTokenToString(byte[] bytes)
+ {
+ string result = "";
+ for (int i = 0; i < 8; i++)
+ {
+ result += m_HexTable[bytes[i]];
+ }
+
+ return result;
+ }
+#endif
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Injection Scanner",
+ Description = "This module monitors the introduction of external assemblies into the application executable code and checks it against the list of trusted ones.",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#injection-scanner"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig { }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionScanner.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionScanner.cs.meta
new file mode 100644
index 0000000..1790cde
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionScanner.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 79bea2ee5dd148feae14f9e56335aadb
+timeCreated: 1710017540
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionWarnings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionWarnings.cs
new file mode 100644
index 0000000..7380948
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionWarnings.cs
@@ -0,0 +1,7 @@
+namespace DevsDaddy.GameShield.Core.Modules.Injection
+{
+ public static class InjectionWarnings
+ {
+ public static string InjectionDetected = "It looks like your version of the game has detected third-party code not expected here. Your version of the product may have been hacked.";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionWarnings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionWarnings.cs.meta
new file mode 100644
index 0000000..6cf4f2f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Injection/InjectionWarnings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: dff94cf903634591af54b55442b57fc3
+timeCreated: 1710080711
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory.meta
new file mode 100644
index 0000000..a394383
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1b23a248a46c48ecb808184ebec5020b
+timeCreated: 1709969036
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryProtector.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryProtector.cs
new file mode 100644
index 0000000..80bda51
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryProtector.cs
@@ -0,0 +1,103 @@
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory
+{
+ ///
+ /// Memory Protector Module
+ ///
+ public class MemoryProtector : IShieldModule
+ {
+ public Options Config => _currentOptions;
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ // Fire Disconnected Complete
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ // Fire Initialization Complete
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Memory Protector",
+ Description = "This module monitors and sends a notification if a user has attempted to change the value of a protected (SecuredType) types in memory.",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#memory-protection"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+ public float FloatEpsilon = 0.0001f;
+ public float Vector2Epsilon = 0.1f;
+ public float Vector3Epsilon = 0.1f;
+ public float Vector4Epsilon = 0.1f;
+ public float QuaternionEpsilon = 0.1f;
+ public float ColorEpsilon = 0.1f;
+ public byte Color32Epsilon = 1;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryProtector.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryProtector.cs.meta
new file mode 100644
index 0000000..afe1abb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryProtector.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 36fce6dcc2754c458ab2d8c6985d3545
+timeCreated: 1709969053
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryWarnings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryWarnings.cs
new file mode 100644
index 0000000..603d40a
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryWarnings.cs
@@ -0,0 +1,7 @@
+namespace DevsDaddy.GameShield.Core.Modules.Memory
+{
+ public static class MemoryWarnings
+ {
+ public static string TypeHackWarning = "Your game's memory has not been modified as expected. It looks like you have a cheat system running on your device.";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryWarnings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryWarnings.cs.meta
new file mode 100644
index 0000000..b21dd64
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/MemoryWarnings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 489c6402de3148bf82d4e6036fd3a147
+timeCreated: 1710020139
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes.meta
new file mode 100644
index 0000000..45fa959
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 7081ef41dd9c45a4b261e470c227eeef
+timeCreated: 1710019783
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredBool.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredBool.cs
new file mode 100644
index 0000000..924c29a
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredBool.cs
@@ -0,0 +1,180 @@
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Boolean Type
+ ///
+ [System.Serializable]
+ public struct SecuredBool
+ {
+ // Crypto Key
+ private static byte cryptoKey = 215;
+
+#if UNITY_EDITOR
+ public static byte cryptoKeyEditor = cryptoKey;
+#endif
+
+ // Serialized Fields
+ [SerializeField] private byte currentCryptoKey;
+ [SerializeField] private int hiddenValue;
+ [SerializeField] private bool fakeValue;
+ [SerializeField] private bool fakeValueChanged;
+ [SerializeField] private bool inited;
+
+ private SecuredBool(int value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = false;
+ fakeValueChanged = false;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(byte newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static int Encrypt(bool value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static int Encrypt(bool value, byte key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ int encryptedValue = value ? 213 : 181;
+
+ encryptedValue ^= key;
+
+ return encryptedValue;
+ }
+
+ public static bool Decrypt(int value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static bool Decrypt(int value, byte key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ value ^= key;
+
+ return value != 181;
+ }
+
+ public int GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(int encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ fakeValueChanged = true;
+ }
+ }
+
+ private bool InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(false);
+ fakeValue = false;
+ fakeValueChanged = true;
+ inited = true;
+ }
+
+ byte key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ int value = hiddenValue;
+ value ^= key;
+
+ bool decrypted = value != 181;
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValueChanged && decrypted != fakeValue) {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredBool(bool value)
+ {
+ SecuredBool obscured = new SecuredBool(Encrypt(value));
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ obscured.fakeValueChanged = true;
+ }
+
+ return obscured;
+ }
+ public static implicit operator bool(SecuredBool value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredBool))
+ return false;
+
+ SecuredBool oi = (SecuredBool)obj;
+ return (hiddenValue == oi.hiddenValue);
+ }
+
+ public bool Equals(SecuredBool obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredBool.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredBool.cs.meta
new file mode 100644
index 0000000..eb88f58
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredBool.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 8417c9a167da475b83fe1741a6de908f
+timeCreated: 1710019821
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredByte.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredByte.cs
new file mode 100644
index 0000000..9428897
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredByte.cs
@@ -0,0 +1,188 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Byte Type
+ ///
+ [System.Serializable]
+ public struct SecuredByte : IEquatable, IFormattable
+ {
+ private static byte cryptoKey = 244;
+
+#if UNITY_EDITOR
+ public static byte cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private byte currentCryptoKey;
+ [SerializeField] private byte hiddenValue;
+ [SerializeField] private byte fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredByte(byte value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(byte newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = EncryptDecrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static byte EncryptDecrypt(byte value)
+ {
+ return EncryptDecrypt(value, 0);
+ }
+
+ public static byte EncryptDecrypt(byte value, byte key)
+ {
+ if (key == 0)
+ {
+ return (byte)(value ^ cryptoKey);
+ }
+ return (byte)(value ^ key);
+ }
+
+ public byte GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(byte encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private byte InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = EncryptDecrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ byte key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ byte decrypted = EncryptDecrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredByte(byte value)
+ {
+ SecuredByte obscured = new SecuredByte(EncryptDecrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+
+ public static implicit operator byte(SecuredByte value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredByte operator ++(SecuredByte input)
+ {
+ byte decrypted = (byte)(input.InternalDecrypt() + 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredByte operator --(SecuredByte input)
+ {
+ byte decrypted = (byte)(input.InternalDecrypt() - 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredByte))
+ return false;
+
+ SecuredByte ob = (SecuredByte)obj;
+ return hiddenValue == ob.hiddenValue;
+ }
+
+ public bool Equals(SecuredByte obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredByte.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredByte.cs.meta
new file mode 100644
index 0000000..07b0d6c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredByte.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 69e165a28f704f53b2f4815240c3a2c2
+timeCreated: 1710020311
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredChar.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredChar.cs
new file mode 100644
index 0000000..f591528
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredChar.cs
@@ -0,0 +1,180 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Char Type
+ ///
+ [System.Serializable]
+ public struct SecuredChar : IEquatable
+ {
+ private static char cryptoKey = '\x2014';
+
+#if UNITY_EDITOR
+ public static char cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private char currentCryptoKey;
+ [SerializeField] private char hiddenValue;
+ [SerializeField] private char fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredChar(char value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = '\0';
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(char newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = EncryptDecrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static char EncryptDecrypt(char value)
+ {
+ return EncryptDecrypt(value, '\0');
+ }
+
+ public static char EncryptDecrypt(char value, char key)
+ {
+ if (key == '\0')
+ {
+ return (char)(value ^ cryptoKey);
+ }
+ return (char)(value ^ key);
+ }
+
+ public char GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(char encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private char InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = EncryptDecrypt('\0');
+ fakeValue = '\0';
+ inited = true;
+ }
+
+ char key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ char decrypted = EncryptDecrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != '\0' && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredChar(char value)
+ {
+ SecuredChar obscured = new SecuredChar(EncryptDecrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+
+ public static implicit operator char(SecuredChar value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredChar operator ++(SecuredChar input)
+ {
+ char decrypted = (char)(input.InternalDecrypt() + 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredChar operator --(SecuredChar input)
+ {
+ char decrypted = (char)(input.InternalDecrypt() - 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredChar))
+ return false;
+
+ SecuredChar ob = (SecuredChar)obj;
+ return hiddenValue == ob.hiddenValue;
+ }
+
+ public bool Equals(SecuredChar obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ #if !UNITY_WINRT
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+ #endif
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredChar.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredChar.cs.meta
new file mode 100644
index 0000000..766436f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredChar.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 0933070ae4cc42c5a964579e48c2cd3b
+timeCreated: 1710020689
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor.cs
new file mode 100644
index 0000000..f0c4feb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor.cs
@@ -0,0 +1,433 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Color Type
+ ///
+ [System.Serializable]
+ public struct SecuredColor
+ {
+ private static int cryptoKey = 120222;
+ private static readonly Color initialFakeValue = Color.black;
+
+ #if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+ #endif
+
+ // Serialized Fields
+ [SerializeField] private int currentCryptoKey;
+ [SerializeField] private RawEncryptedColor hiddenValue;
+ [SerializeField] private Color fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredColor(RawEncryptedColor encrypted)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = encrypted;
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ public float r
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.r);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.r) > protector.Config.ColorEpsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.r = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.r = value;
+ }
+ }
+ }
+
+ public float g
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.g);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.g) > protector.Config.ColorEpsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.g = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.g = value;
+ }
+ }
+ }
+
+ public float b
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.b);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.b) > protector.Config.ColorEpsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.b = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.b = value;
+ }
+ }
+ }
+
+ public float a
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.a);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.a) > protector.Config.ColorEpsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.a = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.a = value;
+ }
+ }
+ }
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return r;
+ case 1:
+ return g;
+ case 2:
+ return b;
+ case 3:
+ return a;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredColor index!");
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ r = value;
+ break;
+ case 1:
+ g = value;
+ break;
+ case 2:
+ b = value;
+ break;
+ case 3:
+ a = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredColor index!");
+ }
+ }
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static RawEncryptedColor Encrypt(Color value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static RawEncryptedColor Encrypt(Color value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ RawEncryptedColor result;
+ result.r = SecuredFloat.Encrypt(value.r, key);
+ result.g = SecuredFloat.Encrypt(value.g, key);
+ result.b = SecuredFloat.Encrypt(value.b, key);
+ result.a = SecuredFloat.Encrypt(value.a, key);
+
+ return result;
+ }
+
+ public static Color Decrypt(RawEncryptedColor value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static Color Decrypt(RawEncryptedColor value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ Color result;
+ result.r = SecuredFloat.Decrypt(value.r, key);
+ result.g = SecuredFloat.Decrypt(value.g, key);
+ result.b = SecuredFloat.Decrypt(value.b, key);
+ result.a = SecuredFloat.Decrypt(value.a, key);
+
+ return result;
+ }
+
+ public RawEncryptedColor GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(RawEncryptedColor encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private Color InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(initialFakeValue, cryptoKey);
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ Color value;
+
+ value.r = SecuredFloat.Decrypt(hiddenValue.r, key);
+ value.g = SecuredFloat.Decrypt(hiddenValue.g, key);
+ value.b = SecuredFloat.Decrypt(hiddenValue.b, key);
+ value.a = SecuredFloat.Decrypt(hiddenValue.a, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && !fakeValue.Equals(Color.black) && !CompareVectorsWithTolerance(value, fakeValue))
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return value;
+ }
+
+ private bool CompareVectorsWithTolerance(Color color1, Color color2)
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float epsilon = (protector != null) ? protector.Config.ColorEpsilon : 0.1f;
+ return Math.Abs(color1.r - color2.r) < epsilon &&
+ Math.Abs(color1.g - color2.g) < epsilon &&
+ Math.Abs(color1.b - color2.b) < epsilon &&
+ Math.Abs(color1.a - color2.a) < epsilon;
+ }
+
+ private float InternalDecryptField(int encrypted)
+ {
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ float result = SecuredFloat.Decrypt(encrypted, key);
+ return result;
+ }
+
+ private int InternalEncryptField(float encrypted)
+ {
+ int result = SecuredFloat.Encrypt(encrypted, cryptoKey);
+ return result;
+ }
+
+ #region Operators
+ public static implicit operator SecuredColor(Color value)
+ {
+ SecuredColor obscured = new SecuredColor(Encrypt(value, cryptoKey));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator Color(SecuredColor value)
+ {
+ return value.InternalDecrypt();
+ }
+ public static SecuredColor operator +(SecuredColor a, SecuredColor b)
+ {
+ return a.InternalDecrypt() + b.InternalDecrypt();
+ }
+ public static SecuredColor operator +(Color a, SecuredColor b)
+ {
+ return a + b.InternalDecrypt();
+ }
+ public static SecuredColor operator +(SecuredColor a, Color b)
+ {
+ return a.InternalDecrypt() + b;
+ }
+ public static SecuredColor operator -(SecuredColor a, SecuredColor b)
+ {
+ return a.InternalDecrypt() - b.InternalDecrypt();
+ }
+ public static SecuredColor operator -(Color a, SecuredColor b)
+ {
+ return a - b.InternalDecrypt();
+ }
+ public static SecuredColor operator -(SecuredColor a, Color b)
+ {
+ return a.InternalDecrypt() - b;
+ }
+ public static SecuredColor operator *(SecuredColor a, float d)
+ {
+ return a.InternalDecrypt() * d;
+ }
+ public static SecuredColor operator *(float d, SecuredColor a)
+ {
+ return d * a.InternalDecrypt();
+ }
+ public static SecuredColor operator /(SecuredColor a, float d)
+ {
+ return a.InternalDecrypt() / d;
+ }
+
+ public static bool operator ==(SecuredColor lhs, SecuredColor rhs)
+ {
+ return lhs.InternalDecrypt() == rhs.InternalDecrypt();
+ }
+ public static bool operator ==(Color lhs, SecuredColor rhs)
+ {
+ return lhs == rhs.InternalDecrypt();
+ }
+ public static bool operator ==(SecuredColor lhs, Color rhs)
+ {
+ return lhs.InternalDecrypt() == rhs;
+ }
+
+ public static bool operator !=(SecuredColor lhs, SecuredColor rhs)
+ {
+ return lhs.InternalDecrypt() != rhs.InternalDecrypt();
+ }
+ public static bool operator !=(Color lhs, SecuredColor rhs)
+ {
+ return lhs != rhs.InternalDecrypt();
+ }
+ public static bool operator !=(SecuredColor lhs, Color rhs)
+ {
+ return lhs.InternalDecrypt() != rhs;
+ }
+ #endregion
+
+ public override bool Equals(object other)
+ {
+ return InternalDecrypt().Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ [System.Serializable]
+ public struct RawEncryptedColor
+ {
+ public int r;
+ public int g;
+ public int b;
+ public int a;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor.cs.meta
new file mode 100644
index 0000000..ead4b36
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 919535a3474d4d8dacd5179673b4c7f0
+timeCreated: 1710020868
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor32.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor32.cs
new file mode 100644
index 0000000..68ad97f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor32.cs
@@ -0,0 +1,355 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Color32 Type
+ ///
+ [System.Serializable]
+ public struct SecuredColor32
+ {
+ private static int cryptoKey = 120223;
+ private static readonly Color32 initialFakeValue = new Color32(0,0,0,1);
+
+ #if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+ #endif
+
+ // Serialized Fields
+ [SerializeField] private int currentCryptoKey;
+ [SerializeField] private RawEncryptedColor32 hiddenValue;
+ [SerializeField] private Color32 fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredColor32(RawEncryptedColor32 encrypted)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = encrypted;
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ public byte r
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ byte decrypted = InternalDecryptField(hiddenValue.r);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.r) > protector.Config.Color32Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.r = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.r = value;
+ }
+ }
+ }
+
+ public byte g
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ byte decrypted = InternalDecryptField(hiddenValue.g);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.g) > protector.Config.Color32Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.g = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.g = value;
+ }
+ }
+ }
+
+ public byte b
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ byte decrypted = InternalDecryptField(hiddenValue.b);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.b) > protector.Config.Color32Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.b = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.b = value;
+ }
+ }
+ }
+
+ public byte a
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ byte decrypted = InternalDecryptField(hiddenValue.a);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.a) > protector.Config.Color32Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.a = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.a = value;
+ }
+ }
+ }
+
+ public byte this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return r;
+ case 1:
+ return g;
+ case 2:
+ return b;
+ case 3:
+ return a;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredColor32 index!");
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ r = value;
+ break;
+ case 1:
+ g = value;
+ break;
+ case 2:
+ b = value;
+ break;
+ case 3:
+ a = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredColor32 index!");
+ }
+ }
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static RawEncryptedColor32 Encrypt(Color32 value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static RawEncryptedColor32 Encrypt(Color32 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ RawEncryptedColor32 result;
+ result.r = SecuredByte.EncryptDecrypt((byte)value.r, (byte)key);
+ result.g = SecuredByte.EncryptDecrypt((byte)value.g, (byte)key);
+ result.b = SecuredByte.EncryptDecrypt((byte)value.b, (byte)key);
+ result.a = SecuredByte.EncryptDecrypt((byte)value.a, (byte)key);
+
+ return result;
+ }
+
+ public static Color32 Decrypt(RawEncryptedColor32 value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static Color32 Decrypt(RawEncryptedColor32 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ Color32 result = new Color32();
+ result.r = SecuredByte.EncryptDecrypt((byte)value.r, (byte)key);
+ result.g = SecuredByte.EncryptDecrypt((byte)value.g, (byte)key);
+ result.b = SecuredByte.EncryptDecrypt((byte)value.b, (byte)key);
+ result.a = SecuredByte.EncryptDecrypt((byte)value.a, (byte)key);
+
+ return result;
+ }
+
+ public RawEncryptedColor32 GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(RawEncryptedColor32 encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private Color32 InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(initialFakeValue, cryptoKey);
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ Color32 value = new Color32();
+
+ value.r = SecuredByte.EncryptDecrypt((byte)hiddenValue.r, (byte)key);
+ value.g = SecuredByte.EncryptDecrypt((byte)hiddenValue.g, (byte)key);
+ value.b = SecuredByte.EncryptDecrypt((byte)hiddenValue.b, (byte)key);
+ value.a = SecuredByte.EncryptDecrypt((byte)hiddenValue.a, (byte)key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && !fakeValue.Equals(Color.black) && !CompareVectorsWithTolerance(value, fakeValue))
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return value;
+ }
+
+ private bool CompareVectorsWithTolerance(Color32 color1, Color32 color2)
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float epsilon = (protector != null) ? protector.Config.Color32Epsilon : 1;
+ return Math.Abs(color1.r - color2.r) < epsilon &&
+ Math.Abs(color1.g - color2.g) < epsilon &&
+ Math.Abs(color1.b - color2.b) < epsilon &&
+ Math.Abs(color1.a - color2.a) < epsilon;
+ }
+
+ private byte InternalDecryptField(int encrypted)
+ {
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ byte result = SecuredByte.EncryptDecrypt((byte)encrypted, (byte)key);
+ return result;
+ }
+
+ private int InternalEncryptField(float encrypted)
+ {
+ int result = SecuredFloat.Encrypt(encrypted, cryptoKey);
+ return result;
+ }
+
+ public override bool Equals(object other)
+ {
+ return InternalDecrypt().Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ [System.Serializable]
+ public struct RawEncryptedColor32
+ {
+ public int r;
+ public int g;
+ public int b;
+ public int a;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor32.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor32.cs.meta
new file mode 100644
index 0000000..6371dc0
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredColor32.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2f9b85e44f484acbabc1e7132450caf5
+timeCreated: 1710021651
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredDecimal.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredDecimal.cs
new file mode 100644
index 0000000..2d278f8
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredDecimal.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Runtime.InteropServices;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Decimal Type
+ ///
+ [System.Serializable]
+ public struct SecuredDecimal : IEquatable, IFormattable
+ {
+ private static long cryptoKey = 209208L;
+
+#if UNITY_EDITOR
+ public static long cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private long currentCryptoKey;
+ [SerializeField] private byte[] hiddenValue;
+ [SerializeField] private decimal fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredDecimal(byte[] value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0m;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(long newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = InternalEncrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static decimal Encrypt(decimal value)
+ {
+ return Encrypt(value, cryptoKey);
+ }
+
+ public static decimal Encrypt(decimal value, long key)
+ {
+ var u = new DecimalLongBytesUnion();
+ u.d = value;
+ u.l1 = u.l1 ^ key;
+ u.l2 = u.l2 ^ key;
+
+ return u.d;
+ }
+
+ private static byte[] InternalEncrypt(decimal value)
+ {
+ return InternalEncrypt(value, 0L);
+ }
+
+ private static byte[] InternalEncrypt(decimal value, long key)
+ {
+ long currKey = key;
+ if (currKey == 0L)
+ {
+ currKey = cryptoKey;
+ }
+
+ DecimalLongBytesUnion union = new DecimalLongBytesUnion();
+ union.d = value;
+ union.l1 = union.l1 ^ currKey;
+ union.l2 = union.l2 ^ currKey;
+
+ return new[]
+ {
+ union.b1, union.b2, union.b3, union.b4, union.b5, union.b6, union.b7, union.b8,
+ union.b9, union.b10, union.b11, union.b12, union.b13, union.b14, union.b15, union.b16
+ };
+ }
+
+ public static decimal Decrypt(decimal value)
+ {
+ return Decrypt(value, cryptoKey);
+ }
+
+ public static decimal Decrypt(decimal value, long key)
+ {
+ DecimalLongBytesUnion u = new DecimalLongBytesUnion();
+ u.d = value;
+ u.l1 = u.l1 ^ key;
+ u.l2 = u.l2 ^ key;
+ return u.d;
+ }
+
+ public decimal GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ DecimalLongBytesUnion union = new DecimalLongBytesUnion();
+ union.b1 = hiddenValue[0];
+ union.b2 = hiddenValue[1];
+ union.b3 = hiddenValue[2];
+ union.b4 = hiddenValue[3];
+ union.b5 = hiddenValue[4];
+ union.b6 = hiddenValue[5];
+ union.b7 = hiddenValue[6];
+ union.b8 = hiddenValue[7];
+ union.b9 = hiddenValue[8];
+ union.b10 = hiddenValue[9];
+ union.b11 = hiddenValue[10];
+ union.b12 = hiddenValue[11];
+ union.b13 = hiddenValue[12];
+ union.b14 = hiddenValue[13];
+ union.b15 = hiddenValue[14];
+ union.b16 = hiddenValue[15];
+
+ return union.d;
+ }
+
+ public void SetEncrypted(decimal encrypted)
+ {
+ inited = true;
+ DecimalLongBytesUnion union = new DecimalLongBytesUnion();
+ union.d = encrypted;
+
+ hiddenValue = new[]
+ {
+ union.b1, union.b2, union.b3, union.b4, union.b5, union.b6, union.b7, union.b8,
+ union.b9, union.b10, union.b11, union.b12, union.b13, union.b14, union.b15, union.b16
+ };
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private decimal InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = InternalEncrypt(0m);
+ fakeValue = 0m;
+ inited = true;
+ }
+
+ long key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ DecimalLongBytesUnion union = new DecimalLongBytesUnion();
+ union.b1 = hiddenValue[0];
+ union.b2 = hiddenValue[1];
+ union.b3 = hiddenValue[2];
+ union.b4 = hiddenValue[3];
+ union.b5 = hiddenValue[4];
+ union.b6 = hiddenValue[5];
+ union.b7 = hiddenValue[6];
+ union.b8 = hiddenValue[7];
+ union.b9 = hiddenValue[8];
+ union.b10 = hiddenValue[9];
+ union.b11 = hiddenValue[10];
+ union.b12 = hiddenValue[11];
+ union.b13 = hiddenValue[12];
+ union.b14 = hiddenValue[13];
+ union.b15 = hiddenValue[14];
+ union.b16 = hiddenValue[15];
+
+ union.l1 = union.l1 ^ key;
+ union.l2 = union.l2 ^ key;
+
+ decimal decrypted = union.d;
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ private struct DecimalLongBytesUnion
+ {
+ [FieldOffset(0)]
+ public decimal d;
+
+ [FieldOffset(0)]
+ public long l1;
+
+ [FieldOffset(8)]
+ public long l2;
+
+ [FieldOffset(0)]
+ public byte b1;
+
+ [FieldOffset(1)]
+ public byte b2;
+
+ [FieldOffset(2)]
+ public byte b3;
+
+ [FieldOffset(3)]
+ public byte b4;
+
+ [FieldOffset(4)]
+ public byte b5;
+
+ [FieldOffset(5)]
+ public byte b6;
+
+ [FieldOffset(6)]
+ public byte b7;
+
+ [FieldOffset(7)]
+ public byte b8;
+
+ [FieldOffset(8)]
+ public byte b9;
+
+ [FieldOffset(9)]
+ public byte b10;
+
+ [FieldOffset(10)]
+ public byte b11;
+
+ [FieldOffset(11)]
+ public byte b12;
+
+ [FieldOffset(12)]
+ public byte b13;
+
+ [FieldOffset(13)]
+ public byte b14;
+
+ [FieldOffset(14)]
+ public byte b15;
+
+ [FieldOffset(15)]
+ public byte b16;
+ }
+
+ public static implicit operator SecuredDecimal(decimal value)
+ {
+ SecuredDecimal obscured = new SecuredDecimal(InternalEncrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator decimal(SecuredDecimal value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredDecimal operator ++(SecuredDecimal input)
+ {
+ decimal decrypted = input.InternalDecrypt() + 1m;
+ input.hiddenValue = InternalEncrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+
+ return input;
+ }
+
+ public static SecuredDecimal operator --(SecuredDecimal input)
+ {
+ decimal decrypted = input.InternalDecrypt() - 1m;
+ input.hiddenValue = InternalEncrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredDecimal))
+ return false;
+ SecuredDecimal d = (SecuredDecimal)obj;
+ return d.InternalDecrypt().Equals(InternalDecrypt());
+ }
+
+ public bool Equals(SecuredDecimal obj)
+ {
+ return obj.InternalDecrypt().Equals(InternalDecrypt());
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredDecimal.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredDecimal.cs.meta
new file mode 100644
index 0000000..9c3a3c3
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredDecimal.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 935902d680184d6190d77bff0bb6572b
+timeCreated: 1710021991
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredFloat.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredFloat.cs
new file mode 100644
index 0000000..74035f0
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredFloat.cs
@@ -0,0 +1,276 @@
+using System;
+using System.Runtime.InteropServices;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ [System.Serializable]
+ public struct SecuredFloat : IEquatable, IFormattable
+ {
+ private static int cryptoKey = 230887;
+
+#if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField]
+ private int currentCryptoKey;
+
+ [SerializeField]
+ private byte[] hiddenValue;
+
+ [SerializeField]
+ private float fakeValue;
+
+ [SerializeField]
+ private bool inited;
+
+ private SecuredFloat(byte[] value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = InternalEncrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static int Encrypt(float value)
+ {
+ return Encrypt(value, cryptoKey);
+ }
+
+ public static int Encrypt(float value, int key)
+ {
+ var u = new FloatIntBytesUnion();
+ u.f = value;
+ u.i = u.i ^ key;
+
+ return u.i;
+ }
+
+ private static byte[] InternalEncrypt(float value)
+ {
+ return InternalEncrypt(value, 0);
+ }
+
+ private static byte[] InternalEncrypt(float value, int key)
+ {
+ int currKey = key;
+ if (currKey == 0)
+ {
+ currKey = cryptoKey;
+ }
+
+ var u = new FloatIntBytesUnion();
+ u.f = value;
+ u.i = u.i ^ currKey;
+
+ return new[] { u.b1, u.b2, u.b3, u.b4 };
+ }
+
+ public static float Decrypt(int value)
+ {
+ return Decrypt(value, cryptoKey);
+ }
+
+ public static float Decrypt(int value, int key)
+ {
+ var u = new FloatIntBytesUnion();
+ u.i = value ^ key;
+ return u.f;
+ }
+
+ public int GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ var union = new FloatIntBytesUnion();
+ union.b1 = hiddenValue[0];
+ union.b2 = hiddenValue[1];
+ union.b3 = hiddenValue[2];
+ union.b4 = hiddenValue[3];
+
+ return union.i;
+ }
+
+ public void SetEncrypted(int encrypted)
+ {
+ inited = true;
+ FloatIntBytesUnion union = new FloatIntBytesUnion();
+ union.i = encrypted;
+
+ hiddenValue = new[] { union.b1, union.b2, union.b3, union.b4 };
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private float InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = InternalEncrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ var union = new FloatIntBytesUnion();
+ union.b1 = hiddenValue[0];
+ union.b2 = hiddenValue[1];
+ union.b3 = hiddenValue[2];
+ union.b4 = hiddenValue[3];
+
+ union.i = union.i ^ key;
+
+ float decrypted = union.f;
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && Math.Abs(decrypted - fakeValue) > protector.Config.FloatEpsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ private struct FloatIntBytesUnion
+ {
+ [FieldOffset(0)]
+ public float f;
+
+ [FieldOffset(0)]
+ public int i;
+
+ [FieldOffset(0)]
+ public byte b1;
+
+ [FieldOffset(1)]
+ public byte b2;
+
+ [FieldOffset(2)]
+ public byte b3;
+
+ [FieldOffset(3)]
+ public byte b4;
+ }
+
+ public static implicit operator SecuredFloat(float value)
+ {
+ SecuredFloat obscured = new SecuredFloat(InternalEncrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator float(SecuredFloat value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredFloat operator ++(SecuredFloat input)
+ {
+ float decrypted = input.InternalDecrypt() + 1f;
+ input.hiddenValue = InternalEncrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+
+ return input;
+ }
+
+ public static SecuredFloat operator --(SecuredFloat input)
+ {
+ float decrypted = input.InternalDecrypt() - 1f;
+ input.hiddenValue = InternalEncrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredFloat))
+ return false;
+ SecuredFloat d = (SecuredFloat)obj;
+ float dParam = d.InternalDecrypt();
+ float dThis = InternalDecrypt();
+ if ((double)dParam == (double)dThis)
+ return true;
+ return float.IsNaN(dParam) && float.IsNaN(dThis);
+ }
+
+ public bool Equals(SecuredFloat obj)
+ {
+ float dParam = obj.InternalDecrypt();
+ float dThis = InternalDecrypt();
+
+
+ if ((double)dParam == (double)dThis)
+ return true;
+ return float.IsNaN(dParam) && float.IsNaN(dThis);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredFloat.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredFloat.cs.meta
new file mode 100644
index 0000000..283a52f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredFloat.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e2173dd04cde43c3bbdba8b3b60f9e7f
+timeCreated: 1710020971
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredInt.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredInt.cs
new file mode 100644
index 0000000..93c5a92
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredInt.cs
@@ -0,0 +1,208 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Int Type
+ ///
+ [System.Serializable]
+ public struct SecuredInt : IEquatable, IFormattable
+ {
+ private static int cryptoKey = 444444;
+
+ #if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+ #endif
+
+ [SerializeField]
+ private int currentCryptoKey;
+
+ [SerializeField]
+ private int hiddenValue;
+
+ [SerializeField]
+ private int fakeValue;
+
+ [SerializeField]
+ private bool inited;
+
+ private SecuredInt(int value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static int Encrypt(int value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static int Encrypt(int value, int key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public static int Decrypt(int value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static int Decrypt(int value, int key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public int GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(int encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private int InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ int decrypted = Decrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredInt(int value)
+ {
+ SecuredInt obscured = new SecuredInt(Encrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator int(SecuredInt value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredInt operator ++(SecuredInt input)
+ {
+ int decrypted = input.InternalDecrypt() + 1;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredInt operator --(SecuredInt input)
+ {
+ int decrypted = input.InternalDecrypt() - 1;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredInt))
+ return false;
+
+ SecuredInt oi = (SecuredInt)obj;
+ return (hiddenValue == oi.hiddenValue);
+ }
+
+ public bool Equals(SecuredInt obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredInt.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredInt.cs.meta
new file mode 100644
index 0000000..c05023b
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredInt.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f254e2add4994b8aad0c63624a743e68
+timeCreated: 1710057405
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredLong.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredLong.cs
new file mode 100644
index 0000000..d4e5f33
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredLong.cs
@@ -0,0 +1,203 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Long Type
+ ///
+ [System.Serializable]
+ public struct SecuredLong : IEquatable, IFormattable
+ {
+ private static long cryptoKey = 444442L;
+
+ #if UNITY_EDITOR
+ public static long cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private long currentCryptoKey;
+ [SerializeField] private long hiddenValue;
+ [SerializeField] private long fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredLong(long value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(long newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static long Encrypt(long value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static long Decrypt(long value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static long Encrypt(long value, long key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public static long Decrypt(long value, long key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public long GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(long encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private long InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ long key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ long decrypted = Decrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+
+ public static implicit operator SecuredLong(long value)
+ {
+ SecuredLong obscured = new SecuredLong(Encrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator long(SecuredLong value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredLong operator ++(SecuredLong input)
+ {
+ long decrypted = input.InternalDecrypt() + 1L;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredLong operator --(SecuredLong input)
+ {
+ long decrypted = input.InternalDecrypt() - 1L;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredLong))
+ return false;
+
+ SecuredLong o = (SecuredLong)obj;
+ return (hiddenValue == o.hiddenValue);
+ }
+
+ public bool Equals(SecuredLong obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredLong.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredLong.cs.meta
new file mode 100644
index 0000000..e7b887d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredLong.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 48d1fa4b23534e03b575f7103efadce0
+timeCreated: 1710057596
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredQuaternion.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredQuaternion.cs
new file mode 100644
index 0000000..d5f5c1c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredQuaternion.cs
@@ -0,0 +1,193 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Quaternion Type
+ ///
+ [System.Serializable]
+ public class SecuredQuaternion
+ {
+ private static int cryptoKey = 120205;
+ private static readonly Quaternion initialFakeValue = Quaternion.identity;
+
+#if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+#endif
+
+ // Serialized Params
+ [SerializeField] private int currentCryptoKey;
+ [SerializeField] private RawEncryptedQuaternion hiddenValue;
+ [SerializeField] private Quaternion fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredQuaternion(RawEncryptedQuaternion value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static RawEncryptedQuaternion Encrypt(Quaternion value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static RawEncryptedQuaternion Encrypt(Quaternion value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ RawEncryptedQuaternion result;
+ result.x = SecuredFloat.Encrypt(value.x, key);
+ result.y = SecuredFloat.Encrypt(value.y, key);
+ result.z = SecuredFloat.Encrypt(value.z, key);
+ result.w = SecuredFloat.Encrypt(value.w, key);
+
+ return result;
+ }
+
+ public static Quaternion Decrypt(RawEncryptedQuaternion value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static Quaternion Decrypt(RawEncryptedQuaternion value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ Quaternion result;
+ result.x = SecuredFloat.Decrypt(value.x, key);
+ result.y = SecuredFloat.Decrypt(value.y, key);
+ result.z = SecuredFloat.Decrypt(value.z, key);
+ result.w = SecuredFloat.Decrypt(value.w, key);
+
+ return result;
+ }
+
+ public RawEncryptedQuaternion GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(RawEncryptedQuaternion encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private Quaternion InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(initialFakeValue);
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ Quaternion value;
+
+ value.x = SecuredFloat.Decrypt(hiddenValue.x, key);
+ value.y = SecuredFloat.Decrypt(hiddenValue.y, key);
+ value.z = SecuredFloat.Decrypt(hiddenValue.z, key);
+ value.w = SecuredFloat.Decrypt(hiddenValue.w, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && !CompareQuaternionsWithTolerance(value, fakeValue))
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return value;
+ }
+
+ private bool CompareQuaternionsWithTolerance(Quaternion q1, Quaternion q2)
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float epsilon = (protector != null) ? protector.Config.QuaternionEpsilon : 0.1f;
+ return Math.Abs(q1.x - q2.x) < epsilon &&
+ Math.Abs(q1.y - q2.y) < epsilon &&
+ Math.Abs(q1.z - q2.z) < epsilon &&
+ Math.Abs(q1.w - q2.w) < epsilon;
+ }
+
+ public static implicit operator SecuredQuaternion(Quaternion value)
+ {
+ SecuredQuaternion obscured = new SecuredQuaternion(Encrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator Quaternion(SecuredQuaternion value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ [System.Serializable]
+ public struct RawEncryptedQuaternion
+ {
+ public int x;
+ public int y;
+ public int z;
+ public int w;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredQuaternion.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredQuaternion.cs.meta
new file mode 100644
index 0000000..e07366c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredQuaternion.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: dad309ad954e407cb25b4ffe45be7d84
+timeCreated: 1710059226
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredSByte.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredSByte.cs
new file mode 100644
index 0000000..6ced1e0
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredSByte.cs
@@ -0,0 +1,188 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured SByte Type
+ ///
+ [System.Serializable]
+ public struct SecuredSByte : IEquatable, IFormattable
+ {
+ private static sbyte cryptoKey = 112;
+
+#if UNITY_EDITOR
+ public static sbyte cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private sbyte currentCryptoKey;
+ [SerializeField] private sbyte hiddenValue;
+ [SerializeField] private sbyte fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredSByte(sbyte value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(sbyte newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = EncryptDecrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static sbyte EncryptDecrypt(sbyte value)
+ {
+ return EncryptDecrypt(value, 0);
+ }
+
+ public static sbyte EncryptDecrypt(sbyte value, sbyte key)
+ {
+ if (key == 0)
+ {
+ return (sbyte)(value ^ cryptoKey);
+ }
+ return (sbyte)(value ^ key);
+ }
+
+ public sbyte GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(sbyte encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private sbyte InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = EncryptDecrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ sbyte key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ sbyte decrypted = EncryptDecrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredSByte(sbyte value)
+ {
+ SecuredSByte obscured = new SecuredSByte(EncryptDecrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator sbyte(SecuredSByte value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredSByte operator ++(SecuredSByte input)
+ {
+ sbyte decrypted = (sbyte)(input.InternalDecrypt() + 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredSByte operator --(SecuredSByte input)
+ {
+ sbyte decrypted = (sbyte)(input.InternalDecrypt() - 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredSByte))
+ return false;
+
+ SecuredSByte ob = (SecuredSByte)obj;
+ return hiddenValue == ob.hiddenValue;
+ }
+
+ public bool Equals(SecuredSByte obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredSByte.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredSByte.cs.meta
new file mode 100644
index 0000000..f910cb8
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredSByte.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: d467e706a05a46b982f518ceb45fe9e1
+timeCreated: 1710059275
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredShort.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredShort.cs
new file mode 100644
index 0000000..6c84d44
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredShort.cs
@@ -0,0 +1,188 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Short Type
+ ///
+ [System.Serializable]
+ public struct SecuredShort : IEquatable, IFormattable
+ {
+ private static short cryptoKey = 214;
+
+#if UNITY_EDITOR
+ public static short cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private short currentCryptoKey;
+ [SerializeField] private short hiddenValue;
+ [SerializeField] private short fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredShort(short value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(short newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = EncryptDecrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static short EncryptDecrypt(short value)
+ {
+ return EncryptDecrypt(value, 0);
+ }
+
+ public static short EncryptDecrypt(short value, short key)
+ {
+ if (key == 0)
+ {
+ return (short)(value ^ cryptoKey);
+ }
+ return (short)(value ^ key);
+ }
+
+ public short GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(short encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private short InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = EncryptDecrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ short key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ short decrypted = EncryptDecrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredShort(short value)
+ {
+ SecuredShort obscured = new SecuredShort(EncryptDecrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator short(SecuredShort value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredShort operator ++(SecuredShort input)
+ {
+ short decrypted = (short)(input.InternalDecrypt() + 1);
+ input.hiddenValue = EncryptDecrypt(decrypted);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredShort operator --(SecuredShort input)
+ {
+ short decrypted = (short)(input.InternalDecrypt() - 1);
+ input.hiddenValue = EncryptDecrypt(decrypted);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredShort))
+ return false;
+
+ SecuredShort ob = (SecuredShort)obj;
+ return hiddenValue == ob.hiddenValue;
+ }
+
+ public bool Equals(SecuredShort obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredShort.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredShort.cs.meta
new file mode 100644
index 0000000..7e8eb67
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredShort.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 24e2ce5a06a143c493e3aa72fb25291d
+timeCreated: 1710059696
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredString.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredString.cs
new file mode 100644
index 0000000..ee72526
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredString.cs
@@ -0,0 +1,258 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured String Type
+ ///
+ [System.Serializable]
+ public sealed class SecuredString
+ {
+ private static string cryptoKey = "4441";
+
+#if UNITY_EDITOR
+ public static string cryptoKeyEditor = cryptoKey;
+#endif
+
+ // Serialized Params
+ [SerializeField] private string currentCryptoKey;
+ [SerializeField] private byte[] hiddenValue;
+ [SerializeField] private string fakeValue;
+ [SerializeField] private bool inited;
+
+
+ // for serialization purposes
+ private SecuredString(){}
+
+ private SecuredString(byte[] value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = null;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(string newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = InternalEncrypt(InternalDecrypt());
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static string EncryptDecrypt(string value)
+ {
+ return EncryptDecrypt(value, "");
+ }
+
+ public static string EncryptDecrypt(string value, string key)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return "";
+ }
+
+ if (string.IsNullOrEmpty(key))
+ {
+ key = cryptoKey;
+ }
+
+ int keyLength = key.Length;
+ int valueLength = value.Length;
+
+ char[] result = new char[valueLength];
+
+ for (int i = 0; i < valueLength; i++)
+ {
+ result[i] = (char)(value[i] ^ key[i % keyLength]);
+ }
+
+ return new string(result);
+ }
+
+ public string GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return GetString(hiddenValue);
+ }
+
+ public void SetEncrypted(string encrypted)
+ {
+ inited = true;
+ hiddenValue = GetBytes(encrypted);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private static byte[] InternalEncrypt(string value)
+ {
+ return GetBytes(EncryptDecrypt(value, cryptoKey));
+ }
+
+ private string InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = InternalEncrypt("");
+ fakeValue = "";
+ inited = true;
+ }
+
+ string key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ if (string.IsNullOrEmpty(key))
+ {
+ key = cryptoKey;
+ }
+
+ string result = EncryptDecrypt(GetString(hiddenValue), key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector!=null && !string.IsNullOrEmpty(fakeValue) && result != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return result;
+ }
+
+ public static implicit operator SecuredString(string value)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+
+ SecuredString obscured = new SecuredString(InternalEncrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator string(SecuredString value)
+ {
+ if (value == null)
+ {
+ return null;
+ }
+ return value.InternalDecrypt();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt();
+ }
+
+ public static bool operator ==(SecuredString a, SecuredString b)
+ {
+ if (ReferenceEquals(a, b))
+ {
+ return true;
+ }
+
+ if (((object)a == null) || ((object)b == null))
+ {
+ return false;
+ }
+
+ return ArraysEquals(a.hiddenValue, b.hiddenValue);
+ }
+
+ public static bool operator !=(SecuredString a, SecuredString b)
+ {
+ return !(a == b);
+ }
+
+ public override bool Equals(object obj)
+ {
+ SecuredString strA = obj as SecuredString;
+ string strB = null;
+ if (strA != null) strB = GetString(strA.hiddenValue);
+
+ return string.Equals(hiddenValue, strB);
+ }
+
+ public bool Equals(SecuredString value)
+ {
+ byte[] a = null;
+ if (value != null) a = value.hiddenValue;
+
+ return ArraysEquals(hiddenValue, a);
+ }
+
+ public bool Equals(SecuredString value, StringComparison comparisonType)
+ {
+ string strA = null;
+ if (value != null) strA = value.InternalDecrypt();
+
+ return string.Equals(InternalDecrypt(), strA, comparisonType);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ static byte[] GetBytes(string str)
+ {
+ byte[] bytes = new byte[str.Length * sizeof(char)];
+ System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
+ return bytes;
+ }
+
+ static string GetString(byte[] bytes)
+ {
+ char[] chars = new char[bytes.Length / sizeof(char)];
+ System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
+ return new string(chars);
+ }
+
+ static bool ArraysEquals(byte[] a1, byte[] a2)
+ {
+ if (a1 == a2)
+ {
+ return true;
+ }
+
+ if ((a1 != null) && (a2 != null))
+ {
+ if (a1.Length != a2.Length)
+ {
+ return false;
+ }
+ for (int i = 0; i < a1.Length; i++)
+ {
+ if (a1[i] != a2[i])
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredString.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredString.cs.meta
new file mode 100644
index 0000000..c8ada79
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredString.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 82a2cf53e201405daf6b2f7bbfb61d05
+timeCreated: 1710059739
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUInt.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUInt.cs
new file mode 100644
index 0000000..3546eeb
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUInt.cs
@@ -0,0 +1,202 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured UInt Type
+ ///
+ [System.Serializable]
+ public class SecuredUInt : IEquatable, IFormattable
+ {
+ private static uint cryptoKey = 240513;
+
+#if UNITY_EDITOR
+ public static uint cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private uint currentCryptoKey;
+ [SerializeField] private uint hiddenValue;
+ [SerializeField] private uint fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredUInt(uint value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(uint newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static uint Encrypt(uint value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static uint Decrypt(uint value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static uint Encrypt(uint value, uint key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public static uint Decrypt(uint value, uint key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public uint GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(uint encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private uint InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ uint key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ uint decrypted = Decrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredUInt(uint value)
+ {
+ SecuredUInt obscured = new SecuredUInt(Encrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator uint(SecuredUInt value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredUInt operator ++(SecuredUInt input)
+ {
+ uint decrypted = input.InternalDecrypt() + 1;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredUInt operator --(SecuredUInt input)
+ {
+ uint decrypted = input.InternalDecrypt() - 1;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredUInt))
+ return false;
+
+ SecuredUInt oi = (SecuredUInt)obj;
+ return ((int)hiddenValue == (int)oi.hiddenValue);
+ }
+
+ public bool Equals(SecuredUInt obj)
+ {
+ return (int)hiddenValue == (int)obj.hiddenValue;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUInt.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUInt.cs.meta
new file mode 100644
index 0000000..f115dc3
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUInt.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: dc8db2b8463e4ecdb83437b9553fc88a
+timeCreated: 1710060022
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredULong.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredULong.cs
new file mode 100644
index 0000000..fd9e842
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredULong.cs
@@ -0,0 +1,203 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured ULong Type
+ ///
+ [System.Serializable]
+ public class SecuredULong : IEquatable, IFormattable
+ {
+ private static ulong cryptoKey = 444443L;
+
+#if UNITY_EDITOR
+ public static ulong cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private ulong currentCryptoKey;
+ [SerializeField] private ulong hiddenValue;
+ [SerializeField] private ulong fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredULong(ulong value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(ulong newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static ulong Encrypt(ulong value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static ulong Decrypt(ulong value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static ulong Encrypt(ulong value, ulong key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public static ulong Decrypt(ulong value, ulong key)
+ {
+ if (key == 0)
+ {
+ return value ^ cryptoKey;
+ }
+ return value ^ key;
+ }
+
+ public ulong GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(ulong encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private ulong InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ ulong key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ ulong decrypted = Decrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredULong(ulong value)
+ {
+ SecuredULong obscured = new SecuredULong(Encrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator ulong(SecuredULong value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredULong operator ++(SecuredULong input)
+ {
+ ulong decrypted = input.InternalDecrypt() + 1L;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredULong operator --(SecuredULong input)
+ {
+ ulong decrypted = input.InternalDecrypt() - 1L;
+ input.hiddenValue = Encrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredULong))
+ return false;
+
+ SecuredULong o = (SecuredULong)obj;
+ return (hiddenValue == o.hiddenValue);
+ }
+
+ public bool Equals(SecuredULong obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredULong.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredULong.cs.meta
new file mode 100644
index 0000000..0df6e01
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredULong.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6b343a73173c4ffc82562ed93428a8e0
+timeCreated: 1710060033
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUShort.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUShort.cs
new file mode 100644
index 0000000..e0ca7f9
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUShort.cs
@@ -0,0 +1,188 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured UShort Type
+ ///
+ [System.Serializable]
+ public class SecuredUShort : IEquatable, IFormattable
+ {
+ private static ushort cryptoKey = 224;
+
+#if UNITY_EDITOR
+ public static ushort cryptoKeyEditor = cryptoKey;
+#endif
+
+ [SerializeField] private ushort currentCryptoKey;
+ [SerializeField] private ushort hiddenValue;
+ [SerializeField] private ushort fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredUShort(ushort value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = 0;
+ inited = true;
+ }
+
+ public static void SetNewCryptoKey(ushort newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = EncryptDecrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static ushort EncryptDecrypt(ushort value)
+ {
+ return EncryptDecrypt(value, 0);
+ }
+
+ public static ushort EncryptDecrypt(ushort value, ushort key)
+ {
+ if (key == 0)
+ {
+ return (ushort)(value ^ cryptoKey);
+ }
+ return (ushort)(value ^ key);
+ }
+
+ public ushort GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(ushort encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private ushort InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = EncryptDecrypt(0);
+ fakeValue = 0;
+ inited = true;
+ }
+
+ ushort key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ ushort decrypted = EncryptDecrypt(hiddenValue, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && fakeValue != 0 && decrypted != fakeValue)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return decrypted;
+ }
+
+ public static implicit operator SecuredUShort(ushort value)
+ {
+ SecuredUShort obscured = new SecuredUShort(EncryptDecrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator ushort(SecuredUShort value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public static SecuredUShort operator ++(SecuredUShort input)
+ {
+ ushort decrypted = (ushort)(input.InternalDecrypt() + 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public static SecuredUShort operator --(SecuredUShort input)
+ {
+ ushort decrypted = (ushort)(input.InternalDecrypt() - 1);
+ input.hiddenValue = EncryptDecrypt(decrypted, input.currentCryptoKey);
+
+ if (GameShield.Main.GetModule() != null)
+ {
+ input.fakeValue = decrypted;
+ }
+ return input;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (!(obj is SecuredUShort))
+ return false;
+
+ SecuredUShort ob = (SecuredUShort)obj;
+ return hiddenValue == ob.hiddenValue;
+ }
+
+ public bool Equals(SecuredUShort obj)
+ {
+ return hiddenValue == obj.hiddenValue;
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public string ToString(IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(provider);
+ }
+
+ public string ToString(string format, IFormatProvider provider)
+ {
+ return InternalDecrypt().ToString(format, provider);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUShort.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUShort.cs.meta
new file mode 100644
index 0000000..e98c171
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredUShort.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b6a65dd65de04269983b3ea94ae5ed35
+timeCreated: 1710060042
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector2.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector2.cs
new file mode 100644
index 0000000..6f82d42
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector2.cs
@@ -0,0 +1,288 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Vector2 Type
+ ///
+ [System.Serializable]
+ public struct SecuredVector2
+ {
+ private static int cryptoKey = 120206;
+ private static readonly Vector2 initialFakeValue = Vector2.zero;
+
+#if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+#endif
+
+ // Serialized Fields
+ [SerializeField] private int currentCryptoKey;
+ [SerializeField] private RawEncryptedVector2 hiddenValue;
+ [SerializeField] private Vector2 fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredVector2(RawEncryptedVector2 value)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = value;
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ public float x
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.x);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.x) > protector.Config.Vector2Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.x = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.x = value;
+ }
+ }
+ }
+
+ public float y
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.y);
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.y) > protector.Config.Vector2Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.y = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.y = value;
+ }
+ }
+ }
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredVector2 index!");
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredVector2 index!");
+ }
+ }
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static RawEncryptedVector2 Encrypt(Vector2 value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static RawEncryptedVector2 Encrypt(Vector2 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ RawEncryptedVector2 result;
+ result.x = SecuredFloat.Encrypt(value.x, key);
+ result.y = SecuredFloat.Encrypt(value.y, key);
+
+ return result;
+ }
+
+ public static Vector2 Decrypt(RawEncryptedVector2 value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static Vector2 Decrypt(RawEncryptedVector2 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ Vector2 result;
+ result.x = SecuredFloat.Decrypt(value.x, key);
+ result.y = SecuredFloat.Decrypt(value.y, key);
+
+ return result;
+ }
+
+ public RawEncryptedVector2 GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(RawEncryptedVector2 encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private Vector2 InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(initialFakeValue);
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ Vector2 value;
+
+ value.x = SecuredFloat.Decrypt(hiddenValue.x, key);
+ value.y = SecuredFloat.Decrypt(hiddenValue.y, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && !fakeValue.Equals(initialFakeValue) && !CompareVectorsWithTolerance(value, fakeValue))
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return value;
+ }
+
+ private bool CompareVectorsWithTolerance(Vector2 vector1, Vector2 vector2)
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float epsilon = (protector != null) ? protector.Config.Vector2Epsilon : 0.1f;
+ return Math.Abs(vector1.x - vector2.x) < epsilon &&
+ Math.Abs(vector1.y - vector2.y) < epsilon;
+ }
+
+ private float InternalDecryptField(int encrypted)
+ {
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ float result = SecuredFloat.Decrypt(encrypted, key);
+ return result;
+ }
+
+ private int InternalEncryptField(float encrypted)
+ {
+ int result = SecuredFloat.Encrypt(encrypted, cryptoKey);
+ return result;
+ }
+
+ public static implicit operator SecuredVector2(Vector2 value)
+ {
+ SecuredVector2 obscured = new SecuredVector2(Encrypt(value));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator Vector2(SecuredVector2 value)
+ {
+ return value.InternalDecrypt();
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ [System.Serializable]
+ public struct RawEncryptedVector2
+ {
+ public int x;
+ public int y;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector2.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector2.cs.meta
new file mode 100644
index 0000000..300bcff
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector2.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5be7db2a3a054d3ba400020e3d1ed4a9
+timeCreated: 1710060394
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector3.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector3.cs
new file mode 100644
index 0000000..ca6f142
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector3.cs
@@ -0,0 +1,399 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Vector3 Type
+ ///
+ [System.Serializable]
+ public struct SecuredVector3
+ {
+ private static int cryptoKey = 120207;
+ private static readonly Vector3 initialFakeValue = Vector3.zero;
+
+#if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+#endif
+
+ // Serialized Fields
+ [SerializeField] private int currentCryptoKey;
+ [SerializeField] private RawEncryptedVector3 hiddenValue;
+ [SerializeField] private Vector3 fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredVector3(RawEncryptedVector3 encrypted)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = encrypted;
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ public float x
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.x);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.x) > protector.Config.Vector3Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.x = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.x = value;
+ }
+ }
+ }
+
+ public float y
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.y);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.y) > protector.Config.Vector3Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.y = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.y = value;
+ }
+ }
+ }
+
+ public float z
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.z);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.z) > protector.Config.Vector3Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.z = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.z = value;
+ }
+ }
+ }
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredVector3 index!");
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredVector3 index!");
+ }
+ }
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static RawEncryptedVector3 Encrypt(Vector3 value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static RawEncryptedVector3 Encrypt(Vector3 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ RawEncryptedVector3 result;
+ result.x = SecuredFloat.Encrypt(value.x, key);
+ result.y = SecuredFloat.Encrypt(value.y, key);
+ result.z = SecuredFloat.Encrypt(value.z, key);
+
+ return result;
+ }
+
+ public static Vector3 Decrypt(RawEncryptedVector3 value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static Vector3 Decrypt(RawEncryptedVector3 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ Vector3 result;
+ result.x = SecuredFloat.Decrypt(value.x, key);
+ result.y = SecuredFloat.Decrypt(value.y, key);
+ result.z = SecuredFloat.Decrypt(value.z, key);
+
+ return result;
+ }
+
+ public RawEncryptedVector3 GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(RawEncryptedVector3 encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private Vector3 InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(initialFakeValue, cryptoKey);
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ Vector3 value;
+
+ value.x = SecuredFloat.Decrypt(hiddenValue.x, key);
+ value.y = SecuredFloat.Decrypt(hiddenValue.y, key);
+ value.z = SecuredFloat.Decrypt(hiddenValue.z, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector!=null && !fakeValue.Equals(Vector3.zero) && !CompareVectorsWithTolerance(value, fakeValue))
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return value;
+ }
+
+ private bool CompareVectorsWithTolerance(Vector3 vector1, Vector3 vector2)
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float epsilon = (protector!=null) ? protector.Config.Vector3Epsilon : 0.1f;
+ return Math.Abs(vector1.x - vector2.x) < epsilon &&
+ Math.Abs(vector1.y - vector2.y) < epsilon &&
+ Math.Abs(vector1.z - vector2.z) < epsilon;
+ }
+
+ private float InternalDecryptField(int encrypted)
+ {
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ float result = SecuredFloat.Decrypt(encrypted, key);
+ return result;
+ }
+
+ private int InternalEncryptField(float encrypted)
+ {
+ int result = SecuredFloat.Encrypt(encrypted, cryptoKey);
+ return result;
+ }
+
+ #region Operators
+ public static implicit operator SecuredVector3(Vector3 value)
+ {
+ SecuredVector3 obscured = new SecuredVector3(Encrypt(value, cryptoKey));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator Vector3(SecuredVector3 value)
+ {
+ return value.InternalDecrypt();
+ }
+ public static SecuredVector3 operator +(SecuredVector3 a, SecuredVector3 b)
+ {
+ return a.InternalDecrypt() + b.InternalDecrypt();
+ }
+ public static SecuredVector3 operator +(Vector3 a, SecuredVector3 b)
+ {
+ return a + b.InternalDecrypt();
+ }
+ public static SecuredVector3 operator +(SecuredVector3 a, Vector3 b)
+ {
+ return a.InternalDecrypt() + b;
+ }
+ public static SecuredVector3 operator -(SecuredVector3 a, SecuredVector3 b)
+ {
+ return a.InternalDecrypt() - b.InternalDecrypt();
+ }
+ public static SecuredVector3 operator -(Vector3 a, SecuredVector3 b)
+ {
+ return a - b.InternalDecrypt();
+ }
+ public static SecuredVector3 operator -(SecuredVector3 a, Vector3 b)
+ {
+ return a.InternalDecrypt() - b;
+ }
+ public static SecuredVector3 operator -(SecuredVector3 a)
+ {
+ return -a.InternalDecrypt();
+ }
+ public static SecuredVector3 operator *(SecuredVector3 a, float d)
+ {
+ return a.InternalDecrypt() * d;
+ }
+ public static SecuredVector3 operator *(float d, SecuredVector3 a)
+ {
+ return d * a.InternalDecrypt();
+ }
+ public static SecuredVector3 operator /(SecuredVector3 a, float d)
+ {
+ return a.InternalDecrypt() / d;
+ }
+
+ public static bool operator ==(SecuredVector3 lhs, SecuredVector3 rhs)
+ {
+ return lhs.InternalDecrypt() == rhs.InternalDecrypt();
+ }
+ public static bool operator ==(Vector3 lhs, SecuredVector3 rhs)
+ {
+ return lhs == rhs.InternalDecrypt();
+ }
+ public static bool operator ==(SecuredVector3 lhs, Vector3 rhs)
+ {
+ return lhs.InternalDecrypt() == rhs;
+ }
+
+ public static bool operator !=(SecuredVector3 lhs, SecuredVector3 rhs)
+ {
+ return lhs.InternalDecrypt() != rhs.InternalDecrypt();
+ }
+ public static bool operator !=(Vector3 lhs, SecuredVector3 rhs)
+ {
+ return lhs != rhs.InternalDecrypt();
+ }
+ public static bool operator !=(SecuredVector3 lhs, Vector3 rhs)
+ {
+ return lhs.InternalDecrypt() != rhs;
+ }
+ #endregion
+
+ public override bool Equals(object other)
+ {
+ return InternalDecrypt().Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ [System.Serializable]
+ public struct RawEncryptedVector3
+ {
+ public int x;
+ public int y;
+ public int z;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector3.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector3.cs.meta
new file mode 100644
index 0000000..7b16d07
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector3.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5dc2ed386abc4d30bcb84b63bb8a060b
+timeCreated: 1710060421
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector4.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector4.cs
new file mode 100644
index 0000000..11314aa
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector4.cs
@@ -0,0 +1,437 @@
+using System;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Memory.SecuredTypes
+{
+ ///
+ /// Secured Vector4 Type
+ ///
+ [System.Serializable]
+ public struct SecuredVector4
+ {
+ private static int cryptoKey = 120207;
+ private static readonly Vector4 initialFakeValue = Vector4.zero;
+
+#if UNITY_EDITOR
+ public static int cryptoKeyEditor = cryptoKey;
+#endif
+
+ // Serialized Fields
+ [SerializeField] private int currentCryptoKey;
+ [SerializeField] private RawEncryptedVector4 hiddenValue;
+ [SerializeField] private Vector4 fakeValue;
+ [SerializeField] private bool inited;
+
+ private SecuredVector4(RawEncryptedVector4 encrypted)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = encrypted;
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ public float x
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.x);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.x) > protector.Config.Vector4Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.x = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.x = value;
+ }
+ }
+ }
+
+ public float y
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.y);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.y) > protector.Config.Vector4Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.y = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.y = value;
+ }
+ }
+ }
+
+ public float z
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.z);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.z) > protector.Config.Vector4Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.z = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.z = value;
+ }
+ }
+ }
+
+ public float w
+ {
+ get
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float decrypted = InternalDecryptField(hiddenValue.w);
+ if (protector!=null && !fakeValue.Equals(initialFakeValue) && Math.Abs(decrypted - fakeValue.w) > protector.Config.Vector4Epsilon)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+ return decrypted;
+ }
+
+ set
+ {
+ hiddenValue.w = InternalEncryptField(value);
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue.w = value;
+ }
+ }
+ }
+
+ public float this[int index]
+ {
+ get
+ {
+ switch (index)
+ {
+ case 0:
+ return x;
+ case 1:
+ return y;
+ case 2:
+ return z;
+ case 3:
+ return w;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredVector3 index!");
+ }
+ }
+ set
+ {
+ switch (index)
+ {
+ case 0:
+ x = value;
+ break;
+ case 1:
+ y = value;
+ break;
+ case 2:
+ z = value;
+ break;
+ case 3:
+ w = value;
+ break;
+ default:
+ throw new IndexOutOfRangeException("Invalid SecuredVector3 index!");
+ }
+ }
+ }
+
+ public static void SetNewCryptoKey(int newKey)
+ {
+ cryptoKey = newKey;
+ }
+
+ public void ApplyNewCryptoKey()
+ {
+ if (currentCryptoKey != cryptoKey)
+ {
+ hiddenValue = Encrypt(InternalDecrypt(), cryptoKey);
+ currentCryptoKey = cryptoKey;
+ }
+ }
+
+ public static RawEncryptedVector4 Encrypt(Vector4 value)
+ {
+ return Encrypt(value, 0);
+ }
+
+ public static RawEncryptedVector4 Encrypt(Vector4 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ RawEncryptedVector4 result;
+ result.x = SecuredFloat.Encrypt(value.x, key);
+ result.y = SecuredFloat.Encrypt(value.y, key);
+ result.z = SecuredFloat.Encrypt(value.z, key);
+ result.w = SecuredFloat.Encrypt(value.w, key);
+
+ return result;
+ }
+
+ public static Vector4 Decrypt(RawEncryptedVector4 value)
+ {
+ return Decrypt(value, 0);
+ }
+
+ public static Vector4 Decrypt(RawEncryptedVector4 value, int key)
+ {
+ if (key == 0)
+ {
+ key = cryptoKey;
+ }
+
+ Vector4 result;
+ result.x = SecuredFloat.Decrypt(value.x, key);
+ result.y = SecuredFloat.Decrypt(value.y, key);
+ result.z = SecuredFloat.Decrypt(value.z, key);
+ result.w = SecuredFloat.Decrypt(value.w, key);
+
+ return result;
+ }
+
+ public RawEncryptedVector4 GetEncrypted()
+ {
+ ApplyNewCryptoKey();
+ return hiddenValue;
+ }
+
+ public void SetEncrypted(RawEncryptedVector4 encrypted)
+ {
+ inited = true;
+ hiddenValue = encrypted;
+ if (GameShield.Main.GetModule() != null)
+ {
+ fakeValue = InternalDecrypt();
+ }
+ }
+
+ private Vector4 InternalDecrypt()
+ {
+ if (!inited)
+ {
+ currentCryptoKey = cryptoKey;
+ hiddenValue = Encrypt(initialFakeValue, cryptoKey);
+ fakeValue = initialFakeValue;
+ inited = true;
+ }
+
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ Vector4 value;
+
+ value.x = SecuredFloat.Decrypt(hiddenValue.x, key);
+ value.y = SecuredFloat.Decrypt(hiddenValue.y, key);
+ value.z = SecuredFloat.Decrypt(hiddenValue.z, key);
+ value.w = SecuredFloat.Decrypt(hiddenValue.w, key);
+
+ MemoryProtector protector = GameShield.Main.GetModule();
+ if (protector != null && !fakeValue.Equals(Vector4.zero) && !CompareVectorsWithTolerance(value, fakeValue))
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 101,
+ Message = MemoryWarnings.TypeHackWarning,
+ IsCritical = true,
+ Module = protector
+ });
+ }
+
+ return value;
+ }
+
+ private bool CompareVectorsWithTolerance(Vector4 vector1, Vector4 vector2)
+ {
+ MemoryProtector protector = GameShield.Main.GetModule();
+ float epsilon = (protector!=null) ? protector.Config.Vector4Epsilon : 0.1f;
+ return Math.Abs(vector1.x - vector2.x) < epsilon &&
+ Math.Abs(vector1.y - vector2.y) < epsilon &&
+ Math.Abs(vector1.z - vector2.z) < epsilon &&
+ Math.Abs(vector1.w - vector2.w) < epsilon;
+ }
+
+ private float InternalDecryptField(int encrypted)
+ {
+ int key = cryptoKey;
+
+ if (currentCryptoKey != cryptoKey)
+ {
+ key = currentCryptoKey;
+ }
+
+ float result = SecuredFloat.Decrypt(encrypted, key);
+ return result;
+ }
+
+ private int InternalEncryptField(float encrypted)
+ {
+ int result = SecuredFloat.Encrypt(encrypted, cryptoKey);
+ return result;
+ }
+
+ #region Operators
+ public static implicit operator SecuredVector4(Vector4 value)
+ {
+ SecuredVector4 obscured = new SecuredVector4(Encrypt(value, cryptoKey));
+ if (GameShield.Main.GetModule() != null)
+ {
+ obscured.fakeValue = value;
+ }
+ return obscured;
+ }
+ public static implicit operator Vector4(SecuredVector4 value)
+ {
+ return value.InternalDecrypt();
+ }
+ public static SecuredVector4 operator +(SecuredVector4 a, SecuredVector4 b)
+ {
+ return a.InternalDecrypt() + b.InternalDecrypt();
+ }
+ public static SecuredVector4 operator +(Vector4 a, SecuredVector4 b)
+ {
+ return a + b.InternalDecrypt();
+ }
+ public static SecuredVector4 operator +(SecuredVector4 a, Vector4 b)
+ {
+ return a.InternalDecrypt() + b;
+ }
+ public static SecuredVector4 operator -(SecuredVector4 a, SecuredVector4 b)
+ {
+ return a.InternalDecrypt() - b.InternalDecrypt();
+ }
+ public static SecuredVector4 operator -(Vector4 a, SecuredVector4 b)
+ {
+ return a - b.InternalDecrypt();
+ }
+ public static SecuredVector4 operator -(SecuredVector4 a, Vector4 b)
+ {
+ return a.InternalDecrypt() - b;
+ }
+ public static SecuredVector4 operator -(SecuredVector4 a)
+ {
+ return -a.InternalDecrypt();
+ }
+ public static SecuredVector4 operator *(SecuredVector4 a, float d)
+ {
+ return a.InternalDecrypt() * d;
+ }
+ public static SecuredVector4 operator *(float d, SecuredVector4 a)
+ {
+ return d * a.InternalDecrypt();
+ }
+ public static SecuredVector4 operator /(SecuredVector4 a, float d)
+ {
+ return a.InternalDecrypt() / d;
+ }
+
+ public static bool operator ==(SecuredVector4 lhs, SecuredVector4 rhs)
+ {
+ return lhs.InternalDecrypt() == rhs.InternalDecrypt();
+ }
+ public static bool operator ==(Vector4 lhs, SecuredVector4 rhs)
+ {
+ return lhs == rhs.InternalDecrypt();
+ }
+ public static bool operator ==(SecuredVector4 lhs, Vector4 rhs)
+ {
+ return lhs.InternalDecrypt() == rhs;
+ }
+
+ public static bool operator !=(SecuredVector4 lhs, SecuredVector4 rhs)
+ {
+ return lhs.InternalDecrypt() != rhs.InternalDecrypt();
+ }
+ public static bool operator !=(Vector4 lhs, SecuredVector4 rhs)
+ {
+ return lhs != rhs.InternalDecrypt();
+ }
+ public static bool operator !=(SecuredVector4 lhs, Vector4 rhs)
+ {
+ return lhs.InternalDecrypt() != rhs;
+ }
+ #endregion
+
+ public override bool Equals(object other)
+ {
+ return InternalDecrypt().Equals(other);
+ }
+
+ public override int GetHashCode()
+ {
+ return InternalDecrypt().GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return InternalDecrypt().ToString();
+ }
+
+ public string ToString(string format)
+ {
+ return InternalDecrypt().ToString(format);
+ }
+
+ [System.Serializable]
+ public struct RawEncryptedVector4
+ {
+ public int x;
+ public int y;
+ public int z;
+ public int w;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector4.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector4.cs.meta
new file mode 100644
index 0000000..f824396
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Memory/SecuredTypes/SecuredVector4.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 5640e6bce9304f7a9ae3a6d21c13de90
+timeCreated: 1710060431
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/ModuleInfo.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/ModuleInfo.cs
new file mode 100644
index 0000000..8a8c595
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/ModuleInfo.cs
@@ -0,0 +1,9 @@
+namespace DevsDaddy.GameShield.Core.Modules
+{
+ public class ModuleInfo
+ {
+ public string Name = "";
+ public string Description = "";
+ public string DocumentationLink = "";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/ModuleInfo.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/ModuleInfo.cs.meta
new file mode 100644
index 0000000..2fa4452
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/ModuleInfo.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: cf04357a2da94d17ba3a5727156ae2a4
+timeCreated: 1710001653
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack.meta
new file mode 100644
index 0000000..8d2927d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: f8f0c349fa8c4192a4c72d824062c41f
+timeCreated: 1710016792
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackDetector.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackDetector.cs
new file mode 100644
index 0000000..0ca0d7e
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackDetector.cs
@@ -0,0 +1,196 @@
+using System;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.SpeedHack
+{
+ ///
+ /// SpeedHack Detector Module
+ ///
+ public class SpeedHackDetector : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ private const long TICKS_PER_SECOND = TimeSpan.TicksPerMillisecond * 1000;
+ private const int THRESHOLD = 5000000;
+
+ private float m_Interval = 1f;
+ private byte m_MaxFalsePositives = 3;
+ private int m_CoolDown = 30;
+
+ private byte m_CurrentFalsePositives;
+ private int m_CurrentCooldownShots;
+ private long m_TicksOnStart;
+ private long m_VulnerableTicksOnStart;
+ private long m_PrevTicks;
+ private long m_PrevIntervalTicks;
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ // Setup from Config
+ m_Interval = _currentOptions.Interval;
+ m_MaxFalsePositives = _currentOptions.MaxFalsePositives;
+ m_CoolDown = _currentOptions.CoolDown;
+
+ ResetStartTicks();
+ m_CurrentFalsePositives = 0;
+ m_CurrentCooldownShots = 0;
+ _isPaused = false;
+
+ // Fire Initialization Complete
+ EventMessenger.Main.Subscribe(OnGameLoopUpdate);
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Reset Startup Ticks
+ ///
+ private void ResetStartTicks()
+ {
+ m_TicksOnStart = DateTime.UtcNow.Ticks;
+ m_VulnerableTicksOnStart = System.Environment.TickCount * TimeSpan.TicksPerMillisecond;
+ m_PrevTicks = m_TicksOnStart;
+ m_PrevIntervalTicks = m_TicksOnStart;
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ // Fire Disconnected Complete
+ EventMessenger.Main.Unsubscribe(OnGameLoopUpdate);
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ if(!_isPaused) ResetStartTicks();
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// On Game Loop Updated
+ ///
+ ///
+ private void OnGameLoopUpdate(ApplicationLoopUpdated payload) {
+ if(_isPaused) return;
+
+ long ticks = DateTime.UtcNow.Ticks;
+ long ticksSpentSinceLastUpdate = ticks - m_PrevTicks;
+
+ if (ticksSpentSinceLastUpdate < 0 || ticksSpentSinceLastUpdate > TICKS_PER_SECOND)
+ {
+ if (Debug.isDebugBuild) Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} SpeedHack Detector: System DateTime change or > 1 second game freeze detected!");
+ ResetStartTicks();
+ return;
+ }
+ m_PrevTicks = ticks;
+
+ long intervalTicks = (long)(m_Interval * TICKS_PER_SECOND);
+ if (ticks - m_PrevIntervalTicks >= intervalTicks)
+ {
+ long vulnerableTicks = System.Environment.TickCount * TimeSpan.TicksPerMillisecond;
+ if (Mathf.Abs((vulnerableTicks - m_VulnerableTicksOnStart) - (ticks - m_TicksOnStart)) > THRESHOLD)
+ {
+ m_CurrentFalsePositives++;
+ if (m_CurrentFalsePositives > m_MaxFalsePositives)
+ {
+ if (Debug.isDebugBuild) Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} SpeedHackDetector: final detection!");
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 321,
+ Message = SpeedHackWarnings.SpeedHackDetected,
+ IsCritical = true,
+ Module = this
+ });
+ PauseDetector(true);
+ }
+ else
+ {
+ if (Debug.isDebugBuild) Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} SpeedHackDetector: detection! Allowed false positives left: " + (m_MaxFalsePositives - m_CurrentFalsePositives));
+ m_CurrentCooldownShots = 0;
+ ResetStartTicks();
+ }
+ }
+ else if (m_CurrentFalsePositives > 0 && m_CoolDown > 0)
+ {
+ if (Debug.isDebugBuild) Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} SpeedHackDetector: success shot! Shots till Cooldown: " + (m_CoolDown - m_CurrentCooldownShots));
+ m_CurrentCooldownShots++;
+ if (m_CurrentCooldownShots >= m_CoolDown)
+ {
+ if (Debug.isDebugBuild) Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} SpeedHackDetector: Cooldown!");
+ m_CurrentFalsePositives = 0;
+ }
+ }
+
+ m_PrevIntervalTicks = ticks;
+ }
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "SpeedHack Detector",
+ Description = "The module allows you to track time acceleration attempts to change character speeds in-game, by monitoring the real time flow and frame time.",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#speedhack-detector"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+ public float Interval = 1f;
+ public byte MaxFalsePositives = 3;
+ public int CoolDown = 30;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackDetector.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackDetector.cs.meta
new file mode 100644
index 0000000..a2852b5
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackDetector.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 4dccb72eb2f04a878a2772b18d6b7ee7
+timeCreated: 1710017392
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackWarnings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackWarnings.cs
new file mode 100644
index 0000000..e136be5
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackWarnings.cs
@@ -0,0 +1,7 @@
+namespace DevsDaddy.GameShield.Core.Modules.SpeedHack
+{
+ public static class SpeedHackWarnings
+ {
+ public const string SpeedHackDetected = "The system detected a mismatch in the time intervals between the tacts of the game cycle. You may be using a game speed cheat.";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackWarnings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackWarnings.cs.meta
new file mode 100644
index 0000000..0fe8c12
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/SpeedHack/SpeedHackWarnings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 7ce569244338436c96c6a70d18966422
+timeCreated: 1710085737
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport.meta
new file mode 100644
index 0000000..e41ca0c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 7d0ffba3f34542cf86ebfb22d58d234a
+timeCreated: 1710016798
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportDetector.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportDetector.cs
new file mode 100644
index 0000000..40ccc19
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportDetector.cs
@@ -0,0 +1,171 @@
+using System.Collections.Generic;
+using System.Linq;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Teleport
+{
+ ///
+ /// Teleport Detector Module
+ ///
+ public class TeleportDetector : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ private float timeToCheck = 1f;
+ private float interval = 1f;
+
+ private List _targets = new List();
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ _targets = _currentOptions.targets;
+ interval = _currentOptions.Interval;
+ timeToCheck = interval;
+
+ if(_targets.Count < 1)
+ Debug.LogWarning($"{GeneralStrings.LOG_PREFIX} No Target setup to Teleport Detector. Please, use AddTarget() to initialize detection.");
+
+ _isPaused = false;
+
+ // Fire Initialization Complete
+ EventMessenger.Main.Subscribe(OnGameLoopUpdate);
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Add Teleport Target
+ ///
+ ///
+ public void AddTarget(TeleportTargetChecker target) {
+ if(_targets.Contains(target)) return;
+ _targets.Add(target);
+ interval = _currentOptions.Interval;
+ timeToCheck = _currentOptions.Interval;
+ }
+
+ ///
+ /// Remove Target
+ ///
+ ///
+ public void RemoveTarget(TeleportTargetChecker target) {
+ if (_targets.Contains(target))
+ _targets.Remove(target);
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ EventMessenger.Main.Unsubscribe(OnGameLoopUpdate);
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// On Game Loop Updated
+ ///
+ ///
+ private void OnGameLoopUpdate(ApplicationLoopUpdated payload) {
+ if(_isPaused || _targets.Count < 1) return;
+
+ if (timeToCheck <= 0f)
+ {
+ foreach (var target in _targets) {
+ if(target == null || target.Target == null) continue;
+ if (target.LastPosition != Vector3.zero) {
+ float distance = Vector3.Distance(target.LastPosition, target.Target.position);
+ if (distance > target.MaxSpeed)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 422,
+ Message = string.Format(TeleportWarnings.TeleportCheating, target.Target.gameObject.name),
+ IsCritical = true,
+ Module = this
+ });
+ PauseDetector(true);
+ }
+ }
+
+ target.LastPosition = target.Target.position;
+ }
+
+ timeToCheck = interval;
+ }
+ else
+ {
+ timeToCheck -= payload.DeltaTime;
+ }
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Teleport Detector",
+ Description = "This module tracks a player's maximum allowable movements based on their speed to check for teleportation hacks",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#teleport-detector"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+ public List targets = new List();
+ public float Interval = 1f;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportDetector.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportDetector.cs.meta
new file mode 100644
index 0000000..535f810
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportDetector.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 70c1352523b04d339d0a3dfe1da87b53
+timeCreated: 1710017884
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportTargetChecker.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportTargetChecker.cs
new file mode 100644
index 0000000..b39fd55
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportTargetChecker.cs
@@ -0,0 +1,11 @@
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.Teleport
+{
+ public class TeleportTargetChecker
+ {
+ public Transform Target;
+ public Vector3 LastPosition;
+ public float MaxSpeed = 3f;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportTargetChecker.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportTargetChecker.cs.meta
new file mode 100644
index 0000000..7080d6e
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportTargetChecker.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 9ffa490ea10d4e2f8020158be33012ad
+timeCreated: 1710315907
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportWarnings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportWarnings.cs
new file mode 100644
index 0000000..4eeeb04
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportWarnings.cs
@@ -0,0 +1,7 @@
+namespace DevsDaddy.GameShield.Core.Modules.Teleport
+{
+ public static class TeleportWarnings
+ {
+ public const string TeleportCheating = "The system detected unnatural movement of the {0} entity. You may have used a cheat to teleport your character.";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportWarnings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportWarnings.cs.meta
new file mode 100644
index 0000000..26c8bf8
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Teleport/TeleportWarnings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: c0448231d45f44208c2258b042c08ba3
+timeCreated: 1710086311
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time.meta
new file mode 100644
index 0000000..dcc4e6a
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2e9f965d7903409d893d072a059efec0
+timeCreated: 1710016830
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeProtector.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeProtector.cs
new file mode 100644
index 0000000..9c42343
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeProtector.cs
@@ -0,0 +1,293 @@
+using System;
+using System.Collections;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+using UnityEngine.Networking;
+
+namespace DevsDaddy.GameShield.Core.Modules.Time
+{
+ ///
+ /// Time Skip Protector Module
+ ///
+ public class TimeProtector : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ private float timeCheckInterval = 10f;
+ private long availableTolerance = 60;
+ private bool networkCompare = true;
+
+ private float timeToCheck = 10f;
+ private long lastTime = 0;
+ private long lastLocalTime = 0;
+
+
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ timeCheckInterval = _currentOptions.CheckingInterval;
+ availableTolerance = _currentOptions.AvailableTolerance;
+ networkCompare = _currentOptions.NetworkCompare;
+ timeToCheck = timeCheckInterval;
+
+ CompareTime();
+
+ // Fire Initialization Complete
+ EventMessenger.Main.Subscribe(OnLoopUpdated);
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ // Fire Disconnected Complete
+ EventMessenger.Main.Unsubscribe(OnLoopUpdated);
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// On Application Loop Updated
+ ///
+ ///
+ private void OnLoopUpdated(ApplicationLoopUpdated payload) {
+ if(_isPaused) return;
+ if (timeToCheck <= 0f)
+ {
+ CompareTime();
+ }
+ else
+ {
+ timeToCheck -= payload.DeltaTime;
+ }
+ }
+
+ ///
+ /// Compare Timings
+ ///
+ private void CompareTime() {
+ long currentNetworkTime = 0;
+ long currentLocalTime = GetCurrentLocalTime();
+
+ if (networkCompare)
+ {
+ GetCurrentNetworkTime(time =>
+ {
+ currentNetworkTime = time;
+ if (lastTime == 0)
+ {
+ lastTime = currentNetworkTime;
+ lastLocalTime = currentLocalTime;
+ }
+ else
+ {
+ CompareTwoTimestamps(currentNetworkTime, currentLocalTime);
+ }
+ }, () => {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 244,
+ IsCritical = true,
+ Message = TimeWarnings.NetworkTimeError,
+ Module = this
+ });
+ PauseDetector(true);
+ });
+ }
+ else
+ {
+ currentNetworkTime = GetCurrentLocalTime();
+ if (lastTime == 0)
+ {
+ lastTime = currentNetworkTime;
+ lastLocalTime = currentLocalTime;
+ }
+ else
+ {
+ CompareTwoTimestamps(currentNetworkTime, currentLocalTime);
+ }
+ }
+ }
+
+ ///
+ /// Compare Two Timestamps
+ ///
+ ///
+ ///
+ void CompareTwoTimestamps(long currentNetworkTime, long currentLocalTime)
+ {
+ long networkTimeDiff = 0;
+ long localTimeDiff = 0;
+ long avgTimeDiff = 0;
+
+ networkTimeDiff = currentNetworkTime - lastTime;
+ localTimeDiff = currentLocalTime - lastLocalTime;
+ avgTimeDiff = (localTimeDiff > networkTimeDiff)
+ ? localTimeDiff - networkTimeDiff
+ : networkTimeDiff - localTimeDiff;
+ if (avgTimeDiff > availableTolerance)
+ {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Code = 245,
+ IsCritical = true,
+ Message = TimeWarnings.TimeCheating,
+ Module = this
+ });
+ PauseDetector(true);
+ return;
+ }
+
+ lastTime = currentNetworkTime;
+ lastLocalTime = currentLocalTime;
+ }
+
+ ///
+ /// Get Current Network Time
+ ///
+ ///
+ ///
+ private void GetCurrentNetworkTime(Action onTimeRecieved, Action onRequestError) {
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = RequestNetworkTime(onTimeRecieved, onRequestError),
+ Id = "NetworkTimeCompare"
+ });
+ }
+
+ ///
+ /// Request Network Time
+ ///
+ ///
+ ///
+ ///
+ private IEnumerator RequestNetworkTime(Action onTimeRecieved, Action onRequestError)
+ {
+ UnityWebRequest webRequest = new UnityWebRequest(_currentOptions.NetworkServer, "GET");
+ DownloadHandlerBuffer dH = new DownloadHandlerBuffer();
+ webRequest.downloadHandler = dH;
+ yield return webRequest.SendWebRequest();
+ if (webRequest.result == UnityWebRequest.Result.Success)
+ {
+ NetworkTimeModel response = JsonUtility.FromJson(webRequest.downloadHandler.text);
+ onTimeRecieved?.Invoke(response.unixtime);
+ }
+ else
+ {
+ onRequestError?.Invoke();
+ }
+
+ webRequest.Dispose();
+ }
+
+ ///
+ /// Get Current Local Time
+ ///
+ ///
+ private long GetCurrentLocalTime()
+ {
+ DateTime epochStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+ long currentEpochTime = (long)(DateTime.UtcNow - epochStart).TotalSeconds;
+ return currentEpochTime;
+ }
+
+ ///
+ /// Seconds Elapsed
+ ///
+ ///
+ ///
+ ///
+ private int SecondsElapsed(int t1, int t2)
+ {
+ int difference = t1 - t2;
+ return Mathf.Abs(difference);
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Time Skip Protector",
+ Description = "This module allows you to protect yourself against time rewinds on the user's device",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#timeskip-protector"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+ public float CheckingInterval = 10f;
+ public int AvailableTolerance = 60;
+ public bool NetworkCompare = true;
+ public string NetworkServer = "https://worldtimeapi.org/api/timezone/utc";
+ }
+
+ [System.Serializable]
+ public class NetworkTimeModel
+ {
+ public string abbreviation = "";
+ public string client_ip = "";
+ public string datetime = "";
+ public uint day_of_week = 0;
+ public uint day_of_year = 0;
+ public bool dst = false;
+ public int dst_offset = 0;
+ public int raw_offset = 0;
+ public string timezone = "";
+ public long unixtime = 0;
+ public string utc_datetime = "";
+ public string utc_offset = "+00:00";
+ public uint week_number = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeProtector.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeProtector.cs.meta
new file mode 100644
index 0000000..35e3052
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeProtector.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e9fd14c25d1941b3bfed14b57daa3b7a
+timeCreated: 1710018206
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeWarnings.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeWarnings.cs
new file mode 100644
index 0000000..8dabe6e
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeWarnings.cs
@@ -0,0 +1,9 @@
+namespace DevsDaddy.GameShield.Core.Modules.Time
+{
+ public static class TimeWarnings
+ {
+ public const string NetworkTimeError = "Failed to check network time. Please, try again later or contact us.";
+ public const string TimeCheating =
+ "A big difference between the elapsed time on your device and the network time has been detected. Please change the date and time on your device to the current values and try again.";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeWarnings.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeWarnings.cs.meta
new file mode 100644
index 0000000..41402f5
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Time/TimeWarnings.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 137a81c262da491f9168ae77adc66c9d
+timeCreated: 1710400628
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack.meta
new file mode 100644
index 0000000..0cb455b
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: be9fec7ee2264bb19794ce10ab5dab8f
+timeCreated: 1710016865
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallHackProtector.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallHackProtector.cs
new file mode 100644
index 0000000..9aa8562
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallHackProtector.cs
@@ -0,0 +1,303 @@
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+
+namespace DevsDaddy.GameShield.Core.Modules.WallHack
+{
+ ///
+ /// NoClip Detector Module
+ ///
+ public class WallHackProtector : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ private const string SERVICE_CONTAINER_NAME = "__WALLHACK_SERVICE__";
+ private readonly Vector3 rigidPlayerVelocity = new Vector3(0, 0, 1f);
+
+ private Vector3 spawnPosition;
+
+ // Private Params
+ private int whLayer = -1;
+ private GameObject serviceContainer;
+ private Rigidbody rigidPlayer;
+ private CharacterController charControllerPlayer;
+ private float charControllerVelocity = 0;
+
+ private float timeToCheck = 4f;
+ private float checkInterval = 4f;
+ private bool checkRigid = false;
+ private bool checkController = false;
+
+#if DEBUG
+ private bool rigidDetected = false;
+ private bool controllerDetected = false;
+#endif
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ spawnPosition = _currentOptions.SpawnPosition;
+ InitDetector();
+
+ // Fire Initialization Complete
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ UninitDetector();
+
+ // Fire Disconnected Complete
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ if (isPaused) {
+ StopRigidModule();
+ StopControllerModule();
+ }
+ else {
+ StartRigidModule();
+ StartControllerModule();
+ }
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Initialize Detector
+ ///
+ private void InitDetector()
+ {
+ InitCommon();
+ InitRigidModule();
+ InitControllerModule();
+
+ StartRigidModule();
+ StartControllerModule();
+ }
+
+ ///
+ /// Uninitialize Detector
+ ///
+ private void UninitDetector()
+ {
+ _isPaused = true;
+ StopRigidModule();
+ StopControllerModule();
+ GameObject.Destroy(serviceContainer);
+ }
+
+ ///
+ /// Initialize Common Modules
+ ///
+ private void InitCommon()
+ {
+ if (whLayer == -1) whLayer = LayerMask.NameToLayer("Ignore Raycast");
+
+ serviceContainer = new GameObject(SERVICE_CONTAINER_NAME);
+ serviceContainer.layer = whLayer;
+ serviceContainer.transform.position = spawnPosition;
+ serviceContainer.transform.parent = null;
+ GameObject.DontDestroyOnLoad(serviceContainer);
+
+ GameObject wall = new GameObject("Wall");
+ wall.AddComponent();
+ wall.layer = whLayer;
+ wall.transform.parent = serviceContainer.transform;
+ wall.transform.localPosition = Vector3.zero;
+
+ wall.transform.localScale = new Vector3(3, 3, 0.5f);
+ }
+
+ ///
+ /// Initialize Rigid Modules
+ ///
+ private void InitRigidModule()
+ {
+ GameObject player = new GameObject("RigidPlayer");
+ player.AddComponent().height = 2;
+ player.layer = whLayer;
+ player.transform.parent = serviceContainer.transform;
+ player.transform.localPosition = new Vector3(0.75f, 0, -1f);
+ rigidPlayer = player.AddComponent();
+ rigidPlayer.useGravity = false;
+ }
+
+ ///
+ /// Initialize Controller Module
+ ///
+ private void InitControllerModule()
+ {
+ GameObject player = new GameObject("ControlledPlayer");
+ player.AddComponent().height = 2;
+ player.layer = whLayer;
+ player.transform.parent = serviceContainer.transform;
+ player.transform.localPosition = new Vector3(-0.75f, 0, -1f);
+ charControllerPlayer = player.AddComponent();
+ }
+
+ ///
+ /// Start Rigid Module
+ ///
+ private void StartRigidModule()
+ {
+ rigidPlayer.rotation = Quaternion.identity;
+ rigidPlayer.angularVelocity = Vector3.zero;
+ rigidPlayer.transform.localPosition = new Vector3(0.75f, 0, -1f);
+ rigidPlayer.velocity = rigidPlayerVelocity;
+ checkRigid = true;
+ }
+
+ ///
+ /// Stop Rigid Module
+ ///
+ private void StopRigidModule()
+ {
+ rigidPlayer.velocity = Vector3.zero;
+ checkRigid = false;
+ }
+
+ ///
+ /// Start Controller Module
+ ///
+ private void StartControllerModule()
+ {
+ charControllerPlayer.transform.localPosition = new Vector3(-0.75f, 0, -1f);
+ charControllerVelocity = 0.01f;
+ checkController = true;
+ }
+
+ ///
+ /// Stop Controller Module
+ ///
+ private void StopControllerModule()
+ {
+ charControllerVelocity = 0;
+ checkController = false;
+ }
+
+ ///
+ /// On Game Loop Updated
+ ///
+ ///
+ private void OnGameLoopUpdate(ApplicationLoopUpdated payload) {
+ if(_isPaused) return;
+
+ // Restart checks
+ if (timeToCheck <= 0f) {
+ timeToCheck = checkInterval;
+ if(checkRigid) StartRigidModule();
+ if(checkController) StartControllerModule();
+ }
+ else {
+ timeToCheck -= payload.DeltaTime;
+ }
+
+ if (charControllerVelocity > 0)
+ {
+ charControllerPlayer.Move(new Vector3(Random.Range(-0.002f, 0.002f), 0, charControllerVelocity));
+ if (charControllerPlayer.transform.localPosition.z > 1f)
+ {
+#if DEBUG
+ controllerDetected = true;
+#endif
+ StopControllerModule();
+ Detect();
+ }
+ }
+ }
+
+ ///
+ /// On Fixed Loop Updated
+ ///
+ ///
+ private void OnFixedLoopUpdate(ApplicationFixedLoopUpdated payload) {
+ if(_isPaused) return;
+
+ if (rigidPlayer.transform.localPosition.z > 1f)
+ {
+#if DEBUG
+ rigidDetected = true;
+#endif
+ StopRigidModule();
+
+ Detect();
+ }
+ }
+
+ private void Detect() {
+ EventMessenger.Main.Publish(new SecurityWarningPayload {
+ Module = this,
+ Message = WallhackMessages.Detected,
+ Code = 562,
+ IsCritical = true
+ });
+ PauseDetector(true);
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Wallhack Protector",
+ Description = "This module allows you to cheat physics-based WallHack software cheats",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#wallhack-protector"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+ public Vector3 SpawnPosition = new Vector3(-1000,-1000,-1000);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallHackProtector.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallHackProtector.cs.meta
new file mode 100644
index 0000000..a708a68
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallHackProtector.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6c37038b4ff94274aac942bbbf3af0fd
+timeCreated: 1710018005
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallhackMessages.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallhackMessages.cs
new file mode 100644
index 0000000..ae5cbc5
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallhackMessages.cs
@@ -0,0 +1,7 @@
+namespace DevsDaddy.GameShield.Core.Modules.WallHack
+{
+ public static class WallhackMessages
+ {
+ public const string Detected = "System detected wallhack service. Please, restart game and try again";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallhackMessages.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallhackMessages.cs.meta
new file mode 100644
index 0000000..4a2e04f
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/WallHack/WallhackMessages.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 3e675df159b74482a8a86a88c4221647
+timeCreated: 1710092418
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web.meta
new file mode 100644
index 0000000..28acdce
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 9e1b00acfc3d4b91baa21752e808affd
+timeCreated: 1710017374
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/SecuredRequest.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/SecuredRequest.cs
new file mode 100644
index 0000000..2c39339
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/SecuredRequest.cs
@@ -0,0 +1,445 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.CryptoLibrary.Core;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+using UnityEngine.Networking;
+
+namespace DevsDaddy.GameShield.Core.Modules.Web
+{
+ ///
+ /// Secured Web Requests Module
+ ///
+ public class SecuredRequest : IShieldModule
+ {
+ private Options _currentOptions;
+ private bool _initialized = false;
+ private bool _isPaused = false;
+
+ // Web Requests Pull
+ private int simplePostId = 0;
+ private List _requests = new List();
+
+ ///
+ /// Setup Module
+ ///
+ ///
+ ///
+ public void SetupModule(IShieldModuleConfig config = null, bool reinitialize = false) {
+ if (!Application.isPlaying) return;
+
+ // Change Configuration
+ _currentOptions = (Options)config ?? new Options();
+ EventMessenger.Main.Publish(new SecurityModuleConfigChanged {
+ Module = this,
+ Config = _currentOptions
+ });
+
+ // Initialize Module
+ if (!_initialized && !reinitialize)
+ Initialize();
+ }
+
+ ///
+ /// Disconnect Module
+ ///
+ public void Disconnect() {
+ // Fire Disconnected Complete
+ EventMessenger.Main.Publish(new SecurityModuleDisconnected {
+ Module = this
+ });
+ }
+
+ ///
+ /// Toggle Pause for Current Detector
+ ///
+ ///
+ public void PauseDetector(bool isPaused) {
+ if(isPaused == _isPaused) return;
+ _isPaused = isPaused;
+ EventMessenger.Main.Publish(new SecurityModulePause {
+ Module = this,
+ IsPaused = _isPaused
+ });
+ }
+
+ ///
+ /// Check if Detector Paused
+ ///
+ ///
+ public bool IsPaused() {
+ return _isPaused;
+ }
+
+ ///
+ /// Initialize Module
+ ///
+ private void Initialize() {
+ // Fire Initialization Complete
+ EventMessenger.Main.Publish(new SecurityModuleInitialized {
+ Module = this
+ });
+ }
+
+ ///
+ /// Send Web Request
+ ///
+ ///
+ ///
+ ///
+ public void SendRequest(WebRequestData data, Action onComplete = null, Action onError = null) {
+ // Add Requests to List
+ data.RequestId = _requests.Count + 1;
+ _requests.Add(data);
+
+ // Send Request
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = WebRequest(data, onComplete, onError),
+ Id = "SecuredRequest" + data.RequestId
+ });
+ }
+
+ ///
+ /// Send Post Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Post(string url, ICryptoProvider provider, Action onComplete = null, Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PostRequest(url, provider,null, null, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Send Post Request with Headers
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Post(string url, ICryptoProvider provider, Dictionary headers, Action onComplete = null, Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PostRequest(url, provider, headers, null, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Send Post Request with Headers and Body
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Post(string url, ICryptoProvider provider, Dictionary headers, Dictionary body, Action onComplete = null, Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PostRequest(url, provider, headers, body, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Put(string url, ICryptoProvider provider, Action onComplete = null,
+ Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PutRequest(url, provider, null, null, null, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Put(string url, ICryptoProvider provider, Dictionary headers, Action onComplete = null,
+ Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PutRequest(url, provider, headers, null, null, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Put(string url, ICryptoProvider provider, string body, Action onComplete = null,
+ Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PutRequest(url, provider, null, body, null, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Put(string url, ICryptoProvider provider, byte[] body, Action onComplete = null,
+ Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PutRequest(url, provider, null, null, body, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Put(string url, ICryptoProvider provider, Dictionary headers, string body, Action onComplete = null,
+ Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PutRequest(url, provider, headers, body, null, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void Put(string url, ICryptoProvider provider, Dictionary headers, byte[] body, Action onComplete = null,
+ Action onError = null) {
+ simplePostId++;
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = PutRequest(url, provider, headers, null, body, onComplete, onError),
+ Id = "SecuredPostRequest" + simplePostId
+ });
+ }
+
+ ///
+ /// Post Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private IEnumerator PostRequest(string url, ICryptoProvider provider, Dictionary headers = null,
+ Dictionary body = null, Action onComplete = null,
+ Action onError = null) {
+ // Check Parameters
+ if (provider == null) {
+ Debug.LogError("Failed to send Secured Request. Encryption module can't be null");
+ yield break;
+ }
+ if (string.IsNullOrEmpty(url)) {
+ Debug.LogError("Failed to send Secured Request. Url can't be null");
+ yield break;
+ }
+
+ // Work with Body
+ Dictionary encryptedBody;
+ if (body != null && body.Count > 0) {
+ encryptedBody = new Dictionary();
+ foreach (var reqData in body) {
+ encryptedBody.Add(reqData.Key, provider.EncryptString(reqData.Value));
+ }
+ }
+ else {
+ encryptedBody = body;
+ }
+
+ // Send Request
+ UnityWebRequest req = UnityWebRequest.Post(url, encryptedBody);
+ if (headers != null && headers.Count > 0) {
+ foreach (var header in headers) {
+ req.SetRequestHeader(header.Key, header.Value);
+ }
+ }
+
+ req.SetRequestHeader("Encrypted", provider.GetType().Name);
+ yield return req.SendWebRequest();
+ if (req.result == UnityWebRequest.Result.Success) {
+ WebRequestResponse response = new WebRequestResponse {
+ RawText = req.downloadHandler.text,
+ RawBinary = req.downloadHandler.data,
+ Code = req.responseCode,
+ DecryptedBinary = provider.DecryptBinary(req.downloadHandler.data),
+ DecryptedText = provider.DecryptString(req.downloadHandler.text)
+ };
+ onComplete?.Invoke(response);
+ }
+ else {
+ onError?.Invoke($"Failed to process web request. Code: {req.responseCode}. Error: {req.result.ToString()}");
+ }
+ }
+
+ ///
+ /// Send Put Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ private IEnumerator PutRequest(string url, ICryptoProvider provider, Dictionary headers = null,
+ string textbody = null, byte[] bytebody = null, Action onComplete = null,
+ Action onError = null) {
+ // Check Parameters
+ if (provider == null) {
+ Debug.LogError("Failed to send Secured Request. Encryption module can't be null");
+ yield break;
+ }
+ if (string.IsNullOrEmpty(url)) {
+ Debug.LogError("Failed to send Secured Request. Url can't be null");
+ yield break;
+ }
+
+ // Work with Body
+ if (!string.IsNullOrEmpty(textbody))
+ textbody = provider.EncryptString(textbody);
+
+ if(bytebody != null && bytebody.Length > 0)
+ bytebody = provider.EncryptBinary(bytebody);
+
+ // Send Request
+ UnityWebRequest req;
+ if (!string.IsNullOrEmpty(textbody)) {
+ req = UnityWebRequest.Put(url, textbody);
+ }
+ else if(bytebody != null && bytebody.Length > 0){
+ req = UnityWebRequest.Put(url, bytebody);
+ }
+ else {
+ req = UnityWebRequest.Put(url, "");
+ }
+ if (headers != null && headers.Count > 0) {
+ foreach (var header in headers) {
+ req.SetRequestHeader(header.Key, header.Value);
+ }
+ }
+
+ req.SetRequestHeader("Encrypted", provider.GetType().Name);
+ yield return req.SendWebRequest();
+ if (req.result == UnityWebRequest.Result.Success) {
+ WebRequestResponse response = new WebRequestResponse {
+ RawText = req.downloadHandler.text,
+ RawBinary = req.downloadHandler.data,
+ Code = req.responseCode,
+ DecryptedBinary = provider.DecryptBinary(req.downloadHandler.data),
+ DecryptedText = provider.DecryptString(req.downloadHandler.text)
+ };
+ onComplete?.Invoke(response);
+ }
+ else {
+ onError?.Invoke($"Failed to process web request. Code: {req.responseCode}. Error: {req.result.ToString()}");
+ }
+ }
+
+ ///
+ /// Web Request
+ ///
+ ///
+ ///
+ ///
+ ///
+ private IEnumerator WebRequest(WebRequestData data, Action onComplete = null, Action onError = null) {
+ // Check Parameters
+ if (data.Provider == null) {
+ Debug.LogError("Failed to send Secured Request. Encryption module can't be null");
+ yield break;
+ }
+ if (string.IsNullOrEmpty(data.Url)) {
+ Debug.LogError("Failed to send Secured Request. Url can't be null");
+ yield break;
+ }
+
+ // Work with Request Body
+ UploadHandler uploadHandler = null;
+ if (data.UploadData != null && data.UploadData.Length > 0) {
+ uploadHandler = new UploadHandlerRaw(data.Provider.EncryptBinary(data.UploadData));
+ }
+
+ // Send Request
+ UnityWebRequest req = new UnityWebRequest(data.Url, data.Method, data.DownloadHandler, uploadHandler);
+ foreach (var header in data.Headers) {
+ req.SetRequestHeader(header.Key, header.Value);
+ }
+ req.SetRequestHeader("Encrypted", data.Provider.GetType().Name);
+ yield return req.SendWebRequest();
+ if (req.result == UnityWebRequest.Result.Success) {
+ WebRequestResponse response = new WebRequestResponse {
+ RawText = req.downloadHandler.text,
+ RawBinary = req.downloadHandler.data,
+ Code = req.responseCode,
+ DecryptedBinary = data.Provider.DecryptBinary(req.downloadHandler.data),
+ DecryptedText = data.Provider.DecryptString(req.downloadHandler.text)
+ };
+ onComplete?.Invoke(response);
+ }
+ else {
+ onError?.Invoke($"Failed to process web request. Code: {req.responseCode}. Error: {req.result.ToString()}");
+ }
+ }
+
+ ///
+ /// Get Module Information
+ ///
+ ///
+ public ModuleInfo GetModuleInfo() {
+ return new ModuleInfo {
+ Name = "Secured Requests",
+ Description = "This module allows you to exchange encrypted requests with the server with an additional layer of protection",
+ DocumentationLink = "https://github.com/DevsDaddy/GameShield/wiki/Modules-Overview#secured-requests"
+ };
+ }
+
+ // Module Options Configuration
+ [System.Serializable]
+ public class Options : IShieldModuleConfig
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/SecuredRequest.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/SecuredRequest.cs.meta
new file mode 100644
index 0000000..97c852c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/SecuredRequest.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 874b500fa8b7483bbe756f2a3e5277c1
+timeCreated: 1710018311
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/WebRequestData.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/WebRequestData.cs
new file mode 100644
index 0000000..58e7dec
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/WebRequestData.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using DevsDaddy.Shared.CryptoLibrary.Core;
+using UnityEngine.Networking;
+
+namespace DevsDaddy.GameShield.Core.Modules.Web
+{
+ [System.Serializable]
+ public class WebRequestData
+ {
+ // Request Data
+ public long RequestId = 0;
+ public string Url = "";
+ public string Method = "GET";
+ public Dictionary Headers = new Dictionary();
+ public byte[] UploadData;
+ public ICryptoProvider Provider;
+
+ // Handlers
+ public DownloadHandler DownloadHandler;
+ }
+
+ public class WebRequestResponse
+ {
+ public long Code;
+ public string DecryptedText;
+ public byte[] DecryptedBinary;
+ public string RawText;
+ public byte[] RawBinary;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/WebRequestData.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/WebRequestData.cs.meta
new file mode 100644
index 0000000..5341642
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Modules/Web/WebRequestData.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: d9afee5725d44fa8a22920d74eb8cff2
+timeCreated: 1710395229
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads.meta
new file mode 100644
index 0000000..ea87234
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: b5d34b76b8604283ac84ef664832ed9f
+timeCreated: 1709921119
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/LifecyclePayloads.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/LifecyclePayloads.cs
new file mode 100644
index 0000000..f7dffe3
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/LifecyclePayloads.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections;
+using DevsDaddy.Shared.EventFramework.Core.Payloads;
+
+namespace DevsDaddy.GameShield.Core.Payloads
+{
+ [System.Serializable]
+ public class ApplicationClosePayload : IPayload
+ {
+ public bool IsQuitting = false;
+ public DateTime Time;
+ }
+
+ [System.Serializable]
+ public class ApplicationPausePayload : IPayload
+ {
+ public bool IsPaused = false;
+ public DateTime Time;
+ }
+
+ [System.Serializable]
+ public class ApplicationStartedPayload : IPayload
+ {
+ public DateTime Time;
+ }
+
+ [System.Serializable]
+ public class ApplicationLoopUpdated : IPayload
+ {
+ public float DeltaTime;
+ }
+
+ [System.Serializable]
+ public class ApplicationFixedLoopUpdated : IPayload
+ {
+ public float DeltaTime;
+ }
+
+ [System.Serializable]
+ public class RequestCoroutine : IPayload
+ {
+ public string Id;
+ public IEnumerator Coroutine;
+ }
+
+ [System.Serializable]
+ public class StopCoroutine : IPayload
+ {
+ public string Id;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/LifecyclePayloads.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/LifecyclePayloads.cs.meta
new file mode 100644
index 0000000..769502e
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/LifecyclePayloads.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 1a9ba64908d740878e89f92b900e9721
+timeCreated: 1709921361
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/SecurityPayloads.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/SecurityPayloads.cs
new file mode 100644
index 0000000..09e508d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/SecurityPayloads.cs
@@ -0,0 +1,40 @@
+using DevsDaddy.GameShield.Core.Modules;
+using DevsDaddy.Shared.EventFramework.Core.Payloads;
+
+namespace DevsDaddy.GameShield.Core.Payloads
+{
+ [System.Serializable]
+ public class SecurityWarningPayload : IPayload
+ {
+ public uint Code;
+ public IShieldModule Module;
+ public string Message = "";
+ public bool IsCritical = false;
+ }
+
+ [System.Serializable]
+ public class SecurityModuleConfigChanged : IPayload
+ {
+ public IShieldModule Module;
+ public IShieldModuleConfig Config;
+ }
+
+ [System.Serializable]
+ public class SecurityModuleInitialized : IPayload
+ {
+ public IShieldModule Module;
+ }
+
+ [System.Serializable]
+ public class SecurityModuleDisconnected : IPayload
+ {
+ public IShieldModule Module;
+ }
+
+ [System.Serializable]
+ public class SecurityModulePause : IPayload
+ {
+ public IShieldModule Module;
+ public bool IsPaused;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/SecurityPayloads.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/SecurityPayloads.cs.meta
new file mode 100644
index 0000000..83cad89
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Payloads/SecurityPayloads.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 95e0a5971d3f42bcb394eabbe56221aa
+timeCreated: 1709968713
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter.meta
new file mode 100644
index 0000000..0feed27
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: cfa6c697b86647b2badee242561354d3
+timeCreated: 1710085229
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportData.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportData.cs
new file mode 100644
index 0000000..021ed69
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportData.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace DevsDaddy.GameShield.Core.Reporter
+{
+ [System.Serializable]
+ public class ReportData
+ {
+ public string Gateway = "";
+ public bool IsUserReport = false;
+ public DateTime LocalTime = DateTime.Now;
+ public string Message = "";
+ public string ModuleType = "";
+ public string Code = "";
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportData.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportData.cs.meta
new file mode 100644
index 0000000..fd70083
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportData.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 985b0ef6c4334642befff72eed0e3bbc
+timeCreated: 1712758872
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReporterWorker.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReporterWorker.cs
new file mode 100644
index 0000000..88a6ce3
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReporterWorker.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections;
+using DevsDaddy.GameShield.Core.Constants;
+using DevsDaddy.GameShield.Core.Payloads;
+using DevsDaddy.Shared.EventFramework;
+using UnityEngine;
+using UnityEngine.Networking;
+
+namespace DevsDaddy.GameShield.Core.Reporter
+{
+ ///
+ /// Reporting Worker Class
+ ///
+ public static class ReporterWorker
+ {
+ ///
+ /// Send Report to Server
+ ///
+ ///
+ ///
+ ///
+ public static void Send(ReportData data, Action onComplete = null, Action onError = null) {
+ EventMessenger.Main.Publish(new RequestCoroutine {
+ Coroutine = SendReport(data, onComplete, onError),
+ Id = "GameShieldReportProcessing"
+ });
+ }
+
+ ///
+ /// Send Report
+ ///
+ ///
+ ///
+ ///
+ ///
+ private static IEnumerator SendReport(ReportData data, Action onComplete = null, Action onError = null) {
+ string url = $"{GameShield.Main.GetBackendUrl()}/{data.Gateway}";
+ if (string.IsNullOrEmpty(url)) {
+ onError?.Invoke($"{GeneralStrings.LOG_PREFIX} Failed to send report. Backend URL and Gateway are empty");
+ yield break;
+ }
+
+ // Request
+ var req = new UnityWebRequest(url, "POST");
+ byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(JsonUtility.ToJson(data));
+ req.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
+ req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
+ req.SetRequestHeader("Content-Type", "application/json");
+
+ yield return req.SendWebRequest();
+
+ if (req.isDone && req.downloadHandler.isDone)
+ {
+ if (string.IsNullOrEmpty(req.downloadHandler.text)) {
+ onError?.Invoke($"{GeneralStrings.LOG_PREFIX} Failed to parse server response at reporting processing. Response are empty.");
+ yield break;
+ }
+
+ onComplete?.Invoke(req.downloadHandler.text);
+ }
+ else
+ {
+ onError?.Invoke($"{GeneralStrings.LOG_PREFIX} Reporting Processing Error: {req.error}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReporterWorker.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReporterWorker.cs.meta
new file mode 100644
index 0000000..c3c2c9c
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReporterWorker.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 49e74ad1da8b4e799b45523e52a0af24
+timeCreated: 1710085266
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportingPayload.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportingPayload.cs
new file mode 100644
index 0000000..7dff35a
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportingPayload.cs
@@ -0,0 +1,13 @@
+using System;
+using DevsDaddy.Shared.EventFramework.Core.Payloads;
+
+namespace DevsDaddy.GameShield.Core.Reporter
+{
+ [System.Serializable]
+ public class ReportingPayload : IPayload
+ {
+ public ReportData Data;
+ public Action OnComplete;
+ public Action OnError;
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportingPayload.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportingPayload.cs.meta
new file mode 100644
index 0000000..4a95fba
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Reporter/ReportingPayload.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: dc6e237323df450e8b480594c644b114
+timeCreated: 1712759610
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils.meta
new file mode 100644
index 0000000..afa6ded
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: ece8ce023a0e4e3396033538652cd6c7
+timeCreated: 1709921162
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/EnumerableExtensions.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/EnumerableExtensions.cs
new file mode 100644
index 0000000..082747d
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/EnumerableExtensions.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace DevsDaddy.GameShield.Core.Utils
+{
+ ///
+ /// Enumerable Extensions
+ ///
+ public static class EnumerableExtensions
+ {
+ ///
+ /// Shuffle
+ ///
+ ///
+ ///
+ ///
+ public static IList Shuffle(this IEnumerable sequence)
+ {
+ return sequence.Shuffle(new Random());
+ }
+
+ ///
+ /// Shuffle
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static IList Shuffle(this IEnumerable sequence, Random randomNumberGenerator)
+ {
+ if (sequence == null)
+ {
+ throw new ArgumentNullException("sequence");
+ }
+
+ if (randomNumberGenerator == null)
+ {
+ throw new ArgumentNullException("randomNumberGenerator");
+ }
+
+ T swapTemp;
+ List values = sequence.ToList();
+ int currentlySelecting = values.Count;
+ while (currentlySelecting > 1)
+ {
+ int selectedElement = randomNumberGenerator.Next(currentlySelecting);
+ --currentlySelecting;
+ if (currentlySelecting != selectedElement)
+ {
+ swapTemp = values[currentlySelecting];
+ values[currentlySelecting] = values[selectedElement];
+ values[selectedElement] = swapTemp;
+ }
+ }
+
+ return values;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/EnumerableExtensions.cs.meta b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/EnumerableExtensions.cs.meta
new file mode 100644
index 0000000..e70c6f3
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/EnumerableExtensions.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: dfb936c7106a4b9fa781c477b2afeaca
+timeCreated: 1712818505
\ No newline at end of file
diff --git a/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/Generator.cs b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/Generator.cs
new file mode 100644
index 0000000..15dbc18
--- /dev/null
+++ b/Unity Game Shield/Assets/DevsDaddy/GameShield/Core/Utils/Generator.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Linq;
+using DevsDaddy.GameShield.Core.Constants;
+using UnityEngine;
+using Random = System.Random;
+
+namespace DevsDaddy.GameShield.Core.Utils
+{
+ ///