Hi all. I am having a small problem with CustomControl. Before updating to JME3 SDK3.0 (Stable) everything was working fine with the CustomControl. It was behaving as it should and the attributes are being saved. After re-installing JME to JME3 SDK 3.0 (Stable) the CustomControl behaves as it should but the attributes are not saving. I tried to figure out the problem and see how others did but could not find a solution. I did create a new model and set the CustomControl on it but still the same problem remains. Any help will be appreciated.
Here is the code of one of the CustomControl which is just a basic one:
When you say “not saving” what exactly do you mean? Are the read()/write() methods ever called? If so, does a file get created? Perhaps the problem is not in DamageControl but in the code which initializes and uses it.
@sgold : I did mention that it is a CustomControl/AbstractControl. The purpose of this is to set behaviors of the objects/models so that I don’t need to call it from my other classes but can if I want to, so I don’t need to initialize in other classes. What I do is create CustomControl set the attributes and save the value of the attributes but the problem is that the attributes are not being saved in the Scene Composer. It used to save the attributes in the Scene Composer but after updating to the new version it does not. Maybe I am missing something.
Ah found the mistake. The attributes in the CustomControl in SceneComposer are being saved but the values are not shown in the properties screen in the SceneComposer. I created a new project to see if older projects had some problem. Then I found this problem. I created a new AbstractControl class to check and found that the values are being saved through read()/write() methods but for some reason are not shown in the properties screen in SceneComposer. It only shows when the values are set but when I re-open the .j3o file the values are gone from the Properties screen but they do exist.
@Override
public Control cloneForSpatial(Spatial spatial) {
NewClass control = new NewClass();
control.setTestBool1(testBool1);
control.setTestFloat1(testFloat1);
control.setTestFloat2(testFloat2);
control.setTestInt1(testInt1);
control.setSpatial(spatial);
return control;
}
public static void main(String[] args) {
Main app = new Main();
app.start();
}
@Override
public void simpleInitApp() {
/** A white ambient light source. */
AmbientLight ambient = new AmbientLight();
ambient.setColor(ColorRGBA.White);
rootNode.addLight(ambient);
DirectionalLight dl = new DirectionalLight();
dl.setColor(ColorRGBA.White);
dl.setDirection(new Vector3f(2.8f,-2.8f,-2.8f).normalizeLocal());
rootNode.addLight(dl);
//This is the model with the AbstractControl/NewClass.java
Spatial spatial = assetManager.loadModel("Models/Dummy1.mesh.j3o");
rootNode.attachChild(spatial);
//Printing out the values from NewClass.java in the model
NewClass control = spatial.getControl(NewClass.class);
System.out.println(control.getTestFloat1());
System.out.println(control.getTestFloat2());
System.out.println(control.getTestInt1());
System.out.println(control.isTestBool1());
}
@Override
public void simpleUpdate(float tpf) {
//TODO: add update code
}
@Override
public void simpleRender(RenderManager rm) {
//TODO: add render code
}
Just a debugging tip. I’m a big fan of “println” debugging and it would have helped you a lot in this case. Whenever there is a question like “Why isn’t this happening?” Step 1 is usually to determine if it’s even running. A System.out.println() will tell you that… and then let you go to the next step of verifying that the values are saved/loaded like you meant in this case.
I only mention it because it would probably have taken only as long as writing your well thought-out original post… and you’d have had your answer right away.
To the other problem, I don’t know. I’m not sure the SDK automatically inspects custom classes… but I have no knowledge of SDK magic.
@pspeed : Yeah I should have checked it with println before . I guess I just got off guard from SDK not showing the values in the Properties screen :facepalm: Any way thanks. =D
Having looked at the class com.jme3.gde.core.sceneexplorer.nodes.JmeGenericControl, it seems that the property sheet is not filled simply because
a) PropertyUtils.getPropertyDescriptor(c, field) is being called
This in turn will create a new PropertyDescriptor(field.getName(), c), which expects both a get<PropertyName> and isPropertyName method to be available.
The result is that PropertyUtils.getPropertyDescriptor() will always return null if both or one of these methods are missing.
In my opinion, PropertyUtils should check whether there is a getter or setter and then pass in these method names directly using the other available constructor,
and passing in null for methods which are not available.
I could provide you with a patch that would solve that problem.
@axnsoftware said:
Having looked at the class com.jme3.gde.core.sceneexplorer.nodes.JmeGenericControl, it seems that the property sheet is not filled simply because
a) PropertyUtils.getPropertyDescriptor(c, field) is being called
This in turn will create a new PropertyDescriptor(field.getName(), c), which expects both a get<PropertyName> and isPropertyName method to be available.
The result is that PropertyUtils.getPropertyDescriptor() will always return null if both or one of these methods are missing.
In my opinion, PropertyUtils should check whether there is a getter or setter and then pass in these method names directly using the other available constructor,
and passing in null for methods which are not available.
I could provide you with a patch that would solve that problem.
I’m not sure what you are talking about here. Java’s PropertyDescriptor will work with either an isXXX OR a getXXX method. PropertyDescriptor only requires that there be both an accessor and a mutator and it will keep track of both. This seems logical in this case since the SDK will need to display and to edit that value.
PropertyDescriptor would be completely broken otherwise. So maybe there is an edge case you haven’t explained properly.
It in turn will delegate to the other constructor, which will then
this.readMethodName = readMethodName;
if (readMethodName != null && getReadMethod() == null) {
throw new IntrospectionException("Method not found: " + readMethodName);
}
this.writeMethodName = writeMethodName;
if (writeMethodName != null && getWriteMethod() == null) {
throw new IntrospectionException("Method not found: " + writeMethodName);
}
causing PropertyUtils to always return null for non boolean, hence the IS_PREFIX, fields.
So, if you have a non boolean field with getter and setter and named them appropriately,
PropertyUtils will always fail as the property descriptor is looking for is<FieldName> instead
of get<FieldName>.
I must admit, though, that I am using Java 7 and it seems that the OP does the same.
The same holds true for PropertyUtils#getPropertyDescriptor(Class, Method).
getReadMethod() will check for getXXX or isXXX as needed.
PropertyDescriptor would be 100% broken (ie: most of the Java Beans API would be broken) if what you say is true since every property would require both a getXXX and an isXXX… which just isn’t true.