[SOLVED] Cannot invoke because "contentMan" is null

I just started JME3 to learn after many many years. And I know only Unity Godot.
I just love Java and JME3. I was running code and stuck in this error. Help and suggest me what to read to improve my JME3 code and skills.

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.Node;
import com.jme3.asset.AssetManager;
import com.jme3.scene.Spatial;
import com.jme3.math.Vector3f;
import com.jme3.light.DirectionalLight;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.AnalogListener;
import com.jme3.input.MouseInput;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;

/**
 * This is the Main Class of your Game. You should only do initialization here.
 * Move your Logic into AppStates or Controls
 * @author normenhansen
 */
public class Main extends SimpleApplication {
    
     Box b=new Box(1,1,1);
        Geometry geom =new Geometry("Box",b);
        
       AssetManager asm=this.getAssetManager(); // Still trying to get rid of null error so, i'm using it as global
      private Material geoMat;
        
         
        
        
        
        
        
    int count;
    

    float value=0.5f;
   private boolean isRunning=true;
    
    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
       count=1011;
        
          
        
        Material mat = new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Red);
        geom.setMaterial(mat);
 
        Box b2=new Box(1,1,1);
        Geometry geom2=new Geometry("Box2", b2);
        Material mat2=new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
        mat2.setColor("Color", ColorRGBA.Green);
        geom2.setMaterial(mat2);
        
       
        
       
        Node n=new Node();
        rootNode.attachChild(n);
         
       
        Spatial terrain=assetManager.loadModel("Scenes/Terrain.j3o");
        
        geom2.setLocalTranslation(new Vector3f(0,-2,0));
       
        n.attachChild(geom);
         DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-0.1f, -0.7f, -1.0f).normalizeLocal());
        n.addLight(sun);
        terrain.setLocalTranslation(new Vector3f(0,-3,0));
        n.attachChild(terrain);
        InitKeys();
    }
public void RotateCube( ){
    
    
        this.geoMat=new Material(assetManager,"Common/MatDefs/Misc/Unshaded.j3md");
    
        this.geoMat.setColor(("Color"), ColorRGBA.Blue);
         geom.setMaterial(this.geoMat);
        
      
        
        Node n2=new Node();
    rootNode.attachChild(n2);
    n2.attachChild(  geom);
 
       geom.setLocalTranslation(3,0,0);
          geom.rotate(.2f, 0, 0);
         value=value+0.5f;
       
       
        System.out.println("This is working roate X Val: "+    geom.getLocalTranslation().x);
    }
    @Override
    public void simpleUpdate(float tpf) {
        //TODO: add update code
        
         
    }

    @Override
    public void simpleRender(RenderManager rm) {
        //TODO: add render code
    }
    
    
    void InitKeys(){
    
        inputManager.addMapping("Pause",  new KeyTrigger(KeyInput.KEY_P));
        inputManager.addMapping("Left",   new KeyTrigger(KeyInput.KEY_J));
        inputManager.addMapping("Right",  new KeyTrigger(KeyInput.KEY_K));
        inputManager.addMapping("Rotate", new KeyTrigger(KeyInput.KEY_SPACE),
                                          new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        
     MyCombinedListener mc=new MyCombinedListener();
  // inputManager.addListener(mc,   "Pause", "Left", "Right", "Rotate" );
 inputManager.addListener(actionListener, "Pause");
        inputManager.addListener(analogListener, "Left", "Right", "Rotate");
    
    }
    
    final private ActionListener actionListener = new ActionListener() {
        @Override
        public void onAction(String name, boolean keyPressed, float tpf) {
            if (name.equals("Pause") && !keyPressed) {
                isRunning = !isRunning;
            }
        }
    };
  
        
    
    
    final private AnalogListener analogListener = new AnalogListener() {
        @Override
        public void onAnalog(String name, float value, float tpf) {
             
            if (isRunning) {
                Main m=new Main();
                if (name.equals("Rotate")) {
                     m. RotateCube();
                      System.out.println("Counter is: "+m.count);
                }
                if (name.equals("Right")) {
                    geom.move((new Vector3f(value, 0,0)) );
                }
                if (name.equals("Left")) {
                    geom.move(new Vector3f(-value, 0,0));
                }
            } else {
                System.out.println("Press P to unpause.");
            }
        }
    };
    
}





Uncaught exception thrown in Thread[jME3 Main,5,main]
NullPointerException: Cannot invoke “com.jme3.asset.AssetManager.loadAsset(com.jme3.asset.AssetKey)” because “contentMan” is null

Help me learn how to use AssetManager outside simpleInitApp(), When I create material in other functions. it says “contentMan” is null

Hi! Glad you love Java and JME3! Me too

Would you be able to edit your question and put your code within a code block. It is quite hard to read currently; each indented section is being interpreted as a separate code block

1 Like

OK. I am working

I don’t think you’ve included enough code. The exception is referring to something not even in the code block we see.

When the main class in your application extends SimpleApplication, it gets a bunch of “magic” fields by default. (Fields from the superclass.) This is super confusing for new users but unfortunately is something we live with for “backwards compatibility” reasons.

This gives some new developers the impression that “assetManager” is some magic global thing… but it’s just another class field like any other.

If you want some other class to have access to the assetManager then you must pass it to that class like any other parameter… either on its constructor or some other method.

Edit: also because this comes up all the time… only one class in your application should extend SimpleApplication. You only want one application in your application.

2 Likes

Looks like you’ve deleted a lot of the code. We do want the whole thing. Just nicely formatted. And the whole exception (the whole stack trace; not just the message)

That said I do think pspeed is right. You’re not passing AssetManager to whereever it is you want to use it. That isn’t JME specific, just normal java stuff.

p.s. on a formatting point. RotateCube is a method so should be lower camel case rotateCube. To an extent in your own projects you can follow whatever standards you like but people reading your code will mistakenly think RotateCube is a class if it is in upper camel case like this

1 Like

Pastin whole code

I have pasted whole code.

this is the error.

SEVERE: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.NullPointerException: Cannot invoke "com.jme3.asset.AssetManager.loadAsset(com.jme3.asset.AssetKey)" because "contentMan" is null
	at com.jme3.material.Material.<init>(Material.java:105)
	at mygame.Main.RotateCube(Main.java:89)
	at mygame.Main$2.onAnalog(Main.java:154)
	at com.jme3.input.InputManager.invokeAnalogs(InputManager.java:250)
	at com.jme3.input.InputManager.invokeUpdateActions(InputManager.java:220)
	at com.jme3.input.InputManager.update(InputManager.java:924)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:785)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:248)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:160)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:224)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:242)
	at java.base/java.lang.Thread.run(Thread.java:833)

Jun 06, 2024 8:03:20 PM com.jme3.system.JmeSystemDelegate lambda$new$0
WARNING: JmeDialogsFactory implementation not found.
Uncaught exception thrown in Thread[jME3 Main,5,main]
NullPointerException: Cannot invoke "com.jme3.asset.AssetManager.loadAsset(com.jme3.asset.AssetKey)" because "contentMan" is null
BUILD SUCCESSFUL (total time: 2 seconds)

Your problem is here

final private AnalogListener analogListener = new AnalogListener() {
        @Override
        public void onAnalog(String name, float value, float tpf) {

            if (isRunning) {
                Main m=new Main();
                if (name.equals("Rotate")) {
                    m. RotateCube();
                    System.out.println("Counter is: "+m.count);
                }
                if (name.equals("Right")) {
                    geom.move((new Vector3f(value, 0,0)) );
                }
                if (name.equals("Left")) {
                    geom.move(new Vector3f(-value, 0,0));
                }
            } else {
                System.out.println("Press P to unpause.");
            }
        }
    };

You are saying, in the listener. "I want a whole new application, forget about the old one; in the Main m=new Main();. And that new application hasn’t been started, it is just an empty shell. Don’t do that. You must only have one application

1 Like

Thanks. Let me try it. I will post if I get this resolved. But I think I need
Main main=new Main();
object to access the geom to rotate it.
Can I use Asset Manager outside a class without extending the SimpleApplication.

1 Like

I think our messages crossed. Your problem is that you are creating multiple applications Main m=new Main() rather than mutating your existing application.

What your code is (sort of) currently saying is:

Every time a button is pressed I want a whole new application

(Edit: ha, crossed again, but you had noticed my first message)

1 Like

I got your point. But this is painful for a unity user. when I have to use a field which is depending on SimpleApplication. I can’t access it without starting it !!
I want the existing application to rotate the cube without restarting or creating new app. (with the new Main():wink:
Where to learn these things !!

Thanks it worked !!
Love you all guys. tell me where to start learning this engine. !! THanks again.

Here is a fixed version of your analogListener

    final private AnalogListener analogListener = new AnalogListener() {
        @Override
        public void onAnalog(String name, float value, float tpf) {

            if (isRunning) {
                //Main m=new Main(); <-- Do not create a whole new application
                if (name.equals("Rotate")) {
                    RotateCube(); //<-- implicitly refers to "this.RotateCube"
                    System.out.println("Counter is: "+count); //<-- implicitly refers to "this.count"
                }
                if (name.equals("Right")) {
                    geom.move((new Vector3f(value, 0,0)) );
                }
                if (name.equals("Left")) {
                    geom.move(new Vector3f(-value, 0,0));
                }
            } else {
                System.out.println("Press P to unpause.");
            }
        }
    };

Note that it is within the scope of your running application so it has access to all of your Main classes methods. If this was not within Main you’d need to pass the objects you’d want to manipulate through

Where to learn these things !!

Game programming is hard, a lot of people start with game programming because its fun but you do miss out on a lot of the fundamentals. The jmonkey wiki is where to learn about jmonkey but I think your confusion is more java based

1 Like

I’ve tried to put together a simple java example that has the same problem as your original code

public class SimpleJava {

    public static void main(String[] args){
        GoodDog goodDog = new GoodDog();
        goodDog.bark();
        goodDog.bark();
        goodDog.bark();
        System.out.println(goodDog.barks); //prints 3

        BadDog badDog = new BadDog();
        badDog.bark();
        badDog.bark();
        badDog.bark();
        System.out.println(badDog.barks); //prints 0
    }

    private static class GoodDog {
        int barks;

        public GoodDog(){
            barks = 0;
        }

        public void bark(){
            barks++;
        }
    }

    private static class BadDog {
        int barks;

        public BadDog(){
            barks = 0;
        }

        public void bark(){
            BadDog otherBadDog = new BadDog();
            otherBadDog.barks++; //eeek! Why are we getting a second bad dog involved
        }
    }
}

If you can see why BadDog is broken and always has zero barks after bark() is called you’ll understand the fundamental issue with your original code

That code is arguably too simplified, so if you understand that but still not the original problem how about this. Here we have a BarkEffector (analogous to the AnalogLIstener) that is an inner class of a Dog (analogous to the SimpleApplication)

public class SimpleJava {

    public static void main(String[] args){
        GoodDog goodDog = new GoodDog();
        goodDog.bark();
        goodDog.bark();
        goodDog.bark();
        System.out.println(goodDog.barks); //prints 3

        BadDog badDog = new BadDog();
        badDog.bark();
        badDog.bark();
        badDog.bark();
        System.out.println(badDog.barks); //prints 0
    }

    private static class GoodDog {

        BarkEffector effector = new BarkEffector() {
            @Override
            public void bark() {
                barks++; //this is implicitly using the outer class's barks field
            }
        };

        int barks;

        public GoodDog(){
            barks = 0;
        }

        public void bark(){
            effector.bark();
        }
    }

    private static class BadDog {

        BarkEffector effector = new BarkEffector() {
            @Override
            public void bark() {
                BadDog badDog = new BadDog(); //eeek! this is a whole nother dog, not the one we are currently using
                badDog.barks++; //this is incrementing the barks field of the new dog, not the one we are currently using
                //and now the new badDog goes out of scope and is thrown away. 
            }
        };

        int barks;

        public BadDog(){
            barks = 0;
        }

        public void bark(){
            effector.bark();
        }
    }

    private interface BarkEffector{
        void bark();
    }
}

This exception is not thrown by the included code. The contentMan variable does not appear anywhere in that code.

1 Like

contentMan is an argument in Material’s constructor. The problem is the OP was passing null to a Material (because of instantiating a new Main class).

I.e. that is within the jMonkey library code

2 Likes

Thanks for now I’m happy with what I have learnt from you today. thanks again.

2 Likes

Thank you too man.