Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

It depends on if you are declaring a new object or not, but that's a basic C# question, not a KSP question.

If you are asking questions of that level I would look at finding some C# tutorials online that would get you started. Modding KSP is all done in C#, just through the KSP API, so learning C# is learning to mod KSP.

D.

Link to comment
Share on other sites

Alright thanks a lot! MonoDevelop doesn't seem to complain but just to be sure should I define it as 'ModuleEngines x = part.FindMo...;'? I'm very new to this you see :)

That's correct (if you're just looking for the first one - otherwise you would want a list). But as Diazo mentioned, C# tutorials might be a good place to start with this stuff.

Link to comment
Share on other sites

During a collision I get the collider which I'm colliding with.

For example:

public void OnCollisionStay(Collision c)
{
if (isActive)
{
collidingObject = c.collider.gameObject;
collisionPoint = c.contacts[0];
}
}

Now I want to find the part this collider belongs to.

I came up with this method but it won't find the part:

public Part GetPartByGameObject(GameObject gameObject)
{
Part foundPart = null;

FlightGlobals.Vessels.ForEach(vessel =>
{
foundPart = vessel.Parts.Find(part =>
{
if (gameObject.Equals(part.gameObject))
return true;

return false;
});
});

return foundPart;
}

IMO this should work but it always returns null. What did I do wrong?

Link to comment
Share on other sites

You're making the assumption that the collider is on the same GameObject as a Part, but that's never the case. Instead, Parts are made up of a hierarchy of GameObjects. The top-level one contains logic (ex: PartModules) and rigidbody, then another as a child called model, then beneath that as children are GameObjects with Renderers, Animations, Colliders--all the other things that make up a Part and come from cloned instances of models from GameDatabase.databaseModel

Just look upwards in the hierarchy:

        private Part GetPartFromCollider(Collider c)
{
return c.gameObject.GetComponentInParent<Part>();
}

Edited by xEvilReeperx
Link to comment
Share on other sites

Does anyone know the event when a packed part is remove from the scene?

At the moment I've got this:

		public void OnPartPack()
{
LeaveCamera ();
}

This works but it kicks in at about 500m(?).

OnDestroy doesn't work.

Edit: Fixed it. Just needed to add this to the OnDestroy();

if (sCurrentCamera.vessel != FlightGlobals.ActiveVessel)
{
RestoreMainCamera();
}

Edit2: Actually that didn't work, well it did but it didn't correctly restore the main camera.

So to fix it I added this to update:

			if (sCurrentCamera != null) { // Is the current camera a hullcam
if (sCurrentCamera.vessel != FlightGlobals.ActiveVessel) { // Is it not on the active vessel
Vector3d activeVesselPos = FlightGlobals.ActiveVessel.orbit.getRelativePositionAtUT (Planetarium.GetUniversalTime ()) + FlightGlobals.ActiveVessel.orbit.referenceBody.position; // Calculate active vessel position
Vector3d cameraVesselPos = sCurrentCamera.vessel.orbit.getRelativePositionAtUT (Planetarium.GetUniversalTime ()) + sCurrentCamera.vessel.orbit.referenceBody.position; // Calculate current camera position

sCameraDistance = (activeVesselPos - cameraVesselPos).magnitude; // Calculate the distance between them

if (sCameraDistance >= 2480) { // If distance between them is larger than 2480 then leave the current camera.
LeaveCamera ();
}
}
}

It works perfectly, but maybe someone has an easier way of doing it?

Edited by Albert VDS
Link to comment
Share on other sites

Can someone please tell me how I can get a List of all parts, that have been researched (science mode) and that are purchased (career mode).

Here is what I have now:

foreach (var loadedPart in PartLoader.LoadedPartsList)
{
try
{
if (ResearchAndDevelopment.PartModelPurchased(loadedPart))
{
items.Add(loadedPart);
}
}
catch (Exception)
{
Debug.Log("[OSE] - Part " + loadedPart.name + " could not be added to available parts list");
}
}

I logged the length of the LoadedPartsList and the newly created list called items and they both have the same length no matter how far I am in the tech tree.

Link to comment
Share on other sites

Can someone please tell me how I can get a List of all parts, that have been researched (science mode) and that are purchased (career mode).

I was literally testing such a function just now :)


private static bool partResearched(AvailablePart ap){
if (ResearchAndDevelopment.Instance == null) {
print ("no ResearchAndDevelopment.Instance, must be sandbox mode");
return true;
}
if (!ResearchAndDevelopment.PartTechAvailable(ap)) {
print (ap.name+".PartTechAvailable()==false");
return false;
}

if (!ResearchAndDevelopment.PartModelPurchased (ap)) {
print (ap.name + ".PartModelPurchased()==false");
return false;
}
return true;
}

This works in sandbox, science, and career. In Sandbox, always returns true. In science, returns true if PartTechAvailable(), since PartModelPurchased() is always true in Science mode. In career, both PartModelPurchased() and PartTechAvailable() have to be true.

HOWEVER!!! ResearchAndDevelopment.Instance doesn't exist on .Start() or .Awake(). I had to move all the part detection stuff to my onTrue (when someone clicks the GUI button). It's inefficient to re-check all the parts every time the GUI is shown, but it works.

Link to comment
Share on other sites

I was literally testing such a function just now :)


private static bool partResearched(AvailablePart ap){
if (ResearchAndDevelopment.Instance == null) {
print ("no ResearchAndDevelopment.Instance, must be sandbox mode");
return true;
}
if (!ResearchAndDevelopment.PartTechAvailable(ap)) {
print (ap.name+".PartTechAvailable()==false");
return false;
}

if (!ResearchAndDevelopment.PartModelPurchased (ap)) {
print (ap.name + ".PartModelPurchased()==false");
return false;
}
return true;
}

This works in sandbox, science, and career. In Sandbox, always returns true. In science, returns true if PartTechAvailable(), since PartModelPurchased() is always true in Science mode. In career, both PartModelPurchased() and PartTechAvailable() have to be true.

HOWEVER!!! ResearchAndDevelopment.Instance doesn't exist on .Start() or .Awake(). I had to move all the part detection stuff to my onTrue (when someone clicks the GUI button). It's inefficient to re-check all the parts every time the GUI is shown, but it works.

Thank you very much, I will try that out. The code currently is in the onStart Method, so it needs to be moved, but I think it can go to the context menu action, that opens the GUI. This might even be better than OnStart, because the list will be loaded only when needed.

Edit: I tried that out now and the problem really is, that you cannot run that detection in OnStart. I moved the detection to the GUI initialization and now it seems to work. You can reduce the code you posted to a one liner if you do not need the logging




private bool PartResearched(AvailablePart p)
{
return ResearchAndDevelopment.PartTechAvailable(p) && ResearchAndDevelopment.PartModelPurchased(p);
}

I only tested this in Sandbox and Career mode without part unlock, but so far it does what it should do.

Edited by ObiVanDamme
Link to comment
Share on other sites

I'm getting this error, and not sure what to do about it.

As far as I can tell, it's making my plugin not work at all.

Code is here, if it needs looking at: https://github.com/Ydoow/KSP_Konsole

Non platform assembly: /home/clark/Code/Mono/KSP_Konsole/KSP_Konsole/bin/Debug/KSP_Konsole.dll (this message is harmless)

AssemblyLoader: Exception loading 'KSP_Konsole': System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.

at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (bool)

at System.Reflection.Assembly.GetTypes () [0x00000] in <filename unknown>:0

at AssemblyLoader.LoadAssemblies () [0x00000] in <filename unknown>:0

Additional information about this exception:

System.TypeLoadException: Could not load type 'Kerbalish.Parser' from assembly 'KSP_Konsole, Version=1.0.5707.36052, Culture=neutral, PublicKeyToken=null'.

System.TypeLoadException: Could not load type 'Kerbalish.Lexer' from assembly 'KSP_Konsole, Version=1.0.5707.36052, Culture=neutral, PublicKeyToken=null'

Link to comment
Share on other sites

My first suspicion would be that you are not compiling against Net 3.5 which is what KSP runs on.

Failing that, I'm not sure, at a quick glance everything looks correct code wise.

If you are compiling against Net 3.5 already, I'll take a closer look but that is the first thing to check.

D.

Link to comment
Share on other sites

I'm getting this error, and not sure what to do about it.

As far as I can tell, it's making my plugin not work at all.

Code is here, if it needs looking at: https://github.com/Ydoow/KSP_Konsole

Non platform assembly: /home/clark/Code/Mono/KSP_Konsole/KSP_Konsole/bin/Debug/KSP_Konsole.dll (this message is harmless)

AssemblyLoader: Exception loading 'KSP_Konsole': System.Reflection.ReflectionTypeLoadException: The classes in the module cannot be loaded.

at (wrapper managed-to-native) System.Reflection.Assembly:GetTypes (bool)

at System.Reflection.Assembly.GetTypes () [0x00000] in <filename unknown>:0

at AssemblyLoader.LoadAssemblies () [0x00000] in <filename unknown>:0

Additional information about this exception:

System.TypeLoadException: Could not load type 'Kerbalish.Parser' from assembly 'KSP_Konsole, Version=1.0.5707.36052, Culture=neutral, PublicKeyToken=null'.

System.TypeLoadException: Could not load type 'Kerbalish.Lexer' from assembly 'KSP_Konsole, Version=1.0.5707.36052, Culture=neutral, PublicKeyToken=null'

My first suspicion would be that you are not compiling against Net 3.5 which is what KSP runs on.

Failing that, I'm not sure, at a quick glance everything looks correct code wise.

If you are compiling against Net 3.5 already, I'll take a closer look but that is the first thing to check.

D.

As Diazo said. Your project file is compiling against .NET 4.5

Link to comment
Share on other sites

I am trying to modify some code I found. It is adding an EVA parachute MODULE to kerbals. Within the parachute MODULE, ModuleKrKerbalParachute, there is a float value called deployeddrag. I want to set this to a value when I add this MODULE to the KerbalEVA part I want to set the value to 10. I am not sure how to write the code to set the value when adding the MODULE. Thank you! :)


namespace EVAParachutes {
[KSPAddon(KSPAddon.Startup.MainMenu, true)]
public class initKerbalEVA : UnityEngine.MonoBehaviour {
public void Awake() {

ConfigNode EVA = new ConfigNode("MODULE");
EVA.AddValue("name", "ModuleKrKerbalParachute");


try {
PartLoader.getPartInfoByName("kerbalEVA").partPrefab.AddModule(EVA);
} catch{}


EVA = new ConfigNode("MODULE");
EVA.AddValue("name", "ModuleKrKerbalParachute");
try {
PartLoader.getPartInfoByName("kerbalEVAfemale").partPrefab.AddModule(EVA);
} catch{}
}
}}

Link to comment
Share on other sites

Just add it to the ConfigNode the same way the name value is added:



public const float evaChuteDeployedDrag = 10f;

...

EVA.AddValue("name", "ModuleKrKerbalParachute");
EVA.AddValue("deployedDrag", evaChuteDeployedDrag.ToString());

Link to comment
Share on other sites

Is it possible to read and write module info of the parent part? Like if I have a custom module on part A which is attached to part B, can I retrieve/edit the info of a module on part B from the module on part A?

Link to comment
Share on other sites

royals: You certainly can, the only trick is getting the reference to the correct part.

Inside a part module: this.vessel.Parts is a list of all parts on the vessel your partModule is attached to.

There is also two other potential commands unfortunately I can't remember them exactly.

Look for something like this.part.GetParentParts() which will return a list of parts between your current part and the root part, and this.partGetChildren() which will return a list of all parts that use this part to reach the root part.

If you always want a part you are connected to, you could also look at the attachement nodes and see if there is some way to pull attached parts that way.

Not a part of KSP I've dealt with much, but hopefully this at least points you in the right direction.

D.

Link to comment
Share on other sites

royals: You certainly can, the only trick is getting the reference to the correct part.

Inside a part module: this.vessel.Parts is a list of all parts on the vessel your partModule is attached to.

There is also two other potential commands unfortunately I can't remember them exactly.

Look for something like this.part.GetParentParts() which will return a list of parts between your current part and the root part, and this.partGetChildren() which will return a list of all parts that use this part to reach the root part.

If you always want a part you are connected to, you could also look at the attachement nodes and see if there is some way to pull attached parts that way.

Not a part of KSP I've dealt with much, but hopefully this at least points you in the right direction.

D.

Alright thanks but I figured it out, used x = part.parent and then x.FindModuleImplementing<>();

What I'm now curious about is how about editing custom modules? UnityEngine doesn't include my class Foobar, so if I want to reference something in another module which I've made myself, how does that work? For example with engines I can say 'ModuleEngines x = blah blah' but I can't say 'Foobar x = ...' since neither System nor UnityEngine has that class. Must I add a "using x;" or how would I go about that?

Link to comment
Share on other sites

You will want to tag the values you want to edit with KSPField, they will then show in the partModule.Fields list and you can access them by name.

int val1 = (int)otherPartModule.Fields["Value1"]; //gets value of an Int from another partModule

otherPartModule.Fields["Value2"] = 5f; //set's Value2 (of type float) in the other partModule to 5

You can reference the other partModule as a PartModule type, you don't need to reference it as your custom type.

D.

Link to comment
Share on other sites

You will want to tag the values you want to edit with KSPField, they will then show in the partModule.Fields list and you can access them by name.

int val1 = (int)otherPartModule.Fields["Value1"]; //gets value of an Int from another partModule

otherPartModule.Fields["Value2"] = 5f; //set's Value2 (of type float) in the other partModule to 5

You can reference the other partModule as a PartModule type, you don't need to reference it as your custom type.

D.

Great thanks a bunch! Exactly what I need, much appreciated! But how do I see if my part actually has that module? I don't know how to use PartModuleList (part.Modules) but I assume it's that or something like it that I should use?

Link to comment
Share on other sites

part.FindModulesImplementing<SomePartModuleClass>() or part.Modules["SomePartModuleClass"] will just return an empty list or null if the module does not exist. There might also be part.Modules.Contains("SomePartModuleClass") but I don't remember for sure.

Link to comment
Share on other sites

part.FindModulesImplementing<SomePartModuleClass>() or part.Modules["SomePartModuleClass"] will just return an empty list or null if the module does not exist. There might also be part.Modules.Contains("SomePartModuleClass") but I don't remember for sure.

Contains exists, but has the limitation of being an exact match (Contains("ModuleEngines") won't find ModuleEnginesFX or other derivatives but FindModulesImplementing<ModuleEngines>() will)

Link to comment
Share on other sites

The catch being that you can only use FindModulesImplementing on classes you know are loaded, so stock classes and the ones in your mod.

That is sufficient most of the time, just be aware you have to use .Contains for referencing another mod.

D.

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