/// <summary> /// Checks if the specified accessory is a hair accessory /// </summary> public bool IsHairAccessory(int slot) { try { var accessory = ChaControl.GetAccessoryObject(slot); if (accessory == null) { return(false); } return(accessory.GetComponent <ChaCustomHairComponent>() != null); } catch { return(false); } }
internal static bool IsHairAccessory(ChaControl chaCtrl, int slot) { try { ChaAccessoryComponent accessory = chaCtrl.GetAccessoryObject(slot)?.GetComponent <ChaAccessoryComponent>(); if (accessory == null) { return(false); } return(accessory.gameObject?.GetComponent <ChaCustomHairComponent>() != null); } catch { return(false); } }
internal void ImportFromRendererInfo(int SlotIndex) { GameObject go = ChaControl.GetAccessoryObject(SlotIndex); if (go == null) { return; } Renderer[] rends = go.GetComponentsInChildren <Renderer>(true); List <RouteRule> rules = new List <RouteRule>(); int skipped = 0; int added = 0; foreach (Renderer rend in rends) { foreach (Material mat in rend.materials) { string ObjPath = GetGameObjectPath(rend.transform).Replace(ChaControl.gameObject.name + "/", ""); string MatName = mat.NameFormatted(); RouteRule rule = new RouteRule { GameObjectPath = ObjPath, Action = Action.Clone, OldName = MatName, NewName = MatName + "_cloned" }; RouteRule exist = CurOutfitTrigger.Where(x => x.GameObjectPath == ObjPath && x.NewName == MatName).FirstOrDefault(); if (exist != null) { skipped++; continue; } CurOutfitTrigger.Add(rule); added++; } } Logger.LogMessage($"skipped: {skipped}, added: {added}"); }
/// <summary> /// Checks if the specified accessory has length transforms (trfLength in the ChaCustomHairComponent MonoBehavior) /// </summary> public bool HasLengthTransforms() { var accessory = ChaControl.GetAccessoryObject(AccessoriesApi.SelectedMakerAccSlot); if (accessory == null) { return(false); } var chaCustomHairComponent = accessory.GetComponent <ChaCustomHairComponent>(); if (chaCustomHairComponent != null) { for (var i = 0; i < chaCustomHairComponent.trfLength.Length; i++) { if (chaCustomHairComponent.trfLength[i] != null) { return(true); } } } return(false); }
/// <summary> /// Updates the specified hair accessory /// </summary> public void UpdateAccessory(int slot, bool updateCharacter = true) { if (!IsHairAccessory(slot)) { return; } var acc = ChaControl.GetAccessoryObject(slot); if (acc == null) { return; } ChaAccessoryComponent chaAccessoryComponent = acc.GetComponent <ChaAccessoryComponent>(); if (chaAccessoryComponent == null) { return; } ChaCustomHairComponent chaCustomHairComponent = chaAccessoryComponent.gameObject.GetComponent <ChaCustomHairComponent>(); if (chaCustomHairComponent.rendHair == null) { return; } if (!HairAccessories.ContainsKey(CurrentCoordinateIndex)) { return; } if (!HairAccessories[CurrentCoordinateIndex].TryGetValue(slot, out var hairAccessoryInfo)) { return; } if (chaAccessoryComponent.rendNormal == null) { return; } if (chaCustomHairComponent.rendHair == null) { return; } if (updateCharacter && hairAccessoryInfo.ColorMatch) { if (MakerAPI.InsideAndLoaded) { CvsAccessory cvsAccessory = AccessoriesApi.GetMakerAccessoryPageObject(slot).GetComponent <CvsAccessory>(); cvsAccessory.UpdateAcsColor01(ChaControl.chaFile.custom.hair.parts[0].baseColor); cvsAccessory.UpdateAcsColor02(ChaControl.chaFile.custom.hair.parts[0].startColor); cvsAccessory.UpdateAcsColor03(ChaControl.chaFile.custom.hair.parts[0].endColor); OutlineColorPicker.SetValue(slot, ChaControl.chaFile.custom.hair.parts[0].outlineColor, false); hairAccessoryInfo.OutlineColor = ChaControl.chaFile.custom.hair.parts[0].outlineColor; } else { for (var i = 0; i < chaCustomHairComponent.rendHair.Length; i++) { Renderer renderer = chaCustomHairComponent.rendHair[i]; if (renderer == null) { continue; } if (renderer.sharedMaterial.HasProperty(ChaShader._Color)) { renderer.sharedMaterial.SetColor(ChaShader._Color, ChaControl.chaFile.custom.hair.parts[0].baseColor); } if (renderer.sharedMaterial.HasProperty(ChaShader._Color2)) { renderer.sharedMaterial.SetColor(ChaShader._Color2, ChaControl.chaFile.custom.hair.parts[0].startColor); } if (renderer.sharedMaterial.HasProperty(ChaShader._Color3)) { renderer.sharedMaterial.SetColor(ChaShader._Color3, ChaControl.chaFile.custom.hair.parts[0].endColor); } } } } Texture2D texHairGloss = (Texture2D)AccessTools.Property(typeof(ChaControl), "texHairGloss").GetValue(ChaControl, null); for (var i = 0; i < chaCustomHairComponent.rendHair.Length; i++) { Renderer renderer = chaCustomHairComponent.rendHair[i]; if (renderer == null) { continue; } if (renderer.sharedMaterial.HasProperty(ChaShader._HairGloss)) { if (hairAccessoryInfo.HairGloss) { renderer.sharedMaterial.SetTexture(ChaShader._HairGloss, texHairGloss); } else { renderer.sharedMaterial.SetTexture(ChaShader._HairGloss, null); } } if (renderer.sharedMaterial.HasProperty(ChaShader._LineColor)) { if (hairAccessoryInfo.ColorMatch) { renderer.sharedMaterial.SetColor(ChaShader._LineColor, ChaControl.chaFile.custom.hair.parts[0].outlineColor); } else { renderer.sharedMaterial.SetColor(ChaShader._LineColor, hairAccessoryInfo.OutlineColor); } } } for (var i = 0; i < chaCustomHairComponent.rendAccessory.Length; i++) { Renderer renderer = chaCustomHairComponent.rendAccessory[i]; if (renderer == null) { continue; } if (renderer.sharedMaterial.HasProperty(ChaShader._Color)) { renderer.sharedMaterial.SetColor(ChaShader._Color, hairAccessoryInfo.AccessoryColor); } if (renderer.sharedMaterial.HasProperty(ChaShader._Color2)) { renderer.sharedMaterial.SetColor(ChaShader._Color2, hairAccessoryInfo.AccessoryColor); } if (renderer.sharedMaterial.HasProperty(ChaShader._Color3)) { renderer.sharedMaterial.SetColor(ChaShader._Color3, hairAccessoryInfo.AccessoryColor); } } chaCustomHairComponent.lengthRate = hairAccessoryInfo.HairLength; }
private void Start() { CharacterApi.RegisterExtraBehaviour <MaterialRouterController>(GUID); HooksInstance = Harmony.CreateAndPatchAll(typeof(Hooks)); BepInEx.Bootstrap.Chainloader.PluginInfos.TryGetValue("com.deathweasel.bepinex.materialeditor", out PluginInfo PluginInfo); Type MaterialEditorCharaController = PluginInfo.Instance.GetType().Assembly.GetType("KK_Plugins.MaterialEditor.MaterialEditorCharaController"); HooksInstance.Patch(MaterialEditorCharaController.GetMethod("OnReload", AccessTools.all, null, new[] { typeof(GameMode), typeof(bool) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialEditorCharaController_OnReload_Prefix))); HooksInstance.Patch(MaterialEditorCharaController.GetMethod("OnCoordinateBeingLoaded", AccessTools.all, null, new[] { typeof(ChaFileCoordinate), typeof(bool) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialEditorCharaController_OnCoordinateBeingLoaded_Prefix))); HooksInstance.Patch(MaterialEditorCharaController.GetMethod("CorrectTongue", AccessTools.all, null, new Type[0], null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialEditorCharaController_CorrectTongue_Prefix))); Type MaterialEditorMaterialAPI = PluginInfo.Instance.GetType().Assembly.GetType("MaterialEditorAPI.MaterialAPI"); if (MaterialEditorMaterialAPI.GetMethods().Single(x => x.Name == "SetTexture").GetParameters().ElementAtOrDefault(3)?.ParameterType == typeof(Texture)) { HooksInstance.Patch(MaterialEditorMaterialAPI.GetMethod("SetTexture", AccessTools.all, null, new[] { typeof(GameObject), typeof(string), typeof(string), typeof(Texture) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialAPI_SetTexture_Prefix))); } else { HooksInstance.Patch(MaterialEditorMaterialAPI.GetMethod("SetTexture", AccessTools.all, null, new[] { typeof(GameObject), typeof(string), typeof(string), typeof(Texture2D) }, null), prefix: new HarmonyMethod(typeof(Hooks), nameof(Hooks.MaterialAPI_SetTexture_Prefix))); } MakerAPI.MakerBaseLoaded += (object sender, RegisterCustomControlsEvent ev) => { HooksMakerInstance = Harmony.CreateAndPatchAll(typeof(HooksMaker)); }; MakerAPI.MakerFinishedLoading += (object sender, EventArgs ev) => { btmGetTemplate.Visible.OnNext(false); btmImportSetting.Visible.OnNext(false); btmRemoveSetting.Visible.OnNext(false); }; AccessoriesApi.SelectedMakerAccSlotChanged += (object sender, AccessorySlotEventArgs ev) => { InitCurrentSlot(); }; MakerAPI.MakerExiting += (object sender, EventArgs ev) => { HooksMakerInstance.UnpatchAll(HooksMakerInstance.Id); HooksMakerInstance = null; }; AccessoriesApi.AccessoryTransferred += (object sender, AccessoryTransferEventArgs ev) => { MaterialRouterController pluginCtrl = GetController(MakerAPI.GetCharacterControl()); pluginCtrl.AccessoryTransferEvent(ev); }; AccessoriesApi.AccessoriesCopied += (object sender, AccessoryCopyEventArgs ev) => { MaterialRouterController pluginCtrl = GetController(MakerAPI.GetCharacterControl()); pluginCtrl.AccessoryCopyEvent(ev); }; MakerAPI.RegisterCustomSubCategories += (object sender, RegisterSubCategoriesEvent ev) => { ChaControl chaCtrl = MakerAPI.GetCharacterControl(); MaterialRouterController pluginCtrl = GetController(chaCtrl); MakerCategory category = new MakerCategory("05_ParameterTop", "tglMaterialRouter", MakerConstants.Parameter.Attribute.Position + 1, "Router"); ev.AddSubCategory(category); ev.AddControl(new MakerText("BodyTrigger", category, this)); ev.AddControl(new MakerButton("Export", category, this)).OnClick.AddListener(delegate { pluginCtrl.ExportBodyTrigger(); }); ev.AddControl(new MakerButton("Import", category, this)).OnClick.AddListener(delegate { pluginCtrl.ImportBodyTrigger(); }); ev.AddControl(new MakerButton("Reset", category, this)).OnClick.AddListener(delegate { pluginCtrl.ResetBodyTrigger(); }); ev.AddControl(new MakerSeparator(category, this)); ev.AddControl(new MakerText("OutfitTriggers", category, this)); ev.AddControl(new MakerButton("Export", category, this)).OnClick.AddListener(delegate { pluginCtrl.ExportOutfitTrigger(); }); ev.AddControl(new MakerButton("Import", category, this)).OnClick.AddListener(delegate { pluginCtrl.ImportOutfitTrigger(); }); ev.AddControl(new MakerButton("Reset", category, this)).OnClick.AddListener(delegate { pluginCtrl.ResetOutfitTrigger(); }); ev.AddControl(new MakerSeparator(category, this)); ev.AddControl(new MakerText("Config", category, this)); tglSkipCloned = ev.AddControl(new MakerToggle(category, "Get Template Skip Cloned", CfgSkipCloned.Value, this)); tglSkipCloned.ValueChanged.Subscribe(value => CfgSkipCloned.Value = value); ev.AddControl(new MakerSeparator(category, this)); ev.AddControl(new MakerText("Tools", category, this)); ev.AddControl(new MakerButton("Reload", category, Instance)).OnClick.AddListener(delegate { string CardPath = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Paths.ExecutablePath) + "_MaterialRouter.png"); chaCtrl.chaFile.SaveCharaFile(CardPath, byte.MaxValue, false); chaCtrl.chaFile.LoadFileLimited(CardPath); if (chaCtrl.chaFile.GetLastErrorCode() != 0) { throw new Exception("LoadFileLimited failed"); } chaCtrl.ChangeCoordinateType(true); chaCtrl.Reload(); CustomBase.Instance.updateCustomUI = true; }); ev.AddControl(new MakerButton("Info", category, Instance)).OnClick.AddListener(delegate { Logger.LogInfo($"[BodyTrigger][{pluginCtrl?.BodyTrigger?.Count}]"); for (int i = 0; i < chaCtrl.chaFile.coordinate.Length; i++) { Logger.LogInfo($"[OutfitTriggers][{i}][{pluginCtrl?.OutfitTriggers?[i].Count}]"); } }); ev.AddControl(new MakerButton("Head Get Template", MakerConstants.Face.All, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHead, true)); ev.AddControl(new MakerButton("Body Get Template", MakerConstants.Face.All, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objBody, true)); const string labelConsolePrint = "Console Output"; const string labelGenerateSetting = "Generate Setting"; const string labelRemoveSetting = "Remove Setting"; ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Top, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[0])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Bottom, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[1])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Bra, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[2])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Shorts, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[3])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Gloves, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[4])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Panst, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[5])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.Socks, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[6])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.InnerShoes, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[7])); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Clothes.OuterShoes, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objClothes[8])); btmGetTemplate = MakerAPI.AddAccessoryWindowControl(new MakerButton(labelConsolePrint, null, this)); btmGetTemplate.OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.GetAccessoryObject(AccessoriesApi.SelectedMakerAccSlot))); btmImportSetting = MakerAPI.AddAccessoryWindowControl(new MakerButton(labelGenerateSetting, null, this)); btmImportSetting.OnClick.AddListener(() => pluginCtrl.ImportFromRendererInfo(AccessoriesApi.SelectedMakerAccSlot)); btmRemoveSetting = MakerAPI.AddAccessoryWindowControl(new MakerButton(labelRemoveSetting, null, this)); btmRemoveSetting.OnClick.AddListener(() => pluginCtrl.RemoveAccSlotInfo(AccessoriesApi.SelectedMakerAccSlot)); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Back, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[0], true)); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Front, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[1], true)); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Side, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[2], true)); ev.AddControl(new MakerButton(labelConsolePrint, MakerConstants.Hair.Extension, this)).OnClick.AddListener(() => PrintRendererInfo(chaCtrl, chaCtrl.objHair[3], true)); }; }