Browse Source

Merge branch 'master' of https://git.coder.horse/meidomustard/modifiedMM

habeebweeb 3 years ago
parent
commit
f918cfcec2

+ 1 - 1
.gitignore

@@ -1,6 +1,6 @@
+MultipleMaids/lib/
 ## Ignore Visual Studio temporary files, build results, and
 ## files generated by popular Visual Studio add-ons.
-
 .vs/
 
 # User-specific files

+ 165 - 357
MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Gui.cs

@@ -1,4 +1,4 @@
-using ExIni;
+using ExIni;
 using MyRoomCustom;
 using System;
 using System.Collections;
@@ -379,7 +379,7 @@ namespace CM3D2.MultipleMaids.Plugin
             if (!modItemsOnly)
             {
                 bool previousGUIState = GUI.enabled;
-                GUI.enabled = slotIndex > 1;
+                GUI.enabled = slotIndex > 1 || !bg2Busy;
                 modItemsToggle = GUI.Toggle(new Rect(GetPix(156),
                     GetPix(115),
                     GetPix(50),
@@ -391,133 +391,140 @@ namespace CM3D2.MultipleMaids.Plugin
                 GUI.enabled = previousGUIState;
             }
 
-
-
-            int iconSize = GetPix(45);
-            Rect position1;
-            Rect viewRect;
-            int bg2ItemCount = slotIndex == 1 ?
-                creativeSortList.Count :
-                (!modItemsOnly && modItemsToggle) ?
-                    numberOfModItems : sortList.Count;
-            if (sceneLevel != 5)
+            if (slotIndex > 0)
             {
-                position1 = new Rect(GetPix(7),
-                                      GetPix(138),
-                                      GetPix(44) * 4 + GetPix(20),
-                                      rectWin.height - GetPix(148));
-                viewRect = new Rect(0.0f,
-                                    0.0f,
-                                    position1.width * 0.845f,
-                                    Mathf.Ceil(bg2ItemCount / 4f) * iconSize + GetPix(10));
-            }
-            else
-            {
-                position1 = new Rect(GetPix(7),
-                                      GetPix(138),
-                                      GetPix(44) * 4 + GetPix(20),
-                                      rectWin.height - GetPix(148));
-                viewRect = new Rect(0.0f,
-                                    0.0f,
-                                    position1.width * 0.845f,
-                                    Mathf.Ceil(bg2ItemCount / 4f) * iconSize + GetPix(10));
-            }
+                if (bg2Busy && slotIndex > 1)
+                {
+                    GUI.Label(new Rect(GetPix(15), GetPix(130), GetPix(90), GetPix(25)), "Initializing...");
+                }
 
-            bg2ScrollPos = GUI.BeginScrollView(position1, bg2ScrollPos, viewRect);
-            int bg2Index = 0;
-            List<SortItem> bg2List = slotIndex == 1 ? creativeSortList : sortList;
-            foreach (SortItem sortItem in bg2List)
-            {
-                if (slotIndex > 1 && modItemsToggle && !sortItem.isMod)
+                int iconSize = GetPix(45);
+                Rect position1;
+                Rect viewRect;
+                int bg2ItemCount = slotIndex == 1 ?
+                    creativeSortList.Count :
+                    (!modItemsOnly && modItemsToggle) ?
+                        numberOfModItems : sortList.Count;
+                if (sceneLevel != 5)
                 {
-                    continue;
+                    position1 = new Rect(GetPix(7),
+                                          GetPix(138),
+                                          GetPix(44) * 4 + GetPix(20),
+                                          rectWin.height - GetPix(148));
+                    viewRect = new Rect(0.0f,
+                                        0.0f,
+                                        position1.width * 0.845f,
+                                        Mathf.Ceil(bg2ItemCount / 4f) * iconSize + GetPix(10));
                 }
-                Rect position2 = new Rect(
-                    bg2Index % 4 * iconSize,
-                    bg2Index / 4 * iconSize,
-                    iconSize,
-                    iconSize
-                );
-                if (GUI.Button(position2, ""))
+                else
+                {
+                    position1 = new Rect(GetPix(7),
+                                          GetPix(138),
+                                          GetPix(44) * 4 + GetPix(20),
+                                          rectWin.height - GetPix(148));
+                    viewRect = new Rect(0.0f,
+                                        0.0f,
+                                        position1.width * 0.845f,
+                                        Mathf.Ceil(bg2ItemCount / 4f) * iconSize + GetPix(10));
+                }
+
+                bg2ScrollPos = GUI.BeginScrollView(position1, bg2ScrollPos, viewRect);
+                int bg2Index = 0;
+                List<SortItem> bg2List = slotIndex == 1 ? creativeSortList : sortList;
+                foreach (SortItem sortItem in bg2List)
                 {
-                    GameObject gameObject = null;
-                    if (slotIndex > 1)
+                    if (slotIndex > 1 && modItemsToggle && !sortItem.isMod)
                     {
-                        string menu = sortItem.menu;
-                        byte[] modBuf = null;
-                        bool ready = true;
-                        if (sortItem.isOfficialMod)
+                        continue;
+                    }
+                    Rect position2 = new Rect(
+                        bg2Index % 4 * iconSize,
+                        bg2Index / 4 * iconSize,
+                        iconSize,
+                        iconSize
+                    );
+                    if (GUI.Button(position2, ""))
+                    {
+                        GameObject gameObject = null;
+                        if (slotIndex > 1)
                         {
-                            menu = sortItem.baseMenu;
+                            string menu = sortItem.menu;
+                            byte[] modBuf = null;
+                            bool ready = true;
+                            if (sortItem.isOfficialMod)
+                            {
+                                menu = sortItem.baseMenu;
 
-                            using (FileStream fileStream = new FileStream(sortItem.menu, FileMode.Open))
+                                using (FileStream fileStream = new FileStream(sortItem.menu, FileMode.Open))
+                                {
+                                    if (fileStream == null)
+                                    {
+                                        ready = false;
+                                    }
+                                    else
+                                    {
+                                        modBuf = new byte[fileStream.Length];
+                                        fileStream.Read(modBuf, 0, (int)fileStream.Length);
+                                    }
+                                }
+                            }
+                            byte[] menuBuf = null;
+                            using (AFileBase afileBase = GameUty.FileOpen(menu, null))
                             {
-                                if (fileStream == null)
+                                if (ready = afileBase.IsValid())
                                 {
-                                    ready = false;
+                                    menuBuf = afileBase.ReadAll();
                                 }
-                                else
+                            }
+
+                            if (ready)
+                            {
+                                string[] meshInfo = ProcScriptBin(menuBuf);
+                                gameObject = ImportCM2.LoadSkinMesh_R(meshInfo[0], meshInfo, 1);
+                                gameObject.name = menu;
+                                if (sortItem.isOfficialMod)
                                 {
-                                    modBuf = new byte[fileStream.Length];
-                                    fileStream.Read(modBuf, 0, (int)fileStream.Length);
+                                    gameObject.name += $"#{Path.GetFileName(sortItem.menu)}";
+                                    ProcModScriptBin(modBuf, gameObject);
                                 }
                             }
                         }
-                        byte[] menuBuf = null;
-                        using (AFileBase afileBase = GameUty.FileOpen(menu, null))
+                        else
                         {
-                            if (ready = afileBase.IsValid())
-                            {
-                                menuBuf = afileBase.ReadAll();
-                            }
+                            // My Room Custom content
+                            PlacementData.Data data = PlacementData.GetData(int.Parse(sortItem.menu));
+                            gameObject = Instantiate(data.GetPrefab());
+                            gameObject.name = $"creative_{sortItem.baseMenu}";
                         }
 
-                        if (ready)
+                        if (gameObject != null)
                         {
-                            string[] meshInfo = ProcScriptBin(menuBuf);
-                            gameObject = ImportCM2.LoadSkinMesh_R(meshInfo[0], meshInfo, 1);
-                            gameObject.name = menu;
-                            if (sortItem.isOfficialMod)
-                            {
-                                gameObject.name += $"#{Path.GetFileName(sortItem.menu)}";
-                                ProcModScriptBin(modBuf, gameObject);
-                            }
+                            doguBObject.Add(gameObject);
+                            gameObject.transform.position = new Vector3(0, 0, 0.4f);
+                            doguCnt = doguBObject.Count - 1;
+                            gDogu[doguCnt] = GameObject.CreatePrimitive(PrimitiveType.Cube);
+                            gDogu[doguCnt].GetComponent<Renderer>().material = m_material;
+                            gDogu[doguCnt].layer = 8;
+                            gDogu[doguCnt].GetComponent<Renderer>().enabled = false;
+                            gDogu[doguCnt].SetActive(false);
+                            gDogu[doguCnt].transform.position = gameObject.transform.position;
+                            mDogu[doguCnt] = gDogu[doguCnt].AddComponent<MouseDrag6>();
+                            mDogu[doguCnt].isScale = false;
+                            mDogu[doguCnt].obj = gDogu[doguCnt];
+                            mDogu[doguCnt].maid = gameObject;
+                            mDogu[doguCnt].angles = gameObject.transform.eulerAngles;
+                            gDogu[doguCnt].transform.localScale = new Vector3(cubeSize, cubeSize, cubeSize);
+                            mDogu[doguCnt].ido = 1;
                         }
                     }
-                    else
-                    {
-                        // My Room Custom content
-                        PlacementData.Data data = PlacementData.GetData(int.Parse(sortItem.menu));
-                        gameObject = Instantiate(data.GetPrefab());
-                        gameObject.name = $"creative_{sortItem.baseMenu}";
-                    }
 
-                    if (gameObject != null)
-                    {
-                        doguBObject.Add(gameObject);
-                        gameObject.transform.position = new Vector3(0, 0, 0.4f);
-                        doguCnt = doguBObject.Count - 1;
-                        gDogu[doguCnt] = GameObject.CreatePrimitive(PrimitiveType.Cube);
-                        gDogu[doguCnt].GetComponent<Renderer>().material = m_material;
-                        gDogu[doguCnt].layer = 8;
-                        gDogu[doguCnt].GetComponent<Renderer>().enabled = false;
-                        gDogu[doguCnt].SetActive(false);
-                        gDogu[doguCnt].transform.position = gameObject.transform.position;
-                        mDogu[doguCnt] = gDogu[doguCnt].AddComponent<MouseDrag6>();
-                        mDogu[doguCnt].isScale = false;
-                        mDogu[doguCnt].obj = gDogu[doguCnt];
-                        mDogu[doguCnt].maid = gameObject;
-                        mDogu[doguCnt].angles = gameObject.transform.eulerAngles;
-                        gDogu[doguCnt].transform.localScale = new Vector3(cubeSize, cubeSize, cubeSize);
-                        mDogu[doguCnt].ido = 1;
-                    }
+                    GUI.DrawTexture(position2, sortItem.tex);
+                    bg2Index++;
                 }
 
-                GUI.DrawTexture(position2, sortItem.tex);
-                bg2Index++;
+                GUI.EndScrollView();
             }
 
-            GUI.EndScrollView();
             GUI.enabled = true;
             GUI.Label(new Rect(GetPix(3), GetPix(108), GetPix(100), GetPix(25)),
                       "服装",
@@ -553,6 +560,7 @@ namespace CM3D2.MultipleMaids.Plugin
                 if (!sceneManagerInitialize) InitializeSceneManager();
             }
 
+            GUI.enabled = !bg2Busy;
             int num1 =
                     slotCombo.List(new Rect(GetPix(51),
                                              GetPix(111),
@@ -769,9 +777,7 @@ namespace CM3D2.MultipleMaids.Plugin
                 return;
             }
 
-            numberOfModItems = 0;
             slotIndex = num1;
-            sortList.Clear();
             bg2ScrollPos = new Vector2(0.0f, 0.0f);
 
             if (slotIndex == 0)
@@ -802,219 +808,14 @@ namespace CM3D2.MultipleMaids.Plugin
             }
             else
             {
-                if (itemDataList.Count == 0)
+                if (!bg2Initialized)
                 {
-                    #region menu files
-                    HashSet<string> modMenus = null;
-                    if (!modItemsOnly)
-                    {
-                        modMenus = new HashSet<string>(GameUty.ModOnlysMenuFiles
-                            .Select(file => Path.GetFileName(file).ToLowerInvariant()));
-                    }
-
-                    string[] menuFiles = modItemsOnly ? GameUty.ModOnlysMenuFiles : GameUty.MenuFiles;
-                    foreach (string menuFile in menuFiles)
-                    {
-                        string fileName = Path.GetFileName(menuFile);
-                        byte[] buf;
-                        using (AFileBase aFileBase = GameUty.FileOpen(menuFile))
-                        {
-                            if (!aFileBase.IsValid())
-                            {
-                                continue;
-                            }
-                            buf = aFileBase.ReadAll();
-                        }
-
-                        ItemData item = new ItemData()
-                        {
-                            menu = fileName,
-                            isMod = modItemsOnly ? true : modMenus.Contains(fileName)
-                        };
-                        BinaryReader binaryReader = new BinaryReader(new MemoryStream(buf), Encoding.UTF8);
-                        if (binaryReader.ReadString() != "CM3D2_MENU")
-                        {
-                            binaryReader.Close();
-                        }
-                        else
-                        {
-                            try
-                            {
-                                binaryReader.ReadInt32();
-                                binaryReader.ReadString();
-                                item.name = binaryReader.ReadString();
-                                item.category = binaryReader.ReadString();
-                                binaryReader.ReadString();
-                                binaryReader.ReadInt32();
-                                bool run = true;
-                                do
-                                {
-                                    int size;
-                                    do
-                                    {
-                                        size = binaryReader.ReadByte();
-                                    } while (size == 0);
-
-                                    for (int index = 0; index < size; ++index)
-                                    {
-                                        string header = binaryReader.ReadString();
-                                        if (header == "icons" || header == "icon")
-                                        {
-                                            run = false;
-                                            item.icon = binaryReader.ReadString();
-                                            break;
-                                        }
-
-                                        if (header == "priority")
-                                        {
-                                            int.TryParse(binaryReader.ReadString(), out item.priority);
-                                            break;
-                                        }
-                                    }
-                                } while (run);
-
-                                itemDataList.Add(item);
-                            }
-                            catch { }
-
-                            binaryReader.Close();
-                        }
-                    }
-                    #endregion
-
-                    #region mod files
-                    foreach (string modFile in Menu.GetModFiles())
-                    {
-                        byte[] buf = null;
-                        try
-                        {
-                            using (FileStream fileStream = new FileStream(modFile, FileMode.Open))
-                            {
-                                if (fileStream == null)
-                                {
-                                    continue;
-                                }
-                                buf = new byte[fileStream.Length];
-                                fileStream.Read(buf, 0, (int)fileStream.Length);
-                            }
-                        }
-                        catch { }
-
-                        if (buf == null)
-                        {
-                            continue;
-                        }
-
-                        ItemData item = new ItemData()
-                        {
-                            isMod = true,
-                            isOfficialMod = true,
-                            menu = modFile,
-                            priority = 1000
-                        };
-
-                        BinaryReader binaryReader = new BinaryReader(new MemoryStream(buf), Encoding.UTF8);
-                        if (binaryReader.ReadString() != "CM3D2_MOD")
-                        {
-                            binaryReader.Close();
-                        }
-                        else
-                        {
-                            try
-                            {
-                                binaryReader.ReadInt32();
-                                string iconName = binaryReader.ReadString();
-                                string baseItemPath = binaryReader.ReadString().Replace(":", " ");
-                                item.baseItem = Path.GetFileName(baseItemPath);
-                                item.name = binaryReader.ReadString();
-                                item.category = binaryReader.ReadString();
-                                binaryReader.ReadString();
-                                string mpnValue = binaryReader.ReadString();
-                                MPN mpn = MPN.null_mpn;
-                                try
-                                {
-                                    mpn = (MPN)Enum.Parse(typeof(MPN), mpnValue, true);
-                                }
-                                catch
-                                {
-                                    binaryReader.Close();
-                                    continue;
-                                }
-                                if (mpn != MPN.null_mpn)
-                                {
-                                    binaryReader.ReadString();
-                                }
-                                binaryReader.ReadString();
-                                int size = binaryReader.ReadInt32();
-                                for (int i = 0; i < size; i++)
-                                {
-                                    string key = binaryReader.ReadString();
-                                    int count = binaryReader.ReadInt32();
-                                    byte[] data = binaryReader.ReadBytes(count);
-                                    if (string.Equals(key, iconName, StringComparison.InvariantCultureIgnoreCase))
-                                    {
-                                        Texture2D tex = new Texture2D(1, 1, TextureFormat.RGBA32, false);
-                                        tex.LoadImage(data);
-                                        item.tex = tex;
-                                        break;
-                                    }
-                                }
-                                itemDataList.Add(item);
-                            }
-                            catch { }
-                            binaryReader.Close();
-                        }
-                    }
-                    #endregion
-                }
-
-                foreach (ItemData itemData in itemDataList)
-                {
-                    if (itemData.category == slotArray[slotIndex] && itemData.priority > 0)
-                    {
-                        sortList.Add(new SortItem()
-                        {
-                            category = itemData.category,
-                            priority = itemData.priority,
-                            name = itemData.name,
-                            icon = itemData.icon,
-                            menu = itemData.menu,
-                            tex = itemData.tex,
-                            isMod = itemData.isMod,
-                            isOfficialMod = itemData.isOfficialMod,
-                            baseMenu = itemData.baseItem
-                        });
-                    }
+                    GameMain.Instance.StartCoroutine(InitializeBG2());
                 }
-
-                IOrderedEnumerable<SortItem> sortedItemList = sortList
-                    .OrderBy(item => item.priority)
-                    .ThenBy(item => item.name);
-
-                List<SortItem> sortItemList = new List<SortItem>();
-
-                string previousMenu = "";
-                foreach (SortItem item in sortedItemList)
+                else
                 {
-                    try
-                    {
-                        if (item.menu != previousMenu)
-                        {
-                            if (!modItemsOnly && item.isMod) numberOfModItems++;
-                            if (item.tex == null)
-                            {
-                                byte[] data = ImportCM.LoadTexture(GameUty.FileSystem, item.icon, false).data;
-                                Texture2D texture2D = new Texture2D(50, 50, TextureFormat.RGB565, false);
-                                texture2D.LoadImage(data);
-                                item.tex = texture2D;
-                            }
-                            previousMenu = item.menu;
-                            sortItemList.Add(item);
-                        }
-                    }
-                    catch { }
+                    SetBG2Props();
                 }
-                sortList = sortItemList;
             }
         }
 
@@ -4853,7 +4654,7 @@ namespace CM3D2.MultipleMaids.Plugin
                             DynamicSkirtBone fieldValue =
                                     GetFieldValue<BoneHair3, DynamicSkirtBone>(maid.body0.goSlot[index2].bonehair3, "m_SkirtBone");
                             SkirtListArray[selectMaidIndex][index2] = fieldValue;
-                            SetFieldValue8<BoneHair3, DynamicSkirtBone>(maid.body0.goSlot[index2].bonehair3,
+                            SetFieldValue<BoneHair3, DynamicSkirtBone>(maid.body0.goSlot[index2].bonehair3,
                                                                         "m_SkirtBone",
                                                                          null);
                         }
@@ -4862,7 +4663,7 @@ namespace CM3D2.MultipleMaids.Plugin
                     {
                         for (int index2 = 0; index2 < maid.body0.goSlot.Count; ++index2)
                         {
-                            SetFieldValue8<BoneHair3, DynamicSkirtBone>(maid.body0.goSlot[index2].bonehair3,
+                            SetFieldValue<BoneHair3, DynamicSkirtBone>(maid.body0.goSlot[index2].bonehair3,
                                                                         "m_SkirtBone",
                                                                         SkirtListArray[selectMaidIndex][index2]);
                         }
@@ -6134,10 +5935,11 @@ namespace CM3D2.MultipleMaids.Plugin
                     }
 
                     string[] strArray = faceComboList[faceIndex[selectMaidIndex]].text.Split(':')[2].Split(',');
-                    fieldValue2[(int)morph.hash["eyeclose"]] = float.Parse(strArray[0]);
-                    fieldValue2[(int)morph.hash["eyeclose2"]] = float.Parse(strArray[1]);
+
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] = float.Parse(strArray[0]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] = float.Parse(strArray[1]);
                     fieldValue2[(int)morph.hash["eyeclose3"]] = float.Parse(strArray[2]);
-                    fieldValue2[(int)morph.hash["eyeclose6"]] = float.Parse(strArray[3]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] = float.Parse(strArray[3]);
                     fieldValue1[(int)morph.hash["hitomih"]] = float.Parse(strArray[4]);
                     fieldValue1[(int)morph.hash["hitomis"]] = float.Parse(strArray[5]);
                     fieldValue1[(int)morph.hash["mayuha"]] = float.Parse(strArray[6]);
@@ -6151,7 +5953,7 @@ namespace CM3D2.MultipleMaids.Plugin
                     fieldValue1[(int)morph.hash["tangout"]] = float.Parse(strArray[14]);
                     fieldValue1[(int)morph.hash["tangup"]] = float.Parse(strArray[15]);
                     fieldValue1[(int)morph.hash["eyebig"]] = float.Parse(strArray[16]);
-                    fieldValue2[(int)morph.hash["eyeclose5"]] = float.Parse(strArray[17]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] = float.Parse(strArray[17]);
                     fieldValue1[(int)morph.hash["mayuw"]] = float.Parse(strArray[18]);
                     fieldValue1[(int)morph.hash["mouthhe"]] = float.Parse(strArray[19]);
                     fieldValue1[(int)morph.hash["mouthc"]] = float.Parse(strArray[20]);
@@ -6300,10 +6102,11 @@ namespace CM3D2.MultipleMaids.Plugin
                     }
 
                     string[] strArray = faceComboList[faceIndex[selectMaidIndex]].text.Split(':')[2].Split(',');
-                    fieldValue2[(int)morph.hash["eyeclose"]] = float.Parse(strArray[0]);
-                    fieldValue2[(int)morph.hash["eyeclose2"]] = float.Parse(strArray[1]);
+
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] = float.Parse(strArray[0]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] = float.Parse(strArray[1]);
                     fieldValue2[(int)morph.hash["eyeclose3"]] = float.Parse(strArray[2]);
-                    fieldValue2[(int)morph.hash["eyeclose6"]] = float.Parse(strArray[3]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] = float.Parse(strArray[3]);
                     fieldValue1[(int)morph.hash["hitomih"]] = float.Parse(strArray[4]);
                     fieldValue1[(int)morph.hash["hitomis"]] = float.Parse(strArray[5]);
                     fieldValue1[(int)morph.hash["mayuha"]] = float.Parse(strArray[6]);
@@ -6317,7 +6120,7 @@ namespace CM3D2.MultipleMaids.Plugin
                     fieldValue1[(int)morph.hash["tangout"]] = float.Parse(strArray[14]);
                     fieldValue1[(int)morph.hash["tangup"]] = float.Parse(strArray[15]);
                     fieldValue1[(int)morph.hash["eyebig"]] = float.Parse(strArray[16]);
-                    fieldValue2[(int)morph.hash["eyeclose5"]] = float.Parse(strArray[17]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] = float.Parse(strArray[17]);
                     fieldValue1[(int)morph.hash["mayuw"]] = float.Parse(strArray[18]);
                     fieldValue1[(int)morph.hash["mouthhe"]] = float.Parse(strArray[19]);
                     fieldValue1[(int)morph.hash["mouthc"]] = float.Parse(strArray[20]);
@@ -6821,29 +6624,31 @@ namespace CM3D2.MultipleMaids.Plugin
                     TMorph morph = maidArray[selectMaidIndex].body0.Face.morph;
                     float[] fieldValue1 = GetFieldValue<TMorph, float[]>(morph, "BlendValues");
                     float[] fieldValue2 = GetFieldValue<TMorph, float[]>(morph, "BlendValuesBackup");
-                    string str1 = inName4 + ":" + fieldValue2[(int)morph.hash["eyeclose"]] + ","
-                                  + fieldValue2[(int)morph.hash["eyeclose2"]] + ","
-                                  + fieldValue2[(int)morph.hash["eyeclose3"]] + ","
-                                  + fieldValue2[(int)morph.hash["eyeclose6"]] + ","
-                                  + fieldValue1[(int)morph.hash["hitomih"]] + ","
-                                  + fieldValue1[(int)morph.hash["hitomis"]] + ","
-                                  + fieldValue1[(int)morph.hash["mayuha"]] + ","
-                                  + fieldValue1[(int)morph.hash["mayuup"]] + ","
-                                  + fieldValue1[(int)morph.hash["mayuv"]] + ","
-                                  + fieldValue1[(int)morph.hash["mayuvhalf"]] + ","
-                                  + fieldValue1[(int)morph.hash["moutha"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouths"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouthdw"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouthup"]] + ","
-                                  + fieldValue1[(int)morph.hash["tangout"]] + ","
-                                  + fieldValue1[(int)morph.hash["tangup"]] + ","
-                                  + fieldValue1[(int)morph.hash["eyebig"]] + ","
-                                  + fieldValue2[(int)morph.hash["eyeclose5"]] + ","
-                                  + fieldValue1[(int)morph.hash["mayuw"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouthhe"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouthc"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouthi"]] + ","
-                                  + fieldValue1[(int)morph.hash["mouthuphalf"]] + ",";
+
+                    string str1 = inName4 + ":"
+                        + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] + ","
+                        + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] + ","
+                        + fieldValue2[(int)morph.hash["eyeclose3"]] + ","
+                        + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] + ","
+                        + fieldValue1[(int)morph.hash["hitomih"]] + ","
+                        + fieldValue1[(int)morph.hash["hitomis"]] + ","
+                        + fieldValue1[(int)morph.hash["mayuha"]] + ","
+                        + fieldValue1[(int)morph.hash["mayuup"]] + ","
+                        + fieldValue1[(int)morph.hash["mayuv"]] + ","
+                        + fieldValue1[(int)morph.hash["mayuvhalf"]] + ","
+                        + fieldValue1[(int)morph.hash["moutha"]] + ","
+                        + fieldValue1[(int)morph.hash["mouths"]] + ","
+                        + fieldValue1[(int)morph.hash["mouthdw"]] + ","
+                        + fieldValue1[(int)morph.hash["mouthup"]] + ","
+                        + fieldValue1[(int)morph.hash["tangout"]] + ","
+                        + fieldValue1[(int)morph.hash["tangup"]] + ","
+                        + fieldValue1[(int)morph.hash["eyebig"]] + ","
+                        + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] + ","
+                        + fieldValue1[(int)morph.hash["mayuw"]] + ","
+                        + fieldValue1[(int)morph.hash["mouthhe"]] + ","
+                        + fieldValue1[(int)morph.hash["mouthc"]] + ","
+                        + fieldValue1[(int)morph.hash["mouthi"]] + ","
+                        + fieldValue1[(int)morph.hash["mouthuphalf"]] + ",";
                     string str2;
                     try
                     {
@@ -7030,10 +6835,10 @@ namespace CM3D2.MultipleMaids.Plugin
                     }
 
                     string[] strArray = faceComboList[faceIndex[selectMaidIndex]].text.Split(':')[2].Split(',');
-                    fieldValue2[(int)morph.hash["eyeclose"]] = float.Parse(strArray[0]);
-                    fieldValue2[(int)morph.hash["eyeclose2"]] = float.Parse(strArray[1]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] = float.Parse(strArray[0]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] = float.Parse(strArray[1]);
                     fieldValue2[(int)morph.hash["eyeclose3"]] = float.Parse(strArray[2]);
-                    fieldValue2[(int)morph.hash["eyeclose6"]] = float.Parse(strArray[3]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] = float.Parse(strArray[3]);
                     fieldValue1[(int)morph.hash["hitomih"]] = float.Parse(strArray[4]);
                     fieldValue1[(int)morph.hash["hitomis"]] = float.Parse(strArray[5]);
                     fieldValue1[(int)morph.hash["mayuha"]] = float.Parse(strArray[6]);
@@ -7047,7 +6852,7 @@ namespace CM3D2.MultipleMaids.Plugin
                     fieldValue1[(int)morph.hash["tangout"]] = float.Parse(strArray[14]);
                     fieldValue1[(int)morph.hash["tangup"]] = float.Parse(strArray[15]);
                     fieldValue1[(int)morph.hash["eyebig"]] = float.Parse(strArray[16]);
-                    fieldValue2[(int)morph.hash["eyeclose5"]] = float.Parse(strArray[17]);
+                    fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] = float.Parse(strArray[17]);
                     fieldValue1[(int)morph.hash["mayuw"]] = float.Parse(strArray[18]);
                     fieldValue1[(int)morph.hash["mouthhe"]] = float.Parse(strArray[19]);
                     fieldValue1[(int)morph.hash["mouthc"]] = float.Parse(strArray[20]);
@@ -8647,7 +8452,7 @@ namespace CM3D2.MultipleMaids.Plugin
                 mFontSize = fontSize;
                 GameObject gameObject = GameObject.Find("__GameMain__/SystemUI Root").transform.Find("MessageWindowPanel").gameObject;
                 //MessageClass messageClass = new MessageClass(gameObject, GameMain.Instance.ScriptMgr.adv_kag.MessageWindowMgr);
-                SetFieldValue2<UILabel, int>(UTY.GetChildObject(gameObject, "MessageViewer/MsgParent/Message", false)
+                SetFieldValue<UILabel, int>(UTY.GetChildObject(gameObject, "MessageViewer/MsgParent/Message", false)
                                                 .GetComponent<UILabel>(),
                                              "mFontSize",
                                              fontSize);
@@ -8677,16 +8482,19 @@ namespace CM3D2.MultipleMaids.Plugin
 
                 MessageClass inst = new MessageClass(gameObject1, messageWindowMgr);
                 // Fix for ENG version: reconfigure MessageClass to behave as in JP game
-                inst.subtitles_manager_.visible = false;
-                inst.subtitles_manager_ = null;
+                if (inst.subtitles_manager_ != null)
+                {
+                    inst.subtitles_manager_.visible = false;
+                    inst.subtitles_manager_ = null;
+                }
                 component.gameObject.SetActive(true);
                 nameComponent.gameObject.SetActive(true);
                 UTY.GetChildObject(gameObject1, "MessageViewer/MsgParent/MessageBox", false).SetActive(true);
-                SetFieldValue5<MessageClass, UILabel>(inst, "message_label_", component);
-                SetFieldValue5<MessageClass, UILabel>(inst, "name_label_", nameComponent);
+                SetFieldValue<MessageClass, UILabel>(inst, "message_label_", component);
+                SetFieldValue<MessageClass, UILabel>(inst, "name_label_", nameComponent);
 
                 component.ProcessText();
-                SetFieldValue2<UILabel, int>(component, "mFontSize", fontSize);
+                SetFieldValue<UILabel, int>(component, "mFontSize", fontSize);
 
                 inst.SetText(inName, inText, "", 0, AudioSourceMgr.Type.System);
                 inst.FinishChAnime();

+ 10 - 7
MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Init.cs

@@ -1,4 +1,4 @@
-using ExIni;
+using ExIni;
 using MyRoomCustom;
 using System;
 using System.Collections;
@@ -38,7 +38,7 @@ namespace CM3D2.MultipleMaids.Plugin
                 {
                     for (int index2 = 0; index2 < stockMaid.body0.goSlot.Count; ++index2)
                     {
-                        SetFieldValue8<BoneHair3, DynamicSkirtBone>(stockMaid.body0.goSlot[index2].bonehair3,
+                        SetFieldValue<BoneHair3, DynamicSkirtBone>(stockMaid.body0.goSlot[index2].bonehair3,
                                                                     "m_SkirtBone",
                                                                     SkirtListArray[index1][index2]);
                     }
@@ -120,7 +120,7 @@ namespace CM3D2.MultipleMaids.Plugin
             MessageWindowMgr messageWindowMgr = GameMain.Instance.ScriptMgr.adv_kag.MessageWindowMgr;
             new MessageClass(gameObject, messageWindowMgr).Clear();
             messageWindowMgr.CloseMessageWindowPanel();
-            SetFieldValue2<UILabel, int>(UTY.GetChildObject(gameObject, "MessageViewer/MsgParent/Message", false).GetComponent<UILabel>(),
+            SetFieldValue<UILabel, int>(UTY.GetChildObject(gameObject, "MessageViewer/MsgParent/Message", false).GetComponent<UILabel>(),
                                          "mFontSize",
                                          fontSize);
             ikMaid = 0;
@@ -439,7 +439,6 @@ namespace CM3D2.MultipleMaids.Plugin
             selectLightIndex = 0;
             itemCombo2.selectedItemIndex = 0;
             slotCombo.selectedItemIndex = 0;
-            sortList.Clear();
             maidCallScrollPos = new Vector2(0.0f, 0.0f);
             poseScrollPos = new Vector2(0.0f, 0.0f);
             faceScrollPos = new Vector2(0.0f, 0.0f);
@@ -470,6 +469,11 @@ namespace CM3D2.MultipleMaids.Plugin
 
         public void init()
         {
+            if (bg2Busy)
+            {
+                bg2Busy = false;
+                GameMain.Instance.StopCoroutine(InitializeBG2());
+            }
             isInit = true;
             isVR = GameMain.Instance.VRMode;
             for (int index1 = 0; index1 < GameMain.Instance.CharacterMgr.GetStockMaidCount(); ++index1)
@@ -496,7 +500,7 @@ namespace CM3D2.MultipleMaids.Plugin
                 {
                     for (int index2 = 0; index2 < stockMaid.body0.goSlot.Count; ++index2)
                     {
-                        SetFieldValue8<BoneHair3, DynamicSkirtBone>(stockMaid.body0.goSlot[index2].bonehair3,
+                        SetFieldValue<BoneHair3, DynamicSkirtBone>(stockMaid.body0.goSlot[index2].bonehair3,
                                                                     "m_SkirtBone",
                                                                     SkirtListArray[index1][index2]);
                     }
@@ -634,7 +638,7 @@ namespace CM3D2.MultipleMaids.Plugin
             MessageWindowMgr messageWindowMgr = GameMain.Instance.ScriptMgr.adv_kag.MessageWindowMgr;
             new MessageClass(gameObject, messageWindowMgr).Clear();
             messageWindowMgr.CloseMessageWindowPanel();
-            SetFieldValue2<UILabel, int>(UTY.GetChildObject(gameObject, "MessageViewer/MsgParent/Message", false).GetComponent<UILabel>(),
+            SetFieldValue<UILabel, int>(UTY.GetChildObject(gameObject, "MessageViewer/MsgParent/Message", false).GetComponent<UILabel>(),
                                          "mFontSize",
                                          fontSize);
             ikMaid = 0;
@@ -960,7 +964,6 @@ namespace CM3D2.MultipleMaids.Plugin
             selectLightIndex = 0;
             itemCombo2.selectedItemIndex = 0;
             slotCombo.selectedItemIndex = 0;
-            sortList.Clear();
             maidCallScrollPos = new Vector2(0.0f, 0.0f);
             poseScrollPos = new Vector2(0.0f, 0.0f);
             faceScrollPos = new Vector2(0.0f, 0.0f);

+ 54 - 54
MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.Update.cs

@@ -188,10 +188,10 @@ namespace CM3D2.MultipleMaids.Plugin
                                + UTY.GetChildObject(mainCamera.gameObject, VRCamera, false).transform.rotation
                                * Vector3.forward
                                * (Input.GetAxis("Mouse ScrollWheel") * (float)(5.0 * Time.deltaTime * 2.0 * 5.0));
-                SetFieldValue3<OvrCamera, Vector3>(GameMain.Instance.OvrMgr.OvrCamera, "v", maid);
+                SetFieldValue<OvrCamera, Vector3>(GameMain.Instance.OvrMgr.OvrCamera, "v", maid);
                 Transform fieldValue = GetFieldValue<OvrCamera, Transform>(GameMain.Instance.OvrMgr.OvrCamera, "m_trBaseHead");
                 fieldValue.position = maid;
-                SetFieldValue4<OvrCamera, Transform>(GameMain.Instance.OvrMgr.OvrCamera, "m_trBaseHead", fieldValue);
+                SetFieldValue<OvrCamera, Transform>(GameMain.Instance.OvrMgr.OvrCamera, "m_trBaseHead", fieldValue);
             }
 
             if (isMekure1a || isMekure2a || isZurasia)
@@ -576,7 +576,7 @@ namespace CM3D2.MultipleMaids.Plugin
                                 fieldValue[TBody.SlotID.accSenaka] = isAccSenaka;
                             }
 
-                            SetFieldValue6<TBody, Hashtable>(maidArray[index1].body0, "m_hFoceHide", fieldValue);
+                            SetFieldValue<TBody, Hashtable>(maidArray[index1].body0, "m_hFoceHide", fieldValue);
                             maidArray[index1].body0.FixMaskFlag();
                             maidArray[index1].body0.FixVisibleFlag(false);
                         }
@@ -2544,10 +2544,10 @@ namespace CM3D2.MultipleMaids.Plugin
                                                     maid.boMabataki = false;
                                                 }
 
-                                                fieldValue2[(int)morph.hash["eyeclose"]] = float.Parse(strArray9[0]);
-                                                fieldValue2[(int)morph.hash["eyeclose2"]] = float.Parse(strArray9[1]);
+                                                fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] = float.Parse(strArray9[0]);
+                                                fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] = float.Parse(strArray9[1]);
                                                 fieldValue2[(int)morph.hash["eyeclose3"]] = float.Parse(strArray9[2]);
-                                                fieldValue2[(int)morph.hash["eyeclose6"]] = float.Parse(strArray9[3]);
+                                                fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] = float.Parse(strArray9[3]);
                                                 fieldValue1[(int)morph.hash["hitomih"]] = float.Parse(strArray9[4]);
                                                 fieldValue1[(int)morph.hash["hitomis"]] = float.Parse(strArray9[5]);
                                                 fieldValue1[(int)morph.hash["mayuha"]] = float.Parse(strArray9[6]);
@@ -2561,7 +2561,7 @@ namespace CM3D2.MultipleMaids.Plugin
                                                 fieldValue1[(int)morph.hash["tangout"]] = float.Parse(strArray9[14]);
                                                 fieldValue1[(int)morph.hash["tangup"]] = float.Parse(strArray9[15]);
                                                 fieldValue1[(int)morph.hash["eyebig"]] = float.Parse(strArray9[16]);
-                                                fieldValue2[(int)morph.hash["eyeclose5"]] = float.Parse(strArray9[17]);
+                                                fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] = float.Parse(strArray9[17]);
                                                 fieldValue1[(int)morph.hash["mayuw"]] = float.Parse(strArray9[18]);
                                                 fieldValue1[(int)morph.hash["mouthhe"]] = float.Parse(strArray9[19]);
                                                 fieldValue1[(int)morph.hash["mouthc"]] = float.Parse(strArray9[20]);
@@ -4727,7 +4727,6 @@ namespace CM3D2.MultipleMaids.Plugin
                         bgCombo2.selectedItemIndex = 0;
                         itemCombo2.selectedItemIndex = 0;
                         slotCombo.selectedItemIndex = 0;
-                        sortList.Clear();
                         maidCallScrollPos = new Vector2(0.0f, 0.0f);
                         poseScrollPos = new Vector2(0.0f, 0.0f);
                         faceScrollPos = new Vector2(0.0f, 0.0f);
@@ -4827,13 +4826,15 @@ namespace CM3D2.MultipleMaids.Plugin
                             isGlove = maid.body0.GetMask(TBody.SlotID.glove);
                             isMegane = maid.body0.GetMask(TBody.SlotID.megane);
                             isAccSenaka = maid.body0.GetMask(TBody.SlotID.accSenaka);
+
                             TMorph morph = maidArray[selectMaidIndex].body0.Face.morph;
                             float[] fieldValue1 = GetFieldValue<TMorph, float[]>(morph, "BlendValues");
                             float[] fieldValue2 = GetFieldValue<TMorph, float[]>(morph, "BlendValuesBackup");
-                            eyeclose = fieldValue2[(int)morph.hash["eyeclose"]];
-                            eyeclose2 = fieldValue2[(int)morph.hash["eyeclose2"]];
+
+                            eyeclose = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]];
+                            eyeclose2 = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]];
                             eyeclose3 = fieldValue2[(int)morph.hash["eyeclose3"]];
-                            eyeclose6 = fieldValue2[(int)morph.hash["eyeclose6"]];
+                            eyeclose6 = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]];
                             hitomih = fieldValue1[(int)morph.hash["hitomih"]];
                             hitomis = fieldValue1[(int)morph.hash["hitomis"]];
                             mayuha = fieldValue1[(int)morph.hash["mayuha"]];
@@ -4847,7 +4848,7 @@ namespace CM3D2.MultipleMaids.Plugin
                             tangout = fieldValue1[(int)morph.hash["tangout"]];
                             tangup = fieldValue1[(int)morph.hash["tangup"]];
                             eyebig = fieldValue1[(int)morph.hash["eyebig"]];
-                            eyeclose5 = fieldValue2[(int)morph.hash["eyeclose5"]];
+                            eyeclose5 = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]];
                             mayuw = fieldValue1[(int)morph.hash["mayuw"]];
                             mouthhe = fieldValue1[(int)morph.hash["mouthhe"]];
                             mouthc = fieldValue1[(int)morph.hash["mouthc"]];
@@ -5184,10 +5185,10 @@ namespace CM3D2.MultipleMaids.Plugin
                             morph.EyeMabataki = 0.0f;
                             isFaceInit = false;
                             maidArray[selectMaidIndex].body0.Face.morph.FixBlendValues_Face();
-                            eyeclose = fieldValue2[(int)morph.hash["eyeclose"]];
-                            eyeclose2 = fieldValue2[(int)morph.hash["eyeclose2"]];
+                            eyeclose = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]];
+                            eyeclose2 = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]];
                             eyeclose3 = fieldValue2[(int)morph.hash["eyeclose3"]];
-                            eyeclose6 = fieldValue2[(int)morph.hash["eyeclose6"]];
+                            eyeclose6 = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]];
                             hitomih = fieldValue1[(int)morph.hash["hitomih"]];
                             hitomis = fieldValue1[(int)morph.hash["hitomis"]];
                             mayuha = fieldValue1[(int)morph.hash["mayuha"]];
@@ -5201,7 +5202,7 @@ namespace CM3D2.MultipleMaids.Plugin
                             tangout = fieldValue1[(int)morph.hash["tangout"]];
                             tangup = fieldValue1[(int)morph.hash["tangup"]];
                             eyebig = fieldValue1[(int)morph.hash["eyebig"]];
-                            eyeclose5 = fieldValue2[(int)morph.hash["eyeclose5"]];
+                            eyeclose5 = fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]];
                             mayuw = fieldValue1[(int)morph.hash["mayuw"]];
                             mouthhe = fieldValue1[(int)morph.hash["mouthhe"]];
                             mouthc = fieldValue1[(int)morph.hash["mouthc"]];
@@ -5411,10 +5412,11 @@ namespace CM3D2.MultipleMaids.Plugin
                             TMorph morph = maidArray[selectMaidIndex].body0.Face.morph;
                             float[] fieldValue1 = GetFieldValue<TMorph, float[]>(morph, "BlendValues");
                             float[] fieldValue2 = GetFieldValue<TMorph, float[]>(morph, "BlendValuesBackup");
-                            fieldValue2[(int)morph.hash["eyeclose"]] = eyeclose;
-                            fieldValue2[(int)morph.hash["eyeclose2"]] = eyeclose2;
+
+                            fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] = eyeclose;
+                            fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] = eyeclose2;
                             fieldValue2[(int)morph.hash["eyeclose3"]] = eyeclose3;
-                            fieldValue2[(int)morph.hash["eyeclose6"]] = eyeclose6;
+                            fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] = eyeclose6;
                             fieldValue1[(int)morph.hash["hitomih"]] = hitomih;
                             fieldValue1[(int)morph.hash["hitomis"]] = hitomis;
                             fieldValue1[(int)morph.hash["mayuha"]] = mayuha;
@@ -5424,7 +5426,7 @@ namespace CM3D2.MultipleMaids.Plugin
                             fieldValue1[(int)morph.hash["tangout"]] = tangout;
                             fieldValue1[(int)morph.hash["tangup"]] = tangup;
                             fieldValue1[(int)morph.hash["eyebig"]] = eyebig;
-                            fieldValue2[(int)morph.hash["eyeclose5"]] = eyeclose5;
+                            fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] = eyeclose5;
                             fieldValue1[(int)morph.hash["mayuw"]] = mayuw;
                             try
                             {
@@ -5432,17 +5434,14 @@ namespace CM3D2.MultipleMaids.Plugin
                             }
                             catch { }
 
-                            if (!isDanceChu)
-                            {
-                                fieldValue1[(int)morph.hash["moutha"]] = moutha;
-                                fieldValue1[(int)morph.hash["mouths"]] = mouths;
-                                fieldValue1[(int)morph.hash["mouthdw"]] = mouthdw;
-                                fieldValue1[(int)morph.hash["mouthup"]] = mouthup;
-                                fieldValue1[(int)morph.hash["mouthhe"]] = mouthhe;
-                                fieldValue1[(int)morph.hash["mouthc"]] = mouthc;
-                                fieldValue1[(int)morph.hash["mouthi"]] = mouthi;
-                                fieldValue1[(int)morph.hash["mouthuphalf"]] = mouthuphalf;
-                            }
+                            fieldValue1[(int)morph.hash["moutha"]] = moutha;
+                            fieldValue1[(int)morph.hash["mouths"]] = mouths;
+                            fieldValue1[(int)morph.hash["mouthdw"]] = mouthdw;
+                            fieldValue1[(int)morph.hash["mouthup"]] = mouthup;
+                            fieldValue1[(int)morph.hash["mouthhe"]] = mouthhe;
+                            fieldValue1[(int)morph.hash["mouthc"]] = mouthc;
+                            fieldValue1[(int)morph.hash["mouthi"]] = mouthi;
+                            fieldValue1[(int)morph.hash["mouthuphalf"]] = mouthuphalf;
 
                             if (isNamida)
                             {
@@ -7737,29 +7736,30 @@ namespace CM3D2.MultipleMaids.Plugin
                 TMorph morph = maid.body0.Face.morph;
                 float[] fieldValue1 = GetFieldValue<TMorph, float[]>(morph, "BlendValues");
                 float[] fieldValue2 = GetFieldValue<TMorph, float[]>(morph, "BlendValuesBackup");
-                string str118 = str117 + fieldValue2[(int)morph.hash["eyeclose"]] + ","
-                                + fieldValue2[(int)morph.hash["eyeclose2"]] + ","
-                                + fieldValue2[(int)morph.hash["eyeclose3"]] + ","
-                                + fieldValue2[(int)morph.hash["eyeclose6"]] + ","
-                                + fieldValue1[(int)morph.hash["hitomih"]] + ","
-                                + fieldValue1[(int)morph.hash["hitomis"]] + ","
-                                + fieldValue1[(int)morph.hash["mayuha"]] + ","
-                                + fieldValue1[(int)morph.hash["mayuup"]] + ","
-                                + fieldValue1[(int)morph.hash["mayuv"]] + ","
-                                + fieldValue1[(int)morph.hash["mayuvhalf"]] + ","
-                                + fieldValue1[(int)morph.hash["moutha"]] + ","
-                                + fieldValue1[(int)morph.hash["mouths"]] + ","
-                                + fieldValue1[(int)morph.hash["mouthdw"]] + ","
-                                + fieldValue1[(int)morph.hash["mouthup"]] + ","
-                                + fieldValue1[(int)morph.hash["tangout"]] + ","
-                                + fieldValue1[(int)morph.hash["tangup"]] + ","
-                                + fieldValue1[(int)morph.hash["eyebig"]] + ","
-                                + fieldValue2[(int)morph.hash["eyeclose5"]] + ","
-                                + fieldValue1[(int)morph.hash["mayuw"]] + ","
-                                + fieldValue1[(int)morph.hash["mouthhe"]] + ","
-                                + fieldValue1[(int)morph.hash["mouthc"]] + ","
-                                + fieldValue1[(int)morph.hash["mouthi"]] + ","
-                                + fieldValue1[(int)morph.hash["mouthuphalf"]] + ",";
+                string str118 = str117
+                    + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] + ","
+                    + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose2")]] + ","
+                    + fieldValue2[(int)morph.hash["eyeclose3"]] + ","
+                    + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose6")]] + ","
+                    + fieldValue1[(int)morph.hash["hitomih"]] + ","
+                    + fieldValue1[(int)morph.hash["hitomis"]] + ","
+                    + fieldValue1[(int)morph.hash["mayuha"]] + ","
+                    + fieldValue1[(int)morph.hash["mayuup"]] + ","
+                    + fieldValue1[(int)morph.hash["mayuv"]] + ","
+                    + fieldValue1[(int)morph.hash["mayuvhalf"]] + ","
+                    + fieldValue1[(int)morph.hash["moutha"]] + ","
+                    + fieldValue1[(int)morph.hash["mouths"]] + ","
+                    + fieldValue1[(int)morph.hash["mouthdw"]] + ","
+                    + fieldValue1[(int)morph.hash["mouthup"]] + ","
+                    + fieldValue1[(int)morph.hash["tangout"]] + ","
+                    + fieldValue1[(int)morph.hash["tangup"]] + ","
+                    + fieldValue1[(int)morph.hash["eyebig"]] + ","
+                    + fieldValue2[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose5")]] + ","
+                    + fieldValue1[(int)morph.hash["mayuw"]] + ","
+                    + fieldValue1[(int)morph.hash["mouthhe"]] + ","
+                    + fieldValue1[(int)morph.hash["mouthc"]] + ","
+                    + fieldValue1[(int)morph.hash["mouthi"]] + ","
+                    + fieldValue1[(int)morph.hash["mouthuphalf"]] + ",";
                 string str119;
                 try
                 {

+ 460 - 58
MultipleMaids/CM3D2/MultipleMaids/Plugin/MultipleMaids.cs

@@ -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;
@@ -5167,6 +5169,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()
         {
@@ -5197,70 +5212,24 @@ namespace CM3D2.MultipleMaids.Plugin
             maidProp.boTempDut = false;
         }
 
-
-        internal static TResult GetFieldValue<T, TResult>(T inst, string name)
-        {
-            if (inst == null)
-            {
-                return default(TResult);
-            }
-
-            FieldInfo fieldInfo = GetFieldInfo<T>(name);
-            if (fieldInfo == null)
-            {
-                return default(TResult);
-            }
-
-            return (TResult)fieldInfo.GetValue(inst);
-        }
-
         internal static FieldInfo GetFieldInfo<T>(string name)
         {
             BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
             return typeof(T).GetField(name, bindingAttr);
         }
 
-        internal static void SetFieldValue<T, TResult>(T inst, string name, Maid maid)
+        internal static TValue GetFieldValue<TType, TValue>(TType instance, string field)
         {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
+            FieldInfo fieldInfo = GetFieldInfo<TType>(field);
+            if (fieldInfo == null || !fieldInfo.IsStatic && instance == null) return default(TValue);
+            return (TValue)fieldInfo.GetValue(instance);
         }
 
-        internal static void SetFieldValue2<T, TResult>(T inst, string name, int maid)
+        internal static void SetFieldValue<TType, TValue>(TType instance, string name, TValue value)
         {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
+            GetFieldInfo<TType>(name).SetValue(instance, value);
         }
 
-        internal static void SetFieldValue3<T, TResult>(T inst, string name, Vector3 maid)
-        {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
-        }
-
-        internal static void SetFieldValue4<T, TResult>(T inst, string name, Transform maid)
-        {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
-        }
-
-        internal static void SetFieldValue5<T, TResult>(T inst, string name, UILabel maid)
-        {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
-        }
-
-        internal static void SetFieldValue6<T, TResult>(T inst, string name, Hashtable maid)
-        {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
-        }
-
-        internal static void SetFieldValue7<T, TResult>(T inst, string name, float[] maid)
-        {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
-        }
-
-        internal static void SetFieldValue8<T, TResult>(T inst, string name, DynamicSkirtBone maid)
-        {
-            GetFieldInfo<T>(name).SetValue(inst, maid);
-        }
-
-
         private void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode)
         {
             sceneLevel = scene.buildIndex;
@@ -5361,7 +5330,7 @@ namespace CM3D2.MultipleMaids.Plugin
                     GetFieldValue<TMorph, float[]>(morph, "BlendValues");
                     float[] fieldValue = GetFieldValue<TMorph, float[]>(morph, "BlendValuesBackup");
                     morph.EyeMabataki = 0.0f;
-                    fieldValue[(int)morph.hash["eyeclose"]] = 0.0f;
+                    fieldValue[(int)morph.hash[EyeCloseFaceKey(morph.bodyskin, "eyeclose")]] = 0.0f;
                 }
 
                 maid.body0.Face.morph.FixBlendValues_Face();
@@ -5610,6 +5579,439 @@ namespace CM3D2.MultipleMaids.Plugin
             }
         }
 
+        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 readonly JsonSerializerSettings serializationSettings;
+            public static readonly string cachePath = Path.Combine(configPath, "cache.json");
+            private 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 (!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()
+        {
+            if (BG2Acc == null)
+            {
+                BG2Acc = new Dictionary<string, List<SortItem>>(StringComparer.InvariantCultureIgnoreCase);
+                BG2AccInit = new Dictionary<string, bool>(StringComparer.InvariantCultureIgnoreCase);
+                foreach (string category in accMpn)
+                {
+                    BG2Acc[category] = new List<SortItem>();
+                    BG2AccInit[category] = false;
+                }
+            }
+
+            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
+            {
+                if (!modItemsOnly)
+                {
+                    bg2Busy = true;
+                    while (!GameMain.Instance.MenuDataBase.JobFinished()) yield return null;
+                    if (!bg2Busy) yield break;
+                    bg2Busy = false;
+
+                    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);
+                }
+            }
+
+            bg2Initialized = true;
+            SetBG2Props();
+        }
+
+        private string EyeCloseFaceKey(TBodySkin face, string faceKey)
+        {
+            if (face.PartsVersion >= 120 && faceKey.IndexOf("eyeclose") == 0)
+            {
+                if (faceKey == "eyeclose3") return faceKey;
+                if (faceKey == "eyeclose")
+                {
+                    faceKey += '1';
+                }
+                TMorph.GP01FB_FACE_TYPE faceType = face.morph.GetFaceTypeGP01FB();
+                faceKey += TMorph.crcFaceTypesStr[(int)faceType];
+            }
+            return faceKey;
+        }
+
+        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;
+        private Dictionary<string, bool> BG2AccInit;
+
+        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 = string.Compare(x.name, 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))
+                        {
+                            Util.Logger.Log(Util.LogLevel.Warning, $"Could not find icon '{item.icon}' for menu '{item.menu}'");
+                            return true;
+                        }
+                        else
+                        {
+                            try
+                            {
+                                byte[] data = ImportCM.LoadTexture(GameUty.FileSystem, item.icon, false).data;
+                                texture2D = new Texture2D(50, 50, TextureFormat.RGB565, false);
+                                texture2D.LoadImage(data);
+                            }
+                            catch
+                            {
+                                Util.Logger.Log(Util.LogLevel.Warning, $"Failed to load '{item.icon}' for menu '{item.menu}'");
+                                return true;
+                            }
+                        }
+                        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;
+            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, SortItem sortItem)
+        {
+            if (!validBG2Menu(menuFile)) return false;
+
+            byte[] buf = null;
+            try
+            {
+                using (AFileBase aFileBase = GameUty.FileOpen(menuFile))
+                {
+                    if (!aFileBase.IsValid()) return false;
+                    if (aFileBase.GetSize() == 0)
+                    {
+                        Util.Logger.Log(Util.LogLevel.Error, $"Menu file '{menuFile}' is empty");
+                        return false;
+                    }
+                    buf = aFileBase.ReadAll();
+                }
+            }
+            catch
+            {
+                Util.Logger.Log(Util.LogLevel.Error, $"Could not read menu file '{menuFile}'");
+                return false;
+            }
+
+            if (buf == null) return false;
+
+            using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(buf), Encoding.UTF8))
+            {
+                try
+                {
+                    if (binaryReader.ReadString() != "CM3D2_MENU") return false;
+                    else
+                    {
+                        binaryReader.ReadInt32();
+                        binaryReader.ReadString();
+                        sortItem.name = binaryReader.ReadString();
+                        sortItem.category = binaryReader.ReadString();
+                        if (!accMpn.Contains(sortItem.category)) return false;
+                        binaryReader.ReadString();
+                        binaryReader.ReadInt32();
+                        bool run = true;
+                        do
+                        {
+                            int size;
+                            do
+                            {
+                                size = binaryReader.ReadByte();
+                            } while (size == 0);
+
+                            for (int index = 0; index < size; ++index)
+                            {
+                                string header = binaryReader.ReadString();
+                                if (header == "icons" || header == "icon")
+                                {
+                                    run = false;
+                                    sortItem.icon = binaryReader.ReadString();
+                                    break;
+                                }
+
+                                if (header == "priority")
+                                {
+                                    int.TryParse(binaryReader.ReadString(), out sortItem.priority);
+                                    break;
+                                }
+                            }
+                        } while (run);
+                    }
+                }
+                catch
+                {
+                    Util.Logger.Log(Util.LogLevel.Error, $"Could not parse menu file '{menuFile}'");
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        private static bool ParseModMenuFile(string modMenuFile, SortItem sortItem)
+        {
+            if (!validBG2Menu(modMenuFile)) return false;
+
+            byte[] buf = null;
+            try
+            {
+                using (FileStream fileStream = new FileStream(modMenuFile, FileMode.Open))
+                {
+                    if (fileStream == null) return false;
+                    if (fileStream.Length == 0L)
+                    {
+                        Util.Logger.Log(Util.LogLevel.Error, $"Mod menu file '{modMenuFile}' is empty");
+                        return false;
+                    }
+                    buf = new byte[fileStream.Length];
+                    fileStream.Read(buf, 0, (int)fileStream.Length);
+                }
+            }
+            catch
+            {
+                Util.Logger.Log(Util.LogLevel.Error, $"Could not read mod menu file '{modMenuFile}'");
+                return false;
+            }
+
+            if (buf == null) return false;
+
+            using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(buf), Encoding.UTF8))
+            {
+                try
+                {
+                    if (binaryReader.ReadString() != "CM3D2_MOD") return false;
+                    else
+                    {
+                        binaryReader.ReadInt32();
+                        string iconName = binaryReader.ReadString();
+                        string baseItemPath = binaryReader.ReadString().Replace(":", " ");
+                        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;
+                        try
+                        {
+                            mpn = (MPN)Enum.Parse(typeof(MPN), mpnValue, true);
+                        }
+                        catch
+                        {
+                            return false;
+                        }
+                        if (mpn != MPN.null_mpn)
+                        {
+                            binaryReader.ReadString();
+                        }
+                        binaryReader.ReadString();
+                        int size = binaryReader.ReadInt32();
+                        for (int i = 0; i < size; i++)
+                        {
+                            string key = binaryReader.ReadString();
+                            int count = binaryReader.ReadInt32();
+                            byte[] data = binaryReader.ReadBytes(count);
+                            if (string.Equals(key, iconName, StringComparison.InvariantCultureIgnoreCase))
+                            {
+                                Texture2D tex = new Texture2D(1, 1, TextureFormat.RGBA32, false);
+                                tex.LoadImage(data);
+                                sortItem.tex = tex;
+                                break;
+                            }
+                        }
+                    }
+                }
+                catch
+                {
+                    Util.Logger.Log(Util.LogLevel.Error, $"Could not parse mod menu file '{modMenuFile}'");
+                    return false;
+                }
+            }
+            return true;
+        }
+
         private static string PluginString()
         {
             return $"{PluginName} {PluginVersion}";
@@ -5639,11 +6041,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;

+ 3 - 0
MultipleMaids/MultipleMaids.csproj

@@ -29,6 +29,9 @@
     <Reference Include="UnityInjector">
       <HintPath>lib\UnityInjector.dll</HintPath>
     </Reference>
+	<Reference Include="Newtonsoft.Josn">
+	  <HintPath>lib\Newtonsoft.Json.dll</HintPath>
+	</Reference>
   </ItemGroup>
 
   <Target Name="ILRepack" AfterTargets="Build">

BIN
MultipleMaids/lib/Assembly-CSharp-firstpass.dll


BIN
MultipleMaids/lib/Assembly-CSharp.dll


BIN
MultipleMaids/lib/Assembly-UnityScript-firstpass.dll