0

I'm making a small game in JavaFX and I want a Highscore-system. Because I'm not that good with databases, I wrote the data to a textfile. But that easy editable, so I would want to write it to a textfile in AppData. So I tried with this line:

File file = new File(System.getenv("AppData") + "\\" + [Namefoler\\NameFile]);

But it keeps saying that I do not have acces to that folder. Writing to and off a file is no problem so my system works fine if I just write it to a textfile in the same directory as my jar. But it keeps throwing these errors.

Does someone know how I can prevent this, or a better solution for my problem?

Thanks in advance

Aleandro
  • 43
  • 7
  • http://stackoverflow.com/questions/18906163/how-do-i-create-directories-and-files-within-the-users-appdata-directory – noobcoder Apr 05 '17 at 21:32
  • Tried both, but they don't work! – Aleandro Apr 05 '17 at 21:34
  • The [preferences API](https://docs.oracle.com/javase/8/docs/technotes/guides/preferences/) is probably a better solution for you. – jewelsea Apr 05 '17 at 21:39
  • @jewelsea, But than I can only memorise 1 highscore? I want to make a list of all the highscores! – Aleandro Apr 05 '17 at 21:42
  • Sure, look at the [Preferences class](https://docs.oracle.com/javase/8/docs/api/java/util/prefs/Preferences.html), you can put associate any number of key/value pairs that you wish. As a bonus, it is not Windows specific, so it will work on non-Windows platforms that don't feature AppData. – jewelsea Apr 05 '17 at 21:46
  • If users find the preferences file can they change it? Otherwise it's not a very good solution cause I don't want that the user can change its own score! – Aleandro Apr 05 '17 at 21:53
  • Well, they could do that with a file in app data too. If you are very concerned, then you could encrypt the data using a key embedded in your app or a server based encryption/decryption service that you would write. Though rather than writing your own it would be better to use something like [Amazon S3](http://docs.aws.amazon.com/AmazonS3/latest/dev/DataDurability.html). – jewelsea Apr 05 '17 at 21:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/140017/discussion-between-aleandro-and-jewelsea). – Aleandro Apr 05 '17 at 22:01

1 Answers1

1

This answer is not to do with AppData, but you did ask about other solutions, so this is one based upon the Preferences API. The sample is for a preferences based API storage for a high-score system. The sample does not encrypt data.

You mention in your question that you are worried about the user modifying the preferences to fudge high scores. Encrypting or hiding data for a client application such that a user is not able to modify the data is a tricky proposition, so I won't go into how to do that here. If that is a requirement for you, then you can research other info on the internet for methods to accomplish that.

score system

ScoreStorage.java

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

public class ScoreStorage {
    private static final int MAX_NUM_SCORES = 3;

    private static final String SCORE_PREFERENCE_KEY_PREFIX = "score-";

    private ObservableList<Integer> scores = FXCollections.observableArrayList();
    private Preferences scorePreferences = Preferences.userNodeForPackage(
        ScoreStorage.class
    );

    public ScoreStorage() throws BackingStoreException {
        for (String key: scorePreferences.keys()) {
            scores.add(scorePreferences.getInt(key, 0));
        }
    }

    public ObservableList<Integer> getUnmodifiableScores() {
        return FXCollections.unmodifiableObservableList(scores);
    }

    public void clearScores() {
        scores.clear();
        storeScores();
    }

    public void recordScore(int score) {
        int i = 0;
        while (i < MAX_NUM_SCORES && i < scores.size() && scores.get(i) >= score) {
            i++;
        }

        if (i < MAX_NUM_SCORES) {
            if (scores.size() == MAX_NUM_SCORES) {
                scores.remove(scores.size() - 1);
            }
            scores.add(i, score);
            storeScores();
        }
    }

    private void storeScores() {
        int i = 0;
        for (int score: scores) {
            scorePreferences.putInt(SCORE_PREFERENCE_KEY_PREFIX + i, score);
            i++;
        }
        while (i < MAX_NUM_SCORES) {
            scorePreferences.remove(SCORE_PREFERENCE_KEY_PREFIX + i);
            i++;
        }
    }
}

HighScoreApp.java

Test harness:

import javafx.application.Application;
import javafx.geometry.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;

import java.util.Random;
import java.util.prefs.BackingStoreException;

public class HighScoreApp extends Application {

    private static ScoreStorage scoreStorage;

    private Random random = new Random(42);

    @Override
    public void start(Stage stage) throws Exception {
        ListView<Integer> scoreList = new ListView<>(scoreStorage.getUnmodifiableScores());
        scoreList.setPrefHeight(150);

        Label lastScoreLabel = new Label();

        Button generateScore = new Button("Generate new score");
        generateScore.setOnAction(event -> {
            int lastScore = random.nextInt(11_000);
            lastScoreLabel.setText("" + lastScore);
            scoreStorage.recordScore(lastScore);
        });

        Button clearScores = new Button("Clear scores");
        clearScores.setOnAction(event -> scoreStorage.clearScores());

        HBox scoreGenerator = new HBox(10, generateScore, lastScoreLabel);
        scoreGenerator.setAlignment(Pos.BASELINE_LEFT);

        VBox layout = new VBox(10, scoreGenerator, scoreList, clearScores);
        layout.setPadding(new Insets(10));

        stage.setScene(new Scene(layout));
        stage.show();
    }

    public static void main(String[] args) throws BackingStoreException {
        scoreStorage = new ScoreStorage();
        launch(args);
    }
}
jewelsea
  • 150,031
  • 14
  • 366
  • 406