// System using System; // Unity using UnityEngine; // GUPS - AntiCheat - Core using GUPS.AntiCheat.Core.Protected; // GUPS - AntiCheat using GUPS.AntiCheat.Detector; using GUPS.AntiCheat.Settings; namespace GUPS.AntiCheat.Protected { /// /// Represents a protected Vector2, enhancing security for sensitive vector data. /// In most scenarios, it is recommended to replace the default Vector2 type with this protected variant. /// [Serializable] public struct ProtectedVector2 : IProtected, IDisposable, ISerializationCallbackReceiver { /// /// A struct does not have a default constructor that is called when the structure is created. Therefore, the protected primitive must return /// a default value if it does not have an assigned value. /// private bool isInitialized; /// /// Gets a value indicating whether the protected value has integrity, i.e., whether it has maintained its original state. /// private bool hasIntegrity; /// /// Gets a value indicating whether the protected value has integrity, i.e., whether it has maintained its original state. /// public bool HasIntegrity { get => hasIntegrity || !isInitialized; private set => hasIntegrity = value; } /// /// The encrypted true value for the x-component. /// private UIntFloat obfuscatedValueX; /// /// The encrypted true value for the y-component. /// private UIntFloat obfuscatedValueY; /// /// Used for calculation of int/float values for the secured value. /// private UIntFloat manager; /// /// A secret key used to obfuscate the true value. /// private UInt32 secret; /// /// A honeypot pretending to be the original value. If a user attempts to change this value via a cheat/hack engine, notifications will be triggered. /// The protected value will maintain its true representation. /// [SerializeField] private Vector2 fakeValue; /// /// Unity serialization hook. Ensures the correct values are serialized. /// public void OnBeforeSerialize() { this.fakeValue = Value; } /// /// Unity deserialization hook. Ensures the correct values are deserialized. /// public void OnAfterDeserialize() { this = this.fakeValue; } /// /// Creates a new protected Vector2 with the specified value. /// /// The initial value of the protected Vector2. public ProtectedVector2(Vector2 _Value) { // Initialization this.isInitialized = true; // Initialization - Secured values. this.obfuscatedValueX.intValue = 0; this.obfuscatedValueX.floatValue = 0; this.obfuscatedValueY.intValue = 0; this.obfuscatedValueY.floatValue = 0; // Initialization - Manager. this.manager.intValue = 0; this.manager.floatValue = 0; // Initialization - Random secret. this.secret = 0; // Initialization - Fake value. this.fakeValue = Vector2.zero; // Initialization - Integrity. this.hasIntegrity = true; // Obfuscate the value. this.Obfuscate(_Value); } /// /// Gets and sets the true unencrypted field value. /// public Vector2 Value { get { if (!this.isInitialized) { return new Vector2(); } if (!this.CheckIntegrity()) { AntiCheatMonitor.Instance.GetDetector()?.OnNext(this); } return this.UnObfuscate(); } set { this.Obfuscate(value); } } /// /// Gets the true unencrypted field value. /// object IProtected.Value => this.Value; /// /// Obfuscates the specified value, encrypting it with the secret key. /// private void Obfuscate(Vector2 _Value) { // Obfuscate the value. this.manager.floatValue = _Value.x; this.manager.intValue = this.manager.intValue ^ this.secret; this.obfuscatedValueX.floatValue = this.manager.floatValue; this.manager.floatValue = _Value.y; this.manager.intValue = this.manager.intValue ^ this.secret; this.obfuscatedValueY.floatValue = this.manager.floatValue; // Assign the fake value. this.fakeValue = _Value; } /// /// Unobfuscates the secured value and returns the true unencrypted value. /// /// The true unencrypted value. private Vector2 UnObfuscate() { // Get the unobfuscated value. Vector2 var_RealValue = new Vector2(); this.manager.intValue = this.obfuscatedValueX.intValue ^ this.secret; var_RealValue.x = this.manager.floatValue; this.manager.intValue = this.obfuscatedValueY.intValue ^ this.secret; var_RealValue.y = this.manager.floatValue; // Return the unobfuscated value. return var_RealValue; } /// /// Obfuscates the current value, generating a new random secret key. /// public void Obfuscate() { // Unobfuscate the secured value. Vector2 var_UnobfuscatedValue = this.UnObfuscate(); // Create a new random secret. this.secret = (UInt32)GlobalSettings.RandomProvider.RandomInt32(1, Int32.MaxValue); // Obfuscate the value. this.Obfuscate(var_UnobfuscatedValue); } /// /// Checks the integrity of the protected value, detecting if an attacker changed the honeypot fake value. /// /// True if the protected value has integrity; otherwise, false. public bool CheckIntegrity() { // Unobfuscate the secured value. Vector2 var_UnobfuscatedValue = this.UnObfuscate(); // Check if an attacker changed the honeypot fake value. if (this.fakeValue != var_UnobfuscatedValue) { this.HasIntegrity = false; } // Return the integrity status. return this.HasIntegrity; } /// /// Releases the resources used by the protected Vector2. /// public void Dispose() { this.obfuscatedValueX.intValue = 0; this.obfuscatedValueY.intValue = 0; this.manager.intValue = 0; this.secret = 0; } /// /// Returns a string representation of the protected Vector2. /// /// A string representation of the protected Vector2. public override string ToString() { return this.Value.ToString(); } /// /// Gets the hash code for the protected value. /// /// The hash code for the protected value. public override int GetHashCode() { return this.Value.GetHashCode(); } #region Serialization /// /// Used to serialize the protected to the player prefs. /// /// The obfuscated x value of the protected. /// The obfuscated y value of the protected. /// The secret key used to obfuscate the true value. internal void Serialize(out UInt32 _ObfuscatedValueX, out UInt32 _ObfuscatedValueY, out UInt32 _Secret) { _ObfuscatedValueX = this.obfuscatedValueX.intValue; _ObfuscatedValueY = this.obfuscatedValueY.intValue; _Secret = this.secret; } /// /// Used to deserialize the protected from the player prefs. /// /// The obfuscated x value of the protected. /// The obfuscated y value of the protected. /// The secret key used to obfuscate the true value. internal void Deserialize(UInt32 _ObfuscatedValueX, UInt32 _ObfuscatedValueY, UInt32 _Secret) { this.obfuscatedValueX.intValue = _ObfuscatedValueX; this.obfuscatedValueY.intValue = _ObfuscatedValueY; this.secret = _Secret; this.fakeValue = this.UnObfuscate(); } #endregion #region Implicit operator /// /// Implicitly converts a regular Vector2 to a protected Vector2. /// /// The regular Vector2 to be converted. /// A new instance of the protected Vector2. public static implicit operator ProtectedVector2(Vector2 _Value) { return new ProtectedVector2(_Value); } /// /// Implicitly converts a protected Vector2 to a regular Vector2. /// /// The protected Vector2 to be converted. /// The true unencrypted value of the protected Vector2. public static implicit operator Vector2(ProtectedVector2 _Value) { return _Value.Value; } /// /// Implicitly converts a protected Vector2 to a protected Quaternion. /// /// The protected Vector2 to be converted. /// The encrypted value as protected Quaternion. public static implicit operator ProtectedQuaternion(ProtectedVector2 _Value) { return new ProtectedQuaternion(new Quaternion(_Value.Value.x, _Value.Value.y, 0, 0)); } /// /// Implicitly converts a protected Quaternion to a protected Vector2. /// /// The protected Quaternion to be converted. /// The encrypted value as protected Vector2. public static implicit operator ProtectedVector2(ProtectedQuaternion _Value) { return new ProtectedVector2(new Vector2(_Value.Value.x, _Value.Value.y)); } #endregion #region Equality operator /// /// Checks if two protected Vector2 instances are equal. /// /// The first protected Vector2. /// The second protected Vector2. /// True if the values of the protected Vector2 instances are equal; otherwise, false. public static bool operator ==(ProtectedVector2 v1, ProtectedVector2 v2) { return v1.Value == v2.Value; } /// /// Checks if two protected Vector2 instances are not equal. /// /// The first protected Vector2. /// The second protected Vector2. /// True if the values of the protected Vector2 instances are not equal; otherwise, false. public static bool operator !=(ProtectedVector2 v1, ProtectedVector2 v2) { return v1.Value != v2.Value; } /// /// Checks if the protected Vector2 is equal to the specified object. /// /// The object to compare with the protected Vector2. /// True if the values are equal; otherwise, false. public override bool Equals(object obj) { if (obj is ProtectedVector2) { return this.Value == ((ProtectedVector2)obj).Value; } return this.Value.Equals(obj); } #endregion } }