Converters

Now that the new file system in the next step should be to move the converters to the new system, this should not be difficult as all it takes is changing a few lines of code. I would be happy to do it if no one else wants to do it.

You mean for the XML format?  Personally I think jme's old binary system should be left behind.

We do not have to change the old system, just make a copy of the converters.



All the converters did was load a scene from a file and saved it in the old jme format,



We just need to make a copy that saves them to the new format instead.

Oh, gotcha, misunderstood your first posting.

Just looked over the code, It probely take me a 30 minutes or less to port and test the converters properly.I have limited access to a computer now, so I will have to wate for the weekend (Still trying to get computer repaired).

I think it was in some other thread, it was said that saving with DummyDisplaySystem, will make an unloadable file (due to different class names) for the normal DisplaySystem.

yeah, this is a major oversight on our part.

We should be able to overcome most of that (it's largely states that are the sticking point) though by handling it specially in GeomBatch's export/import.  Basically save out as non-specific states, generating display system specific ones on the read.

I almost am done with ported the converters.



Md2 works perfectly.

Md3 has some animation problems. (I do not think I can fix it)



The rest works well with the exception of the textures. The new loader dose not have the ability to set a texture class path. Should the converters have that ability or should the new importer be modified.

Here is what I have so far: I think that the new importer will have to be changed to fix the textures and Md3 is beond me.



http://hometown.aol.com/badmi2/jmeconverters.zip

Has any one looked at this? I think that the converters are working fine, it is the modal code that needs to be changed.

And that should be fixed first. Till then people better use the old model system.

Ok, I've started working on this solution, but it's not quite as clean as I would like. Here's how it works:


  1. Savable now has a method: public Class getClassTag that in most cases returns: MyClass.class;
  2. BinaryExporter uses this method to write out the class type.
  3. LWJGL* classes will not override this method but make use of the parents. I.e. AlphaState getClassTag returns AlphaState.class, and LWJGLAlphaState will not override getClassTag.



    This allows only AlphaState to be saved (which is fine, as there are no LWJGL Savables that actually save any data, except LWJGLCamera and that is being fixed).



    Now, reading is where it gets a little more painful. Because BinaryImporter knows nothing about the subclass therefore instead of doing:



    Savable out = (Savable)Class.forName(bco.className).newInstance();



    we need to do:



    Savable out = BinaryClassLoader.fromName(bco.className);



    where in most casses this method returns;



    (Savable)Class.forName(name).newInstance();



    However, if the class name is "AlphaState" it'd do:



    (Savable)DisplaySystem.getDisplaySystem().getRenderer().getAlphaState();



    Which means, yes, that BinaryClassLoader needs to know about what specific classes it needs to have display system load for it. I'm not thrilled about this aspect, but am not seeing a clean way around it. Any comments?

Assuming that the LWJGL* classes do not save any data themselves, you could get the name of the (top most) class in which the actual write method is using getClass(), and then use getDeclaredMethods() to see if there is a write() method. If not, use getSuperclass() and try again… Don't know how much performance this would suck up, but I think with some caching it'd be ok. This would avoid adding getClassTag() to the interface…



Still leaves the last problem of when to use factory methods for creating a class. I'm fine with hard coding them, but I suppose you if you want something cleaner could make a kind of generic "registry" for this, but that can always be done later… you could even forget about the whole stuff I wrote above here and use it for the other way around too (just replace lwjgl.LWJGLAlphaState by AlphaState, etc.).



Something like:



public class SavableRegistry {

public static HashMap mapping = new HashMap();
public static HashMap factory = new HashMap();

 public static register(String name, String longname, String factorymethod) {

The use of reflection means that we can no longer use tools that strip the code of names making it difficult to reverse compile. Perhaps all Savable classes should be placed in a map in the loader so reflection would not have to be used.  The map can also store another interface that loads the savable in a custom way. The other advantages of this system would be that it allows a programmer to block unwanted stables and that you can specify program generated textures.

Badmi, for ultra protection against such decompilation (I assume you mean for your own classes since jME is already pubically available so it would be pointless to obfuscate it) you could also simply make your own Importer/Exporter classes…

llama said:

Assuming that the LWJGL* classes do not save any data themselves, you could get the name of the (top most) class in which the actual write method is using getClass()


Hmm, but that assumes you never would want to save and reload a class that happens to extend a Savable but does not need to save/write any additional data... (which is likely to happen and probably already does in a few of the jME classes.)

it's really to bad that you can't have static methods in interfaces(forcing a createInstance method on all Savables where they could do new MyClass() or DisplaySystem.xxx.createState etc)



i don't fancy using reflection in combination with not forcing them, cause it allways ends up in programmer errors…it's so easy to forget to implement the methods without an interface or parent class forcing them…



but, if we didnt care about that, you could do it like this:


Savable out = null;
try {
   out = (Savable)Class.forName(bco.className).getMethod("createInstance").invoke(null);
   System.out.println("found creatInstance method");
} catch ( NoSuchMethodException e ) {
   try {
      out = (Savable)Class.forName(bco.className).newInstance();
      System.out.println("did not find creatInstance method, using default");
   } catch ( Exception e1 ) {}
} catch ( Exception e ) {}



where the classes would implement the method createInstance if they wanted a different way of being created:


public static Savable createInstance() {
   return DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
}



but theres gotta be better ways of doing it...

What bothers me about this solution Mr. Coder, is the createInstance method is now not part of the Savable contract.

exactly what i meant, and that's why it's too bad you can't have statics in an interface…and that it is easy to forget to implement etc when they are not forced through an interface or superclass…