|  | @@ -1,9 +1,14 @@
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  |  using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using System.Diagnostics;
 | 
	
		
			
				|  |  |  using System.IO;
 | 
	
		
			
				|  |  | +using System.Linq;
 | 
	
		
			
				|  |  |  using System.Reflection;
 | 
	
		
			
				|  |  |  using System.Reflection.Emit;
 | 
	
		
			
				|  |  | +using System.Security.Cryptography;
 | 
	
		
			
				|  |  | +using System.Text;
 | 
	
		
			
				|  |  |  using UnityEngine;
 | 
	
		
			
				|  |  | +using Debug = UnityEngine.Debug;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace COM3D2.CacheEditMenu
 | 
	
		
			
				|  |  |  {
 | 
	
	
		
			
				|  | @@ -24,7 +29,7 @@ namespace COM3D2.CacheEditMenu
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      public static class Hooks
 | 
	
		
			
				|  |  |      {
 | 
	
		
			
				|  |  | -        private const int CACHE_VERSION = 1011;
 | 
	
		
			
				|  |  | +        private const int CACHE_VERSION = 1020;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |          private static readonly Dictionary<string, MenuInfo> infoCache = new Dictionary<string, MenuInfo>();
 | 
	
		
			
				|  |  |          private static BinaryWriter cacheWriter;
 | 
	
	
		
			
				|  | @@ -170,53 +175,84 @@ namespace COM3D2.CacheEditMenu
 | 
	
		
			
				|  |  |              return true;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        private static void Init()
 | 
	
		
			
				|  |  | +        private static byte[] HashMenus(string[] menuList)
 | 
	
		
			
				|  |  |          {
 | 
	
		
			
				|  |  | -            if (cacheWriter != null)
 | 
	
		
			
				|  |  | -                return;
 | 
	
		
			
				|  |  | -            var cacheDir = Path.Combine(Patcher.Patcher.SybarisPath, "EditMenuCache");
 | 
	
		
			
				|  |  | -            var cachePath = Path.Combine(cacheDir, "EditMenuCache.dat");
 | 
	
		
			
				|  |  | +            var md5 = MD5.Create();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var rebuildCache = false;
 | 
	
		
			
				|  |  | +            foreach (var s in menuList)
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                var buf = Encoding.Unicode.GetBytes(s);
 | 
	
		
			
				|  |  | +                md5.TransformBlock(buf, 0, buf.Length, null, 0);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            Directory.CreateDirectory(cacheDir);
 | 
	
		
			
				|  |  | +            md5.TransformFinalBlock(new byte[0], 0, 0);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return md5.Hash;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            if (File.Exists(cachePath))
 | 
	
		
			
				|  |  | -                using (var br = new BinaryReader(File.Open(cachePath, FileMode.Open, FileAccess.Read)))
 | 
	
		
			
				|  |  | +        private static bool ReadCache(string cachePath)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (!File.Exists(cachePath)) 
 | 
	
		
			
				|  |  | +                return false;
 | 
	
		
			
				|  |  | +            using (var br = new BinaryReader(File.Open(cachePath, FileMode.Open, FileAccess.Read)))
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                try
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    try
 | 
	
		
			
				|  |  | +                    var cacheVer = br.ReadInt32();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    if (cacheVer != CACHE_VERSION)
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        int cacheVer = br.ReadInt32();
 | 
	
		
			
				|  |  | -                        int menuFilesCount = br.ReadInt32();
 | 
	
		
			
				|  |  | -                        int modMenuFilesCount = br.ReadInt32();
 | 
	
		
			
				|  |  | -                        
 | 
	
		
			
				|  |  | -                        if (cacheVer == CACHE_VERSION && 
 | 
	
		
			
				|  |  | -                            menuFilesCount == GameUty.MenuFiles.Length && 
 | 
	
		
			
				|  |  | -                            modMenuFilesCount == GameUty.ModOnlysMenuFiles.Length)
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            while (true)
 | 
	
		
			
				|  |  | -                            {
 | 
	
		
			
				|  |  | -                                var menuInfo = new MenuInfo();
 | 
	
		
			
				|  |  | -                                menuInfo.Deserialize(br);
 | 
	
		
			
				|  |  | -                                infoCache[menuInfo.key] = menuInfo;
 | 
	
		
			
				|  |  | -                            }
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | -                        else
 | 
	
		
			
				|  |  | -                        {
 | 
	
		
			
				|  |  | -                            Debug.LogWarning("Outdated cache, rebuilding...");
 | 
	
		
			
				|  |  | -                            rebuildCache = true;
 | 
	
		
			
				|  |  | -                        }
 | 
	
		
			
				|  |  | +                        Debug.LogWarning("Old cache version, rebuilding...");
 | 
	
		
			
				|  |  | +                        return false;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | -                    catch (FormatException e)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    var menuFilesHashSize = br.ReadInt32();
 | 
	
		
			
				|  |  | +                    var menuFilesHash = br.ReadBytes(menuFilesHashSize);
 | 
	
		
			
				|  |  | +                    if (!menuFilesHash.SequenceEqual(HashMenus(GameUty.MenuFiles)))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        Debug.Log($"Failed to deserialize cache because {e.Message}. Rebuilding the cache...");
 | 
	
		
			
				|  |  | -                        rebuildCache = true;
 | 
	
		
			
				|  |  | +                        Debug.LogWarning(".menu files changed, rebuilding cache...");
 | 
	
		
			
				|  |  | +                        return false;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  | -                    catch (EndOfStreamException)
 | 
	
		
			
				|  |  | +                            
 | 
	
		
			
				|  |  | +                    var modMenuFilesHashSize = br.ReadInt32();
 | 
	
		
			
				|  |  | +                    var modMenuFilesHash = br.ReadBytes(modMenuFilesHashSize);
 | 
	
		
			
				|  |  | +                    if (!modMenuFilesHash.SequenceEqual(HashMenus(GameUty.ModOnlysMenuFiles)))
 | 
	
		
			
				|  |  |                      {
 | 
	
		
			
				|  |  | -                        // End of file, no need to read more
 | 
	
		
			
				|  |  | +                        Debug.LogWarning("Mod .menu files changed, rebuilding cache...");
 | 
	
		
			
				|  |  | +                        return false;
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                        
 | 
	
		
			
				|  |  | +                    while (true)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        var menuInfo = new MenuInfo();
 | 
	
		
			
				|  |  | +                        menuInfo.Deserialize(br);
 | 
	
		
			
				|  |  | +                        infoCache[menuInfo.key] = menuInfo;
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  | +                catch (FormatException e)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    Debug.Log($"Failed to deserialize cache because {e.Message}. Rebuilding the cache...");
 | 
	
		
			
				|  |  | +                    return false;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                catch (EndOfStreamException)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    // End of file, no need to read more
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return true;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        private static void Init()
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            if (cacheWriter != null)
 | 
	
		
			
				|  |  | +                return;
 | 
	
		
			
				|  |  | +            var cacheDir = Path.Combine(Patcher.Patcher.SybarisPath, "EditMenuCache");
 | 
	
		
			
				|  |  | +            var cachePath = Path.Combine(cacheDir, "EditMenuCache.dat");
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            Directory.CreateDirectory(cacheDir);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            var rebuildCache = !ReadCache(cachePath);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var stream = rebuildCache ? File.Create(cachePath) : File.OpenWrite(cachePath);
 | 
	
		
			
				|  |  |              cacheWriter = new BinaryWriter(stream);
 | 
	
	
		
			
				|  | @@ -224,8 +260,14 @@ namespace COM3D2.CacheEditMenu
 | 
	
		
			
				|  |  |              if (rebuildCache)
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  cacheWriter.Write(CACHE_VERSION);
 | 
	
		
			
				|  |  | -                cacheWriter.Write(GameUty.MenuFiles.Length);
 | 
	
		
			
				|  |  | -                cacheWriter.Write(GameUty.ModOnlysMenuFiles.Length);
 | 
	
		
			
				|  |  | +                var menuHash = HashMenus(GameUty.MenuFiles);
 | 
	
		
			
				|  |  | +                var modMenuHash = HashMenus(GameUty.ModOnlysMenuFiles);
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                cacheWriter.Write(menuHash.Length);
 | 
	
		
			
				|  |  | +                cacheWriter.Write(menuHash);
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                cacheWriter.Write(modMenuHash.Length);
 | 
	
		
			
				|  |  | +                cacheWriter.Write(modMenuHash);
 | 
	
		
			
				|  |  |                  
 | 
	
		
			
				|  |  |                  foreach (var keyValuePair in infoCache)
 | 
	
		
			
				|  |  |                      keyValuePair.Value.Serialize(cacheWriter);
 |