Thank you @Momoko_Fan, I have sorted this out now.
I have not seen this documented anywhere but in the java doc, where you need to know that you are looking for subclasses of AssetCache and AssetProcessor, these subclasses explain their specializations quite well. I am leaving this code example for any future monkeys, it has an example of a clone-on-load object and a reference-on-load object, using one object that is a ClonableSmartAsset and one that is not. There is plenty of System.out.println, to provide quick transparency of de-serialization, object creation and cloning.
[java]
package mygame;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.AssetKey;
import com.jme3.asset.AssetProcessor;
import com.jme3.asset.CloneableAssetProcessor;
import com.jme3.asset.CloneableSmartAsset;
import com.jme3.asset.cache.AssetCache;
import com.jme3.asset.cache.WeakRefAssetCache;
import com.jme3.asset.cache.WeakRefCloneAssetCache;
import com.jme3.asset.plugins.FileLocator;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import com.jme3.export.binary.BinaryExporter;
import com.jme3.export.binary.BinaryImporter;
import com.jme3.system.JmeContext;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Main extends SimpleApplication {
/**
* The savable object that needs import / export
*/
public static class ClonableSavable implements Savable, CloneableSmartAsset {
private AssetKey key;
float value = 7f;
int no = 5;
public ClonableSavable() {
System.out.println(" - Create ClonableSavable() - ( de-serialization )" );
}
public ClonableSavable( float value, int no ) {
this.value = value;
this.no = no;
System.out.println(" - Create ClonableSavable( " + value +", " + no + " ) - ( creation || clone )" );
}
public void write( JmeExporter ex ) throws IOException {
OutputCapsule c = ex.getCapsule( this );
c.write( value, "value", 0f );
c.write( no, "no", 0 );
}
public void read( JmeImporter im ) throws IOException {
InputCapsule c = im.getCapsule( this );
this.value = c.readFloat( "value", 0f );
this.no = c.readInt( "no", 0 );
System.out.println(" - Reading ClonableSavable()" );
}
public void setKey( AssetKey key ) {
this.key = key;
}
public AssetKey getKey() {
return this.key;
}
@Override
public Object clone() {
ClonableSavable clone = new ClonableSavable( this.value, this.no );
System.out.println(" - Cloning class: " + this.getClass().getSimpleName() + ", object: @" + this.hashCode() + ", clone: @" + clone.hashCode() );
return clone;
}
}
public static class NonClonableSavable implements Savable {
float value = 7f;
int no = 5;
public NonClonableSavable() {
System.out.println(" - Create NonClonableSavable() - ( de-serialization )" );
}
public NonClonableSavable( float value, int no ) {
this.value = value;
this.no = no;
System.out.println(" - Create NonClonableSavable( " + value +", " + no + " ) - ( creation )" );
}
public void write( JmeExporter ex ) throws IOException {
OutputCapsule c = ex.getCapsule( this );
c.write( value, "value", 0f );
c.write( no, "no", 0 );
}
public void read( JmeImporter im ) throws IOException {
InputCapsule c = im.getCapsule( this );
this.value = c.readFloat( "value", 0f );
this.no = c.readInt( "no", 0 );
System.out.println(" - Reading NonClonableSavable()" );
}
Object o;
}
private static String gameName = "TestLoadSave";
public static void main(String[] args) {
Logger.getLogger("").setLevel( Level.WARNING );
Main app = new Main();
app.start( JmeContext.Type.Headless );
}
@Override
public void simpleInitApp() {
// Register a locator for our game resources:
String userHome = System.getProperty( "user.home" ) + "\\" + gameName + "\\";
this.getAssetManager().registerLocator( userHome , FileLocator.class );
// Register a loader for loading SavableObject.class
this.getAssetManager().registerLoader( BinaryImporter.class, "so1" );
this.getAssetManager().registerLoader( BinaryImporter.class, "so2" );
// Save objects:
this.testSave();
// Load objects:
this.testLoad();
System.exit( 0 );
}
private void testSave(){
System.out.println("\n****************");
System.out.println("** SAVING **");
System.out.println("****************");
this.exportSavableObject( new ClonableSavable( 7.1f, 0 ), "test\\so.so1" );
this.exportSavableObject( new NonClonableSavable( 7.2f, 1 ), "test\\so.so2" );
}
private void testLoad(){
System.out.println("\n*****************");
System.out.println("** LOADING **");
System.out.println("*****************");
String stringKey = "test\\so.so2";
AssetKey noCloneKey = new AssetKey( "test\\so.so2" );
AssetKey cloneKey = new AssetKey( "test\\so.so1" ){
@Override
public Class getCacheType(){
return WeakRefCloneAssetCache.class;
}
@Override
public Class getProcessorType(){
return CloneableAssetProcessor.class;
}
};
System.out.println("Loading NonClonableSavable #1");
NonClonableSavable s1_no1 = ( NonClonableSavable ) this.getAssetManager().loadAsset( noCloneKey );
System.out.println("Loading NonClonableSavable #2");
NonClonableSavable s1_no2 = ( NonClonableSavable ) this.getAssetManager().loadAsset( noCloneKey );
System.out.println("Loading ClonableSavable #1");
ClonableSavable s2_no1 = ( ClonableSavable ) this.getAssetManager().loadAsset( cloneKey );
System.out.println("Loading ClonableSavable #2");
ClonableSavable s2_no2 = ( ClonableSavable ) this.getAssetManager().loadAsset( cloneKey );
System.out.println("\n*****************");
System.out.println("** RESULTS **");
System.out.println("*****************");
System.out.println( s1_no1.getClass().getSimpleName() + " loaded using noCloneKey:");
System.out.println(" no1 == no2: " + ( s1_no1 == s1_no2 ) + " ( @"+ s1_no1.hashCode() + " == @" + s1_no2.hashCode() +" ) - " + ( ( s1_no1 == s1_no2 ) ? "REFERENCE!" : "CLONES!" ) );
System.out.println( s2_no1.getClass().getSimpleName() +" loaded using cloneKey:");
System.out.println(" no1 == no2: " + ( s2_no1 == s2_no2 ) + " ( @"+ s2_no1.hashCode() + " == @" + s2_no2.hashCode() +" ) - " + ( ( s2_no1 == s2_no2 ) ? "REFERENCE!" : "CLONES!" ) );
}
private ClonableSavable importSavableObject( AssetKey key ){
ClonableSavable so = ( ClonableSavable ) this.getAssetManager().loadAsset( key );
System.out.println("Loaded object #" + so.no + " result: " + so );
return so;
}
private void exportSavableObject( Savable toSave, String name ) {
String userHome = System.getProperty( "user.home" )+ "\\" + gameName + "\\";
BinaryExporter exporter = BinaryExporter.getInstance();
File file = new File( userHome + name );
System.out.print("Saving SavableObject to: " + file.getAbsolutePath() );
try {
exporter.save( toSave, file );
System.out.println( " - Success!" );
} catch ( IOException ex ) {
System.out.println( " - Failure!" );
ex.printStackTrace();
}
}
}
[/java]
Output should look like this:
** SAVING **
- Create ClonableSavable( 7.1, 0 ) - ( creation || clone )
Saving SavableObject to: C:\Users\nhald\TestLoadSave\test\so.so1 - Success!
- Create NonClonableSavable( 7.2, 1 ) - ( creation )
Saving SavableObject to: C:\Users\nhald\TestLoadSave\test\so.so2 - Success!
** LOADING **
Loading NonClonableSavable #1
- Create NonClonableSavable() - ( de-serialization )
- Reading NonClonableSavable()
Loading NonClonableSavable #2
Loading ClonableSavable #1
- Create ClonableSavable() - ( de-serialization )
- Reading ClonableSavable()
- Create ClonableSavable( 7.1, 0 ) - ( creation || clone )
- Cloning class: ClonableSavable, object: @26094370, clone: @11650554
Loading ClonableSavable #2
- Create ClonableSavable( 7.1, 0 ) - ( creation || clone )
- Cloning class: ClonableSavable, object: @26094370, clone: @20754125
** RESULTS **
NonClonableSavable loaded using noCloneKey:
no1 == no2: true ( @24347419 == @24347419 ) - REFERENCE!
ClonableSavable loaded using cloneKey:
no1 == no2: false ( @11650554 == @20754125 ) - CLONES!