Jump to content

[ANSWERED] Throttle event


Recommended Posts

Does KSP have an event for when the throttle changes, that I can call in my plugin?

If not, what are the alternatives - how can I do calculations when the player changes the throttle in flight?

-----------------------------------------------------------------------------------------------------

Answer: No KSP does not have an event for throttle yet. But I have created one, which will be part of my next release of GTIndustries mod.

 

Edited by Warezcrawler
Link to comment
Share on other sites

4 hours ago, Warezcrawler said:

Does KSP have an event for when the throttle changes, that I can call in my plugin?

Not that I am aware of, but you can now create your own event :

 

4 hours ago, Warezcrawler said:

If not, what are the alternatives - how can I do calculations when the player changes the throttle in flight?

You can check the state of "vessel.ctrlState.mainThrottle" in every Update() or less frequently with a coroutine.

Link to comment
Share on other sites

If this is per vessel, just monitor the mentioned vessel.ctrlState.mainThrottle. The overhead of an event isn't worth imo.

Note the throttle gauge seen on screen is a different object, FlightInputHandler.state.mainThrottle.

Either way:

public float savedThrottle;

public void FixedUpdate()
{
  if(savedThrottle != FlightInputHandler.state.mainThrottle)
  {
    //run code on throttle change here.
    savedThrottle = FlightInputHandler.state.mainThrottle;
  }
}

Note that because throttle change happens over several update frames, the above code will fire several times for the "same" throttle change.

D.

Edited by Diazo
Link to comment
Share on other sites

2 hours ago, Li0n said:

You can check the state of "vessel.ctrlState.mainThrottle" in every Update() or less frequently with a coroutine.

Ok, I've been avoiding using onUpdate() and onFixedUpdate() because I really do not want to end up with a mod that is hitting performance.

Would a coroutine be better for performance? Or would the overhead of having the coroutine runnning be worse than just doing as Diazo is suggesting and just checking the throttlestate every frame?

(now I would be happy if I knew how to create and independent tread to run this process in - taking the load of the main tread)

 

1 hour ago, Diazo said:

If this is per vessel, just monitor the mentioned vessel.ctrlState.mainThrottle. The overhead of an event isn't worth imo.

Note the throttle gauge seen on screen is a different object, FlightInputHandler.state.mainThrottle.

What is the difference between these two? Is it that the bottom one would fire for all loaded vessels if I do this in a parts module, while the top one would only fire for the specific vessel?

Edited by Warezcrawler
Link to comment
Share on other sites

26 minutes ago, Warezcrawler said:

Ok, I've been avoiding using onUpdate() and onFixedUpdate() because I really do not want to end up with a mod that is hitting performance.

Would a coroutine be better for performance? Or would the overhead of having the coroutine runnning be worse than just doing as Diazo is suggesting and just checking the throttlestate every frame?

No idea what is better performance wise. In my opinion, using one or the other depends on how often do you need to interact with the "throttlestate".

Can you speak more about the mod you're planing ?

Edited by Li0n
Link to comment
Share on other sites

53 minutes ago, Warezcrawler said:

Ok, I've been avoiding using onUpdate() and onFixedUpdate() because I really do not want to end up with a mod that is hitting performance.

Would a coroutine be better for performance? Or would the overhead of having the coroutine runnning be worse than just doing as Diazo is suggesting and just checking the throttlestate every frame?

(now I would be happy if I knew how to create and independent tread to run this process in - taking the load of the main tread)

 

What is the difference between these two? Is it that the bottom one would fire for all loaded vessels if I do this in a parts module, while the top one would only fire for the specific vessel?

Keep in mind that you have to run background logic of some sort to check the throttle to either throw an event or check in a coroutine anyway and I would lay odds that either of those would just be checking current throttle against a saved value anyway. A coroutine that checks once every 5 seconds would probably be lower overhead,  but I don't know how long a delay would be required for the coroutine to be less overhead then just checking every frame.

As for the two throttle objects, every vessel (including focus vessel) have a vessel.ctrlStat.mainThrottle.

However, the throttle UI object seen on screen is FlightInputHandler.state.mainThrottle and the vessel.ctrlState.mainThrottle seems to get slaved to this for the focus vessel. So any changes made to vessel.ctrlState.mainThrottle on the focus vessel don't take as the value in FlightInputHandler.state.mainThrtottle overwrites it.

It's been a few KSP versions since I tested that, but it is since KSP 1.0 or newer so I have no reason to think its changed.

D.

Edited by Diazo
Link to comment
Share on other sites

On 29/01/2017 at 6:36 PM, Diazo said:

Keep in mind that you have to run background logic of some sort to check the throttle to either throw an event or check in a coroutine anyway and I would lay odds that either of those would just be checking current throttle against a saved value anyway. A coroutine that checks once every 5 seconds would probably be lower overhead,  but I don't know how long a delay would be required for the coroutine to be less overhead then just checking every frame.

The overhead of checking all the time in update (main processing thread) bother me. I really get your point, and hope Squad will implement a stock event I can subscribe to.

In the meantime, I did some research and think I can implement this as a separate thread running in parallel with the main one for KSP/Unity. I'm thinking throwing a coroutine the continuously listens for the throttle in the parallel thread. I just tried it out in another plugin I have, where I use a coroutine to listens for an animation to finish before implementing the manipulations of the partModule, and it seems to work fine, even if I am aggressive in my execution of it. (basically the point of multithreads)

I will look something like this (might be errors)

public void SomeMethod()
{
  ....logic

  Thread parallelThread = new Thread(() => threadExecution(0.0f, 0.1f));
  parallelThread.Start();

  ..more logic
}

//The threading method have to return void I think
private void threadExecution(float starttime, float waitingtime)
{
  StartCoroutine(myCoroutine(starttime, waitingtime));
}

public float savedThrottle;
private IEnumerator myCoroutine(float starttime, float waitingtime)
{
  yield return new WaitForSeconds(starttime);
  while(true)
  {
	if (!HighLogic.LoadedSceneIsFlight) break;
	
	...coroutine logic

    if(savedThrottle != FlightInputHandler.state.mainThrottle)
    {
      //run code on throttle change here.
      savedThrottle = FlightInputHandler.state.mainThrottle;
      yield return new WaitForSeconds(waitingtime);
    }
	else yield return new WaitForSeconds(waitingtime);
  }
}

I think this approach could take the load of the main thread.... Maybe this is helpful to other mods as well, as an alternative to using Update() or OnUpdate(), if synchronous timing with main processes is not needed.

Link to comment
Share on other sites

On 29/01/2017 at 6:08 PM, Li0n said:

Can you speak more about the mod you're planing ?

My mod (collection) evolves around versatility of engines, converters and intake - and maybe more will come. Pretty much multimode of several modules. The engine one exists in stock, but only have two modes, while mine have as many as is configured. Most of the time I stop at 4, but whatever one feels like is possible.

The intake one is intended for removing the need of having multiple intake modules in an intake, just because you want IntakeAir and IntakeAtm as possibilities.

The converter switch (multimode) is for when you want the ISRU to have multiple mode, while thinking that having 10 different modes running simultaneously is just plain weird. This on restricts it to only have on running at any one time, and possibly only possible to change in VAB/SPH if you thus desire for your mod.

And, I've been looking into having the ISP curve be tied to the throttle ever since a fellow suggested it the thread of my mod. I originally turned it down since KSP 1.2 had an implementation of this. But I've been testing on it, and it does not seem to work.... If it does work, I can say I have been unsuccessful in getting it to work.

I posted a question in this regard, but got no answer

Since then I have been considering implementing this feature in my mod, and this thread was to find the best way to get the information regarding the throttle.

Link to comment
Share on other sites

I managed to create my first event, and it is even running in a separate thread. So event if I stress it, KSP keeps running smoothly, which it does not do if I do the same using coroutines.

I sharing it, for all those who are struggling with event's, thinking it could help somebody.

https://github.com/WarezCrawler/Guybrush101/blob/master/GTI_Utilities/GTI_Events.cs

First I initialize the event in it's own static class, which runs at the main menu.

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class GTI_EventCreator : MonoBehaviour
    {
        public static EventVoid onThrottleChange;

        private void Awake()
        {
            Debug.Log("[GTI] Event 'onThrottleChange' Created");
            if (onThrottleChange == null) onThrottleChange = new EventVoid("onThrottleChange");
        }
    }

Then in another class, I start the detection of the throttle to change. It starts a parallel process when in flight, which is cycling and checking the state of the throttle while in flight.

Spoiler

    [KSPAddon(KSPAddon.Startup.Flight, false)]
    public class GTI_Events : MonoBehaviour
    {
        private static float savedThrottle;
        private EventVoid onThrottleChangeEvent;
        public static bool EventDetectorRunning = false;
        private bool initEvent;
        private ConfigNode EventConfig;

        private void Awake()
        {
            //Load Config
            EventConfig = GetConfigurationsCFG();
            if (!bool.TryParse(EventConfig.GetValue("initEvent"), out initEvent)) initEvent = true;

            onThrottleChangeEvent = GameEvents.FindEvent<EventVoid>("onThrottleChange");
            
            //Starting the thread which will continuously check and raise the Throttle Event if interaction was detected
            startThread();
        }

        private void startThread()
        {
            if (initEvent)
            {
                if (!EventDetectorRunning)
                {
                    Thread EventThread = new Thread(() =>
                    {
                        //StartCoroutine(UpdateEvent());
                        EventDetectorRunning = true;
                        GTI_inFlightEventDetector();
                    });
                    Debug.Log("[GTI] Starting GTI Event thread");
                    EventThread.Start();
                }
                else Debug.Log("[GTI] GTI onThrottle event detector allready runnning. New Activation Cancelled.");
            }
            else
            {
                Debug.Log("[GTI] The GTI Event 'onThrottleChange' deactivated. initEvent was set to 'false'");
                Destroy(this.gameObject);
            }
        }
        private void GTI_inFlightEventDetector()        //For threaded execution --> Detects the basis for event
        {
            Debug.Log("[GTI] GTI_inFlightEventDetector Started in new thread");
            int EventCheckFreqIdle, EventCheckFreqActive;
            if (!int.TryParse(EventConfig.GetValue("EventCheckFreqIdle"),   out EventCheckFreqIdle  ))      EventCheckFreqIdle   = 500;
            if (!int.TryParse(EventConfig.GetValue("EventCheckFreqActive"), out EventCheckFreqActive))      EventCheckFreqActive = 100;
            int wait = EventCheckFreqIdle;

            //Stopwatch for timing how long the event checking is running
            System.Diagnostics.Stopwatch stopwatch;
            stopwatch = System.Diagnostics.Stopwatch.StartNew();

            Debug.Log("[GTI] Event thread GTI_inFlightEventDetector started\nEventCheckFreqIdle: " + EventCheckFreqIdle + "\nEventCheckFreqActive: " + EventCheckFreqActive);
            while (EventDetectorRunning)
            {
                if (savedThrottle != FlightInputHandler.state.mainThrottle)
                {
                    //run code on throttle change here.
                    savedThrottle = FlightInputHandler.state.mainThrottle;
                    onThrottleChangeEvent.Fire();
                    wait = EventCheckFreqActive;
                }
                else { wait = EventCheckFreqIdle; }

                Thread.Sleep(wait);
            }
            stopwatch.Stop();
            var ts = stopwatch.Elapsed;
            string elapsedTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
            Debug.Log("[GTI] GTI_inFlightEventDetector Stopped.\tRuntime = " + elapsedTime);
        }
        
        private void OnDestroy()
        {
            Debug.Log("[GTI] GTI_Events destroyed");
            EventDetectorRunning = false;
        }

        private ConfigNode GetConfigurationsCFG()
        {
            ConfigNode node;
            try
            {
                node = ConfigNode.Load(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/GTI_Config.cfg");
                node = node.GetNode("EventConfig");
            }
            catch
            {
                Debug.LogError("[GTI] " + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "/GTI_Config.cfg NOT FOUND");
                //manage NRE errors
              	node = new ConfigNode();
            }
            return node;
        }
    }
}

 

Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

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