Jump to content

First time plugin making, let's get some help.


Recommended Posts

6 years of JAVA coding, think I understand C# now.

But still a bummer on plugin making, so why not make this thread useful?

My current objective is; make a fuel tank that drains(dump) liquid fuel.

using UnityEngine;
using FirstPlugIn.Extensions;
using KSP.IO;

namespace FirstPlugIn
{
public class FirstPlugIn : PartModule
{
public static Rect windowPos = new Rect(); // Made a window
private GUIStyle windowStyle, labelStyle;
private bool hasInitStyle = false;

private double fuel; // Saves fuel amount in tank.

[KSPEvent(guiActive = true, guiName = "Dump Fuel")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Dumping Fuel", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Stop", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Stopped Dumping", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}

public override void OnStart(StartState state)
{
if (state != StartState.Editor)
{
if (!hasInitStyle)
InitStyles();
RenderingManager.AddToPostDrawQueue(0, OnDraw);

fuel = this.vessel.GetActiveResource(new PartResourceDefinition("LiquidFuel")).amount;
}
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel)
{
this.rigidbody.AddRelativeForce(Vector3.up * 1000f * FlightInputHandler.state.mainThrottle);

if(Events["ActivateEvent"].active)
{
if (fuel >= 0)
fuel--;

this.vessel.GetActiveResource(new PartResourceDefinition("LiquidFuel")).amount = fuel;
Debug.Log(this.vessel.GetActiveResource(new PartResourceDefinition("LiquidFuel")).amount);
}
}
}

private void OnDraw()
{
if (this.vessel == FlightGlobals.ActiveVessel && this.part.IsPrimary(this.vessel.Parts, this.ClassID))
{
windowPos = GUILayout.Window(10, windowPos, OnWindow, "Hello World!", windowStyle);

if(windowPos.x == 0f && windowPos.y == 0f)
{
windowPos = windowPos.CenterScreen();
}
}
}

private void OnWindow(int windowID)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Hello World! This is a Label", labelStyle);
GUILayout.EndHorizontal();

GUI.DragWindow();
}

private void InitStyles()
{
windowStyle = new GUIStyle(HighLogic.Skin.window);
windowStyle.fixedWidth = 250f;

labelStyle = new GUIStyle(HighLogic.Skin.label);
labelStyle.stretchWidth = true;

hasInitStyle = true;
}

public override void OnSave(ConfigNode node)
{
if (this.vessel == FlightGlobals.ActiveVessel)
{
PluginConfiguration config = PluginConfiguration.CreateForType<FirstPlugIn>();

config.SetValue("Window Position", windowPos);
config.save();
}
}

public override void OnLoad(ConfigNode node)
{
PluginConfiguration config = PluginConfiguration.CreateForType<FirstPlugIn>();

config.load();
windowPos = config.GetValue<Rect>("Window Position");
}
}
}

Had an idea of storing fuel amount when start, then use this value to chage the fuel amount on update.

Expected output is to display the text "Dumping Fuel" and "Stopped Dumping", as well as drain the fuel from the tank too.

Text display works, but when I check the fuel gauge, it remains still. Am I using a wrong resource method?

Link to comment
Share on other sites

Alright, so I found PartResource and PartResourceDefinition.

I guess PartResrouce is the actual resource, but don't know if it is pointting the liquid fuel. Guess I have to use PartResourceDefinision to use PartResource????

Link to comment
Share on other sites

So I looked into my .cfg file,

Originally, had RESOURCE outside of MODULE, but now I see other people's .cfg files including RESOURCE inside of MODULE.

So I guess I'll have to change my .cfg to


MODULE
{
name=FirstPlugIn

RESOURCE
{
name = LiquidFuel
amount = 540
maxAmount = 540
}

RESOURCE
{
name = Oxidizer
amount = 660
maxAmount = 660
}
}

Something like this and call the resource via plugin?

Link to comment
Share on other sites

So instead of working with right-click option, I decided to look into resource management first.

I've been reading through Mu's 0.15 code update, and found out about part.RequestResource method.

So on the Update method, I added RequestResource method to 'request' fuel on every frame.

using UnityEngine;
using FirstPlugIn.Extensions;
using KSP.IO;

namespace FirstPlugIn
{
public class FirstPlugIn : PartModule
{
public static Rect windowPos = new Rect(); // Made a window
private GUIStyle windowStyle, labelStyle;
private bool hasInitStyle = false;

private PartResourceDefinition fuel;
private FuelTank ft;

[KSPEvent(guiActive = true, guiName = "Dump Fuel")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Dumping Fuel", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Stop", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Stopped Dumping", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}

public override void OnStart(StartState state)
{
if (state != StartState.Editor)
{
if (!hasInitStyle)
InitStyles();
RenderingManager.AddToPostDrawQueue(0, OnDraw);

foreach(Part part in vessel.parts)
{
if (part is FuelTank)
ft = (FuelTank)part;
}

// Dead Code
fuel = new PartResourceDefinition("LiquidFuel");
}
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel)
{
this.rigidbody.AddRelativeForce(Vector3.up * 1000f * FlightInputHandler.state.mainThrottle); // Just a silly code to see if it flies

part.RequestResource("LiquidFuel", 1); // Request 1 unit of fuel from(or to) somewhere I don't know.
}
}

private void OnDraw()
{
if (this.vessel == FlightGlobals.ActiveVessel && this.part.IsPrimary(this.vessel.Parts, this.ClassID))
{
windowPos = GUILayout.Window(10, windowPos, OnWindow, "Hello World!", windowStyle);

if(windowPos.x == 0f && windowPos.y == 0f)
{
windowPos = windowPos.CenterScreen();
}
}
}

private void OnWindow(int windowID)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Hello World! This is a Label", labelStyle);
GUILayout.EndHorizontal();

GUI.DragWindow();
}

private void InitStyles()
{
windowStyle = new GUIStyle(HighLogic.Skin.window);
windowStyle.fixedWidth = 250f;

labelStyle = new GUIStyle(HighLogic.Skin.label);
labelStyle.stretchWidth = true;

hasInitStyle = true;
}

public override void OnSave(ConfigNode node)
{
if (this.vessel == FlightGlobals.ActiveVessel)
{
PluginConfiguration config = PluginConfiguration.CreateForType<FirstPlugIn>();

config.SetValue("Window Position", windowPos);
config.save();
}
}

public override void OnLoad(ConfigNode node)
{
PluginConfiguration config = PluginConfiguration.CreateForType<FirstPlugIn>();

config.load();
windowPos = config.GetValue<Rect>("Window Position");
}
}
}

Question now is, will it work with multiple same fuel tanks and crossfeed each other? (For balancing purpose that is)

Link to comment
Share on other sites

Take a look at my code that simulates a tank leak.

When using part.RequestResource, the resource will be fetched using the usual flow rules, so basically from the furthest tank of the same resource that can be reached. Also, you can stop it by using those little green buttons in the right click menu.

By the way, that method also returns the amount of resource that it was actually able to consume, so:


if ( part.RequestResource("LiquidFuel", myAmount ) < myAmount ) // there isn't enough liquid fuel

Keep in mind though that it does request it on every frame, so 1 per frame -> ~30 units per second. You might want to do your computations using seconds, and then convert it using TimeWarp.fixedDeltaTime;

Link to comment
Share on other sites

Thanks for the code, I'll look into it :D

Reason for adding a right-click option is to make this fuel dumping plugin turn into a generator (Liquid Fuel -> Electricity)

So far I have tried radial attaching(4 fuel tanks), and each fuel tank works as expected.

However, is there a way to balance these fuel tanks so they dump liquid fuel equally? (Crossfeeing without fuel lines that is)

Code so far

using UnityEngine;
using FirstPlugIn.Extensions;
using KSP.IO;
using System.Collections;

namespace FirstPlugIn
{
public class FirstPlugIn : PartModule
{
public static Rect windowPos = new Rect(); // Made a window
private GUIStyle windowStyle, labelStyle;
private bool hasInitStyle = false;

[KSPEvent(guiActive = true, guiName = "Dump Fuel")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Dumping Fuel", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Stop Dump", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Stopped Dumping", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}

public override void OnStart(StartState state)
{
if (state != StartState.Editor)
{
if (!hasInitStyle)
InitStyles();
RenderingManager.AddToPostDrawQueue(0, OnDraw);
}
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel)
{
this.rigidbody.AddRelativeForce(Vector3.up * 1000f * FlightInputHandler.state.mainThrottle);

if(Events["DeactivateEvent"].active)
{
part.RequestResource("LiquidFuel", 1);
}
}
}

private void OnDraw()
{
if (this.vessel == FlightGlobals.ActiveVessel && this.part.IsPrimary(this.vessel.Parts, this.ClassID))
{
windowPos = GUILayout.Window(10, windowPos, OnWindow, "Hello World!", windowStyle);

if(windowPos.x == 0f && windowPos.y == 0f)
{
windowPos = windowPos.CenterScreen();
}
}
}

private void OnWindow(int windowID)
{
GUILayout.BeginHorizontal();
GUILayout.Label("Hello World! This is a Label", labelStyle);
GUILayout.EndHorizontal();

GUI.DragWindow();
}

private void InitStyles()
{
windowStyle = new GUIStyle(HighLogic.Skin.window);
windowStyle.fixedWidth = 250f;

labelStyle = new GUIStyle(HighLogic.Skin.label);
labelStyle.stretchWidth = true;

hasInitStyle = true;
}

public override void OnSave(ConfigNode node)
{
if (this.vessel == FlightGlobals.ActiveVessel)
{
PluginConfiguration config = PluginConfiguration.CreateForType<FirstPlugIn>();

config.SetValue("Window Position", windowPos);
config.save();
}
}

public override void OnLoad(ConfigNode node)
{
PluginConfiguration config = PluginConfiguration.CreateForType<FirstPlugIn>();

config.load();
windowPos = config.GetValue<Rect>("Window Position");
}
}
}

Think I should move that GUI sample to separate module. It's getting messy :P

Link to comment
Share on other sites

However, is there a way to balance these fuel tanks so they dump liquid fuel equally? (Crossfeeing without fuel lines that is)

Not that I know of: probably not through stock KSP, you'll need to manually find your tanks and update each of them.

Link to comment
Share on other sites

Day Two on Mod making, tidy things up and made it to work (single fuel tank it is)

I found this.vessel.parts. Think I can store all the same type of parts(ie. my fuel tank) as a List, use them to balance each other.

Question is, how can I identify these parts from other parts?

Power Generator code (Changed so I can stretch my goals)

using UnityEngine;
using KSP.IO;
using System.Collections;

namespace PowerGenerator
{
public class PowerGenerator : PartModule
{
public override void OnUpdate()
{
this.part.PumpFuel(Events["DeactivateEvent"].active);
}

[KSPEvent(guiActive = true, guiName = "Dump Fuel")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Dumping Fuel", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Stop Dump", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Stopped Dumping", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}
}
}

Generator property code -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace PowerGenerator
{
public static class GeneratorProp
{
public static void PumpFuel(this Part part, bool isActivated)
{
if (isActivated)
part.RequestResource("LiquidFuel", 0.05f);
}
}
}

Link to comment
Share on other sites

4 Fuel tanks attached on a command pod, dumping fuel individually so far.

So to dump fuel, use RequestResoure(), then how do I actually acquire fuel from other tanks?

I see RequestResource() and RequestFuel(). Looks like RequestFuel() has another parameter to check request ID, then how am I to call this request ID from other tanks?

Link to comment
Share on other sites

So I've tried

part.RequestFuel(part, 0.05f, (uint)part.ClassID);

Part is part itself, 0.05f as amount, and part.ClassID as request ID, but didn't work.

Do I use this method when I actually receive fuel?

Link to comment
Share on other sites

It just occurred to me that you are trying to make a generator (yes, I didn't read very carefully: sorry).

You could make it work like this, but you are probably better off by deriving ModuleGenerator: check it out, it's a part module that specifically handles resource generators (it's the same one used by RTGs for example).

In fact, you might not even need to do it: unless you are trying to do something fancy, you can just add this to the part.cfg file:


MODULE
{
name = ModuleGenerator
isAlwaysActive = False
activateGUIName = Fire up
shutdownGUIName = Shut down

INPUT_RESOURCE
{
name = LiquidFuel
rate = 0.09
}

INPUT_RESOURCE
{
name = Oxidizer
rate = 0.11
}

OUTPUT_RESOURCE
{
name = ElectricCharge
rate = 2
}
}

Link to comment
Share on other sites

It just occurred to me that you are trying to make a generator (yes, I didn't read very carefully: sorry).

You could make it work like this, but you are probably better off by deriving ModuleGenerator: check it out, it's a part module that specifically handles resource generators (it's the same one used by RTGs for example).

Well for now I'm making things with existing resources so I can get an idea of how resources are handled in a plugin.

At the end, I'd like to stretch my goal to a fuel cell plugin that simulates Hydrogen and Oxygen reaction.

Maybe I can still use existing ModuleGenerator and just change the input and output, but I don't know, I want to simulate more things like waste management and sort of things.

Link to comment
Share on other sites

Will it be possible to manage resources in separate classes/variables? Like,


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using KSP.IO;

namespace PowerGenerator
{
public class ModResource
{
private string name;
private float amount;

public ModResource(string name, float amount)
{

}

public ModResource(PartResource resource, float amount)
{
name = resource.name;
this.amount = amount;
}
}
}

Then mabye you can create separate object for resource that handles amount and type easily and apply it to lower level methods(ie. RequestFuel)?

Link to comment
Share on other sites

So far I have wrote


// Used to store multiple resources (IF there is more than one)
List<ModResource> resources;

public PartResource fuel;

public override void OnStart(PartModule.StartState state)
{
// Create empty list of Modifed resources
resources = new List<ModResource>();

// If there are at least one resource in this part
if(this.part.Resources.Count > 0)
{
// For each resources, get PartResource and it's parent part
foreach(PartResource resource in this.part.Resources)
{
resources.Add(new ModResource(resource, this.part));
}
}

// Below deprecated
fuel = new PartResource();
fuel.SetInfo(new PartResourceDefinition("LiquidFuel"));

foreach(PartResource resource in part.Resources)
{
if(resource is PartResource && (resource.GetInfo() == fuel.GetInfo()))
{
fuel.amount = resource.amount;
fuel.maxAmount = resource.maxAmount;
break;
}
}
}

Then I questioned myself if it is possible to use this modified resource object to control actual fuel tank??

Link to comment
Share on other sites

Well, it's just a wrapper around it, so it would work. However, if you are writing a PartModule, this.part.Resources will only give you the resources contained inside the part, not the whole vessel: so you can't get the other fuel tanks this way.

You would need to write a partless plugin that scans all the parts in the vessel for that. I think there was a tutorial for partless plugins around here, but I can't seem to find it right now.

Link to comment
Share on other sites

Well, it's just a wrapper around it, so it would work. However, if you are writing a PartModule, this.part.Resources will only give you the resources contained inside the part, not the whole vessel: so you can't get the other fuel tanks this way.

You would need to write a partless plugin that scans all the parts in the vessel for that. I think there was a tutorial for partless plugins around here, but I can't seem to find it right now.

Oh yes, I've read about part/partless plugins. Think I know how to code it.

Though I'm still not cleared on how resource structures are made in KSP, so gonna take bit more time tweaking around on it.

Link to comment
Share on other sites

Been testing multiple ways to dump fuel through plugin, and three methods so far.


try
{
// Method 1, direct change.
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "LiquidFuel")
{
resource.amount = 50;

if (resource.amount == 50)
{
Debug.Log("Method 1 Worked!");
resource.amount = resource.maxAmount;
}
else Debug.Log("Method 1 failed!");
}
}
catch(MissingReferenceException e)
{
Debug.Log("Cannot use this Method 1!");
}

try
{
// Method 2, uses fuel object to change amount and sends it back to actual resource
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "LiquidFuel")
{
fuel = resource;
fuel.amount = 50;
resource.amount = fuel.amount;

if (resource.amount == 50)
{
Debug.Log("Method 2 workd!");
resource.amount = resource.maxAmount;
}
else Debug.Log("Method 2 failed!");
}
}
catch (MissingReferenceException e)
{
Debug.Log("Cannot use this Method 2!");
}

// Method 3, this for sure works as it goes through entire vessel
foreach(Part part in vessel.parts)
foreach(PartResource resource in part.Resources)
{
if (resource.resourceName == "LiquidFuel")
{
fuel = resource;
fuel.amount = 50;
resource.amount = fuel.amount;
Debug.Log("Force changed resource: " + fuel.name + ", " + resource.amount);
}

Debug.Log("resource info : " + resource.name + " Contains : " + resource.resourceName + ", " + resource.amount + ", " + resource.maxAmount);
}

So figured out you can directly change the fuel amount through this, so I guess I can use this to add up the electrical chage throughout the ship.

Well, onward to figure out how to send resources throughout the ship.

Link to comment
Share on other sites

Alright, so I've added ElectricChage to my .cfg file as one of my RESOURCE, turns out, KSP cannot take extra resource in the cfg, causing the entire model in VAB to grow infinite size. Only two resources available in .cfg, think I have to find detour on power generating.

I'm thinking since I can use 2 resources at least, modify them and simulate them as if they were drawn by the generator, then add some electric charges to whatever part that takes electric charges.

Link to comment
Share on other sites

One more thing I found out, whenever I try to test my fuel tank with command pod attached to it, it throws NullReferenceException, so I tested another ship without my part, didn't throw any NullReferenceException. So for sure it comes from my plugin.

But I'm not sure where it's coming from. I pretty much deleted any unused varibales and nothing in my code is being referenced as NULL so gotta figure out where it's coming from.

EDIT : Well, turns out it was KSP's bug switching scene directly from Spacecenter to Flight. I've tried switching view from Editor to Flight, NullRefereceException wasn't thrown so good to know my plugin works without any problems.

Just for the sake of logging, here is the part where it throws Exception.


[HighLogic]: =========================== Scene Change : From SPACECENTER to FLIGHT =====================

(Filename: C:/BuildAgent/work/d3d49558e4d408f4/artifacts/StandalonePlayerGenerated/UnityEngineDebug.cpp Line: 53)

NullReferenceException
at (wrapper managed-to-native) UnityEngine.Component:InternalGetTransform ()

at UnityEngine.Component.get_transform () [0x00000] in <filename unknown>:0

at SpaceCenterCamera2.UpdateTransformOverview () [0x00000] in <filename unknown>:0

at SpaceCenterCamera2.UpdateTransform () [0x00000] in <filename unknown>:0

at SpaceCenterCamera2.Update () [0x00000] in <filename unknown>:0

(Filename: Line: -1)

NullReferenceException: Object reference not set to an instance of an object
at TimeWarp.Update () [0x00000] in <filename unknown>:0

(Filename: Line: -1)

UnloadTime: 5.479031 ms
Unloading 1 Unused Serialized files (Serialized files now loaded: 0 / Dirty serialized files: 0)

Unloading 1572 unused Assets to reduce memory usage. Loaded Objects now: 69229.
Total: 97.938026 ms (FindLiveObjects: 4.513797 ms CreateObjectMapping: 4.379476 ms MarkObjects: 86.971039 ms DeleteObjects: 1.620772 ms)

Unloading 0 Unused Serialized files (Serialized files now loaded: 0 / Dirty serialized files: 0)

Unloading 0 unused Assets to reduce memory usage. Loaded Objects now: 69217.
Total: 97.722038 ms (FindLiveObjects: 5.645035 ms CreateObjectMapping: 4.918097 ms MarkObjects: 86.561371 ms DeleteObjects: 0.183854 ms)

UnloadTime: 3.596311 ms
Unloading 3 Unused Serialized files (Serialized files now loaded: 0 / Dirty serialized files: 0)

Unloading 78 unused Assets to reduce memory usage. Loaded Objects now: 71084.
Total: 110.833687 ms (FindLiveObjects: 5.951607 ms CreateObjectMapping: 5.797652 ms MarkObjects: 98.133919 ms DeleteObjects: 0.420365 ms)

------------------- initializing flight mode... ------------------

Edited by CSX_Ind
Link to comment
Share on other sites

Finally got to simulate VERY simple fuel cell with existing resources.

Still need to calculate electric charge distribution throughout the vessel. But I think it's good time to stretch my goal here now.

PowerGenerator.cs


using UnityEngine;
using KSP.IO;
using System.Collections.Generic;

namespace PowerGenerator
{
public class PowerGenerator : PartModule
{
public override void OnStart(PartModule.StartState state)
{
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel && this.part.isPrimary(this.vessel.parts, this.ClassID))
if(this.part.PumpFuel(Events["DeactivateEvent"].active))
{
foreach (Part part in this.vessel.parts)
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "ElectricCharge")
resource.amount += 0.04 * Time.deltaTime;
}
}

[KSPEvent(guiActive = true, guiName = "Dump Fuel")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Dumping Fuel", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Stop Dump", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Stopped Dumping", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}
}
}

GeneratorProp.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace PowerGenerator
{
public static class GeneratorProp
{
public static bool PumpFuel(this Part part, bool isActivated)
{
if (isActivated)
{
foreach (PartResource resource in part.Resources)
{
if (resource.resourceName == "LiquidFuel")
{
if (resource.amount > 0)
resource.amount -= 0.02 * Time.deltaTime;
else return false;
}
else if (resource.resourceName == "Oxidizer")
{
if(resource.amount > 0)
resource.amount -= 0.01 * Time.deltaTime;
}
}
return true;
}
return false;
}

public static bool isPrimary(this Part checkPart, List<Part> parts, int partModuleID)
{
foreach(Part part in parts)
{
if (part.Modules.Contains(partModuleID))
if (part == checkPart)
return true;
}

return false;
}
}
}

Going to stretch my goal to add my own resource(ie. Hydrogen and Oxygen) then simulate fuel cell from it.

Link to comment
Share on other sites

Day Three on Fuel Cell plugin making, cleaned up my code since GeneratorProp was a bit overkill.


using UnityEngine;
using KSP.IO;
using System.Collections.Generic;

namespace PowerGenerator
{
public class PowerGenerator : PartModule
{
PartResource fuel, oxyg;
public override void OnStart(PartModule.StartState state)
{
foreach (PartResource resource in part.Resources)
{
if (resource.resourceName == "LiquidFuel")
fuel = resource;
if (resource.resourceName == "Oxidizer")
oxyg = resource;
}
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel && this.part.isPrimary(this.vessel.parts, this.ClassID))
{
if (ActivateGenerator(Events["DeactivateEvent"].active))
{
foreach (Part part in this.vessel.parts)
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "ElectricCharge" && (resource.amount < resource.maxAmount))
resource.amount += 0.04 * Time.deltaTime;
}

UpdateResources();
}
}

private bool ActivateGenerator(bool isActivated)
{
if (isActivated)
{
if (fuel.amount > 0)
{
fuel.amount -= 0.02 * Time.deltaTime;
if (oxyg.amount > 0)
{
oxyg.amount -= 0.01 * Time.deltaTime;
return true;
}
else return false;
}
else return false;
}
return false;
}

private void UpdateResources()
{
foreach(PartResource resource in part.Resources)
{
if (resource.resourceName == fuel.resourceName)
resource.amount = fuel.amount;
if (resource.resourceName == oxyg.resourceName)
resource.amount = oxyg.amount;
}
}

[KSPEvent(guiActive = true, guiName = "Activate Fuel Cell")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Generator : On", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Deactivate Fuel Cell", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Generator : Off", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}

[KSPAction("Toggle Fuel Cell")]
public void SimpleAction(KSPActionParam param)
{
if (param.type == KSPActionType.Activate)
ActivateEvent();
else if (param.type == KSPActionType.Deactivate)
DeactivateEvent();
}
}
}

So I guess I have to add my custom resources and test them out.

Is there a way to change the color of the gauge of these resources instead of green?

Link to comment
Share on other sites

Added Hydrogen and Oxygen, also tweaked charge distribution a bit so any battery/pod with low chage will get equally charged.


using UnityEngine;
using KSP.IO;
using System.Collections.Generic;

namespace PowerGenerator
{
public class PowerGenerator : PartModule
{
PartResource fuel, oxyg;
public override void OnStart(PartModule.StartState state)
{
foreach (PartResource resource in part.Resources)
{
if (resource.resourceName == "Hydrogen")
fuel = resource;
if (resource.resourceName == "Oxygen")
oxyg = resource;
}
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel && this.part.isPrimary(this.vessel.parts, this.ClassID))
{
if (ActivateGenerator(Events["DeactivateEvent"].active))
{
double parts = CountChargeRequired();

foreach (Part part in this.vessel.parts)
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "ElectricCharge" && (resource.amount < resource.maxAmount))
resource.amount += (0.24 / parts) * Time.deltaTime;
}

UpdateResources();
}
}

private bool ActivateGenerator(bool isActivated)
{
if (isActivated)
{
if (oxyg.amount > 0)
{
oxyg.amount -= 0.02 * Time.deltaTime;
if (fuel.amount > 0)
{
fuel.amount -= 0.01 * Time.deltaTime;
return true;
}
else return false;
}
else return false;
}
return false;
}

private void UpdateResources()
{
foreach(PartResource resource in part.Resources)
{
if (resource.resourceName == fuel.resourceName)
resource.amount = fuel.amount;
if (resource.resourceName == oxyg.resourceName)
resource.amount = oxyg.amount;
}
}

private double CountChargeRequired()
{
double count = 0;
foreach (Part part in this.vessel.parts)
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "ElectricCharge" && (resource.amount < resource.maxAmount))
count++;

return count;
}

[KSPEvent(guiActive = true, guiName = "Activate Fuel Cell")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Generator : On", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Deactivate Fuel Cell", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Generator : Off", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}

[KSPAction("Toggle Fuel Cell")]
public void SimpleAction(KSPActionParam param)
{
if (param.type == KSPActionType.Activate)
ActivateEvent();
else if (param.type == KSPActionType.Deactivate)
DeactivateEvent();
}
}
}

Still wondering if there is other way to manage resources instead of searching through resources with for loops.

Link to comment
Share on other sites

Still wondering if there is other way to manage resources instead of searching through resources with for loops.

You can just search them once and use them later:


// pseudo code

PartResource oxy;
PartResource fuel;

void OnStart()
{
this.oxy = this.part.Resources["Oxidizer"];
this.fuel = this.part.Resources["LiquidFuel"];
}

void Update()
{
this.oxy = // ...
this.fuel = // ...
}

Link to comment
Share on other sites

Thanks to Ippo, new & improved code.


using UnityEngine;
using KSP.IO;
using System.Collections.Generic;

namespace PowerGenerator
{
public class PowerGenerator : PartModule
{
PartResource fuel, oxyg;

public override void OnStart(PartModule.StartState state)
{
this.fuel = this.part.Resources["Hydrogen"];
this.oxyg = this.part.Resources["Oxygen"];
}

public override void OnUpdate()
{
if(this.vessel == FlightGlobals.ActiveVessel && this.part.isPrimary(this.vessel.parts, this.ClassID))
{
if (ActivateGenerator(Events["DeactivateEvent"].active))
{
double parts = CountChargeRequired();

foreach (Part part in this.vessel.parts)
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "ElectricCharge" && (resource.amount < resource.maxAmount))
resource.amount += (0.24 / parts) * Time.deltaTime;
}

//UpdateResources();
}
}

private bool ActivateGenerator(bool isActivated)
{
if (isActivated)
{
if (this.oxyg.amount > 0)
{
this.oxyg.amount -= 0.02 * Time.deltaTime;
if (this.fuel.amount > 0)
{
this.fuel.amount -= 0.01 * Time.deltaTime;
return true;
}
else return false;
}
else return false;
}
return false;
}

private void UpdateResources()
{
foreach(PartResource resource in part.Resources)
{
if (resource.resourceName == this.fuel.resourceName)
resource.amount = this.fuel.amount;
if (resource.resourceName == this.oxyg.resourceName)
resource.amount = this.oxyg.amount;
}
}

private double CountChargeRequired()
{
double count = 0;
foreach (Part part in this.vessel.parts)
foreach (PartResource resource in part.Resources)
if (resource.resourceName == "ElectricCharge" && (resource.amount < resource.maxAmount))
count++;

return count;
}

[KSPEvent(guiActive = true, guiName = "Activate Fuel Cell")]
public void ActivateEvent()
{
ScreenMessages.PostScreenMessage("Generator : On", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = false;
Events["DeactivateEvent"].active = true;
}

[KSPEvent(guiActive = true, guiName = "Deactivate Fuel Cell", active = false)]
public void DeactivateEvent()
{
ScreenMessages.PostScreenMessage("Generator : Off", 5.0f, ScreenMessageStyle.UPPER_CENTER);

Events["ActivateEvent"].active = true;
Events["DeactivateEvent"].active = false;
}

[KSPAction("Toggle Fuel Cell")]
public void SimpleAction(KSPActionParam param)
{
if (param.type == KSPActionType.Activate)
ActivateEvent();
else if (param.type == KSPActionType.Deactivate)
DeactivateEvent();
}
}
}

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