User preferences and initialization

I’ve added a “user preferences” functionality to my game, and I’d like to convert it into an appstate.
The “user preferences” is a text file that resides on

%USERPROFILE%/saved games/<my jme game>

I think that this folder makes the best sense and really is one of the few things that microsoft did right.
On other OS the folder is

~/.<my jme game>/

On the user preferences there stuff that should be loaded before starting the application. For example one setting is for showing the JME settings, so it is problematic to have it converted into an appstate, since the initialization starts later on… any thought on this?

I would have your Globals class deal with paths and access to option files and the appState would deal with displaying the options and allowing to modify them.

1 Like

Any reason you aren’t using:
https://docs.oracle.com/javase/7/docs/api/java/util/prefs/Preferences.html

I want to expose these settings in a user readable and user editable manner. I don’t want to tell the user to open regedit on %HCLASS_LOCAL_BANANA%

1 Like

There’s no reason you can’t do that with the preferences API. In fact, your editing UI will be exactly the same. Just persist through the API, rather than XML/homemade flat file, and your user can’t break it by moving/deleting the file. Also, probably easier to implement.

All the things I’ve done so far ( I/O wise ) with jME are:

  • load a human-readable text file via AssetLoader or directly using my utility class
  • load a binary format using AssetLoader and standard Java serialization in tandem
  • load 2 different binary formats from custom .j3o files (using the Savable API of jME)
    → I’m not sure, but I think using AssetLoader or Savable won’t help you in that special case.

Why do you try to wrap that into an AppState so hard?
Just provide a static method in your ...Application or use a “Globals” singleton.

Another idea:
If there is no settings file for the AppSettings, show the settings dialog.
If there is a settings file - read it and use that + show an Options dialog later.
→ The book “jMonkeyEngine 3.0” by Ruth Kusterer shows you how to do it in chapter 10, page 291
→ boils down to AppSettings.load( (see code in public github repo)
+
custom idea from Ogli:
If you always want to show that dialog or not, use a second file as a marker.
If the file (e.g. “show_settings”) is available, show the settings dialog.
Do it like AppSettings.load( did it.

Primitive ideas, but could lead to success. :chimpanzee_smile:

Netbeans has “Properties” and “EditableProperties” for that.
You could definately change that to load a file instead of using the Netbeans Resources.
It internally relies on the Properties Java API.

As for Path: Something like (warning, pseudocode): Environment.get(“user.home”) + “\Saved Games” (when System.get(“os.version”) is Windows, if not, just take .gameName as Folder)

1 Like

It’s not well documented but I think this method gives you a place in the user’s home dir:
https://javadoc.jmonkeyengine.org/com/jme3/system/JmeSystem.html#getStorageFolder(com.jme3.system.JmeSystem.StorageFolderType)

…that works on various platforms. You could check the source to figure out how it decides where that is to confirm.

Then I agree with others, just put your settings access code in a singleton. There’s only going to be one so a singleton is fine.

So you mean something like

class LoadSettings extends BaseAppState{

static void loadPreferences(String folderName){
//load stuff
}

//AppState init, update etc.

}

Not sure when I said that I needed to find out where is the home dir, however as I said:

I think this is the best choice, but I welcome any suggestions and in fact I hoped that the discussion would highlight a best practice for storing game-specific user data.

…except if it’s a singleton then maybe there isn’t a strong reason to make it an app state at all. Especially since you would need to access it before it’s really managed anyway.

1 Like

Note: I will add that in my own case, I actually DO register my singleton config manager as an app state. In that case, it’s just because I don’t write out the changes the user makes to preferences until update()… it covers the case where they change screen resolution at runtime to something that crashes the game. Only if the change is successful will another AppState.update() be called.

Ehm … :chimpanzee_closedlaugh: :chimpanzee_wink:
Two people said “make a singleton” and Paul also agreed.
One even said “why try make an Appstate” (just a guy called Ogli)

Yes, I was wondering too. But Paul’s hint is okay. I did not know it and did not know what you wrote in the original post. I’m using “user.home” in my game together with getGameName() it’s wrapped in a getGameFolder() method.

Yes, that would be desireable. But it seems there is no best practices. In this thread we have seen at least four different ways to do it. I’m using a binary file called “game_settings.j3o” today, but I agree that a “game_config.txt” or “game.cfg” would be better. Not sure, but I think the AppSettings.load( that I mentioned might use human-readable text too (will need to investigate this).

Damned, these pink colors hurt my eyes… :chimpanzee_closedlaugh:

AppSettings uses Java preferences.

The theory is that you don’t want users directly editing things that could give them parse errors at runtime… so you wrap all changes in a UI for your app.

Nice theory, but in practice human-readable text config files are widely used.
I think both have their pro and con.

Sure they are… but so are Preferences/the registry. Both very widely used.

This assumes a lot of work that might or might not be done… telling the users to edit settings is a lazy but effective way to save time.
The Preferences API solves a problem, but not this problem.

To be more assertive over my point: saved games on Windows should be on %USERPROFILE%/saved games/my jme game because:

  • it is user-specific
  • the saved game folder is “relocatable”, has a recognizable icon, it is even i18n-ized and in general is built for this purpouse

Unfortunately, other OS don’t have this notion so I revert to the old back ~/.myapp practice…
Any thoughts?

1 Like

Take a look at where the JME method puts them? It’s supposed to automatically take care of this for you and may already do the right thing. It lacks documentation so it’s hard to say but would take 5 minutes to check.

As I suspected, it uses Java Preferences API…

I have no idea what you are talking about:

…it does use the user’s home directory, though. (Which 90% of Java apps also use on Windows judging by the amount of .foo directories I have right now.)

Many games (even the better ones) use human-readable text config files.
Also, my favorite emulators make use of this.
I would not want my users to have to use registry editor under Windows - just like Pesegato.
Both Windows and Linux can make use of the same human-readable format.
For me it’s obvious why so many game makers use human-readable text.
The parse-errors-thing is not a big deal - just use default values if you encounter a line that can’t be parsed and write to the log file that the line (with showing its content) could not been parsed. So easy.
If you encounter a corrupt binary file that crashes the game, you can’t fix that and neither can your users. Whatever the reason of the crash may be (and whoever made that binary file or hacked it by using hex editors - might even be a rare case where your own binary crashes because you not having tested this rare case).
For me the pros of human-readable text are stronger than the cons.