diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java
index 7c69fdf51..d4f3658c0 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/AbstractPhysicsControl.java
@@ -41,6 +41,8 @@ import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
@@ -49,7 +51,7 @@ import java.io.IOException;
*
* @author normenhansen
*/
-public abstract class AbstractPhysicsControl implements PhysicsControl {
+public abstract class AbstractPhysicsControl implements PhysicsControl, JmeCloneable {
private final Quaternion tmp_inverseWorldRotation = new Quaternion();
protected Spatial spatial;
@@ -161,6 +163,12 @@ public abstract class AbstractPhysicsControl implements PhysicsControl {
}
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+ this.spatial = cloner.clone(spatial);
+ createSpatialData(this.spatial);
+ }
+
public void setSpatial(Spatial spatial) {
if (this.spatial != null && this.spatial != spatial) {
removeSpatialData(this.spatial);
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java
index d88e57a26..30190f1f1 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/BetterCharacterControl.java
@@ -50,6 +50,8 @@ import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
@@ -68,7 +70,7 @@ import java.util.logging.Logger;
*
* @author normenhansen
*/
-public class BetterCharacterControl extends AbstractPhysicsControl implements PhysicsTickListener {
+public class BetterCharacterControl extends AbstractPhysicsControl implements PhysicsTickListener, JmeCloneable {
protected static final Logger logger = Logger.getLogger(BetterCharacterControl.class.getName());
protected PhysicsRigidBody rigidBody;
@@ -670,6 +672,14 @@ public class BetterCharacterControl extends AbstractPhysicsControl implements Ph
return control;
}
+ @Override
+ public Object jmeClone() {
+ BetterCharacterControl control = new BetterCharacterControl(radius, height, mass);
+ control.setJumpForce(jumpForce);
+ control.spatial = this.spatial;
+ return control;
+ }
+
@Override
public void write(JmeExporter ex) throws IOException {
super.write(ex);
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java
index f455043eb..7ef80778c 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/CharacterControl.java
@@ -44,13 +44,15 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
* You might want to try BetterCharacterControl
as well.
* @author normenhansen
*/
-public class CharacterControl extends PhysicsCharacter implements PhysicsControl {
+public class CharacterControl extends PhysicsCharacter implements PhysicsControl, JmeCloneable {
protected Spatial spatial;
protected boolean enabled = true;
@@ -104,6 +106,29 @@ public class CharacterControl extends PhysicsCharacter implements PhysicsControl
return control;
}
+ @Override
+ public Object jmeClone() {
+ CharacterControl control = new CharacterControl(collisionShape, stepHeight);
+ control.setCcdMotionThreshold(getCcdMotionThreshold());
+ control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
+ control.setCollideWithGroups(getCollideWithGroups());
+ control.setCollisionGroup(getCollisionGroup());
+ control.setFallSpeed(getFallSpeed());
+ control.setGravity(getGravity());
+ control.setJumpSpeed(getJumpSpeed());
+ control.setMaxSlope(getMaxSlope());
+ control.setPhysicsLocation(getPhysicsLocation());
+ control.setUpAxis(getUpAxis());
+ control.setApplyPhysicsLocal(isApplyPhysicsLocal());
+ control.spatial = this.spatial;
+ return control;
+ }
+
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+ this.spatial = cloner.clone(spatial);
+ }
+
public void setSpatial(Spatial spatial) {
this.spatial = spatial;
setUserObject(spatial);
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java
index 55fdfdcc3..70c636507 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/GhostControl.java
@@ -44,6 +44,8 @@ import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
@@ -51,7 +53,7 @@ import java.io.IOException;
* overlaps with other physics objects (e.g. aggro radius).
* @author normenhansen
*/
-public class GhostControl extends PhysicsGhostObject implements PhysicsControl {
+public class GhostControl extends PhysicsGhostObject implements PhysicsControl, JmeCloneable {
protected Spatial spatial;
protected boolean enabled = true;
@@ -106,6 +108,25 @@ public class GhostControl extends PhysicsGhostObject implements PhysicsControl {
return control;
}
+ @Override
+ public Object jmeClone() {
+ GhostControl control = new GhostControl(collisionShape);
+ control.setCcdMotionThreshold(getCcdMotionThreshold());
+ control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
+ control.setCollideWithGroups(getCollideWithGroups());
+ control.setCollisionGroup(getCollisionGroup());
+ control.setPhysicsLocation(getPhysicsLocation());
+ control.setPhysicsRotation(getPhysicsRotationMatrix());
+ control.setApplyPhysicsLocal(isApplyPhysicsLocal());
+ control.spatial = this.spatial;
+ return control;
+ }
+
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+ this.spatial = cloner.clone(spatial);
+ }
+
public void setSpatial(Spatial spatial) {
this.spatial = spatial;
setUserObject(spatial);
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
index 78cc4ca0a..6c25b6662 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/KinematicRagdollControl.java
@@ -61,6 +61,8 @@ import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.util.TempVars;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.*;
import java.util.logging.Level;
@@ -92,7 +94,7 @@ import java.util.logging.Logger;
*
* @author Normen Hansen and Rémy Bouquet (Nehon)
*/
-public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener {
+public class KinematicRagdollControl extends AbstractPhysicsControl implements PhysicsCollisionListener, JmeCloneable {
protected static final Logger logger = Logger.getLogger(KinematicRagdollControl.class.getName());
protected List listeners;
@@ -920,6 +922,17 @@ public class KinematicRagdollControl extends AbstractPhysicsControl implements P
return control;
}
+ @Override
+ public Object jmeClone() {
+ KinematicRagdollControl control = new KinematicRagdollControl(preset, weightThreshold);
+ control.setMode(mode);
+ control.setRootMass(rootMass);
+ control.setWeightThreshold(weightThreshold);
+ control.setApplyPhysicsLocal(applyLocal);
+ control.spatial = this.spatial;
+ return control;
+ }
+
public Vector3f setIKTarget(Bone bone, Vector3f worldPos, int chainLength) {
Vector3f target = worldPos.subtract(targetModel.getWorldTranslation());
ikTargets.put(bone.getName(), target);
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java
index 0e1f1c019..25a23cc7c 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/RigidBodyControl.java
@@ -51,13 +51,15 @@ import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Sphere;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
*
* @author normenhansen
*/
-public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl {
+public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl, JmeCloneable {
protected Spatial spatial;
protected boolean enabled = true;
@@ -116,6 +118,39 @@ public class RigidBodyControl extends PhysicsRigidBody implements PhysicsControl
return control;
}
+ @Override
+ public Object jmeClone() {
+ RigidBodyControl control = new RigidBodyControl(collisionShape, mass);
+ control.setAngularFactor(getAngularFactor());
+ control.setAngularSleepingThreshold(getAngularSleepingThreshold());
+ control.setCcdMotionThreshold(getCcdMotionThreshold());
+ control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
+ control.setCollideWithGroups(getCollideWithGroups());
+ control.setCollisionGroup(getCollisionGroup());
+ control.setDamping(getLinearDamping(), getAngularDamping());
+ control.setFriction(getFriction());
+ control.setGravity(getGravity());
+ control.setKinematic(isKinematic());
+ control.setKinematicSpatial(isKinematicSpatial());
+ control.setLinearSleepingThreshold(getLinearSleepingThreshold());
+ control.setPhysicsLocation(getPhysicsLocation(null));
+ control.setPhysicsRotation(getPhysicsRotationMatrix(null));
+ control.setRestitution(getRestitution());
+
+ if (mass > 0) {
+ control.setAngularVelocity(getAngularVelocity());
+ control.setLinearVelocity(getLinearVelocity());
+ }
+ control.setApplyPhysicsLocal(isApplyPhysicsLocal());
+ control.spatial = this.spatial;
+ return control;
+ }
+
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+ this.spatial = cloner.clone(spatial);
+ }
+
public void setSpatial(Spatial spatial) {
this.spatial = spatial;
setUserObject(spatial);
diff --git a/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java b/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java
index 0600da9bc..7ad36b3ae 100644
--- a/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java
+++ b/jme3-bullet/src/common/java/com/jme3/bullet/control/VehicleControl.java
@@ -46,6 +46,8 @@ import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
import java.util.Iterator;
@@ -53,7 +55,7 @@ import java.util.Iterator;
*
* @author normenhansen
*/
-public class VehicleControl extends PhysicsVehicle implements PhysicsControl {
+public class VehicleControl extends PhysicsVehicle implements PhysicsControl, JmeCloneable {
protected Spatial spatial;
protected boolean enabled = true;
@@ -156,6 +158,63 @@ public class VehicleControl extends PhysicsVehicle implements PhysicsControl {
return control;
}
+ @Override
+ public Object jmeClone() {
+ VehicleControl control = new VehicleControl(collisionShape, mass);
+ control.setAngularFactor(getAngularFactor());
+ control.setAngularSleepingThreshold(getAngularSleepingThreshold());
+ control.setAngularVelocity(getAngularVelocity());
+ control.setCcdMotionThreshold(getCcdMotionThreshold());
+ control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
+ control.setCollideWithGroups(getCollideWithGroups());
+ control.setCollisionGroup(getCollisionGroup());
+ control.setDamping(getLinearDamping(), getAngularDamping());
+ control.setFriction(getFriction());
+ control.setGravity(getGravity());
+ control.setKinematic(isKinematic());
+ control.setLinearSleepingThreshold(getLinearSleepingThreshold());
+ control.setLinearVelocity(getLinearVelocity());
+ control.setPhysicsLocation(getPhysicsLocation());
+ control.setPhysicsRotation(getPhysicsRotationMatrix());
+ control.setRestitution(getRestitution());
+
+ control.setFrictionSlip(getFrictionSlip());
+ control.setMaxSuspensionTravelCm(getMaxSuspensionTravelCm());
+ control.setSuspensionStiffness(getSuspensionStiffness());
+ control.setSuspensionCompression(tuning.suspensionCompression);
+ control.setSuspensionDamping(tuning.suspensionDamping);
+ control.setMaxSuspensionForce(getMaxSuspensionForce());
+
+ for (Iterator it = wheels.iterator(); it.hasNext();) {
+ VehicleWheel wheel = it.next();
+ VehicleWheel newWheel = control.addWheel(wheel.getLocation(), wheel.getDirection(), wheel.getAxle(), wheel.getRestLength(), wheel.getRadius(), wheel.isFrontWheel());
+ newWheel.setFrictionSlip(wheel.getFrictionSlip());
+ newWheel.setMaxSuspensionTravelCm(wheel.getMaxSuspensionTravelCm());
+ newWheel.setSuspensionStiffness(wheel.getSuspensionStiffness());
+ newWheel.setWheelsDampingCompression(wheel.getWheelsDampingCompression());
+ newWheel.setWheelsDampingRelaxation(wheel.getWheelsDampingRelaxation());
+ newWheel.setMaxSuspensionForce(wheel.getMaxSuspensionForce());
+
+ // Copy the wheel spatial reference directly for now. They'll
+ // get fixed up in the cloneFields() method
+ newWheel.setWheelSpatial(wheel.getWheelSpatial());
+ }
+ control.setApplyPhysicsLocal(isApplyPhysicsLocal());
+
+ control.spatial = spatial;
+ return control;
+ }
+
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+ this.spatial = cloner.clone(spatial);
+
+ for( VehicleWheel wheel : wheels ) {
+ Spatial spatial = cloner.clone(wheel.getWheelSpatial());
+ wheel.setWheelSpatial(spatial);
+ }
+ }
+
public void setSpatial(Spatial spatial) {
this.spatial = spatial;
setUserObject(spatial);
diff --git a/jme3-core/src/main/java/com/jme3/animation/AnimControl.java b/jme3-core/src/main/java/com/jme3/animation/AnimControl.java
index 9c3013f5e..36dbb6be5 100644
--- a/jme3-core/src/main/java/com/jme3/animation/AnimControl.java
+++ b/jme3-core/src/main/java/com/jme3/animation/AnimControl.java
@@ -38,11 +38,14 @@ import com.jme3.scene.Mesh;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import com.jme3.util.TempVars;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.Map;
import java.util.Map.Entry;
/**
@@ -65,7 +68,7 @@ import java.util.Map.Entry;
*
* @author Kirill Vainer
*/
-public final class AnimControl extends AbstractControl implements Cloneable {
+public final class AnimControl extends AbstractControl implements Cloneable, JmeCloneable {
/**
* Skeleton object must contain corresponding data for the targets' weight buffers.
@@ -131,6 +134,32 @@ public final class AnimControl extends AbstractControl implements Cloneable {
}
}
+ @Override
+ public Object jmeClone() {
+ AnimControl clone = (AnimControl) super.jmeClone();
+ clone.channels = new ArrayList();
+ clone.listeners = new ArrayList();
+
+ return clone;
+ }
+
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+ super.cloneFields(cloner, original);
+
+ this.skeleton = cloner.clone(skeleton);
+
+ // Note cloneForSpatial() never actually cloned the animation map... just its reference
+ HashMap newMap = new HashMap<>();
+
+ // animationMap is cloned, but only ClonableTracks will be cloned as they need a reference to a cloned spatial
+ for( Map.Entry e : animationMap.entrySet() ) {
+ newMap.put(e.getKey(), cloner.clone(e.getValue()));
+ }
+
+ this.animationMap = newMap;
+ }
+
/**
* @param animations Set the animations that this AnimControl
* will be capable of playing. The animations should be compatible
diff --git a/jme3-core/src/main/java/com/jme3/animation/Animation.java b/jme3-core/src/main/java/com/jme3/animation/Animation.java
index 5ae34628e..9fe47db9f 100644
--- a/jme3-core/src/main/java/com/jme3/animation/Animation.java
+++ b/jme3-core/src/main/java/com/jme3/animation/Animation.java
@@ -35,6 +35,8 @@ import com.jme3.export.*;
import com.jme3.scene.Spatial;
import com.jme3.util.SafeArrayList;
import com.jme3.util.TempVars;
+import com.jme3.util.clone.Cloner;
+import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;
/**
@@ -42,7 +44,7 @@ import java.io.IOException;
*
* @author Kirill Vainer, Marcin Roguski (Kaelthas)
*/
-public class Animation implements Savable, Cloneable {
+public class Animation implements Savable, Cloneable, JmeCloneable {
/**
* The name of the animation.
@@ -190,6 +192,33 @@ public class Animation implements Savable, Cloneable {
}
}
+ @Override
+ public Object jmeClone() {
+ try {
+ return super.clone();
+ } catch( CloneNotSupportedException e ) {
+ throw new RuntimeException("Error cloning", e);
+ }
+ }
+
+ @Override
+ public void cloneFields( Cloner cloner, Object original ) {
+
+ // There is some logic here that I'm copying but I'm not sure if
+ // it's a mistake or not. If a track is not a CloneableTrack then it
+ // isn't cloned at all... even though they all implement clone() methods. -pspeed
+ SafeArrayList