Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

There are no conversions of any sort that happens that removes data when you cast a reference type to it's base type. It is just that while it has been casted it will no longer appear to be what it actually is unless you cast it back again. During runtime however, it will always be the same object. Information is never lost.

public class A
{
public string Name = "I'm A";
}

public class B : A
{
public string OtherName = "I'm also B";
}

public class C : A
{
public string SpecialName = "It's a me, C!";
}

public static void Test()
{
var listA = new List<A>();
listA.Add(new A());
listA.Add(new B());
listA.Add(new C());

foreach (var item in listA)
{
Console.Write(item.Name);
var theB = item as B;
if (theB != null)
{
Console.WriteLine(theB.OtherName);
}
if (item is C)
{
Console.WriteLine(((C)item).SpecialName);
}
}
}

// OUTPUT:
// I'm A
// I'm A
// I'm also B
// I'm A
// It's a me, C!

This is called Polymorphism, and is a very important part of object-oriented programming. I can recommend reading about it, Microsofts MSDN article on the topic is a good start.

Edited by Uzza
Link to comment
Share on other sites

Thanks, I didn't knew that. :)

But I have one more question:

If I would change your code to this: (C extending B)

public class A
{
public string Name = "I'm A";
}

public class B : A
{
public string OtherName = "I'm also B";
}

public class C : B //<--- now extending B
{
public string SpecialName = "It's a me, C!";
}

public static void Test()
{
var listA = new List<A>();
listA.Add(new A());
listA.Add(new B());
listA.Add(new C());

foreach (var item in listA)
{
Console.Write(item.Name);
var theB = item as B;
if (theB != null)
{
Console.WriteLine(theB.OtherName);
}
if (item is C)
{
Console.WriteLine(((C)item).SpecialName);
}
}
}

What would the Output be for the C-instance?

Does C contains the members of A and B?

Link to comment
Share on other sites

What would the Output be for the C-instance?

Does C contains the members of A and B?

The inheritance chain can keep going in infinity, however at some point you will have such a deep hierarchy that any calls to a member causes a stackoverflow error.

Since the Test function first prints A, then checks if it's B and then prints, and finally checks if it's C and prints, it's output will be:

//OUTPUT
// I'm A
// I'm also B
// It's a me, C!

Edited by Uzza
Link to comment
Share on other sites

The inheritance chain can keep going in infinity, however at some point you will have such a deep hierarchy that any calls to a member causes a stackoverflow error.

I don't believe it is the calling of the member function that causes the stack overflow as that should just be a simple, single function call. The problem will come when you first create the object as that will call the default (compiler generated because you don't explicitly define it yourself) constructor function for the class which will begin by calling the base class first. The base class constructor function will call its base class and so on all the way down the hierarchy which will fill up the stack...

Of course, there is absolutely no reason, in practice, to ever create a class hierarchy that is anywhere near that deep so the point is rather moot, but meh...

Link to comment
Share on other sites

Hello,

Someone found out how to destroy / make buildings explode in c#? I'm building a mod that should be able to do that... I've tried it as a gameobject from the part collider and then part.explode, but it has no effect.

Greetings,

Gesture.

Link to comment
Share on other sites

What's the best way to get what biome a vessel is in for a science context?

I'm currently doing this:

string biome = vessel.landedAt ?? "";
if (biome == string.Empty) { biome = ScienceUtil.GetExperimentBiome(vessel.mainBody, vessel.latitude, vessel.longitude); }

based on some stuff I've seen in a few other mods. Seems to work fine for getting the biome from the biome map, but getting the special KSP-centre biomes using vessel.landedAt isn't doing what I expect - it's 'Launchpad' for the first few frames, and then it changes to 'KSC_LaunchPad_platform'. Actual ModuleScienceExperiments give 'Launchpad' for the same location, no matter when they're fired.

Is there a better solution than figuring out what all the possible values are and mapping them to the appropriate science-biome-name?

Link to comment
Share on other sites

Hey guys... Is there a way to specify a requirement list for adding a part to a vessel, or a filter on what kind of parts it can be connected to?

For example, I'm planning on adding a barebone surface mounted probe core, without its own reaction wheels, monopropellant tank, batteries or any of that, just the plain control system functionality - mainly to make manned units remote controllable (while power lasts), and equip them with the RT2 flight computer.

I'd like to avoid this being tacked on to a solid fuel rocket with a battery pack, and flown. (Even though this sounds exactly like the sort of thing a kerbal might decide to do.) So I'm wondering if I can configure the part so that it can only be connected to a pod (or only added if the vehicle has a pod).

Link to comment
Share on other sites

You would have to add a simple part module to your part to hold the code, but the logic should be pretty straight forward.

Pseudo logic follows, I'm skipping a lot of the actual code


//run this code in editor only
GameEvent.onPartAttach.Add(YourAttachCheck);

public void YourAttacheCheck(Part p)
{
bool validAttachement = true;
<<Insert your condition checks here turning validAttachment false if it fails the condition>>
if(!validAttachement)
{
p.destroy();
ScreenMessage("Invalid attachement");
}
}

That would require significant expansion to turn into actual working code, but it shows the logic that should work.

Note that this checks at the time the part is attached to the vessel. If you want to check when leaving the edtior that is a bigger deal and I'm not sure how to do it off the top of my head.

D.

Link to comment
Share on other sites

What's the best way to get what biome a vessel is in for a science context?

I'm currently doing this:

string biome = vessel.landedAt ?? "";
if (biome == string.Empty) { biome = ScienceUtil.GetExperimentBiome(vessel.mainBody, vessel.latitude, vessel.longitude); }

based on some stuff I've seen in a few other mods. Seems to work fine for getting the biome from the biome map, but getting the special KSP-centre biomes using vessel.landedAt isn't doing what I expect - it's 'Launchpad' for the first few frames, and then it changes to 'KSC_LaunchPad_platform'. Actual ModuleScienceExperiments give 'Launchpad' for the same location, no matter when they're fired.

Is there a better solution than figuring out what all the possible values are and mapping them to the appropriate science-biome-name?

The solution is Vessel.GetLandedAtString(vessel.landedAt). Don't know why I didn't spot that method earlier, but it does the appropriate renaming.

Link to comment
Share on other sites

I'm looking for a way to detect if a part is currently 'picked up' in the VAB. I would assume it is the 'mouseGrab' field in EditorLogic, but I can't find the way to get a reference to the instance of this singleton class after the latest update. Any insights?

Link to comment
Share on other sites

I'm looking for a way to detect if a part is currently 'picked up' in the VAB. I would assume it is the 'mouseGrab' field in EditorLogic, but I can't find the way to get a reference to the instance of this singleton class after the latest update. Any insights?

EditorLogic.fetch will give you the instance. In Part Angle Display I use:

EditorLogic editor = EditorLogic.fetch;

if (!editor.PartSelected)

...to detect if no part is currently picked up. However, I also check if editor.editorScreen == EditorLogic.EditorScreen.Parts because you can only pick up parts in the "Parts" mode (rather than action groups or crew).

You can see the source here.

Link to comment
Share on other sites

EditorLogic.fetch will give you the instance. In Part Angle Display I use:

EditorLogic editor = EditorLogic.fetch;

if (!editor.PartSelected)

...to detect if no part is currently picked up. However, I also check if editor.editorScreen == EditorLogic.EditorScreen.Parts because you can only pick up parts in the "Parts" mode (rather than action groups or crew).

You can see the source here.

Perfect. The second part of your answer actually is a better way to solve the problem that I have.

Link to comment
Share on other sites

Okay, I'm having trouble keeping track of my ships for my mod and want to move from using the Vessel.ID to using the part.FlightID of the rootPart.

Before I embark on a multi-hour rewrite however, I want to confirm two things:

a) part.FlightID stays the same across game sessions.

B) part.FlightID is guaranteed unique within a game session.

I have done some very basic testing and it looks like this is the case, but I'm hoping there is someone out there who has used it more extensively and can confirm.

For reference, the reason I want to do this is that some of the time when you dock/undock, the FlightGlobals.ActiveVessel object does not change, it simply has the parts of the ship that is docking/undocking add/removed as appropriate from its part tree so my mod is not firing the dock/undock event it needs to.

D.

Link to comment
Share on other sites

I'm trying to detect a Vessel being backgrounded from a PartModule on the Vessel and pass the Vessel ID on somewhere else. When I say 'backgrounded', I mean when the player leaves a vessel in flight and goes to the space center.

From what I can tell PartModule.OnDestroy() gets called when recovering or backgrounding a Vessel, but it's also called all the goddamn time (like twice when starting a flight before there's even a ship on the launchpad), and vessel is sometimes null when it's called - not sure if it's reliable when it is or isn't null by then. OnInactive() doesn't seem to be called for backgrounding. I haven't tried listening for events yet - OnVesselDestroy() seems like the obvious one, but also looks like it'll get a bunch of spurious calls as well. OnVesselLoaded() would be perfect were it not the wrong way around.

Thoughts?

Link to comment
Share on other sites

@jamespicone: If it is only when leaving the flight scene that you need to do this check, the onGameSceneLoadRequested event will do what you need.

If you also need to trigger your event during flight when changing vessels, that is a harder question and one I'm still struggling with myself (as per my previous post).

D.

Link to comment
Share on other sites

I'm looking to make a small modification to the default UI. So far I've only modded parts without much trouble, but I don't even know how to get started with this.

Basically I'm just tired of having to subtract the fuel mass from the total part mass to figure out each part's dry mass. So I want to mod the VAB/SPH part tool tips to display dry mass along with the other stats (mass, drag, crash tolerance and Max temp).

Link to comment
Share on other sites

Is there an ApplicationLauncher example? I am trying to make a simple plugin that will toggle an image using the ApplicationLauncher class, and I don't know what to do. I've looked at this, http://anatid.github.io/XML-Documentation-for-the-KSP-API/class_application_launcher.html#aea384a13ab78885be4800e2334427700 but can't really understand it.

Link to comment
Share on other sites

Hi all,

I'm having some more ConfigNode problems. Hopefully this is something really obvious, but it's driving me nuts. I have a class:

/** Simple implementation of an ordered pair.
*
* Works around the lack of tuple support in .NET 3.5, and can
* do things that KeyValuePair can't
*
* @tparam T The type of the first pair element
* @tparam U The type of the second pair element
*/
internal class Pair<T, U> {
/** Should have a default constructor */
public Pair() {
}
/** Creates a new ordered pair
*
* @param[in] first,second The values to store
*
* @post The new object represents the pair (first, second).
*
* @exceptsafe Does not throw exceptions.
*/
public Pair(T first, U second) {
this.First = first;
this.Second = second;
}
/** The first element of the pair */
[Persistent] public T First { get; set; }
/** The second element of the pair */
[Persistent] public U Second { get; set; }
}

As you can see, its members have the Persistent attribute. Then I try to run

var testNode = new ConfigNode();
ConfigNode.CreateConfigFromObject(new Pair<string, double>("a string", 1.0), testNode);
Debug.Log("Defined Pair: " + testNode);

and the log output is:

Defined Pair: 
{
}

How do I get the class to persist?

Edited by Starstrider42
Link to comment
Share on other sites

Quoted message to make it clear what I'm talking about.

First, can you try naming the config node? I ran into issues using unnamed nodes previously so I'd like to make sure that isn't causing the issue.

var testNode = new ConfigNode();

change to

var testNode = new ConfigNode("DEFINEDPAIR");

This change alone should change the log output to:

Defined Pair: 
{
name = DEFINEDPAIR
}

The other thing to try is change how the object is created.

ConfigNode.CreateConfigFromObject(new Pair<string, double>("a string", 1.0), testNode);

change to

testNode = ConfigNode.CreateConfigFromObject(new Pair<string, double>("a string", 1.0));

Note I have not used this function of ConfigNodes, but those suggestions are what my experience does suggest.

D.

Hi all,

I'm having some more ConfigNode problems. Hopefully this is something really obvious, but it's driving me nuts. I have a class:

/** Simple implementation of an ordered pair.
*
* Works around the lack of tuple support in .NET 3.5, and can
* do things that KeyValuePair can't
*
* @tparam T The type of the first pair element
* @tparam U The type of the second pair element
*/
internal class Pair<T, U> {
/** Should have a default constructor */
public Pair() {
}
/** Creates a new ordered pair
*
* @param[in] first,second The values to store
*
* @post The new object represents the pair (first, second).
*
* @exceptsafe Does not throw exceptions.
*/
public Pair(T first, U second) {
this.First = first;
this.Second = second;
}
/** The first element of the pair */
[Persistent] public T First { get; set; }
/** The second element of the pair */
[Persistent] public U Second { get; set; }
}

As you can see, its members have the Persistent attribute. Then I try to run

var testNode = new ConfigNode();
ConfigNode.CreateConfigFromObject(new Pair<string, double>("a string", 1.0), testNode);
Debug.Log("Defined Pair: " + testNode);

and the log output is:

Defined Pair: 
{
}

How do I get the class to persist?

Link to comment
Share on other sites

[..]

Does Persistent work with Properties? I haven't used it in quite a while but think it only worked on fields. You might want to try this instead:

class ... {
...
/** The first element of the pair */
[Persistent] public T First;
/** The second element of the pair */
[Persistent] public U Second;
}

If you want to use properties for public stuff since its good style you can use private fields fields to save the actual value. C# would do the same for you anyway.

Link to comment
Share on other sites

Does anyone have any idea how ModuleGenerator is persisted?

Context: I have an unloaded Vessel, and I'm trying to determine the OUTPUT_RESOURCE of any ModuleGenerator attached to it. I can quite happily walk the ProtoPartSnapshot tree, dig up ProtoPartModuleSnapshot objects with moduleName == "ModuleGenerator", but then the only data present is the ConfigNode moduleValues, which contains nothing useful:


MODULE
{
name = ModuleGenerator
isEnabled = True
generatorIsActive = True
throttle = 0.5
EVENTS
{
Activate
{
active = False
guiActive = True
guiIcon = Activate Generator
guiName = Activate Generator
category = Activate Generator
guiActiveUnfocused = False
unfocusedRange = 2
externalToEVAOnly = True
}
Shutdown
{
active = False
guiActive = True
guiIcon = Shutdown Generator
guiName = Shutdown Generator
category = Shutdown Generator
guiActiveUnfocused = False
unfocusedRange = 2
externalToEVAOnly = True
}
}
ACTIONS
{
ToggleAction
{
actionGroup = None
}
ActivateAction
{
actionGroup = None
}
ShutdownAction
{
actionGroup = None
}
}
}

and a null moduleRef. But the properties of the module have to be constructible from the persistence data/protovessel stuff, because otherwise you'd save and load and all your RTGs wouldn't work. So where's the info?

Link to comment
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...