Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Try looking at r4am0n\'s and CardBoardBoxProcessor\'s MechJeb Autopilot. They have a GUI which you can see in their source code, you learn a lot by reading the code.

Then we have Unity\'s own documentation:

http://unity3d.com/support/documentation/ScriptReference/30_search.html?q=gui

And some basic tutorial:

http://unity3d.com/support/documentation/Components/GUI%20Scripting%20Guide.html

How you apply it to KSP you\'ll have to figure out yourself, or by help from other people\'s source codes.

Thanks, I didn\'t see the Autopilot mod. I was going off of a unity tutorial, but wasn\'t sure how to apply to KSP.

Link to comment
Share on other sites

Still cannot figure out when the part creates its Rigidbodies :\'(. I\'ve seen toastar\'s post, tried most of the methods listed there and still have not succeeded.

The problem is that I need to create my physics objects after the game has created its ones, otherwise it spams error messages, parts explode at launch etc. Could someone give me a hint please?

UPD. Which methods post messages \'[craft-name]: ground contact! - error: XXXm\' and \'Unpacking craft-name\' to the console? Obviously not the onUnpack() method and not onPartTouchdown(), I\'ve already tried to override them...

Link to comment
Share on other sites

@Tosh: onUnpack() and onPartTouchdown() are most likely part-specific, where the methods handling those messages are most likely attached to the vessel overall. I don\'t know precisely what you\'re doing, but some of my code requires to be certain that all parts are spawned in before it activates, else bad things happen, and to do that I use if (Rigidbody.isKinematic == true) {}, which checks whether the game has just unfrozen the craft. If you don\'t care so much about all parts being present, and just that the rigidbody exists, if (Rigidbody != null) {} may help. And if you need to check this for all parts, foreach (Part partcheck in vessel.parts) {} will let you cycle through them all.

Link to comment
Share on other sites

I\'ve been struggling to get a GUI working properly. I can display the GUI, but it doesn\'t seem to be registering button presses.

http://snipt.org/ufPj3

If someone can tell me why this doesn\'t add 'abort' to the flight logger when you click the 'ABORT' button it would be most appreciated.

Link to comment
Share on other sites

I\'ve been struggling to get a GUI working properly. I can display the GUI, but it doesn\'t seem to be registering button presses.

http://snipt.org/ufPj3

If someone can tell me why this doesn\'t add 'abort' to the flight logger when you click the 'ABORT' button it would be most appreciated.

The code looks right... I\'ve had a few problems with focus, you can try GUI.FocusWindow() to see if it helps.

Link to comment
Share on other sites

GUI.FocusWindow() didn\'t fix it, it did break every other menu though, even after running UnfocusWindow :)

Weirdly, the code I posted works if you left and right click at the same time.

Got it! http://snipt.org/ufTb9

I had to use GUILayout.BeginVertical() & GUILayout.EndVertical()

This shouldn\'t be necessary according to the Unity documentation.

Link to comment
Share on other sites

@Tosh: onUnpack() and onPartTouchdown() are most likely part-specific, where the methods handling those messages are most likely attached to the vessel overall. -snip-
Iskierka, thanks for your reply. It seems we\'re solving the same problem: spinning wheels ;)

I wonder is there a way to attach a delegate to that vessel-handling code. The problem is that in some launches the game tries to remove all the vessel\'s rigidbodies in an arbitrary moment (not notifying the part at all!) -- and fails if the part has already created some physics above them. And in other launches the game starts to analyze ground collisions in some weird way (probably not taking into account newly created physics?), which obviously leads to an explosion...

Well, I\'ll fiddle with the code a couple of days before releasing it... with all the bugs it contains 8)

Link to comment
Share on other sites

Tosh, what is it that you\'re trying to accomplish exactly? I may be able to assist if I have a clearer picture of the situation. I understand you\'re wanting to register a rigidbody colliding the with ground? Sometimes that why can be more important then the what :)

Link to comment
Share on other sites

Tosh, what is it that you\'re trying to accomplish exactly? I may be able to assist if I have a clearer picture of the situation. I understand you\'re wanting to register a rigidbody colliding the with ground? Sometimes that why can be more important then the what :)

Yes, I\'m trying to create a \'classic\' four-wheel cart from Unity tutorial -- parent rigidbody and 4 bodies with WheelColliders attached. For now (thanks to Iskierka) the only problem that\'s left is the cart collides with ground on launch in spite that (according to console log) the wheels are already created. Though it can be fixed by placing the cart on the top of several StackDecouplers :).

I\'ll release the code in a day or two (after fixing some animation issues), then we\'ll look into it together.

Link to comment
Share on other sites

Well there are several ways to handle the problem.

In my case, I\'m using KSP\'s built in part features, to create the 3d model and get a node collider (rigidbody) for the part. This handles all the logic, attachment and instantiation in the VAB. Now it appears that whenever the the part is instantiated, it has a (OnPartStart) method that is called once. This is where you can do any functions that require access to a game object. Since I\'ve now got a fully loaded part, I create and configure my wheel collider, then attach it to transform.FindChild('model'). It will initially spawn resting against the node collider of the part. Then as the simulation starts and the physics come online, it will 'pop' you up to rest on the wheel collider instead. But the actual part itself must have a master node_collider. As this handles the logic for part destruction. If at any time the transform origin for the 'part' is below ground it will be destroyed. I also make sure that my wheel collider is below the rigidbody for the part. I know its a little complicated. If you want, just PM me and I\'ll share my source code with you so you can see how I did it. I\'m not ready to release it yet, because I\'m recoding the entire thing to support advanced suspensions and drive trains. But I figure the creation of the wheel collider is the part you are interested in.

Link to comment
Share on other sites

Well, wheels problems are solved. But here\'s another one: how do I to determine which body am I currently orbiting? I guess it must be somewhere in FlightGlobals class, but I\'ve no documentation on it...

UPD. Huh, nevermind, I\'ve VS installed. It\'s FlightGlobals.currentMainBody.

Link to comment
Share on other sites

Is it possible to process data during reading them from part.cfg. Like get one or several values from there, rewrite them to some array, get the same fields again, rewrite them to other position in the array and so on...

If that\'s not wery good idea, what\'s the best way to read a text file in the part folder (and how to get the proper path&) immidiately after cfg processing?

I just have some ideas that are not very static...

Link to comment
Share on other sites

Is it possible to process data during reading them from part.cfg. Like get one or several values from there, rewrite them to some array, get the same fields again, rewrite them to other position in the array and so on...

If that\'s not wery good idea, what\'s the best way to read a text file in the part folder (and how to get the proper path&) immidiately after cfg processing?

I just have some ideas that are not very static...

Are you planning on the .cfg having changed when you re-read the fields?

If you need to read a file you should be able to use the standard System functions to accomplish that. Just look up a c# file i/o example.

Link to comment
Share on other sites

Is it possible to process data during reading them from part.cfg. Like get one or several values from there, rewrite them to some array, get the same fields again, rewrite them to other position in the array and so on...

If that\'s not wery good idea, what\'s the best way to read a text file in the part folder (and how to get the proper path&) immidiately after cfg processing?

I just have some ideas that are not very static...

I\'ve seen such a code in MechJeb project. See http://svn.mumech.com/KSP/trunk/MuMechLib/MechJeb.cs
Link to comment
Share on other sites

Could someone explain the maths in the MechJeb plugin?

I want to write similar code that will let me point the ship in a direction of my choosing.

I think this is the relevant bit:


Quaternion tgt = Quaternion.LookRotation(tgt_fwd, tgt_up);
Quaternion delta = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.transform.rotation) * tgt);

err = new Vector3((delta.eulerAngles.x > 180) ? (delta.eulerAngles.x - 360.0F) : delta.eulerAngles.x, (delta.eulerAngles.y > 180) ? (delta.eulerAngles.y - 360.0F) : delta.eulerAngles.y, (delta.eulerAngles.z > 180) ? (delta.eulerAngles.z - 360.0F) : delta.eulerAngles.z) / 180.0F;
integral += err * TimeWarp.fixedDeltaTime;
deriv = (err - prev_err) / TimeWarp.fixedDeltaTime;
act = Kp * err + Ki * integral + Kd * deriv;
prev_err = err;

I see how the [tt]act[/tt] variable is later applied to the [tt]FlightCtrlState[/tt], that bit makes sense to me, what\'s confusing me is how the [tt]act[/tt] is being derived. I think it\'s partly confusing because there\'s a feedback loop to help make the movement smoother, could someone maybe write code / psuedocode showing how the process would work without the loop, so I could understand it better?

I guess the main question is: How do I go from having a desired heading in a vector, to applying forces in the correct direction to orientate the ship towards that vector?

Link to comment
Share on other sites

Could someone explain the maths in the MechJeb plugin?

I want to write similar code that will let me point the ship in a direction of my choosing.

I think this is the relevant bit:


Quaternion tgt = Quaternion.LookRotation(tgt_fwd, tgt_up);
Quaternion delta = Quaternion.Inverse(Quaternion.Euler(90, 0, 0) * Quaternion.Inverse(vessel.transform.rotation) * tgt);

err = new Vector3((delta.eulerAngles.x > 180) ? (delta.eulerAngles.x - 360.0F) : delta.eulerAngles.x, (delta.eulerAngles.y > 180) ? (delta.eulerAngles.y - 360.0F) : delta.eulerAngles.y, (delta.eulerAngles.z > 180) ? (delta.eulerAngles.z - 360.0F) : delta.eulerAngles.z) / 180.0F;
integral += err * TimeWarp.fixedDeltaTime;
deriv = (err - prev_err) / TimeWarp.fixedDeltaTime;
act = Kp * err + Ki * integral + Kd * deriv;
prev_err = err;

I see how the [tt]act[/tt] variable is later applied to the [tt]FlightCtrlState[/tt], that bit makes sense to me, what\'s confusing me is how the [tt]act[/tt] is being derived. I think it\'s partly confusing because there\'s a feedback loop to help make the movement smoother, could someone maybe write code / psuedocode showing how the process would work without the loop, so I could understand it better?

I guess the main question is: How do I go from having a desired heading in a vector, to applying forces in the correct direction to orientate the ship towards that vector?

That is a PID controller. It isn\'t very simple to explain, and took quite a while to get into that state in which it works reasonably...

As for what you want, your best approach would be to use this code fragment as is, and set those variables before it:

tgt_fwd = the direction you want to go, in world coordinates

tgt_up = the direction you want 'up' to be, will only affect roll. If you want to keep the current one, use vessel.transform.up

The integral and prev_err variables must be kept from frame to frame, and should be zeroed if you change your target. Else than that, you will probably need to calibrate your K parameters, but the values in MechJeb should work if you keep the code like that.

Link to comment
Share on other sites

I was having the same problem with buttons mentioned earlier in this thread, where they would only only work if I simultaneously left and right clicked. I tried enclosing them in all sorts of BeginVertical/EndVertical\'s and BeginHorizontal/EndHorizontal\'s, but that wasn\'t helping me. In fact I\'m pretty sure the culprit is the GUI.DragWindow command, which lets the GUI window get dragged around. The DragWindow function takes a Rect that specifies what portion of the window you can click on to drag the window. But if that Rect covers a button then you won\'t be able to click on that button. To fix this, the DragWindow command should go *after* all the other GUI stuff, so that it doesn\'t eat the mouse events before they get to the actual controls.

I\'ll put a note about this in the example code on the wiki.

Link to comment
Share on other sites

That is a PID controller. It isn\'t very simple to explain, and took quite a while to get into that state in which it works reasonably...

As for what you want, your best approach would be to use this code fragment as is, and set those variables before it:

tgt_fwd = the direction you want to go, in world coordinates

tgt_up = the direction you want 'up' to be, will only affect roll. If you want to keep the current one, use vessel.transform.up

The integral and prev_err variables must be kept from frame to frame, and should be zeroed if you change your target. Else than that, you will probably need to calibrate your K parameters, but the values in MechJeb should work if you keep the code like that.

Thank you, that\'s helped me understand a bit of what\'s going on. If I wanted to remove the PID controller, could I replace the variable [tt]act[/tt] with [tt]err[/tt] in the following code and have the module still work? (obviously it wouldn\'t work as well, but would it work a bit?)


s.pitch = Mathf.Clamp(s.pitch + act.x, -1.0F, 1.0F);
s.yaw = Mathf.Clamp(s.yaw - act.y, -1.0F, 1.0F);
s.roll = Mathf.Clamp(s.roll + act.z, -1.0F, 1.0F);

(I don\'t want to remove the feedback controller, I\'m just checking if I\'m understanding it right.)

Link to comment
Share on other sites

Thank you, that\'s helped me understand a bit of what\'s going on. If I wanted to remove the PID controller, could I replace the variable [tt]act[/tt] with [tt]err[/tt] in the following code and have the module still work? (obviously it wouldn\'t work as well, but would it work a bit?)


s.pitch = Mathf.Clamp(s.pitch + act.x, -1.0F, 1.0F);
s.yaw = Mathf.Clamp(s.yaw - act.y, -1.0F, 1.0F);
s.roll = Mathf.Clamp(s.roll + act.z, -1.0F, 1.0F);

(I don\'t want to remove the feedback controller, I\'m just checking if I\'m understanding it right.)

The [tt]err[/tt] variable is the difference from where you are pointed to where you want to point, so yes, just acting directly on the error would give you a P controller (same effect as setting Ki and Kd to 0 and Kp to 1). The practical effect is that the ship will try to correct the course, but will ignore angular momentum, so it will overshot and try again, then reverse the controls and keep doing that.

Link to comment
Share on other sites

The [tt]err[/tt] variable is the difference from where you are pointed to where you want to point, so yes, just acting directly on the error would give you a P controller (same effect as setting Ki and Kd to 0 and Kp to 1). The practical effect is that the ship will try to correct the course, but will ignore angular momentum, so it will overshot and try again, then reverse the controls and keep doing that.

Thanks r4m0n, that\'s really helpful and has shown me how to do this:

I\'ve got a lot more exploring and testing to do, but now that I know what\'s going on I can better code a version to my purpose :). Thanks for explaining!

Link to comment
Share on other sites

Can anybody answer this:

I\'m inititiating an array in onPartLoad() (tested at that point, works OK). When I try to refer to this value in flight scene (from OnFlightStart()), I get only 'Object reference not set to instance of object'.

What to do in order to not lose the values? ???

Link to comment
Share on other sites

Can anybody answer this:

I\'m inititiating an array in onPartLoad() (tested at that point, works OK). When I try to refer to this value in flight scene (from OnFlightStart()), I get only 'Object reference not set to instance of object'.

What to do in order to not lose the values? ???

Hard to answer. What type of values are you storing? Have you instantiated each specific value in the array?

Show a complete code please. Or PM it if you don\'t want to expose it to public.

So that\'s halfway there -- just need to figure out where to find the actual API class/function/etc descriptions...
There\'s no class documentation at this moment. You may either refer to already written plugins or install VisualStudio and use the Object Browser to look at what\'s available.

[mod]My bad, reverted. Sorry.[/mod]

Link to comment
Share on other sites

I offer the following question to the coding oracle:

Where can I initialize and destroy a TCPListener reliably, so its only active while I\'m flying a rocket.

At the moment I\'m doing this (link to other post). In short I\'m overriding OnPartUpdate and check every tick whether my Listener is null. I hav no idea where to close down the socket yet.

Thanks for your help.

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