Jump to content

[Help] NullReference when changing scene


Recommended Posts

I'm just a beginner in the coding but Ikeep getting a NullReference when change from a scene (ex: From Main Menu to Space Center)

This is my code where it throws the error

void Start()
{
foreach (var vessel in FlightGlobals.Vessels)
{
vessel.FindPartModulesImplementing<SkyLabExperiment>().ForEach(part =>
{
part.config = this;
});
}
}

I know that I need to 'destroy' this, but I just don't know how.

You can look into the code on my GitHub repo.

Edited by Olympic1
Link to comment
Share on other sites

Wrap your code in try-catch-blocks to get an idea where the exception comes from.

Or you check each time when you are accessing an object if it's null.

You could also print to the log files what your mod is doing atm. This often gives an idea what went wrong.

Link to comment
Share on other sites

your code asks for FlightGlobals.Vessels, afaik that is not available in Main Menu or at space center..

you should add this

void Start()

{

if (HighLogic.LoadedSceneIsEditor || this.vessel == null)

{

return;

}

foreach (var vessel in FlightGlobals.Vessels)

{

vessel.FindPartModulesImplementing<SkyLabExperiment>().ForEach(part =>

{

part.config = this;

});

}

}

then your code only runs in flight scene..

Link to comment
Share on other sites

your code asks for FlightGlobals.Vessels, afaik that is not available in Main Menu or at space center..

you should add this

then your code only runs in flight scene..

Thx for that, I'll test it

- - - Updated - - -

your code asks for FlightGlobals.Vessels, afaik that is not available in Main Menu or at space center..

you should add this

then your code only runs in flight scene..

Do I then also need to create a " public object vessel { get; set; } "

Because

if (HighLogic.LoadedSceneIsEditor || this.[COLOR="#FF0000"]vessel[/COLOR] == null)

isn't defined nowhere

Link to comment
Share on other sites

It's obviouse you are still too inexperienced in programming. You should try to write some simple programs like tic tac toe or a calculator instead of modding KSP.

The reason is KSP uses some basic and advanced concepts you don't know about. I mean concepts like state machines, object-oriented programming (including inheritance, polymorphism, the difference between instances and classes, etc.), and so on. We can't simply tell how all that works - that could take years!

Link to comment
Share on other sites

It's obviouse you are still too inexperienced in programming. You should try to write some simple programs like tic tac toe or a calculator instead of modding KSP.

The reason is KSP uses some basic and advanced concepts you don't know about. I mean concepts like state machines, object-oriented programming (including inheritance, polymorphism, the difference between instances and classes, etc.), and so on. We can't simply tell how all that works - that could take years!

I know that's why I said in the beginning that I'm just a beginner in coding.

Link to comment
Share on other sites

That's why I suggested that you should to try some more simple programs instead of a KSP mod. It'll help you to learn all the basic concepts.

I taught myself programming 16 years ago. I studied applied computer science and even I sometimes have problems figuring out what the game does. The lack of documentation doesn't make it easier. A beginner like you will have a lot more problems.

Link to comment
Share on other sites

AS a beginner, I'd suggest you run through a bunch of Unity scripting tutorials videos, they're really good. Unity is free to download, so you can follow and play around far more easily than you can in KSP. I started from cold in June, it's HARD. KSP makes things seriously frustrating because you have to restart it every time you change your code to get it to reload the plugin. It makes everything take 20x longer than it should while learning and you're making lots of mistakes, as I'm sure you've found. Playing in Unity, you'll quickly get a handle on how the language works, plus a good grounding in the Unity specific stuff (Classes, Types, etc.). From there, diving into the semi-documented KSP API won't seem quite so hard. Unity forums are an excellent source of information, and once you've got a grasp on the basics, there are some incredibly helpful people round here for those niggly API bits. Don't forget to read source from other mods, it will teach you loads.

Don't be disheartened, just take a step back and make life easy for yourself :)

Link to comment
Share on other sites

Let's have a crash course (it's what kerbals do) in inheritance and then a crash course into your "crash"... heh. (i think i'll mod ksp tonight anyway:) I've been sitting on new torus model for 3 months)

All Classes in c# are objects. This is the core of objected oriented programming. Objects are Referenced with pointers. Every variable in c# is also treated as a pointer. There are some crazy things you can do with this knowledge but for now we'll keep to the object definition. Think of your class as a physical object like a flashlight. It has variables (the state of the light, the battery power ,etc) and it has methods (turn on the light, turn off the light, open the battery compartment, etc). When you have a manufactured copy of that flashlight you can point to it with your finger. That flashlight's object is referenced with a pointer. It is one instance of the designed object.

Your mod class uses a base object, defined like so

class MyShipModule: Module ...

That little colon is telling the compiler that your class extends or inherits the methods and variables from the base class. In this case the module you inherited has a variable called "vessel" which is an object of type Vessel. That's what the "this.Vessel" is. this is a "pointer" that points to your class's object. Basically you took someone else's flashlight and added features to it, like a laser pointer. You can add methods to the new class (turn on the laser, turn off the laser) but you can also still reference the original class's variables (battery power, state of the light, etc). You can access them through use of the "this" pointer, which refers to the object that the method is being run on. The this pointer is not actually necessary. just saying Vessel in that if statement is the same.

Now for the Null Reference Exception.

It is possible to have a pointer that does not actually have an object on the other end of it. You're potentially referencing a new flashlight but it hasn't arrived yet. This pointer carries a special value of "null", meaning there is nothing at the other end of it. Your code is trying to use a feature on the flashlight that doesn't exist (turning on the flashlight). When this happens the computer "throws an exception". This is the computer saying "hey there is no object on the other end of this pointer, what should I do?". The exception mechanism allows you to then "catch" an exception and tell the computer what to do when that happens. Your code is in error because you didn't tell the computer what to do when the object pointed to doesn't exist.

In this case you're trying to reference the container Vessels out of FlightGlobals, which is a null pointer. The computer can't find the object on the other end and throws an exception. There are several ways you can solve this problem.

1. Prevent it. If you know that there is nothing on the other end of the variable (the game state is the main menu) and the code you're running won't apply in the current situation you can check for that and exit your code as there is nothing to do.

2. Check for the null. You check for Null before you access the variable. If you use the variable a lot this can get tedious. You also have to figure out what to do when the variable is null.

3. Catch the exception. Wrap it all in a try...catch block. The try block says that there might be an exception occurring in the second of code inside. If one occurs then you'll catch it with the catch block.

try and catch lets you catch any exception, even ones you didn't think about. What if you go out of bounds on the flight globals vessel list? What if you try to reference something that's supposed to be there on a vessel?

When choosing how to handle when the variable is null there are slight performance issues to keep in mind.

If you chose the prevent it route then you'll only check the single state (main menu) and you'll exit out of your code. Any time you don't execute part of a code you'll gain some performance. In games this performance means higher framerates. If you do the check for null route then you'll have a higher performance cost but not too great. This is for if you want to execute your code still but want to handle missing objects on a case-by-case situation. The exception catching path is the slowest as there is "overhead" in throwing and catching an exception. Exception catching should only be used when the objects you're using communicate with exceptions. Most of .NET functions are notorious for this. Chances are the code you write for a KSP mod won't be too complex so simply checking for null before you use an object is the best route.

That's our kerbal crashing course in c#.

Link to comment
Share on other sites

I know that's why I said in the beginning that I'm just a beginner in coding.

Bull ...., I started with c# in KSP last april..

Aqua might be right - but this is no answer for your question..

No, you don't need to define the vessel in this case..

you are working on a "PartModule" - they all come with some vars to work with.

(inheritance)

One is the vessel this script runs on => this.vessel

While you controll this vessel, it's the same as "FlightGlobals.ActiveVessel"

While you controll an other vessel, this.vessel still contains the same vessel reference - the one with the part module..

It's used for things like making sure your script only runs when you ARE controlling this vessel - example:

if(this.vessel == FlightGlobals.ActiveVessel)

{

//The vessel with this script is the active vessel

}

That is why it's there - so you can figure out what's going on at runtime.

Ok - it's not there only for that, but that is how you use it mostly..

The second one is

this.part

works the same but references the part the module is running on..

With those two infos, you have alleady passed the tick tack toe state in my opinion...

The other terms Aqua mentined are usefull to know but not relelvant for your task here..

btw - I also am a coder since decades - but c# and Unity and KSP is new to me

PS: may beMichael explained all that allready - tl/dr before breakfast - if so, I appologize..

ok - time for breakfast.. :-)

En scheene liebi lüüt...

that's swiss german for: you all have a nice day pals..

Link to comment
Share on other sites

Something sounded strange about this, so I went and had a look at the source.

tl;dr: It's not a partmodule and things here are heading way off course

I am wondering why that section is split off from the part module, and why KSPAddon is used to initialise it rather than a constructor which looks to be more appropriate from my quick look.

ie.


// in the partmodule OnStart()
thisClass test = new thisClass(/* initialisation parameters */)

Add a constructor to the class that you are currently starting with KSPAddon and drop KSPAddon. The effect should be the same, but you get the code as part of the partmodule. If you want to enforce that only a single instance is running concurrently (may or may not be neccesary) then you can do things like use a Singleton variable instead of the constructor directly.

Edited by Crzyrndm
Link to comment
Share on other sites

I'm sorry if I you think I'm a dog in a manger. That wasn't my intension. I just wanted to point Olympic1 to some stuff in which he'll have quick success. Especially beginners need them as they can quickly get frustrated. They usually don't have that thick skin yet you sometimes need when programming complex stuff.

Back to topic:

I wrote about some common practices to debug a code:

Wrap your code in try-catch-blocks to get an idea where the exception comes from.

Or you check each time when you are accessing an object if it's null.

You could also print to the log files what your mod is doing atm. This often gives an idea what went wrong.

1) Try-catch-blocks lets you catch an exception which can occure in the try-block and lets you react on it in the catch-block. An exception itself is a state of a program where it can't continue without crashing because it tries something impossible. Exceptions usually occur when the programmer didn't make sure that his code only runs with the data it can process.

The two most common exceptions which you can accidently trigger when developing code are:

NullPointerException - happens when you're trying to access an object that doesn't exist

ArgumentOutOfBoundsException - happens when you're trying to access data past the bounds of an array

There are a number of ways how to apply a try-catch-block to your code:

void Start()
{
try
{
// If an exception occures inside this block the execution will be aborted immediatly and the catch-block will be executed.
// Note: This makes a program run a bit slower because it adds some checks to the enclosed code (invisible to you). So use it sparsely.

foreach (var vessel in FlightGlobals.Vessels)
{
vessel.FindPartModulesImplementing<SkyLabExperiment>().ForEach(part =>
{
part.config = this;
});
}
}
catch (Exception e)
{
// This only gets executed if an exception occured somewhere in the try-block above.
Debug.LogError("An exception occured. Details:\n" + e.ToString());

// Normal code execution resumes after the following bracket like nothing happened.
}

// Be aware that you can't assume at this point in the code that the try-block executed without errors!

// ... do some other stuff...
}

void Start()
{
foreach (var vessel in FlightGlobals.Vessels)
{
try
{
// This time the try-catch-block is inside the foreach-loop.
// You can do that if you know that the loop itself doesn't trigger the exception.

vessel.FindPartModulesImplementing<SkyLabExperiment>().ForEach(part =>
{
part.config = this;
});
}
catch (Exception e)
{
Debug.LogError("An exception occured. Probably the vessel reference isn't set. Details:\n" + e.ToString());
}
}
}

To be able to use exceptions you'll have to add the assembly which contains them. That is System.Exception. Add using System.Exception; to the start of your code or use System.Exception e in the catch-block so the program knows where it can find it.

2. If you know that a NullPointerException is the reason why your code fails you can do an explicit check for that instead of using a try-catch-block. The execution is a lot faster and you can usually pinpoint the code line where the error happens. Be aware that null is a special kind of literal which is usually only used to check for non-existing references, to initialize an reference* and to "delete" an object (but that's a more complicated topic so I leave it out).

void Start()
{
if (FlightGlobals.Vessels != null) // Check if the content of the Vessels property exists (= has a reference set)
{
foreach (var vessel in FlightGlobals.Vessels)
{
if (vessel != null) // Check if vessel exists. If it doesn't, it'll trigger the else-block.
{
vessel.FindPartModulesImplementing<SkyLabExperiment>().ForEach(part =>
{
if (part.config != null)
{
part.config = this;
}
else
{
Debug.LogError("Error: part.config doesn't exist!");
}
});
}
else
{
Debug.LogError("Error: vessel doesn't exist!");
}
// After the if- or else-block execution will continue at this point.
}
}
else
{
Debug.LogError("Error: FlightGlobals.Vessels doesn't exist!");
}
}

* null can be used to initialize a reference:

Vessel myVessel; // declaration of the myVessel object of the type Vessel
// Note that myVessel does not have a value yet! There is no content so you can't even check for null.
myVessel = null; // initialize with null
// Now myVessel contains something you can check for.

3. The Unity engine provides a simple way to add your own messages to a log. KSP will use this log to create the <KSPdir>\KSP.log (less detailed, easy to read) and <KSPdir>\KSP_Data\output_log.txt (more detailed but a bit more difficult to read) files and shows all the messages in the Alt+F12 debug tool in the game at runtime.

You can use that to check what your code does.

// KSP.log: [LOG 01:23:45.678] A simple message in the log
// output_log.txt: (Filename: C:/BuildAgent/work/d63dfc6385190b60/artifacts/StandalonePlayerGenerated/UnityEngineDebug.cpp Line: 49)
// A simple message in the log
Debug.Log("A simple message in the log");

// KSP.log: [WRN 01:23:45.678] A warning message in the log
// output_log.txt: (Filename: C:/BuildAgent/work/d63dfc6385190b60/artifacts/StandalonePlayerGenerated/UnityEngineDebug.cpp Line: 49)
// A warning message in the log
Debug.LogWarning("A warning message in the log");

// KSP.log: [ERR 01:23:45.678] An error message in the log
// output_log.txt: (Filename: C:/BuildAgent/work/d63dfc6385190b60/artifacts/StandalonePlayerGenerated/UnityEngineDebug.cpp Line: 49)
// An error message in the log
Debug.LogError("An error message in the log");

// There's also LogException but I never saw anyone using it.

Link to comment
Share on other sites

1) Try-catch-blocks lets you catch an exception [...]


catch (Exception e)

While a catch all can have some use I would recommend to stay away from it as much as you can. It leads to some really bad coding habit where you just hide the exception and never resolve the real problem. (My code is not immune from that bad habit...)

Catch specific exception ( DivideByZeroException, FileNotFoundException, ...) and make sure the catch is not commonly called in normal use because it's S L O W.

* null can be used to initialize a reference:

Vessel myVessel; // declaration of the myVessel object of the type Vessel
// Note that myVessel does not have a value yet! There is no content so you can't even check for null.
myVessel = null; // initialize with null
// Now myVessel contains something you can check for.

Wut ?!?

Vessel myVessel;

Is exactly the the same as

Vessel myVessel = null;

for a class or a reference.

Or I just moved into some strange parallel universe.

(Just don't be pedantic and talk about the Unity null check please)

Edited by sarbian
Link to comment
Share on other sites

You found an error in a C# book I read! It explicitly says that a variable which is declared inside a method does not count as initialized and therefore has no default value (false, 0 or null). I don't link that book because it's in German. But what I can link to you is this:

A variable must have a value assigned to it before that value can be obtained. A variable that is assigned initially at declaration has a well-defined initial value and is always considered definitely assigned. An initially unassigned variable has no initial value. For an initially unassigned variable to be considered definitely assigned at a certain location, an assignment to the variable must occur in every possible execution path leading to that location.
(Underscore by me)

Later it says all variables have a default value. It contradicts itself. :rolleyes:

On the contrary the MSDN, a wiki book and the ECMA norm says that in C# variables are always initialized on declaration.

There are more people who get that wrong. It must be because of Java (instance variables have default values, local variables don't) and C++ (reference types don't have a default value, some other types get a value but it's a random one and the rest gets a 0 converted to that type) which behave differently.

If in question I would stick to what Microsoft says. And initialize variables always on declaration, just to be sure. It's also considered as good style.

Edited by *Aqua*
Link to comment
Share on other sites

The articles you linked talk about Value, major V, like enum, float, int, ...

Vessel is a Class, so myVessel would be a reference and would have a default value, minor v, of null.

It is the same in Java.

Link to comment
Share on other sites

In Java you have primitive types like int, float, etc. There are circumstances in which they don't get a default value assigned.

C# doesn't have primitive types, everything is an object.

That's seems to be one reason why people (like me) mix that up. Because of other programming languages I use, I'm so used to the fact there isn't always a default value that I assumed it's the same in C#.

Link to comment
Share on other sites

While a catch all can have some use I would recommend to stay away from it as much as you can. It leads to some really bad coding habit where you just hide the exception and never resolve the real problem. (My code is not immune from that bad habit...)

Catch specific exception ( DivideByZeroException, FileNotFoundException, ...) and make sure the catch is not commonly called in normal use because it's S L O W.

Wut ?!?

Is exactly the the same as

for a class or a reference.

Or I just moved into some strange parallel universe.

(Just don't be pedantic and talk about the Unity null check please)

A note about this:

Vessel myVessel;

vs

Vessel myVessel=null;

If you're compiling this in visual studio it will give you an error when you use variable from the first version and never assigned it. The first version is a declared but uninitialized variable. Used to be that compilers allowed this (c and c++ did) but that's a HORRRRRRIBLE practice because the variable would pickup whatever was in the memory space that the computer gave it when you ran the program. If you declared

int myVariable;

there's no telling what was in the memory that the computer assigns for that variable and that could lead to unpredictable behavior out of your program. This especially goes for if that variable is supposed to be a pointer.

C# the compiler correctly identifies this as an error if you try to use the uninitialized variable. Even to test if it's null.

If you create the variable and then assign a new object to it

Vessel myvessel = new Vessel() then you don't have to initialize. Otherwise you should initialize the variable when you create it.

Edit: a PS or slashie if you will

/Uninitialized variables are the cause of probably i'd say 50% of crashes in computer programs (I don't know the exact percent but it's up there). The other half is caused by improperly handled multi-threading... something you hopefully don't have to handle while modding KSP.

Edited by michaelhester07
Link to comment
Share on other sites

Edit: a PS or slashie if you will

/Uninitialized variables are the cause of probably i'd say 50% of crashes in computer programs (I don't know the exact percent but it's up there). The other half is caused by improperly handled multi-threading... something you hopefully don't have to handle while modding KSP.

The other 50% comes from users. But don't tell them that.

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