Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

They're static relative to the part. As sarbian says, the position of the origin changes. Five units right of the part will always be five units right of the part: relative positions are preserved. But absolution position is not preserved, because the very origin of the universe shifts (to avoid FP issues). Always rely on relative positions, not absolute positions.

Link to post
Share on other sites
Check in GameParameters, it holds all of the difficulty settings. The sub-class CareerParams has most of the relevant career mode options (rewards, science, starting amounts, etc...).

GameParameters.GetDefaultParameters() will give you the the default parameters for a given game type and difficulty level.

OK thanks, I found it. Is anyone able to save me hours of banging my head against a wall and show me how to reference that? All I want to do is change the default variable value, and that is all the C# I need to touch. I don't care if the player changes it again at run time with the slider, as long as it is initially set to this value.

The instance of CareerParams is named "Career"

namespace mymod {
public class mymod : MonoBehaviour {
Career.StartingScience = 10.0f;
}
}

C# makes me want to strangle someone, especially since I know how to write scripts inside of classes, but the referencing drives me insane.

Link to post
Share on other sites
They're static relative to the part. As sarbian says, the position of the origin changes. Five units right of the part will always be five units right of the part: relative positions are preserved. But absolution position is not preserved, because the very origin of the universe shifts (to avoid FP issues). Always rely on relative positions, not absolute positions.

Thanks, but right now this is the only code I have for positioning:


GameObject launchPos = new GameObject();
Vector3 worldPosition = _srcPart.transform.TransformPoint(_spawnOffset);
launchPos.transform.position = worldPosition;
Transform launchTransform = launchPos.transform;
_newConstructRootPart.localRoot.transform.Translat e(launchTransform.position, Space.World);

And it still results in the same warping (notice it spawns at -15m in the debug log?)

You even explained it quite nicely here: http://forum.kerbalspaceprogram.com/threads/105756-transform-position-changes-after-revert-flight-to-launch

And there's a solution too, yet I still can't fathom it or get it to work properly. Seems so simple

Edited by TAz00
Link to post
Share on other sites

Hey all, Nifty here.

I have a question about getting something to run during any scene in which game time is running. I've gathered that I'm going to need to use KSPScenario and ScenarioModule, but I'm not sure on how to detect the passage of time during the update loop. I need this in order to run part failure calculations for vessels that are unloaded (for my part failure mod Kerbal Mechanics). I just did some testing with HighLogic.CurrentGame.universalTime, but that appears not to move at all at least up to 5 decimals for whatever reason...

Link to post
Share on other sites

Blarg.

I tried to find this myself, but to no avail, so here I am asking again: Does anyone know how to check programmatically whether a solar panel is open, closed, or broken as well as how to change these properties?

Link to post
Share on other sites
Blarg.

I tried to find this myself, but to no avail, so here I am asking again: Does anyone know how to check programmatically whether a solar panel is open, closed, or broken as well as how to change these properties?

ModuleDeployableSolarPanel.panelState, and ModuleDeployableSolarPanel.Extend()/Retract()/breakPanels().

Un-breaking panels is probably nontrivial.

Link to post
Share on other sites

Is there a faster way to do incremental changes to a plugin then compiling, starting KSP, testing, shutting down KSP, making changes, repeat? I cannot reload the plugin because the dll is locked so I cannot copy the new version over to reload it. I'm spending more time reloading KSP than actually doing plugin dev currently.

Also: is there a way to get the closest approach of a vessel to a target, including maneuver node(s)?

Edited by The Lone Wolfling
Link to post
Share on other sites

How would I make something like a UI_FloatRange for a KSPField that would allow for nonlinear step increments? Specifically, I am trying to make a multiplier for various rover wheel settings that follows an exponential step size so that numbers less than 1 get the same space on the slider as numbers greater than 1.

My current code is

[KSPField(isPersistant = true, guiActive = false, guiActiveEditor = true, guiName = "Spring Multiplier"), UI_FloatRange(minValue = 0f, maxValue = 5f, stepIncrement = 0.1f)]

How would I change this to create a nonlinear slider?

Edited by roflmaoqwertyqaz
Link to post
Share on other sites

The Lone Wolfling : no and here

kenbob5588 : Unity and partool are for making model. Wrong thread and subforum but you would need Unity 4.2.2 for making parts.

belac : sorry, can't open your link from work :(

roflmaoqwertyqaz : no. you would have to define your own control like KSPAPIEL does

Link to post
Share on other sites

Model preview icons in the VAB/SPH (that spin when you hover over them). What do I look for in the API for doing something similar in a plug-in myself? (I'm wanting to do a preview of a static in Kerbal Konstructs.)

Link to post
Share on other sites

There isn't anything in the API accessible that I know of but it's easy enough to set up yourself. Example:

[KSPAddon(KSPAddon.Startup.MainMenu, true)]
public class PartModelPreviewer : MonoBehaviour
{
private const int PreviewWidth = 200;
private const int PreviewHeight = 200;
private const int RenderLayer = 8;
private const float PreviewTime = 2f;
private const float PreviewRevolutionRate = 180f;
private const float TargetPreviewSize = 0.7f; // size 1 would take up the whole vertical camera space

private string _current = "<None>";

private void Start()
{
gameObject.AddComponent<Camera>();

camera.cullingMask = (1 << RenderLayer);
camera.clearFlags = ~CameraClearFlags.Nothing;
camera.nearClipPlane = 0.1f;
camera.farClipPlane = 10f;
camera.orthographic = true;
camera.backgroundColor = new Color(0f, .7f, 0f, 0f);

camera.orthographicSize = 0.5f;
camera.pixelRect = new Rect(0f, Screen.height - PreviewHeight, PreviewWidth, PreviewHeight);

transform.position = new Vector3(0f, 0f, -8f);
transform.LookAt(Vector3.zero, Vector3.up);

StartCoroutine(Cycle());
}


private IEnumerator Cycle()
{
while (true)
{
foreach (var part in PartLoader.LoadedPartsList.Where(ap => ap.iconPrefab != null))
{
_current = part.name;

var go = (GameObject) Instantiate(part.iconPrefab);
go.SetLayerRecursive(RenderLayer);


go.SetActive(true);

var bounds = go.GetRendererBounds();
float multiplier = TargetPreviewSize / Mathf.Max(bounds.size.x, bounds.size.y, bounds.size.z);

go.transform.localScale = Vector3.one*multiplier;
go.transform.rotation = Quaternion.AngleAxis(-30f, Vector3.right);

transform.position = new Vector3(transform.position.x, bounds.center.y, transform.position.z);

go.transform.parent = transform;


yield return StartCoroutine(Preview(go));

Destroy(go);
}
}
}


private IEnumerator Preview(GameObject previewObject)
{
float start = Time.time;

while (Time.time - start < PreviewTime)
{
yield return 0;

previewObject.transform.Rotate(Vector3.up, Time.deltaTime * PreviewRevolutionRate);
}
}


private void OnGUI()
{
GUI.Label(new Rect(0, 0, 200f, 20f), "Displaying " + _current);
}
}

Link to post
Share on other sites
The Lone Wolfling : no and here

Drat. And that's a good start, I suppose. Though, what, I'll have to walk the active vessel and target orbits and check distance? That's O(n^2), potentially.

Also, that seems to contradict the stock "closest approach" on occasion.

Do I really have to reinvent the wheel to that extent, though? The game does basically what I want already to display the closest approach(es).

Link to post
Share on other sites

Alright, I'm a little stuck. I'm trying to modify an attribute of a class, but I'm having a hard time how to work that out.

It's the collectWarningText string in the ModuleScienceExperiment class. I think I would have to make the change inside the CollectDataExternalEvent function, but I don't know the syntax for working with attributes, can't find an example of it, and I'm just making myself more and more confused. I feel like I'm getting further and further from the solution. Right now I'm at:


using UnityEngine;


namespace ScienceWarning
{

[INDENT]public class ScienceWarning : ModuleScienceExperiment
{[/INDENT]


[INDENT=2]private string _testString = "Test String";

public override void OnStart(PartModule.StartState state)
{[/INDENT]
[INDENT=3]this.CollectDataExternalEvent();[/INDENT]
[INDENT=2]}[/INDENT]

[INDENT]}[/INDENT]


}

If someone could help with a little direction or let me know of an existing example I could look at, I would greatly appreciate it :)

Edit: I've been looking for how to do this in the documentation here, as well as using the object viewer in Visual Studio.

Edited by LittleBlueGaming
Link to post
Share on other sites

@LittleBlueGaming: What your code there is is a new partModule named ScienceWarning. If you are not adding it to a part then it will do nothing.

You can't actually change the code of ModuleScienceExperiment itself, you can however change the values in a ModuleScienceExperiment class after KSP loads however.

If .collectWarningText is a KSPField, then you can do the change via a ModuleManager patch without needing a plugin.

I suspect it is not a KSPField however, so things get trickier.

I'd start by trying something like the following:

In a KSPAddon.MainMenu class, take the OnStart() method and cycle through every ProtoPart in the part loader.

If that ProtoPart has the ModuleScienceExperiment partModule, change the ModuleScienceExperiment's .collectWarningString to "Test String".

This will make all parts in the game across all vessels have "Test String", you can add filters and such if you only want to change it on some parts, a different string for different parts, etc.

I can't remember the actual code grammar from memory, but I did use the correct terms so you should be able to find examples pretty easily with google.

Hope that helps,

D.

Link to post
Share on other sites

Alright, modifying jamespicone's example here, I've got this:


[KSPAddon(KSPAddon.Startup.MainMenu, false)]
public class ScienceWarning : PartModule
{
public override void OnAwake()
{
foreach (AvailablePart a in PartLoader.LoadedPartsList)
{
if (a.partPrefab.Modules != null)
{
foreach (PartModule m in a.partPrefab.Modules)
{
if ( a.partPrefab.Modules.Contains("ModuleScienceExperiment") && a.partPrefab.name == "GooExperiment" )
{
Debug.Log("LB Log: Found Experiment in: " + a.name);
var modA = a.partPrefab.Modules.GetModule(1);
Debug.Log(modA);
}
}
}
}
}
}

Debug menu gives me


[Log]: LB Log: Found Experiment in: GooExperiment
[Log]: GooExperiment (ModuleScienceExperiment)

So it seems that I have the right thing stored in modA, and somehow I should be able to change the warning text attribute in it... however I can't figure out how to do that.

If I've gone down the completely wrong path again, maybe I should stick to blowing up rockets :P

Link to post
Share on other sites

You are close:


[KSPAddon(KSPAddon.Startup.MainMenu, false)]
public class ScienceWarning : PartModule
{
public override void OnAwake()
{
foreach (AvailablePart a in PartLoader.LoadedPartsList)
{
if (a.partPrefab.Modules != null)
{
foreach (PartModule m in a.partPrefab.Modules)
{
if ( m.moduleName == "ModuleScienceExperiment" && a.partPrefab.name == "GooExperiment" ) //change this to check the partmodule 'm' we are actually on.
{
Debug.Log("LB Log: Found Experiment in: " + a.name); //check we've found the correct partModule
//var modA = a.partPrefab.Modules.GetModule(1); //we already have this reference as partModule 'm' from the foreach. Note that this line was wrong, the GetModule(1) would return the second partModule in the list, not the ModuleScienceExperiment module. (The Modules list is zero-index.)
//Debug.Log(modA);
ModuleScienceExperiment sciExp = (ModuleScienceExperiment) m; //convert from type PartModule to type ModuleScienceExperiment as .collectWarningText lives there
sciExp.collectWarningText = "YourCustomWarningHere"; //change the value you are looking for.
}
}
}
}
}
}

And then any vessel that has a goo experiment on it should inherit this modified part in the part loader and display your custom message.

D.

Edited by Diazo
Link to post
Share on other sites

It works perfectly, thanks.

I was having a hard time figuring out how to filter just that module, so I was planning on constructing a loop for the goo and another for the materials study. I was trying to use IndexOf to get the module index but couldn't get that to work.

Converting types was the biggest thing I was missing, I wasn't even aware that was something I needed to do. You've given me a lot to think about :)

Link to post
Share on other sites

Ya, inheritance is one of the more non-intuitive parts of C#. It is well documented however with many examples out there if you google it. Casting (converting types) is a big part of managing data in C# that will come up again.

On the IndexOf and GetModule methods, I would recommend staying away from them and use the .moduleName string compare instead. I say this because when other mods add their own partModules to a part, it is quite likely that the location of your own partModule will change in the part.Modules list.

So the index number that returns your part module on your machine would return the partModule for random ModX that is installed on another player's machine.

D.

Link to post
Share on other sites

Am i right in assuming [KSPField] does not support ints?

I wanted to store an enum as an int in persistence in the past but i had to use a float instead. Flooring the number to int then enum each time its loaded from persistence. This the best way to do it? Or is using a string better? In my noobish ways i assumed floats process faster than strings.

Link to post
Share on other sites

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...