diff --git a/PulsarModLoader/CustomGUI/GUIMain.cs b/PulsarModLoader/CustomGUI/GUIMain.cs index cdcee12..4511862 100644 --- a/PulsarModLoader/CustomGUI/GUIMain.cs +++ b/PulsarModLoader/CustomGUI/GUIMain.cs @@ -4,6 +4,8 @@ using System.Linq; using System.Reflection; using HarmonyLib; +using PulsarModLoader.Utilities; +using Steamworks; using UnityEngine; using static UnityEngine.GUILayout; @@ -95,8 +97,14 @@ void WindowFunction(int WindowID) ModListScroll = BeginScrollView(ModListScroll); { for (ushort p = 0; p < mods.Count; p++) - if (Button(mods[p].Name)) - selectedMod = p; + { + var mod = mods[p]; + var name = mods[p].Name; + if (ModManager.Instance.UpdatesAviable.Any(m => m.Mod == mod)) + name = "(!) " + name; + if (Button(name)) + selectedMod = p; + } } EndScrollView(); } @@ -122,6 +130,15 @@ void WindowFunction(int WindowID) if (mod.LongDescription != string.Empty) Label($"Long Description: {mod.LongDescription}"); Label($"MPRequirement: {((MPModChecks.MPRequirement)mod.MPRequirements).ToString()}"); + Space(1f); + var result = ModManager.Instance.UpdatesAviable.FirstOrDefault(av => av.Mod == mod); + if (result != null) + { + if (result.IsUpdated) + Label("Restart the game to apply the changes!"); + else if(Button($"Update this mod to version {result.Data.Version}?")) + ModUpdateCheck.UpdateMod(result); + } } EndScrollView(); } diff --git a/PulsarModLoader/MPModChecks/MPModCheckManager.cs b/PulsarModLoader/MPModChecks/MPModCheckManager.cs index c1fd125..02b279e 100644 --- a/PulsarModLoader/MPModChecks/MPModCheckManager.cs +++ b/PulsarModLoader/MPModChecks/MPModCheckManager.cs @@ -184,7 +184,7 @@ private void UpdateMyModList() { MyStream.Position = 0; byte[] Hash = MyHasher.ComputeHash(MyStream); - ProcessedMods[i] = new MPModDataBlock(currentMod.HarmonyIdentifier(), currentMod.Name, currentMod.Version, (MPRequirement)currentMod.MPRequirements, currentMod.ModID, Hash); + ProcessedMods[i] = new MPModDataBlock(currentMod.HarmonyIdentifier(), currentMod.Name, currentMod.Version, (MPRequirement)currentMod.MPRequirements, currentMod.VersionLink, Hash); } } } diff --git a/PulsarModLoader/ModManager.cs b/PulsarModLoader/ModManager.cs index 3453f2f..5ef901d 100644 --- a/PulsarModLoader/ModManager.cs +++ b/PulsarModLoader/ModManager.cs @@ -61,6 +61,8 @@ public class ModManager private readonly Dictionary activeMods; private readonly HashSet modDirectories; + internal List UpdatesAviable = new List(2); + private static ModManager _instance = null; /// @@ -98,7 +100,10 @@ public ModManager() IsOldVersion = false; #if !DEBUG - try + if ((PMLConfig.LastPMLUpdateCheck.Value.Day - DateTime.Today.Day) == 0) return; + PMLConfig.LastPMLUpdateCheck.Value = DateTime.Today; + + try { using (var web = new System.Net.WebClient()) { @@ -266,7 +271,6 @@ private Assembly ResolveModsDirectory(object sender, ResolveEventArgs args) /// public PulsarMod LoadMod(string assemblyPath) { - if (!File.Exists(assemblyPath)) { throw new IOException($"Couldn't find file: {assemblyPath}"); @@ -274,16 +278,21 @@ public PulsarMod LoadMod(string assemblyPath) try { - Assembly asm = Assembly.LoadFile(assemblyPath); - Type modType = asm.GetTypes().FirstOrDefault(t => t.IsSubclassOf(typeof(PulsarMod))); + Assembly asm = Assembly.Load(File.ReadAllBytes(assemblyPath)); // load as bytes to avoid locking the file + Type modType = asm.GetTypes().FirstOrDefault(t => t.IsSubclassOf(typeof(PulsarMod))); if (modType != null) { PulsarMod mod = Activator.CreateInstance(modType) as PulsarMod; - activeMods.Add(mod.Name, mod); + mod.VersionInfo = FileVersionInfo.GetVersionInfo(assemblyPath); + activeMods.Add(mod.Name, mod); OnModSuccessfullyLoaded?.Invoke(mod.Name, mod); Logger.Info($"Loaded mod: {mod.Name} Version {mod.Version} Author: {mod.Author}"); + + if (ModUpdateCheck.IsUpdateAviable(mod)) + Logger.Info($"↑ ↑ ↑ !This mod is outdated! ↑ ↑ ↑"); + return mod; } else diff --git a/PulsarModLoader/PMLConfig.cs b/PulsarModLoader/PMLConfig.cs index 6120467..cc65661 100644 --- a/PulsarModLoader/PMLConfig.cs +++ b/PulsarModLoader/PMLConfig.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System; +using UnityEngine; namespace PulsarModLoader { @@ -9,7 +10,9 @@ public static class PMLConfig public static SaveValue DebugMode = new SaveValue("DebugMode", false); - public static void SetDefault() + public static SaveValue LastPMLUpdateCheck = new SaveValue("LastPMLUpdateCheck", DateTime.Today.AddDays(-2)); + + public static void SetDefault() { ModInfoTextAnchor.Value = TextAnchor.UpperLeft; } diff --git a/PulsarModLoader/PulsarMod.cs b/PulsarModLoader/PulsarMod.cs index 9728773..44f76dd 100644 --- a/PulsarModLoader/PulsarMod.cs +++ b/PulsarModLoader/PulsarMod.cs @@ -11,7 +11,7 @@ namespace PulsarModLoader /// public abstract class PulsarMod { - private FileVersionInfo VersionInfo; + internal FileVersionInfo VersionInfo; /// /// @@ -31,7 +31,6 @@ public PulsarMod() // Can't use Assembly.GetExecutingAssembly() or it grabs this assembly instead of the mod's! // Executing assembly is technically PML's during base class methods. Assembly asm = GetType().Assembly; - VersionInfo = FileVersionInfo.GetVersionInfo(asm.Location); harmony = new Harmony(HarmonyIdentifier()); harmony.PatchAll(asm); @@ -176,10 +175,10 @@ public virtual void Enable() enabled = true; } - /// - /// Mod ID for future feature involving download IDs for a public webserver - /// - public virtual string ModID + /// + /// A link to the version file containing information about the latest version of the mod. Null if there is no link for this mod. + /// + public virtual string VersionLink { get { diff --git a/PulsarModLoader/PulsarModLoader.csproj b/PulsarModLoader/PulsarModLoader.csproj index 5e7c1f8..d3a646a 100644 --- a/PulsarModLoader/PulsarModLoader.csproj +++ b/PulsarModLoader/PulsarModLoader.csproj @@ -244,6 +244,7 @@ + diff --git a/PulsarModLoader/Utilities/ModUpdateCheck.cs b/PulsarModLoader/Utilities/ModUpdateCheck.cs new file mode 100644 index 0000000..5eedd1b --- /dev/null +++ b/PulsarModLoader/Utilities/ModUpdateCheck.cs @@ -0,0 +1,87 @@ +using PulsarModLoader.Chat.Commands; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Valve.Newtonsoft.Json; + +namespace PulsarModLoader.Utilities +{ + internal static class ModUpdateCheck + { + internal static bool IsUpdateAviable(PulsarMod mod) + { +#if DEBUG + return false; // disabled for debug builds +#endif + if (PMLConfig.DebugMode.Value) // disabled for debug mode + return false; + + if (string.IsNullOrEmpty(mod.VersionLink)) // disabled for mods without link + return false; + + using (var web = new System.Net.WebClient()) + { + web.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"); + var file = JsonConvert.DeserializeObject(web.DownloadString(mod.VersionLink)); + var result = CompareVersions(mod.Version, file.Version); + + if (result) + ModManager.Instance.UpdatesAviable.Add(new UpdateModInfo() { Mod = mod, Data = file }); + + return result; + } + } + + private static bool CompareVersions(string current, string fromServer) + { + var currentParsed = current.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); + var fromServerParsed = fromServer.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray(); + + for(int i = 0; i < currentParsed.Length; i++) + { + if (currentParsed[i] > fromServerParsed[i]) // return false if "1.4" vs "1.3" + return false; + + if (currentParsed[i] < fromServerParsed[i]) // return true if "1.4" vs "1.5" + return true; + } + + if (fromServerParsed.Length > currentParsed.Length) // return true if CompareVersions("1.4", "1.4.1") + return true; + + return false; // if "1.4" vs "1.4" + } + + internal static void UpdateMod(UpdateModInfo info) + { + //info.Mod.Unload(); + var path = info.Mod.VersionInfo.FileName; + using (var web = new System.Net.WebClient()) + { + web.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36"); + var dll = web.DownloadData(info.Data.DownloadLink); + File.WriteAllBytes(path, dll); + //ModManager.Instance.LoadMod(path); + } + info.IsUpdated = true; + } + + internal struct VersionFile + { + public string Version; + public string DownloadLink; + } + + internal class UpdateModInfo + { + public PulsarMod Mod; + public VersionFile Data; + public bool IsUpdated = false; + } + } +}