protected override void OnCoordinateBeingSaved(ChaFileCoordinate coordinate)
        {
            var data = new PluginData();

            data.data.Add(nameof(ClothingUnlocked) + "Coordinate", ClothingUnlocked);
            SetExtendedData(data);
        }
            private static void ChaFileCoordinateLoadHook(ChaFileCoordinate coordinate, BinaryReader br)
            {
                try
                {
                    string marker  = br.ReadString();
                    int    version = br.ReadInt32();

                    int length = br.ReadInt32();

                    if (marker == Marker && version == DataVersion && length > 0)
                    {
                        byte[] bytes      = br.ReadBytes(length);
                        var    dictionary = MessagePackSerializer.Deserialize <Dictionary <string, PluginData> >(bytes);

                        internalCoordinateDictionary.Set(coordinate, dictionary);
                    }
                    else
                    {
                        internalCoordinateDictionary.Set(coordinate, new Dictionary <string, PluginData>()); //Overriding with empty data just in case there is some remnant from former loads.
                    }
                }
                catch (EndOfStreamException)
                {
                    // Incomplete/non-existant data
                    internalCoordinateDictionary.Set(coordinate, new Dictionary <string, PluginData>());
                }
                catch (InvalidOperationException)
                {
                    // Invalid/unexpected deserialized data
                    internalCoordinateDictionary.Set(coordinate, new Dictionary <string, PluginData>());
                }

                //Firing the event in any case
                CoordinateReadEvent(coordinate);
            }
Esempio n. 3
0
        internal void OnCoordinateBeingLoadedInternal(ChaFileCoordinate coordinate)
        {
#if AI || HS2
            // If the controller didn't load yet then delay the coordinate load event until after onreload to avoid losing data from coordinate
            if (!_wasLoaded)
            {
                StartCoroutine(new WaitUntil(() => _wasLoaded).AppendCo(() => OnCoordinateBeingLoadedInternal(coordinate)));
                return;
            }
#endif

            try
            {
                if (!ControllerRegistration.MaintainCoordinateState)
                {
                    OnCoordinateBeingLoaded(coordinate);
                }

                OnCoordinateBeingLoaded(coordinate, ControllerRegistration.MaintainCoordinateState);
            }
            catch (Exception e)
            {
                KoikatuAPI.Logger.LogError(e);
            }
        }
        public void UpdateOnCoordinateLoadApply(ChaFileCoordinate coordinate, List <Tuple <int, int> > movedSlots)
        {
            CharaCustomFunctionController dbController = FindDynamicBoneController();

            if (dbController == null || snapshotData == null)
            {
                return;
            }

#if DEBUG
            AdditionalAccessoryControlsPlugin.Instance.Log.LogInfo($"DB Restore Snapshot {snapshotData}");
#endif

            // Update the material editor data to account for moving slots
            IList currentSaveData = FillDBEditorLists();
            MoveSlots(movedSlots, currentSaveData, snapshotData);
            ApplyDynamicBoneList(currentSaveData);

            // Need to do both of these, first in case material editor hasn't loaded yet, second if they have
            OnCoordinateSave.Invoke(dbController, new object[] { coordinate });
            OnCoordinateLoad.Invoke(dbController, new object[] { coordinate, false });

#if DEBUG
            AdditionalAccessoryControlsPlugin.Instance.Log.LogInfo($"DB After Application {FillDBEditorLists()}");
#endif

            snapshotData = null;
        }
            protected override void OnCoordinateBeingSaved(ChaFileCoordinate coordinate)
            {
                MissingKindCheck(_currentCoordinateIndex);
                MissingPartCheck(_currentCoordinateIndex);
                MissingGroupCheck(_currentCoordinateIndex);
                MissingPropertyCheck(_currentCoordinateIndex);

                RefreshCache();
                DebugMsg(LogLevel.Info, $"[OnCoordinateBeingSaved][{CharaFullName}][PropertyList.Count: {_cachedCoordinatePropertyList?.Count}]");

                if (_cachedCoordinatePropertyList?.Count == 0)
                {
                    SetCoordinateExtendedData(coordinate, null);
                    return;
                }

                List <TriggerProperty> _tempTriggerProperty = _cachedCoordinatePropertyList.JsonClone() as List <TriggerProperty>;
                List <TriggerGroup>    _tempTriggerGroup    = _cachedCoordinateGroupList.JsonClone() as List <TriggerGroup>;

                _tempTriggerProperty.ForEach(x => x.Coordinate = -1);
                _tempTriggerGroup.ForEach(x => x.Coordinate    = -1);
                _tempTriggerGroup.ForEach(x => x.State         = 0);
                PluginData _pluginData = new PluginData()
                {
                    version = _pluginDataVersion
                };

                _pluginData.data.Add("TriggerPropertyList", MessagePackSerializer.Serialize(_tempTriggerProperty));
                _pluginData.data.Add("TriggerGroupList", MessagePackSerializer.Serialize(_tempTriggerGroup));
                SetCoordinateExtendedData(coordinate, _pluginData);
            }
        private static void OnCoordinateBeingLoaded(ChaControl character, ChaFileCoordinate coordinateFile)
        {
#if EC || AI
            KoikatuAPI.Logger.LogDebug($"Loading coord \"{coordinateFile.coordinateName}\" to chara \"{GetLogName(character)}\"");
#elif KK
            KoikatuAPI.Logger.LogDebug($"Loading coord \"{coordinateFile.coordinateName}\" to chara \"{GetLogName(character)}\" / {(ChaFileDefine.CoordinateType)character.fileStatus.coordinateType}");
#endif

            foreach (var controller in GetBehaviours(character))
            {
                controller.OnCoordinateBeingLoadedInternal(coordinateFile);
            }

            var args = new CoordinateEventArgs(character, coordinateFile);
            try
            {
                CoordinateLoaded?.Invoke(null, args);
            }
            catch (Exception e)
            {
                KoikatuAPI.Logger.LogError(e);
            }

            if (MakerAPI.InsideAndLoaded)
            {
                MakerAPI.OnReloadInterface(args);
            }
        }
        public void UpdateOnCoordinateSave(ChaFileCoordinate coordinate, List <int> slotsToRemove)
        {
            CharaCustomFunctionController dbController = FindDynamicBoneController();

            if (dbController == null)
            {
                return;
            }

            snapshotData = null;

            // Store a snapshot for later restoration
            snapshotData = FillDBEditorLists();
            // And our copy for tampering with
            IList saveData = FillDBEditorLists();

#if DEBUG
            AdditionalAccessoryControlsPlugin.Instance.Log.LogInfo($"DB Update Coord Save: Storing Snapshot {snapshotData}");
#endif

            // Remove character accessories from save data
            ClearRemovedSlots(slotsToRemove, saveData);
            ApplyDynamicBoneList(saveData);

#if DEBUG
            AdditionalAccessoryControlsPlugin.Instance.Log.LogInfo($"DB Update Coord Save: After Slot Removal {saveData}");
#endif
            OnCoordinateSave.Invoke(dbController, new object[] { coordinate });
        }
Esempio n. 8
0
        private static void ExtendedCoordinateLoad(ChaFileCoordinate file)
        {
            if (!IsResolving)
            {
                return;
            }

            Logger.Log(LogLevel.Debug, $"Loading coordinate [{file.coordinateName}]");

            var extData = ExtendedSave.GetExtendedDataById(file, UniversalAutoResolver.UARExtID);
            List <ResolveInfo> extInfo;

            if (extData == null || !extData.data.ContainsKey("info"))
            {
                Logger.Log(LogLevel.Debug, "No sideloader marker found");
                extInfo = null;
            }
            else
            {
                var tmpExtInfo = (object[])extData.data["info"];
                extInfo = tmpExtInfo.Select(x => ResolveInfo.Unserialize((byte[])x)).ToList();

                Logger.Log(LogLevel.Debug, "Sideloader marker found");
                Logger.Log(LogLevel.Debug, $"External info count: {extInfo.Count}");
                foreach (ResolveInfo info in extInfo)
                {
                    Logger.Log(LogLevel.Debug, $"External info: {info.GUID} : {info.Property} : {info.Slot}");
                }
            }

            IterateCoordinatePrefixes(UniversalAutoResolver.ResolveStructure, file, extInfo);
        }
Esempio n. 9
0
        public static void ChaFileCoordinateSaveFilePostHook(ChaFileCoordinate __instance, string path)
        {
            Logger.Log(LogLevel.Debug, $"Reloading coordinate [{path}]");

            var extData = ExtendedSave.GetExtendedDataById(__instance, UniversalAutoResolver.UARExtID);

            var tmpExtInfo = (List <byte[]>)extData.data["info"];
            var extInfo    = tmpExtInfo.Select(ResolveInfo.Unserialize);

            Logger.Log(LogLevel.Debug, $"External info count: {extInfo.Count()}");
            foreach (ResolveInfo info in extInfo)
            {
                Logger.Log(LogLevel.Debug, $"External info: {info.GUID} : {info.Property} : {info.Slot}");
            }

            void ResetStructResolveStructure(Dictionary <CategoryProperty, StructValue <int> > propertyDict, object structure, IEnumerable <ResolveInfo> extInfo2, string propertyPrefix = "")
            {
                foreach (var kv in propertyDict)
                {
                    var extResolve = extInfo.FirstOrDefault(x => x.Property == $"{propertyPrefix}{kv.Key.ToString()}");

                    if (extResolve != null)
                    {
                        kv.Value.SetMethod(structure, extResolve.LocalSlot);

                        Logger.Log(LogLevel.Debug, $"[UAR] Resetting {extResolve.GUID}:{extResolve.Property} to internal slot {extResolve.LocalSlot}");
                    }
                }
            }

            IterateCoordinatePrefixes(ResetStructResolveStructure, __instance, extInfo);
        }
        protected override void OnCoordinateBeingLoaded(ChaFileCoordinate coordinate, bool maintainState)
        {
            if (maintainState)
            {
                return;
            }

            var currentOverlayTextures = CurrentOverlayTextures;

            if (currentOverlayTextures == null)
            {
                return;
            }

            currentOverlayTextures.Clear();

            var data = GetCoordinateExtendedData(coordinate);

            if (data != null && data.data.TryGetValue(OverlayDataKey, out var bytes) && bytes is byte[] byteArr)
            {
                var dict = MessagePackSerializer.Deserialize <Dictionary <string, ClothesTexData> >(byteArr);
                if (dict != null)
                {
                    foreach (var texData in dict)
                    {
                        currentOverlayTextures.Add(texData.Key, texData.Value);
                    }
                }
            }

            StartCoroutine(RefreshAllTexturesCo());
        }
Esempio n. 11
0
            internal static void ChaFileCoordinateSaveFilePostHook(ChaFileCoordinate __instance, string path)
            {
                if (DoingImport)
                {
                    return;
                }

                Sideloader.Logger.LogDebug($"Reloading coordinate [{path}]");

                var extData = ExtendedSave.GetExtendedDataById(__instance, UARExtIDOld) ?? ExtendedSave.GetExtendedDataById(__instance, UARExtID);

                var tmpExtInfo = (List <byte[]>)extData.data["info"];
                var extInfo    = tmpExtInfo.Select(ResolveInfo.Deserialize).ToList();

                Sideloader.Logger.LogDebug($"External info count: {extInfo.Count}");

                if (Sideloader.DebugLogging.Value)
                {
                    foreach (ResolveInfo info in extInfo)
                    {
                        Sideloader.Logger.LogDebug($"External info: {info.GUID} : {info.Property} : {info.Slot}");
                    }
                }

                void ResetStructResolveStructure(Dictionary <CategoryProperty, StructValue <int> > propertyDict, object structure, IEnumerable <ResolveInfo> extInfo2, string propertyPrefix = "")
                {
                    foreach (var kv in propertyDict)
                    {
                        var extResolve = extInfo.FirstOrDefault(x => x.Property == $"{propertyPrefix}{kv.Key.ToString()}");

                        if (extResolve != null)
                            kv.Value.SetMethod(structure, extResolve.LocalSlot); }
                    }
                }
Esempio n. 12
0
            internal static void ExtendedCoordinateLoad(ChaFileCoordinate file)
            {
                Sideloader.Logger.LogDebug($"Loading coordinate [{file.coordinateName}]");

                var extData = ExtendedSave.GetExtendedDataById(file, UARExtIDOld) ?? ExtendedSave.GetExtendedDataById(file, UARExtID);
                List <ResolveInfo> extInfo;

                if (extData == null || !extData.data.ContainsKey("info"))
                {
                    Sideloader.Logger.LogDebug("No sideloader marker found");
                    extInfo = null;
                }
                else
                {
                    var tmpExtInfo = (object[])extData.data["info"];
                    extInfo = tmpExtInfo.Select(x => ResolveInfo.Deserialize((byte[])x)).ToList();

                    Sideloader.Logger.LogDebug($"Sideloader marker found, external info count: {extInfo.Count}");

                    if (Sideloader.DebugLogging.Value)
                    {
                        foreach (ResolveInfo info in extInfo)
                        {
                            Sideloader.Logger.LogDebug($"External info: {info.GUID} : {info.Property} : {info.Slot}");
                        }
                    }
                }

                IterateCoordinatePrefixes(ResolveStructure, file, extInfo);
            }
            public static void CharaData_InitializePost(ChaControl __instance, ChaFileCoordinate srcCoorde, bool reload, bool forceChange)
            {
                if (srcCoorde == __instance.chaFile.coordinate)
                {
                    if (reload)
                    {
                        ReloadChara(__instance);
                    }
                    return;
                }

                // Make sure we were called by the correct methods to avoid triggering this when a character is being fully reloaded
                // Need to inspect whole stack trace and grab the earliest methods in the stack to avoid MoreAccessories hooks
                var isCoordinateLoad = new StackTrace().GetFrames()?.Any(f =>
                {
                    var method = f.GetMethod();
                    return(method.Name == "UpdateClothEvent" ||
                           method.Name == "LoadClothesFile" ||
                           method.DeclaringType?.Name == "ADVMainScene" ||
                           method.DeclaringType?.Name == "HSceneSpriteCoordinatesCard");
                });

                if (isCoordinateLoad != false)
                {
                    OnCoordinateBeingLoaded(__instance, __instance.nowCoordinate);
                }
            }
            public static void ChaFileCoordinateSaveHook(ChaFileCoordinate file, BinaryWriter bw)
            {
                CoordinateWriteEvent(file);

                _logger.Log(LogLevel.Debug, "Coordinate hook!");

                var extendedData = GetAllExtendedData(file);

                if (extendedData == null || extendedData.Count == 0)
                {
                    return;
                }

                var originalLength   = bw.BaseStream.Length;
                var originalPosition = bw.BaseStream.Position;

                try
                {
                    var bytes = MessagePackSerialize(extendedData);

                    bw.Write(Marker);
                    bw.Write(Version);
                    bw.Write(bytes.Length);
                    bw.Write(bytes);
                }
                catch (Exception e)
                {
                    _logger.Log(LogLevel.Warning, $"Failed to save extended data in card. {e.Message}");
                    bw.BaseStream.Position = originalPosition;
                    bw.BaseStream.SetLength(originalLength);
                }
            }
Esempio n. 15
0
 protected override void OnCoordinateBeingLoaded(ChaFileCoordinate coordinate, bool maintainState)
 {
     if (ProxyVolumes.TryGetValue(ChaControl, out var proxyVolume))
     {
         StartCoroutine(WaitUntilOtherProcess(proxyVolume));
     }
     base.OnCoordinateBeingLoaded(coordinate, maintainState);
 }
Esempio n. 16
0
            protected override void OnCoordinateBeingSaved(ChaFileCoordinate coordinate)
            {
                var data = new PluginData();

                data.data.Add(PushupConstants.PushupCoordinate_BraData, MessagePackSerializer.Serialize(CurrentBraData));
                data.data.Add(PushupConstants.PushupCoordinate_TopData, MessagePackSerializer.Serialize(CurrentTopData));
                SetCoordinateExtendedData(coordinate, data);
            }
Esempio n. 17
0
            protected override void OnCoordinateBeingSaved(ChaFileCoordinate coordinate)
            {
                OutfitTriggers[CurrentCoordinateIndex] = SortRouteRules(OutfitTriggers[CurrentCoordinateIndex]);
                PluginData ExtendedData = new PluginData();

                ExtendedData.data.Add("OutfitTrigger", MessagePackSerializer.Serialize(OutfitTriggers[CurrentCoordinateIndex]));
                ExtendedData.version = ExtDataVer;
                SetCoordinateExtendedData(coordinate, ExtendedData);
            }
Esempio n. 18
0
        /// <summary>
        /// 將Controller內之ExtData儲存至Coordinate ExtendedData內
        /// </summary>
        /// <param name="chaCtrl">來源ChaControl</param>
        /// <param name="coordinate">目標Coordinate</param>
        public void SetCoordinateDataFromController(ChaControl chaCtrl, ChaFileCoordinate coordinate = null)
        {
            if (null == coordinate)
            {
                coordinate = chaCtrl.nowCoordinate;
            }
            MonoBehaviour controller = GetController(chaCtrl);

            controller.Invoke("OnCoordinateBeingSaved", new object[] { coordinate });
        }
        //The HS2 / AI way to detect clothing change
        protected override void OnCoordinateBeingLoaded(ChaFileCoordinate coordinate)
        {
            if (PregnancyPlusPlugin.DebugLog.Value)
            {
                PregnancyPlusPlugin.Logger.LogInfo($"+= $OnCoordinateBeingLoaded {coordinate.coordinateName}");
            }
            OnCoordinateLoaded();

            base.OnCoordinateBeingLoaded(coordinate);
        }
Esempio n. 20
0
        public static void SetCoordinateExtDataFromController(ChaControl chaCtrl, ChaFileCoordinate coordinate = null)
        {
            if (null == coordinate)
            {
                coordinate = chaCtrl.nowCoordinate;
            }
            MonoBehaviour COBOCController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "CharaOverlaysBasedOnCoordinateController"));

            COBOCController.Invoke("OnCoordinateBeingSaved", new object[] { coordinate });
        }
Esempio n. 21
0
            protected override void OnCoordinateBeingSaved(ChaFileCoordinate coordinate)
            {
                Logger.Log(DebugLogLevel, $"[OnCoordinateBeingSaved][{ChaControl.chaFile.parameter?.fullname}] Fired!!");
                CurOutfitTriggerInfo = CharaTriggerInfo.ElementAtOrDefault(CurrentCoordinateIndex);
                Logger.Log(DebugLogLevel, $"[OnCoordinateBeingSaved] CurOutfitTriggerInfo.Parts count: {CurOutfitTriggerInfo.Parts.Count()}");
                SyncOutfitTriggerInfo(CurrentCoordinateIndex);
                PluginData ExtendedData = new PluginData();

                ExtendedData.data.Add("OutfitTriggerInfo", MessagePackSerializer.Serialize(CurOutfitTriggerInfo));
                SetCoordinateExtendedData(coordinate, ExtendedData);
            }
Esempio n. 22
0
        /// <summary>
        /// 由Coordinate載入ExtData至Controller內
        /// </summary>
        /// <param name="chaCtrl">要被設定的ChaControl</param>
        /// <param name="coordinate">要載入的coordibate</param>
        public void SetControllerFromCoordinate(ChaControl chaCtrl, ChaFileCoordinate coordinate = null)
        {
            if (null == coordinate)
            {
                coordinate = chaCtrl.nowCoordinate;
            }
            MonoBehaviour controller = GetController(chaCtrl);

            controller.Invoke("OnCoordinateBeingLoaded", new object[] { coordinate, false });
            return;
        }
            internal static void ConvertCoordinateFile(ChaFileCoordinate emcoorde, KoikatsuCharaFile.ChaFileCoordinate kkcoorde)
            {
                // Move data from import dictionary to normal dictionary before the imported cards are saved so the imported data is written
                var result = _internalCoordinateImportDictionary.Get(kkcoorde);

                if (result != null)
                {
                    CoordinateImportEvent(result);
                    internalCoordinateDictionary.Set(emcoorde, result);
                }
            }
Esempio n. 24
0
        /// <summary>
        /// Get PluginData for a ChaFileCoordinate for the specified extended save data ID
        /// </summary>
        /// <param name="file">ChaFileCoordinate for which to get extended data</param>
        /// <param name="id">ID of the data saved to the card</param>
        /// <returns>PluginData</returns>
        public static PluginData GetExtendedDataById(ChaFileCoordinate file, string id)
        {
            if (file == null || id == null)
            {
                return(null);
            }

            var dict = internalCoordinateDictionary.Get(file);

            return(dict != null && dict.TryGetValue(id, out var extendedSection) ? extendedSection : null);
        }
Esempio n. 25
0
        public static bool SetControllerFromCoordinate(ChaControl chaCtrl, ChaFileCoordinate coordinate = null)
        {
            if (null == coordinate)
            {
                coordinate = chaCtrl.nowCoordinate;
            }
            MonoBehaviour COBOCController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "CharaOverlaysBasedOnCoordinateController"));

            COBOCController.Invoke("OnCoordinateBeingLoaded", new object[] { coordinate, false });
            return(true);
        }
Esempio n. 26
0
        /// <summary>
        /// Method to add data to KKATData.
        /// </summary>
        /// <param curr>Current file to copy from</param>
        /// <param key>Specific key to add, used for adding keys by character cards</param>
        internal static void AddClothes(ChaFileCoordinate curr, string key = null)
        {
            if (!_toggleClothes.Value)
            {
                return;
            }
            key = key == null?Utilities.CreateNewKey(curr) : key;

            KK_Archetypes.Data.ClothesDict.Add(key, curr.clothes);
            KK_Archetypes.Data.AccessoryDict.Add(key, curr.accessory);
        }
 internal void OnCoordinateBeingSavedInternal(ChaFileCoordinate coordinate)
 {
     try
     {
         OnCoordinateBeingSaved(coordinate);
     }
     catch (Exception e)
     {
         KoikatuAPI.Log(LogLevel.Error, e);
     }
 }
Esempio n. 28
0
        public static void SetExtendedDataById(ChaFileCoordinate file, string id, PluginData extendedFormatData)
        {
            Dictionary <string, PluginData> chaDictionary = internalCoordinateDictionary.Get(file);

            if (chaDictionary == null)
            {
                chaDictionary = new Dictionary <string, PluginData>();
                internalCoordinateDictionary.Set(file, chaDictionary);
            }

            chaDictionary[id] = extendedFormatData;
        }
 /// <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);
 }
 /// <summary>
 /// Get extended data of the specified coordinate by using the ID you specified when registering this controller.
 /// This should be used inside the <see cref="OnCoordinateBeingLoaded(ChaFileCoordinate,bool)"/> 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 get the data from</param>
 public PluginData GetCoordinateExtendedData(ChaFileCoordinate coordinate)
 {
     if (coordinate == null)
     {
         throw new ArgumentNullException(nameof(coordinate));
     }
     if (ExtendedDataId == null)
     {
         throw new ArgumentException(nameof(ExtendedDataId));
     }
     return(ExtendedSave.GetExtendedDataById(coordinate, ExtendedDataId));
 }