/// <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)); } }
private static void ExtendedSceneSave(string path) { try { Dictionary <string, object> ExtendedData = new Dictionary <string, object>(); List <AnimationControllerInfo> AnimationControllerInfoList = new List <AnimationControllerInfo>(); foreach (var IKObj in IKObjectInfoList) { AnimationControllerInfoList.Add(new AnimationControllerInfo { CharDicKey = IKObj.CharacterKey, ItemDicKey = IKObj.ObjectKey, IKPart = IKObj.IKPart }); } if (AnimationControllerInfoList.Count == 0) { ExtendedSave.SetSceneExtendedDataById(PluginName, null); } else { ExtendedData.Add("AnimationInfo", AnimationControllerInfoList.Select(x => x.Serialize()).ToList()); ExtendedSave.SetSceneExtendedDataById(PluginName, new PluginData { data = ExtendedData }); } Logger.Log(LogLevel.Debug, "Saved KK_AnimationController animations"); } catch (Exception ex) { Logger.Log(LogLevel.Error | LogLevel.Message, "Could not save KK_AnimationController animations."); Logger.Log(LogLevel.Error, ex.ToString()); } }
/// <summary> /// Scene has to be fully loaded for all characters and objects to exist in the game /// </summary> private void SceneLoaded(Scene s, LoadSceneMode lsm) { if (s.name == "StudioNotification" && LoadClicked) { LoadClicked = false; try { IKObjectInfoList.Clear(); PluginData ExtendedData = ExtendedSave.GetSceneExtendedDataById(PluginName); if (ExtendedData != null && ExtendedData.data.ContainsKey("AnimationInfo")) { List <AnimationControllerInfo> AnimationControllerInfoList; AnimationControllerInfoList = ((object[])ExtendedData.data["AnimationInfo"]).Select(x => AnimationControllerInfo.Unserialize((byte[])x)).ToList(); foreach (var AnimInfo in AnimationControllerInfoList) { IKObjectInfo LoadedAnimInfo = new IKObjectInfo(); var Character = Singleton <Studio.Studio> .Instance.dicObjectCtrl.Where(x => x.Key == AnimInfo.CharDicKey).Select(x => x.Value as OCIChar).First(); LoadedAnimInfo.CharacterKey = AnimInfo.CharDicKey; LoadedAnimInfo.CharacterObject = GameObject.Find(Character.charInfo.name); LoadedAnimInfo.IKPart = AnimInfo.IKPart; LoadedAnimInfo.IKTarget = Character.listIKTarget.Where(x => x.boneObject.name == AnimInfo.IKPart).First(); var LinkedItem = Singleton <Studio.Studio> .Instance.dicObjectCtrl.Where(x => x.Key == AnimInfo.ItemDicKey).Select(x => x.Value).First(); switch (LinkedItem) { case OCIItem Item: LoadedAnimInfo.ObjectKey = Item.objectInfo.dicKey; LoadedAnimInfo.SelectedObject = Item.childRoot.gameObject; break; case OCIFolder Folder: LoadedAnimInfo.ObjectKey = Folder.objectInfo.dicKey; LoadedAnimInfo.SelectedObject = Folder.childRoot.gameObject; break; case OCIRoute Route: LoadedAnimInfo.ObjectKey = Route.objectInfo.dicKey; LoadedAnimInfo.SelectedObject = Route.childRoot.gameObject; break; } IKObjectInfoList.Add(LoadedAnimInfo); } } Logger.Log(LogLevel.Debug, "Loaded KK_AnimationController animations"); } catch (Exception ex) { Logger.Log(LogLevel.Error | LogLevel.Message, "Could not load KK_AnimationController animations."); Logger.Log(LogLevel.Error, ex.ToString()); } } }
/// <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 }
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(); }
// Token: 0x06000006 RID: 6 RVA: 0x000020F8 File Offset: 0x000002F8 private static void ExtendedSceneLoadInUpdate() { try { Logger.Log(LogLevel.Info, "Start loading VMDPlay info from scene data."); object obj; if (ExtendedSave.GetSceneExtendedDataById("KKVMDPlayExtSave").data.TryGetValue("xml", out obj)) { if (obj != null && obj is byte[]) { Logger.Log(LogLevel.Info, string.Format("Found VMDPlay info XML data: {0}", ((byte[])obj).Length)); MemoryStream inStream = new MemoryStream((byte[])obj); Console.WriteLine("ExtSave: Loading from PNG."); XmlDocument xmlDocument = new XmlDocument(); xmlDocument.Load(inStream); Console.WriteLine(xmlDocument.ToString()); KKVMDPlayExtSavePlugin.OnLoad(xmlDocument.DocumentElement); } else { Logger.Log(LogLevel.Message, "Data not found."); } } else { Logger.Log(LogLevel.Message, "Data not found."); } } catch (Exception ex) { Logger.Log(LogLevel.Error, string.Format("Failed to load data. {0}", ex.StackTrace)); } }
internal static void ExtendedHousingLoad(CraftInfo info) { if (info == null) { return; // TODO: check if this case needs debug logging message. } if (Sideloader.DebugLoggingResolveInfo.Value) { Sideloader.Logger.LogInfo($"Resolving Extended Save Game"); } PluginData ExtendedData = ExtendedSave.GetExtendedDataById(info, UARExtID); if (ExtendedData != null) { var ResolvedInfo = ((Dictionary <int, byte[]>)ExtendedData.data[mapItemInfoKey]); int index = 0; HousingObjectIteration(info.ObjectInfos, ref index, (item, i) => { if (!ResolvedInfo.TryGetValue(i, out byte[] bytes)) { return; } var extResolve = AIGameResolveInfo.Deserialize(bytes); if (extResolve == null) { return; } item.ID = extResolve.Slot; ResolveHousingFurniture(extResolve, item); });
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); } } }
private static void ExtendedSceneLoad(string path) { PluginData ExtendedData = ExtendedSave.GetSceneExtendedDataById(UniversalAutoResolver.UARExtID); UniversalAutoResolver.ResolveStudioObjects(ExtendedData, UniversalAutoResolver.ResolveType.Load); UniversalAutoResolver.ResolveStudioMap(ExtendedData, UniversalAutoResolver.ResolveType.Load); }
private static void ExtendedCardLoad(ChaFile file) { Logger.Log(LogLevel.Debug, $"Loading card [{file.charaFileName}]"); 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}"); } } IterateCardPrefixes(UniversalAutoResolver.ResolveStructure, file, extInfo); }
private void ExtendedSave_PoseBeingSaved(string poseName, PauseCtrl.FileInfo fileInfo, OCIChar ociChar, ExtendedSave.GameNames gameName) { var data = new PluginData(); //Facial expression #if PH data.data.Add(EyesPatternData, ociChar.charStatus.eyesPtn); data.data.Add(MouthPatternData, ociChar.charStatus.mouthPtn); data.data.Add(EyeOpenData, ociChar.charStatus.eyesOpenMax); data.data.Add(MouthOpenData, ociChar.oiCharInfo.mouthOpen); #else data.data.Add(EyebrowPatternData, ociChar.charFileStatus.eyebrowPtn); data.data.Add(EyesPatternData, ociChar.charFileStatus.eyesPtn); data.data.Add(MouthPatternData, ociChar.charFileStatus.mouthPtn); data.data.Add(EyeOpenData, ociChar.charFileStatus.eyesOpenMax); data.data.Add(MouthOpenData, ociChar.oiCharInfo.mouthOpen); #endif //Only save skirt FK if enabled if (ociChar.oiCharInfo.activeFK[SkirtFKIndex]) { Dictionary <int, Vector3> skirtFK = new Dictionary <int, Vector3>(); foreach (KeyValuePair <int, OIBoneInfo> item2 in ociChar.oiCharInfo.bones.Where(b => (OIBoneInfo.BoneGroup.Skirt & b.Value.group) != 0)) { skirtFK.Add(item2.Key, item2.Value.changeAmount.rot); } data.data.Add(SkirtFKData, MessagePackSerializer.Serialize(skirtFK)); } //Joint correction data.data.Add(JointCorrectionData, MessagePackSerializer.Serialize(ociChar.oiCharInfo.expression)); ExtendedSave.SetPoseExtendedDataById(PoseToolsData, data); }
/// <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); } } }
/// <summary> /// Attempt to import old KK_CharaOverlaysBasedOnCoordinate data. /// Based on code from https://github.com/jim60105/KK/blob/99dd9a055679cea8bf2c7d85a357ca53c4233636/KK_CharaOverlaysBasedOnCoordinate/KK_CharaOverlaysBasedOnCoordinate.cs /// </summary> private bool TryImportCOBOC() { #if KK || KKS var data = ExtendedSave.GetExtendedDataById(ChaFileControl, "com.jim60105.kk.charaoverlaysbasedoncoordinate"); if (data == null) { return(false); } KoiSkinOverlayMgr.Logger.LogInfo("[Import] Trying to import KK_CharaOverlaysBasedOnCoordinate data."); Dictionary <TKey, TValue> ToDictionary <TKey, TValue>(object self) { if (!(self is IDictionary dictionary)) { KoiSkinOverlayMgr.Logger.LogWarning($"[Import] Failed to cast to Dictionary! Likely invalid data."); return(null); } return(CastDict(dictionary).ToDictionary(entry => (TKey)entry.Key, entry => (TValue)entry.Value)); IEnumerable <DictionaryEntry> CastDict(IDictionary dic) { foreach (DictionaryEntry entry in dic) { yield return(entry); } } } if ((!data.data.TryGetValue("AllCharaOverlayTable", out var tmpOverlayTable) || tmpOverlayTable == null) || (!data.data.TryGetValue("AllCharaResources", out var tmpResources) || null == tmpResources)) { KoiSkinOverlayMgr.Logger.LogWarning("[Import] Wrong PluginData version, can't import."); }
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); } } }
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 }
internal static void ExtendedCardLoad(ChaFile file) { Sideloader.Logger.LogDebug($"Loading card [{file.charaFileName}]"); 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}"); } } } IterateCardPrefixes(ResolveStructure, file, extInfo); }
/// <summary> /// Method to retrieve a list of BoneModifiers from a selected card in the maker, without loading a character. /// </summary> public static List <BoneModifier> GetBoneModifiersFromCard() { ChaFile file = Utilities.GetSelectedCharacter(); PluginData bonedata = ExtendedSave.GetExtendedDataById(file, "KKABMPlugin.ABMData"); List <BoneModifier> modifiers = new List <BoneModifier>(); if (bonedata != null) { try { switch (bonedata.version) { // Only support for version 2 case 2: modifiers = LZ4MessagePackSerializer.Deserialize <List <BoneModifier> >((byte[])bonedata.data["boneData"]); break; default: throw new NotSupportedException($"Save version {bonedata.version} is not supported"); } } catch (Exception ex) { Logger.Log(LogLevel.Error, "[KK_Archetypes] Failed to load KKABMX extended data - " + ex); } } return(modifiers); }
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(); } }
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); }
/// <summary> /// Save your custom data to the scene under the ID you specified when registering this controller. /// </summary> /// <param name="data">Your custom data to be written to the scene. Can be null to remove the data.</param> public void SetExtendedData(PluginData data) { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } ExtendedSave.SetSceneExtendedDataById(ExtendedDataId, data); }
/// <summary> /// Get extended data based on supplied ExtendedDataId. When in chara maker loads data from character that's being loaded. /// </summary> public PluginData GetExtendedData() { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } return(ExtendedSave.GetExtendedDataById(Manager.Game.Instance.saveData, ExtendedDataId)); }
/// <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); }
/// <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(CustomParameterControl, ExtendedDataId, data); }
/// <summary> /// Get extended data of the last loaded scene by using the ID you specified when registering this controller. /// </summary> public PluginData GetExtendedData() { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } return(ExtendedSave.GetSceneExtendedDataById(ExtendedDataId)); }
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> /// Get extended data of the current character by using the ID you specified when registering this controller. /// This should be used inside the <see cref="OnReload(KKAPI.GameMode,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="getFromLoadedChara">If true, when in chara maker load data from character that's being loaded. /// When outside maker or false, always grab current character's data.</param> public PluginData GetExtendedData(bool getFromLoadedChara) { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } var chaFile = getFromLoadedChara ? MakerAPI.LastLoadedChaFile ?? ChaFileControl : ChaFileControl; return(ExtendedSave.GetExtendedDataById(chaFile, ExtendedDataId)); }
internal static void ExtendedSceneLoad(string path) { PluginData ExtendedData = ExtendedSave.GetSceneExtendedDataById(UARExtID); ResolveStudioObjects(ExtendedData, ResolveType.Load); ResolveStudioMap(ExtendedData, ResolveType.Load); ResolveStudioFilter(ExtendedData, ResolveType.Load); ResolveStudioRamp(ExtendedData, ResolveType.Load); ResolveStudioBGM(ExtendedData, ResolveType.Load); }
/// <summary> /// Get extended data of the current character by using the ID you specified when registering this controller. /// </summary> /// <param name="getFromLoadedChara">If true, when in chara maker load data from character that's being loaded. /// When outside maker or false, always grab current character's data.</param> public PluginData GetExtendedData(bool getFromLoadedChara) { if (ExtendedDataId == null) { throw new ArgumentException(nameof(ExtendedDataId)); } var customParameter = getFromLoadedChara ? MakerAPI.LastLoadedChaFile ?? CustomParameterControl : CustomParameterControl; //todo return(ExtendedSave.GetExtendedDataById(customParameter, ExtendedDataId)); }
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() } } }); }