Error during Java deserialization

Hey,



I tried to develop a jme multiplaygame, where the advanced vehicle is synchronized.

(same as discussed in http://www.jmonkeyengine.com/jmeforum/index.php?topic=7490.msg63657#msg63657)



Here the controller code:



package vig.game.network.controller;

import vig.game.scene.VehicleNode;
import vig.game.scene.vehicles.TutorialCar;

import com.captiveimagination.jgn.synchronization.GraphicalController;
import com.captiveimagination.jgn.synchronization.message.SynchronizeCreateMessage;
import com.captiveimagination.jgn.synchronization.message.SynchronizeMessage;
import com.captiveimagination.jgn.synchronization.message.SynchronizeRemoveMessage;
import com.jme.math.Vector3f;

/**
 * This is a basic implementation of the GraphicalControler for the jME-Physics project.
 *
 * @author Matthew D. Hicks
 */
public class CarController implements GraphicalController<VehicleNode> {
    private Vector3f store;

    public CarController() {
        store = new Vector3f();
    }

    public void applySynchronizationMessage(SynchronizeMessage message, VehicleNode car) {
        System.out.print('.');
        CarMessage m = (CarMessage) message;
        m.applayToCar(car);
    }

    public SynchronizeMessage createSynchronizationMessage(VehicleNode car) {
        CarMessage message = new CarMessage();
        message.setCar(car);
        return message;
    }

    /**
     * This method will always return 1.0f. It is recommended to override this method in games to provide better efficiency to synchronization.
     */
    public float proximity(VehicleNode dpn, short playerId) {
        return 1.0f;
    }

    /**
     * This method will always return true. It is recommended to override this method in games to provide a layer of security.
     */
    public boolean validateMessage(SynchronizeMessage message, VehicleNode dpn) {
        return true;
    }

    public boolean validateCreate(SynchronizeCreateMessage message) {
        return true;
    }

    public boolean validateRemove(SynchronizeRemoveMessage message) {
        return true;
    }
}



but when i try it i get the following exception....

com.captiveimagination.jgn.convert.ConversionException: Error during Java deserialization.
at com.captiveimagination.jgn.convert.SerializableConverter.readObjectData(SerializableConverter.java:57)
at com.captiveimagination.jgn.convert.Converter.readClassAndObject(Converter.java:185)
at com.captiveimagination.jgn.convert.FieldConverter.readObjectData(FieldConverter.java:108)
at com.captiveimagination.jgn.convert.Converter.readClassAndObject(Converter.java:185)
at com.captiveimagination.jgn.NIOMessageServer.readMessage(NIOMessageServer.java:190)
at com.captiveimagination.jgn.UDPMessageServer.read(UDPMessageServer.java:116)
at com.captiveimagination.jgn.NIOMessageServer.updateTraffic(NIOMessageServer.java:143)
at com.captiveimagination.jgn.clientserver.JGNServer.updateTraffic(JGNServer.java:172)
at com.captiveimagination.jgn.clientserver.JGNServer.update(JGNServer.java:160)
at com.captiveimagination.jgn.UpdatableRunnable.run(JGN.java:435)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.io.UTFDataFormatException
at java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(ObjectInputStream.java:3082)
at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3007)
at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2820)
at java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1051)
at java.io.ObjectStreamClass.readNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readClassDescriptor(ObjectInputStream.java:809)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1565)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1496)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1732)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1329)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:351)
at com.captiveimagination.jgn.convert.SerializableConverter.readObjectData(SerializableConverter.java:55)
... 10 more

what might be the reason????

Here the code of our vehicle, which is build out of the tutorial car:

package vig.game.scene;

import vig.game.hud.BulletInterface;
import vig.game.hud.HudNode;
import vig.game.hud.LifeInterface;
import vig.game.scene.vehicles.DummyVehicle;
import vig.game.scene.vehicles.TutorialCar;
import vig.game.scene.vehicles.VehicleModel;

import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jmex.physics.PhysicsSpace;

public class VehicleNode extends Node {
   private static final long serialVersionUID = 4785222707809565983L;

   final static public int DUMMY = 0;
   final static public int TUTORIALCAR = 1;
   
   int maxEnergy = 1;
   int currEnergy = 1;
   
   protected int collisionTolerance = 500;
   protected int currToleranceLevel = collisionTolerance;
   
   int weaponS = 0;
   int weaponM = 0;
   int weaponL = 0;
   
   int enginePower;
   VehicleModel model;
   
   int modelType = 0;
   
   int playerNumber;
   
   boolean hudLinked = false;
   HudNode hud;
   
   int portalImmunityCounter = 0;
   
   public VehicleNode(PhysicsSpace pSpace, int modelType, int maxEnergy, int playerNumber)
   {
      this(modelType,maxEnergy,playerNumber);
      
      this.setModel(modelType, pSpace);
   }
   
   public VehicleNode(int modelType, int maxEnergy, int playerNumber)
   {
      this.maxEnergy = maxEnergy;
      this.currEnergy = maxEnergy;
      this.playerNumber = playerNumber;
      this.modelType = modelType;
      
      initVehicle();
   }
   
   public void build(PhysicsSpace pSpace)
   {
      setModel(modelType, pSpace);
   }
   
   protected void initVehicle()
   {
      setName("Vehicle" + playerNumber);
      setRenderQueueMode(Renderer.QUEUE_OPAQUE);
   }
   
   
   
   /**
    * Loads the model with the given ID to this.
    *
    * @param modelID
    * @param pSpace
    */
   public void setModel(int modelID, PhysicsSpace pSpace)
   {
      switch (modelID)
      {
      case TUTORIALCAR:
         model = new TutorialCar(pSpace, enginePower, this);
         break;
      default:
         model = new DummyVehicle(pSpace, enginePower, this);
      };
      
      attachChild(model);
      
      updateGeometricState(0.0f, true);
        updateRenderState();
   }
   
   
   
   /**
    * Reduces the energy by the given amount.
    *
    * @param amount
    */
   public void reduceEnergy(int amount)
   {
      currEnergy = currEnergy - amount;
      
      if (this.hudLinked)
      {
         ((LifeInterface)this.hud.getInterface(HudNode.LIFE_INTERFACE)).setValue(this.currEnergy);
      }
   }
   
   
   
   /**
    * Increases the current energy by the given amount.
    * <br />
    * If the sum of current energy and given amount would be higher
    * than the maximum of energy, the vehicle can store, the current
    * energy will only be set to the maximum.
    *
    * @param amount
    */
   public void increaseEnergy(int amount)
   {
      if (currEnergy + amount < maxEnergy)
      {
         currEnergy = currEnergy + amount;
      }
      else
      {
         currEnergy = maxEnergy;
      }
      
      if (this.hudLinked)
      {
         ((LifeInterface)this.hud.getInterface(HudNode.LIFE_INTERFACE)).setValue(this.currEnergy);
      }
   }
   
   
   
   /**
    * Returns the number of energy points, the vehicle currently has.
    *
    * @return
    */
   public int getEnergy()
   {
      return currEnergy;
   }

   
   
   /**
    * Returns the maximum of energy, this verhicle can store.
    *
    * @return
    */
   public int getMaxEnergy()
   {
      return maxEnergy;
   }
   
   
   
   /**
    * Returns the player's number.
    *
    * @return
    */
   public int getPlayerNumber()
   {
      return playerNumber;
   }
   
   
   
   /**
    * Returns the model representing this vehicle.
    *
    * @return
    */
   public VehicleModel getModel()
   {
      return model;
   }
   
   
   
   /**
    * Returns the number of bullets of the given type available
    * for this vehicle.
    *
    * @param    weaponType   Weapon's type from WeaponNode
    * @return   int         Number of bullets for the given weapon type
    */
   public int getBulletQuantity(int weaponType)
   {
      switch (weaponType)
      {
      case WeaponNode.SIZES:
         return weaponS;
         
      case WeaponNode.SIZEM:
         return weaponM;
         
      case WeaponNode.SIZEL:
         return weaponL;
         
      default:
         return 0;
      }
   }
   
   
   
   /**
    * Increases the number of bullets of the given type by
    * the given number of bullets.
    *
    * @param weaponType   Type of the weapon whose bullet number is increased
    * @param number      Number of bullets to add to the existing bullets
    */
   public void increaseBulletQuantity(int weaponType, int number)
   {
      switch (weaponType)
      {
      case WeaponNode.SIZES:
         weaponS = weaponS + number;
         if (this.hudLinked)
         {
            ((BulletInterface)this.hud.getInterface(HudNode.BULLET_INTERFACE)).setText(WeaponNode.SIZES,String.valueOf(weaponS));
         }
         break;
         
      case WeaponNode.SIZEM:
         weaponM = weaponM + number;
         if (this.hudLinked)
         {
            ((BulletInterface)this.hud.getInterface(HudNode.BULLET_INTERFACE)).setText(WeaponNode.SIZEM,String.valueOf(weaponM));
         }
         break;
         
      case WeaponNode.SIZEL:
         weaponL = weaponL + number;
         if (this.hudLinked)
         {
            ((BulletInterface)this.hud.getInterface(HudNode.BULLET_INTERFACE)).setText(WeaponNode.SIZEL,String.valueOf(weaponL));
         }
         break;
      }
   }
   
   
   
   /**
    * Decreases the number of bullets of the given type by
    * the given number of bullets.
    *
    * @param weaponType   Type of the weapon whose bullet number is decresed
    * @param number      Number of bullets to remove from the existing bullets
    */
   public void decreaseBulletQuantity(int weaponType, int number)
   {
      switch (weaponType)
      {
      case WeaponNode.SIZES:
         weaponS = (weaponS - number > 0) ? weaponS - number : 0;
         if (this.hudLinked)
         {
            ((BulletInterface)this.hud.getInterface(HudNode.BULLET_INTERFACE)).setText(WeaponNode.SIZES,String.valueOf(weaponS));
         }
         break;
         
      case WeaponNode.SIZEM:
         weaponM = (weaponM - number > 0) ? weaponM - number : 0;
         if (this.hudLinked)
         {
            ((BulletInterface)this.hud.getInterface(HudNode.BULLET_INTERFACE)).setText(WeaponNode.SIZEM,String.valueOf(weaponM));
         }
         break;
         
      case WeaponNode.SIZEL:
         weaponL = (weaponL - number > 0) ? weaponL - number : 0;
         if (this.hudLinked)
         {
            ((BulletInterface)this.hud.getInterface(HudNode.BULLET_INTERFACE)).setText(WeaponNode.SIZEL,String.valueOf(weaponL));
         }
         break;
      }
   }
   
   
   
   /**
    * Returns the tolerance of this vehicle against collisions.
    * <br />
    * The higher the value, the less damage will be done by collisions.
    *
    * @return
    */
   public int getCollisionTolerance()
   {
      return collisionTolerance;
   }
   
   
   
   /**
    * Sets the tolerance of this vehicle against collisions.
    * <br />
    * The higher the value, the less damage will be done by collisions.
    *
    * @param toleranceValue
    */
   public void setCollisionTolerance(int toleranceValue)
   {
      if (toleranceValue > 0)
      {
         collisionTolerance = toleranceValue;
      }
   }
   
   
   
   /**
    * Sets the current tolerance level.
    * <br />
    * Every time when a collision event is fired on the vehicle, the
    * tolerance level should be decreased. If it reaches 0, the vehicle
    * will take damage. The tolerance level should be reset after this.
    * Its highest value is defined by the collision tolerance of this vehicle.
    *
    * @param toleranceLevel
    */
   public void setToleranceLevel(int toleranceLevel)
   {
      if (toleranceLevel > 0 && toleranceLevel <= this.collisionTolerance)
      {
         this.currToleranceLevel = toleranceLevel;
      }
      else if (toleranceLevel > this.collisionTolerance)
      {
         this.currToleranceLevel = this.collisionTolerance;
      }
   }
   
   
   
   /**
    * Resets the current tolerance level to the value
    * of the collision tolerance.
    * <br />
    * Every time when a collision event is fired on the vehicle, the
    * tolerance level should be decreased. If it reaches 0, the vehicle
    * will take damage. The tolerance level should be reset after this.
    * Its highest value is defined by the collision tolerance of this vehicle.
    *
    */
   public void resetToleranceLevel()
   {
      this.currToleranceLevel = this.collisionTolerance;
   }
   
   
   
   /**
    * Reduces the current tolerance level by the given value.
    * <br />
    * Every time when a collision event is fired on the vehicle, the
    * tolerance level should be decreased. If it reaches 0, the vehicle
    * will take damage. The tolerance level should be reset after this.
    * Its highest value is defined by the collision tolerance of this vehicle.
    *
    * @param value
    */
   public void reduceToleranceLevel(int value)
   {
      if (this.currToleranceLevel - value < 0)
      {
         this.currToleranceLevel = 0;
      }
      else
      {
         this.currToleranceLevel = this.currToleranceLevel - value;
      }
   }
   
   
   
   /**
    * Returns the value of the current tolerance level.
    * <br />
    * Every time when a collision event is fired on the vehicle, the
    * tolerance level should be decreased. If it reaches 0, the vehicle
    * will take damage. The tolerance level should be reset after this.
    * Its highest value is defined by the collision tolerance of this vehicle.
    * @return
    */
   public int getToleranceLevel()
   {
      return currToleranceLevel;
   }
   
   
   
   /**
    * Links a HudNode to data of this vehicle.
    *
    * @param hud
    */
   public void linkHud(HudNode hud)
   {
      if (hud != null)
      {
         this.hudLinked = true;
         this.hud = hud;
         
         ((LifeInterface)this.hud.getInterface(HudNode.LIFE_INTERFACE)).setMaxValue(this.maxEnergy);
         ((LifeInterface)this.hud.getInterface(HudNode.LIFE_INTERFACE)).setValue(this.currEnergy);
      }
   }
   
   
   
   /**
    * Removes the HudNode currently linked to this vehicle.
    */
   public void unlinkHud()
   {
      if (this.hudLinked)
      {
         this.hudLinked = false;
         this.hud = null;
      }
   }
   
   
   
   /**
    * Returns the HudNode currently linked to this vehicle.
    *
    * @return
    */
   public HudNode getHud()
   {
      return this.hud;
   }
   
   
   
   /**
    * Returns true, if this vehicle was linked to a HudNode, else false.
    *
    * @return
    */
   public boolean isLinkedToHud()
   {
      return this.hudLinked;
   }
   
   
   public void makePortalImmune()
   {
      this.portalImmunityCounter = 250;
   }
   
   public void decreasePortalImmunityCounter()
   {
      if (this.portalImmunityCounter > 0)
      {
         this.portalImmunityCounter--;
      }
   }
   
   public boolean isPortalImmune()
   {
      return (this.portalImmunityCounter > 0);
   }
}

What does CarMessage look like?

Sorry, forgot to post it :slight_smile:


package com.captiveimagination.jmephysicsnet;

import net.sf.dots.sandhopper.Car;

import com.captiveimagination.jgn.synchronization.message.SynchronizeMessage;

public class CarMessage extends SynchronizeMessage {
    CarObject chassi = new CarObject();
    CarObject frontSuspLeftBase = new CarObject();
    CarObject frontSuspRightBase = new CarObject();
    CarObject rearSuspLeftBase = new CarObject();
    CarObject rearSuspRightBase = new CarObject();

    CarObject frontSuspLeftWheel = new CarObject();
    CarObject frontSuspRightWheel = new CarObject();
    CarObject rearSuspLeftWheel = new CarObject();
    CarObject rearSuspRightWheel = new CarObject();

    public void setCar(Car car) {

        chassi.setObject(car.getChassis());
        frontSuspLeftBase.setObject(car.getFrontSuspension().getLeftBase());
        frontSuspRightBase.setObject(car.getFrontSuspension().getRightBase());
        rearSuspLeftBase.setObject(car.getRearSuspension().getLeftBase());
        rearSuspRightBase.setObject(car.getRearSuspension().getRightBase());
        frontSuspLeftWheel.setObject(car.getFrontSuspension().getLeftWheel().getPhysicsNode());
        frontSuspRightWheel.setObject(car.getFrontSuspension().getRightWheel().getPhysicsNode());
        rearSuspLeftWheel.setObject(car.getRearSuspension().getLeftWheel().getPhysicsNode());
        rearSuspRightWheel.setObject(car.getRearSuspension().getRightWheel().getPhysicsNode());

    }

    public void applayToCar(Car car) {
        chassi.setObject(car.getChassis());
        frontSuspLeftBase.applayToObject(car.getFrontSuspension().getLeftBase());
        frontSuspRightBase.applayToObject(car.getFrontSuspension().getRightBase());
        rearSuspLeftBase.applayToObject(car.getRearSuspension().getLeftBase());
        rearSuspRightBase.applayToObject(car.getRearSuspension().getRightBase());
        frontSuspLeftWheel.applayToObject(car.getFrontSuspension().getLeftWheel().getPhysicsNode());
        frontSuspRightWheel.applayToObject(car.getFrontSuspension().getRightWheel().getPhysicsNode());
        rearSuspLeftWheel.applayToObject(car.getRearSuspension().getLeftWheel().getPhysicsNode());
        rearSuspRightWheel.applayToObject(car.getRearSuspension().getRightWheel().getPhysicsNode());

    }

    public CarObject getChassi() {
        return chassi;
    }

    public void setChassi(CarObject chassi) {
        this.chassi = chassi;
    }

    public CarObject getFrontSuspLeftBase() {
        return frontSuspLeftBase;
    }

    public void setFrontSuspLeftBase(CarObject frontSuspLeftBase) {
        this.frontSuspLeftBase = frontSuspLeftBase;
    }

    public CarObject getFrontSuspRightBase() {
        return frontSuspRightBase;
    }

    public void setFrontSuspRightBase(CarObject frontSuspRightBase) {
        this.frontSuspRightBase = frontSuspRightBase;
    }

    public CarObject getRearSuspLeftBase() {
        return rearSuspLeftBase;
    }

    public void setRearSuspLeftBase(CarObject rearSuspLeftBase) {
        this.rearSuspLeftBase = rearSuspLeftBase;
    }

    public CarObject getRearSuspRightBase() {
        return rearSuspRightBase;
    }

    public void setRearSuspRightBase(CarObject rearSuspRightBase) {
        this.rearSuspRightBase = rearSuspRightBase;
    }

    public CarObject getFrontSuspLeftWheel() {
        return frontSuspLeftWheel;
    }

    public void setFrontSuspLeftWheel(CarObject frontSuspLeftWheel) {
        this.frontSuspLeftWheel = frontSuspLeftWheel;
    }

    public CarObject getFrontSuspRightWheel() {
        return frontSuspRightWheel;
    }

    public void setFrontSuspRightWheel(CarObject frontSuspRightWheel) {
        this.frontSuspRightWheel = frontSuspRightWheel;
    }

    public CarObject getRearSuspLeftWheel() {
        return rearSuspLeftWheel;
    }

    public void setRearSuspLeftWheel(CarObject rearSuspLeftWheel) {
        this.rearSuspLeftWheel = rearSuspLeftWheel;
    }

    public CarObject getRearSuspRightWheel() {
        return rearSuspRightWheel;
    }

    public void setRearSuspRightWheel(CarObject rearSuspRightWheel) {
        this.rearSuspRightWheel = rearSuspRightWheel;
    }
}

There is a problem with Object serialization in the latest release of JGN in conjunction with synchronization system.  I haven't really bothered to fix it because you REALLY should not be sending anything in synchronization apart from primitives when possible.  I would highly recommend converting this to be a series of floats to send the minimal amount of information possible for bandwidth and performance reasons.