Read/Write High Score Externally

Hi there,

This is my first endevour into actually trying to read/write to an external file using java.

I’m trying to retrieve an integer (a high score) compare it to the current score, and replace it with a new high score (if applicable)

What would be the best way to do this?

I’d have no idea where to start or what the best way to achieve this.

The thing is, it has to be able to save the value through the application being shut down or restarted. So I imagine I need some sort of xml file.

You don’t need XML for something this simple. But if you plan to add much additional information to the file in the future, you might consider using XML.

If you don’t use XML, the following article may be helpful to you:

For basic Java questions, the stackoverflow.com site is more appropriate than this forum.

@BigBob said: Hi there,

This is my first endevour into actually trying to read/write to an external file using java.

I’m trying to retrieve an integer (a high score) compare it to the current score, and replace it with a new high score (if applicable)

What would be the best way to do this?

I’d have no idea where to start or what the best way to achieve this.

The thing is, it has to be able to save the value through the application being shut down or restarted. So I imagine I need some sort of xml file.

Is this for an Android or Desktop game?

@t0neg0d

it is for an android game

Solved with

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:save_and_load

2 Likes

Clever!

Theres also a SaveGame class in the jme3tools package that does this in a more automated way and without using files (which don’t work on all OSs).

@normen said: Theres also a SaveGame class in the jme3tools package that does this in a more automated way and without using files (which don't work on all OSs).

Hey there, you…

I’m trying to compile a list of options for going about this and so I tried to get this working on Android, however I get an exception that states the file system is read only. Are there any particular permissions that need to be set in the manifest to get SaveGame to work on Android?

Honestly, this would be the ideal way of handling this, as the other options would be:

  1. Pre-create an XML or text file as part of one of the packages and modify it (not so good an option).
  2. Use Android’s SharedPreferences… this is just messy.
  3. Ive read there is a storage area for each apk when installed that you can read/write to without setting specific permissions, however, I haven’t been able to figure out how to use this. This would work well… Ijusyt haven’t gotten it to work.
  4. Rely on something like CloudSave from Google’s API… however, I still haven’t gotten this to work properly, as it requires the use of Layout Components I can’t get to show over JME’s render area yet.

Anyways, I’d like to add each option to the cheat sheet so others can decide what’s best for there app and not have to spend a week trying to get something working.

Any help would be appreciated!

@BigBob said: Solved with

https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:save_and_load

Hey there!

Can you give me a short run-down on how you got this working, avoiding the issue I mentioned in the post above?

Thanks!

Hi there t0neg0d!

Well I sure can :stuck_out_tongue:

I started by making a node and then applying a User Data to it. I then saved the Node as a .j3o file, and then loaded the .j3o via asset manager and retrieving the high score!

I then simply rewrite the .j3o if the high score is higher with the new high score :P!

It simply uses the project assets in the folder so no need to do anything crazy or super complicated.

This .j3o stuff will allow to do everything from basic scene saving to high scores and achievements.

Possibly even multiple user accounts by saving the information into a .j3o

Here is my culprit method

[java] //Saves the highscore into a node, this is only ran when the high score is higher
public void saveHighScore() {
BinaryExporter exporter = BinaryExporter.getInstance();
File file = new File(“Assets/Models/”+“HighScore.j3o”);
int newScore = player.finalScore;
highScore = new Node(“HighScore”);
highScore.setUserData(“HighScore”, newScore);
try {
exporter.save(highScore, file);
System.out.println(“Saved!”);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, “Error: Failed to save game!”, ex);
}
}[/java]

And for retrieving the node, it’s just a simple node loading!

[java]
private void getHighScore(){
highScore = (Node) assetManager.loadModel(“Models/HighScore.j3o”);
player = new Player();
player.score = -1;
player.highScore = highScore.getUserData(“HighScore”);
}[/java]

2 Likes
@BigBob said: Hi there t0neg0d!

Well I sure can :stuck_out_tongue:

I started by making a node and then applying a User Data to it. I then saved the Node as a .j3o file, and then loaded the .j3o via asset manager and retrieving the high score!

I then simply rewrite the .j3o if the high score is higher with the new high score :P!

It simply uses the project assets in the folder so no need to do anything crazy or super complicated.

This .j3o stuff will allow to do everything from basic scene saving to high scores and achievements.

Possibly even multiple user accounts by saving the information into a .j3o

Here is my culprit method

[java] //Saves the highscore into a node, this is only ran when the high score is higher
public void saveHighScore() {
BinaryExporter exporter = BinaryExporter.getInstance();
File file = new File(“Assets/Models/”+“HighScore.j3o”);
int newScore = player.finalScore;
highScore = new Node(“HighScore”);
highScore.setUserData(“HighScore”, newScore);
try {
exporter.save(highScore, file);
System.out.println(“Saved!”);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, “Error: Failed to save game!”, ex);
}
}[/java]

And for retrieving the node, it’s just a simple node loading!

[java]
private void getHighScore(){
highScore = (Node) assetManager.loadModel(“Models/HighScore.j3o”);
player = new Player();
player.score = -1;
player.highScore = highScore.getUserData(“HighScore”);
}[/java]

Ooooohh… you are writing into the assets jar. Wouldn’t this alter the checksum and do you or anyone else know if this is a problem when wanting to update your app?

EDIT: A while back I used a similar approach with XML, but an empty Node with user data set would work great if the checksum isn’t an issue for updating apps.

Updating the app will definitely be an issue, as it would reset anything in the assets.jar and send the users highscore back to whatever the default is on the .j3o.

I have not truely wrapped my mind around the odds and ends of android and how it works and this was more of a solution of convenience than a true way to save.

But (in my mind) this problem would be an issue with any updating of the application wheter it was a .j3o or not, as all files are in the APK which is updated when updating the app.

I assume any files in there will have issues when updating. So presumably to properly save, you must get out of your own APK and save it externally on the device itself.

Where and how to do that, I don’t know.

I gave this problem some thought, but decided not to dwell as I would most likely open a pandora’s box I didn’t need to deal with on my first read/write endeavor.

I’m not sure what a check sum is but I haven’t had any issues with how I’ve done it :stuck_out_tongue:

If you do every conquer the idea of how to save when updating the application, the only thing I could come up with was using game center or some sort of database to communicate with.

From what I understand there is a service that saves information, like achievements etc. But for the project I was making I couldn’t imagine huge issues with losing the high score on update.

But for a really serious project, losing the information on updates isn’t tolerable.

You can write it elsewhere, but you’d have to get outside your own .apk and of course know the proper directory on the phone.

@BigBob said: Updating the app will definitely be an issue, as it would reset anything in the assets.jar and send the users highscore back to whatever the default is on the .j3o.

I have not truely wrapped my mind around the odds and ends of android and how it works and this was more of a solution of convenience than a true way to save.

But (in my mind) this problem would be an issue with any updating of the application wheter it was a .j3o or not, as all files are in the APK which is updated when updating the app.

I assume any files in there will have issues when updating. So presumably to properly save, you must get out of your own APK and save it externally on the device itself.

Where and how to do that, I don’t know.

I gave this problem some thought, but decided not to dwell as I would most likely open a pandora’s box I didn’t need to deal with on my first read/write endeavor.

I’m not sure what a check sum is but I haven’t had any issues with how I’ve done it :stuck_out_tongue:

If you do every conquer the idea of how to save when updating the application, the only thing I could come up with was using game center or some sort of database to communicate with.

From what I understand there is a service that saves information, like achievements etc. But for the project I was making I couldn’t imagine huge issues with losing the high score on update.

But for a really serious project, losing the information on updates isn’t tolerable.

You can write it elsewhere, but you’d have to get outside your own .apk and of course know the proper directory on the phone.

Okay, I have your answer for you!

the directory you want to write to is this:

“data/data/<YOUR PACKAGE NAME>/”

For example:

“data/data/com.mycompany.mygame/”

You APK has read/write privileges by default to this directory. This directory is safe to write into as it can’t be opened or modified by the user unless the device is rooted. If you want to take it one step more, you could encrypt/decrypt, but I wouldn’t worry to much about that.

With your permission, I’ll merge the solutions and add the to the project cheat sheet.

On a related note for any who are interested, you can use the solution provided above (j3o + user data), however, you can also use XML (standard XML parsing), text files, encrypted binaries, etc… you are not limited in any capacity that I can see as to what you choose to use this space for.

@t0neg0d

:stuck_out_tongue: awesome

So simply changing the directory to what what you what you said and it writes to the device itself?

And this information saves independently of the application updating?

And yes add everything to the android sheet!

@BigBob said: @t0neg0d

:stuck_out_tongue: awesome

So simply changing the directory to what what you what you said and it writes to the device itself?

And this information saves independently of the application updating?

And yes add everything to the android sheet!

Yes and no… there is one catch:

When loading data you need to register the location and the path slightly changes. Here is an example of how to implement it:

[java]
public void saveGame(String name, Node node) {
BinaryExporter exporter = BinaryExporter.getInstance();
// No slash at the begin of the path
File file = new File(“data/data/<YOUR PACKAGE NAME>/” + name + “.j3o”);
try {
exporter.save(node, file);
} catch (IOException ex) {
Logger.getLogger(getClass().getName()).log(Level.SEVERE, “Error: Failed to save game.”, ex);
}
}

public Node loadGame(String name) {
// Added slash to the beginning of the path
// Also note that this only needs to be registered once, so do this some place else :wink:
main.getAssetManager().registerLocator(“/data/data/<YOUR PAKAGE NAME>/”, FileLocator.class);
Node node = (Node)main.getAssetManager().loadModel(name + “.j3o”);
return node;
}
[/java]

I would suggest nesting nodes where you can… for example:

[java]
Node profiles = new Node();
// Create a Profile and store it in a new Node
Node profile1 = new Node(“Profile 1”);
profile1.setUserData(“someKey”, someData);
profiles.attachChild(profile1);
// Then save profiles. When you read it back in, you can loop through the child Nodes to create a list of saved profiles, etc.
[/java]