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); }
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 }); }
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); }
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()); }
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); } } }
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); } }
protected override void OnCoordinateBeingLoaded(ChaFileCoordinate coordinate, bool maintainState) { if (ProxyVolumes.TryGetValue(ChaControl, out var proxyVolume)) { StartCoroutine(WaitUntilOtherProcess(proxyVolume)); } base.OnCoordinateBeingLoaded(coordinate, maintainState); }
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); }
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); }
/// <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); }
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 }); }
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); }
/// <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); } }
/// <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); }
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); }
/// <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); } }
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)); }