|
@@ -3,8 +3,10 @@ using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Diagnostics;
|
|
|
using System.IO;
|
|
|
+using System.Linq;
|
|
|
using System.Reflection;
|
|
|
using System.Text;
|
|
|
+using Newtonsoft.Json;
|
|
|
using UnityEngine;
|
|
|
using UnityEngine.SceneManagement;
|
|
|
using UnityInjector;
|
|
@@ -5180,6 +5182,19 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
private readonly bool[] zFlg = new bool[maxMaidCnt];
|
|
|
private readonly bool[] zurasi = new bool[maxMaidCnt];
|
|
|
private readonly bool[] zurasin = new bool[maxMaidCnt];
|
|
|
+ private static readonly string configPath;
|
|
|
+
|
|
|
+ static MultipleMaids()
|
|
|
+ {
|
|
|
+ configPath = Path.Combine(
|
|
|
+ Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
|
|
|
+ @"Config\MultipleMaids"
|
|
|
+ );
|
|
|
+ if (!Directory.Exists(configPath))
|
|
|
+ {
|
|
|
+ Directory.CreateDirectory(configPath);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
public void Awake()
|
|
|
{
|
|
@@ -5577,22 +5592,257 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private static bool ParseNativeMenuFile(int menuIndex, ItemData itemData)
|
|
|
+ private static readonly HashSet<string> accMpn = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
|
|
|
+ {
|
|
|
+ "accashi", "acchana", "acchat", "acchead", "accheso", "acckami", "acckamisub", "acckubi", "acckubiwa",
|
|
|
+ "accmimi", "accnip", "accsenaka", "accshippo", "accude", "accxxx", "bra", "glove", "headset", "megane",
|
|
|
+ "mizugi", "onepiece", "panz", "shoes", "skirt", "stkg", "wear",
|
|
|
+ };
|
|
|
+
|
|
|
+ private class BG2Cache
|
|
|
+ {
|
|
|
+ private static JsonSerializerSettings serializationSettings;
|
|
|
+ public static readonly string cachePath = Path.Combine(configPath, "cache.json");
|
|
|
+ private static Dictionary<string, SortItem> bg2Props;
|
|
|
+ public int Size => bg2Props.Count();
|
|
|
+ private bool rebuild = false;
|
|
|
+ public SortItem this[string menu]
|
|
|
+ {
|
|
|
+ get => bg2Props[menu];
|
|
|
+ set
|
|
|
+ {
|
|
|
+ rebuild = true;
|
|
|
+ bg2Props[menu] = value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static BG2Cache()
|
|
|
+ {
|
|
|
+ serializationSettings = new JsonSerializerSettings
|
|
|
+ {
|
|
|
+ NullValueHandling = NullValueHandling.Ignore,
|
|
|
+ DefaultValueHandling = DefaultValueHandling.Ignore
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ public BG2Cache()
|
|
|
+ {
|
|
|
+ if (bg2Props != null) return;
|
|
|
+
|
|
|
+ if (!File.Exists(cachePath))
|
|
|
+ {
|
|
|
+ bg2Props = new Dictionary<string, SortItem>();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ string cacheJson = File.ReadAllText(cachePath);
|
|
|
+ bg2Props = JsonConvert.DeserializeObject<Dictionary<string, SortItem>>(cacheJson);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool Has(string menu)
|
|
|
+ {
|
|
|
+ return bg2Props.ContainsKey(menu);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void WriteToFile()
|
|
|
+ {
|
|
|
+ if (!rebuild) return;
|
|
|
+ string cacheJson = JsonConvert.SerializeObject(bg2Props, serializationSettings);
|
|
|
+ File.WriteAllText(cachePath, cacheJson);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool bg2Initialized = false;
|
|
|
+ private bool bg2Busy = false;
|
|
|
+ private IEnumerator InitializeBG2()
|
|
|
+ {
|
|
|
+ foreach (string category in accMpn)
|
|
|
+ {
|
|
|
+ BG2Acc[category] = new List<SortItem>();
|
|
|
+ BG2AccInit[category] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bg2Initialized = true;
|
|
|
+ bg2Busy = true;
|
|
|
+
|
|
|
+ BG2Cache cache = new BG2Cache();
|
|
|
+
|
|
|
+ if (GameUty.MenuFiles?.Length > 0)
|
|
|
+ {
|
|
|
+ HashSet<string> modMenus = null;
|
|
|
+ if (!modItemsOnly) modMenus = new HashSet<string>(GameUty.ModOnlysMenuFiles);
|
|
|
+
|
|
|
+ string[] menuFiles = modItemsOnly ? GameUty.ModOnlysMenuFiles : GameUty.MenuFiles;
|
|
|
+ foreach (string menuFile in menuFiles)
|
|
|
+ {
|
|
|
+ SortItem item;
|
|
|
+ bool add = false;
|
|
|
+ if (!cache.Has(menuFile))
|
|
|
+ {
|
|
|
+ item = new SortItem()
|
|
|
+ {
|
|
|
+ menu = menuFile,
|
|
|
+ isMod = modItemsOnly || modMenus.Contains(menuFile)
|
|
|
+ };
|
|
|
+ add = ParseMenuFile(menuFile, item);
|
|
|
+ cache[menuFile] = item;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ item = cache[menuFile];
|
|
|
+ add = validBG2Menu(item);
|
|
|
+ }
|
|
|
+ if (add) BG2Acc[item.category].Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ while (!GameMain.Instance.MenuDataBase.JobFinished()) yield return null;
|
|
|
+
|
|
|
+ if (!modItemsOnly)
|
|
|
+ {
|
|
|
+ for (int i = 0; i < GameMain.Instance.MenuDataBase.GetDataSize(); i++)
|
|
|
+ {
|
|
|
+ SortItem item = new SortItem();
|
|
|
+ if (ParseNativeMenuFile(i, item)) BG2Acc[item.category].Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (string modMenuFile in GameUty.ModOnlysMenuFiles)
|
|
|
+ {
|
|
|
+ SortItem item;
|
|
|
+ bool add = false;
|
|
|
+ if (!cache.Has(modMenuFile))
|
|
|
+ {
|
|
|
+ item = new SortItem()
|
|
|
+ {
|
|
|
+ menu = modMenuFile,
|
|
|
+ isMod = true
|
|
|
+ };
|
|
|
+ add = ParseMenuFile(modMenuFile, item);
|
|
|
+ cache[modMenuFile] = item;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ item = cache[modMenuFile];
|
|
|
+ add = validBG2Menu(item);
|
|
|
+ }
|
|
|
+ if (add) BG2Acc[item.category].Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ cache.WriteToFile();
|
|
|
+
|
|
|
+ foreach (string modFile in Menu.GetModFiles())
|
|
|
+ {
|
|
|
+ SortItem item = new SortItem()
|
|
|
+ {
|
|
|
+ menu = modFile,
|
|
|
+ isMod = true,
|
|
|
+ isOfficialMod = true,
|
|
|
+ priority = 1000
|
|
|
+ };
|
|
|
+ if (ParseModMenuFile(modFile, item))
|
|
|
+ {
|
|
|
+ BG2Acc[item.category].Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ bg2Busy = false;
|
|
|
+ SetBG2Props();
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void WriteToFile(string name, IEnumerable<string> list)
|
|
|
+ {
|
|
|
+ string modsPath = Path.Combine(Path.GetFullPath(".\\"), @"Mod");
|
|
|
+ if (Path.GetExtension(name) != ".txt") name += ".txt";
|
|
|
+ File.WriteAllLines(Path.Combine(modsPath, name), list.ToArray());
|
|
|
+ }
|
|
|
+
|
|
|
+ private Dictionary<string, List<SortItem>> BG2Acc
|
|
|
+ = new Dictionary<string, List<SortItem>>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
+ private Dictionary<string, bool> BG2AccInit
|
|
|
+ = new Dictionary<string, bool>(StringComparer.InvariantCultureIgnoreCase);
|
|
|
+
|
|
|
+ private void SetBG2Props()
|
|
|
+ {
|
|
|
+ string category = slotArray[slotIndex];
|
|
|
+
|
|
|
+ sortList = BG2Acc[category];
|
|
|
+
|
|
|
+ if (!BG2AccInit[category])
|
|
|
+ {
|
|
|
+ BG2AccInit[category] = true;
|
|
|
+
|
|
|
+ sortList.Sort((x, y) =>
|
|
|
+ {
|
|
|
+ int res = x.priority.CompareTo(y.priority);
|
|
|
+ if (res == 0) res = x.name.CompareTo(y.name);
|
|
|
+ return res;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ numberOfModItems = 0;
|
|
|
+
|
|
|
+ string previousMenu = String.Empty;
|
|
|
+ sortList.RemoveAll(item =>
|
|
|
+ {
|
|
|
+ if (item.menu != previousMenu)
|
|
|
+ {
|
|
|
+ if (!modItemsOnly && item.isMod) numberOfModItems++;
|
|
|
+
|
|
|
+ if (item.tex == null)
|
|
|
+ {
|
|
|
+ Texture2D texture2D;
|
|
|
+ if (string.IsNullOrEmpty(item.icon) || !GameUty.FileSystem.IsExistentFile(item.icon))
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ byte[] data = ImportCM.LoadTexture(GameUty.FileSystem, item.icon, false).data;
|
|
|
+ texture2D = new Texture2D(50, 50, TextureFormat.RGB565, false);
|
|
|
+ texture2D.LoadImage(data);
|
|
|
+ }
|
|
|
+ item.tex = texture2D;
|
|
|
+ }
|
|
|
+ previousMenu = item.menu;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private static bool validBG2Menu(string menu)
|
|
|
+ {
|
|
|
+ menu = Path.GetFileNameWithoutExtension(menu).ToLower();
|
|
|
+ return !(menu.EndsWith("_del") || menu.Contains("zurashi") || menu.Contains("mekure")
|
|
|
+ || menu.Contains("porori") || menu.Contains("moza"));
|
|
|
+ }
|
|
|
+
|
|
|
+ private static bool validBG2Menu(SortItem item)
|
|
|
+ {
|
|
|
+ return accMpn.Contains(item.category) && validBG2Menu(item.menu);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static bool ParseNativeMenuFile(int menuIndex, SortItem sortItem)
|
|
|
{
|
|
|
MenuDataBase menuDataBase = GameMain.Instance.MenuDataBase;
|
|
|
menuDataBase.SetIndex(menuIndex);
|
|
|
if (menuDataBase.GetBoDelOnly()) return false;
|
|
|
- itemData.menu = menuDataBase.GetMenuFileName().ToLower();
|
|
|
- itemData.name = menuDataBase.GetMenuName();
|
|
|
- itemData.category = menuDataBase.GetCategoryMpnText();
|
|
|
- itemData.icon = menuDataBase.GetIconS();
|
|
|
- itemData.priority = (int)menuDataBase.GetPriority();
|
|
|
+ sortItem.category = menuDataBase.GetCategoryMpnText();
|
|
|
+ if (!accMpn.Contains(sortItem.category)) return false;
|
|
|
+ sortItem.menu = menuDataBase.GetMenuFileName().ToLower();
|
|
|
+ if (!validBG2Menu(sortItem.menu)) return false;
|
|
|
+ sortItem.name = menuDataBase.GetMenuName();
|
|
|
+ sortItem.icon = menuDataBase.GetIconS();
|
|
|
+ sortItem.priority = (int)menuDataBase.GetPriority();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- private static bool ParseMenuFile(string menuFile, ItemData itemData)
|
|
|
+ private static bool ParseMenuFile(string menuFile, SortItem sortItem)
|
|
|
{
|
|
|
- if (menuFile.EndsWith("_del.menu")) return false;
|
|
|
+ if (!validBG2Menu(menuFile)) return false;
|
|
|
|
|
|
byte[] buf;
|
|
|
using (AFileBase aFileBase = GameUty.FileOpen(menuFile))
|
|
@@ -5610,8 +5860,9 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
{
|
|
|
binaryReader.ReadInt32();
|
|
|
binaryReader.ReadString();
|
|
|
- itemData.name = binaryReader.ReadString();
|
|
|
- itemData.category = binaryReader.ReadString();
|
|
|
+ sortItem.name = binaryReader.ReadString();
|
|
|
+ sortItem.category = binaryReader.ReadString();
|
|
|
+ if (!accMpn.Contains(sortItem.category)) return false;
|
|
|
binaryReader.ReadString();
|
|
|
binaryReader.ReadInt32();
|
|
|
bool run = true;
|
|
@@ -5629,13 +5880,13 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
if (header == "icons" || header == "icon")
|
|
|
{
|
|
|
run = false;
|
|
|
- itemData.icon = binaryReader.ReadString();
|
|
|
+ sortItem.icon = binaryReader.ReadString();
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (header == "priority")
|
|
|
{
|
|
|
- int.TryParse(binaryReader.ReadString(), out itemData.priority);
|
|
|
+ int.TryParse(binaryReader.ReadString(), out sortItem.priority);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -5650,8 +5901,10 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- private static bool ParseModMenuFile(string modMenuFile, ItemData modItemData)
|
|
|
+ private static bool ParseModMenuFile(string modMenuFile, SortItem sortItem)
|
|
|
{
|
|
|
+ if (!validBG2Menu(modMenuFile)) return false;
|
|
|
+
|
|
|
byte[] buf = null;
|
|
|
try
|
|
|
{
|
|
@@ -5676,9 +5929,10 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
binaryReader.ReadInt32();
|
|
|
string iconName = binaryReader.ReadString();
|
|
|
string baseItemPath = binaryReader.ReadString().Replace(":", " ");
|
|
|
- modItemData.baseItem = Path.GetFileName(baseItemPath);
|
|
|
- modItemData.name = binaryReader.ReadString();
|
|
|
- modItemData.category = binaryReader.ReadString();
|
|
|
+ sortItem.baseMenu = Path.GetFileName(baseItemPath);
|
|
|
+ sortItem.name = binaryReader.ReadString();
|
|
|
+ sortItem.category = binaryReader.ReadString();
|
|
|
+ if (!accMpn.Contains(sortItem.category)) return false;
|
|
|
binaryReader.ReadString();
|
|
|
string mpnValue = binaryReader.ReadString();
|
|
|
MPN mpn = MPN.null_mpn;
|
|
@@ -5705,7 +5959,7 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
{
|
|
|
Texture2D tex = new Texture2D(1, 1, TextureFormat.RGBA32, false);
|
|
|
tex.LoadImage(data);
|
|
|
- modItemData.tex = tex;
|
|
|
+ sortItem.tex = tex;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -5718,6 +5972,7 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
+
|
|
|
private static string PluginString()
|
|
|
{
|
|
|
return $"{PluginName} {PluginVersion}";
|
|
@@ -5747,11 +6002,11 @@ namespace CM3D2.MultipleMaids.Plugin
|
|
|
|
|
|
private class SortItem
|
|
|
{
|
|
|
- public string category = String.Empty;
|
|
|
- public string menu = string.Empty;
|
|
|
- public string baseMenu = string.Empty;
|
|
|
- public string name = string.Empty;
|
|
|
- public string icon = string.Empty;
|
|
|
+ public string category;
|
|
|
+ public string menu;
|
|
|
+ public string baseMenu;
|
|
|
+ public string name;
|
|
|
+ public string icon;
|
|
|
public bool isCreative = false;
|
|
|
public bool isOfficialMod = false;
|
|
|
public bool isMod = false;
|