Creating PhysicVehicle error

@normen can you confirm this?

Well I have a crash with
java.lang.NullPointerException: The vehicle object does not exist.
at com.jme3.bullet.PhysicsSpace.addVehicle(Native Method)
at com.jme3.bullet.PhysicsSpace.addRigidBody(PhysicsSpace.java:638)
at com.jme3.bullet.PhysicsSpace.addCollisionObject(PhysicsSpace.java:423)

And I think the cause is a update/rebuild error in the physic vehicles, or I understand some part of the concept false.

I create a PhysicVehicle with

rbody = new PhysicsVehicle(shape, pobj.getMass());
this.physicspace.addCollisionObject(rbody);

Now what happens, the constructor calls rebuildRigidBody
This calls postRebuild()
this in the Vehicle subclass should create the native Vehicle if it does not exist, but only if a physicspace does already exist (it does not as it is still in the initial constructor call at this point, so no vehicle is created here at this time)
[java]
if (space == null) {
return;
}
[/java]

Then I add it to the Physicspace, this goes to private void addRigidBody(PhysicsRigidBody node)

here it is tested if it represents a Vehicle
[java]
if (node instanceof PhysicsVehicle) {
logger.log(Level.FINE, “Adding vehicle constraint {0} to physics space.”, Long.toHexString(((PhysicsVehicle) node).getVehicleId()));
physicsVehicles.put(((PhysicsVehicle) node).getVehicleId(), (PhysicsVehicle) node);
addVehicle(physicsSpaceId, ((PhysicsVehicle) node).getVehicleId());
[/java]

At this point the vehicleid is tried to be used, however since no other attempt to rebuild happened, it is 0 here leading to the exception above.

I think the solution would be to check for the vehicle and do a rebuild it none exist.

Can anyone confirm this finding? If so I will attempt to patch this and post the diff.

This little hack does represent a dirty workaround, that simple sets the correct Physicspace and retries to create that vehicle object

[java]
if (node instanceof PhysicsVehicle) {
final PhysicsVehicle vehicle = (PhysicsVehicle) node;
vehicle.physicsSpace = this;
vehicle.postRebuild();
PhysicsSpace.logger.log(Level.FINE, “Adding vehicle constraint {0} to physics space.”, Long.toHexString(((PhysicsVehicle) node).getVehicleId()));
this.physicsVehicles.put(vehicle.getVehicleId(), vehicle);

		this.addVehicle(this.physicsSpaceId, vehicle.getVehicleId());
	}

[/java]

Try using “addCollisionObject” for the PhysicsSpace.

I actually did, but it makes no difference:

@normen

[java]

public void addCollisionObject(final PhysicsCollisionObject obj) {
	if (obj instanceof PhysicsGhostObject) {
		this.addGhostObject((PhysicsGhostObject) obj);
	} else if (obj instanceof PhysicsRigidBody) {
		this.addRigidBody((PhysicsRigidBody) obj);
	} else if (obj instanceof PhysicsVehicle) {
		this.addRigidBody((PhysicsVehicle) obj);
	} else if (obj instanceof PhysicsCharacter) {
		this.addCharacter((PhysicsCharacter) obj);
	}
}

[/java]

Also why is there the extra case for the Vehicle? I would assume there was at some point maybee a utility method that did set the physicspace? (my current jme is around 1-2 week old svn version)

It works with the VehicleControl it seems. The reason is how bullet works :slight_smile: A vehicle is a constraint and a rigidbody and the constraint needs a connection to the physics space.

Yes, the control does set this properly, however since we offer the lower level api shouldn’t it also work. (Reason i need this that I dont work with the scenegraph on serverside but with a more or less pure es by now)

I even pointed a bit hacky but working solution to this, please don’t ignore the problem I’m trying to tell, wich is a state error due to a failed assumption. The assumption is onyl valid when using it via a controll as it does a two phased init more or less.

Sure it should work but the control also just uses the base object and it works. The question is whats different from the control, the constructors are all the same. Just because I don’t immediately start the IDE, scrutinize the code and commit a fix doesn’t mean I’m ignoring anything. I give you hints and answers so you can maybe find the issue before me.

Ah ok I more interpreted it like:
What I use works, gtfo ^^

@normen

Here the reason why it works with the Controll

[java]

public void setPhysicsSpace(PhysicsSpace space) {
    createVehicle(space);
    if (space == null) {
        if (this.space != null) {
            this.space.removeCollisionObject(this);
            added = false;
        }
    } else {
        if(this.space==space) return;
        space.addCollisionObject(this);
        added = true;
    }
    this.space = space;
}

[/java]

Upon attaching the vehicle, it gets force generated, else it would suffer the very same bug mentiond above.

So, there will have to be some moment where you call createVehicle if you use the base class. Or at least supply a physics space. Some time ago the class would grab the physics space via a threadlocal variable but that obviously isn’t a solution either if you want to handle the lifetime yourself.

Yes, but then the documentation is a bit off

[java]
/**
* Used internally, creates the actual vehicle constraint when vehicle is added to phyicsspace
*/
public void createVehicle(final PhysicsSpace space) {
[/java]

Also why does the vehicle gets recreated in postRebuild, but is used already in Rebuild, no matter wich path is done, it is build 2 times this way. (As without one the rebuild will never succed, but its rebuild conditionless in the postRebuild)

The lifecycle management of the native vehicle itself looks a bit strange.
Especiall since the superclass is still using that threadlocals.

-> rebuild is useing the threadlocal, vehicle stuff is using a field. and rebuild is calling the vehicle code without ever ensuring the field is set (even tho it knows the correct value due to the threadlocal). By default it is not set.

So the most simple and not breaking change would be t the rid of the duplicate rebuild in postRebuild and state in the documenation that a explicit createVehicle call is necessary? Or do you see a better approch to polish this?

The problem is that there is no RigidBody without a vehicle constraint which in turn cannot be created without a Physics Space. This basically means that the creation of the vehicle in bullet is “inside out” compared to all other objects. It has to be recreated in rebuild because changes cannot be made to the vehicle, it has to be recreated when you e.g. remove a wheel.

Yes, absolutly wight, but why doing it in POSTrebuild then ? we already have one as else the normal rebuild could not be finished.

@Empire Phoenix said: Yes, absolutly wight, but why doing it in POSTrebuild then ? we already have one as else the normal rebuild could not be finished.

But its not in the rebuild method, its in setPhysicsSpace, which is only in the Control. It needs to be in rebuild, so maybe “pre” but then the RigidBody isn’t there :slight_smile: The fact that the vehicle gets created two times is not much of an overhead. I’ll check how this could be cleaned up some time. For now just create the vehicle in the right moment when you don’t use controls.

Yes, its not that much of an issue to me, but thought it should be mentioned.