public static void SetControllerFromExtData(ChaControl chaCtrl) { MonoBehaviour COBOCController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "CharaOverlaysBasedOnCoordinateController")); COBOCController.Invoke("OnReload", new object[] { 2, false }); return; }
public static MonoBehaviour GetExtendedDataFromController(ChaControl chaCtrl, out Dictionary <string, object> dict) { MonoBehaviour controller = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "KoiClothesOverlayController")); dict = new Dictionary <string, object>(); if (null == controller) { Logger.LogDebug($"No KCOX Controller found on {chaCtrl.fileParam.fullname}"); } else { int cnt = 0; foreach (string mainName in MainClothesNames) { cnt += GetOverlay(controller, dict, mainName) ? 1 : 0; } foreach (string subName in SubClothesNames) { cnt += GetOverlay(controller, dict, subName) ? 1 : 0; } foreach (string maskKind in MaskKind) { cnt += GetOverlay(controller, dict, maskKind) ? 1 : 0; } Logger.LogDebug("Get Overlay/Mask Total: " + cnt); } return(controller); }
/// <summary> /// 由ExtData載入HairAcc至Controller內,注意這條是異步執行 /// </summary> /// <param name="chaCtrl">要被設定的ChaControl</param> /// <returns></returns> public static void SetControllerFromExtData(ChaControl chaCtrl) { MonoBehaviour HairAccCusController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); //注意這條是異步執行 HairAccCusController.Invoke("OnReload", new object[] { 2, false }); }
/// <summary> /// 載入CopyHairAcc所用的來源和目標 /// </summary> /// <param name="sourceChaCtrl">來源</param> /// <param name="targetChaCtrl">目標</param> public static void GetControllerAndBackupData(ChaControl sourceChaCtrl, ChaControl targetChaCtrl = null) { if (null != sourceChaCtrl) { SetExtDataFromController(sourceChaCtrl); ClearHairAccBackup(); SourceHairAccCusController = sourceChaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); if (null == SourceHairAccCusController) { Logger.LogDebug("No Source Hair Accessory Customizer Controller found"); return; } Logger.LogDebug("Source-----"); GetDataFromExtData(sourceChaCtrl, out sourceHairBackup); } if (null != targetChaCtrl) { SetExtDataFromController(targetChaCtrl); TargetHairAccCusController = targetChaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); if (null == TargetHairAccCusController) { Logger.LogDebug("No Target Hair Accessory Customizer Controller found"); return; } Logger.LogDebug("Target-----"); GetDataFromExtData(targetChaCtrl, out targetHairBackup); } }
/// <summary> /// Get all extra behaviours for specified character. If null, returns extra behaviours for all characters. /// </summary> public static IEnumerable <CharaCustomFunctionController> GetBehaviours(ChaControl character = null) { if (character == null) { return(_registeredHandlers.SelectMany(x => x.Instances)); } return(character.GetComponents <CharaCustomFunctionController>()); }
private static void CreateOrAddBehaviours(ChaControl target) { foreach (var handler in _registeredHandlers) { var existing = target.gameObject.GetComponents(handler.Value.ControllerType) .Cast <CharaCustomFunctionController>() .FirstOrDefault(x => x.ExtendedDataId == handler.Value.ExtendedDataId); if (existing == null) { try { handler.Value.CreateInstance(target); } catch (Exception e) { KoikatuAPI.Logger.LogError(e); } } } #if KK || KKS var controllers = target.GetComponents <CharaCustomFunctionController>(); target.UpdateAsObservable().Subscribe( _ => { var changed = false; var currentCoordinate = (ChaFileDefine.CoordinateType)target.fileStatus.coordinateType; for (var i = 0; i < controllers.Length; i++) { var controllerSubject = controllers[i].CurrentCoordinate; if (i == 0) { changed = currentCoordinate != controllerSubject.Value; if (changed && KoikatuAPI.EnableDebugLogging) { KoikatuAPI.Logger.LogMessage( $"Changed coord of character {target.fileParam.fullname} to {currentCoordinate}"); } } if (changed) { controllerSubject.OnNext(currentCoordinate); } } }); #endif // Trigger the equivalent of "Start" reload from controllers if (!MakerAPI.InsideMaker) { target.StartCoroutine(CoroutineUtils.CreateCoroutine(new WaitForEndOfFrame(), () => { }, () => OnCharacterReloaded(target))); } }
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 }); }
public static bool CheckControllerPrepared(ChaControl chaCtrl) { if (!KK_StudioCoordinateLoadOption._isKCOXExist) { return(true); } MonoBehaviour controller = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "KoiClothesOverlayController")); return(null != controller && (bool)controller?.GetProperty("Started") && null != controller.GetProperty("CurrentOverlayTextures")); }
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); }
public static bool CheckControllerPrepared(ChaControl chaCtrl) { if (!KK_StudioCoordinateLoadOption._isMaterialEditorExist) { return(true); } MonoBehaviour controller = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "MaterialEditorCharaController")); return(null != controller && !(bool)controller?.GetProperty("CharacterLoading")); }
/// <summary> /// 由ChaControl Controller取得TextureDictionary,注意這個無法寫回 /// </summary> /// <param name="chaCtrl">對象ChaControl</param> /// <returns></returns> public static Dictionary <int, object> GetTextureDictionaryFromController(ChaControl chaCtrl) { MonoBehaviour MaterialEditorController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "MaterialEditorCharaController")); if (null == MaterialEditorController) { Logger.LogDebug("No MaterialEditor Controller found"); return(null); } Dictionary <int, object> TextureDictionary = MaterialEditorController.GetField("TextureDictionary").ToDictionary <int, object>(); //if (TextureDictionary is Dictionary<int, object> tdb) { // Logger.LogDebug("TextureDictionaryBackup Count: " + tdb.Count); //} return(TextureDictionary); }
public static MonoBehaviour GetExtendedDataFromController(ChaControl chaCtrl, out Dictionary <string, object> dict) { dict = new Dictionary <string, object>(); MonoBehaviour controller = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Namespace, "KKABMX.Core")); if (null == controller) { Logger.LogDebug("No ABMX BoneController found"); return(null); } //Logger.LogDebug("BoneController Get"); List <object> Modifiers = new List <object>(); foreach (string boneName in (IEnumerable <string>)controller.Invoke("GetAllPossibleBoneNames")) { object tmpModifier = controller.Invoke("GetModifier", new object[] { boneName }); if (null != tmpModifier) { Modifiers.Add(tmpModifier); } } dict = Modifiers .Where(x => (bool)x.Invoke("IsCoordinateSpecific")) .Where(x => !(bool)x.Invoke("IsEmpty")) .ToDictionary( x => (string)x.GetProperty("BoneName"), //x.BoneName, x => { Logger.LogDebug("Get original ABMX BoneData: " + (string)x.GetProperty("BoneName")); object y = x.Invoke("GetModifier", new object[] { (ChaFileDefine.CoordinateType)chaCtrl.fileStatus.coordinateType }); return(y.Invoke("Clone")); } ); if (dict == null || dict.Count == 0) { Logger.LogDebug("No original ABMX BoneData."); } else { Logger.LogDebug("Get original ABMX BoneData: " + dict.Count); } return(controller); }
/// <summary> /// 從HairAccessoryController取得給定ChaControl的HairAccessories和單一hairAccessoryInfo /// </summary> /// <param name="chaCtrl">要查詢的ChaControl</param> /// <param name="nowcoordinateExtData">nowCoordinate的hairAccessoryInfo</param> /// <returns>整個HairAccessories</returns> public static Dictionary <int, Dictionary <int, object> > GetDataFromController(ChaControl chaCtrl, out Dictionary <int, object> nowcoordinateExtData) { nowcoordinateExtData = null; MonoBehaviour HairAccCusController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); Dictionary <int, object> HairAccessories = HairAccCusController?.GetField("HairAccessories").ToDictionary <int, object>(); Dictionary <int, Dictionary <int, object> > result = null; if (null != HairAccessories && HairAccessories.Count != 0) { result = new Dictionary <int, Dictionary <int, object> >(); foreach (KeyValuePair <int, object> kv in HairAccessories) { if (null != kv.Value) { result[kv.Key] = new Dictionary <int, object>(); foreach (KeyValuePair <int, object> kv2 in kv.Value.ToDictionary <int, object>()) { result[kv.Key][kv2.Key] = new Dictionary <object, object> { { "HairGloss", kv2.Value.GetField("HairGloss") }, { "ColorMatch", kv2.Value.GetField("ColorMatch") }, { "OutlineColor", kv2.Value.GetField("OutlineColor") }, { "AccessoryColor", kv2.Value.GetField("AccessoryColor") }, { "HairLength", kv2.Value.GetField("HairLength") } }; } } } result.TryGetValue(chaCtrl.fileStatus.coordinateType, out nowcoordinateExtData); if (null != nowcoordinateExtData) { Logger.LogDebug($"Get {chaCtrl.fileParam.fullname} Hair Accessories From Controller: {nowcoordinateExtData.Count}"); Logger.LogDebug($"->{string.Join(",", nowcoordinateExtData.Select(x => x.Key.ToString()).ToArray())}"); } else { Logger.LogDebug($"Get {chaCtrl.fileParam.fullname} Hair Accessories From Controller, but no HairAccInfo on current coordinate"); } return(result); } Logger.LogDebug($"No Hair Accessories get from {chaCtrl.fileParam.fullname}'s Controller"); nowcoordinateExtData = null; return(null); }
/// <summary> /// 由Coordinate載入HairAcc至Controller內 /// </summary> /// <param name="chaCtrl">要被設定的ChaControl</param> /// <param name="coordinate">要載入的coordibate</param> /// <returns></returns> public static bool SetControllerFromCoordinate(ChaControl chaCtrl, ChaFileCoordinate coordinate = null) { if (null == coordinate) { coordinate = chaCtrl.nowCoordinate; } MonoBehaviour HairAccCusController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); if (null != HairAccCusController) { //注意這條是異步執行 HairAccCusController.Invoke("OnCoordinateBeingLoaded", new object[] { coordinate, false }); return(true); } else { Logger.LogDebug($"No HairAccController found!"); } return(false); }
/// <summary> /// 取得CharaCustomFunctionController /// </summary> /// <param name="chaCtrl">對象ChaControl</param> /// <returns>CharaCustomFunctionController</returns> public MonoBehaviour GetController(ChaControl chaCtrl) { if (!(chaCtrl is ChaControl)) { Logger.LogDebug("No ChaControl found"); return(null); } if (DefaultChaCtrl == chaCtrl && null != DefaultController) { return(DefaultController); } MonoBehaviour controller = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, ControllerName)); if (null == controller) { Logger.LogDebug($"No {CCFCName} Controller found"); } return(controller); }
/// <summary> /// 由ChaControl Controller取得ExtData /// </summary> /// <param name="chaCtrl">對象ChaControl</param> /// <param name="MaterialBackup">Output Material Data Backup</param> /// <param name="TextureDictionaryBackup">Output TextureDiuctionary,注意這個無法寫回Controller</param> /// <returns></returns> public static MonoBehaviour GetExtDataFromController(ChaControl chaCtrl, out Dictionary <string, object> MaterialBackup, out Dictionary <int, object> TextureDictionaryBackup) { MaterialBackup = new Dictionary <string, object>(); TextureDictionaryBackup = null; MonoBehaviour MaterialEditorController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "MaterialEditorCharaController")); if (null == MaterialEditorController) { Logger.LogDebug("No MaterialEditor Controller found"); return(null); } TextureDictionaryBackup = GetTextureDictionaryFromController(chaCtrl); foreach (StoredValueInfo storedValue in storedValueInfos) { MaterialBackup.Add(storedValue.listName, MaterialEditorController.GetField(storedValue.listName).ToListWithoutType()); } //Logger.LogDebug($"Get {chaCtrl.fileParam.fullname} Material From Controller"); return(MaterialEditorController); }
public static void ClearHairAccOnController(ChaControl chaCtrl, int?coordinateIndex = null) { if (null == coordinateIndex) { coordinateIndex = chaCtrl.fileStatus.coordinateType; } MonoBehaviour HairAccCusController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); //Dictionary<int, object> HairAccessories = HairAccCusController?.GetField("HairAccessories").ToDictionary<int, object>(); object HairAccessories = HairAccCusController?.GetField("HairAccessories"); if (HairAccessories is IDictionary h) { h.Remove(coordinateIndex); HairAccCusController.SetField("HairAccessories", h); Logger.LogDebug($"Remove {chaCtrl.fileParam.fullname} {Enum.GetName(typeof(ChaFileDefine.CoordinateType), coordinateIndex)} Hair Accessories From Controller"); } else { Logger.LogDebug($"{chaCtrl.fileParam.fullname}'s Hair Accessories already empty in Controller"); } }
/// <summary> /// 將給入的Material Data Backup儲存至ChaControl之Controller內 /// </summary> /// <param name="chaCtrl">目標ChaControl</param> /// <param name="objectType">類型</param> /// <param name="MaterialBackup">要存入的Material Data Backup</param> /// <param name="Slot">Coordinate ClothesKind 或 Accessory Slot</param> public static void SetToController(ChaControl chaCtrl, ObjectType objectType, Dictionary <string, object> MaterialBackup = null, int Slot = -1) { Predicate <object> predicate = new Predicate <object>(x => (int)x.GetField("ObjectType") == (int)objectType && (int)x.GetField("CoordinateIndex") == chaCtrl.fileStatus.coordinateType && //若Slot有給入,則加上檢查Slot的判斷 (Slot < 0) ? true : (int)x.GetField("Slot") == Slot ); //是否有執行到 bool doFlag = false; MonoBehaviour MaterialEditorController; if (null == MaterialBackup) { MaterialEditorController = GetExtDataFromController(chaCtrl, out Dictionary <string, object> m, out Dictionary <int, object> _); if (null == MaterialBackup) { MaterialBackup = m; } } else { MaterialEditorController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "MaterialEditorCharaController")); } if (null != MaterialEditorController && null != MaterialBackup) { for (int i = 0; i < storedValueInfos.Length; i++) { StoredValueInfo storedValue = storedValueInfos[i]; bool doFlag2 = false; object target = MaterialEditorController.GetField(storedValue.listName).ToListWithoutType(); //移除 doFlag2 = target.RemoveAll(predicate) > 0; //加回 object obj2Add = MaterialBackup[storedValue.listName].Where(predicate); if (obj2Add.Count() > 0) { doFlag2 = true; target.AddRange(obj2Add); } if (doFlag2) { MaterialEditorController.SetField(storedValue.listName, target); GetExtDataFromController(chaCtrl, out Dictionary <string, object> m, out Dictionary <int, object> t); Logger.LogDebug($"--->{storedValue.className}: {m[storedValue.listName].Count()}"); } doFlag |= doFlag2; } if (doFlag) { if (objectType == ObjectType.Clothing) { Logger.LogDebug($"-->Material Set: Clothes " + ((Slot >= 0) ? $", {Patches.ClothesKindName[Slot]}" : ", All Clothes")); } else if (objectType == ObjectType.Accessory) { Logger.LogDebug($"-->Material Set: Accessory" + ((Slot >= 0) ? ", Slot " + Slot : ", All Slots")); } } } }
public static void CopyCurrentCharaOverlayByController(ChaControl sourceChaCtrl, ChaControl targetChaCtrl, bool[] isChecked) { MonoBehaviour sourceController = sourceChaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "CharaOverlaysBasedOnCoordinateController")); MonoBehaviour targetController = targetChaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "CharaOverlaysBasedOnCoordinateController")); object sourceOverlays = sourceController.GetProperty("CurrentOverlay").ToDictionaryWithoutType(); object targetOverlays = targetController.GetProperty("CurrentOverlay").ToDictionaryWithoutType(); object result = sourceOverlays.ToDictionaryWithoutType(); //Clone it to use the structure result.RemoveAll(x => true); _ = sourceOverlays.ForEach((x) => { DictionaryEntry d = (DictionaryEntry)x; int checkCase = -1; switch (Convert.ToInt32(d.Key)) { case 1: case 3: checkCase = 2; break; case 2: case 4: checkCase = 1; break; case 5: case 6: checkCase = 0; break; case 0: break; default: Logger.LogWarning("Cast failed while reading overlays from KK_COBOC!"); break; } if (checkCase >= 0 && checkCase < isChecked.Length) { if (isChecked[checkCase]) { result.Add(d.Key, ((byte[])d.Value).Clone()); } else if (targetOverlays.TryGetValue(d.Key, out object val)) { result.Add(d.Key, ((byte[])val).Clone()); } else { result.Add(d.Key, new byte[] { }); } } }); if (targetController.SetProperty("CurrentOverlay", result)) { //單眼 if (isChecked[0]) { int[] sourceIris = (int[])sourceController.GetField("IrisDisplaySide"); int[] targetIris = (int[])targetController.GetField("IrisDisplaySide"); int sourceType = sourceChaCtrl.fileStatus.coordinateType; int targetType = targetChaCtrl.fileStatus.coordinateType; if (sourceIris.Length > sourceType && targetIris.Length > targetType) { targetIris[targetType] = sourceIris[sourceType]; } targetController.SetField("IrisDisplaySide", targetIris); } targetController.Invoke("OverwriteOverlay"); Logger.LogDebug($"Copy Current CharaOverlay {sourceChaCtrl.fileParam.fullname} -> {targetChaCtrl.fileParam.fullname}: {isChecked[0]} {isChecked[1]} {isChecked[2]}"); } }
/// <summary> /// 將Controller內之Material Editor Data儲存至ChaControl ExtendedData內 /// </summary> /// <param name="chaCtrl">對象ChaControl</param> public static void SetExtDataFromController(ChaControl chaCtrl) { MonoBehaviour MaterialEditorController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "MaterialEditorCharaController")); MaterialEditorController.Invoke("OnCardBeingSaved", new object[] { 1 }); }
/// <summary> /// 由Controller載入HairAcc至ExtData內 /// </summary> /// <param name="chaCtrl">要被設定的ChaControl</param> /// <returns></returns> public static void SetExtDataFromController(ChaControl chaCtrl) { MonoBehaviour HairAccCusController = chaCtrl.GetComponents <MonoBehaviour>().First(x => Equals(x.GetType().Name, "HairAccessoryController")); HairAccCusController.Invoke("OnCardBeingSaved", new object[] { 1 }); }
public static void SetExtDataFromController(ChaControl chaCtrl) { MonoBehaviour COBOCController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "CharaOverlaysBasedOnCoordinateController")); COBOCController.Invoke("SavePluginData", new object[] { false }); }
/// <summary> /// 檢核LoadState,這是因為異步流程所需,檢查Extdata是否已從Coordinate載入完成 /// </summary> /// <param name="chaCtrl">檢核的ChaControl</param> /// <returns>檢核通過</returns> public static bool CheckControllerPrepared(ChaControl chaCtrl, bool doReload = false) { if (!KK_StudioCoordinateLoadOption._isHairAccessoryCustomizerExist) { return(true); } ChaFileCoordinate coordinate = chaCtrl.nowCoordinate; bool?flag = true; Dictionary <int, object> dataFromCoorExt = GetDataFromCoordinate(coordinate); GetDataFromController(chaCtrl, out Dictionary <int, object> dataFromCon); //過濾假的HairAccInfo if (null != dataFromCoorExt) { foreach (KeyValuePair <int, object> rk in dataFromCoorExt.Where(x => null == Patches.GetChaAccessoryComponent(chaCtrl, x.Key)?.gameObject.GetComponent <ChaCustomHairComponent>()).ToList()) { dataFromCoorExt.Remove(rk.Key); } Logger.LogDebug($"Test with {dataFromCoorExt.Count} HairAcc after remove fake HairAccData {string.Join(",", dataFromCoorExt.Select(x => x.Key.ToString()).ToArray())}"); } if (null != dataFromCon) { foreach (KeyValuePair <int, object> rk in dataFromCon.Where(x => null == Patches.GetChaAccessoryComponent(chaCtrl, x.Key)?.gameObject.GetComponent <ChaCustomHairComponent>()).ToList()) { dataFromCon.Remove(rk.Key); } Logger.LogDebug($"Test with {dataFromCon.Count} HairAcc after remove fake HairAccData {string.Join(",", dataFromCon.Select(x => x.Key.ToString()).ToArray())}"); } if (null != dataFromCoorExt && dataFromCoorExt.Count > 0) { if (null != dataFromCon && dataFromCon.Count == dataFromCoorExt.Count) { foreach (KeyValuePair <int, object> kv in dataFromCoorExt) { if (dataFromCon.ContainsKey(kv.Key)) { continue; } else { flag = false; break; } } } else { flag = false; } } else { //No data from coordinate extData if (null != dataFromCon && dataFromCon.Count != 0) { flag = false; } else { flag = null; } } if (null == flag) { return(true); } else if (true == flag) { MonoBehaviour HairAccCusController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "HairAccessoryController")); HairAccCusController.Invoke("UpdateAccessories", new object[] { true }); return(true); } else { if (doReload) { SetControllerFromCoordinate(chaCtrl, coordinate); } return(false); } }
public static void SetExtDataFromController(ChaControl chaCtrl) { MonoBehaviour KCOXController = chaCtrl.GetComponents <MonoBehaviour>().FirstOrDefault(x => Equals(x.GetType().Name, "KoiClothesOverlayController")); KCOXController.Invoke("OnCardBeingSaved", new object[] { 1 }); }