Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Code has to be in a function not just directly in the class definition. You need to arrange for it to be run somehow. Assuming your code doesn't actually look like the above and you have a function that is being called periodically you should be able to use:

foreach(Vessel thisVessel in FlightGlobals.Vessels.Where(v => (v.vesselType == VesselType.SpaceObject)))
{
// Do whatever you want to with the thisVessel variable, e.g. check what it is orbiting, check if the orbit hits the planet etc.

}

If you don't have a working framework for your plugin then I suggest you grab one of the very useful, prebuilt example plugin frameworks that are available and work from there...

Edited by Padishar
Link to comment
Share on other sites

Also, you need to give an identifier to be used for the vessel in the foreach loop.

For example:

foreach (Vessel oneOfTheVessels in FlightGlobals.Vessels)
{
Debug.Log(oneOfTheVessels.vesselName);
}

There's some more info on foreach loops here.

Edited by pizzaoverhead
Link to comment
Share on other sites

How do i know the drain rate of a resource in a vessel? Preferably without taking into account the production rate.

Also how do i know how much of a part there is on a vessel? I think there is a part list.

That's not going to be easy. You'll need to calculate it manually I think. Basically, you'll need through loop all the parts in a vessel, get the amount of each result, and then calculate that again on the next frame, substract both, divide by the time between frames, and you'll get drain rate. However that will include resource creation.

For the part count, yes, there's vessel.parts, which is what you're looking for.

EDIT:

there this should do it:

        public Dictionary<PartResourceDefinition, double> resources = new Dictionary<PartResourceDefinition, double>();

public Dictionary<PartResourceDefinition, double> GetResourceRates(Vessel vessel)
{
Dictionary<PartResourceDefinition, double> amounts = new Dictionary<PartResourceDefinition, double>(), rates = new Dictionary<PartResourceDefinition, double>(); ;

foreach(PartResource resource in vessel.parts.SelectMany(p => p.Resources.list))
{
if(!amounts.ContainsKey(resource.info))
{
amounts.Add(resource.info, resource.amount);
}
else
{
amounts[resource.info] += resource.amount;
}
}

foreach (PartResourceDefinition resource in amounts.Keys)
{
if (resources.Count <= 0)
{
rates.Add(resource, 0);
continue;
}

double oldAmount = resources[resource], newAmount = amounts[resource];
double realRate = (oldAmount - newAmount) / TimeWarp.fixedDeltaTime;
rates.Add(resource, realRate);
}

resources = amounts;
return rates;
}

And for part count, vessel.parts.Count is all you need :)

Edited by stupid_chris
Link to comment
Share on other sites

That's not going to be easy. You'll need to calculate it manually I think. Basically, you'll need through loop all the parts in a vessel, get the amount of each result, and then calculate that again on the next frame, substract both, divide by the time between frames, and you'll get drain rate. However that will include resource creation.

For the part count, yes, there's vessel.parts, which is what you're looking for.

EDIT:

there this should do it:

(code)

And for part count, vessel.parts.Count is all you need :)

What is this dictionary stuff at the beginning?

Also another question: how do i know the resource information about a Part? I need to code a PartModule to know what/how much resources it can contain, the current amount of a certain resource, etc.

GetConnectedResources() is what i am looking for? How do i use it? If you look at this API there is an int argument called resourceID. What it is used for?

If i want to know how much of ElectricCharge a certain Part currently has, for example, what i would need to do?

Edited by ThermalShark
Link to comment
Share on other sites

I decided to go with foreach as I understand it slightly better than LINQ, my question is within the foreach loop, do I put another foreach with in the first that says foreach asteroid with periapsis > 30K within Kerbins reference frame? Is there a with operator in C#? Or something similar? Still very confused about it, but at least I understand how the foreach loop works in the first bit of code.

Link to comment
Share on other sites

What is this dictionary stuff at the beginning?

Also another question: how do i know the resource information about a Part? I need to code a PartModule to know what/how much resources it can contain, the current amount of a certain resource, etc.

GetConnectedResources() is what i am looking for? How do i use it? If you look at this API there is an int argument called resourceID. What it is used for?

If i want to know how much of ElectricCharge a certain Part currently has, for example, what i would need to do?

I figured the resources out. I noticed GetConnectedResources() returns void, so i looked harder and found the property Part.Resources (i had not seen it before because i only looked at the functions and variables). But i still have questions: Is Part.Resources a list of PartResources? If yes, are the PartResources sorted in a certain way on the list? If i wanted to know the amount of ElectricCharge, would i need to loop through all PartResources seeing their names until i found the ElectricCharge?

I still don't know what the dictionary stuff is, though.

Edited by ThermalShark
Link to comment
Share on other sites

Is Part.Resources a list of PartResources? If yes, are the PartResources sorted in a certain way on the list? If i wanted to know the amount of ElectricCharge, would i need to loop through all PartResources seeing their names until i found the ElectricCharge?

Actually, worse: it is a PartResourceList, instead of a List<PartResource>. This means that most of the sweet things that a list can do aren't supported: in particular, since you can't use Select() and similar, you will have to loop through every item:


foreach (PartResource p in part.Resources)
{
if (p.resourceName == "ElectricCharge") //do stuff;
}

... unless there's a better method that I didn't find yet.

Link to comment
Share on other sites

Actually, worse: it is a PartResourceList, instead of a List<PartResource>. This means that most of the sweet things that a list can do aren't supported: in particular, since you can't use Select() and similar, you will have to loop through every item:


PartResourceList partResources = ...
IEnumerable<Part> batteries = partResources.list.Where(r => r.resourceName == "ElectricCharge").Select(r => r.part);

Link to comment
Share on other sites

Now i need to know what is the best way to drain or add a resource. I want to drain only from a single part, without automatically pumping stuff from other parts. In the KSP API, here is what i found about the subject, all on the Part class:


//FUNCTIONS:
virtual bool DrainFuel (float amount)
virtual bool RequestFuel (Part source.float amount, uint reqId)

double RequestResource(int resourveID, double demand)
float RequestResource(int resourveID, float demand)
double RequestResource(string resourceName, double demand)
float RequestResource(string resourceName, float demand)

double TransferResource (int resourceID, double amount)

But i believe all of the above, if they work, will pump fuel from other parts, so the only way might be using one of those:


void GetConnectedResources (int resourceID,List<PartResource>resources)

OR

//this is a property:
PartResourceList Resources [get]

Then directly adding or subtracting the amount. But i have many of questions about these:

Does the first even work? The API says it returns void, so i don't think it works.

And what is with the resourceID argument?

About the second: As Ippo said, it's type is PartResourceList, not List<PartResource>, but there is not a page about the PartResourceList type on the API. I think this means i can't do something like that:

part.Resources[0]

to refer to the first element in the list. Can someone confirm all these stuff?

Link to comment
Share on other sites

I figured the resources out. I noticed GetConnectedResources() returns void, so i looked harder and found the property Part.Resources (i had not seen it before because i only looked at the functions and variables). But i still have questions: Is Part.Resources a list of PartResources? If yes, are the PartResources sorted in a certain way on the list? If i wanted to know the amount of ElectricCharge, would i need to loop through all PartResources seeing their names until i found the ElectricCharge?

I still don't know what the dictionary stuff is, though.

Basically, a dictionary is a list that stores key/values pairs. In this case, the keys are PartResourceDefinitions (resource info) and the values doubles (the amount of that resource). It's by far the best way to store pairs, as a a key/value pair is always boudn together.

Actually, worse: it is a PartResourceList, instead of a List<PartResource>. This means that most of the sweet things that a list can do aren't supported: in particular, since you can't use Select() and similar, you will have to loop through every item:

Nah, you can just do part.Resources.list and it returns a List<PartResource> which is a copy of what you had.

Now i need to know what is the best way to drain or add a resource. I want to drain only from a single part, without automatically pumping stuff from other parts. In the KSP API, here is what i found about the subject, all on the Part class:


//FUNCTIONS:
virtual bool DrainFuel (float amount)
virtual bool RequestFuel (Part source.float amount, uint reqId)

double RequestResource(int resourveID, double demand)
float RequestResource(int resourveID, float demand)
double RequestResource(string resourceName, double demand)
float RequestResource(string resourceName, float demand)

double TransferResource (int resourceID, double amount)

But i believe all of the above, if they work, will pump fuel from other parts, so the only way might be using one of those:


void GetConnectedResources (int resourceID,List<PartResource>resources)

OR

//this is a property:
PartResourceList Resources [get]

Then directly adding or subtracting the amount. But i have many of questions about these:

Does the first even work? The API says it returns void, so i don't think it works.

And what is with the resourceID argument?

About the second: As Ippo said, it's type is PartResourceList, not List<PartResource>, but there is not a page about the PartResourceList type on the API. I think this means i can't do something like that:

part.Resources[0]

to refer to the first element in the list. Can someone confirm all these stuff?

You really don't want to do that. Doing that would mean bypassing fuel flow logic, and that's a very bad idea unless you're really 100% sure that this is the sole and only solution to your problem. Seriously, there's an implemented fuel flow logic, better use it.

part.RequestResource() is pretty much the best way to drain/refill the amount of resources in a ship.

Now for some more clear explanation of the dictionary madness earlier:

There's really no simple way to get resource flow rate. There's no hook for you to get into really. So you /need/ to compute how much resources have changed from the last frame and then figure out the change rate. However, this isn't as easy again, because resources are stored individually in each part, there is not "global" container for the whole vessel. So if you want to know how much resources are in the vessel, you need to compute how much of each resource is in each part and the same resources together. So, since you don't know how many resources are in the vessel, you'll need to store them into a list. But then, since a list isn't good enough since it only lets you store one element, this is where dictionary comes in. So instead of simply storing the resources, or storing amounts with no name, you can store pairs of resources/amount.

Basically, in what I wrote, the first line is just a field that contains the amount of resources in the vessel from the last frame. The GetResourcesRate(Vessel) method does three things:

1) Figure out how much resources are in the vessel right now

2) Store that into a dictionary for the next frame

3) Return a dictionary containing resource flowing rate

So basically you'll want to use it somewhat like this:

        private void FixedUpdate()
{
Dictionary<PartResourceDefinition, double> rates = GetResourceRates(this.vessel);

foreach(PartResourceDefinition resource in rates.Keys)
{
print("Resource: " + resource.name);
print("Rate: " + rates[resource]);
print("Current amount: " + resources[resource]);
}
}

So with only that, you can know the flow rate of each resource, and how much of each is in the ship. You could do the same individually for parts with the same logic, but once again, I really don't reccomend you to try to handle resource flow yourself.

Link to comment
Share on other sites

[...]

You really don't want to do that. Doing that would mean bypassing fuel flow logic, and that's a very bad idea unless you're really 100% sure that this is the sole and only solution to your problem. Seriously, there's an implemented fuel flow logic, better use it.

part.RequestResource() is pretty much the best way to drain/refill the amount of resources in a ship.

[...]

I see that RequestResource returns a double or float.

But what exactly RequestResource does? It pumps resources from other parts? Or drains from the part and returns what it drained so i can add it directly to the PartResource.amount of another part? Or it is used to create/destroy resources? And what i do with what it returns?

Please explain me how i can do all these stuff:

- Pump resources around

- Create resources

- Destroy resources

Link to comment
Share on other sites

RequestResource drains the amount of resource from the parts of the vessel according to fuel flow logic. Negative amounts work, so it can also be used to refil. If you want to create/destroy resources, simply creating a new PartResource() and then setting the fields correctly should do it, as well as using Destroy() to remove resources.

Link to comment
Share on other sites

I see that RequestResource returns a double or float.

But what exactly RequestResource does? It pumps resources from other parts? Or drains from the part and returns what it drained so i can add it directly to the PartResource.amount of another part? Or it is used to create/destroy resources? And what i do with what it returns?

Please explain me how i can do all these stuff:

- Pump resources around

- Create resources

- Destroy resources

Chris's stuff is on the money. One other thing to look at might be some existing code:

Just note that in the code links thats just the actual transfer stuff, and in TaranisElsu's case there is a dump part there. There are others too like Kethane, so maybe looking through some of those as examples might help.

Link to comment
Share on other sites

[...] If you want to create/destroy resources, simply creating a new PartResource() and then setting the fields correctly should do it, as well as using Destroy() to remove resources.

When i said create/destroy resources, i meant adding or subtracting amounts of a resource to a existing PartResource. But just out of curiosity, can i do this:?


private PartResource pr = new PartResource();

//(set up stuff like resourceName, maxAmount, etc)

part.Resources.list.Add(pr)


RequestResource drains the amount of resource from the parts of the vessel according to fuel flow logic. Negative amounts work, so it can also be used to refil. [...]

Thanks. RequestResource will return the amount of resource it has drained, right?

My problem has been solved (for now), but if wanted to drain 30 LiquidFuel from a tank, without ever affecting other parts, i could not use RequestResource because if the tank only had 20 LF, i would drain 10 from other parts. In that case the only option would be to directly modify PartResource.amount, right? (maybe disabling crossfeed could not be an option, because i could need to transfer unrelated resources through the part, or if i needed fuel lines to not be able to pump from the part.)

Link to comment
Share on other sites


PartResourceList partResources = ...
IEnumerable<Part> batteries = partResources.list.Where(r => r.resourceName == "ElectricCharge").Select(r => r.part);

Thanks man, I didn't know it :)

Incidentally, it's going to be very useful to me too.

Link to comment
Share on other sites

Hey guys, Just skimmed through the forums and thought I might ask for some advice.

I'm interested in relaunching my Ion Cannon mod now with the new mod/plugin section (it's been a while)

I'd like to move past or ignore the old 'overheating' method and simply destroy the target that's more then 2.5km away (asteroids too?)

What I'd like to know is if there's code to delete objects in space, and how to check that the ship has direct line of sight.

I'm not a skilled coder, so tutorials or code snippets would be great.

If you'd like to collab, my skype is digi_byte

Link to comment
Share on other sites

When i said create/destroy resources, i meant adding or subtracting amounts of a resource to a existing PartResource. But just out of curiosity, can i do this:?


private PartResource pr = new PartResource();

//(set up stuff like resourceName, maxAmount, etc)

part.Resources.list.Add(pr)


Most likely yes.

Thanks. RequestResource will return the amount of resource it has drained, right?

Exactly.

My problem has been solved (for now), but if wanted to drain 30 LiquidFuel from a tank, without ever affecting other parts, i could not use RequestResource because if the tank only had 20 LF, i would drain 10 from other parts. In that case the only option would be to directly modify PartResource.amount, right? (maybe disabling crossfeed could not be an option, because i could need to transfer unrelated resources through the part, or if i needed fuel lines to not be able to pump from the part.)

And again, I don't think you want to do that unless it'S for a very specific type of thing where you absolutely need to do that and there's no other solution. You really don't want to be bypassing resource flow, because incidentally you might drain something that flow logic wouldn't allow and that's not always good.

Link to comment
Share on other sites

Welp, Decided to give MonoDevelop now known as Xamarin a go as my main Program. After following the Wiki and the tutorial basic tutorial I get some errors.

Error CS0103: The name 'RenderManager' does not exist in the current context (CS0103)

Error CS0103: The name 'Highlogic' does not exist in the current context (CS0103)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace IonStormCommand
{
public class IonStormCommand : PartModule
{
private Rect _windowPosition = new Rect();
private GUIStyle _windowStyle, _labelStyle;
private bool _initStyles = false;


public override void OnStart(StartState state)
{
if (state != StartState.Editor)
{
if (!_initStyles) InitStyles();
RenderManager.AddToPostDrawQueue (0, OnDraw);
}
}

private void OnDraw()
{
if (this.vessel == FlightGlobals.ActiveVessel)
_windowPosition = GUILayout.Window(10, _windowPosition, OnWindow, "This is the Title", _windowStyle);
}

private void OnWindow(int windowID)
{
GUILayout.BeginHorizontal();
GUILayout.Label("this is a label", _labelStyle);
GUILayout.EndHorizontal();
GUI.DragWindow();
}

private void InitStyles()
{
_windowStyle = new GUIStyle(Highlogic.Skin.window);
_windowStyle.fixedWidth = 250f;

_labelStyle = new GUIStyle(Highlogic.Skin.label);
_labelStyle.stretchWidth = true;

_initStyles = true;
}


}
}

I must be doing something obvious wrong.

Link to comment
Share on other sites

Since we are talking about resources, how can I add one to an EVA kerbal?

I'm looking at the source for TAC life support, but I don't really understand exactly how and when he does it.

Right now I am doing this: if the active vessel is an eva, look for a part named "kerbalEVA" and add the resource. However, I always stop at the log line telling me that it couldn't find a part with that name... what am I doing wrong?

EDIT: forgot to say that I don't want the transfer to be automatic, like in TACLS, but it must happen on an event. You go to the part, activate the event, and receive your spare parts.

EDIT AGAIN: ok, so after putting debug lines everywhere, I found out the source of the problem. Even when ActiveVessel.isEVA, the ActiveVessel is not the EVA kerbal, thus the code I had posted is awfully wrong.

Edited by Ippo
Link to comment
Share on other sites

Welp, Decided to give MonoDevelop now known as Xamarin a go as my main Program. After following the Wiki and the tutorial basic tutorial I get some errors.

Error CS0103: The name 'RenderManager' does not exist in the current context (CS0103)

Error CS0103: The name 'Highlogic' does not exist in the current context (CS0103)

---snip---

I must be doing something obvious wrong.

I guess you have added UnityEngine.dll as a reference (or it would be complaining about lots of other stuff too) but have you added Assembly-CSharp.dll (which contains the main KSP code)?

Edit: Actually it looks like your names are just wrong. They should be HighLogic (capital L) and RenderingManager...

Edited by Padishar
Link to comment
Share on other sites

Ok, I managed to find the active EVA and add a resource to it.

However, this resource doesn't show up in the resource panel... does anybody know why this could be?

Link to comment
Share on other sites

Ok, I managed to find the active EVA and add a resource to it.

However, this resource doesn't show up in the resource panel... does anybody know why this could be?

Not sure, but I remember reading about them being Private variables, but you could use Unity code to hack it if KSP doesn't have any nodes or w/e their called

My guess would be that the Kerbals when EVA don't share their resource information apart from when you hover the mouse over them.

In other news I think I'm trying to tackle a problem that's a bit big for an noob like me to tackle.

I realized I want a list of targets for my plugin, looking at the scripts prior but can't figure out how I would use it.

Ideally I would have buttons or a roll-out and a search feature that would list targets in a select-able list...

but that's insane, I wouldn't even know where to start.

I believe a enum list would be a start, then a target button to tell the ship to target that, then an align button to tell the ship to align

enum Mode {Mode1, Mode2, Mode3}
var mode : Mode;

Edited by DIGI_Byte
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...