using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using UnityEngine; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using wf; namespace COM3D2.MeidoPhotoStudio.Plugin { internal class Constants { public static readonly string customPosePath; public static readonly string scenesPath; public static readonly string kankyoPath; public static readonly string configPath; public static readonly int mainWindowID = 765; public static readonly int messageWindowID = 961; public static readonly int sceneManagerWindowID = 876; public static readonly int sceneManagerModalID = 283; public static readonly int dropdownWindowID = 777; public enum Window { Call, Pose, Face, BG, BG2, Main, Message, Save, SaveModal } public enum Scene { Daily = 3, Edit = 5 } public static readonly List PoseGroupList; public static readonly Dictionary> PoseDict; public static readonly Dictionary>> CustomPoseDict; public static readonly List FaceBlendList; public static readonly List BGList; public static readonly List> MyRoomCustomBGList; public static event EventHandler MenuFilesChange; public static int CustomPoseGroupsIndex { get; private set; } = -1; public static int MyRoomCustomBGIndex { get; private set; } = -1; public static List doguCategories { get; private set; } public static readonly Dictionary> DoguDict; public enum DoguCategory { Other, Mob, Desk, HandItem, BGSmall } public static readonly Dictionary customDoguCategories = new Dictionary() { [DoguCategory.Other] = "other", [DoguCategory.Mob] = "mob", [DoguCategory.Desk] = "desk", [DoguCategory.HandItem] = "handItem", [DoguCategory.BGSmall] = "bgSmall" }; static Constants() { string modsPath = Path.Combine(Path.GetFullPath(".\\"), @"Mod\MeidoPhotoStudio"); customPosePath = Path.Combine(modsPath, "Custom Poses"); scenesPath = Path.Combine(modsPath, "Scenes"); kankyoPath = Path.Combine(modsPath, "Environments"); configPath = Path.Combine( Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), @"Config\MeidoPhotoStudio" ); foreach (string directory in new[] { customPosePath, scenesPath, kankyoPath, configPath }) { if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); } PoseDict = new Dictionary>(); PoseGroupList = new List(); CustomPoseDict = new Dictionary>>(); FaceBlendList = new List(); BGList = new List(); MyRoomCustomBGList = new List>(); // DoguList = new List(); // OtherDoguList = new List(); DoguDict = new Dictionary>(); } public static void Initialize() { InitializePoses(); InitializeFaceBlends(); InitializeBGs(); InitializeDogu(); } public static void InitializePoses() { // Load Poses string poseListJson = File.ReadAllText(Path.Combine(configPath, "mm_pose_list.json")); List poseLists = JsonConvert.DeserializeObject>(poseListJson); foreach (SerializePoseList poseList in poseLists) { PoseDict[poseList.UIName] = poseList.PoseList; PoseGroupList.Add(poseList.UIName); } // Get Other poses that'll go into Normal 2 and Ero 2 string[] com3d2MotionList = GameUty.FileSystem.GetList("motion", AFileSystemBase.ListType.AllFile); if (com3d2MotionList != null && com3d2MotionList.Length > 0) { HashSet poseSet = new HashSet(); foreach (KeyValuePair> poses in PoseDict) { foreach (string pose in poses.Value) { poseSet.Add(pose); } } List editPoseList = new List(); List otherPoseList = new List(); List eroPoseList = new List(); foreach (string path in com3d2MotionList) { if (Path.GetExtension(path) == ".anm") { string file = Path.GetFileNameWithoutExtension(path); if (!poseSet.Contains(file)) { if (file.StartsWith("edit_")) { editPoseList.Add(file); } else if (file != "dance_cm3d2_001_zoukin" && file != "dance_cm3d2_001_mop" && file != "aruki_1_idougo_f" && file != "sleep2" && file != "stand_akire2" && !file.EndsWith("_3_") && !file.EndsWith("_5_") && !file.StartsWith("vr_") && !file.StartsWith("dance_mc") && !file.Contains("_kubi_") && !file.Contains("a01_") && !file.Contains("b01_") && !file.Contains("b02_") && !file.EndsWith("_m2") && !file.EndsWith("_m2_once_") && !file.StartsWith("h_") && !file.StartsWith("event_") && !file.StartsWith("man_") && !file.EndsWith("_m") && !file.Contains("_m_") && !file.Contains("_man_") ) { if (!path.Contains(@"\sex\")) otherPoseList.Add(file); else eroPoseList.Add(file); } } } } PoseDict["normal"].AddRange(editPoseList); PoseDict["normal2"] = otherPoseList; PoseDict["ero2"] = eroPoseList; PoseGroupList.AddRange(new[] { "normal2", "ero2" }); } CustomPoseGroupsIndex = PoseGroupList.Count; Action GetPoses = directory => { List> poseList = new List>(); foreach (string file in Directory.GetFiles(directory)) { if (Path.GetExtension(file) == ".anm") { string fileName = Path.GetFileNameWithoutExtension(file); poseList.Add(new KeyValuePair(fileName, file)); } } if (poseList.Count > 0) { string poseGroupName = new DirectoryInfo(directory).Name; PoseGroupList.Add(poseGroupName); CustomPoseDict[poseGroupName] = poseList; } }; GetPoses(customPosePath); foreach (string directory in Directory.GetDirectories(customPosePath)) { GetPoses(directory); } } public static void InitializeFaceBlends() { using (CsvParser csvParser = OpenCsvParser("phot_face_list.nei")) { for (int cell_y = 1; cell_y < csvParser.max_cell_y; cell_y++) { if (csvParser.IsCellToExistData(3, cell_y)) { string blendValue = csvParser.GetCellAsString(3, cell_y); FaceBlendList.Add(blendValue); } } } } public static void InitializeBGs() { // Load BGs PhotoBGData.Create(); List photList = PhotoBGData.data; // COM3D2 BGs foreach (PhotoBGData bgData in photList) { if (!string.IsNullOrEmpty(bgData.create_prefab_name)) { string bg = bgData.create_prefab_name; BGList.Add(bg); } } // CM3D2 BGs if (GameUty.IsEnabledCompatibilityMode) { using (CsvParser csvParser = OpenCsvParser("phot_bg_list.nei", GameUty.FileSystemOld)) { for (int cell_y = 1; cell_y < csvParser.max_cell_y; cell_y++) { if (csvParser.IsCellToExistData(3, cell_y)) { string bg = csvParser.GetCellAsString(3, cell_y); BGList.Add(bg); } } } } Dictionary saveDataDict = MyRoomCustom.CreativeRoomManager.GetSaveDataDic(); if (saveDataDict != null) { MyRoomCustomBGIndex = BGList.Count; MyRoomCustomBGList.AddRange(saveDataDict); } } public static void InitializeDogu() { foreach (string customCategory in customDoguCategories.Values) { DoguDict[customCategory] = new List(); } InitializeDeskItems(); InitializePhotoBGItems(); InitializeOtherDogu(); if (MenuFileUtility.MenuFilesReady) InitializeHandItems(); else MenuFileUtility.MenuFilesReadyChange += (s, a) => InitializeHandItems(); doguCategories = new List(); foreach (KeyValuePair keyValuePair in PhotoBGObjectData.popup_category_list) { string category = keyValuePair.Key; if (category == "マイオブジェクト") continue; doguCategories.Add(keyValuePair.Key); } foreach (DoguCategory category in Enum.GetValues(typeof(DoguCategory))) { doguCategories.Add(customDoguCategories[category]); } } private static void InitializeOtherDogu() { DoguDict[customDoguCategories[DoguCategory.BGSmall]] = BGList; DoguDict[customDoguCategories[DoguCategory.Mob]].AddRange(new[] { "Mob_Man_Stand001", "Mob_Man_Stand002", "Mob_Man_Stand003", "Mob_Man_Sit001", "Mob_Man_Sit002", "Mob_Man_Sit003", "Mob_Girl_Stand001", "Mob_Girl_Stand002", "Mob_Girl_Stand003", "Mob_Girl_Sit001", "Mob_Girl_Sit002", "Mob_Girl_Sit003", "Salon:65", "Salon:63", "Salon:69" }); List DoguList = DoguDict[customDoguCategories[DoguCategory.Other]]; string ignoreListPath = Path.Combine(configPath, "mm_ignore_list.json"); string ignoreListJson = File.ReadAllText(ignoreListPath); string[] ignoreList = JsonConvert.DeserializeObject>(ignoreListJson).ToArray(); // bg object extend HashSet doguHashSet = new HashSet(StringComparer.InvariantCultureIgnoreCase); doguHashSet.UnionWith(BGList); doguHashSet.UnionWith(ignoreList); foreach (KeyValuePair> keyValuePair in DoguDict) { doguHashSet.UnionWith(keyValuePair.Value); } string[] com3d2BgList = GameUty.FileSystem.GetList("bg", AFileSystemBase.ListType.AllFile); foreach (string path in com3d2BgList) { if (Path.GetExtension(path) == ".asset_bg" && !path.Contains("myroomcustomize")) { string file = Path.GetFileNameWithoutExtension(path); if (!doguHashSet.Contains(file) && !file.EndsWith("_hit")) { DoguList.Add(file); doguHashSet.Add(file); } } } // Get cherry picked dogu that I can't find in the game files string doguExtendPath = Path.Combine(configPath, "mm_dogu_extend.json"); string doguExtendJson = File.ReadAllText(doguExtendPath); DoguList.AddRange(JsonConvert.DeserializeObject>(doguExtendJson)); string[] cm3d2BgList = GameUty.FileSystemOld.GetList("bg", AFileSystemBase.ListType.AllFile); foreach (string path in cm3d2BgList) { if (Path.GetExtension(path) == ".asset_bg") { string file = Path.GetFileNameWithoutExtension(path); if (!doguHashSet.Contains(file) && !file.EndsWith("_not_optimisation")) { DoguList.Add(file); } } } } private static void InitializeDeskItems() { HashSet enabledIDs = new HashSet(); CsvCommonIdManager.ReadEnabledIdList( CsvCommonIdManager.FileSystemType.Normal, true, "desk_item_enabled_id", ref enabledIDs ); CsvCommonIdManager.ReadEnabledIdList( CsvCommonIdManager.FileSystemType.Old, true, "desk_item_enabled_id", ref enabledIDs ); List com3d2DeskDogu = DoguDict[customDoguCategories[DoguCategory.Desk]]; Action GetDeskItems = fs => { using (CsvParser csvParser = OpenCsvParser("desk_item_detail.nei", fs)) { for (int cell_y = 1; cell_y < csvParser.max_cell_y; cell_y++) { if (csvParser.IsCellToExistData(0, cell_y)) { int cell = csvParser.GetCellAsInteger(0, cell_y); if (enabledIDs.Contains(cell)) { string dogu = String.Empty; if (csvParser.IsCellToExistData(3, cell_y)) { dogu = csvParser.GetCellAsString(3, cell_y); } else if (csvParser.IsCellToExistData(4, cell_y)) { dogu = csvParser.GetCellAsString(4, cell_y); } if (!string.IsNullOrEmpty(dogu)) { com3d2DeskDogu.Add(dogu); } } } } } }; GetDeskItems(GameUty.FileSystem); } private static void InitializePhotoBGItems() { PhotoBGObjectData.Create(); List photoBGObjectList = PhotoBGObjectData.data; List doguCategories = new List(); HashSet addedCategories = new HashSet(StringComparer.InvariantCultureIgnoreCase); foreach (PhotoBGObjectData photoBGObject in photoBGObjectList) { string category = photoBGObject.category; if (!addedCategories.Contains(category)) { addedCategories.Add(category); doguCategories.Add(category); } if (!DoguDict.ContainsKey(category)) { DoguDict[category] = new List(); } string dogu = String.Empty; if (!string.IsNullOrEmpty(photoBGObject.create_prefab_name)) { dogu = photoBGObject.create_prefab_name; } else if (!string.IsNullOrEmpty(photoBGObject.create_asset_bundle_name)) { dogu = photoBGObject.create_asset_bundle_name; } else if (!string.IsNullOrEmpty(photoBGObject.direct_file)) { dogu = photoBGObject.direct_file; } if (!string.IsNullOrEmpty(dogu)) { DoguDict[category].Add(dogu); } } DoguDict["パーティクル"].AddRange(new[] { "Particle/pLineY", "Particle/pLineP02", "Particle/pHeart01", "Particle/pLine_act2", "Particle/pstarY_act2" }); } private static void InitializeHandItems() { MenuDataBase menuDataBase = GameMain.Instance.MenuDataBase; string ignoreListPath = Path.Combine(configPath, "mm_ignore_list.json"); string ignoreListJson = File.ReadAllText(ignoreListPath); string[] ignoreList = JsonConvert.DeserializeObject>(ignoreListJson).ToArray(); HashSet doguHashSet = new HashSet(StringComparer.InvariantCultureIgnoreCase); doguHashSet.UnionWith(BGList); doguHashSet.UnionWith(ignoreList); foreach (KeyValuePair> keyValuePair in DoguDict) { doguHashSet.UnionWith(keyValuePair.Value); } string category = customDoguCategories[DoguCategory.HandItem]; for (int i = 0; i < menuDataBase.GetDataSize(); i++) { menuDataBase.SetIndex(i); MPN mpn = (MPN)menuDataBase.GetCategoryMpn(); if (mpn == MPN.handitem) { string menuFileName = menuDataBase.GetMenuFileName(); if (menuDataBase.GetBoDelOnly() || menuFileName.EndsWith("_del.menu")) continue; string handItemAsOdogu = Utility.HandItemToOdogu(menuFileName); string isolatedHandItem = menuFileName.Substring(menuFileName.IndexOf('_') + 1); if (!doguHashSet.Contains(handItemAsOdogu) && !doguHashSet.Contains(isolatedHandItem)) { doguHashSet.Add(isolatedHandItem); DoguDict[category].Add(menuFileName); // Check for a half deck of cards to add the full deck as well if (menuFileName == "handitemd_cards_i_.menu") { DoguDict[category].Add("handiteml_cards_i_.menu"); } } } } OnMenuFilesChange(MenuFilesEventArgs.HandItems); } private static CsvParser OpenCsvParser(string nei, AFileSystemBase fs) { try { if (fs.IsExistentFile(nei)) { AFileBase file = fs.FileOpen(nei); CsvParser csvParser = new CsvParser(); if (csvParser.Open(file)) return csvParser; else file?.Dispose(); } } catch { } return null; } private static CsvParser OpenCsvParser(string nei) { return OpenCsvParser(nei, GameUty.FileSystem); } public static void WriteToFile(string name, IEnumerable list) { if (Path.GetExtension(name) != ".txt") name += ".txt"; File.WriteAllLines(Path.Combine(configPath, name), list.ToArray()); } private static void OnMenuFilesChange(MenuFilesEventArgs args) { MenuFilesChange?.Invoke(null, args); } private class SerializePoseList { public string UIName { get; set; } public List PoseList { get; set; } } } public class MenuFilesEventArgs : EventArgs { public EventType Type { get; } public enum EventType { HandItems, MenuFiles } public static MenuFilesEventArgs HandItems => new MenuFilesEventArgs(EventType.HandItems); public static MenuFilesEventArgs MenuFiles => new MenuFilesEventArgs(EventType.MenuFiles); public MenuFilesEventArgs(EventType type) { this.Type = type; } } }