Jump to content

partmodule and mono problems.


Recommended Posts

Decided to add a part to the plugin I been working on. The problem seems to be that for some reason the new partmodule part of the code is not communicating with the old code that never had a part.

This is how it should work...

1. New PartMudule part of code with context menu.. Player selects and the mission goal is complete (The Actual Mission Goal Is To EVA and Click Part to Repair it)

a. This part works.. The context menu works in game and the code is executed.

2. What its actaully doing. The context menu is pressed.. It executes the code.. The code seems to go to the next part but it stops?

3. I set up a button in the Original part of the code that basically does what I want the context menu to do.. When I push this button in game it works.. And mission Goal Is complete!!

4. The original Code is setup without a part and most of the parts of the .class files im editing are partials of MissionController.. So they all work together without any initializations. Mission Controller is the MainSpace Of plugin. and is

"public partial class MissionController : MonoBehaviour"

5. The new part of the code.. that is another seperate .class file is

"public class repairStation : PartModule"

is there some sort of permissions im missing or not understanding? If I have a bool set up in the Partmodule.. If I set up an IF statment in MissionController it does not seem to be able to read the new value in Partmodule. In fact it seems that anyting excuted within PartModule can only be read inside partmodule. It aslo seems that anything that is done inside the original MissionController Code can't be read by Partmodule. This is confusing me to no end. Any idea on how to get this to work?

This is the Github of the project.

https://github.com/malkuth1974/KSPMissionController

PS did they change the forums? LOL.. Sucks to write anything without the advanced options.

Edited by malkuth
Link to comment
Share on other sites

Please think about what exactly your code is doing. For example in repairStation.OnUpdate(), that are pretty much your instructions:


Enable or disable some event
Enable or disable another event
if( whatever ){
Create a new MissionController and save it in a local variable
Call some func on the newly created object
// You don't explicitly do sth, but in fact drop the last reference to the newly created object so it isn't used anymore and can be destroyed internally
}

Same in MissionController.drawMainWindow(). You create a new object of type repairStation. Of it will always be in the same state of an newly initiated repairStation, so an

if( repStation.repair )

just below does not make any sense at all. Anyway, lets make it short. You need a reference to the actual object your want to interact with. Creating a new object is almost never a solution for "i don't have a reference"... just like repairing you own chair is not the same as repairing any just newly created chair. I could give you the exact lines you need, but a little bit of research will help you to understand how you can adds behaviors (PartModules are nothing else) to an unity game objects & how they handle it internally. Once you know how you, you will no doubt be able to fix your issue. All necessary info should either be here on the KSP forum & mod source codes or directly in unitys ScriptReference docs / via Google... if you need any, at all. Hope that helps you to get on the right track.

Link to comment
Share on other sites

thanks for the info. I knew the if statment wasn't working.. But I have been trying to figure this out for 2 days. LOL. Still totally new to C# so its been a long learning curve. :) I will figure it out. So I take it your saying that creating a new instance of something is not the answer?

Seems to me that if you have a simple bool.. false. And you use the Part context to change it to true..

If from another class if you initiate that bool to be read by the other class it should work.. But it does not. I guess I will have to keep researching.

If I should start using Ref to keep the original bool and be able to change it.. Then since the objects I need to edit are in different classes.. I would still have to create a new in at least one of them correct? Since having a ref in one class is fine.. But in another class I will still have to initiate the ref to call it..

Edited by malkuth
Link to comment
Share on other sites

You only have/should create a new one if there isn't one already. Didn't you mention that both modules work fine on their own? They could not, if they wouldn't already exist... so they most likely were already created from other parts of the game/mod, e.G. by loading the part & part module or however MissionController does it. If they exist, you have to get a ref without creating another copy. And we are back on how to do this / how unity manages its MonoBehaviors... *referring to their docs & google*

Link to comment
Share on other sites

hmmm maybe im not being clear.. As I'm new to C# and still learning as I go, what Im trying to say so I might not have all the correct terms down.

But the original MissionController never had a part. And it used this bit of code to simulate the adding a part. (for windows and stuff could show up without adding a part)

 public class MissionControllerTest : KSP.Testing.UnitTest
{
public MissionControllerTest () : base()
{
I.AddI<MissionController> ("MISSION_CONTROLLER");
}
}

static class I
{
private static GameObject _gameObject;

public static T AddI<T> (string name) where T : Component
{
if (_gameObject == null) {
_gameObject = new GameObject (name, typeof(T));
GameObject.DontDestroyOnLoad (_gameObject);

return _gameObject.GetComponent<T> ();
} else {
if (_gameObject.GetComponent<T> () != null)
return _gameObject.GetComponent<T> ();
else
return _gameObject.AddComponent<T> ();
}
}
}

So it never used the PartModule Inheritance..

When I added a part to Mission Controller I used the PartModule Inheritance for the first time in its own Class file. So

public class repairStation : PartModule

Now MissionController is set like this

public partial class MissionController : MonoBehaviour

all the classes that Have all The MissionGoals Info in them are seperate classes too and also are set as

 public partial class MissionController

Now I know I had confusing things set in the code.. But it was 2 days of trying so many different ideas that I didn't clean it all up. I have since combined repairStation Class into RepairGoal to make it easier to code. But they are still seperate classes. Just in same file.

So now that Seems clear enough.

Every Thing in the code works.... But what I want to do is in repairStation class I originally had it set up for when you right click on the part a context menu appears.. You select it and it changes a BoolValue to True...

Now In the code for RepairGoal there is a check to see when The Bool from repairStation is set to True.. When that happens the MissionGoal Is complete. The problem has been all this time that nothing outside of repairStation seems to be seeing the bool being changed to True.. So its not working.

Also To check to see if how I wrote RepairGoal correct and it Actually works, I set up a Button Inside of MissionController : MonoBehavior to simulate the same thing that repairStation code is suppose to do.. That actually works.. And if you push that ingame the mission will be complete. This part of the code is not going to stay.. I want this to work from repairStation instead. But I used it to just check if MissionGoal Actually works. And it does.

Now I understand what your saying about Referencing somewhat. Since repairStation is a seperate class from Missioncontroller: MonoBehavior and all the other Classes Im working with are Basically inheriting MissionController : MonoBehavior Code.. That is why the Button I made works correct.

But since repairStation only inherits from PartModule and Not MissionController I have to use the New command to initiated stuff.. But now I understand that makes a copy of whatever it is Im calling and doesn't actually change the Reference.. So this is why the code I execute inside of repairStation can't be read by MissionController.

What you see in the code now is what I tried to do to replace the Bool and use a Method Instead like the other MissionGoals Used.. (I copied DockingGoal and CrashGoal) All these Use Flag System.

So what I did was this. Set up some methods instead (that was the part where I made things harder then they needed)

In missioncontroller I copied the DockingGoal to be almost the same as RepairGoal.. It uses a flag system and when the flag is set to REPAIR it will set a bool that is located inside GameEvents to true in this case (isrepaired). Then I set up this little method inside MissionCotrollerEvents (still a partial of MissionController) To set the whole thing in motion.


public void shipRepaired()
{
eventFlags = eventFlags.Add(EventFlags.REPAIR);
print("Event Flag Has Been Set To: " + eventFlags);
}

So far so good.. This method is also what I use in the Button I set Up To TEST If RepairGoal actually works.

Now in repairstation this bit of code is located like this.

[KSPEvent(guiActive = true, guiName = "Start Repair", active = true)] 
public void EnableRepair()
{
repair = true;
MissionController mc = new MissionController();
mc.shipRepaired();
print("repair is = " + repair);

Now in game the context menu works.. You can right click and select Start Repair.. And it even activates the code.. But for some reason it stop at shipRepaired() inside MissionController : Behavior.

I have a print() set up inside the code.. In game it actually gets to the print and prints it out from shipRepaired() Event Flag Has Been Set To: " + eventFlags and even says ingame that eventflags set to REPAIR.. But stops there.. And the other part of code is never executed which sets the bool to true.. That code is like this.

if (eventFlags.Has(EventFlags.REPAIR))
{
print("Event Flag Set: " + eventFlags + " and about to be Removed.");
eventFlags = eventFlags.Remove(EventFlags.REPAIR);
s.events.isrepaired = true;
print("isrepaire is = " + s.events.isrepaired + " current flag is: " + eventFlags);
}

So I take it that Im doing this.

MissionController mc = new MissionController();
mc.shipRepaired();

I'm still only making a copy of the Refrence? But I thought the whole point of a Method was that it can be called from anywhere in the code. :(

Edited by malkuth
Link to comment
Share on other sites

Anyway I think I get it now.. And will try my fixes using a ref. I will report if it works.. Totally forgot that even a method will create 2 copies.. Be back in a little bit.l

EDIT ADDED NEW UPDATE

I feel like such a godarn idiot.. Really using static changes everything.. HOLY FREAKING CRAP... 3 days and all the trouble I was missing one little word in the code..

IT WORKS!!!

Thanks so much Faark for the nudge in the right direction.

Edited by malkuth
Link to comment
Share on other sites

No... thats not really the solution i wanted you to find.^^ Static means that there will alway only be a single "repair" bool slot at all per application. What if someone starts the mission again or loads a save? Sure, you could add a lot of code to handle all those cases and reset your bool. But there really is no reason to make it static. You have a repair you ship goal. Maybe you want to repair 2 different parts, so you create a goal for each of those parts. Anyway, what you should try to do is find the reference to your repairStation PartModule. Its a part module, so its associated with a part... so a way to do it is to loop though all parts of your vessel and check if it has a repairStation, and whether its repair flag is set. You will used GetComponent to do so, btw.

Btw, you shouldn't use KSP.Testing.UnitTest anymore. Afaik its an old way that "abuses" stuff within KSP to load stuff instantly. KSPAddon is the way to go... that way you can even make sure your Addon is loaded only in flight & reloaded when screens changes. Something like that might by nice for you:


[KSPAddon(KSPAddon.Startup.Flight, false)]
public class YourController: MonoBehaviour{
public static YourController CurrentControllerInstance;
public void Start(){
CurrentControllerInstance= this;
}
}

That lets KSP take care of loading your MonoBehavior while you still can access the last created one from anywhere via a static var. Technically you do not need the static var. You could also find the current instance via Unity's API. But in this case the simple version should be enough. Though your mission controller might not like being reload every screen, especially since it look like it would reload lots of resources... so you might just want to skip that for now^^

Btw2: Who has written KSPMissionController.activeVessel? There should not be a try catch, but they should either check FlightGlobals.ready or FlightGlobals.fetch instead.

Link to comment
Share on other sites

No... thats not really the solution i wanted you to find.^^ Static means that there will alway only be a single "repair" bool slot at all per application. What if someone starts the mission again or loads a save? Sure, you could add a lot of code to handle all those cases and reset your bool. But there really is no reason to make it static. You have a repair you ship goal. Maybe you want to repair 2 different parts, so you create a goal for each of those parts. Anyway, what you should try to do is find the reference to your repairStation PartModule. Its a part module, so its associated with a part... so a way to do it is to loop though all parts of your vessel and check if it has a repairStation, and whether its repair flag is set. You will used GetComponent to do so, btw.

Btw, you shouldn't use KSP.Testing.UnitTest anymore. Afaik its an old way that "abuses" stuff within KSP to load stuff instantly. KSPAddon is the way to go... that way you can even make sure your Addon is loaded only in flight & reloaded when screens changes. Something like that might by nice for you:


[KSPAddon(KSPAddon.Startup.Flight, false)]
public class YourController: MonoBehaviour{
public static YourController CurrentControllerInstance;
public void Start(){
CurrentControllerInstance= this;
}
}

That lets KSP take care of loading your MonoBehavior while you still can access the last created one from anywhere via a static var. Technically you do not need the static var. You could also find the current instance via Unity's API. But in this case the simple version should be enough. Though your mission controller might not like being reload every screen, especially since it look like it would reload lots of resources... so you might just want to skip that for now^^

Btw2: Who has written KSPMissionController.activeVessel? There should not be a try catch, but they should either check FlightGlobals.ready or FlightGlobals.fetch instead.

Mission controller was originally written by nobody. i took over the project when .21 came out. Most of the code was not even written by me or the other person working on it Nathan. We just added new things to it. Knew about the new way to add to make KSP plugins run without that old code bit.. But I was a little nervous.. Didn't know what it would break.

I will try the new method way of starting it up and comment out that old way..

seems to work.

We took over MC in an alpha state... And its still an alpha so don't be too hard on it. ;) Code cleanup is coming after I have a few more C# classes under my belt.

The repairGoal wasn't meant to be part of the active vessel.. The plan I have when this is finished is to be able to check (have not figured out how to do this yet) the active vessels in the universe (IE the vessels located in persistent file) and check to see if it has the part I added. If it does the player can select a random mission that will select the Vessel with the part and make it the missionGoal. If there are say 7 satellites that have the part on it.. Then missionController Random Mission will select 1 of the 7 vessels for the MissionGoal. So not only will eventually the MissionGoal of getting out of vessel and right clicking on part have to be met.. But if I can figure it out.. The vessel ID will have to match too.

This part of the code I knew would be the HARD part.. didn't think I would get stuck on the simple part.. Like I did.

Edited by malkuth
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...