Not signed in (Sign In)

Discussion Tag Cloud

Categories

Vanilla 1.1.9 is a product of Lussumo. More Information: Documentation, Community Support.

  1.  
    I am currently working learning the ropes in nl2 scripting and I have hit a snag, I am trying to create objects ex. Station, Brakes, in order to create a more dynamic, reusable code. I made a constructor to transfer a block object but I'm having no luck successfully transferring the object to the new class variable. The class is loading fine and displaying text but I keep getting no value for the Block inputs.

    import com.nolimitscoaster.*;

    /**
    * Script to handle a generic station
    */
    public class Station implements BlockSection {

    private Block block;
    private Block nextBlock;

    public Station(Block block1, Block block2) {

    block = block1;
    nextBlock = block2;
    }

    public static void process(Block currentBlock, Block nextBlock) {
    }

    public Block getBlock() {
    return block;
    }

    public void setBlock(Block block1) {
    block = block1;
    System.out.println("Station initialized: " + block1);
    }


    I'm having no luck figuring out how to send a Block from one class to another, I keep getting a null pointer exception...


    // Block Sections and Switches
    private Coaster coaster;
    private Block unload2Block;
    private Block unload1Block;
    private Block load2Block;
    private Block load1Block;
    private Block preLaunchWaitBlock;
    private Block preLaunchBlock;
    private Block preStopBlock;
    private Block finalStopBlock;
    private Block transferTrackBlock;
    private SpecialTrack transferSwitch;
    private int mode;

    // Local class Objects
    private Station unload2;
    private Station unload1;
    private Station load2;
    private Station load1;
    private Brake preLaunchWait;
    private Brake preLaunch;
    private Brake preStop;
    private Brake finalStop;
    private Brake transferTrack;

    public bool onInit() {

    // array of blocks and names in track order
    Block[] coasterBlocks = {
    preLaunchWaitBlock, preLaunchBlock, preStopBlock, finalStopBlock,
    transferTrackBlock, unload2Block, unload1Block, load2Block, load1Block};
    String[] names = {
    "Pre Launch Wait", "Pre Launch", "Pre Stop", "Final Stop",
    "Transfer Table", "Unload 2", "Unload 1", "Load 2", "Load 1"};

    // Detect the coaster this script belongs to...
    coaster = sim.getCoasterForEntityId(getParentEntityId());

    if (coaster == null) {
    System.err.println(scriptName + ": Not attatched to the coaster");
    return false;
    }

    // assign the block system controller to the coaster
    coaster.setBlockSystemController(this);

    // initialize all Block Sections in a loop
    for (int i = coasterBlocks.length - 1; i >= 0; i--) {

    coasterBlocks[i] = coaster.getBlock(names[i]);

    if (!checkAndSetInitialBlockState(coasterBlocks[i], names[i])) {
    return false;
    }

    coasterBlocks[i].setAdvanceFwdVisible(true);
    }

    unload2 = new Station(unload2Block, unload1Block);
    unload1 = new Station(unload1Block, load2Block);
    load2 = new Station(load2Block, load1Block);
    load1 = new Station(load1Block, preLaunchWaitBlock);
    preLaunchWait = new Brake(preLaunchWaitBlock, preLaunchBlock);
    preLaunch = new Brake(preLaunchBlock, preStopBlock);
    preStop = new Brake(preStopBlock, finalStopBlock);
    finalStop = new Brake(finalStopBlock, transferTrackBlock);
    transferTrack = new Brake(transferTrackBlock, unload2Block);


    here is the reference code that keeps giving me the null pointer exception.


    preLaunchWait.getBlock().setAdvanceFwdEnabled(preLaunchWait.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    preLaunch.getBlock().setAdvanceFwdEnabled(preLaunch.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    preStop.getBlock().setAdvanceFwdEnabled(preStop.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    finalStop.getBlock().setAdvanceFwdEnabled(finalStop.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    transferTrack.getBlock().setAdvanceFwdEnabled(transferTrack.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    unload2.getBlock().setAdvanceFwdEnabled(unload2.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    unload1.getBlock().setAdvanceFwdEnabled(unload1.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    load2.getBlock().setAdvanceFwdEnabled(load2.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);
    load1.getBlock().setAdvanceFwdEnabled(load1.getBlock().getState() == STATE_BLOCK_WAIT_FOR_ADVANCE);


    Any help at all would be greatly appreciated, it hard to find info on this topic anywhere. Even in the game help documentation, I cant find any good examples.
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 14th 2016 edited
     
    not sure, if this is the solution, but...


    here is a very basic class, that i use to check, if the imports are correct.

    package System.Environment.classes;


    import com.nolimitscoaster.*;
    //import nlvm.math3d.*;
    import nlvm.lang.*;


    public class store_activeErv extends Script{

    public bool ExternalRun = false;
    public bool InternalRun = true;

    public static void storeErv(){

    System.out.println("storeErv");
    }


    }


    You see? its set to "public".
    You can only send values of "public" vars to other classes.

    And this is how i access these values:


    //import nlvm.math3d.*;
    import nlvm.lang.*;

    //import Makro Classes

    import System.Environment.classes.*;
    import System.Debug.*;

    public class debug_ENV extends Script{
    store_activeErv activeErv = new store_activeErv(); //assign class to variable

    public bool onInit(){

    activeErv.storeErv(); //call external function/method
    System.out.println(activeErv().ExternalRun); //call external variable (boolean value)
    }


    Maybe there are some syntax errors in it, because i havn't tested it.
    But im 70% sure, its because your variables arn't public.

    greetings, foxy.
    •  
      CommentAuthorbestdani
    • CommentTimeDec 14th 2016 edited
     
    @Füchschen: He calls a public method that returns a private member which should be fine and is very often even considered as a good programming style (example why at the end of my post). Trying to access a private member should cause a "compile" time error and not a null pointe exception at runtime.


    The class looks fine at the first glance, but this construct seems to cause the problem:
    Block[] coasterBlocks = {
    preLaunchWaitBlock, preLaunchBlock, preStopBlock, finalStopBlock,
    transferTrackBlock, unload2Block, unload1Block, load2Block, load1Block};

    since
    coasterBlocks[i] = coaster.getBlock(names[i]); will not set any of the private Block members that are used later and they will remain null.

    Compare with this:

    public class NullTest{
    private static Integer i1, i2, i3;

    private static void fail(){
    Integer[] ii = {i1, i2, i3};
    ii[0] = new Integer(1);
    ii[1] = new Integer(2);
    ii[2] = new Integer(3);

    System.out.println("\nfail:");
    System.out.println(ii[0]);
    System.out.println(ii[1]);
    System.out.println(ii[2]);
    System.out.println(i1);
    System.out.println(i2);
    System.out.println(i3);
    System.out.println(ii[0] == i1);
    System.out.println(ii[1] == i2);
    System.out.println(ii[2] == i3);
    }

    private static void success(){
    i1 = new Integer(3);
    i2 = new Integer(4);
    i3 = new Integer(5);
    Integer[] ii = {i1, i2, i3};

    System.out.println("\nsuccess:");
    System.out.println(ii[0]);
    System.out.println(ii[1]);
    System.out.println(ii[2]);
    System.out.println(i1);
    System.out.println(i2);
    System.out.println(i3);
    System.out.println(ii[0] == i1);
    System.out.println(ii[1] == i2);
    System.out.println(ii[2] == i3);
    }

    public static void main(){
    fail();
    success();
    }
    }
    /* output:
    fail:
    1
    2
    3
    null
    null
    null
    false
    false
    false

    success:
    3
    4
    5
    3
    4
    5
    true
    true
    true
    /*
    (I don't know if this behaviour differs from Java but I guess not)

    While I understand your intention and you could probably enforce this by using some wrappers around your Block variables I would suggest to get rid of that names and Block array and instead to use just a method like:

    private Block setupNewBlock(String name) {
    Block block = coaster.getBlock(name);
    if (checkAndSetInitialBlockState(block, name)) {
    block.setAdvanceFwdVisible(true);
    return block;
    } else {
    //maybe add some error message here and even stop the script at this point
    return null;
    }
    }

    and then just replace that for loop construct with:

    preLaunchWaitBlock = setupNewBlock("Pre Launch Wait");
    preLaunchBlock = setupNewBlock("Pre Launch");
    //and so on


    And because this is a good example to demonstrate why it's often preferable to use private members and public access methods, you could even add this to your constructor which automatically checks if still a "null" pointer is assigned:

    public Station(Block block1, Block block2) {
    setBlock(block1);
    //actually you could also do that for block2
    nextBlock = block2;
    }

    public void setBlock(Block block1) {
    if (block1 == null){
    //another error msg and maybe script stop point, or make this method return a boolean
    } else {
    System.out.println("Station initialized: " + block1);
    }
    }
    •  
      CommentAuthorFüchschen
    • CommentTimeDec 14th 2016 edited
     
    ^
    I have just tested the construct and it worked for me just fine.
    But i used simple string vars instead of blocks. (because: eclipse...)

    ... i'll try it later in NL2 again.

    and BTW:
    first make the code work
    and THEN make it pretty (good programming style)