From 167183795c2ab5cf56c8c27168d39cfb424692a3 Mon Sep 17 00:00:00 2001 From: nexus4880 <38168516+nexus4880@users.noreply.github.com> Date: Wed, 29 May 2024 10:09:32 -0700 Subject: [PATCH 1/4] Added the mod verification logic --- Fika.Core/FikaPlugin.cs | 2 +- .../Models/ModValidationResponse.cs | 17 +++ Fika.Core/Utils/FikaModHandler.cs | 102 ++++++++++++------ 3 files changed, 89 insertions(+), 32 deletions(-) create mode 100644 Fika.Core/Networking/Models/ModValidationResponse.cs diff --git a/Fika.Core/FikaPlugin.cs b/Fika.Core/FikaPlugin.cs index 848ffe38..10a0aae6 100644 --- a/Fika.Core/FikaPlugin.cs +++ b/Fika.Core/FikaPlugin.cs @@ -246,7 +246,7 @@ protected void Awake() private IEnumerator RunModHandler() { yield return new WaitForSeconds(5); - ModHandler.Run(); + ModHandler.VerifyMods(); } private void GetClientConfig() diff --git a/Fika.Core/Networking/Models/ModValidationResponse.cs b/Fika.Core/Networking/Models/ModValidationResponse.cs new file mode 100644 index 00000000..f5fba64c --- /dev/null +++ b/Fika.Core/Networking/Models/ModValidationResponse.cs @@ -0,0 +1,17 @@ +using System.Runtime.Serialization; + +namespace Fika.Core.Networking.Http.Models +{ + [DataContract] + public struct ModValidationResponse + { + [DataMember(Name = "forbidden")] + public string[] Forbidden; + + [DataMember(Name = "missingRequired")] + public string[] MissingRequired; + + [DataMember(Name = "hashMismatch")] + public string[] HashMismatch; + } +} \ No newline at end of file diff --git a/Fika.Core/Utils/FikaModHandler.cs b/Fika.Core/Utils/FikaModHandler.cs index c3480226..27b02e3e 100644 --- a/Fika.Core/Utils/FikaModHandler.cs +++ b/Fika.Core/Utils/FikaModHandler.cs @@ -1,70 +1,110 @@ using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; -using Fika.Core.Networking.Models; +using Comfort.Common; +using EFT; +using EFT.UI; +using Fika.Core.Networking.Http.Models; using LiteNetLib.Utils; +using Newtonsoft.Json; +using SPT.Common.Http; +using System.Collections; using System.Collections.Generic; using System.IO; +using UnityEngine; +using Logger = BepInEx.Logging.Logger; namespace Fika.Core.Utils { public class FikaModHandler { - private string[] loadedMods; private readonly ManualLogSource logger = Logger.CreateLogSource("FikaModHandler"); public bool QuestingBotsLoaded = false; public bool SAINLoaded = false; - public void Run() + public void VerifyMods() { - // Store all loaded plugins (mods) to improve compatibility - List tempPluginInfos = []; + PluginInfo[] pluginInfos = [.. Chainloader.PluginInfos.Values]; + + // Set capacity to avoid unnecessarily resizing for people who have a lot of mods loaded + Dictionary loadedMods = new Dictionary(pluginInfos.Length); + + foreach (PluginInfo pluginInfo in pluginInfos) + { + string location = pluginInfo.Location; + byte[] fileBytes = File.ReadAllBytes(location); + uint crc32 = CRC32C.Compute(fileBytes, 0, fileBytes.Length); + loadedMods.Add(pluginInfo.Metadata.GUID, crc32); + CheckSpecialMods(pluginInfo.Metadata.GUID); + } + + string modValidationRequestJson = JsonConvert.SerializeObject(loadedMods); + logger.LogDebug(modValidationRequestJson); + + string validationJson = RequestHandler.PostJson("/fika/client/check/mods", modValidationRequestJson); + logger.LogDebug(validationJson); - foreach (string key in Chainloader.PluginInfos.Keys) + ModValidationResponse validationResult = + JsonConvert.DeserializeObject(validationJson); + + // If any errors were detected we will print what has happened + bool installationError = + validationResult.Forbidden.Length > 0 || + validationResult.MissingRequired.Length > 0 || + validationResult.HashMismatch.Length > 0; + + if (validationResult.Forbidden.Length > 0) { - logger.LogInfo($"Adding {key}, {Chainloader.PluginInfos[key].Metadata.Name} to loaded mods."); - tempPluginInfos.Add(key); - CheckSpecialMods(key); + logger.LogError($"{validationResult.Forbidden.Length} forbidden mod(s) are loaded, have the server host allow or remove the following mods: {string.Join(", ", validationResult.Forbidden)}"); } - /*if (FikaPlugin.Instance.RequiredMods.Count > 0) + if (validationResult.MissingRequired.Length > 0) { - VerifyMods(); - }*/ + logger.LogError($"{validationResult.MissingRequired.Length} missing required mod(s), verify the following mods are present: {string.Join(", ", validationResult.MissingRequired)}"); + } - loadedMods = [.. tempPluginInfos]; + if (validationResult.HashMismatch.Length > 0) + { + logger.LogWarning($"{validationResult.HashMismatch.Length} mismatched mod(s) are loaded, verify the following mods are up to date with the server host: {string.Join(", ", validationResult.HashMismatch)}"); + } - logger.LogInfo($"Loaded {loadedMods.Length} mods!"); + if (installationError) + { + StaticManager.BeginCoroutine(InformInstallationError()); + } } - private void VerifyMods() + private IEnumerator InformInstallationError() { - PluginInfo[] pluginInfos = [.. Chainloader.PluginInfos.Values]; - Dictionary loadedMods = []; - - foreach (PluginInfo pluginInfo in pluginInfos) + while (!Singleton.Instantiated) { - string location = pluginInfo.Location; - byte[] fileBytes = File.ReadAllBytes(location); - uint crc32 = CRC32C.Compute(fileBytes, 0, fileBytes.Length); - loadedMods.Add(pluginInfo.Metadata.GUID, crc32.ToString()); + yield return null; } - ModValidationRequest modValidationRequest = new(loadedMods); - // Send + string message = "Your client doesn't meet server requirements, check logs for more details"; + + // -1f time makes the message permanent + Singleton.Instance.ShowCriticalErrorScreen("INSTALLATION ERROR", message, + ErrorScreen.EButtonType.QuitButton, -1f, Application.Quit, null); } private void CheckSpecialMods(string key) { - if (key == "com.DanW.QuestingBots") + switch (key) { - QuestingBotsLoaded = true; - } + case "com.DanW.QuestingBots": + { + QuestingBotsLoaded = true; - if (key == "me.sol.sain") - { - SAINLoaded = true; + break; + } + case "me.sol.sain": + { + SAINLoaded = true; + + break; + } } } } From 4b6d3033f310b94e84f4390c4405e7eda3638bce Mon Sep 17 00:00:00 2001 From: nexus4880 <38168516+nexus4880@users.noreply.github.com> Date: Wed, 29 May 2024 10:26:21 -0700 Subject: [PATCH 2/4] Added a log for all loaded mods to help identify potential issues --- Fika.Core/Utils/FikaModHandler.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Fika.Core/Utils/FikaModHandler.cs b/Fika.Core/Utils/FikaModHandler.cs index 27b02e3e..65e06c82 100644 --- a/Fika.Core/Utils/FikaModHandler.cs +++ b/Fika.Core/Utils/FikaModHandler.cs @@ -36,6 +36,7 @@ public void VerifyMods() byte[] fileBytes = File.ReadAllBytes(location); uint crc32 = CRC32C.Compute(fileBytes, 0, fileBytes.Length); loadedMods.Add(pluginInfo.Metadata.GUID, crc32); + logger.LogInfo($"Loaded plugin: [{pluginInfo.Metadata.Name}] with GUID [{pluginInfo.Metadata.GUID}] and crc32 [{crc32}]"); CheckSpecialMods(pluginInfo.Metadata.GUID); } From e6f2b6b78cde67d32ad0c4bf7ad392df9196607d Mon Sep 17 00:00:00 2001 From: nexus4880 <38168516+nexus4880@users.noreply.github.com> Date: Wed, 29 May 2024 10:44:49 -0700 Subject: [PATCH 3/4] Updated the ID for FikaPlugin --- Fika.Core/FikaPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fika.Core/FikaPlugin.cs b/Fika.Core/FikaPlugin.cs index 10a0aae6..b7513ec8 100644 --- a/Fika.Core/FikaPlugin.cs +++ b/Fika.Core/FikaPlugin.cs @@ -46,7 +46,7 @@ namespace Fika.Core /// Originally by: Paulov
/// Re-written by: Lacyway /// - [BepInPlugin("com.fika.core", "Fika.Core", "0.9.8906")] + [BepInPlugin("com.project-fika.core", "Fika.Core", "0.9.8906")] [BepInProcess("EscapeFromTarkov.exe")] [BepInDependency("com.SPT.custom", BepInDependency.DependencyFlags.HardDependency)] // This is used so that we guarantee to load after aki-custom, that way we can disable its patches [BepInDependency("com.SPT.singleplayer", BepInDependency.DependencyFlags.HardDependency)] // This is used so that we guarantee to load after aki-singleplayer, that way we can disable its patches From 9e507c6181bc43ad6d938ec3fda14363e1874a2b Mon Sep 17 00:00:00 2001 From: nexus4880 <38168516+nexus4880@users.noreply.github.com> Date: Wed, 29 May 2024 16:47:19 -0700 Subject: [PATCH 4/4] Revert "Updated the ID for FikaPlugin" This reverts commit e6f2b6b78cde67d32ad0c4bf7ad392df9196607d. --- Fika.Core/FikaPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fika.Core/FikaPlugin.cs b/Fika.Core/FikaPlugin.cs index b7513ec8..10a0aae6 100644 --- a/Fika.Core/FikaPlugin.cs +++ b/Fika.Core/FikaPlugin.cs @@ -46,7 +46,7 @@ namespace Fika.Core /// Originally by: Paulov
/// Re-written by: Lacyway /// - [BepInPlugin("com.project-fika.core", "Fika.Core", "0.9.8906")] + [BepInPlugin("com.fika.core", "Fika.Core", "0.9.8906")] [BepInProcess("EscapeFromTarkov.exe")] [BepInDependency("com.SPT.custom", BepInDependency.DependencyFlags.HardDependency)] // This is used so that we guarantee to load after aki-custom, that way we can disable its patches [BepInDependency("com.SPT.singleplayer", BepInDependency.DependencyFlags.HardDependency)] // This is used so that we guarantee to load after aki-singleplayer, that way we can disable its patches