PropertiesGameSettings

There's been a few threads in the past discussing storing GameSettings via Properties. I ended up needing easily-editable game settings so I threw this together.



The class handles both XML and simple properties files.


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.system.GameSettings;
import com.jme.system.PropertiesIO;

/**
 * @author Murray M. Moss <haibijon@gmail.com>
 */
public class PropertiesGameSettings implements GameSettings {

   private static final Logger      logger               = Logger.getLogger(PropertiesGameSettings.class.getName());

   private static final String      DEFAULT_RENDERER      = PropertiesIO.DEFAULT_RENDERER;
   private static final int      DEFAULT_WIDTH         = PropertiesIO.DEFAULT_WIDTH;
   private static final int      DEFAULT_HEIGHT         = PropertiesIO.DEFAULT_HEIGHT;
   private static final int      DEFAULT_DEPTH         = PropertiesIO.DEFAULT_DEPTH;
   private static final int      DEFAULT_FREQUENCY      = PropertiesIO.DEFAULT_FREQ;

   private static final boolean   DEFAULT_VERTICAL_SYNC   = true;
   private static final boolean   DEFAULT_FULLSCREEN      = false;
   private static final int      DEFAULT_DEPTH_BITS      = 8;
   private static final int      DEFAULT_ALPHA_BITS      = 0;
   private static final int      DEFAULT_STENCIL_BITS   = 0;
   private static final int      DEFAULT_SAMPLES         = 0;
   private static final boolean   DEFAULT_MUSIC         = true;
   private static final boolean   DEFAULT_SFX            = true;
   private static final int      DEFAULT_FRAMERATE      = -1;

   private Properties            properties;
   private File               propertiesFile;

   private boolean               storeAsXML;

   public PropertiesGameSettings() {
      this("game.properties", false);
   }

   public PropertiesGameSettings(String propertiesLoc) {
      this(propertiesLoc, false);
   }

   public PropertiesGameSettings(String propertiesLoc, boolean storeAsXML) {

      this.storeAsXML = storeAsXML;
      this.properties = new Properties();
      this.propertiesFile = new File(propertiesLoc);

      if (this.propertiesFile.exists()) {
         this.readProperties();
      }
   }

   private void readProperties() {

      try {
         FileInputStream inputStream = new FileInputStream(this.propertiesFile);

         if (this.storeAsXML) {
            this.properties.loadFromXML(inputStream);
         }

         else {
            this.properties.load(inputStream);
         }

         inputStream.close();
      }

      catch (Exception e) {
         logger.logp(Level.SEVERE, this.getClass()
               .toString(), "readProperties()", "Exception", e);
      }
   }

   private void saveProperties() {

      try {
         FileOutputStream outputStream = new FileOutputStream(this.propertiesFile);

         if (this.storeAsXML) {
            this.properties.storeToXML(outputStream, null);
         }

         else {
            this.properties.store(outputStream, null);
         }

         outputStream.close();
      }

      catch (Exception e) {
         logger.logp(Level.SEVERE, this.getClass()
               .toString(), "saveProperties()", "Exception", e);
      }
   }

   public void clear() throws Exception {
      this.properties.clear();
   }

   public String get(String name, String defaultValue) {
      return this.properties.getProperty(name, defaultValue);
   }

   public int getAlphaBits() {
      return this.getInt("GameAlphaBits", DEFAULT_ALPHA_BITS);
   }

   public void setAlphaBits(int alphaBits) {
      this.setInt("GameAlphaBits", alphaBits);
   }

   public int getDepth() {
      return this.getInt("GameDepth", DEFAULT_DEPTH);
   }

   public void setDepth(int depth) {
      this.setInt("GameDepth", depth);
   }

   public int getDepthBits() {
      return this.getInt("GameDepthBits", DEFAULT_DEPTH_BITS);
   }

   public void setDepthBits(int depthBits) {
      this.setInt("GameDepthBits", depthBits);
   }

   public int getFramerate() {
      return this.getInt("GameFramerate", DEFAULT_FRAMERATE);
   }

   public void setFramerate(int framerate) {
      this.setInt("GameFramerate", framerate);
   }

   public int getFrequency() {
      return this.getInt("GameFrquency", DEFAULT_FREQUENCY);
   }

   public void setFrequency(int frequency) {
      this.setInt("GameFrquency", frequency);
   }

   public int getHeight() {
      return this.getInt("GameHeight", DEFAULT_HEIGHT);
   }

   public void setHeight(int height) {
      this.setInt("GameHeight", height);
   }

   public String getRenderer() {
      return this.properties.getProperty("GameRenderer", DEFAULT_RENDERER);
   }

   public void setRenderer(String renderer) {
      this.set("GameRenderer", renderer);
   }

   public int getSamples() {
      return this.getInt("GameSamples", DEFAULT_SAMPLES);
   }

   public void setSamples(int samples) {
      this.setInt("GameSamples", samples);
   }

   public int getStencilBits() {
      return this.getInt("GameStencilBits", DEFAULT_STENCIL_BITS);
   }

   public void setStencilBits(int stencilBits) {
      this.setInt("GameStencilBits", stencilBits);
   }

   public int getWidth() {
      return this.getInt("GameWidth", DEFAULT_WIDTH);
   }

   public void setWidth(int width) {
      this.setInt("GameWidth", width);
   }

   public boolean isFullscreen() {
      return this.getBoolean("GameFullscreen", DEFAULT_FULLSCREEN);
   }

   public void setFullscreen(boolean fullscreen) {
      this.setBoolean("GameFullscreen", fullscreen);
   }

   public boolean isMusic() {
      return this.getBoolean("GameMusic", DEFAULT_MUSIC);
   }

   public void setMusic(boolean musicEnabled) {
      this.setBoolean("GameMusic", musicEnabled);
   }

   public boolean isSFX() {
      return this.getBoolean("GameSFX", DEFAULT_SFX);
   }

   public void setSFX(boolean sfxEnabled) {
      this.setBoolean("GameSFX", sfxEnabled);
   }

   public boolean isVerticalSync() {
      return this.getBoolean("GameVerticaleSync".toString(), DEFAULT_VERTICAL_SYNC);
   }

   public void setVerticalSync(boolean vsync) {
      this.setBoolean("GameVerticaleSync", vsync);
   }

   public void set(String name, String value) {
      this.properties.setProperty(name, value);
      this.saveProperties();
   }

   public boolean getBoolean(String name, boolean defaultValue) {
      return Boolean.parseBoolean(this.get(name, Boolean.toString(defaultValue)));
   }

   public byte[] getByteArray(String name, byte[] bytes) {
      throw new RuntimeException("Not Implemented.");
   }

   public double getDouble(String name, double defaultValue) {
      return Double.parseDouble(this.properties.getProperty(name, Double.toString(defaultValue)));
   }

   public float getFloat(String name, float defaultValue) {
      return Float.parseFloat(this.properties.getProperty(name, Float.toString(defaultValue)));
   }

   public int getInt(String name, int defaultValue) {
      return Integer.parseInt(this.properties.getProperty(name, Integer.toString(defaultValue)));
   }

   public long getLong(String name, long defaultValue) {
      return Long.parseLong(this.properties.getProperty(name, Long.toString(defaultValue)));
   }

   public Object getObject(String name, Object defaultValue) {
      throw new RuntimeException("Not Implemented.");
   }

   public void setObject(String name, Object value) {

      try {
         ByteArrayOutputStream byteInputStream = new ByteArrayOutputStream();
         ObjectOutputStream objInputStream = new ObjectOutputStream(byteInputStream);
         objInputStream.writeObject(value);

         byte[] bytes = byteInputStream.toByteArray();
         this.setByteArray(name, bytes);
      }

      catch (Exception e) {
         logger.logp(Level.SEVERE, this.getClass()
               .toString(), "setObject(String, Object)", "Exception", e);
      }
   }

   public void setBoolean(String name, boolean value) {
      this.set(name, Boolean.toString(value));
   }

   public void setByteArray(String name, byte[] bytes) {
      this.set(name, new String(bytes));
   }

   public void setDouble(String name, double value) {
      this.set(name, Double.toString(value));
   }

   public void setFloat(String name, float value) {
      this.set(name, Float.toString(value));
   }

   public void setInt(String name, int value) {
      this.set(name, Integer.toString(value));
   }

   public void setLong(String name, long value) {
      this.set(name, Long.toString(value));
   }
}



The get/setObject and byteArray methods are still untested, since they're not currently used anywhere in jME.

Looks interesting, thanks!

That can be very useful for people that want to use property files instead of Preferences.

Any chance of this getting committed?

This should definetly be included in CVS.

I don't have any problem with it being added, but alas I haven't got the time to do it at the moment…if you can convince another developer to get it in, I don't see any issues with it.