123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- using UnityEngine;
- using ExIni;
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.IO;
- using Util;
- namespace CM3D2.MultipleMaids.Plugin
- {
- public partial class MultipleMaids
- {
- internal static readonly byte[] pngEnd = Encoding.ASCII.GetBytes("IEND");
- internal static readonly byte[] kankyoHeader = Encoding.ASCII.GetBytes("KANKYO");
- internal const string sceneDirectoryName = "< Scene Root >";
- internal const string kankyoDirectoryName = "< Kankyo Root >";
- internal readonly string saveScenePath = Path.Combine(Path.GetFullPath(".\\"), "Mod\\MultipleMaidsScene");
- private static string kankyoScenePath = Path.Combine(Path.GetFullPath(".\\"), "Mod\\MultipleMaidsKankyo");
- private static string sceneData;
- private static List<ScenePng> scenes = new List<ScenePng>(50);
- private GUIStyle selectedButtonStyle;
- private GUIStyle sceneSortComboStyle;
- private GUIContent infoString;
- private string[] directoryList;
- private Texture2D frame;
- private Texture2D infoHighlight;
- private Rect sceneManagerRect;
- private Rect sceneModalRect;
- private Rect resizeManagerRect;
- private Vector2 sceneManagerScrollPos = Vector2.zero;
- private Vector2 dirListScrollPos = Vector2.zero;
- private bool sceneManagerInitialize = false;
- private bool loadSceneFlag = false;
- private bool overwriteFlag = false;
- private bool createSceneFlag = false;
- private bool quickSaveFlag = false;
- private bool manageSceneFlag = false;
- private bool kankyoModeFlag = false;
- private bool kankyoToggle = false;
- private bool kankyoScene = false;
- private bool createDirectoryFlag = false;
- private bool deleteDirectoryFlag = false;
- private bool deleteSceneFlag = false;
- private bool resizeManager = false;
- private int selectedScene = 0;
- private int selectedDirectory = 0;
- private string currentDirectory = sceneDirectoryName;
- private string textFieldValue = "";
- private readonly ComboBox2 sceneSortCombo = new ComboBox2();
- private static GUIContent[] sceneSortComboList;
- private static int sceneSortModeOld = 0;
- private static bool sceneSortAscendingOld = true;
- private static int selectedSceneSortMode = 0;
- private static bool sceneSortAscending = true;
- private static readonly string[] ConfigSortMode = new[] { "name", "date_created", "date_modified" };
- private enum SortMode
- {
- Name, DateCreated, DateModified
- }
- public void InitializeSceneManager()
- {
- frame = MakeTex(2, 2, Color.white);
- infoHighlight = MakeTex(2, 2, new Color(0f, 0f, 0f, 0.8f));
- sceneSortCombo.selectedItemIndex = selectedSceneSortMode;
- sceneSortComboList = new GUIContent[] {
- new GUIContent("Name"),
- new GUIContent("Date Created"),
- new GUIContent("Date Modified")
- };
- selectedButtonStyle = new GUIStyle("button");
- selectedButtonStyle.normal.background = MakeTex(1, 1, new Color(0.5f, 0.5f, 0.5f, 0.4f));
- selectedButtonStyle.normal.textColor = Color.white;
- sceneSortComboStyle = new GUIStyle();
- sceneSortComboStyle.normal.textColor = Color.white;
- sceneSortComboStyle.normal.background = MakeTex(2, 2, new Color(0.0f, 0.0f, 0.0f, 0.5f));
- sceneSortComboStyle.onHover.background = sceneSortComboStyle.hover.background = new Texture2D(2, 2);
- sceneSortComboStyle.padding.left = sceneSortComboStyle.padding.right = sceneSortComboStyle.padding.top = sceneSortComboStyle.padding.bottom = GetPix(0);
- sceneSortComboStyle.fontSize = GetPix(13);
- currentDirectory = kankyoModeFlag ? kankyoDirectoryName : sceneDirectoryName;
- GetSceneDirectories();
- if (Preferences["scenemanager"]["converted"].Value != "true")
- {
- ConvertIni();
- Preferences["scenemanager"]["converted"].Value = "true";
- SaveConfig();
- }
- GetScenes(currentDirectory);
- sceneManagerInitialize = true;
- }
- private void SaveSceneSortPreferences()
- {
- if (sceneSortAscending != sceneSortAscendingOld || sceneSortModeOld != selectedSceneSortMode)
- {
- Preferences["scenemanager"]["scene_sort_ascending"].Value = sceneSortAscending ? "true" : "false";
- Preferences["scenemanager"]["scene_sort_mode"].Value = ConfigSortMode[selectedSceneSortMode];
- SaveConfig();
- sceneSortAscendingOld = sceneSortAscending;
- sceneSortModeOld = selectedSceneSortMode;
- }
- }
- private void RefreshSceneManager()
- {
- SwitchDirectory(currentDirectory);
- GetSceneDirectories();
- GetScenes(currentDirectory);
- }
- private void SwitchDirectory(string target)
- {
- string root = kankyoModeFlag ? kankyoScenePath : saveScenePath;
- string path = target.Equals(sceneDirectoryName) || target.Equals(kankyoDirectoryName)
- ? ""
- : target;
- string targetDirectory = Path.Combine(root, path);
- if (!Directory.Exists(targetDirectory))
- {
- currentDirectory = kankyoModeFlag ? kankyoDirectoryName : sceneDirectoryName;
- selectedDirectory = 0;
- GetSceneDirectories();
- }
- else
- {
- selectedDirectory = Array.FindIndex(directoryList, d => d.Equals(target, StringComparison.OrdinalIgnoreCase));
- selectedDirectory = selectedDirectory == -1 ? 0 : selectedDirectory;
- }
- if (target == currentDirectory) return;
- currentDirectory = target;
- GetScenes(target);
- }
- private void GetSceneDirectories()
- {
- if (!Directory.Exists(saveScenePath))
- {
- Directory.CreateDirectory(saveScenePath);
- }
- if (!Directory.Exists(kankyoScenePath))
- {
- Directory.CreateDirectory(kankyoScenePath);
- }
- string root = kankyoModeFlag ? kankyoScenePath : saveScenePath;
- DirectoryInfo[] directoryInfo = new DirectoryInfo(root).GetDirectories();
- directoryList = new string[directoryInfo.Length + 1];
- directoryList[0] = kankyoModeFlag ? kankyoDirectoryName : sceneDirectoryName;
- for (int i = 0; i < directoryInfo.Length; i++)
- {
- directoryList[i + 1] = directoryInfo[i].Name;
- }
- }
- private void GetScenes(string target)
- {
- string root = kankyoModeFlag ? kankyoScenePath : saveScenePath;
- scenes.Clear();
- if (target.Equals(sceneDirectoryName) || target.Equals(kankyoDirectoryName))
- {
- target = "";
- }
- string workingPath = Path.Combine(root, target);
- DirectoryInfo info = new DirectoryInfo(workingPath);
- foreach (var scene in info.GetFiles("*.png"))
- {
- Texture2D screenshot = new Texture2D(2, 2, TextureFormat.ARGB32, false);
- screenshot.LoadImage(File.ReadAllBytes(scene.FullName));
- scenes.Add(new ScenePng(scene, screenshot));
- }
- selectedScene = scenes.Count == 0 ? 0 : scenes.Count - 1;
- SortScenes();
- sceneManagerScrollPos.y = 0;
- }
- private void SortScenes()
- {
- Comparison<ScenePng> sortMode = null;
- switch ((SortMode)selectedSceneSortMode)
- {
- case SortMode.Name:
- sortMode = SortByName;
- break;
- case SortMode.DateCreated:
- sortMode = SortByDateCreated;
- break;
- case SortMode.DateModified:
- sortMode = SortByDateModified;
- break;
- }
- scenes.Sort(sortMode);
- }
- private void SetSceneSortAscending(bool ascending)
- {
- sceneSortAscending = ascending;
- SortScenes();
- }
- private void SetSceneSortMode(int sortMode)
- {
- selectedSceneSortMode = Mathf.Clamp(sortMode, 0, 2);
- SortScenes();
- }
- private static int SortByName(ScenePng a, ScenePng b)
- {
- int direction = sceneSortAscending ? -1 : 1;
- return direction * a.info.Name.CompareTo(b.info.Name);
- }
- private static int SortByDateCreated(ScenePng a, ScenePng b)
- {
- int direction = sceneSortAscending ? -1 : 1;
- return direction * a.info.CreationTime.CompareTo(b.info.CreationTime);
- }
- private static int SortByDateModified(ScenePng a, ScenePng b)
- {
- int direction = sceneSortAscending ? -1 : 1;
- return direction * a.info.LastWriteTime.CompareTo(b.info.LastWriteTime);
- }
- private void CreateDirectory(string directoryName)
- {
- string root = kankyoModeFlag ? kankyoScenePath : saveScenePath;
- directoryName = string.Join("", directoryName.Split(Path.GetInvalidFileNameChars()));
- string newDirectory = Path.Combine(root, directoryName);
- if (!Directory.Exists(newDirectory))
- {
- Directory.CreateDirectory(newDirectory);
- }
- GetSceneDirectories();
- SwitchDirectory(directoryName);
- }
- private void DeleteDirectory()
- {
- string root = kankyoModeFlag ? kankyoScenePath : saveScenePath;
- string directory = Path.Combine(root, directoryList[selectedDirectory]);
- if (Directory.Exists(directory))
- {
- DirectoryInfo dirInfo = new DirectoryInfo(directory);
- foreach (var finfo in dirInfo.GetFiles())
- {
- finfo.Delete();
- }
- dirInfo.Delete();
- currentDirectory = sceneDirectoryName;
- }
- RefreshSceneManager();
- }
- private void DeleteScene()
- {
- string file = scenes[selectedScene].info.FullName;
- if (File.Exists(file))
- {
- scenes[selectedScene].info.Delete();
- scenes.RemoveAt(selectedScene);
- }
- RefreshSceneManager();
- }
- private void OverwriteScene()
- {
- string file = scenes[selectedScene].info.FullName;
- if (!File.Exists(file))
- {
- RefreshSceneManager();
- }
- }
- private void SaveScene()
- {
- string target = currentDirectory;
- bool scene = target.Equals(sceneDirectoryName);
- bool kankyo = target.Equals(kankyoDirectoryName);
- if (scene || kankyo)
- target = "";
- string saveDirectory;
- saveDirectory = kankyoModeFlag
- ? Path.Combine(kankyoScenePath, target)
- : Path.Combine(saveScenePath, target);
- if (!Directory.Exists(saveDirectory))
- {
- thum_byte_to_base64_ = "";
- thum_file_path_ = "";
- RefreshSceneManager();
- return;
- }
- string sceneString = SerializeScene();
- #region MM screenshot processing stuff
- Texture2D screenshot = new Texture2D(1, 1, TextureFormat.ARGB32, false);
- screenshot.LoadImage(File.ReadAllBytes(thum_file_path_));
- float num2 = screenshot.width / (float)screenshot.height;
- Vector2 vector2 = new Vector2(480f, 270f);
- int newWidth = screenshot.width;
- int newHeight = screenshot.height;
- if (vector2.x < (double)screenshot.width && vector2.y < (double)screenshot.height)
- {
- newWidth = (int)vector2.x;
- newHeight = Mathf.RoundToInt(newWidth / num2);
- if (vector2.y < (double)newHeight)
- {
- newHeight = (int)vector2.y;
- newWidth = Mathf.RoundToInt(newHeight * num2);
- }
- }
- else if (vector2.x < (double)screenshot.width)
- {
- newWidth = (int)vector2.x;
- newHeight = Mathf.RoundToInt(newWidth / num2);
- }
- else if (vector2.y < (double)screenshot.height)
- {
- newHeight = (int)vector2.y;
- newWidth = Mathf.RoundToInt(newHeight * num2);
- }
- TextureScale.Bilinear(screenshot, newWidth, newHeight);
- #endregion
- thum_byte_to_base64_ = "";
- thum_file_path_ = "";
- string sceneType = kankyoModeFlag ? "mmkankyo" : "mmscene";
- string filePath;
- string fileName = $"{sceneType}{DateTime.Now:yyyyMMddHHmmss}.png";
- FileInfo oldFileInfo = null;
- if (overwriteFlag)
- {
- oldFileInfo = scenes[selectedScene].info;
- fileName = oldFileInfo.Name;
- scenes.RemoveAt(selectedScene);
- }
- filePath = Path.Combine(saveDirectory, fileName);
- using (FileStream fileStream = File.Create(filePath))
- using (MemoryStream sceneStream = new MemoryStream(Encoding.Unicode.GetBytes(sceneString)))
- {
- byte[] screenshotBuffer = screenshot.EncodeToPNG();
- byte[] sceneBuffer = LZMA.Compress(sceneStream);
- fileStream.Write(screenshotBuffer, 0, screenshotBuffer.Length);
- if (kankyoModeFlag) fileStream.Write(kankyoHeader, 0, kankyoHeader.Length);
- fileStream.Write(sceneBuffer, 0, sceneBuffer.Length);
- }
- ScenePng newScenePng = new ScenePng(new FileInfo(filePath), screenshot);
- if (oldFileInfo != null)
- {
- File.SetCreationTime(filePath, oldFileInfo.CreationTime);
- newScenePng.info.CreationTime = oldFileInfo.CreationTime;
- }
- scenes.Add(newScenePng);
- selectedScene = scenes.Count - 1;
- SortScenes();
- }
- private void ReadScene()
- {
- string filePath = scenes[selectedScene].info.FullName;
- sceneData = null;
- if (!File.Exists(filePath))
- {
- RefreshSceneManager();
- return;
- }
- using (FileStream fileStream = File.OpenRead(filePath))
- {
- long pos = fileStream.Position = fileStream.Length - pngEnd.Length;
- byte[] buf = new byte[pngEnd.Length];
- while (true)
- {
- if (pos < 0)
- {
- Util.Logger.Log(LogLevel.Error, $"Could not read '{Path.GetFileName(filePath)}'");
- return;
- }
- fileStream.Position = pos;
- fileStream.Read(buf, 0, pngEnd.Length);
- if (BytesEqual(buf, pngEnd)) break;
- --pos;
- }
- fileStream.Position += 4;
- byte[] kankyo = new byte[kankyoHeader.Length];
- fileStream.Read(kankyo, 0, kankyo.Length);
- if (BytesEqual(kankyo, kankyoHeader))
- {
- kankyoScene = true;
- }
- else
- {
- kankyoScene = false;
- fileStream.Position -= kankyoHeader.Length;
- }
- try
- {
- using (var sceneStream = LZMA.Decompress(fileStream))
- {
- sceneData = Encoding.Unicode.GetString(sceneStream.ToArray());
- }
- }
- catch (Exception e)
- {
- Util.Logger.Log(LogLevel.Error, $"Failed to decompress scene data because '{e}'\n");
- }
- }
- }
- private static bool BytesEqual(byte[] a, byte[] b)
- {
- if (a.Length != b.Length) return false;
- for (long i = 0; i < a.Length; i++)
- {
- if (a[i] != b[i]) return false;
- }
- return true;
- }
- private void ConvertIni()
- {
- HashSet<int> saveSceneEntries = new HashSet<int>();
- IniSection MMScene = Preferences["scene"];
- foreach (IniKey iniKey in MMScene.Keys)
- {
- string keyName = iniKey.Key;
- if (keyName[0] == 's')
- {
- int index = Int32.Parse(keyName.Substring(1 + (keyName[1] == 's' ? 1 : 0)));
- if (!saveSceneEntries.Contains(index))
- {
- saveSceneEntries.Add(index);
- ConvertSceneToPng(index, MMScene);
- }
- }
- }
- }
- private void ConvertSceneToPng(int index, IniSection MMScene)
- {
- byte[] sceneBuffer;
- byte[] screenshotBuffer = frame.EncodeToPNG();
- string sceneString = MMScene.GetKey($"s{index}")?.RawValue;
- string screenshotString = MMScene.GetKey($"ss{index}")?.RawValue;
- bool kankyo = index >= 10000;
- if (index == 9999 || String.IsNullOrEmpty(sceneString)) return;
- using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(sceneString)))
- {
- sceneBuffer = LZMA.Compress(stream);
- }
- DateTime dateSaved = DateTime.Parse(sceneString.Split(',')[0]);
- if (!String.IsNullOrEmpty(screenshotString))
- screenshotBuffer = Convert.FromBase64String(screenshotString);
- string sceneType = kankyo ? "mmkankyo" : "mmscene";
- string savePngFilename = $"{sceneType}{index}_{dateSaved.ToString("yyyyMMddHHmm")}.png";
- string outPath = Path.Combine(kankyo ? kankyoScenePath : saveScenePath, savePngFilename);
- using (BinaryWriter stream = new BinaryWriter(File.Create(outPath)))
- {
- stream.Write(screenshotBuffer);
- if (kankyo) stream.Write(kankyoHeader);
- stream.Write(sceneBuffer);
- }
- File.SetCreationTime(outPath, dateSaved);
- File.SetLastWriteTime(outPath, dateSaved);
- }
- private class ScenePng
- {
- public FileInfo info { get; }
- public Texture2D screenshot { get; }
- public ScenePng(FileInfo info, Texture2D screenshot)
- {
- this.info = info;
- this.screenshot = screenshot;
- }
- }
- }
- }
|