Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Is there a way to add custom events like the ones provided by the GameEvents-class.

I created two of my own events like so:

[B]public[/B] static class CustomEvents
{
[B]public[/B] static EventData<ProtoVessel> [I]onStationCompleted[/I] = [B]new[/B] EventData<ProtoVessel>("StationCompleted");
[B]public[/B] static EventData<ProtoVessel> [I]onBaseCompleted[/I] = [B]new[/B] EventData<ProtoVessel>("BaseCompleted");
}

But I still had no luck actually firing those events.

This is how I add, fire and remove the events:


[...]
Debug.Log("Firing Station event"); // <-- appears in the log
CustomEvents.[I]onStationCompleted[/I].[B]Fire[/B](FlightGlobals.ActiveVessel.[I]protoVessel[/I]);
[...]

[B]protected[/B] override void [B]OnStart[/B]()
{
Debug.[B]Log[/B](" OnStart called!"); // <-- appears in the log
CustomEvents.[I]onStationCompleted[/I].[B]Add[/B]([B]new[/B] EventData<ProtoVessel>.OnEvent([B]OnStationCompleted[/B]));
CustomEvents.[I]onBaseCompleted[/I].[B]Add[/B]([B]new[/B] EventData<ProtoVessel>.OnEvent([B]OnBaseCompleted[/B]));
}

[B]protected[/B] override void [B]OnDestroy[/B]()
{
Debug.[B]Log[/B]("OnDestroy called!"); // <-- appears in the log
CustomEvents.[I]onStationCompleted[/I].[B]Remove[/B]([B]new[/B] EventData<ProtoVessel>.OnEvent([B]OnStationCompleted[/B]));
CustomEvents.[I]onBaseCompleted[/I].[B]Remove[/B]([B]new[/B] EventData<ProtoVessel>.OnEvent([B]OnBaseCompleted[/B]));
}

[B]private[/B] void [B]OnStationCompleted[/B](ProtoVessel pvessel)
{
Debug.Log("OnStationCompleted called!"); // <-- does NOT appear in the log
}

[B]private[/B] void [B]OnBaseCompleted[/B](ProtoVessel pvessel)
{
Debug.Log("OnBaseCompleted called!"); // <-- does NOT appear in the log
}

As you can see I did everything like with the normal GameEvents but the firing just doesn't call my functions at all. There's not even an error message in the log.

What have I done wrong and how can I fix it?

Edited by MoreUmpf
Link to comment
Share on other sites

Alright, very simple question.

There is the GameSettings Class that contains the keybinds in the game as KeyBinding objects.

I need to make a List<KeyBinding> from those keybinds and I don't want to copy-paste code 100 times to manually do each keybind.

Google says that this should work:

foreach (KeyBinding kb in typeof(GameSettings).GetFields().OfType<KeyBinding>()) //find all keybinds in the game
{
print("keybind " + kb.name);
}

But nothing prints. Note that no error is thrown either so I think I'm on the right track, I'm just looking for the wrong thing so that line of code currently returns zero items.

The issue being I have no clue what I need to change to find the keybinds as I want.

Anyone have any ideas?

D.

Link to comment
Share on other sites

Google says that this should work:

foreach (KeyBinding kb in typeof(GameSettings).GetFields().OfType<KeyBinding>()) //find all keybinds in the game
{
print("keybind " + kb.name);
}

But nothing prints. Note that no error is thrown either so I think I'm on the right track, I'm just looking for the wrong thing so that line of code currently returns zero items.

You've got it almost right but there are two bugs in your code. The first is that GetFields() doesn't return static fields by default. The second is that GetFields() returns an array of FieldInfo[] which means that any fields you did retrieve are immediately thrown out when comparing FieldInfo to KeyBinding in .OfType<KeyBinding>

foreach (FieldInfo kbInfo in typeof (GameSettings).GetFields(BindingFlags.Static | BindingFlags.Public)
.Where(fi => fi.FieldType == typeof(KeyBinding)))
{
var kb = kbInfo.GetValue(null) as KeyBinding;

_log.Normal("Keybinding: '" + kbInfo.Name + "' set to " + kb.primary + (kb.secondary != KeyCode.None ? (" and " + kb.secondary) : ""));
}

Link to comment
Share on other sites

Hi!

I am thinking of making a kind of wormhole mod with actual celestial bodies instead of parts. Now, my problem is how would I go about inverting my orbit calculation wise? What parameters of it have to be changed how?

Example: Ship is suborbital around body A going right round, and I have the parameters of it's orbit (FlightGlobals.ActiveVessel.orbit). Now, as with a real wormhole, your orbit on the other side (Body B) would be reversed. I know how to change it to go left round (add 180 to inclination), but how would I take into account eccentricity, position in orbit, and flip the direction of the 'eccentricity-bulge-direction'?

Edited by StratoK
Link to comment
Share on other sites

If I want to create an inventory of parts for a save, how do I go about doing this?

So you want to have parts allocated for specific game saves? I think you will have to use config nodes for this, but I'm not entirely sure how you would proceed from there.

My question: I'm trying to use ConfigNode to load a string array, but it does not return any results. It just says in the log "System.String[]" Is there a better way to load this information to compare data from the game? In this case, comparing stored values in my config node to the universal time in the game, such that there may be many results to retrieve. If there is no other way to retrieve the data, could someone help me troubleshoot this.

(I'm using a custom .cfg file in my mod folder for now)

string timeOfRestoration;
void Awake()
{
ConfigNode rtLoadNode = ConfigNode.Load("GameData/recoveryTimer/Recoveries.cfg");
Debug.Log(rtLoadNode.GetValues(timeOfRestoration));
}

And yes, I've made sure it's loading the correct file. I've got another line of code in my file to count the nodes in the file and it's returning the correct number so it's definitely working. Thanks.

Link to comment
Share on other sites

string timeOfRestoration;
void Awake()
{
ConfigNode rtLoadNode = ConfigNode.Load("GameData/recoveryTimer/Recoveries.cfg");
[COLOR=#ff0000]foreach (string s in rtLoadNode.GetValues(timeOfRestoration))
Debug.Log(s)[/COLOR]
}

You can't print a collection and expect to get something sensible, you have to print the elements of the collection

Link to comment
Share on other sites

Got a Q thats bugging me. When Timewarp is changed by altitude limits is there anyway to detect thats the reason? I tried looking at the altitude, but when the initial change happens the vessel is not actually at the altitude, and I cant simply check for keystrokes as a mod may be affecting the warp too.

Anyone got any good ideas?

Link to comment
Share on other sites

You checked the alt vs TimeWarp.fetch.GetAltitudeLimit(TimeWarp.fetch.current_rate_index, vessel.mainBody) ? I guess you could check with +1 and -1 on the index.

"when the initial change happens the vessel is not actually at the altitude". Do you see a small difference ? It may be that the alt used for the check is the alt of the the next frame position ( ie pos + velocity * TimeWarp.deltaTime )

Link to comment
Share on other sites

I'm not sure in which order the events for game loading and saving trigger.

So far I think it works like that:

Loading a game save

(KSP reads sfs file)
GameEvent.onGameStateLoaded.Fire() // returns ConfigNode
GameEvent.onGameStateCreated.Fire() // returns Game object

Saving a game save

GameEvent.onGameStateSave.Fire() // returns Game object
GameEvent.onGameStateSaved.Fire() // returns ConfigNode
(KSP writes sfs file)

Is that correct?

Link to comment
Share on other sites

For saving it is :


GameEvent.onGameStateSaved.Fire() // returns ConfigNode giving addons the opportunity to add data to the save
(KSP writes sfs file)
GameEvent.onGameStateSave.Fire() // returns Game object. Save is done

No idea for the Loaded/Created.

Link to comment
Share on other sites

Thank you. That helped a lot! :)

Next question: This gives an error.

[KSPAddon(KSPAddon.Startup.Flight,false)]
public class Test: MonoBehaviour
{
void Awake()
{
Debug.Log("Awake");
GameEvents.onGameStateCreated.Add((game) =>
{
Debug.Log("onGameStateCreated");
});
}
}

[LOG 17:22:44.052] Awake
[EXC 17:22:44.057] NullReferenceException: Object reference not set to an instance of an object
EventData`1+[Game]..ctor (.OnEvent )
EventData`1[Game].Add (.OnEvent evt)
TestNamespace.Test.Awake ()
UnityEngine.GameObject:AddComponent(Type)
AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup)
AddonLoader:StartAddons(Startup)
AddonLoader:OnLevelWasLoaded(Int32)

What's the problem here? Visual Studio accepts the code.

Link to comment
Share on other sites

Thank you. That helped a lot! :)

Next question: This gives an error.

[KSPAddon(KSPAddon.Startup.Flight,false)]
public class Test: MonoBehaviour
{
void Awake()
{
Debug.Log("Awake");
GameEvents.onGameStateCreated.Add((game) =>
{
Debug.Log("onGameStateCreated");
});
}
}

[LOG 17:22:44.052] Awake
[EXC 17:22:44.057] NullReferenceException: Object reference not set to an instance of an object
EventData`1+[Game]..ctor (.OnEvent )
EventData`1[Game].Add (.OnEvent evt)
TestNamespace.Test.Awake ()
UnityEngine.GameObject:AddComponent(Type)
AddonLoader:StartAddon(LoadedAssembly, Type, KSPAddon, Startup)
AddonLoader:StartAddons(Startup)
AddonLoader:OnLevelWasLoaded(Int32)

What's the problem here? Visual Studio accepts the code.

Anonymous methods don't deal well with GameEvents. You need something that can be removed, and since anonymous methods have no signature you couldn't remove the method from the event if you wanted to.

Link to comment
Share on other sites

You checked the alt vs TimeWarp.fetch.GetAltitudeLimit(TimeWarp.fetch.current_rate_index, vessel.mainBody) ? I guess you could check with +1 and -1 on the index.

"when the initial change happens the vessel is not actually at the altitude". Do you see a small difference ? It may be that the alt used for the check is the alt of the the next frame position ( ie pos + velocity * TimeWarp.deltaTime )

Thats the code I was checking to try and see between this and previously whether it had changed AltitudeLimits. I've got a feeling its dropping out based on some lookahead type thing, the Altitude is always greater than the limit when it drops out. I'll try the next frame position idea, thanks Sarbian

Link to comment
Share on other sites

I've got another question:

How can I query which Kerbal is assigned to which capsule seat in the editor crew screen?

I just can't find that information anywhere. part.protoModuleCrew.Count() always reports 0. It seems the only way is to parse the GUI via EditorPanels.Instance.crew (is a UIPanel). I bet there's a better way.

Link to comment
Share on other sites

I've got another question:

How can I query which Kerbal is assigned to which capsule seat in the editor crew screen?

I just can't find that information anywhere. part.protoModuleCrew.Count() always reports 0. It seems the only way is to parse the GUI via EditorPanels.Instance.crew (is a UIPanel). I bet there's a better way.

If you can get the information from the panel manager, I'm not sure what the issue is (you're not parsing the GUI, you're getting information from the class that controls the GUI). Crew is almost certainly added/associated with the vessel post-launch

Link to comment
Share on other sites

If you can get the information from the panel manager, I'm not sure what the issue is

I'm sure that's not how you should do that. There must be somekind of collection somewhere which contains the information which Kerbal goes to which seat. The GUI parses that collection and arranges panels, buttons, etc. according to that... if it works according to the MVC design pattern. And it's this collection I want to get.

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