private static void ApplyToAllDatas(Func <SaveData.CharaData, PregnancyData, bool> action)
        {
            void ApplyToDatas(SaveData.CharaData character)
            {
                var chafiles = character.GetRelatedChaFiles();

                if (chafiles == null)
                {
                    return;
                }
                foreach (var chaFile in chafiles)
                {
                    var data = ExtendedSave.GetExtendedDataById(chaFile, PregnancyPlugin.GUID);
                    var pd   = PregnancyData.Load(data) ?? new PregnancyData();
                    if (action(character, pd))
                    {
                        ExtendedSave.SetExtendedDataById(chaFile, PregnancyPlugin.GUID, pd.Save());
                    }
                }
            }

            foreach (var heroine in Game.Instance.HeroineList)
            {
                ApplyToDatas(heroine);
            }
            ApplyToDatas(Game.Instance.Player);

            // If controller exists then update its state so it gets any pregnancy week updates
            foreach (var controller in FindObjectsOfType <PregnancyCharaController>())
            {
                controller.ReadData();
            }
        }
Ejemplo n.º 2
0
        protected override void OnCardBeingSaved(GameMode currentGameMode)
        {
            var pd = new PluginData {
                version = 2
            };

            OverlayStorage.Save(pd);

#if !EC
            if (!EnableInStudioSkin)
            {
                pd.data[nameof(EnableInStudioSkin)] = EnableInStudioSkin;
            }
            if (!EnableInStudioIris)
            {
                pd.data[nameof(EnableInStudioIris)] = EnableInStudioIris;
            }
#endif

            SetExtendedData(pd.data.Count > 0 ? pd : null);

#if KK || KKS
            ExtendedSave.SetExtendedDataById(ChaFileControl, "com.jim60105.kk.charaoverlaysbasedoncoordinate", null);
#endif
        }
        private static void ApplyToAllDatas(Func<AgentData, PregnancyData, bool> action)
        {
            void ApplyToDatas(AgentData character)
                {
                    var chafiles = character.GetRelatedChaFiles();
                    if (chafiles == null) return;

                    foreach (var chaFile in chafiles)
                    {
                        var data = ExtendedSave.GetExtendedDataById(chaFile, PregnancyPlugin.GUID);
                        var pd = PregnancyData.Load(data) ?? new PregnancyData();
                        if (action(character, pd))
                            ExtendedSave.SetExtendedDataById(chaFile, PregnancyPlugin.GUID, pd.Save());
                    }
                }

                var heroineList = GetHeroineList();
                if (heroineList == null) return;

                foreach (var heroine in heroineList)
                {
                    ApplyToDatas(heroine);
                }
                // ApplyToDatas(Singleton<Map>.Instance.Player.AgentPartner.AgentData);  TODO find male AgentData, if we want to match what KK is now doing

                // If controller exists then update its state so it gets any pregnancy week updates
                foreach (var controller in FindObjectsOfType<PregnancyCharaController>())
                    controller.ReadData();
        }
Ejemplo n.º 4
0
            private static void ExtendedWorldLoad(WorldData worldData)
            {
                if (worldData == null)
                {
                    return;
                }

                var extResolve = ExtendedSave.GetExtendedDataById(worldData, UARExtID);

                if (extResolve == null)
                {
                    return;
                }

                foreach (var dataPair in extResolve.data)
                {
                    if (int.TryParse(dataPair.Key, out int id) &&
                        worldData.HousingData.CraftInfos.TryGetValue(id, out var craftInfo) &&
                        dataPair.Value is Dictionary <string, object> extData)
                    {
                        ExtendedSave.SetExtendedDataById(craftInfo, UARExtID, new PluginData()
                        {
                            data = extData
                        });
                        ExtendedHousingLoad(craftInfo);
                    }
                }
            }
        /// <summary>
        /// Save your custom data to the character card under the ID you specified when registering this controller.
        /// This should be used inside the <see cref="OnCardBeingSaved"/> event.
        /// Consider using one of the other "Get___ExtData" and "Set___ExtData" methods instead since they are more reliable and handle copying and transferring outfits and they conform to built in maker load toggles.
        /// </summary>
        /// <param name="data">Your custom data to be written to the character card. Can be null to remove the data.</param>
        public void SetExtendedData(PluginData data)
        {
            if (ExtendedDataId == null)
            {
                throw new ArgumentException(nameof(ExtendedDataId));
            }
            ExtendedSave.SetExtendedDataById(ChaFileControl, ExtendedDataId, data);

#if KK //todo || KKS
            // Needed for propagating changes back to the original charFile since they don't get copied back.
            var heroine = ChaControl.GetHeroine();
            if (heroine != null)
            {
                ExtendedSave.SetExtendedDataById(heroine.charFile, ExtendedDataId, data);

                if (ChaControl != heroine.chaCtrl)
                {
                    ExtendedSave.SetExtendedDataById(heroine.chaCtrl.chaFile, ExtendedDataId, data);

                    // Update other instance to reflect the new ext data
                    var other = heroine.chaCtrl.GetComponent(GetType()) as CharaCustomFunctionController;
                    if (other != null)
                    {
                        other.OnReloadInternal(KoikatuAPI.GetCurrentGameMode());
                    }
                }

                var npc = heroine.GetNPC();
                if (npc != null && npc.chaCtrl != null && npc.chaCtrl != ChaControl)
                {
                    ExtendedSave.SetExtendedDataById(npc.chaCtrl.chaFile, ExtendedDataId, data);

                    // Update other instance to reflect the new ext data
                    var other = npc.chaCtrl.GetComponent(GetType()) as CharaCustomFunctionController;
                    if (other != null)
                    {
                        other.OnReloadInternal(KoikatuAPI.GetCurrentGameMode());
                    }
                }
            }

            var player = ChaControl.GetPlayer();
            if (player != null)
            {
                ExtendedSave.SetExtendedDataById(player.charFile, ExtendedDataId, data);

                if (ChaControl != player.chaCtrl)
                {
                    ExtendedSave.SetExtendedDataById(player.chaCtrl.chaFile, ExtendedDataId, data);

                    // Update other instance to reflect the new ext data
                    var other = player.chaCtrl.GetComponent(GetType()) as CharaCustomFunctionController;
                    if (other != null)
                    {
                        other.OnReloadInternal(KoikatuAPI.GetCurrentGameMode());
                    }
                }
            }
#endif
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Card saving
        /// </summary>
        private void ExtendedCardSave(ChaFile file)
        {
            PluginData ExtendedData = ExtendedSave.GetExtendedDataById(file, "KK_FutaMod");

            if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa"))
            {
                if (Singleton <CustomBase> .IsInstance() && Singleton <CustomBase> .Instance.chaCtrl != null)
                {
                    //Saving card from chara maker, get the status from the character
                    ExtendedData.data["Futa"] = file.status.visibleSonAlways;
                    ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData);
                }
                else
                {
                    //Not in chara maker, keep the existing extended data
                    ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData);
                }
            }
            else
            {
                if (Singleton <CustomBase> .IsInstance() && Singleton <CustomBase> .Instance.chaCtrl != null)
                {
                    //Saving a character in chara maker that doesn't have extended data
                    ExtendedData      = new PluginData();
                    ExtendedData.data = new Dictionary <string, object> {
                        { "Futa", file.status.visibleSonAlways }
                    };
                    ExtendedSave.SetExtendedDataById(file, "KK_FutaMod", ExtendedData);
                }
            }
        }
Ejemplo n.º 7
0
        /// <summary>
        /// 將dict存入ChaControl ExtendedData
        /// </summary>
        /// <param name="chaCtrl">目標ChaControl</param>
        /// <param name="dict">要存入的dict</param>
        public static void SetToExtData(ChaControl chaCtrl, Dictionary <int, object> dict)
        {
            PluginData data = new PluginData();
            Dictionary <int, Dictionary <int, object> > allExtData = GetDataFromExtData(chaCtrl, out _);
            int coorType = chaCtrl.fileStatus.coordinateType;

            if ((null == dict || dict.Count == 0) && (null == allExtData || allExtData.Count == 0))
            {
                data = null;
            }
            else
            {
                if (null == allExtData)
                {
                    allExtData = new Dictionary <int, Dictionary <int, object> >();
                    Logger.LogDebug($"HairAccCustomizer info not found while saving.");
                }
                if (allExtData.ContainsKey(coorType))
                {
                    allExtData[coorType].Clear();
                    allExtData.Remove(coorType);
                }
                if (null != dict)
                {
                    allExtData[coorType] = dict;
                }
                data.data.Add("HairAccessories", MessagePackSerializer.Serialize(allExtData));
            }
            ExtendedSave.SetExtendedDataById(chaCtrl.chaFile, GUID, data);
        }
        private static void AddPregnancyWeek(ChaFileControl chaFile)
        {
            var data = ExtendedSave.GetExtendedDataById(chaFile, PregnancyPlugin.GUID);

            if (data == null)
            {
                return;
            }

            PregnancyDataUtils.DeserializeData(data, out var week, out var gameplayEnabled, out var fertility, out var schedule);
            // Advance the week of pregnancy. If week is 0 the character is not pregnant
            if (gameplayEnabled && week > 0)
            {
                if (week < PregnancyDataUtils.LeaveSchoolWeek)
                {
                    // Advance through in-school at full configured speed
                    var weekChange = PregnancyPlugin.PregnancyProgressionSpeed.Value;
                    week = Mathf.Min(PregnancyDataUtils.LeaveSchoolWeek, week + weekChange);
                }
                else if (week < PregnancyDataUtils.ReturnToSchoolWeek)
                {
                    // Make sure at least one week is spent out of school
                    var weekChange = Mathf.Min(PregnancyDataUtils.ReturnToSchoolWeek - PregnancyDataUtils.LeaveSchoolWeek - 1, PregnancyPlugin.PregnancyProgressionSpeed.Value);
                    week = week + weekChange;
                }

                if (week >= PregnancyDataUtils.ReturnToSchoolWeek)
                {
                    week = 0;
                }

                //Logger.Log(LogLevel.Debug, $"Preg - pregnancy week for {chaFile.parameter.fullname} is now {week}");
                ExtendedSave.SetExtendedDataById(chaFile, PregnancyPlugin.GUID, PregnancyDataUtils.SerializeData(week, true, fertility, schedule));
            }
        }
Ejemplo n.º 9
0
 /// <summary>
 /// Save your custom data to the character card under the ID you specified when registering this controller.
 /// </summary>
 /// <param name="data">Your custom data to be written to the character card. Can be null to remove the data.</param>
 public void SetExtendedData(PluginData data)
 {
     if (ExtendedDataId == null)
     {
         throw new ArgumentException(nameof(ExtendedDataId));
     }
     ExtendedSave.SetExtendedDataById(ChaFileControl, ExtendedDataId, data);
 }
 /// <summary>
 /// Save your custom data to the character card under the ID you specified when registering this controller.
 /// </summary>
 /// <param name="data">Your custom data to be written to the character card. Can be null to remove the data.</param>
 public void SetExtendedData(PluginData data)
 {
     if (ExtendedDataId == null)
     {
         throw new ArgumentException(nameof(ExtendedDataId));
     }
     ExtendedSave.SetExtendedDataById(Manager.Game.Instance.saveData, ExtendedDataId, data);
 }
Ejemplo n.º 11
0
        public static void CopyChaFile(ChaFile dst, ChaFile src)
        {
            PluginData ExtendedData = ExtendedSave.GetExtendedDataById(src, "KK_FutaMod");

            if (ExtendedData != null && ExtendedData.data.ContainsKey("Futa"))
            {
                ExtendedSave.SetExtendedDataById(dst, "KK_FutaMod", ExtendedData);
            }
        }
 /// <summary>
 /// Set extended data to the specified coordinate by using the ID you specified when registering this controller.
 /// This should be used inside the <see cref="OnCoordinateBeingSaved"/> event.
 /// Consider using one of the other "Get___ExtData" and "Set___ExtData" methods instead since they are more reliable and handle copying and transferring outfits and they conform to built in maker load toggles.
 /// </summary>
 /// <param name="coordinate">Coordinate you want to set the data to</param>
 /// <param name="data">Your custom data to be saved to the coordinate card</param>
 public void SetCoordinateExtendedData(ChaFileCoordinate coordinate, PluginData data)
 {
     if (coordinate == null)
     {
         throw new ArgumentNullException(nameof(coordinate));
     }
     if (ExtendedDataId == null)
     {
         throw new ArgumentException(nameof(ExtendedDataId));
     }
     ExtendedSave.SetExtendedDataById(coordinate, ExtendedDataId, data);
 }
Ejemplo n.º 13
0
        private static void ExtendedCardSave(ChaFile file)
        {
            List <ResolveInfo> resolutionInfo = new List <ResolveInfo>();

            void IterateStruct(object obj, Dictionary <CategoryProperty, StructValue <int> > dict, string propertyPrefix = "")
            {
                foreach (var kv in dict)
                {
                    int slot = kv.Value.GetMethod(obj);

                    var info = UniversalAutoResolver.LoadedResolutionInfo.FirstOrDefault(x => x.Property == kv.Key.ToString() &&
                                                                                         x.LocalSlot == slot);

                    if (info != null)
                    {
                        var newInfo = info.DeepCopy();
                        newInfo.Property = $"{propertyPrefix}{newInfo.Property}";

                        kv.Value.SetMethod(obj, newInfo.Slot);

                        resolutionInfo.Add(newInfo);
                    }
                }
            }

            IterateStruct(file.custom.face, StructReference.ChaFileFaceProperties);
            IterateStruct(file.custom.body, StructReference.ChaFileBodyProperties);
            IterateStruct(file.custom.hair, StructReference.ChaFileHairProperties);

            for (int i = 0; i < file.coordinate.Length; i++)
            {
                var    coordinate = file.coordinate[i];
                string prefix     = $"outfit{i}.";

                IterateStruct(coordinate.clothes, StructReference.ChaFileClothesProperties, prefix);
                IterateStruct(coordinate.makeup, StructReference.ChaFileMakeupProperties, prefix);

                for (int acc = 0; acc < coordinate.accessory.parts.Length; acc++)
                {
                    string accPrefix = $"{prefix}accessory{acc}.";

                    IterateStruct(coordinate.accessory.parts[acc], StructReference.ChaFileAccessoryPartsInfoProperties, accPrefix);
                }
            }

            ExtendedSave.SetExtendedDataById(file, UniversalAutoResolver.UARExtID, new PluginData
            {
                data = new Dictionary <string, object>
                {
                    { "info", resolutionInfo.Select(x => x.Serialize()).ToList() }
                }
            });
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Register new functionality that will be automatically added to all characters (where applicable).
        /// Offers easy API for saving and loading extended data, and for running logic to apply it to the characters.
        /// All necessary hooking and event subscribing is done for you. All you have to do is create a type
        /// that inherits from <code>CharaExtraBehaviour</code> (don't make instances, the API will make them for you).
        /// </summary>
        /// <typeparam name="T">Type with your custom logic to add to a character</typeparam>
        /// <param name="extendedDataId">Extended data ID used by this behaviour. Set to null if not used. Needed to copy the data in some situations.</param>
        public static void RegisterExtraBehaviour <T>(string extendedDataId) where T : CharaCustomFunctionController, new()
        {
            void BasicCopier(ChaFile dst, ChaFile src)
            {
                var extendedData = ExtendedSave.GetExtendedDataById(src, extendedDataId);

                ExtendedSave.SetExtendedDataById(dst, extendedDataId, extendedData);
            }

            var copier = extendedDataId == null ? (CopyExtendedDataFunc)null : BasicCopier;

            RegisterExtraBehaviour <T>(extendedDataId, copier);
        }
        /// <summary>
        /// Save your custom data to the character card under the ID you specified when registering this controller.
        /// This should be used inside the <see cref="OnCardBeingSaved"/> event.
        /// Consider using one of the other "Get___ExtData" and "Set___ExtData" methods instead since they are more reliable and handle copying and transferring outfits and they conform to built in maker load toggles.
        /// </summary>
        /// <param name="data">Your custom data to be written to the character card. Can be null to remove the data.</param>
        public void SetExtendedData(PluginData data)
        {
            if (ExtendedDataId == null)
            {
                throw new ArgumentException(nameof(ExtendedDataId));
            }
            ExtendedSave.SetExtendedDataById(ChaFileControl, ExtendedDataId, data);

#if KK || KKS
            if (KoikatuAPI.GetCurrentGameMode() == GameMode.MainGame)
            {
                // In main game store ext data for the character inside of the main chaFile object (the one that gets saved to game saves).
                // This allows saving ext data inside talk scenes and H scenes without losing it after exiting to main map.
                var heroine = ChaControl.GetHeroine();
                if (heroine != null)
                {
                    ExtendedSave.SetExtendedDataById(heroine.charFile, ExtendedDataId, data);

                    if (ChaControl != heroine.chaCtrl)
                    {
                        ExtendedSave.SetExtendedDataById(heroine.chaCtrl.chaFile, ExtendedDataId, data);
                        // Update other instance to reflect the new ext data
                        CharacterApi.Hooks.SetDirty(heroine, true);
                    }

                    var npc = heroine.GetNPC();
                    if (npc != null && npc.chaCtrl != null && npc.chaCtrl != ChaControl && npc.chaCtrl != heroine.chaCtrl)
                    {
                        ExtendedSave.SetExtendedDataById(npc.chaCtrl.chaFile, ExtendedDataId, data);
                        // Update other instance to reflect the new ext data
                        CharacterApi.Hooks.SetDirty(heroine, true);
                    }
                }
                else
                {
                    var player = ChaControl.GetPlayer();
                    if (player != null)
                    {
                        ExtendedSave.SetExtendedDataById(player.charFile, ExtendedDataId, data);

                        if (ChaControl != player.chaCtrl)
                        {
                            ExtendedSave.SetExtendedDataById(player.chaCtrl.chaFile, ExtendedDataId, data);
                            // Update other instance to reflect the new ext data
                            CharacterApi.Hooks.SetDirty(player, true);
                        }
                    }
                }
            }
#endif
        }
        private static void StartPregnancy(ChaFileControl chaFile)
        {
            var data = ExtendedSave.GetExtendedDataById(chaFile, PregnancyPlugin.GUID);

            PregnancyDataUtils.DeserializeData(data, out var week, out var gameplayEnabled, out var fertility, out var schedule);

            // If week is 0 the character is not pregnant
            if (gameplayEnabled && week <= 0)
            {
                //Logger.Log(LogLevel.Debug, "Preg - starting pregnancy on " + chaFile.parameter.fullname + ", new week is " + 1);

                ExtendedSave.SetExtendedDataById(chaFile, PregnancyPlugin.GUID, PregnancyDataUtils.SerializeData(1, true, fertility, schedule));
            }
        }
Ejemplo n.º 17
0
        public static void KCOXCoordToChara(ChaFileCoordinate coord, ChaFileControl chara)
        {
            Dictionary <string, ClothesTexData> coordData = coord.KCOXData().KCOXCoordinateDictionary();
            Dictionary <ChaFileDefine.CoordinateType, Dictionary <string, ClothesTexData> > charaData =
                chara.KCOXData().KCOXDictionary();

            ChaFileDefine.CoordinateType[] coordinates =
                Enum.GetValues(typeof(ChaFileDefine.CoordinateType)) as ChaFileDefine.CoordinateType[];

            foreach (ChaFileDefine.CoordinateType coordinate in coordinates)
            {
                charaData[coordinate] = coordData;
            }

            ExtendedSave.SetExtendedDataById(chara, KoiClothesOverlayMgr.GUID, charaData.KCOXData());
        }
Ejemplo n.º 18
0
            internal static void ExtendedHousingSave(CraftInfo info)
            {
                if (info == null)
                {
                    return;
                }

                if (Sideloader.DebugLoggingResolveInfo.Value)
                {
                    Sideloader.Logger.LogInfo($"Embedding Resolving Data to Housing");
                }

                Dictionary <string, object> ExtendedData = new Dictionary <string, object>();

                // housing data has no "key" so it's almost nightmare to resolve the id.
                // and worst of all, the structure of housing card object info is nested.
                // so what im going to do is generating iteration index which can be used for distinguishing objects
                int index = 0;
                Dictionary <int, byte[]> ResolutionInfos = new Dictionary <int, byte[]>();

                HousingObjectIteration <byte[]>(info.ObjectInfos, ref index, ResolutionInfos, (item) =>
                {
                    var extResolve = LoadedMainGameResolutionInfo.Where(x => x.LocalSlot == item.ID).FirstOrDefault();
                    if (extResolve != null)
                    {
                        return(new AIGameResolveInfo
                        {
                            GUID = extResolve.GUID,
                            Slot = extResolve.Slot, // I need to know the history about "hard mod compatibility"
                            LocalSlot = extResolve.LocalSlot,
                        }.Serialize());
                    }
                    else
                    {
                        return(null);
                    }
                });
                ExtendedData.Add(mapItemInfoKey, ResolutionInfos);

                ExtendedSave.SetExtendedDataById(info, UARExtID, new PluginData()
                {
                    data = ExtendedData
                });
            }
Ejemplo n.º 19
0
        private static void ExtendedCardSave(ChaFile file)
        {
            List <ResolveInfo> resolutionInfo = new List <ResolveInfo>();

            void IterateStruct(object obj, Dictionary <CategoryProperty, StructValue <int> > dict)
            {
                foreach (var kv in dict)
                {
                    int slot = kv.Value.GetMethod(obj);

                    var info = UniversalAutoResolver.LoadedResolutionInfo.FirstOrDefault(x => x.Property == kv.Key.ToString() &&
                                                                                         x.LocalSlot == slot);

                    if (info != null)
                    {
                        kv.Value.SetMethod(obj, info.Slot);

                        resolutionInfo.Add(info);
                    }
                }
            }

            IterateStruct(file.custom.face, StructReference.ChaFileFaceProperties);
            IterateStruct(file.custom.body, StructReference.ChaFileBodyProperties);
            IterateStruct(file.custom.hair, StructReference.ChaFileHairProperties);

            //foreach (var coordinate in file.coordinate)
            //{
            //    IterateStruct(file.coordinate., StructReference.ChaFileFaceProperties);
            //    IterateStruct(file.custom.face, StructReference.ChaFileFaceProperties);
            //}

            ExtendedSave.SetExtendedDataById(file, UniversalAutoResolver.UARExtID, new PluginData
            {
                data = new Dictionary <string, object>
                {
                    { "info", resolutionInfo.Select(x => x.Serialize()).ToList() }
                }
            });
        }
Ejemplo n.º 20
0
            private static void ExtendedWorldSave(WorldData worldData)
            {
                if (worldData == null)
                {
                    return;                    // just in case
                }
                // ugh... I don't think this is good idea
                // also this code can't resolve world-level resolve.. if there will be any..
                Dictionary <string, object> ExtendedData = new Dictionary <string, object>();

                foreach (var craftInfoPairs in worldData.HousingData.CraftInfos)
                {
                    ExtendedHousingSave(craftInfoPairs.Value);
                    var data = ExtendedSave.GetExtendedDataById(craftInfoPairs.Value, UARExtID).data;
                    ExtendedData.Add(craftInfoPairs.Key.ToString(), data);
                }

                ExtendedSave.SetExtendedDataById(worldData, UARExtID, new PluginData()
                {
                    data = ExtendedData
                });
            }
Ejemplo n.º 21
0
        private static void ExtendedCardSave(ChaFile file)
        {
            List <ResolveInfo> resolutionInfo = new List <ResolveInfo>();

            void IterateStruct(Dictionary <CategoryProperty, StructValue <int> > dict, object obj, IEnumerable <ResolveInfo> extInfo, string propertyPrefix = "")
            {
                foreach (var kv in dict)
                {
                    int slot = kv.Value.GetMethod(obj);

                    var info = UniversalAutoResolver.LoadedResolutionInfo.FirstOrDefault(x => x.Property == kv.Key.ToString() &&
                                                                                         x.LocalSlot == slot);

                    if (info == null)
                    {
                        continue;
                    }


                    var newInfo = info.DeepCopy();
                    newInfo.Property = $"{propertyPrefix}{newInfo.Property}";

                    kv.Value.SetMethod(obj, newInfo.Slot);

                    resolutionInfo.Add(newInfo);
                }
            }

            IterateCardPrefixes(IterateStruct, file, null);

            ExtendedSave.SetExtendedDataById(file, UniversalAutoResolver.UARExtID, new PluginData
            {
                data = new Dictionary <string, object>
                {
                    ["info"] = resolutionInfo.Select(x => x.Serialize()).ToList()
                }
            });
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Register the futa checkbox with MakerAPI
        /// </summary>
        private void AddCategory(object sender, RegisterSubCategoriesEvent args)
        {
            if (Singleton <CustomBase> .Instance.modeSex == 0)
            {
                return;
            }

            FutaToggle = args.AddControl(new MakerToggle(MakerConstants.Body.All, "ふたなり", this));
            void ToggleFuta(bool IsFuta)
            {
                Singleton <CustomBase> .Instance.chaCtrl.chaFile.status.visibleSonAlways = IsFuta;
                PluginData ExtendedData = new PluginData();

                ExtendedData.data = new Dictionary <string, object> {
                    { "Futa", IsFuta }
                };
                ExtendedSave.SetExtendedDataById(Singleton <CustomBase> .Instance.chaCtrl.chaFile, "KK_FutaMod", ExtendedData);
            }

            var obs = Observer.Create <bool>(ToggleFuta);

            FutaToggle.ValueChanged.Subscribe(obs);
            FutaToggle.Value = Singleton <CustomBase> .Instance.chaCtrl.chaFile.status.visibleSonAlways;
        }
Ejemplo n.º 23
0
        public static void KKABMXCoordToChara(ChaFileCoordinate coord, ChaFileControl chara)
        {
            Dictionary <string, BoneModifierData> coordData = coord.KKABMXData().BoneModifierData();
            List <BoneModifier> charaData = chara.KKABMXData().BoneModifiers();

            foreach (KeyValuePair <string, BoneModifierData> pair in coordData)
            {
                BoneModifier modifier = charaData.FirstOrDefault(v => v.BoneName == pair.Key);

                if (modifier == null)
                {
                    charaData.Add(modifier = new BoneModifier(pair.Key));
                }

                modifier.MakeCoordinateSpecific();

                for (int i = 0; i < modifier.CoordinateModifiers.Length; i++)
                {
                    modifier.CoordinateModifiers[i] = pair.Value;
                }
            }

            ExtendedSave.SetExtendedDataById(chara, KKABMX_Core.ExtDataGUID, charaData.KKABMXData());
        }
Ejemplo n.º 24
0
            private static void CopyCoordExtData(ChaFileCoordinate fromCoord, ChaFileCoordinate toCoord)
            {
                // Clear old ext data
                var oldData = ExtendedSave.GetAllExtendedData(toCoord);

                if (oldData != null)
                {
                    foreach (var data in oldData.ToList())
                    {
                        ExtendedSave.SetExtendedDataById(toCoord, data.Key, null);
                    }
                }

                // Copy new ext data from the coordinate that is about to be swapped in
                var newData = ExtendedSave.GetAllExtendedData(fromCoord);

                if (newData != null)
                {
                    foreach (var data in newData.ToList())
                    {
                        ExtendedSave.SetExtendedDataById(toCoord, data.Key, data.Value);
                    }
                }
            }
 /// <summary>
 /// Set extended data for this coordinate card
 /// </summary>
 /// <param name="dataId">Key to save the data under (usually plugin GUID)</param>
 /// <param name="data">Data to set</param>
 public void SetCoordinateExtData(string dataId, PluginData data) => ExtendedSave.SetExtendedDataById(LoadedCoordinate, dataId, data);
Ejemplo n.º 26
0
            internal static void ExtendedCardSave(ChaFile file)
            {
                if (DoingImport)
                {
                    return;
                }

                List <ResolveInfo> resolutionInfo = new List <ResolveInfo>();

                void IterateStruct(Dictionary <CategoryProperty, StructValue <int> > dict, object obj, IEnumerable <ResolveInfo> extInfo, string propertyPrefix = "")
                {
                    foreach (var kv in dict)
                    {
                        int slot = kv.Value.GetMethod(obj);

                        //No need to attempt a resolution info lookup for empty accessory slots and pattern slots
                        if (slot == 0)
                        {
                            continue;
                        }

                        //Check if it's a vanilla item
                        if (slot < BaseSlotID)
#if KK || EC
                        { if (Lists.InternalDataList[kv.Key.Category].ContainsKey(slot))
#elif AI
                        { if (Lists.InternalDataList[(int)kv.Key.Category].ContainsKey(slot))
#endif
                          { continue; } }

                        //For accessories, make sure we're checking the appropriate category
                        if (kv.Key.Category.ToString().Contains("ao_"))
                        {
                            ChaFileAccessory.PartsInfo AccessoryInfo = (ChaFileAccessory.PartsInfo)obj;

                            if ((int)kv.Key.Category != AccessoryInfo.type)
                            {
                                //If the current category does not match the accessory's category do not attempt a resolution info lookup
                                continue;
                            }
                        }

                        var info = TryGetResolutionInfo(kv.Key.ToString(), slot);

                        if (info == null)
                        {
                            continue;
                        }

                        var newInfo = info.DeepCopy();
                        newInfo.Property = $"{propertyPrefix}{newInfo.Property}";

                        kv.Value.SetMethod(obj, newInfo.Slot);

                        resolutionInfo.Add(newInfo);
                    }
                }

                IterateCardPrefixes(IterateStruct, file, null);

                ExtendedSave.SetExtendedDataById(file, UARExtID, new PluginData
                {
                    data = new Dictionary <string, object>
                    {
                        ["info"] = resolutionInfo.Select(x => x.Serialize()).ToList()
                    }
                });
            }
Ejemplo n.º 27
0
        /// <summary>
        /// Sets the visibility state of a character. If no optional parameters are set the character's visiblity state will be read from the character file and set from that.
        /// </summary>
        /// <param name="chaControl">Character for which to set visible state.</param>
        /// <param name="toggleVisible">Toggles the character from visible to invisible and vice versa. Not used if forceVisible is set.</param>
        /// <param name="forceVisible">Forces the character to the state set in forceVisibleState. Overrides default visibility state and toggleVisible.</param>
        /// <param name="forceVisibleState">The visibility state to set a character. Only used if forceVisible is set.</param>
        /// <param name="saveVisibleState">Whether or not the visible state should be saved to the card.</param>
        private static void SetVisibleState(ChaControl chaControl, bool toggleVisible = false, bool forceVisible = false, bool forceVisibleState = false, bool saveVisibleState = true)
        {
            bool       Visible;
            PluginData ExtendedData    = ExtendedSave.GetExtendedDataById(chaControl.chaFile, "KK_InvisibleBody");
            GameObject CharacterObject = GameObject.Find(chaControl.name);

            if (ExtendedData == null)
            {
                Logger.Log(LogLevel.Debug, "No KK_InvisibleBody marker found");
                Visible = true;
                //character has no extended data, create some so it will save and load with the scene
                ExtendedData = new PluginData();
                Dictionary <string, object> dic = new Dictionary <string, object> {
                    { "Visible", Visible }
                };
                ExtendedData.data = dic;
            }
            else
            {
                Logger.Log(LogLevel.Debug, $"KK_InvisibleBody marker found, Visible was {ExtendedData.data["Visible"]}");
                Visible = (bool)ExtendedData.data["Visible"];
            }

            if (forceVisible)
            {
                Visible = forceVisibleState;
            }
            else if (toggleVisible)
            {
                Visible = !Visible;
            }

            if (saveVisibleState)
            {
                ExtendedData.data["Visible"] = Visible;
                ExtendedSave.SetExtendedDataById(chaControl.chaFile, "KK_InvisibleBody", ExtendedData);
            }

            //No need to IterateVisible for visible characters that haven't changed
            if (!(Visible == true && toggleVisible == false && forceVisible == false))
            {
                Transform cf_j_root = CharacterObject.transform.Find("BodyTop/p_cf_body_bone/cf_j_root");
                if (cf_j_root != null)
                {
                    IterateVisible(cf_j_root.gameObject, Visible);
                }

                //female
                Transform cf_o_rootf = CharacterObject.transform.Find("BodyTop/p_cf_body_00/cf_o_root/");
                if (cf_o_rootf != null)
                {
                    IterateVisible(cf_o_rootf.gameObject, Visible);
                }

                //male
                Transform cf_o_rootm = CharacterObject.transform.Find("BodyTop/p_cm_body_00/cf_o_root/");
                if (cf_o_rootm != null)
                {
                    IterateVisible(cf_o_rootm.gameObject, Visible);
                }
            }
        }
Ejemplo n.º 28
0
        private static void ExtendedCoordinateSave(ChaFileCoordinate file)
        {
            List <ResolveInfo> resolutionInfo = new List <ResolveInfo>();

            void IterateStruct(Dictionary <CategoryProperty, StructValue <int> > dict, object obj, IEnumerable <ResolveInfo> extInfo, string propertyPrefix = "")
            {
                foreach (var kv in dict)
                {
                    int slot = kv.Value.GetMethod(obj);

                    //No need to attempt a resolution info lookup for empty accessory slots and pattern slots
                    if (slot == 0)
                    {
                        continue;
                    }

                    //Check if it's a vanilla item
                    if (slot < 100000000)
                    {
                        if (ResourceRedirector.ListLoader.InternalDataList[kv.Key.Category].ContainsKey(slot))
                        {
                            continue;
                        }
                    }

                    //For accessories, make sure we're checking the appropriate category
                    if (kv.Key.Category.ToString().Contains("ao_"))
                    {
                        ChaFileAccessory.PartsInfo AccessoryInfo = (ChaFileAccessory.PartsInfo)obj;

                        if ((int)kv.Key.Category != AccessoryInfo.type)
                        {
                            //If the current category does not match the accessory's category do not attempt a resolution info lookup
                            continue;
                        }
                    }

                    var info = UniversalAutoResolver.LoadedResolutionInfo.FirstOrDefault(x => x.Property == kv.Key.ToString() &&
                                                                                         x.LocalSlot == slot);

                    if (info == null)
                    {
                        continue;
                    }

                    var newInfo = info.DeepCopy();
                    newInfo.Property = $"{propertyPrefix}{newInfo.Property}";

                    kv.Value.SetMethod(obj, newInfo.Slot);

                    resolutionInfo.Add(newInfo);
                }
            }

            IterateCoordinatePrefixes(IterateStruct, file, null);

            ExtendedSave.SetExtendedDataById(file, UniversalAutoResolver.UARExtID, new PluginData
            {
                data = new Dictionary <string, object>
                {
                    ["info"] = resolutionInfo.Select(x => x.Serialize()).ToList()
                }
            });
        }
Ejemplo n.º 29
0
        /// <summary>
        /// 載入擴充資料
        /// </summary>
        /// <param name="ocichar">要被替換的對象</param>
        /// <param name="file">新角色存檔路徑</param>
        /// <param name="sex">性別</param>
        /// <returns></returns>
        private static bool LoadExtendedData(OCIChar ocichar, string file, byte sex)
        {
            ChaFileControl tmpChaFile = new ChaFileControl();

            tmpChaFile.LoadCharaFile(file, sex);

            foreach (string ext in KK_StudioCharaOnlyLoadBody.ExtendedDataToCopy)
            {
                switch (ext)
                {
                case "KKABMPlugin.ABMData":
                    #region ABMX
                    //取得BoneController
                    MonoBehaviour BoneController = ocichar.charInfo.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Namespace, "KKABMX.Core"));
                    if (null == BoneController)
                    {
                        Logger.LogDebug("No ABMX BoneController found");
                        break;
                    }

                    //建立重用function
                    void GetModifiers(Action <object> action)
                    {
                        foreach (string boneName in (IEnumerable <string>)BoneController.Invoke("GetAllPossibleBoneNames"))
                        {
                            object modifier = BoneController.Invoke("GetModifier", new object[] { boneName });
                            if (null != modifier)
                            {
                                action(modifier);
                            }
                        }
                    }

                    //取得舊角色衣服ABMX數據
                    List <object> previousModifier = new List <object>();
                    GetModifiers(x => {
                        if ((bool)x.Invoke("IsCoordinateSpecific"))
                        {
                            previousModifier.Add(x);
                        }
                    });

                    //將擴充資料由暫存複製到角色身上
                    ExtendedSave.SetExtendedDataById(ocichar.charInfo.chaFile, ext, ExtendedSave.GetExtendedDataById(tmpChaFile, ext));

                    //把擴充資料載入ABMX插件
                    BoneController.Invoke("OnReload", new object[] { 2, false });

                    //清理新角色數據,將衣服數據刪除
                    List <object> newModifiers = new List <object>();
                    int           i            = 0;
                    GetModifiers(x => {
                        if ((bool)x.Invoke("IsCoordinateSpecific"))
                        {
                            Logger.LogDebug("Clean new coordinate ABMX BoneData: " + (string)x.GetProperty("BoneName"));
                            x.Invoke("MakeNonCoordinateSpecific");
                            object y = x.Invoke("GetModifier", new object[] { (ChaFileDefine.CoordinateType) 0 });
                            y.Invoke("Clear");
                            x.Invoke("MakeCoordinateSpecific");        //保險起見以免後面沒有成功清除
                            i++;
                        }
                        else
                        {
                            newModifiers.Add(x);
                        }
                    });

                    //將舊的衣服數據合併回到角色身上
                    i = 0;
                    foreach (object modifier in previousModifier)
                    {
                        string bonename = (string)modifier.GetProperty("BoneName");
                        if (!newModifiers.Any(x => string.Equals(bonename, (string)x.GetProperty("BoneName"))))
                        {
                            BoneController.Invoke("AddModifier", new object[] { modifier });
                            Logger.LogDebug("Rollback cooridnate ABMX BoneData: " + bonename);
                        }
                        else
                        {
                            Logger.LogError("Duplicate coordinate ABMX BoneData: " + bonename);
                        }
                        i++;
                    }
                    Logger.LogDebug($"Merge {i} previous ABMX Bone Modifiers");

                    //重整
                    BoneController.SetProperty("NeedsFullRefresh", true);
                    BoneController.SetProperty("NeedsBaselineUpdate", true);
                    BoneController.Invoke("LateUpdate");

                    //把ABMX的數據存進擴充資料
                    BoneController.Invoke("OnCardBeingSaved", new object[] { 1 });
                    BoneController.Invoke("OnReload", new object[] { 2, false });

                    ////列出角色身上所有ABMX數據
                    //Logger.LogDebug("--List all exist ABMX BoneData--");
                    //foreach (string boneName in (IEnumerable<string>)BoneController.Invoke("GetAllPossibleBoneNames", null)) {
                    //    object modifier = BoneController.Invoke("GetModifier", new object[] { boneName });
                    //    if (null != modifier) {
                    //        Logger.LogDebug(boneName);
                    //    }
                    //}
                    //Logger.LogDebug("--List End--");
                    break;

                    #endregion
                case "com.bepis.sideloader.universalautoresolver":
                    #region SideloaderUAS
                    //判斷CategoryNo分類function
                    bool isBelongsToCharaBody(ChaListDefine.CategoryNo categoryNo)
                    {
                        Type StructReference = typeof(UniversalAutoResolver).Assembly.GetType("Sideloader.AutoResolver.StructReference");

                        return(StructReference.GetProperty("ChaFileFaceProperties", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).GetValue(StructReference, null).ToDictionary <object, object>().Keys.Any(x => (ChaListDefine.CategoryNo)x.GetField("Category") == categoryNo) ||
                               StructReference.GetProperty("ChaFileBodyProperties", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).GetValue(StructReference, null).ToDictionary <object, object>().Keys.Any(x => (ChaListDefine.CategoryNo)x.GetField("Category") == categoryNo) ||
                               StructReference.GetProperty("ChaFileHairProperties", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).GetValue(StructReference, null).ToDictionary <object, object>().Keys.Any(x => (ChaListDefine.CategoryNo)x.GetField("Category") == categoryNo) ||
                               StructReference.GetProperty("ChaFileMakeupProperties", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).GetValue(StructReference, null).ToDictionary <object, object>().Keys.Any(x => (ChaListDefine.CategoryNo)x.GetField("Category") == categoryNo));
                    }

                    //extInfo整理
                    int cleanExtData(ref PluginData tmpExtData, bool keepBodyData)
                    {
                        tmpExtData = ExtendedSave.GetExtendedDataById(ocichar.charInfo.chaFile, ext);
                        if (tmpExtData != null && tmpExtData.data.ContainsKey("info"))
                        {
                            if (tmpExtData.data.TryGetValue("info", out object tmpExtInfo))
                            {
                                if (null != tmpExtInfo as object[])
                                {
                                    List <object> tmpExtList = new List <object>(tmpExtInfo as object[]);
                                    Logger.LogDebug($"Sideloader count: {tmpExtList.Count}");
                                    ResolveInfo tmpResolveInfo;
                                    for (int j = 0; j < tmpExtList.Count;)
                                    {
                                        tmpResolveInfo = (ResolveInfo)Extension.Extension.InvokeStatic(typeof(ResolveInfo), "Deserialize", new object[] { (byte[])tmpExtList[j] });

                                        if (keepBodyData == isBelongsToCharaBody(tmpResolveInfo.CategoryNo))
                                        {
                                            Logger.LogDebug($"Add Sideloader info: {tmpResolveInfo.GUID} : {tmpResolveInfo.Property} : {tmpResolveInfo.Slot}");
                                            j++;
                                        }
                                        else
                                        {
                                            Logger.LogDebug($"Remove Sideloader info: {tmpResolveInfo.GUID} : {tmpResolveInfo.Property} : {tmpResolveInfo.Slot}");
                                            tmpExtList.RemoveAt(j);
                                        }
                                    }
                                    tmpExtData.data["info"] = tmpExtList.ToArray();
                                    return(tmpExtList.Count);
                                }
                            }
                        }
                        return(0);
                    }

                    //提出角色身上原始的Sideloader extData
                    PluginData oldExtData = ExtendedSave.GetExtendedDataById(ocichar.charInfo.chaFile, ext);
                    Logger.LogDebug($"Get Old Sideloader Start");
                    int L1 = cleanExtData(ref oldExtData, false);
                    Logger.LogDebug($"Get Old Sideloader: {L1}");

                    //將擴充資料由暫存複製到角色身上
                    ExtendedSave.SetExtendedDataById(ocichar.charInfo.chaFile, ext, ExtendedSave.GetExtendedDataById(tmpChaFile, ext));

                    //清理新角色數據
                    PluginData newExtData = ExtendedSave.GetExtendedDataById(ocichar.charInfo.chaFile, ext);
                    Logger.LogDebug($"Get New Sideloader Start");
                    int L2 = cleanExtData(ref newExtData, true);
                    Logger.LogDebug($"Get New Sideloader: {L2}");

                    //合併新舊數據
                    object[] tmpObj = new object[L1 + L2];
                    (oldExtData?.data?["info"] as object[])?.CopyTo(tmpObj, 0);
                    (newExtData?.data?["info"] as object[])?.CopyTo(tmpObj, L1);
                    PluginData extData = null;
                    if (tmpObj.Length != 0)
                    {
                        extData = new PluginData {
                            data = new Dictionary <string, object> {
                                ["info"] = tmpObj
                            }
                        };
                    }

                    //儲存
                    ExtendedSave.SetExtendedDataById(ocichar.charInfo.chaFile, ext, extData);
                    Logger.LogDebug($"Merge and Save Sideloader: {tmpObj.Length}");

                    //調用原始sideloader載入hook function
                    Extension.Extension.InvokeStatic(typeof(UniversalAutoResolver).GetNestedType("Hooks", BindingFlags.NonPublic), "ExtendedCardLoad", new object[] { ocichar.charInfo.chaFile });
                    break;

                    #endregion
                default:
                    ExtendedSave.SetExtendedDataById(ocichar.charInfo.chaFile, ext, ExtendedSave.GetExtendedDataById(tmpChaFile, ext));
                    break;
                }
                Logger.LogDebug($"Change Extended Data: {ext}");
            }

            return(true);
        }