Browse Source

Add new save manager window and method of saving

The new save manager utilizes PNG files with save data embedded.
When saving, the save data is compressed and appended to the end
of the screenshot. This has not been tested thoroughly and as such,
there may be bugs.
habeebweeb 4 years ago
parent
commit
6a10c24d52

+ 272 - 44
MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Gui.cs

@@ -47,7 +47,7 @@ namespace CM3D2.MultipleMaids.Plugin
                 }
             }
 
-            GUIStyle style = GUI.skin.box;
+            GUIStyle style = new GUIStyle(GUI.skin.box);
             style.fontSize = GetPix(11);
             style.alignment = TextAnchor.UpperRight;
 
@@ -69,6 +69,12 @@ namespace CM3D2.MultipleMaids.Plugin
 
                 rectWin.x = Screen.width - rectWin.width;
                 rectWin.y = GetPix(65);
+
+                saveManagerRect.width = Screen.width * 0.9f;
+                saveManagerRect.height = Screen.height * 0.75f;
+
+                saveManagerRect.x = (float)(Screen.width * 0.5f - saveManagerRect.width * 0.5f);
+                saveManagerRect.y = (float)(Screen.height * 0.5f - saveManagerRect.height * 0.5f);
             }
 
             if (bGuiMessage)
@@ -121,6 +127,11 @@ namespace CM3D2.MultipleMaids.Plugin
                 else if (sceneFlg)
                 {
                     rectWin = GUI.Window(129, rectWin, SaveSceneWindow, "", style);
+
+                    saveManagerRect = GUI.Window(131, saveManagerRect, SaveManagerWindow, "", style);
+
+                    if (!saveManagerInitialize) InitializeSaveManager();
+
                     Rect rect = default;
                     dispNo = 0;
                     for (int index = 0; index < 10; ++index)
@@ -294,10 +305,10 @@ namespace CM3D2.MultipleMaids.Plugin
 
         private void SaveSceneWindow(int winID)
         {
-            GUIStyle style1 = "label";
+            GUIStyle style1 = new GUIStyle("label");
             style1.fontSize = GetPix(12);
             style1.alignment = TextAnchor.UpperLeft;
-            GUIStyle style2 = "button";
+            GUIStyle style2 = new GUIStyle("button");
             style2.fontSize = GetPix(12);
             style2.alignment = TextAnchor.MiddleCenter;
             GUI.Label(new Rect(GetPix(50), GetPix(6), GetPix(100), GetPix(25)),
@@ -435,48 +446,8 @@ namespace CM3D2.MultipleMaids.Plugin
                 {
                     saveScene = page * 10 + index + 1;
                     saveScene2 = saveScene;
-                    GameMain.Instance.SoundMgr.PlaySe("se002.ogg", false);
-                    isScreen2 = true;
-                    if (!isMessage)
-                    {
-                        ui_cam_hide_list_.Clear();
-                        foreach (UICamera uiCamera in NGUITools.FindActive<UICamera>())
-                        {
-                            if (uiCamera.GetComponent<Camera>().enabled)
-                            {
-                                uiCamera.GetComponent<Camera>().enabled = false;
-                                ui_cam_hide_list_.Add(uiCamera);
-                            }
-                        }
-                    }
-                    else
-                    {
-                        editUI = GameObject.Find("/UI Root/Camera");
-                        if (editUI != null)
-                        {
-                            editUI.SetActive(false);
-                        }
-
-                        if (GameMain.Instance.CMSystem.ViewFps)
-                        {
-                            UTY.GetChildObject(GameMain.Instance.gameObject, "SystemUI Root/FpsCounter", false).SetActive(false);
-                        }
-
-                        GameObject childObject1 = UTY.GetChildObject(GameMain.Instance.gameObject, "SystemUI Root/SystemDialog", false);
-                        GameObject childObject2 = UTY.GetChildObject(GameMain.Instance.gameObject, "SystemUI Root/SystemShortcut", false);
-                        childObject1.SetActive(false);
-                        childObject2.SetActive(false);
-                    }
 
-                    isGui = bGui;
-                    bGui = false;
-                    try
-                    {
-                        thum_byte_to_base64_ = string.Empty;
-                        thum_file_path_ = Path.Combine(Path.GetTempPath(), "cm3d2_" + Guid.NewGuid().ToString() + ".png");
-                        GameMain.Instance.MainCamera.ScreenShot(thum_file_path_, 1, true);
-                    }
-                    catch { }
+                    TakeScreenshot();
                 }
 
                 GUI.Label(new Rect(GetPix(25),
@@ -9173,5 +9144,262 @@ namespace CM3D2.MultipleMaids.Plugin
             }
             GUI.DragWindow();
         }
+
+        private void SaveManagerWindow(int winID)
+        {
+            GUIStyle labelStyle = new GUIStyle("label");
+            labelStyle.fontSize = GetPix(12);
+            labelStyle.alignment = TextAnchor.MiddleCenter;
+            GUIStyle newSaveStyle = new GUIStyle("button");
+            newSaveStyle.fontSize = GetPix(50);
+            newSaveStyle.alignment = TextAnchor.MiddleCenter;
+            GUIStyle saveImageStyle = new GUIStyle("box");
+            saveImageStyle.fontSize = GetPix(12);
+            saveImageStyle.alignment = TextAnchor.MiddleCenter;
+            saveImageStyle.padding = new RectOffset(0, 0, 0, 0);
+            GUIStyle saveControlStyle = new GUIStyle("button");
+            saveControlStyle.fontSize = GetPix(18);
+
+            // Window variables
+            float windowPadding = GetPix(10);
+            float windowPaddingY = GetPix(20);
+
+            if (GUI.Button(new Rect(
+                windowPadding,
+                windowPadding,
+                GetPix(25),
+                GetPix(25)
+            ), "X", saveControlStyle))
+            {
+                faceFlg = false;
+                poseFlg = false;
+                sceneFlg = false;
+                kankyoFlg = true;
+                kankyo2Flg = false;
+                bGui = true;
+                copyIndex = 0;
+            }
+
+            if (GUI.Button(new Rect(
+                windowPaddingY + GetPix(25),
+                windowPadding,
+                GetPix(85),
+                GetPix(25)
+            ), "Refresh", saveControlStyle))
+            {
+                InitializeSaveList();
+            }
+
+            if (createSaveFlag || loadSaveFlag)
+            {
+                GUI.enabled = false;
+            }
+
+            #region SAVE_GRID
+
+            float saveGridX = windowPadding + Mathf.Max(480, GetPix(480)) + windowPadding;
+            float saveGridY = windowPaddingY;
+            float saveGridWidth = saveManagerRect.width - saveGridX - windowPadding;
+            float saveGridHeight = saveManagerRect.height - windowPaddingY;
+
+            int numImages = saveScenes.Count;
+
+            float scale = 0.5f;
+            float imageWidth = Mathf.Min(480f * scale, GetPix(480) * scale);
+            float imageHeight = Mathf.Min(270f * scale, GetPix(270) * scale);
+            float imagePadding = GetPix(12);
+
+            int maxColumns = Mathf.Max(1, (int)(saveGridWidth / (imageWidth + imagePadding)));
+            float imageGridWidth = maxColumns * (imageWidth + imagePadding);
+
+            float imageGridX = saveGridX + (saveGridWidth / 2f - imageGridWidth / 2f) + windowPadding;
+
+            float imageGridOffset = (saveGridWidth - imageGridWidth) / 2f;
+
+            Rect saveGridScrollRect = new Rect(
+                saveGridX + windowPadding
+                , saveGridY
+                , saveGridWidth - windowPadding
+                , saveGridHeight - windowPadding
+            );
+
+            Rect saveGridScrollView = new Rect(0, 0
+                , saveGridWidth - 30
+                , (numImages / maxColumns + 1) * (imageHeight + imagePadding) + imagePadding
+            );
+
+            GUI.Box(new Rect(
+            saveGridX
+            , saveGridY
+            , saveGridWidth
+            , saveGridHeight - windowPadding
+            ), "");
+
+            saveManagerScrollPos = GUI.BeginScrollView(saveGridScrollRect, saveManagerScrollPos, saveGridScrollView);
+            if (GUI.Button(new Rect(
+                imageGridOffset
+                , imagePadding
+                , imageWidth
+                , imageHeight)
+                , "+", newSaveStyle))
+            {
+                createSaveFlag = true;
+                TakeScreenshot();
+            }
+
+            int j = 1;
+            int i = numImages - 1;
+
+            while (i >= 0 && j <= numImages)
+            {
+                Texture2D saveImage = saveScenes[i]?.Item2 ?? null;
+                if (saveImage != null)
+                {
+
+                    if (GUI.Button(new Rect(
+                        (j % maxColumns) * imageWidth + (j % maxColumns) * imagePadding + imageGridOffset
+                        , (j / maxColumns) * imageHeight + (j / maxColumns + 1) * imagePadding
+                        , imageWidth
+                        , imageHeight)
+                    , saveImage, saveImageStyle))
+                    {
+                        selectedSave = i;
+                    }
+                    i--;
+                    j++;
+                }
+            }
+
+            GUI.EndScrollView();
+            #endregion
+
+            #region SAVE_CONTROLS
+            if (numImages > 0)
+            {
+                Texture2D previewImage = saveScenes[selectedSave]?.Item2 ?? null;
+                if (previewImage != null)
+                {
+
+                    float saveManagerX = windowPadding;
+                    float saveManagerY = windowPaddingY + GetPix(80);
+
+                    int previewWidth = Mathf.Min(previewImage.width, GetPix(previewImage.width));
+                    int previewHeight = Mathf.Min(previewImage.height, GetPix(previewImage.height));
+
+                    float previewX = saveManagerX + (saveGridX / 2 - previewWidth / 2);
+                    float previewY = saveManagerY;
+
+                    GUI.DrawTexture(new Rect(
+                        previewX - GetPix(10)
+                        , previewY - GetPix(10)
+                        , previewWidth + GetPix(20)
+                        , previewHeight + GetPix(20))
+                        , frame
+                    );
+                    GUI.DrawTexture(new Rect(
+                        previewX,
+                        previewY,
+                        previewWidth,
+                        previewHeight
+                    ), previewImage);
+
+                    float saveControlX = previewX + GetPix(20);
+                    float saveControlY = saveManagerY + previewHeight + windowPaddingY;
+
+                    int saveControlWidth = GetPix(110);
+                    int saveControlHeight = GetPix(40);
+
+                    if (GUI.Button(new Rect(
+                                saveControlX
+                                , saveControlY
+                                , saveControlWidth
+                                , saveControlHeight)
+                                , "Overwrite", saveControlStyle))
+                    {
+                        createSaveFlag = true;
+                        overwriteFlag = true;
+
+                        TakeScreenshot();
+                    }
+
+                    if (GUI.Button(new Rect(
+                        previewX + previewWidth - saveControlWidth - GetPix(20)
+                        , saveControlY
+                        , saveControlWidth
+                        , saveControlHeight)
+                        , "Load", saveControlStyle))
+                    {
+                        // string sceneData = LoadSave(saveScenes[selectedSave].Item1.FullName);
+                        // Debug.Log(sceneData);
+                        loadSaveFlag = true;
+                        loadScene = 1;
+                    }
+                }
+            }
+
+            #endregion
+
+            GUI.enabled = true;
+
+            if (createSaveFlag)
+            {
+                if (File.Exists(thum_file_path_))
+                {
+                    if (overwriteFlag)
+                        OverWrite();
+                    SaveScene();
+                    createSaveFlag = false;
+                    overwriteFlag = false;
+                }
+            }
+
+            GUI.DragWindow();
+        }
+
+        public void TakeScreenshot()
+        {
+            GameMain.Instance.SoundMgr.PlaySe("se002.ogg", false);
+            isScreen2 = true;
+            if (!isMessage)
+            {
+                ui_cam_hide_list_.Clear();
+                foreach (UICamera uiCamera in NGUITools.FindActive<UICamera>())
+                {
+                    if (uiCamera.GetComponent<Camera>().enabled)
+                    {
+                        uiCamera.GetComponent<Camera>().enabled = false;
+                        ui_cam_hide_list_.Add(uiCamera);
+                    }
+                }
+            }
+            else
+            {
+                editUI = GameObject.Find("/UI Root/Camera");
+                if (editUI != null)
+                {
+                    editUI.SetActive(false);
+                }
+
+                if (GameMain.Instance.CMSystem.ViewFps)
+                {
+                    UTY.GetChildObject(GameMain.Instance.gameObject, "SystemUI Root/FpsCounter", false).SetActive(false);
+                }
+
+                GameObject childObject1 = UTY.GetChildObject(GameMain.Instance.gameObject, "SystemUI Root/SystemDialog", false);
+                GameObject childObject2 = UTY.GetChildObject(GameMain.Instance.gameObject, "SystemUI Root/SystemShortcut", false);
+                childObject1.SetActive(false);
+                childObject2.SetActive(false);
+            }
+
+            isGui = bGui;
+            bGui = false;
+            try
+            {
+                thum_byte_to_base64_ = string.Empty;
+                thum_file_path_ = Path.Combine(Path.GetTempPath(), "cm3d2_" + Guid.NewGuid().ToString() + ".png");
+                GameMain.Instance.MainCamera.ScreenShot(thum_file_path_, 1, true);
+            }
+            catch { }
+        }
     }
 }

File diff suppressed because it is too large
+ 1572 - 1542
MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs


+ 181 - 0
MultipleMaids/SaveManager.cs

@@ -0,0 +1,181 @@
+using UnityEngine;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.IO;
+using Util;
+
+namespace CM3D2.MultipleMaids.Plugin
+{
+    public partial class MultipleMaids
+    {
+        private static readonly byte[] pngEnd = Encoding.ASCII.GetBytes("IEND");
+        private Rect saveManagerRect;
+        private Vector2 saveManagerScrollPos = Vector2.zero;
+        private bool saveManagerInitialize;
+        private int selectedSave;
+        private bool loadSaveFlag = false;
+        private bool overwriteFlag = false;
+        private bool createSaveFlag = false;
+        private string saveScenePath = Path.Combine(Path.GetFullPath(".\\"), "Mod\\MultipleMaidsSave");
+        private static string sceneData;
+        private List<Tuple<FileInfo, Texture2D>> saveScenes = new List<Tuple<FileInfo, Texture2D>>(50);
+
+        private Texture2D frame;
+
+        public void InitializeSaveManager()
+        {
+            frame = MakeTex(2, 2, Color.white);
+
+            if (!Directory.Exists(saveScenePath))
+            {
+                Directory.CreateDirectory(saveScenePath);
+            }
+
+            InitializeSaveList();
+            saveManagerInitialize = true;
+        }
+
+        private void InitializeSaveList()
+        {
+            saveScenes.Clear();
+
+            DirectoryInfo info = new DirectoryInfo(saveScenePath);
+
+            foreach (var save in info.GetFiles("*.png"))
+            {
+                Texture2D screenshot = new Texture2D(1, 1, TextureFormat.ARGB32, false);
+                screenshot.LoadImage(File.ReadAllBytes(save.FullName));
+
+                saveScenes.Add(new Tuple<FileInfo, Texture2D>(save, screenshot));
+            }
+
+            saveScenes.Sort((a, b) => a.Item1.LastWriteTime.CompareTo(b.Item1.LastWriteTime));
+
+            selectedSave = saveScenes.Count - 1;
+        }
+
+        private static bool BytesEqual(byte[] a, byte[] b)
+        {
+            if (a.Length != b.Length) return false;
+
+            for (int i = 0; i < a.Length; i++)
+            {
+                if (a[i] != b[i]) return false;
+            }
+            return true;
+        }
+
+        private void LoadSave()
+        {
+            string filePath = saveScenes[selectedSave].Item1.FullName;
+            if (!File.Exists(filePath))
+            {
+                InitializeSaveList();
+                sceneData = null;
+                return;
+            }
+
+            using (FileStream fileStream = File.OpenRead(filePath))
+            {
+                byte[] buffer = new byte[pngEnd.Length];
+                long position = 0;
+
+                while (true)
+                {
+                    int bytesRead = fileStream.Read(buffer, 0, buffer.Length);
+
+                    if (bytesRead != pngEnd.Length)
+                    {
+                        return;
+                    }
+
+                    if (BytesEqual(buffer, pngEnd))
+                    {
+                        fileStream.Position += 4;
+                        break;
+                    }
+
+                    fileStream.Position = ++position;
+                }
+                using (MemoryStream sceneStream = LZMA.Decompress(fileStream))
+                {
+                    sceneData = Encoding.Unicode.GetString(sceneStream.ToArray());
+                }
+            }
+        }
+
+        private void OverWrite()
+        {
+            string filePath = Path.Combine(saveScenePath, saveScenes[selectedSave].Item1.FullName);
+            if (File.Exists(filePath))
+            {
+                File.Delete(filePath);
+            }
+            saveScenes.RemoveAt(selectedSave);
+        }
+
+        private void SaveScene()
+        {
+            string sceneString = SerializeScene(true);
+
+            thum_byte_to_base64_ = "";
+
+            #region MM GUI 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
+
+            string filePath = Path.Combine(saveScenePath, $"mmsave{DateTime.Now:yyyyMMddHHmmss}.png");
+            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);
+                fileStream.Write(sceneBuffer, 0, sceneBuffer.Length);
+            }
+            saveScenes.Add(new Tuple<FileInfo, Texture2D>(new FileInfo(filePath), screenshot));
+            selectedSave = saveScenes.Count - 1;
+            thum_file_path_ = "";
+        }
+
+        private class Tuple<T1, T2>
+        {
+            public T1 Item1 { get; }
+            public T2 Item2 { get; }
+
+            public Tuple(T1 Item1, T2 Item2)
+            {
+                this.Item1 = Item1;
+                this.Item2 = Item2;
+            }
+        }
+    }
+}

+ 89 - 0
MultipleMaids/Util/LZMA.cs

@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+using SevenZip;
+using SevenZip.Compression.LZMA;
+
+namespace Util
+{
+    internal static class LZMA
+    {
+        private static readonly CoderPropID[] PropIDs =
+        {
+        CoderPropID.DictionarySize,
+        CoderPropID.PosStateBits,
+        CoderPropID.LitContextBits,
+        CoderPropID.LitPosBits,
+        CoderPropID.Algorithm,
+        CoderPropID.NumFastBytes,
+        CoderPropID.MatchFinder,
+        CoderPropID.EndMarker
+    };
+
+        private static readonly object[] Properties =
+        {
+        1 << 23,
+        2,
+        3,
+        0,
+        2,
+        128,
+        "bt4",
+        false
+
+    };
+
+        public static byte[] Compress(MemoryStream inStream)
+        {
+            MemoryStream outStream = new MemoryStream();
+
+            Encoder encoder = new Encoder();
+            encoder.SetCoderProperties(PropIDs, Properties);
+            encoder.WriteCoderProperties(outStream);
+
+            Int64 fileSize = inStream.Length;
+
+            for (int i = 0; i < 8; i++)
+            {
+                outStream.WriteByte((Byte)(fileSize >> (8 * i)));
+            }
+
+            encoder.Code(inStream, outStream, -1, -1, null);
+            return outStream.ToArray();
+        }
+
+        public static MemoryStream Decompress(Stream inStream)
+        {
+            MemoryStream outStream = new MemoryStream();
+
+            byte[] properties = new byte[5];
+
+            if (inStream.Read(properties, 0, 5) != 5)
+            {
+                throw new Exception("input .lzma is too short");
+            }
+
+            Decoder decoder = new Decoder();
+
+            decoder.SetDecoderProperties(properties);
+
+            long outSize = 0;
+
+            for (int i = 0; i < 8; i++)
+            {
+                int v = inStream.ReadByte();
+                if (v < 0)
+                {
+                    throw new Exception("Can't Read 1");
+                }
+
+                outSize |= ((long)(byte)v) << (8 * i);
+            }
+
+            long compressedSize = inStream.Length - inStream.Position;
+
+            decoder.Code(inStream, outStream, compressedSize, outSize, null);
+
+            return outStream;
+        }
+    }
+}