Jump to content

The Tweakables Thread


Recommended Posts

I have not found any good spot where people documented how the new tweakables work so I decided to put the things I know here. Please post what you know, too.

Adding a button that changes a bool


[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "My Bool"),
UI_Toggle(disabledText="Disabled", enabledText="Enabled")]
public bool myBool = true;

The parts explained:

guiActive = true show in flight

guiActiveEditor = true tells KSP to show it in the editor (or not)

UI_Toggle(...) defines what text should be shown

Adding a slider

	
[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "My Slider") , UI_FloatRange(minValue = -14f, maxValue = 14f, stepIncrement = 1f)]
public float mySlider= 0;

The type of the slider MUST be float. Doubles will throw an conversion error.

minValue= -14f sets the minimum value. It can be negative

maxValue = 14f ... you can guess that

mySlider= 0; Assign a default value

stepIncrement = 1f steps in which the slider will move

guiActive = true see above

guiActiveEditor = true see above

Calling a function


[KSPEvent(guiName = "Call func", guiActive = true, guiActiveEditor = true)]
public void toggleInflate () {
...
}

guiActive = true see above

guiActiveEditor = true see above

Showing a variable


[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = false, guiName = "My Var")]
public float myVar = 12f;

All the parts here have beenexplained above.

Known or unknown issues

The sliders seem to show up in the editor always, even if you set guiActiveEditor = false. Does anybody know how to prevent this?

Please post whatever you know here. I will add the info to thie top post. THANKS!

Edited by dtobi
Link to comment
Share on other sites

Yeah, excellent thread idea. I was just browsing looking for something on this subject :)

I don't have any info to add to this yet, but I was wondering if anyone had discovered a way to disable existing tweakables on parts.

For example, I have some custom engines that I'd like to disable the thrust limiter tweakble on either through code or config. Any ideas?

Link to comment
Share on other sites

  • 1 month later...

Sorry for the necro here, but just wanted to answer my own question above, as I finally figured out the solution and thought it might help others down the road that may comes across this thread.

Given the tweakables are just KSPFields, something like the following will serve to disable stock tweakables:


tempEngineModule.Fields["thrustPercentage"].guiActiveEditor = false;
tempEngineModule.Fields["thrustPercentage"].guiActive = false;

So, basically all you need is a reference to the module in question, and off you go. In my case, I've decided to add a separate part module to engines where I want to have the thrust limiter disabled that scans through the other modules present in the part in OnStart(), and sets the thrustPercentage attributes for any ModuleEngines like above.

From what I've seen, all KSPFields that Squad uses are public, so it's just a matter of looking at the module in question and figuring out which variable is the internal representation of the field you wish to modify.

Anyways, hope that helps someone else out.

Link to comment
Share on other sites

  • 2 months later...
The sliders seem to show up in the editor always, even if you set guiActiveEditor = false. Does anybody know how to prevent this?

Adding a scene value to the UI_FloatRange does the trick, e.g.

[KSPField(isPersistant = true, guiActive = true, guiActiveEditor = true, guiName = "My Slider") , UI_FloatRange(minValue = -14f, maxValue = 14f, stepIncrement = 1f, [B]scene = UI_Scene.Flight[/B])]
public float mySlider= 0;

The defined values are:

public enum UI_Scene
{
Editor = 1,
Flight = 2,
All = 255,
}

Link to comment
Share on other sites

I'm having trouble displaying a KSP field for a nearby vessel:


[KSPField(guiActive = true, guiActiveEditor = true, guiName = "Port Name:", isPersistant = true)]
public string portName;

It does display properly for the active vessel. Any suggestions?

Link to comment
Share on other sites

I'm having trouble displaying a KSP field for a nearby vessel:


[KSPField(guiActive = true, guiActiveEditor = true, guiName = "Port Name:", isPersistant = true)]
public string portName;

It does display properly for the active vessel. Any suggestions?

I'm not sure that can be done. KSPEvent has a GUiActiveUnfocused clause, but KSPField doesn't. So you'll only get that for the active vessel unfortunately.

Link to comment
Share on other sites

Is there any way to assign UI_FloatRange's minValue/maxValue through the use of variables?

My (and Gaius') TweakScale plugin does that. Code from Scale.cs around line 140:


var range = (UI_FloatRange)this.Fields["tweakScale"].uiControlEditor;
range.minValue = configValue("minScale", defaultValue: isFreeScale ? 0.5f : (float)scaleFactors.First());
range.maxValue = configValue("maxScale", defaultValue: isFreeScale ? 2.0f : (float)scaleFactors.Last());
range.stepIncrement = configValue("stepIncrement", defaultValue: 0.01f);

There's also a uiControlFlight, which I assume is the same thing except while flying, but I haven't tested that.

Link to comment
Share on other sites

My (and Gaius') TweakScale plugin does that. Code from Scale.cs around line 140:


var range = (UI_FloatRange)this.Fields["tweakScale"].uiControlEditor;
range.minValue = configValue("minScale", defaultValue: isFreeScale ? 0.5f : (float)scaleFactors.First());
range.maxValue = configValue("maxScale", defaultValue: isFreeScale ? 2.0f : (float)scaleFactors.Last());
range.stepIncrement = configValue("stepIncrement", defaultValue: 0.01f);

There's also a uiControlFlight, which I assume is the same thing except while flying, but I haven't tested that.

Awesome. Thanks!

Link to comment
Share on other sites

When I try to put

[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "My Bool"),
UI_Toggle(disabledText="Disabled", enabledText="Enabled")]

into my addon code I get errors, "'KSPField' does not contain a definition for guiActiveEditor" and "The type or namespace UI_Toggle could not be found", could anyone tell me why? Have these been removed or...?

Link to comment
Share on other sites

When I try to put
[KSPField(isPersistant = false, guiActive = true, guiActiveEditor = true, guiName = "My Bool"),
UI_Toggle(disabledText="Disabled", enabledText="Enabled")]

into my addon code I get errors, "'KSPField' does not contain a definition for guiActiveEditor" and "The type or namespace UI_Toggle could not be found", could anyone tell me why? Have these been removed or...?

They are still there. Did you define a variable to go along with the KSPField declaration?

Link to comment
Share on other sites

How does one disable symmetry mode across multiple parts if one is to use a bool tweakable KSPField? I'm finding that during the VAB they all share the same value but during flight I can change them individually.

Link to comment
Share on other sites

Is it possible to get a slider as with UI_FloatRange, but with a set of text values? Say for scale, you could have 'small', 'medium', 'large' instead of 0, 1, 2.

Oh man that would be nice to have.

Link to comment
Share on other sites

How would one go about adding tweakable colors to lights like the stock .23.5 lights?

I think you would just copy the module definition from one of the stock lights cfg. Maybe?

Link to comment
Share on other sites

I think you would just copy the module definition from one of the stock lights cfg. Maybe?

I thought about that, but that would mean switching over to .23.5, and though I have it, I don't actively play it yet, as a few mods I love dearly aren't quite up with it yet.

In the meantime, since .23 has tweaks available, I thought maybe there'd be a way to tap into that for the AviationLights mod. Specifically, I'm considering a set of buttons to configure the lights from a set of color presets, so I could right-click and change a light into a red strobe or a green navlight in the VAB/SPH. The idea is that the mod would only need one skin to accommodate all possible variants, and would potentially help make it look a little more realistic.

Link to comment
Share on other sites

Is it possible to get a slider as with UI_FloatRange, but with a set of text values? Say for scale, you could have 'small', 'medium', 'large' instead of 0, 1, 2.

So I wrote some code. Any wizards here who can tell me why this doesn't work?

using System;
using UnityEngine;

namespace TweakScale
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field)]
public class UI_TextRange : UI_Control
{
public string[] valueSet;

public UI_TextRange()
{
valueSet = new string[] { };
}

public override void Load(ConfigNode node, object host)
{
base.Load(node, host);
string tmp;
if (UI_Control.ParseString(out tmp, node, "valueSet", "TextRange", "No value provided"))
{
valueSet = tmp.Split(',').Select(a => a.Trim()).ToArray();
}
}
public override void Save(ConfigNode node, object host)
{
node.AddValue("valueSet", string.Join(", ", valueSet));
}
}
[UI_TextRange]
public class UIPartActionTextRange : UIPartActionFieldItem
{

private float realValue;
private float offset;
private float tmpValue;
public SpriteText fieldAmount;
public SpriteText fieldName;
public UIProgressSlider slider;

protected UI_TextRange progBarControl
{
get
{
return (UI_TextRange)control;
}
}

public UIPartActionTextRange()
{
}

private void Awake()
{
slider.SetValueChangedDelegate(new EZValueChangedDelegate(OnValueChanged));
}

private float GetFieldValue()
{
if (!this.isModule)
{
return this.field.GetValue<float>((object)this.part);
}
else
{
return this.field.GetValue<float>((object)this.partModule);
}
}

private void OnValueChanged(IUIObject obj)
{
this.tmpValue = Mathf.Lerp(0, this.progBarControl.valueSet.Length, this.slider.Value);
this.offset = this.tmpValue % 1;
if (this.offset != 0.0)
{
if (this.offset < 0.5)
{
this.realValue = this.tmpValue - this.offset;
}
else
{
this.realValue = this.tmpValue + 1 - this.offset;
}
}
else
{
this.realValue = this.tmpValue;
}
this.slider.Value = Mathf.InverseLerp(0, this.progBarControl.valueSet.Length, this.realValue);
this.realValue = (float)Math.Round(this.realValue, 5);
this.field.SetValue(this.realValue, this.field.host);
if (this.scene == UI_Scene.Editor)
{
this.SetSymCounterpartValue((object)this.realValue);
}
}

private void SetSliderValue(float rawValue)
{
this.slider.Value = Mathf.Clamp01(rawValue / this.progBarControl.valueSet.Length);
}

public override void Setup(UIPartActionWindow window, Part part, PartModule partModule, UI_Scene scene, UI_Control control, BaseField field)
{
base.Setup(window, part, partModule, scene, control, field);
this.SetSliderValue(this.GetFieldValue());
this.slider.AddValueChangedDelegate(new EZValueChangedDelegate(this.OnValueChanged));
this.slider.ignoreDefault = true;
}

public override void UpdateItem()
{
this.realValue = this.GetFieldValue();
this.fieldName.Text = this.field.guiName;
this.fieldAmount.Text = this.progBarControl.valueSet[(int)realValue];
this.SetSliderValue(this.realValue);
}
}
}

Edited by Biotronic
More info, also a line had disappeared.
Link to comment
Share on other sites

After giving up on my previous idea, I had a new one: How's about I just find that slider and change the text on it? So I do:


public void UpdateWindowText()
{
var win = FindObjectsOfType<UIPartActionWindow>()
.Where(a => a.part == part).FirstOrDefault();
if (win == null)
return;
var widget = win.GetComponentsInChildren<UIPartActionFloatRange>()
.Where(a => a.Control == UiControl)
.FirstOrDefault();

if (widget == null)
return;

widget.fieldAmount.text = "Hello world!";
}

And it works! ...sorta. I do get the text there, but it's immediately overwritten on the next frame. I guess UIPartActionItem.UpdateItem() is called every frame and recalculates it all?

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...