Jump to content

The official unoffical "help a fellow plugin developer" thread


Recommended Posts

Is there anything I need to do to have a persistent scenario module?

I tried making an empty one that just logs when it enters a function, but onload and onsave are never called.

You need something to initialize it the first time. This will set which game scenes it will run in and store that in the persistent file. After that it should run onload and on save whenever you go to the relevant scene.

Most of the Scenario Modules I've seen use basically the same method, so I would just check around.

Link to comment
Share on other sites

You need something to initialize it the first time. This will set which game scenes it will run in and store that in the persistent file. After that it should run onload and on save whenever you go to the relevant scene.

Most of the Scenario Modules I've seen use basically the same method, so I would just check around.

Ok, so basically that's what Taranis is doing with this method, right?

Link to comment
Share on other sites

Uh, maybe I'm doing something wrong here.

I am shamelessly copying Taranis' code to inject my module into the game (hi!), but at the beginning of each scene, I get this popup:

S3NZ3Zw.png

Also, in the persistent file, there is this:


SCENARIO
{
name = TestScenarioModule
scene = 5, 7, 6, 9
aSavedValue = modified and resumed from the persistent save
}

I should also note that I tried logging when my module executes OnLoad and OnSave, and got no signs of life from it. Here's the code in pastebin.

:(

Link to comment
Share on other sites

Uh, maybe I'm doing something wrong here.

You're going to smack your head on the desk in about five seconds when I bold some stuff for you

Also, in the persistent file, there is this:


SCENARIO
{
name = [SIZE=5][SIZE=3][B]TestScenarioModule[/B][/SIZE][/SIZE]
scene = 5, 7, 6, 9
aSavedValue = modified and resumed from the persistent save
}

[snip]
ProtoScenarioModule psm = game.scenarios.Find(s => s.moduleName == typeof([SIZE=5][B]TestScenarioModule[/B][/SIZE]).Name);
if (psm == null)
{
Debug.Log("Adding the scenario module.");
psm = game.AddProtoScenarioModule(typeof([B][SIZE=5]TestScenarioModule[/SIZE][/B]), GameScenes.SPACECENTER,
GameScenes.FLIGHT, GameScenes.EDITOR, GameScenes.SPH);
[...snip]

public class [SIZE=3][B][SIZE=5]TestSM [/SIZE][/B][/SIZE]: ScenarioModule

So you're actually adding a ScenarioModule called TestScenarioModule to the game. Unluckily for you, the game has one and it apparently writes a test value to the persistent file and opens a popup to display it. Your ScenarioModule, TestSM, never runs so of course you never see any output

:)

Link to comment
Share on other sites

Because it has come up and I am doing exactly the same thing, here is the code that I am using to do this.

Posting it so Ippo can see how I do it and for other people to comment if they see something wonky.

This loads a scenario called OSJFlight

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using UnityEngine;

namespace OnScreenJoyStick
{
[KSPAddon(KSPAddon.Startup.SpaceCentre, false)] //install our scenario module. is a partmodule so all calculations can be done in it, no need for a seperate plugin class in the scene
class OSJMainMenu : MonoBehaviour
{
public void Start()
{
var game = HighLogic.CurrentGame;
ProtoScenarioModule psm = game.scenarios.Find(s => s.moduleName == typeof(OSJFlight).Name);
if (psm == null)
{
psm = game.AddProtoScenarioModule(typeof(OSJFlight), GameScenes.FLIGHT);
}
}
}
public class OSJFlight : ScenarioModule //this runs on flight scene start, no need for the KSPAddon as it is already loaded by the code in the SpaceCenter screen.
{
//All your plug in code here. Start, Update, FixedUpdate, OnSave, OnLoad, etc. all work as they do in a partmodule.
}
}

The only thing about this is that I could not get the scenario to load if I used KSPAddon.Startup.MainMenu instead of .SpaceCenter.

Not an issue for my current project as it runs in the flight scene only, but if what you are doing requires code to run on game start (such as a new career game with some sort of mission maybe?), that issue would have to be figured out.

So, how close am I to how other people are doing this?

D.

Link to comment
Share on other sites

The only thing about this is that I could not get the scenario to load if I used KSPAddon.Startup.MainMenu instead of .SpaceCenter.

Not an issue for my current project as it runs in the flight scene only, but if what you are doing requires code to run on game start (such as a new career game with some sort of mission maybe?), that issue would have to be figured out.

That's because ScenarioModules are created on a per-persistent file basis. That's how the actual Scenarios ingame are made; they're just save games that somebody has manually added a savegame-specific ScenarioModule to. The main menu isn't associated with any particular game session so it wouldn't make sense for one to be loaded there.

If you did need to run code before game start, I'd probably go with a separate, non-ScenarioModule KSPAddon that persisted between scenes. Once the player has loaded up a game, you could do whatever it is you wanted: store some info you collected during the main menu into your ScenarioModule, call a function or set up some parameters, etc. Then kill it and run your logic as normal

Link to comment
Share on other sites

I'm trying to make a plug-in to automatically post screenshots to imgur. Is there an API I can use to take screenshots at will, or a way to hook into the F1 keypress event so I know a screenshot has been taken?

Link to comment
Share on other sites

I don't know about the API, but this will detect if the screenshot key is pressed. (Variables names not exact as this is from memory.)


public void Update()
{
if(gameSettings.Screenshot.KeyCode != KeyCode.None & input.getkeydown(gameSettings.Screenshot.KeyCode))
{
print("ScreenShot!");
}

I'm pulling the screenshot key from the settings file here, that way if the player binds screenshot to another key, it will still be recognized.

You also need to check that the keycode is not None as input.GetKeyDown returnes KeyCode.None if there is no key pressed that update. (I think, it may also return null, testing would be required.)

D.

Edited by Diazo
Link to comment
Share on other sites

Thanks for the reply, that's along the lines of what I am looking for. But, how do I access the gameSettings object? Searching through the object browser, I see GameSettings is a class within Assembly-CSharp, however I don't see a "Screenshot" member within it. Furthermore, I can't seem to access anything Assembly-CSharp from within my code, although there is a reference to it in my project.

I feel as though I am missing something key here, such as which classes should I be exploring to learn how to interact with the game? Is there a dev wiki that I haven't been able to find? I am using some sample code I found here http://forum.kerbalspaceprogram.com/threads/56053-Example-plugin-projects-to-help-you-get-started

Link to comment
Share on other sites

Alright, just to check you have the following set as dependencies correct?

Assembly-CSharp

UnityEngine

Assembly-CSHarp-firstpass <- Optional, this is more for interacting with the GUI then the 3D game space.

and then you added

using UnityEngine;

at the top of your project underneath all the other using statements that get added by default?

D.

Link to comment
Share on other sites

Yes, but I can't seem to access anything within the Assembly-CSharp class. In fact, Intellisense does not show it as an option, and typing "Assembly-CSharp.gameSettings" generates an error in the IDE. Is this something to do with the hyphen in the class name? I am more of a VB guy and am relatively new to C# so perhaps I'm doing something stupid.

Link to comment
Share on other sites

It's not a class. Here's a minimal example to get you started:

using System;
using UnityEngine;

namespace TestPlugin
{
[KSPAddon(KSPAddon.Startup.Flight, false)]
public class ScreenshotTest : MonoBehaviour
{
void Update()
{
if (GameSettings.TAKE_SCREENSHOT.GetKeyDown())
Debug.Log("A screenshot was just taken!");
}
}
}

If you have your references set up correctly, that will compile and you can start to tweak it as you like

Link to comment
Share on other sites

Hi,

I have this in a part module attached to an RCS block. It doesn't add any resources (I have tried Oxidizer also). I have also tried commenting out the if statement, and it still doesn't work. I've tried putting the code in OnFixedUpdate also. I got the part.RequestResource to work in another part module. What am I doing wrong here? Would OnFixedUpdate work better?

private void OnDraw(){

if (CompressAir == true) {

part.RequestResource("IntakeAir", -10);

}

}

One more thing,

[KSPEvent(guiActive = true, guiName = "Stop Compressing", active = true)]

public void StopCompression(){

CompressAir = false;

}

I want to change "active = true" to "active = CompressAir" so the "Stop Compressing" button is only active when it is compressing. Instead, it gives me an error. How do I fix this?

Link to comment
Share on other sites

On your first question about resources, I'm not sure as I have not dealt with them a lot. My only thought is do you have resource storage anywhere? Even just an placeholder with a storage size of 0?

I remember reading something about that if there is no storage location present on the vessel, the resource does not generate as there is no place for KSP to put it. To get around this you have to add storage to your part, just with a maxSize of 0 so it does not store any resource.

On the KSPEvent active question, I believe it is because the KSPEvent is pre-compiled and so the CompressAir variable does not exist. Instead, in your code where you change the state of CompressAir, add a KSPEvent.active = true (or false) as needed. (Syntax from memory and not correct.)

Hope that helps.

D.

Link to comment
Share on other sites

Actually it's because KSPEvent is an attribute, so when you declare it like that you can only use compile-time constants. You cannot use your variable directly, you will need to set the value each time:


[COLOR=#333333]private void OnDraw(){[/COLOR]
[COLOR=#333333]if (CompressAir == true) {[/COLOR]
[COLOR=#333333]part.RequestResource("IntakeAir", -10);
[/COLOR]this.Events["StopCompression"].active = true;
[COLOR=#333333]}[/COLOR]
[COLOR=#333333]}[/COLOR]


[COLOR=#333333][KSPEvent(guiActive = true, guiName = "Stop Compressing", active = true)][/COLOR]
[COLOR=#333333]public void StopCompression(){[/COLOR]
[COLOR=#333333]CompressAir = false;
[/COLOR]this.Events["StopCompression"].active = false;
[COLOR=#333333]}

Link to comment
Share on other sites

How can I run some code when a part collides?

Specifically, I would like to run some calculations based on the impact velocity. I see that Part has three OnCollision* methods, but how can I get an event out of them in a PartModule?

Link to comment
Share on other sites

It's not a class. Here's a minimal example to get you started:

using System;
using UnityEngine;

namespace TestPlugin
{
[KSPAddon(KSPAddon.Startup.Flight, false)]
public class ScreenshotTest : MonoBehaviour
{
void Update()
{
if (GameSettings.TAKE_SCREENSHOT.GetKeyDown())
Debug.Log("A screenshot was just taken!");
}
}
}

If you have your references set up correctly, that will compile and you can start to tweak it as you like

Thank you, that helped. Can you do me another favor and list the main classes I should explore to learn more about interacting with the game?

Link to comment
Share on other sites

Thank you, that helped. Can you do me another favor and list the main classes I should explore to learn more about interacting with the game?

Friendy reminder that decompiling is prohibited by the EULA and that this could put you into some serious trouble. However, you can use an assembly browser to look at the declarations of public members of the KSP classes without looking at the underlying code, which is permitted. And for what you need, it depends on what you want to do. FlightGlobals and HighLogic are useful classes, though most of what you will use will be Unity classes, and the docs for those are all around the internet.

Link to comment
Share on other sites

Hi again,

For some reason, this code doesn't seem to be working.

public override void OnFixedUpdate(){

print ("This should say something...");

if (CompressAir == true) {

print ("Should be compressing air...");

part.RequestResource("Oxidizer", -10);

}

}

I think that should spam the log with at least one message every FixedUpdate. But, it doesn't, even when it's OnDraw. The KSPEvent buttons are able to print things to the log, but why can't I do this OnDraw or OnFixedUpdate?

Thanks in advance.

Link to comment
Share on other sites

Hi again,

For some reason, this code doesn't seem to be working.

public override void OnFixedUpdate(){

print ("This should say something...");

if (CompressAir == true) {

print ("Should be compressing air...");

part.RequestResource("Oxidizer", -10);

}

}

I think that should spam the log with at least one message every FixedUpdate. But, it doesn't, even when it's OnDraw. The KSPEvent buttons are able to print things to the log, but why can't I do this OnDraw or OnFixedUpdate?

Thanks in advance.

Use Debug.Log to write stuff to the log.

Also, please use the

 tags when posting code.
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...