/// <summary> /// Get extended data for character's face (face sliders, eye settings). /// Do not store this data because it might change without notice, for example when clothing is copied. Always call Get at the point where you need the data, not earlier. /// If you change any of the data, remember to call the corresponding Set method or the change might not be saved. /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// If no extended data of this plugin was set yet, this method will return null. /// In maker, you can update controls that use this data in the <see cref="MakerAPI.ReloadCustomInterface"/> event. /// </summary> public PluginData GetFaceExtData() { KoikatuAPI.Assert(ChaFileControl.custom != null, "ChaFileControl.custom != null"); KoikatuAPI.Assert(ChaFileControl.custom.face != null, "ChaFileControl.custom.face != null"); ChaFileControl.custom.face.TryGetExtendedDataById(ExtendedDataId, out var data); return(data); }
/// <summary> /// Get extended data for character's parameters (personality, preferences, traits). /// Do not store this data because it might change without notice, for example when clothing is copied. Always call Get at the point where you need the data, not earlier. /// If you change any of the data, remember to call the corresponding Set method or the change might not be saved. /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// If no extended data of this plugin was set yet, this method will return null. /// In maker, you can update controls that use this data in the <see cref="MakerAPI.ReloadCustomInterface"/> event. /// </summary> public PluginData GetParameterExtData() { var chafile = GetExtDataTargetChaFile(false); KoikatuAPI.Assert(chafile.parameter != null, "chafile.parameter != null"); chafile.parameter.TryGetExtendedDataById(ExtendedDataId, out var data); return(data); }
/// <summary> /// Get extended data for character's face (face sliders, eye settings). /// Do not store this data because it might change without notice, for example when clothing is copied. Always call Get at the point where you need the data, not earlier. /// If you change any of the data, remember to call the corresponding Set method or the change might not be saved. /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// If no extended data of this plugin was set yet, this method will return null. /// In maker, you can update controls that use this data in the <see cref="MakerAPI.ReloadCustomInterface"/> event. /// </summary> public PluginData GetFaceExtData() { var chafile = GetExtDataTargetChaFile(false); KoikatuAPI.Assert(chafile.custom != null, "chafile.custom != null"); KoikatuAPI.Assert(chafile.custom.face != null, "chafile.custom.face != null"); chafile.custom.face.TryGetExtendedDataById(ExtendedDataId, out var data); return(data); }
/// <summary> /// Set extended data for a specific accessory. /// Always call Set right after changing any of the data, or the change might not be saved if the data is changed for whatever reason (clothing change, reload, etc.) /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// </summary> /// <param name="data">Extended data to save.</param> /// <param name="accessoryPartId">The accessory part number to open extened data for (0-indexed).</param> /// <param name="coordinateId">The coordinate number to open extened data for if the game supports multiple coords (0-indexed). -1 will use the current coordinate.</param> public void SetAccessoryExtData(PluginData data, int accessoryPartId, int coordinateId = -1) { var coord = GetCoordinate(coordinateId); KoikatuAPI.Assert(coord != null, nameof(coord) + " != null"); KoikatuAPI.Assert(coord.accessory != null, "coord.accessory != null"); var accessoryPart = coord.accessory.parts[accessoryPartId]; accessoryPart.SetExtendedDataById(ExtendedDataId, data); }
/// <summary> /// Set extended data for specific clothes. /// Always call Set right after changing any of the data, or the change might not be saved if the data is changed for whatever reason (clothing change, reload, etc.) /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// </summary> /// <param name="data">Extended data to save.</param> /// <param name="coordinateId">The coordinate number to open extened data for if the game supports multiple coords (0-indexed). -1 will use the current coordinate.</param> public void SetClothesExtData(PluginData data, int coordinateId = -1) { var coord = GetCoordinate(coordinateId); KoikatuAPI.Assert(coord != null, nameof(coord) + " != null"); KoikatuAPI.Assert(coord.clothes != null, "coord.clothes != null"); var clothes = coord.clothes; clothes.SetExtendedDataById(ExtendedDataId, data); }
/// <summary> /// Get extended data for a specific accessory. /// Do not store this data because it might change without notice, for example when clothing is copied. Always call Get at the point where you need the data, not earlier. /// If you change any of the data, remember to call the corresponding Set method or the change might not be saved. /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// If no extended data of this plugin was set yet, this method will return null. /// In maker, you can update controls that use this data in the <see cref="MakerAPI.ReloadCustomInterface"/> event. /// </summary> /// <param name="accessoryPartId">The accessory part number to open extened data for (0-indexed).</param> /// <param name="coordinateId">The coordinate number to open extened data for if the game supports multiple coords (0-indexed). -1 will use the current coordinate.</param> public PluginData GetAccessoryExtData(int accessoryPartId, int coordinateId = -1) { var coord = GetCoordinate(coordinateId); KoikatuAPI.Assert(coord != null, nameof(coord) + " != null"); KoikatuAPI.Assert(coord.accessory != null, "coord.accessory != null"); var accessoryPart = coord.accessory.parts[accessoryPartId]; accessoryPart.TryGetExtendedDataById(ExtendedDataId, out var data); return(data); }
/// <summary> /// Get extended data for specific clothes. /// Do not store this data because it might change without notice, for example when clothing is copied. Always call Get at the point where you need the data, not earlier. /// If you change any of the data, remember to call the corresponding Set method or the change might not be saved. /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// If no extended data of this plugin was set yet, this method will return null. /// In maker, you can update controls that use this data in the <see cref="MakerAPI.ReloadCustomInterface"/> event. /// </summary> /// <param name="coordinateId">The coordinate number to open extened data for if the game supports multiple coords (0-indexed). -1 will use the current coordinate.</param> public PluginData GetClothesExtData(int coordinateId = -1) { var coord = GetCoordinate(coordinateId); KoikatuAPI.Assert(coord != null, nameof(coord) + " != null"); KoikatuAPI.Assert(coord.clothes != null, "coord.clothes != null"); var clothes = coord.clothes; clothes.TryGetExtendedDataById(ExtendedDataId, out var data); return(data); }
/// <summary> /// Set extended data for character's parameters (personality, preferences, traits). /// Always call Set right after changing any of the data, or the change might not be saved if the data is changed for whatever reason (clothing change, reload, etc.) /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// </summary> /// <param name="data">Extended data to save.</param> public void SetParameterExtData(PluginData data) { var chafile = GetExtDataTargetChaFile(true); KoikatuAPI.Assert(chafile.parameter != null, "chafile.parameter != null"); chafile.parameter.SetExtendedDataById(ExtendedDataId, data); // Save both to the main chafile and to the current instance in case it gets saved by something if (chafile != ChaFileControl) { ChaFileControl.parameter.SetExtendedDataById(ExtendedDataId, data); } }
protected override void OnReload(GameMode currentGameMode, bool maintainState) { var a = GetExtendedData(); var b = GetBodyExtData(); var c = GetParameterExtData(); var d = GetFaceExtData(); KoikatuAPI.Assert((a == null && b == null && c == null && d == null) || (a != null && b != null && c != null && d != null), "ext data not lining up"); if (a != null) { KoikatuAPI.Assert(b != null, "b != null"); KoikatuAPI.Assert(c != null, "c != null"); KoikatuAPI.Assert(d != null, "d != null"); var newId = a.data["id"] as string; KoikatuAPI.Assert(newId == b?.data["id"] as string, "a.data[\"id\"] == b.data[\"id\"]"); KoikatuAPI.Assert(newId == c?.data["id"] as string, "a.data[\"id\"] == c.data[\"id\"]"); KoikatuAPI.Assert(newId == d?.data["id"] as string, "a.data[\"id\"] == d.data[\"id\"]"); Console.WriteLine($"ID get from ext data - {newId} | Old ID - {id} | Chara - {ChaControl.name}"); id = newId; } if (id == null) { id = $"{No++} - {SceneApi.GetLoadSceneName()} - {SceneApi.GetAddSceneName()}"; Console.WriteLine($"New ID assigned - {id} | Chara - {ChaControl.name} | {ChaFileControl.parameter.fullname}"); SetParameterExtData(new PluginData() { data = new Dictionary <string, object> { { "id", id } } }); SetBodyExtData(new PluginData() { data = new Dictionary <string, object> { { "id", id } } }); SetFaceExtData(new PluginData() { data = new Dictionary <string, object> { { "id", id } } }); SetExtendedData(new PluginData() { data = new Dictionary <string, object> { { "id", id } } }); } KoikatuAPI.Logger.LogWarning($"event:OnReload chara:{ChaControl.name} currentGameMode:{currentGameMode} maintainState:{maintainState}"); }
private ChaFileCoordinate GetCoordinate(int coordinateId) { KoikatuAPI.Assert(ChaControl.nowCoordinate != null, "ChaControl.nowCoordinate != null"); #if KK || KKS return(coordinateId < 0 ? ChaControl.nowCoordinate : ChaFileControl.coordinate[coordinateId]); #elif EC || AI || HS2 if (coordinateId > 0) { KoikatuAPI.Logger.LogWarning("This game doesn't support multiple coordinates, nowCoordinate will be used!\n" + new System.Diagnostics.StackTrace()); } return(ChaControl.nowCoordinate); #endif }
private ChaFileCoordinate GetCoordinate(int coordinateId) { // Get coord from the current ChaControl since it can be temporarily changed and would mess up ext data of clothes inside heroine.chaCtrl if we saved there KoikatuAPI.Assert(ChaControl.nowCoordinate != null, "ChaControl.nowCoordinate != null"); #if KK || KKS return(coordinateId < 0 ? ChaControl.nowCoordinate : ChaFileControl.coordinate[coordinateId]); #elif EC || AI || HS2 if (coordinateId > 0) { KoikatuAPI.Logger.LogWarning("This game doesn't support multiple coordinates, nowCoordinate will be used!\n" + new System.Diagnostics.StackTrace()); } return(ChaControl.nowCoordinate); #endif }
/// <inheritdoc /> protected override GameObject OnCreateControl(Transform subCategoryList) { var tr = Object.Instantiate(RadioCopy, subCategoryList, false); tr.name = "rb"; var settingName = tr.Find("textTglTitle").GetComponent <TextMeshProUGUI>(); settingName.text = _settingName; settingName.color = TextColor; var sourceToggle = tr.Find("rb00"); Buttons = _buttons.Select( (x, i) => { if (i == 0) { return(sourceToggle); } var newButton = Object.Instantiate(sourceToggle, tr, false); newButton.name = "rb0" + i; return(newButton); }) .Select(x => x.GetComponent <Toggle>()) .ToList() .AsReadOnly(); // If there's less toggles than the number of toggles in a row, expand them to fill all space var singleToggleWidth = 280 / Mathf.Min(Buttons.Count, ColumnCount); var rowCount = Mathf.CeilToInt((float)Buttons.Count / ColumnCount); tr.GetComponent <LayoutElement>().minHeight = 40 * rowCount; var buttonIndex = 0; for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) { for (var columnIndex = 0; columnIndex < ColumnCount; columnIndex++) { if (buttonIndex >= Buttons.Count) { break; } var toggle = Buttons[buttonIndex]; var rt = toggle.GetComponent <RectTransform>(); rt.offsetMin = new Vector2(singleToggleWidth * columnIndex - 280, 8); rt.offsetMax = new Vector2(singleToggleWidth * (columnIndex + 1) - 280, -8); rt.anchorMax = new Vector2(1, 1 - rowIndex / (float)rowCount); rt.anchorMin = new Vector2(1, 1 - (rowIndex + 1) / (float)rowCount); toggle.GetComponentInChildren <TextMeshProUGUI>().text = _buttons[buttonIndex]; var indexCopy = buttonIndex; toggle.onValueChanged.AddListener( a => { if (a || indexCopy == Value) { SetValue(indexCopy); } }); buttonIndex++; } } KoikatuAPI.Assert(buttonIndex >= Buttons.Count, "Didn't loop over all radio buttons, only " + buttonIndex); BufferedValueChanged.Subscribe( i => { for (var index = 0; index < Buttons.Count; index++) { var tgl = Buttons[index]; tgl.isOn = index == i; } }); return(tr.gameObject); }
private static void SpawnActionPoint(ActionIconEntry iconEntry, int created) { var inst = CommonLib.LoadAsset <GameObject>("map/playeractionpoint/00.unity3d", "PlayerActionPoint_05", true); inst.gameObject.name = "CustomActionPoint_" + created; var parent = GameObject.Find("Map/ActionPoints"); inst.transform.SetParent(parent.transform, true); var pap = inst.GetComponentInChildren <PlayerActionPoint>(); var iconRootObject = pap.gameObject; pap.gameObject.name = inst.name; var iconRootTransform = pap.transform; var rendererIcon = pap.renderers.Reverse().First(x => { var tex = x.material.mainTexture; return(tex.width == 256 && tex.height == 256); }); var animator = pap.animator; var renderers = pap.renderers; //iconRootTransform.GetComponentsInChildren<MeshRenderer>(); var particles = pap.particleSystems; //iconRootTransform.GetComponentsInChildren<ParticleSystem>(); KoikatuAPI.Assert(particles.Length == 3, "SpawnActionPoint particles.Length == 3 failed"); pap.gameObject.layer = LayerMask.NameToLayer("Action/ActionPoint"); foreach (Transform child in pap.transform.parent) { if (child != pap.transform) { Object.Destroy(child.gameObject); } } Object.DestroyImmediate(pap, false); iconRootTransform.position = iconEntry.Position; // Set color to pink var pointColor = iconEntry.Color; foreach (var rend in renderers) { rend.material.color = pointColor; } #pragma warning disable 618 foreach (var rend in particles) { rend.startColor = pointColor; } #pragma warning restore 618 // Initial animation state particles[0].Play(); particles[1].Stop(); particles[2].Stop(); // Hook up event/anim logic var evt = iconRootObject.AddComponent <TriggerEnterExitEvent>(); rendererIcon.material.mainTexture = iconEntry.Icon; var playerInRange = false; evt.onTriggerEnter += c => { if (!c.CompareTag("Player")) { return; } playerInRange = true; animator.Play(PAP.Assist.Animation.SpinState); Utils.Sound.Play(Manager.Sound.Type.GameSE2D, Utils.Sound.SEClipTable[0x38], 0f); c.GetComponent <Player>().actionPointList.Add(evt); ActionScene.instance.actionChangeUI.Set(ActionChangeUI.ActionType.Shop); ActionScene.instance.actionChangeUI._text.text = iconEntry.PopupText; particles[0].Stop(); particles[1].Play(); particles[2].Play(); }; evt.onTriggerExit += c => { if (!c.CompareTag("Player")) { return; } playerInRange = false; animator.Play(PAP.Assist.Animation.IdleState); c.GetComponent <Player>().actionPointList.Remove(evt); ActionScene.instance.actionChangeUI.Remove(ActionChangeUI.ActionType.Shop); particles[0].Play(); particles[1].Stop(); particles[2].Stop(); }; evt.UpdateAsObservable() .Subscribe(_ => { // Hide in H scenes and other places var isVisible = !Game.IsRegulate(true) && ActionScene.initialized; if (isVisible) { var asi = ActionScene.instance; isVisible = asi.regulate == 0 && (asi.AdvScene == null || !asi.AdvScene.gameObject.activeSelf) && !TalkScene.isPaly; } if (renderers[0].enabled != isVisible) { foreach (var renderer in renderers) { renderer.enabled = isVisible; } if (!isVisible) { particles[0].Stop(); particles[1].Stop(); particles[2].Stop(); } else { particles[0].Play(); particles[1].Stop(); particles[2].Stop(); } } // Check if player clicked this point if (isVisible && playerInRange && ActionInput.isAction && !ActionScene.instance.Player.isActionNow) { iconEntry.OnOpen(); } }) .AddTo(evt); iconEntry.Instance = inst; iconEntry.OnCreated?.Invoke(evt); }
/// <summary> /// Set extended data for character's parameters (personality, preferences, traits). /// Always call Set right after changing any of the data, or the change might not be saved if the data is changed for whatever reason (clothing change, reload, etc.) /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// </summary> /// <param name="data">Extended data to save.</param> public void SetParameterExtData(PluginData data) { KoikatuAPI.Assert(ChaFileControl.parameter != null, "ChaFileControl.parameter != null"); ChaFileControl.parameter.SetExtendedDataById(ExtendedDataId, data); }
/// <summary> /// Set extended data for character's face (face sliders, eye settings). /// Always call Set right after changing any of the data, or the change might not be saved if the data is changed for whatever reason (clothing change, reload, etc.) /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// </summary> /// <param name="data">Extended data to save.</param> public void SetFaceExtData(PluginData data) { KoikatuAPI.Assert(ChaFileControl.custom != null, "ChaFileControl.custom != null"); KoikatuAPI.Assert(ChaFileControl.custom.face != null, "ChaFileControl.custom.face != null"); ChaFileControl.custom.face.SetExtendedDataById(ExtendedDataId, data); }
/// <summary> /// Get extended data for character's parameters (personality, preferences, traits). /// Do not store this data because it might change without notice, for example when clothing is copied. Always call Get at the point where you need the data, not earlier. /// If you change any of the data, remember to call the corresponding Set method or the change might not be saved. /// This data is saved alongside game data, which means it is automatically copied and moved as necessary. /// If no extended data of this plugin was set yet, this method will return null. /// In maker, you can update controls that use this data in the <see cref="MakerAPI.ReloadCustomInterface"/> event. /// </summary> public PluginData GetParameterExtData() { KoikatuAPI.Assert(ChaFileControl.parameter != null, "ChaFileControl.parameter != null"); ChaFileControl.parameter.TryGetExtendedDataById(ExtendedDataId, out var data); return(data); }