Cephei

The official unoffical "help a fellow plugin developer" thread

Recommended Posts

Disclaimer: I\'m not a c# expert, been coding in it for a week or so :P

But:

if it complaing about a lack of main method, it means it wants to treat your project as a standalone program - the main method is a standard entry point into such. I believe you have chosen wrong project type when you began coding - it should be c# library.

Ooops. Now it works (raaah, compiler works, but not plugin !)

Share this post


Link to post
Share on other sites

Anybody knows, how to find folder of the current part? Except for searching all the part folders for the right name in part.cfg.

Share this post


Link to post
Share on other sites

How do you use the parachute animation system (cannot be retracted, disappears at 0 m/s, moving cables) in a plugin ?

Share this post


Link to post
Share on other sites

Is it possible to destroy (or make completely non-interactible) node_collider?

It\'s necessary in the VAB (to handle surface attachments), but it should disappear in flight (because even allow collision flag makes it interact with other parts when it\'s disconnected). I want to competery remove this collider so that a part inside it won\'t be thrown out on disconnection (there will be multiple additional colliders to properly interact with other objects.

Update: proved too easy: DestroyObject(this.collider);

Share this post


Link to post
Share on other sites

Making a completely custom engine class set derived straight from part.

Can\'t seem to find a straight answer as to whether or not to factor Time.deltaTime into AddForceAtPosition force param.


onActiveFixedUpdate
{
...
this.rigidbody.AddForceAtPosition(thrVector * thrust, this.transform.position, UnityEngine.ForceMode.Force);
}

I already have the thing flyable, and a simple test showed identical results with equivalent liquid/custom engines, but it\'s difficult to produce lag-on-demand(Only shows up when you don\'t want it). Anyone know definitely if Unity physics handles framerate internally, or if I need to compensate explicitly?

Much appreciated if anyone knows.

Share this post


Link to post
Share on other sites

Googled a bit, the FixedUpdate is handled framerate-indepenend, that explains why there was no difference. Otherwise, I could need some engine code for my remake of the Cephei plugin that contained decompiled code, I could also test it at extreme lag for you, so could you maybe give me that engine stuff? Thanks in advance.

Share this post


Link to post
Share on other sites

Consensus on the Unity forums seems to be that the integrator handles the scaling of forces (and torques) so you should not scale them by the timestep. (This makes sense from the way most numerical integration schemes work - the scaling is part of the integration equation, not the input constants.)

It would be nice if we had access to the source code of some exemplar parts - an engine, a fuel tank, a winglet, etc. These would be invaluable for plug-in authors to ensure they are doing things the way the game expects.

Share this post


Link to post
Share on other sites

TYVM for the clarification. I thought it was integrated, but was finding a couple conflicting answers from google, and just wanted to make sure it wouldn\'t come bite me later on.

I\'m more than happy to give you the code, Kreuzung. Once I get a little more in there at least, right now there\'s exactly 5 lines of functional code, 2 of which simply turn the engine on/off with a key. It moves the ship, but does nothing else atm. Was going to put up a thread when it\'s a little more functional, as it\'s actually setup as a class to derive new non-rocket engine types from, rather than a monolithic new engine.

On that note, just a friendly reminder that if you do not explicitly set your class itself as public, it\'s template is not available outside your particular executable, which means nobody else can tell their code what your part is, and so cannot interact with it. Not an issue most of the time; but if you have something that extends/modifies something common like fuel tanks, if you don\'t make it public, the end parts that people use will be incompatible with each other(Tank A becomes ignored by Engine B). r4m0n was already kind enough to agree to this, so MuMech VariableTanks shouldn\'t have any problems.

Share this post


Link to post
Share on other sites

We should maybe agree on some standards (like making the classes public) and maybe even create a class library that implements easy-to-modify classes that implement basic things like engine behaviour or line-of-sight (for solar stuff). In my remake of Cepheis plugin I have a class called EL_API that allows other plugin makers (and myself) to use my energy system as easy as the standard fuel system.

Share this post


Link to post
Share on other sites

Ran into another problem with polymorphism and overridden virtual methods. I\'m far from knowledgeable about C#, so this may be a simple non-issue I\'m making overcomplicated.

Basically, it\'s this:


{
public virtual void MethodA() {
dosomething;
}
}

class Part1 : Part
{
public override void MethodA() {
dosomething;
base.MethodA();
}
}

class Part2 : Part1
{
public override void MethodA() {
dosomething;
base.MethodA(); //how to call Part MethodA directly
}
}
  class Part

Is there any way to skip over the Part1 method in the daisychain and call the Part methods themselves? I found something on delegates, but it was getting ridiculously complicated.

ED: Assuming the only code that can be modified is the Part2 class.

Share this post


Link to post
Share on other sites

Ran into another problem with polymorphism and overridden virtual methods. I\'m far from knowledgeable about C#, so this may be a simple non-issue I\'m making overcomplicated.

Basically, it\'s this:


{
public virtual void MethodA() {
dosomething;
}
}

class Part1 : Part
{
public override void MethodA() {
dosomething;
base.MethodA();
}
}

class Part2 : Part1
{
public override void MethodA() {
dosomething;
base.MethodA(); //how to call Part MethodA directly
}
}
  class Part

Is there any way to skip over the Part1 method in the daisychain and call the Part methods themselves? I found something on delegates, but it was getting ridiculously complicated.

ED: Assuming the only code that can be modified is the Part2 class.

Too lazy to try it out, but you could try something like:


class Part2 : Part1
{
public override void MethodA() {
dosomething;
typeof(Part).GetMethod('MethodA').Invoke(this);
}
}

Mind you, this is an abomination in the name of inheritance, but probably works because of the way Reflection works.

There may be some actual mechanic in the language to do that more cleanly, but I\'m not familiar enough with C# to tell for sure (but apparently I know enough to spill that abomination above ???).

Share this post


Link to post
Share on other sites

Thanks, I\'ll try it out, but from what I read, not even reflection will get you past the override. Seems the method gets resolved to the most overridden version at runtime, even if you somehow fool the compiler at compile time. Fortunately, I haven\'t seen anything bad happen from not calling the Part.OnActiveFixedUpdate method, so I\'m not terribly worried right now.

Share this post


Link to post
Share on other sites

As far as I\'ve been able to tell, all the Part.on{X} functions marked virtual (Part.onFlightStart(), Part.onPartExplode(), etc.) do nothing by themselves, so they are probably empty. It doesn\'t seem to matter if you call the base function or not, I\'ve yet to see any difference in behaviour.

Share this post


Link to post
Share on other sites

Still might be taking a chance here, but I think this falls inside the good line on posting stuff here, and it might help someone who needs an engine with custom behavior.

This is what I came up with for the public LiquidEngine definition parameters. May or may not be accurate, found with trial, error, logic, and Unity ref.


public float fuelConsumption = 1; //Fuel consumption(kg/s)
public float gimbalAngleH = 0; //Horizontal gimbal rotation from input, needs to be applied to gimbal base orientation
public float gimbalAngleV = 0; //Vertical '' These are used in calc to alter engine thrust vector
public float gimbalRange = 0; //Gimbal rotation maximum (in degrees?)
public float heatProduction = 0; //Heat produced by rocket thrust
public float maxThrust = 100; // m/s^2
public float minThrust = 0; // m/s^2 These two are used along with throttle setting to set thrust internal value
public Vector3 thrustVector = Vector3.up; //Set from CFG to align thrust relative to part. Used with below for untranslated orientation
public Vector3 thrustCenter = Vector3.zero; //Not present in LiquidEngine, but in SolidRocket, offset from part origin(is thrust origin)
public bool thrustVectoringCapable = false; //If false, don\'t apply gimbal

protected float thrust; //used internally, for calculating thrust from throttle setting, becomes magnitude of vector passed to AddForce (m/s^2)
protected Vector3 thrVector; //Internal (transformed) thrust vector. Multiplied with above to give direction for AddForce
protected Quaternion initRot; //the initial (local) rotation of the (Transform) gimbal. Needed to animate the gimbal as model need not be aligned & at origin
protected Part fuelSource; //Fueltank the engine directly connects to(if any), needed for (simple) standard fuel calling, and to kill engine when tank dies.
protected Transform gimbal; //transform of gimbal object in model.

Share this post


Link to post
Share on other sites

Unity physics stuff goes in FixedUpdate blocks, which one depends on what you\'re trying to do. I use onActiveFixedUpdate() for my engine code.

There\'s four basic things an engine seems to need done inside that particular block.

1. Get a direction and magnitude to apply the thrust. Also need position if you\'re using thrustCenter offset.

2. Call for fuel.

3. Apply the thrust.

4. Manage visual effects.

There\'s probably more, but this seems to be all that\'s required for my 'no deathray' engine bypass. Custom fuel calls can be done in other ways, the only reason to bother overriding the engine code is to remove functionality. I found that by providing your own

protected override void onActiveFixedUpdate()

and deriving from LiquidEngine, the whole thing doesn\'t need to be rewritten from Part. Also, your method does not seem to need to daisychain back through

base.onActiveFixedUpdate()

. You are giving your own method in LiquidEngine\'s place, and the Part method seems to not be needed.

Share this post


Link to post
Share on other sites

This is some actual code I came up with to do some of what I listed above.

1.

thrVector = transform.rotation * thrustVector;

. This will get you the basic direction to thrust toward. Still needs to be gimbal adjusted. This needs a quaterion and vector, and is the simplest way to get at them I\'ve found.

2.

return base.RequestFuel(Dest, Amount, Part.getFuelReqId());

. This is a working standard fuel call I came up with. Dest is the engine itself, Amount is fuelconsumption normalized for deltaTime, and possibly timewarp depending how used.

getFuelReqId is complicated. Looking at the parameter lists, it appears vanilla fuel handling is done (async?) with a call index. This method call works for me, but I\'ve seen multiple versions in other people\'s code.

3.


protected void ApplyThrust(Part Me, Vector3 force, Vector3 origin)
{
if (force.magnitude == 0 || physicalSignificance != Part.PhysicalSignificance.FULL || rigidbody == null)
return;
Me.rigidbody.AddForceAtPosition(force, origin, UnityEngine.ForceMode.Force);
}
  ApplyThrust(this, thrVector.normalized * thrust, transform.position + thrustCenter);

I call this in a function, so Me = this. This is the heart of the engine code, is the AddForceAtPosition. It takes a direction vector with magnitude=m/s^2, the position to apply force at, and the mode.

4.

Visual effects I just use an on/off if statement, and

Mathf.Lerp(0.5F, 1.0F, (float) (thrust/maxThrust));

to scale the effects. No idea if this is the right way to do it, but it works for me.

I\'ve done this in 3 posts just incase it\'s decided something is too detailed. I don\'t use or have a decompiler, and this is all my own code, anyone if free to use it. I tried to keep it as generalized as possible to avoid possible appearance of duplicating KSP code, some things can only really be written one way without intentionally adding slowcode however.

Share this post


Link to post
Share on other sites

This is some actual code I came up with to do some of what I listed above.

1.

thrVector = transform.rotation * thrustVector;

. This will get you the basic direction to thrust toward. Still needs to be gimbal adjusted. This needs a quaterion and vector, and is the simplest way to get at them I\'ve found.

2.

return base.RequestFuel(Dest, Amount, Part.getFuelReqId());

. This is a working standard fuel call I came up with. Dest is the engine itself, Amount is fuelconsumption normalized for deltaTime, and possibly timewarp depending how used.

getFuelReqId is complicated. Looking at the parameter lists, it appears vanilla fuel handling is done (async?) with a call index. This method call works for me, but I\'ve seen multiple versions in other people\'s code.

3.


protected void ApplyThrust(Part Me, Vector3 force, Vector3 origin)
{
if (force.magnitude == 0 || physicalSignificance != Part.PhysicalSignificance.FULL || rigidbody == null)
return;
Me.rigidbody.AddForceAtPosition(force, origin, UnityEngine.ForceMode.Force);
}
  ApplyThrust(this, thrVector.normalized * thrust, transform.position + thrustCenter);

I call this in a function, so Me = this. This is the heart of the engine code, is the AddForceAtPosition. It takes a direction vector with magnitude=m/s^2, the position to apply force at, and the mode.

4.

Visual effects I just use an on/off if statement, and

Mathf.Lerp(0.5F, 1.0F, (float) (thrust/maxThrust));

to scale the effects. No idea if this is the right way to do it, but it works for me.

I\'ve done this in 3 posts just incase it\'s decided something is too detailed. I don\'t use or have a decompiler, and this is all my own code, anyone if free to use it. I tried to keep it as generalized as possible to avoid possible appearance of duplicating KSP code, some things can only really be written one way without intentionally adding slowcode however.

Talking about trying to 'avoid possible appearance of duplicating KSP code' makes it sound like you read the source :P.

I haven\'t used your code in the VariableEngine yet due to the lack of gimballing, which is quite important (and tricky to implement well). I did have an idea of an ugly hack to do away with the deathray while keeping the base code intact, though, and I\'ll be trying it soon.

Share this post


Link to post
Share on other sites

I started some drama about illegal code, and just wanted to be clear I wasn\'t using anything I wasn\'t supposed to.

Edit: My Part derived engines actually do gimbal, it\'s just a matter of applying the pitch and yaw from the flight ctrl struct to the vector. The problem is that I don\'t know exactly where and how LiquidEngine applies it. I just sent you what I had because it seems to be flyable, though you have to rely on pod/rcs for maneuvering.

Share this post


Link to post
Share on other sites

Has anyone managed to get fxgroups working? I want to emit a visual burst kind of like when an RCS thruster fires. In the RCS block .cfg, there are lines like this:

[tt]fx_gasJet_white = -0.609303, 1.58536, -0.0059382, -0.173648, 0.984808, 0.0, rcsGroup0[/tt]

Which I assume is a position and vector, with some kind of ID string at the end.

Then Part has a [tt]List<FXGroup> fxGroups;[/tt]

which I\'m guessing is a reference to each fx_ line in the .cfg, though I don\'t know if it\'s auto-populated.

(Edit: Turns out it is populated, but with FXGroups with ids 'prelaunch', 'activate', active', and 'deactivate'. None of the fx_ lines in the .cfg seem to be present so they probably have to be parsed/added somehow.)

There\'s also [tt]Part.findFxGroup(string).[/tt] FXGroup itself has[tt] begin()[/tt] and [tt]Burst()[/tt] member functions.

I\'ve tried a few things but without effect, mostly it seems I can\'t initialize the FXGroup correctly. Anyone had any more success than this? I guess I could learn Unity\'s particle system and create it from scratch, but it seems silly to do that when it\'s already in the game.

Share this post


Link to post
Share on other sites

I\'ve tried a few things but without effect, mostly it seems I can\'t initialize the FXGroup correctly. Anyone had any more success than this? I guess I could learn Unity\'s particle system and create it from scratch, but it seems silly to do that when it\'s already in the game.

I\'d recommend learning Unity particle system, it\'s quite simple. You can make a particle emitter working in less than 20 lines of code.

Look for examples in Void Bukerneering Particle Cannon and Gravitsapa plugins.

Share this post


Link to post
Share on other sites

I\'d recommend learning Unity particle system, it\'s quite simple. You can make a particle emitter working in less than 20 lines of code.

Look for examples in Void Bukerneering Particle Cannon and Gravitsapa plugins.

Correction: Cloning one of the existing effects and changing a few parameters takes only a few lines of code, creating a new particle effect purely from C# is currently IMPOSSIBLE.

Share this post


Link to post
Share on other sites
Correction: Cloning one of the existing effects and changing a few parameters takes only a few lines of code, creating a new particle effect purely from C# is currently IMPOSSIBLE.
I meant exactly the same -- instantiating one of existing KSP effects and adjusting all the particle\'s behavior (speed and speed variance, life duration, damping force, etc..).

And as concerning a new particle type... I wonder is it possible to load an external PNG as a particle texture? ;)

Share this post


Link to post
Share on other sites

I meant exactly the same -- instantiating one of existing KSP effects and adjusting all the particle\'s behavior (speed and speed variance, life duration, damping force, etc..).

And as concerning a new particle type... I wonder is it possible to load an external PNG as a particle texture? ;)

'all the particle\'s behavior' is also incorrect. Unity doesn\'t have C# classes for MeshParticleEmitter and EllipsoidParticleEmitter, so the attributes unique to them are inaccessible, making some changes impossible. Also, I haven\'t been able to change the color of the particles in my attempts, but maybe I just didn\'t try hard enough.

Share this post


Link to post
Share on other sites
Unity doesn\'t have C# classes for MeshParticleEmitter and EllipsoidParticleEmitter
Ah. I never considered those ones, point emitter was good enough for me ::)
(Edit: Turns out it is populated, but with FXGroups with ids 'prelaunch', 'activate', active', and 'deactivate'. None of the fx_ lines in the .cfg seem to be present so they probably have to be parsed/added somehow.)
I\'ve just re-read your post...

Those 'prelaunch', 'activate', active' and 'deactivate' groups just tell the game when to display a certain effect. For example, an engine has the following FX definitions in its .CFG:

// --- FX definitions ---
fx_exhaustFlame_blue = 0.0, -0.8, 0.0, 0.0, 1.0, 0.0, active
fx_exhaustLight_blue = 0.0, -0.8, 0.0, 0.0, 0.0, 1.0, active
fx_smokeTrail_light = 0.0, -3.0, 0.0, 0.0, 1.0, 0.0, active
// --- Sound FX definition ---
sound_vent_medium = activate
sound_rocket_hard = active
sound_vent_soft = deactivate

Effects themselves are stored in game resources library under exactly the same name as corresponding .CGF line. For example, fx_exhaustFlame_yellow effect may be started with the following code --

GameObject o = Object.Instantiate( 'Effects/fx_exhaustFlame_yellow' ) as GameObject;
ParticleEmitter e = o.particleEmitter;
// do some setup with that ParticleEmitter; see Unity reference

Share this post


Link to post
Share on other sites

Those 'prelaunch', 'activate', active' and 'deactivate' groups just tell the game when to display a certain effect.

Well yes, I\'m guessing those particular groups are standard for all parts, that are fired automatically (?) when those events happen. But some parts (I think only the RCS thrusters at the moment) define custom group ID strings in the .cfg, like rcsGroup0 etc., that I think are triggered manually.

If you derive a part from RCSModule, you can list the contents of fxGroups and find those custom IDs there (along with the standard ones). You can also trigger them to fire using [tt]findFXGroup('rcsGroup0').Burst()[/tt] and the like. However if you try to define your own custom fx ID in the .cfg you get an error during loading:

ERROR: FX Group \'testGroup\' not found in TestPart

So they\'re not being automatically parsed, you probably have to predefine them in the code somehow.

All in all using Unity\'s particle system directly will probably be less work (actually I know it is; I already have it half-working, I just need to tune the effect parameters to what I want) but I\'d like to get a handle on FXGroups too, especially as they seem to handle sounds as well.

Share this post


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.