diff --git a/jme3-core/src/main/java/com/jme3/util/clone/CloneFunction.java b/jme3-core/src/main/java/com/jme3/util/clone/CloneFunction.java
new file mode 100644
index 000000000..cb5873007
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/util/clone/CloneFunction.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.util.clone;
+
+
+/**
+ * Provides custom cloning for a particular object type. Once
+ * registered with the Cloner, this function object will be called twice
+ * for any cloned object that matches the class for which it was registered.
+ * It will first call cloneObject() to shallow clone the object and then call
+ * cloneFields() to deep clone the object's values.
+ *
+ *
This two step process is important because this is what allows
+ * circular references in the cloned object graph.
+ *
+ * @author Paul Speed
+ */
+public interface CloneFunction {
+
+ /**
+ * Performs a shallow clone of the specified object. This is similar
+ * to the JmeCloneable.clone() method in semantics and is the first part
+ * of a two part cloning process. Once the shallow clone is created, it
+ * is cached and CloneFunction.cloneFields() is called. In this way,
+ * the CloneFunction interface can completely take over the JmeCloneable
+ * style cloning for an object that doesn't otherwise implement that interface.
+ *
+ * @param cloner The cloner performing the cloning operation.
+ * @param original The original object that needs to be cloned.
+ */
+ public T cloneObject( Cloner cloner, T original );
+
+
+ /**
+ * Performs a deep clone of the specified clone's fields. This is similar
+ * to the JmeCloneable.cloneFields() method in semantics and is the second part
+ * of a two part cloning process. Once the shallow clone is created, it
+ * is cached and CloneFunction.cloneFields() is called. In this way,
+ * the CloneFunction interface can completely take over the JmeCloneable
+ * style cloning for an object that doesn't otherwise implement that interface.
+ *
+ * @param cloner The cloner performing the cloning operation.
+ * @param clone The clone previously returned from cloneObject().
+ * @param original The original object that was cloned. This is provided for
+ * the very special case where field cloning needs to refer to
+ * the original object. Mostly the necessary fields should already
+ * be on the clone.
+ */
+ public void cloneFields( Cloner cloner, T clone, T original );
+
+}
diff --git a/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
new file mode 100644
index 000000000..a927223ae
--- /dev/null
+++ b/jme3-core/src/main/java/com/jme3/util/clone/Cloner.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.util.clone;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * A deep clone utility that provides similar object-graph-preserving
+ * qualities to typical serialization schemes. An internal registry
+ * of cloned objects is kept to be used by other objects in the deep
+ * clone process that implement JmeCloneable.
+ *
+ *
By default, objects that do not implement JmeCloneable will
+ * be treated like normal Java Cloneable objects. If the object does
+ * not implement the JmeCloneable or the regular JDK Cloneable interfaces
+ * AND has no special handling defined then an IllegalArgumentException
+ * will be thrown.
+ *
+ *
Enhanced object cloning is done in a two step process. First,
+ * the object is cloned using the normal Java clone() method and stored
+ * in the clone registry. After that, if it implements JmeCloneable then
+ * its cloneFields() method is called to deep clone any of the fields.
+ * This two step process has a few benefits. First, it means that objects
+ * can easily have a regular shallow clone implementation just like any
+ * normal Java objects. Second, the deep cloning of fields happens after
+ * creation wich means that the clone is available to future field cloning
+ * to resolve circular references.
+ *
+ *
Similar to Java serialization, the handling of specific object
+ * types can be customized. This allows certain objects to be cloned gracefully
+ * even if they aren't normally Cloneable. This can also be used as a
+ * sort of filter to keep certain types of objects from being cloned.
+ * (For example, adding the IdentityCloneFunction for Mesh.class would cause
+ * all mesh instances to be shared with the original object graph.)
+ *
+ *
By default, the Cloner registers serveral default clone functions
+ * as follows:
+ * // Example 1: using an instantiated, reusable cloner.
+ * Cloner cloner = new Cloner();
+ * Foo fooClone = cloner.clone(foo);
+ * cloner.clearIndex(); // prepare it for reuse
+ * Foo fooClone2 = cloner.clone(foo);
+ *
+ * // Example 2: using the utility method that self-instantiates a temporary cloner.
+ * Foo fooClone = Cloner.deepClone(foo);
+ *
+ *
+ *
+ * @author Paul Speed
+ */
+public class Cloner {
+
+ /**
+ * Keeps track of the objects that have been cloned so far.
+ */
+ private IdentityHashMap