Jump to content

Recommended Posts

I've got serious problem with using a List / Dictionary collection classes where adding data in one event does not

propagate to other event.

Code example:
 

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

namespace TestPartPlugin
{
    public class TestPartPlugin : PartModule
    {
        public struct teststruct
        {
            public string s;
            public int i;
        }
        public class testclass
        {
            public string s;
            public int i;
        }

        // this is shared among events, it will be passed as argument, for purposes of this example its not a problem ?

        public List<teststruct> l = new List<teststruct>();
        public string ss;
        public override void OnLoad(ConfigNode node)
        {
            base.OnLoad(node);
            ss = new string('x', 10); // just allocate in runtime and fill it with dummy data, for reference to the problem at hand
            teststruct t; //now the interesting part
            for (int i = 0; i < 10; i++)
            {
                t = new teststruct(); //also did same with testclass, same problem
                t.s = "a"; //dummy fill
                t.i = i;
                l.Add(t); //add new item. if i looped in collection inside here, it would work
            }
        }

        public override void OnStartFinished(StartState state) // now the troublesome part
        {
            base.OnStartFinished(state);
            Debug.Log("LIST DUMP START");
            foreach (teststruct t in l)
                Debug.Log("string: " + t.s + " int: " + t.i.ToString()); // BANG ! List/struct is empty !
            Debug.Log("LIST DUMP END");
            Debug.Log("simple string test: " + ss); //this worked, meh ...
        }
    }
}

 

I need a mutable collection that will be filled in OnLoad() and then later being used in OnStartFinished() . Right now, when i fill data in OnLoad(), inside OnStartFinished() my collection will be empty, no data is present. What now ? would using "out" keyword in method argument work ? I tried "ref" also with no result.

Edited by fatcargo
Link to post
Share on other sites

Try and put your Debug.Logs in the OnLoad() as well... See what it was then. Lists work just fine across methods, as long as they are commonly defined in the class. Also try and keep track of the size of the list, is that changing between the two methods?

Note: You do not need to keep base.Onload(...) or base.OnStartFinished(...) both are empty placeholders for modding. Second, only need to use OnStartFinished() if you need to change something which is done in the Start() of the PartModule, otherwise OnStart() is just fine.

I do something like this in my mod, and it is fine. MultiMode is a custom class, but I used a struct earlier and it works too. I use mine across all methods in my class basically.

public List<MultiMode> modes { get; protected set; }
MRC = part.FindModulesImplementing<ModuleResourceConverter>();

public void initializeSettings()
{
	modes = new List<MultiMode>(MRC.Count);
	for (int i = 0; i < MRC.Count; i++)
	{
		modes.Add(new MultiMode()
		{
			moduleIndex = i,
			ID = i.ToString(),
			Name = MRC[i].ConverterName
		});
	}
}

https://github.com/WarezCrawler/Guybrush101/blob/master/GTI_MultiModeConverter/GTI_MultiModeConverter.cs#L22-L34

 

Link to post
Share on other sites

Firstly, thanks to all for replies !

Secondly, i forgot to mention that example plugin was tested in SPH editor scene and OnLoad() does get called properly, every time.

What i don't understand, is that my list simply does not "carry over" to OnStartFinished(), as if it was never called. Simply all references inside

List were lost, wiped clean. Any attempt to use complex type (class, struct, list, dictionary) fails to retain reference outside calling method.

Calling GC.KeepAlive() on my list and its newly added item at end of OnLoad() also failed.

I tried searching on net but no such problems were mentioned (i find most solutions over at stackexchange).

The above example source is what i have compiled into DLL, copied into subfolder in GameData and referenced it in part cfg via MODULE{} node.

I did look at plugin sources at github and pretty much everywhere List is normally used from OnLoad(), nothing unusual. I'm starting to believe something is wrong with my VS 2015 CE install.

Edited by fatcargo
Link to post
Share on other sites

What happens if you use your testclass instead of teststruct? The C# docs say, "A struct is a value type, while a class is a reference type," which makes me suspect that this line:

l.Add(t);

... is actually adding repeated references to the same object, and this line clears/resets that one object instead of creating a new one and assigning a reference to it:

t = new teststruct();

What I'm really wondering now is...

Debug.Log("string: " + t.s + " int: " + t.i.ToString()); // BANG ! List/struct is empty !

... does this comment mean the List is empty, or the struct is empty? What's the actual output?

Link to post
Share on other sites

In the meantime i've changed struct to class and same thing happened.

I know c# has garbage collector that frees unused stuff from memory as soon as all references are gone (included leaving method's scope). But keeping a reference inside a List should keep GC from freeing it.

I'm just reusing the same variable to point to newly created item to be added into List, this shouldn't be the problem ?

Edited by fatcargo
Link to post
Share on other sites
15 hours ago, fatcargo said:

Secondly, i forgot to mention that example plugin was tested in SPH editor scene and OnLoad() does get called properly, every time.

Can you clarify how you're testing this? OnLoad will only run in the editor if the parts are being loaded from disk or the editor cache so when you say "every time" I'm suspicious. It certainly won't be running when you pick a part from the parts list and then place it onto the ship, for example

Link to post
Share on other sites

I would add a Debug.Log line to your OnLoad() method so you can tell when it running first.

I've had issues in the past where the order that Start and Load run in does not seem to be set so my guess is that things are working fine, it's just that OnStartFinished() is running before OnLoad() does so at that time the list is in fact empty.

D.

Link to post
Share on other sites
2 hours ago, Diazo said:

I would add a Debug.Log line to your OnLoad() method so you can tell when it running first.

I've had issues in the past where the order that Start and Load run in does not seem to be set so my guess is that things are working fine, it's just that OnStartFinished() is running before OnLoad() does so at that time the list is in fact empty.

D.

I agree with D, that you need to add logs to the onload and follow the execution order. However, I've never encountered that Onload(), OnStart etc. load order have been different. That said, I'm much newer to modding KSP than D is, he is usually right....

(OnAwake) --> Onload --> OnStart --> OnStartFinished

I think OnAwake is not run every time a module is created, so maybe only for static stuff? (I'm not sure with the awake part).

Link to post
Share on other sites

It comes back to not being sure about the order of operations thing.

Way back when (KSP 0.90 days), I ran into this issue myself where the different methods were running out of order, or at least in a different order then I expected.

The conclusion I came to at the time was that in the editor they ran OnStart then OnLoad, while in flight they ran OnLoad then OnStart, so I decoupled my methods so that it doesn't matter which one ran first.

However, that doesn't make any logical sense but as I still decouple my methods to this day I've never actually tested what the order the methods run in on the current version of KSP.

So yes, it is quite easy to get things out of order. Stick Debug.Log lines everywhere so you know exactly what is happening when is the best advice I have for you right now.

D.

Link to post
Share on other sites

@wasml Thanks for the info, will look into it. If i ever intend to continue writing plugins, debugging will be unavoidable.

One other thing : Does this in-game-debug enable me to explore data structures ? Like for example how does API "see" my config nodes in part cfg, when i traverse all ConfigNode items in VS ?

@ALL thanks for the insights, because of your effort i have realized that PartModules are designed to have static data structures, some flexibility is possible in flight scenes.

So, the module that i write is not purely a PartModule, or more accurately, it needs more than PartModule can offer on it's own. So, i further researched the subject and came up with my working solution for loading part config in editor.

My module needs to configure itself from part config in flight and editor scenes.

Below is example code, a promising start.
 

ConfigNode rootNode = ConfigNode.Load(KSPUtil.ApplicationRootPath + "GameData/0000_MyMods/mypart.cfg");

ConfigNode moduleNode = GetNode("PART").GetNodes("MODULE").Where(m => m.name == "YourModuleClassName").Single().GetNodes();

I can put this in OnStart() and have my config available in editor. Drawback is that i don't know how to obtain my module DLL path from part config is was called from and then use that to build a full path. As it is now, path is hard-coded into plugin, if i can just somehow obtain assembly path it could make my plugin more portable...

Edited by fatcargo
Link to post
Share on other sites
8 hours ago, fatcargo said:

Does this in-game-debug enable me to explore data structures ? Like for example how does API "see" my config nodes in part cfg, when i traverse all ConfigNode items in VS ?

The debug allows you to see the variables/constants/etc that you've declared + the public stuff from KSP. If it's not public - not that I know of but I'm fairly new to C#/.net.

Link to post
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...