diff --git a/project/SPT.Custom/Patches/SaveRegistryToSptFolderPatches.cs b/project/SPT.Custom/Patches/SaveRegistryToSptFolderPatches.cs
new file mode 100644
index 0000000..88cf3c3
--- /dev/null
+++ b/project/SPT.Custom/Patches/SaveRegistryToSptFolderPatches.cs
@@ -0,0 +1,237 @@
+using HarmonyLib;
+using Newtonsoft.Json.Linq;
+using SPT.Reflection.Patching;
+using System;
+using System.IO;
+using System.Reflection;
+using UnityEngine;
+
+namespace SPT.Custom.Patches
+{
+ ///
+ /// Redirect registry reads/writes to a folder in the SPT directory, instead of sharing
+ /// registry entries with live.
+ ///
+ /// Note this is a multi-patch to keep these patches grouped together, as we need to patch
+ /// many methods to properly implement this
+ ///
+ public class SaveRegistryToSptFolderPatches
+ {
+ private static readonly string _sptRegistryPath = Path.Combine(Environment.CurrentDirectory, "user", "sptRegistry");
+ private static readonly string _registryFilePath = Path.Combine(_sptRegistryPath, "registry.json");
+ private static JObject _sptRegistry = new JObject();
+
+ public void Enable()
+ {
+ Init();
+
+ new PatchPlayerPrefsSetInt().Enable();
+ new PatchPlayerPrefsSetFloat().Enable();
+ new PatchPlayerPrefsSetString().Enable();
+ new PatchPlayerPrefsGetInt().Enable();
+ new PatchPlayerPrefsGetFloat().Enable();
+ new PatchPlayerPrefsGetString().Enable();
+ new PatchPlayerPrefsHasKey().Enable();
+ new PatchPlayerPrefsDeleteKey().Enable();
+ new PatchPlayerPrefsDeleteAll().Enable();
+ new PatchPlayerPrefsSave().Enable();
+ }
+
+ public void Init()
+ {
+ // Make sure the registry directory exists
+ if (!Directory.Exists(_sptRegistryPath))
+ {
+ Directory.CreateDirectory(_sptRegistryPath);
+ }
+
+ // Load the existing registry if found
+ if (File.Exists(_registryFilePath))
+ {
+ _sptRegistry = JObject.Parse(File.ReadAllText(_registryFilePath));
+ }
+ }
+
+ public class PatchPlayerPrefsSetInt : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.SetInt));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(string key, int value)
+ {
+ _sptRegistry[key] = value;
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsSetFloat : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.SetFloat));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(string key, float value)
+ {
+ _sptRegistry[key] = value;
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsSetString : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.SetString));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(string key, string value)
+ {
+ _sptRegistry[key] = value;
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsGetInt : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.GetInt), [typeof(string), typeof(int)]);
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(ref int __result, string key, int defaultValue)
+ {
+ if (_sptRegistry.TryGetValue(key, out var value))
+ {
+ __result = value.Value();
+ }
+ else
+ {
+ __result = defaultValue;
+ }
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsGetFloat : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.GetFloat), [typeof(string), typeof(float)]);
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(ref float __result, string key, float defaultValue)
+ {
+ if (_sptRegistry.TryGetValue(key, out var value))
+ {
+ __result = value.Value();
+ }
+ else
+ {
+ __result = defaultValue;
+ }
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsGetString : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.GetString), [typeof(string), typeof(string)]);
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(ref string __result, string key, string defaultValue)
+ {
+ if (_sptRegistry.TryGetValue(key, out var value))
+ {
+ __result = value.Value();
+ }
+ else
+ {
+ __result = defaultValue;
+ }
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsHasKey : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.HasKey));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(ref bool __result, string key)
+ {
+ __result = _sptRegistry.ContainsKey(key);
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsDeleteKey : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.DeleteKey));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix(string key)
+ {
+ _sptRegistry.Remove(key);
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsDeleteAll : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.DeleteAll));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix()
+ {
+ _sptRegistry.RemoveAll();
+ return false;
+ }
+ }
+
+ public class PatchPlayerPrefsSave : ModulePatch
+ {
+ protected override MethodBase GetTargetMethod()
+ {
+ MethodInfo method = AccessTools.Method(typeof(PlayerPrefs), nameof(PlayerPrefs.Save));
+ return method;
+ }
+
+ [PatchPrefix]
+ private static bool PatchPrefix()
+ {
+ File.WriteAllText(_registryFilePath, _sptRegistry.ToString());
+ return false;
+ }
+ }
+
+ }
+}
diff --git a/project/SPT.Custom/SPTCustomPlugin.cs b/project/SPT.Custom/SPTCustomPlugin.cs
index b2c81df..7160a4d 100644
--- a/project/SPT.Custom/SPTCustomPlugin.cs
+++ b/project/SPT.Custom/SPTCustomPlugin.cs
@@ -27,6 +27,7 @@ namespace SPT.Custom
new AddTraitorScavsPatch().Enable();
new CustomAiPatch().Enable();
new SaveSettingsToSptFolderPatch().Enable();
+ new SaveRegistryToSptFolderPatches().Enable();
new QTEPatch().Enable();
new RedirectClientImageRequestsPatch().Enable();
new DisableGameModeAdjustButtonPatch().Enable();