I ran into a rather annoying problem which after much investigation I have boiled down to this:
Controls which are loaded via the asset manager will share List instances when they should not!
here is the easiest way to reproduce:
public class BuggedControl extends AbstractControl{
private List<String> buggedList;
public BuggedControl(){
buggedList = new ArrayList<>();
}
public void addStringToList(String s){
buggedList.add(s);
}
public List<String> getList(){
return buggedList;
}
@Override
protected void controlUpdate(float tpf) {}
@Override
protected void controlRender(RenderManager rm, ViewPort vp) {}
}
public class BugTest extends SimpleApplication{
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
BugTest app = new BugTest();
app.start();
}
@Override
public void simpleInitApp() {
//create 3 spatials via code, add to their lists
Spatial[] codedArray = new Spatial[3];
int coded = 0;
while(coded < 3){
String name = "Test "+coded++;
Node s = new Node(name);
BuggedControl bug = new BuggedControl();
s.addControl(bug);
bug.addStringToList(name);
codedArray[coded-1] = s;
}
//load 3 identical spatials, add to their lists
Spatial[] loadedArray = new Spatial[3];
int loaded = 0;
while(loaded < 3){
String name = "Test "+loaded++;
Spatial s = assetManager.loadModel("Test.j3o");
s.setName(name);
BuggedControl bug = s.getControl(BuggedControl.class);
bug.addStringToList(name);
loadedArray[loaded-1] = s;
}
//print the lists
System.out.println("Coded...");
for(int x=0; x<3; x++){
BuggedControl bug = codedArray[x].getControl(BuggedControl.class);
System.out.println(Arrays.toString(bug.getList().toArray()));
}
System.out.println("Loaded...");
for(int x=0; x<3; x++){
BuggedControl bug = loadedArray[x].getControl(BuggedControl.class);
System.out.println(Arrays.toString(bug.getList().toArray()));
}
}
}
in either the sdk or programmically, create and save a node with the BuggedControl attached, and name it “Test.j3o”
https://drive.google.com/file/d/1SJ2jF7aS9yCJL4iJ6tFyjG8eHmjcLCUw/preview
the above test produces the following console log:
Coded...
[Test 0]
[Test 1]
[Test 2]
Loaded...
[Test 0, Test 1, Test 2]
[Test 0, Test 1, Test 2]
[Test 0, Test 1, Test 2]
I have tested with the lists as final, and not final. The fix I have found is to generate the list when it is first accessed via the update loop.
This bug still presents itself if you create the list in the read() method as well!