Cephei

The official unoffical "help a fellow plugin developer" thread

Recommended Posts

21 hours ago, sarbian said:

It is possible but as you said it is not easy. As for the "not easy to be dynamic" part it depends what you call dynamics. If it s mostly button and text you re fine. Design your UI, use different names for each item and then you can load it as a bundle (see here for inspiration)

Hmmm ok. I would definitely want some of the text to change, certainly at the press of a button, and possibly in real time, and possibly plot a graph (particularly if someone has a neat way of drawing graphs!). I'll have a go with using the asset bundle for now, but give up on that pretty soon if it gives me more grief. My understanding is I can kinda copy old GUI tutorials, just with the re-factoring outlined in the 1.1 conversion thread? Thanks for your help

Share this post


Link to post
Share on other sites

Hello, Is there a way to keep a coroutine active when the game is paused (with something like FlightDriver.setPause(True,True) or in the RnD building) ?

I've tried this...

using System.Collections;
using UnityEngine;

namespace corTest {
	[KSPAddon (KSPAddon.Startup.EveryScene, false)]
	public class corTest : MonoBehaviour {
		void Start() {
			StartCoroutine (test ());
			GameEvents.onGamePause.Add (gamePause);
			GameEvents.onGameUnpause.Add (gameUnPause);
			Debug.Log ("Start");
		}
		void OnDestroy() {
			StopCoroutine (test ());
			GameEvents.onGamePause.Remove (gamePause);
			GameEvents.onGameUnpause.Remove (gameUnPause);
			Debug.Log ("OnDestroy");
		}
		IEnumerator test() {
			int i = 0;
			while (true) {
				Debug.Log ("wait ... " + i);
				i++;
				yield return new WaitForSeconds (1);
			}
		}
		void gamePause() {
			Debug.Log ("gamePause");
		}
		void gameUnPause() {
			Debug.Log ("gameUnPause");
		}
	}
}

And the result is:

wait ... 1
wait ... 2
wait ... 3
wait ... 4
wait ... 5
wait ... 6
wait ... 7
gamePause
gameUnPause
wait ... 8
wait ... 9
wait ... 10

I just want to keep counting on my coroutine without the use of Update(). Thanks !

Share this post


Link to post
Share on other sites
8 minutes ago, Malah said:

Hello, Is there a way to keep a coroutine active when the game is paused (with something like FlightDriver.setPause(True,True) or in the RnD building) ?

 

Yep, use WaitForSecondsRealtime :)

  • Like 1

Share this post


Link to post
Share on other sites
18 minutes ago, sarbian said:

Yep, use WaitForSecondsRealtime :)

As easy as this, thanks :wink:

Edit1: I know why I haven't found it ... it seems to be in Unity 5.4 ... I need to wait KSP 1.2 :P

Edit2: After some research, I will use this in KSP 1.1:

		IEnumerator test() {
			int i = 0;
			while (true) {
				Debug.Log ("wait ... " + i);
				i++;
				float pauseEndTime = Time.realtimeSinceStartup + 1;
				while (Time.realtimeSinceStartup < pauseEndTime) {
					yield return 0;
				}
			}
		}

 

Edited by Malah

Share this post


Link to post
Share on other sites
19 minutes ago, Malah said:

As easy as this, thanks :wink:

Edit1: I know why I haven't found it ... it seems to be in Unity 5.4 ... I need to wait KSP 1.2 :P

Edit2: After some research, I will use:


		IEnumerator test() {
			int i = 0;
			while (true) {
				Debug.Log ("wait ... " + i);
				i++;
				float pauseEndTime = Time.realtimeSinceStartup + 1;
				while (Time.realtimeSinceStartup < pauseEndTime) {
					yield return 0;
				}
			}
		}

 

Or you can use WaitForSeconds (which exists in 5.2) and multiply by Time.timeScale.

Edited by nightingale
  • Like 1

Share this post


Link to post
Share on other sites

The scale is 0 when in pause :)

  • Like 2

Share this post


Link to post
Share on other sites
2 hours ago, sarbian said:

The scale is 0 when in pause :)

Yup, that would make sense. :)

  • Like 1

Share this post


Link to post
Share on other sites

Ok I didn't want to post in here as the thread name states "help a fellow plugin developer" which I am definitely not. I just really want to know if a plugin is possible for what I have in mind. I am more than willing to do the work and learn, I just need to be pointed in the right direction. I have never made a plugin for ksp but I have a love for coding and programing just not in c# or unity so this is going to be a test run for me. I love to learn so any help and guidance will be greatly appreciated. If you think this wouldn't be worth my time that's cool too. ill definitely be here with an open ear.

HERE  is my proposal. i haven't fully fleshed out the details but I think it has potential. check it out!

Share this post


Link to post
Share on other sites
On 8/21/2016 at 6:44 AM, Galileo said:

Ok I didn't want to post in here as the thread name states "help a fellow plugin developer" which I am definitely not. I just really want to know if a plugin is possible for what I have in mind. I am more than willing to do the work and learn, I just need to be pointed in the right direction. I have never made a plugin for ksp but I have a love for coding and programing just not in c# or unity so this is going to be a test run for me. I love to learn so any help and guidance will be greatly appreciated. If you think this wouldn't be worth my time that's cool too. ill definitely be here with an open ear.

HERE  is my proposal. i haven't fully fleshed out the details but I think it has potential. check it out!

Yes, it's possible.

See Multi-tasking Kerbals for a small intro to the trait system (reproduced below since the download link is broken) and making Kerbals do different things.

Also check out Roster Manager which seems to do many of the same things you want to accomplish.

While you can modify the three classes (Pilot, Scientist, Engineer) to have different attributes, I have no idea if you can add additional classes.

 

EXPERIENCE_TRAIT
{
	name = Pilot
	title = Astronaut
	desc = One Kerbal for One Job!

	EFFECT
	{
		name = AutopilotSkill
	}
	
	EFFECT
	{
		name = RepairSkill
	}
	
	EFFECT
	{
		name = VesselScienceReturn
		modifiers = 1.05, 1.1, 1.15, 1.2, 1.25
	}
	EFFECT
	{
		name = PartScienceReturn
		modifiers = 1.05, 1.1, 1.15, 1.2, 1.25
	}
	EFFECT
	{
		name = ScienceSkill
	}
	
}

EXPERIENCE_TRAIT
{
	name = Engineer
	title = Astronaut
	desc = One Kerbal for One Job!

	EFFECT
	{
		name = AutopilotSkill
	}
	
	EFFECT
	{
		name = RepairSkill
	}
	
	EFFECT
	{
		name = VesselScienceReturn
		modifiers = 1.05, 1.1, 1.15, 1.2, 1.25
	}
	EFFECT
	{
		name = PartScienceReturn
		modifiers = 1.05, 1.1, 1.15, 1.2, 1.25
	}
	EFFECT
	{
		name = ScienceSkill
	}
	
}

EXPERIENCE_TRAIT
{
	name = Scientist
	title = Astronaut
	desc = One Kerbal for One Job!

	EFFECT
	{
		name = AutopilotSkill
	}
	
	EFFECT
	{
		name = RepairSkill
	}
	
	EFFECT
	{
		name = VesselScienceReturn
		modifiers = 1.05, 1.1, 1.15, 1.2, 1.25
	}
	EFFECT
	{
		name = PartScienceReturn
		modifiers = 1.05, 1.1, 1.15, 1.2, 1.25
	}
	EFFECT
	{
		name = ScienceSkill
	}
	
}

 

 

Share this post


Link to post
Share on other sites

I'd like clarification on a couple of things.

First: Could someone direct me to a flowchart of how the Unity process goes? I get that there's something to do with Start(), Update(), et cetera, but I don't know exactly when all these methods are called.

Second: How does one trigger action groups? E.g. toggling the Gear action group, or trigger the Stage one.

Third: How do I use coroutines?

Share this post


Link to post
Share on other sites
28 minutes ago, 0111narwhalz said:

I'd like clarification on a couple of things.

First: Could someone direct me to a flowchart of how the Unity process goes? I get that there's something to do with Start(), Update(), et cetera, but I don't know exactly when all these methods are called.

Second: How does one trigger action groups? E.g. toggling the Gear action group, or trigger the Stage one.

Third: How do I use coroutines?

  1. This topic may shed some light. It's specific to PartModules but a lot of the same stuff applies to other MonoBehaviours 
  2. Something like
    FlightGlobals.ActiveVessel.ActionGroups.ToggleGroup(KSPActionGroup.Gear);

    If you're interested in a specific vessel rather than just the active vessel then you can substitute something there

  3. Have you read the Unity documentation on them? (if yes, then you'll know that it's a bit confusing but I just want to know how much you already know before I try to start explaining things)

Share this post


Link to post
Share on other sites

I was wondering if somebody know how to extend the maximum zoom allowed in tracking view and map mode.

Share this post


Link to post
Share on other sites
57 minutes ago, blowfish said:

Have you read the Unity documentation on them? (if yes, then you'll know that it's a bit confusing but I just want to know how much you already know before I try to start explaining things)

Many thanks.

I read it, but it's still a little unclear. I'm trying to make a sort of autopilot, so I need it to wait a physics frame between loops (because it makes no sense to change control inputs any more frequently than that). So should I make OnUpdate() call into the coroutine, and then yield at the end of each loop? And then when I call it again, it starts at the line after yield return null;, right?

As for the lifecycle, this is my understanding:

Load() -> OnStart() -> Start() -> OnFixedUpdate() -> FixedUpdate() 
                                                            ^_________________/

Is this representative of reality?

Share this post


Link to post
Share on other sites
32 minutes ago, 0111narwhalz said:

Many thanks.

I read it, but it's still a little unclear. I'm trying to make a sort of autopilot, so I need it to wait a physics frame between loops (because it makes no sense to change control inputs any more frequently than that). So should I make OnUpdate() call into the coroutine, and then yield at the end of each loop? And then when I call it again, it starts at the line after yield return null;, right?

That's generally correct.  yield return null will defer the rest of the coroutine to the next frame.  I think this might not be quite what you want however.  If you start the coroutine every frame, then it will run the whole coroutine, just part of it will be a frame after it was started.

47 minutes ago, 0111narwhalz said:

Load() -> OnStart() -> Start() -> OnFixedUpdate() -> FixedUpdate() 
                                                            ^_________________/

Is this representative of reality?

That looks correct for those methods (there are other update methods that are run on a different schedule).

Share this post


Link to post
Share on other sites

How do I set up node_stack_top, node_stack_bottom, and node_attach?

Share this post


Link to post
Share on other sites
2 hours ago, RocketSquid said:

How do I set up node_stack_top, node_stack_bottom, and node_attach?

I think this is the wrong thread for this, part configs aren't the same as plugins.  But anyway, the first three numbers are the node's position (relative to the part's origin), and the next 3 are the node's normal (i.e. what direction does it point in).  The last one is optional and defines the size (this must be an integer).  node_attach is special because it defines the actual attach node, stack nodes are anything starting with node_stack_

Share this post


Link to post
Share on other sites
9 hours ago, ShotgunNinja said:

I was wondering if somebody know how to extend the maximum zoom allowed in tracking view and map mode.

You could try CameraManager.GetCurrentCamera() and manipulate the near/far clipping panes and the field of view.

  • Like 1

Share this post


Link to post
Share on other sites
12 hours ago, blowfish said:

That's generally correct.  yield return null will defer the rest of the coroutine to the next frame.  I think this might not be quite what you want however.  If you start the coroutine every frame, then it will run the whole coroutine, just part of it will be a frame after it was started.

How would you suggest I achieve the goal of running a loop once per physframe while keeping a (rather large) set of variables alive between iterations?

Share this post


Link to post
Share on other sites
11 minutes ago, 0111narwhalz said:

How would you suggest I achieve the goal of running a loop once per physframe while keeping a (rather large) set of variables alive between iterations?

I'm confused.  Before it sounded like you wanted it to run every other physics frame.  When exactly do you want this to run?

Share this post


Link to post
Share on other sites
38 minutes ago, 0111narwhalz said:

How would you suggest I achieve the goal of running a loop once per physframe while keeping a (rather large) set of variables alive between iterations?

Normally I'd go with a wrapper class/struct and a function called from fixed update (function in the class, or just another function for a struct).

I prefer to use coroutines for periodic checks (NOT every frame) or as a sort of psuedo-thread for responding to an event over a finite number of frames. Using them to generate additional infinite loops just fragments code that's running on the same events (ie. I like being able to trace all functions that run every frame back to (fixed) update).

I'd say that's just my personal style guidelines though. Running an infinite loop in a coroutine is not going to have major downsides so if that works for you, why not.

Edited by Crzyrndm

Share this post


Link to post
Share on other sites
1 hour ago, blowfish said:

I'm confused.  Before it sounded like you wanted it to run every other physics frame.  When exactly do you want this to run?

Did I? Sorry, I want it to run each physics frame. 1:1 physframe : iteration.

45 minutes ago, Crzyrndm said:

Normally I'd go with a wrapper class/struct and a function called from fixed update (function in the class, or just another function for a struct).

So something like this?

class Autopilot
{
  //Various variables
  public void OnFixedUpdate()
  {
    Iterate(Object);
  }
  void Iterate(Object)
  {
    //Do autopilot-y things
  }
}

Would this preserve the "various variables" between calls of OnFixedUpdate()?

Finally, what's the functional difference between OnFixedUpdate() and FixedUpdate()?

Share this post


Link to post
Share on other sites
15 minutes ago, 0111narwhalz said:

Did I? Sorry, I want it to run each physics frame. 1:1 physframe : iteration.

So something like this?


class Autopilot
{
  //Various variables
  public void OnFixedUpdate()
  {
    Iterate(Object);
  }
  void Iterate(Object)
  {
    //Do autopilot-y things
  }
}

Would this preserve the "various variables" between calls of OnFixedUpdate()?

Finally, what's the functional difference between OnFixedUpdate() and FixedUpdate()?

FixedUpdate and OnFixedUpdate are just instance methods, whatever you do to the instance variables will be kept.

OnFixedUpdate on a PartModule is called by the part's FixedUpdate method.  It is only run if the part has been staged.  FixedUpdate is called by Unity on the PartModule (or any other Behaviour).

Share this post


Link to post
Share on other sites
10 minutes ago, blowfish said:

FixedUpdate and OnFixedUpdate are just instance methods, whatever you do to the instance variables will be kept.

So I don't need a separate Iterate() method? I probably will anyway, because I need some other methods to run at appropriate times, but it's not necessary?

11 minutes ago, blowfish said:

OnFixedUpdate on a PartModule is called by the part's FixedUpdate method.  It is only run if the part has been staged.  FixedUpdate is called by Unity on the PartModule (or any other Behaviour).

So in this case (partless), I should use FixedUpdate() instead of OnFixedUpdate()?

Share this post


Link to post
Share on other sites

Correct, On* methods will not work when inheriting from a module that doesn't implement them for you (including direct from MonoBehaviour (general partless mod)).

and no Fixed update will not store variables for you. You just need to declare them outside the method (loose globals, global wrapper struct instance, global wrapper class instance)

int global var = 0; // increments with every call to Update
class wrapperClass
{
	// wrapper vars
  	int var1;
	// wrapper functions
	void AutoPilotStuff()
	{
		++var1;
	}
}
wrapperClass dataClass = new wrapperClass(); // persistent across method invocations and groups variables nicely

struct wrapperStruct
{
	// wrapper vars
    int var1;
  	// wrapper functions
  	void AutoPilotStuff()
	{
		++var1;
	}
}
wrapperStruct dataStruct = new dataStruct();

void FixedUpdate()
{
  	// not persistent
  	int i = 100; // will be lost when FixedUpdate completes for that frame
  
  	// persistent
	++var; // increase by 1 every physics frame
  	dataStruct.AutoPilotStuff(); // increase by 1 every physics frame
  	dataClass.AutoPilotStuff(); // bundle function and vars for the function together
}

Only variables declared inside the method are lost upon completion of each invocation (If you're new at this, I would avoid using the struct implementation. There are a few gotchas with it)

Edited by Crzyrndm

Share this post


Link to post
Share on other sites

So, I'm writing my first mod, and my C# knowledge is.. shaky to say the least, so bear with me.

What I am basically trying to do, is set it so that when a player returns to the Space Centre, if it detects more Dead crew members than it did last time, it takes some rep away from the player. I know I could set up an Event Handler in the flight scene for this, but so far, everything it needs to do happens in the space centre, so I'd like to keep it that way if at all possible.

I know the code works, because when I load up to the Space Centre from the main menu, the rep is deducted properly. However, when returning to the Space Centre, the rep isn't deducted but the number of dead Kerbals is updated (and outputted to the text file where I'm storing this stuff at the moment).

I'm guessing what is happening is that the game is calling the first Update() before it's loaded the crew list, so it's not finding them. What's weird though is the number of dead Kerbals is being updated properly (which I wouldn't expect to happen if it hadn't finished loading, and it would pick it up on the next pass). Thinking this was my problem, I tried using WaitForSeconds to make sure everything had loaded, but no joy.

This is the relevant bits of my code (apologies for the terrible forum formatting) - I've pruned some bits from Budget() which are working fine, and not relevant to the problem:

Quote

void Update()
        {
            Wait();
            Budget();
        }

private void Budget()

{     

IEnumerable<ProtoCrewMember> DeadCrew = HighLogic.CurrentGame.CrewRoster.Crew.Where(k => k.rosterStatus == ProtoCrewMember.RosterStatus.Dead || k.rosterStatus == ProtoCrewMember.RosterStatus.Missing);

        if (DeadCrew.Count() > DeadCount)
                {
                    Reputation.Instance.AddReputation(-100, TransactionReasons.None);
                    DeadCount = DeadCrew.Count();
                }

}

IEnumerator Wait()
        {
            yield return new WaitForSeconds(10);
        }

So I guess I have two questions:

1) What am I doing wrong? Why is it only doing it on a new save load and not a scene change? It's probably a really obvious rookie mistake.

2) Is there a better way of doing this?

 

Edited by severedsolo

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now