diff --git a/KK_ReloadCharaListOnChange/KK_ReloadCharaListOnChange.cs b/KK_ReloadCharaListOnChange/KK_ReloadCharaListOnChange.cs
index 0278550a..cb8f1174 100644
--- a/KK_ReloadCharaListOnChange/KK_ReloadCharaListOnChange.cs
+++ b/KK_ReloadCharaListOnChange/KK_ReloadCharaListOnChange.cs
@@ -3,9 +3,7 @@
using ChaCustom;
using Harmony;
using System;
-using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Reflection;
using System.Threading;
using UnityEngine.SceneManagement;
@@ -14,29 +12,32 @@
namespace KK_ReloadCharaListOnChange
{
///
- /// Watches the character folders for changes and updates the character/coordinate list in the chara maker.
- /// Probably should be expanded to support studio lists too.
+ /// Watches the character folders for changes and updates the character/coordinate list in the chara maker and studio.
///
[BepInDependency("com.bepis.bepinex.sideloader")]
[BepInPlugin("com.deathweasel.bepinex.reloadcharalistonchange", "Reload Chara List On Change", Version)]
public class KK_ReloadCharaListOnChange : BaseUnityPlugin
{
- public const string Version = "1.3";
+ public const string Version = "1.4";
private static FileSystemWatcher CharacterCardWatcher;
private static FileSystemWatcher CoordinateCardWatcher;
+ private static FileSystemWatcher StudioFemaleCardWatcher;
+ private static FileSystemWatcher StudioMaleCardWatcher;
+ private static FileSystemWatcher StudioCoordinateCardWatcher;
private static readonly string FemaleCardPath = Path.Combine(Paths.GameRootPath, "UserData\\chara\\female");
private static readonly string MaleCardPath = Path.Combine(Paths.GameRootPath, "UserData\\chara\\male");
private static readonly string CoordinateCardPath = Path.Combine(Paths.GameRootPath, "UserData\\coordinate");
- private static List CharacterCardEventList = new List();
- private static List CoordinateCardEventList = new List();
private static bool DoRefresh = false;
private static bool EventFromCharaMaker = false;
private static bool InCharaMaker = false;
- private static CustomCharaFile listCtrlCharacter;
- private static CustomFileListCtrl listCtrlCoordinate;
- private static List lstFileInfoCoordinate;
+ private static CustomCharaFile CustomCharaFileInstance;
+ private static CustomCoordinateFile CustomCoordinateFileInstance;
+ private static Studio.CharaList StudioFemaleListInstance;
+ private static Studio.CharaList StudioMaleListInstance;
+ private static object StudioCoordinateListInstance;
private static Timer CardTimer;
- private static ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
+ private static CardEventType EventType;
+ private static readonly ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
public void Main()
{
@@ -44,64 +45,23 @@ public void Main()
var harmony = HarmonyInstance.Create("com.deathweasel.bepinex.reloadcharalistonchange");
harmony.PatchAll(typeof(KK_ReloadCharaListOnChange));
+ harmony.Patch(typeof(Studio.MPCharCtrl).GetNestedType("CostumeInfo", BindingFlags.NonPublic).GetMethod("InitFileList", AccessTools.all),
+ new HarmonyMethod(typeof(KK_ReloadCharaListOnChange).GetMethod(nameof(StudioCoordinateListPrefix), AccessTools.all)), null);
}
///
- /// When cards are added or removed from the folder create a list of them
+ /// When cards are added or removed from the folder set a flag
///
- private static void CreateCharacterEventLists(object sender, FileSystemEventArgs args)
+ private static void CardEvent(CardEventType eventType)
{
- try
- {
- //Needs to be locked since dumping a bunch of cards in the folder will trigger this event a whole bunch of times that all run at once
- //which sometimes ends up with the list being modified while we're cycling through it later, which is very bad
- rwlock.EnterWriteLock();
+ //Needs to be locked since dumping a bunch of cards in the folder will trigger this event a whole bunch of times that all run at once
+ rwlock.EnterWriteLock();
- //Start a timer which will be reset every time a card is added/removed for when the user dumps in a whole bunch at once
- //Once the timer elapses, a flag will be set to do the refresh on all the cards that were add/remove at once
- if (CardTimer == null)
- {
- //First file, start timer
- CardTimer = new Timer(1000);
- CardTimer.Elapsed += (o, ee) => DoRefresh = true;
- CardTimer.Start();
- }
- else
- {
- //Subsequent file, reset timer
- CardTimer.Stop();
- CardTimer.Start();
- }
-
- string CardPath = args.FullPath;
- string CardName = CardPath.Remove(0, CardPath.LastIndexOf('\\') + 1);
- CardName = CardName.Remove(CardName.IndexOf('.'));
-
- CharacterCardEventList.Add(new CardEventInfo(CardName, CardPath, args.ChangeType));
- }
- catch (Exception ex)
- {
- Logger.Log(LogLevel.Error, ex);
- CardTimer?.Dispose();
- CharacterCardEventList.Clear();
- }
- finally
- {
- rwlock.ExitWriteLock();
- }
- }
- ///
- /// When cards are added or removed from the folder create a list of them
- ///
- private static void CreateCoordinateEventLists(object sender, FileSystemEventArgs args)
- {
try
{
- //Needs to be locked since dumping a bunch of cards in the folder will trigger this event a whole bunch of times that all run at once
- //which sometimes ends up with the list being modified while we're cycling through it later, which is very bad
- rwlock.EnterWriteLock();
+ EventType = eventType;
//Start a timer which will be reset every time a card is added/removed for when the user dumps in a whole bunch at once
- //Once the timer elapses, a flag will be set to do the refresh on all the cards that were add/remove at once
+ //Once the timer elapses, a flag will be set to do the refresh, which will then happen on the next Update.
if (CardTimer == null)
{
//First file, start timer
@@ -115,39 +75,48 @@ private static void CreateCoordinateEventLists(object sender, FileSystemEventArg
CardTimer.Stop();
CardTimer.Start();
}
-
- string CardPath = args.FullPath;
- string CardName = CardPath.Remove(0, CardPath.LastIndexOf('\\') + 1);
- CardName = CardName.Remove(CardName.IndexOf('.'));
-
- CoordinateCardEventList.Add(new CardEventInfo(CardName, CardPath, args.ChangeType));
}
catch (Exception ex)
{
Logger.Log(LogLevel.Error, ex);
CardTimer?.Dispose();
- CharacterCardEventList.Clear();
- }
- finally
- {
- rwlock.ExitWriteLock();
}
+
+ rwlock.ExitWriteLock();
}
///
- /// Add or remove the cards from the list, then refresh the list
+ /// Refresh the list
///
- private static void RefreshCharacterList()
+ private static void RefreshList()
{
try
{
//Turn off resolving to prevent spam since modded stuff isn't relevent for making this list.
Sideloader.AutoResolver.Hooks.IsResolving = false;
-
- typeof(CustomCharaFile).GetMethod("Initialize", BindingFlags.NonPublic | BindingFlags.Instance)?.Invoke(listCtrlCharacter, null);
+ switch (EventType)
+ {
+ case CardEventType.CharaMakerCharacter:
+ typeof(CustomCharaFile).GetMethod("Initialize", AccessTools.all)?.Invoke(CustomCharaFileInstance, null);
+ break;
+ case CardEventType.CharaMakerCoordinate:
+ typeof(CustomCoordinateFile).GetMethod("Initialize", AccessTools.all)?.Invoke(CustomCoordinateFileInstance, null);
+ break;
+ case CardEventType.StudioFemale:
+ StudioFemaleListInstance.InitCharaList(true);
+ break;
+ case CardEventType.StudioMale:
+ StudioMaleListInstance.InitCharaList(true);
+ break;
+ case CardEventType.StudioCoordinate:
+ var sex = Traverse.Create(StudioCoordinateListInstance).Field("sex").GetValue();
+ typeof(Studio.MPCharCtrl).GetNestedType("CostumeInfo", BindingFlags.NonPublic).GetMethod("InitList", AccessTools.all)?.Invoke(StudioCoordinateListInstance, new object[] { 100 });
+ Traverse.Create(StudioCoordinateListInstance).Field("sex").SetValue(sex);
+ break;
+ }
}
catch (Exception ex)
{
- Logger.Log(LogLevel.Error | LogLevel.Message, "An error occured attempting to refresh the character list. Please restart the chara maker.");
+ Logger.Log(LogLevel.Error | LogLevel.Message, "An error occured attempting to refresh the list.");
Logger.Log(LogLevel.Error, $"KK_ReloadCharaListOnChange error: {ex.Message}");
Logger.Log(LogLevel.Error, ex);
}
@@ -157,89 +126,26 @@ private static void RefreshCharacterList()
}
}
///
- /// Add or remove the cards from the list, then refresh the list
- ///
- private static void RefreshCoordinateList()
- {
- bool DidAddOrRemove = false;
-
- //Turn off resolving to prevent spam since modded stuff isn't relevent for making this list.
- Sideloader.AutoResolver.Hooks.IsResolving = false;
-
- try
- {
- foreach (CardEventInfo CardEvent in CoordinateCardEventList)
- {
- if (CardEvent.EventType == WatcherChangeTypes.Deleted)
- {
- CustomFileInfo CardInfo = lstFileInfoCoordinate.FirstOrDefault(x => x.FileName == CardEvent.CardName);
- if (CardInfo == null)
- Logger.Log(LogLevel.Warning, $"{CardEvent.CardName}.png was removed from the folder but could not be found on character list, skipping.");
- else
- {
- listCtrlCoordinate.RemoveList(CardInfo.index);
- DidAddOrRemove = true;
- }
- }
- else if (CardEvent.EventType == WatcherChangeTypes.Created)
- {
- ChaFileCoordinate AddedCoordinate = new ChaFileCoordinate();
-
- if (!AddedCoordinate.LoadFile(CardEvent.CardPath))
- {
- Logger.Log(LogLevel.Warning | LogLevel.Message, $"{CardEvent.CardName}.png is not a coordinate card.");
- }
- else
- {
- DateTime CardTime = File.GetLastWriteTime(CardEvent.CardPath);
-
- //Find the highest index to use for our new index
- int Index = lstFileInfoCoordinate.Count == 0 ? 0 : lstFileInfoCoordinate.Max(x => x.index) + 1;
-
- listCtrlCoordinate.AddList(Index, AddedCoordinate.coordinateName, string.Empty, string.Empty, CardEvent.CardPath, CardEvent.CardName, CardTime);
- DidAddOrRemove = true;
- }
- }
- }
- if (DidAddOrRemove)
- listCtrlCoordinate.ReCreate();
- }
- catch (Exception ex)
- {
- Logger.Log(LogLevel.Error | LogLevel.Message, "An error occured attempting to refresh the coordinate list. Please restart the chara maker.");
- Logger.Log(LogLevel.Error, $"KK_ReloadCharaListOnChange error: {ex.Message}");
- Logger.Log(LogLevel.Error, ex);
- }
- Sideloader.AutoResolver.Hooks.IsResolving = true;
- }
- ///
- /// On a game update run the actual refresh. It must be run from an update or it causes all sorts of errors for reasons I can't figure out.
+ /// On a game update run the actual refresh. It must be run from an update or it causes all sorts of errors.
///
private void Update()
{
if (EventFromCharaMaker && DoRefresh)
{
- //If we saved or deleted a card from the chara maker itself clear the events so cards don't get added twice
- CharacterCardEventList.Clear();
- CoordinateCardEventList.Clear();
+ //If we saved or deleted a card from the chara maker itself there's no need to refresh, the game will handle that.
CardTimer.Dispose();
EventFromCharaMaker = false;
DoRefresh = false;
}
else if (DoRefresh)
{
- if (CharacterCardEventList.Count > 0)
- RefreshCharacterList();
- if (CoordinateCardEventList.Count > 0)
- RefreshCoordinateList();
- CharacterCardEventList.Clear();
- CoordinateCardEventList.Clear();
+ RefreshList();
CardTimer.Dispose();
DoRefresh = false;
}
}
///
- /// Destroy the file watcher when the chara maker ends
+ /// End the file watcher and set variables back to default for next time the chara maker is started
///
private void SceneUnloaded(Scene s)
{
@@ -249,47 +155,32 @@ private void SceneUnloaded(Scene s)
DoRefresh = false;
EventFromCharaMaker = false;
CardTimer?.Dispose();
- CharacterCardWatcher.Dispose();
- CharacterCardEventList.Clear();
- CoordinateCardWatcher.Dispose();
- CoordinateCardEventList.Clear();
- }
- }
-
- private class CardEventInfo
- {
- public string CardName;
- public string CardPath;
- public WatcherChangeTypes EventType;
-
- public CardEventInfo(string cardName, string cardPath, WatcherChangeTypes eventType)
- {
- CardName = cardName;
- CardPath = cardPath;
- EventType = eventType;
+ CardTimer = null;
+ CharacterCardWatcher?.Dispose();
+ CharacterCardWatcher = null;
+ CoordinateCardWatcher?.Dispose();
+ CoordinateCardWatcher = null;
}
}
///
- /// When saving the a new character card in game set a flag
+ /// When saving a new character card in game set a flag
///
[HarmonyPrefix]
[HarmonyPatch(typeof(ChaFileControl), "SaveCharaFile", new[] { typeof(BinaryWriter), typeof(bool) })]
public static void SaveCharaFilePrefix()
{
- if (InCharaMaker)
- if (Singleton.Instance.customCtrl.saveNew == true)
- EventFromCharaMaker = true;
+ if (InCharaMaker && Singleton.Instance.customCtrl.saveNew == true)
+ EventFromCharaMaker = true;
}
///
- /// When saving the a new coordinate card in game set a flag
+ /// When saving a new coordinate card in game set a flag
///
[HarmonyPrefix]
[HarmonyPatch(typeof(ChaFileCoordinate), nameof(ChaFileCoordinate.SaveFile), new[] { typeof(string) })]
public static void SaveCoordinateFilePrefix(string path)
{
- if (InCharaMaker)
- if (!File.Exists(path)) //saving new
- EventFromCharaMaker = true;
+ if (InCharaMaker && !File.Exists(path))
+ EventFromCharaMaker = true;
}
///
/// When deleting a chara card in game set a flag
@@ -318,17 +209,19 @@ public static void DeleteCoordinateFilePrefix()
[HarmonyPatch(typeof(CustomCharaFile), "Initialize")]
public static void CustomCharaFileInitializePrefix(CustomCharaFile __instance)
{
- //Get some references to fields we'll be using later on
- listCtrlCharacter = __instance;
+ if (CharacterCardWatcher == null)
+ {
+ CustomCharaFileInstance = __instance;
- CharacterCardWatcher = new FileSystemWatcher();
- CharacterCardWatcher.Path = Singleton.Instance.modeSex == 0 ? MaleCardPath : FemaleCardPath;
- CharacterCardWatcher.NotifyFilter = NotifyFilters.FileName;
- CharacterCardWatcher.Filter = "*.png";
- CharacterCardWatcher.EnableRaisingEvents = true;
- CharacterCardWatcher.Created += new FileSystemEventHandler(CreateCharacterEventLists);
- CharacterCardWatcher.Deleted += new FileSystemEventHandler(CreateCharacterEventLists);
- CharacterCardWatcher.IncludeSubdirectories = true;
+ CharacterCardWatcher = new FileSystemWatcher();
+ CharacterCardWatcher.Path = Singleton.Instance.modeSex == 0 ? MaleCardPath : FemaleCardPath;
+ CharacterCardWatcher.NotifyFilter = NotifyFilters.FileName;
+ CharacterCardWatcher.Filter = "*.png";
+ CharacterCardWatcher.EnableRaisingEvents = true;
+ CharacterCardWatcher.Created += (o, ee) => CardEvent(CardEventType.CharaMakerCharacter);
+ CharacterCardWatcher.Deleted += (o, ee) => CardEvent(CardEventType.CharaMakerCharacter);
+ CharacterCardWatcher.IncludeSubdirectories = true;
+ }
InCharaMaker = true;
}
@@ -339,17 +232,80 @@ public static void CustomCharaFileInitializePrefix(CustomCharaFile __instance)
[HarmonyPatch(typeof(CustomCoordinateFile), "Initialize")]
public static void CustomCoordinateFileInitializePrefix(CustomCoordinateFile __instance)
{
- //Get some references to fields we'll be using later on
- listCtrlCoordinate = Traverse.Create(__instance).Field("listCtrl").GetValue();
- lstFileInfoCoordinate = Traverse.Create(listCtrlCoordinate).Field("lstFileInfo").GetValue>();
+ if (CoordinateCardWatcher == null)
+ {
+ CustomCoordinateFileInstance = __instance;
+
+ CoordinateCardWatcher = new FileSystemWatcher();
+ CoordinateCardWatcher.Path = CoordinateCardPath;
+ CoordinateCardWatcher.NotifyFilter = NotifyFilters.FileName;
+ CoordinateCardWatcher.Filter = "*.png";
+ CoordinateCardWatcher.EnableRaisingEvents = true;
+ CoordinateCardWatcher.Created += (o, ee) => CardEvent(CardEventType.CharaMakerCoordinate);
+ CoordinateCardWatcher.Deleted += (o, ee) => CardEvent(CardEventType.CharaMakerCoordinate);
+ CoordinateCardWatcher.IncludeSubdirectories = true;
+ }
+ }
+ ///
+ /// Initialize the file watcher once the list has been initiated
+ ///
+ [HarmonyPrefix, HarmonyPatch(typeof(Studio.CharaList), "InitFemaleList")]
+ public static void StudioFemaleListPrefix(Studio.CharaList __instance)
+ {
+ if (StudioFemaleCardWatcher == null)
+ {
+ StudioFemaleListInstance = __instance;
+
+ StudioFemaleCardWatcher = new FileSystemWatcher();
+ StudioFemaleCardWatcher.Path = FemaleCardPath;
+ StudioFemaleCardWatcher.NotifyFilter = NotifyFilters.FileName;
+ StudioFemaleCardWatcher.Filter = "*.png";
+ StudioFemaleCardWatcher.EnableRaisingEvents = true;
+ StudioFemaleCardWatcher.Created += (o, ee) => CardEvent(CardEventType.StudioFemale);
+ StudioFemaleCardWatcher.Deleted += (o, ee) => CardEvent(CardEventType.StudioFemale);
+ StudioFemaleCardWatcher.IncludeSubdirectories = true;
+ }
+ }
+ ///
+ /// Initialize the file watcher once the list has been initiated
+ ///
+ [HarmonyPrefix, HarmonyPatch(typeof(Studio.CharaList), "InitMaleList")]
+ public static void StudioMaleListPrefix(Studio.CharaList __instance)
+ {
+ if (StudioMaleCardWatcher == null)
+ {
+ StudioMaleListInstance = __instance;
+
+ StudioMaleCardWatcher = new FileSystemWatcher();
+ StudioMaleCardWatcher.Path = MaleCardPath;
+ StudioMaleCardWatcher.NotifyFilter = NotifyFilters.FileName;
+ StudioMaleCardWatcher.Filter = "*.png";
+ StudioMaleCardWatcher.EnableRaisingEvents = true;
+ StudioMaleCardWatcher.Created += (o, ee) => CardEvent(CardEventType.StudioMale);
+ StudioMaleCardWatcher.Deleted += (o, ee) => CardEvent(CardEventType.StudioMale);
+ StudioMaleCardWatcher.IncludeSubdirectories = true;
+ }
+ }
+ ///
+ /// Initialize the file watcher once the list has been initiated
+ ///
+ public static void StudioCoordinateListPrefix(object __instance)
+ {
+ if (StudioCoordinateCardWatcher == null)
+ {
+ StudioCoordinateListInstance = __instance;
- CoordinateCardWatcher = new FileSystemWatcher();
- CoordinateCardWatcher.Path = CoordinateCardPath;
- CoordinateCardWatcher.NotifyFilter = NotifyFilters.FileName;
- CoordinateCardWatcher.Filter = "*.png";
- CoordinateCardWatcher.EnableRaisingEvents = true;
- CoordinateCardWatcher.Created += new FileSystemEventHandler(CreateCoordinateEventLists);
- CoordinateCardWatcher.Deleted += new FileSystemEventHandler(CreateCoordinateEventLists);
+ StudioCoordinateCardWatcher = new FileSystemWatcher();
+ StudioCoordinateCardWatcher.Path = CoordinateCardPath;
+ StudioCoordinateCardWatcher.NotifyFilter = NotifyFilters.FileName;
+ StudioCoordinateCardWatcher.Filter = "*.png";
+ StudioCoordinateCardWatcher.EnableRaisingEvents = true;
+ StudioCoordinateCardWatcher.Created += (o, ee) => CardEvent(CardEventType.StudioCoordinate);
+ StudioCoordinateCardWatcher.Deleted += (o, ee) => CardEvent(CardEventType.StudioCoordinate);
+ StudioCoordinateCardWatcher.IncludeSubdirectories = true;
+ }
}
+
+ public enum CardEventType { CharaMakerCharacter, CharaMakerCoordinate, StudioMale, StudioFemale, StudioCoordinate }
}
}