Skip to content

Commit

Permalink
nå funker det skikkelig :)
Browse files Browse the repository at this point in the history
  • Loading branch information
EspenTinius committed May 26, 2026
1 parent 6815b80 commit 06707aa
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 138 deletions.
58 changes: 46 additions & 12 deletions src/main/java/edu/ntnu/idi/idatt2003/g40/mappe/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,28 +217,62 @@ public void start(final Stage stage) throws Exception {
new InGameSettingsController(inGameSettingsView, eventManager, inGameView);
topBarController.setSettingsAction(inGameSettingsController::show);

// Auto-save the currently active save when the player quits back
// to the main menu. Silent if no save is active (i.e. the user
// got into the in-game scene without going through the save list).
topBarController.setOnQuitToMainMenu(() -> {
System.out.println("[auto-save] Quit triggered, attempting snapshot...");
// Auto-save the currently active save. Used by every trigger below
// (quit-button, window close, money change, week advance). Silent
// if no save is active (i.e. the user got into the in-game scene
// without going through the save list), or if a save-load is
// currently in progress (the money / week mutations inside
// applySave fire the same property listeners we hook up below, so
// without this guard we would write half-loaded state back to disk
// in the middle of a load).
Runnable autoSave = () -> {
if (gameStateLoader.isLoading()) {
return;
}
SaveGame snapshot = gameStateLoader.snapshotActiveSave();
if (snapshot == null) {
System.out.println("[auto-save] No active save - nothing to write.");
return;
}
System.out.println("[auto-save] Snapshot built for '" + snapshot.getName()
+ "', balance=" + snapshot.getBalance()
+ ", week=" + snapshot.getWeek()
+ ", shares=" + snapshot.getOwnedShares().size()
+ ", txns=" + snapshot.getTransactions().size());
try {
saveGameService.saveGame(snapshot);
System.out.println("[auto-save] Wrote save '" + snapshot.getName() + "' to disk.");
System.out.println("[auto-save] Wrote save '" + snapshot.getName()
+ "' (balance=" + snapshot.getBalance()
+ ", week=" + snapshot.getWeek()
+ ", shares=" + snapshot.getOwnedShares().size()
+ ", txns=" + snapshot.getTransactions().size() + ").");
} catch (Exception e) {
System.err.println("[auto-save] Failed: " + e.getMessage());
e.printStackTrace();
}
};

// Trigger 1: quit-button in the top bar (refreshes the play-game
// list too so the row balance reflects what we just wrote).
topBarController.setOnQuitToMainMenu(() -> {
System.out.println("[auto-save] Quit-button triggered.");
autoSave.run();
playGameController.refresh();
});

// Trigger 2: window close (X-button on the OS window). Catches the
// case where the user closes the app directly instead of going
// back to the menu.
stage.setOnCloseRequest(e -> {
System.out.println("[auto-save] Window close triggered.");
autoSave.run();
});

// Trigger 3: every time the player's money changes (buy / sell).
// This means progress is persisted immediately after each
// transaction, so a save is never more than one action stale.
player.getMoneyAsFloatProperty().addListener((obs, oldVal, newVal) -> {
autoSave.run();
});

// Trigger 4: every time the in-game week advances. Captures price
// history-related state (the saved week is part of the snapshot).
exchange.weekProperty().addListener((obs, oldVal, newVal) -> {
autoSave.run();
});

// Register all views
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ public final class GameStateLoader
* */
private SaveGame activeSave;

/**
* Flag set while {@link #applySave} is running.
*
* <p>
* The apply-save flow mutates player money and the exchange week,
* both of which fire JavaFX property change events. The auto-save
* listeners hooked up in {@code Main} react to those events, so
* without this flag they would write the half-loaded state back to
* disk in the middle of a load. Auto-save callers check this via
* {@link #isLoading()} and skip while it is {@code true}.
* </p>
* */
private boolean loading;

/**
* Constructor.
*
Expand Down Expand Up @@ -123,6 +137,21 @@ public SaveGame getActiveSave() {
return activeSave;
}

/**
* Returns whether a save-load is currently in progress.
*
* <p>
* Used by the auto-save flow to suppress writes during {@link #applySave},
* since money and week mutations there fire JavaFX property change
* events that auto-save listens to.
* </p>
*
* @return {@code true} while {@link #applySave} is running.
* */
public boolean isLoading() {
return loading;
}

/**
* Builds a fresh {@link SaveGame} snapshot of the current player
* and exchange state, using the active save's name and starting
Expand Down Expand Up @@ -212,79 +241,84 @@ private void applySave(final SaveGame save) {
+ ", shares=" + save.getOwnedShares().size()
+ ", txns=" + save.getTransactions().size());

// 1. Roll the exchange's prices back to the captured baseline and
// the exchange's week back to 1, so the simulation starts
// fresh.
exchange.resetStocksTo(baselinePrices);
exchange.setWeek(1);
loading = true;
try {
// 1. Roll the exchange's prices back to the captured baseline and
// the exchange's week back to 1, so the simulation starts
// fresh.
exchange.resetStocksTo(baselinePrices);
exchange.setWeek(1);

// 2. Reset the player to an empty state with the saved starting
// capital. We use starting capital here (rather than the
// final saved balance) so the per-week net-worth samples
// collected by widget listeners during the advances below
// have a meaningful baseline.
Portfolio portfolio = player.getPortfolio();
portfolio.clear();
TransactionArchive archive = player.getTransactionArchive();
archive.clear();
player.setMoney(BigDecimal.valueOf(save.getStartingCapital()));
player.refreshProperties();
// 2. Reset the player to an empty state with the saved starting
// capital. We use starting capital here (rather than the
// final saved balance) so the per-week net-worth samples
// collected by widget listeners during the advances below
// have a meaningful baseline.
Portfolio portfolio = player.getPortfolio();
portfolio.clear();
TransactionArchive archive = player.getTransactionArchive();
archive.clear();
player.setMoney(BigDecimal.valueOf(save.getStartingCapital()));
player.refreshProperties();

// 3. Advance the exchange (save.getWeek() - 1) times so the
// stock price graphs get a real history, and so widgets that
// track per-week net-worth (the financial summary and the
// stats screen) accumulate chart points via their existing
// weekProperty listeners.
int targetWeek = Math.max(1, save.getWeek());
while (exchange.getWeek() < targetWeek) {
exchange.advance();
}
// 3. Advance the exchange (save.getWeek() - 1) times so the
// stock price graphs get a real history, and so widgets that
// track per-week net-worth (the financial summary and the
// stats screen) accumulate chart points via their existing
// weekProperty listeners.
int targetWeek = Math.max(1, save.getWeek());
while (exchange.getWeek() < targetWeek) {
exchange.advance();
}

// 4. Re-apply the saved owned shares (skipping unknown symbols
// instead of throwing - keeps the load robust against stock
// files that have diverged from the save).
for (OwnedShareData od : save.getOwnedShares()) {
if (!exchange.hasStock(od.getSymbol())) {
System.err.println("Skipping unknown stock from save: "
+ od.getSymbol());
continue;
// 4. Re-apply the saved owned shares (skipping unknown symbols
// instead of throwing - keeps the load robust against stock
// files that have diverged from the save).
for (OwnedShareData od : save.getOwnedShares()) {
if (!exchange.hasStock(od.getSymbol())) {
System.err.println("Skipping unknown stock from save: "
+ od.getSymbol());
continue;
}
Stock stock = exchange.getStock(od.getSymbol());
portfolio.addShare(new Share(
stock, od.getQuantity(), od.getPurchasePrice()));
}
Stock stock = exchange.getStock(od.getSymbol());
portfolio.addShare(new Share(
stock, od.getQuantity(), od.getPurchasePrice()));
}

// 5. Re-apply the saved transactions. We rebuild the original
// Purchase / Sale objects (with their share + calculator)
// directly into the archive, rather than re-running them
// through the player's transaction handler, so the player's
// balance is not mutated again here.
for (TransactionData td : save.getTransactions()) {
if (!exchange.hasStock(td.getSymbol())) {
System.err.println("Skipping transaction with unknown stock: "
+ td.getSymbol());
continue;
// 5. Re-apply the saved transactions. We rebuild the original
// Purchase / Sale objects (with their share + calculator)
// directly into the archive, rather than re-running them
// through the player's transaction handler, so the player's
// balance is not mutated again here.
for (TransactionData td : save.getTransactions()) {
if (!exchange.hasStock(td.getSymbol())) {
System.err.println("Skipping transaction with unknown stock: "
+ td.getSymbol());
continue;
}
Stock stock = exchange.getStock(td.getSymbol());
Share share = new Share(stock, td.getQuantity(), td.getPrice());
TransactionCalculator calculator = (td.getType() == TransactionType.SALE)
? new SaleCalculator(share)
: new PurchaseCalculator(share);
Transaction transaction = (td.getType() == TransactionType.SALE)
? new Sale(share, td.getWeek(), calculator)
: new Purchase(share, td.getWeek(), calculator);
archive.add(transaction);
}
Stock stock = exchange.getStock(td.getSymbol());
Share share = new Share(stock, td.getQuantity(), td.getPrice());
TransactionCalculator calculator = (td.getType() == TransactionType.SALE)
? new SaleCalculator(share)
: new PurchaseCalculator(share);
Transaction transaction = (td.getType() == TransactionType.SALE)
? new Sale(share, td.getWeek(), calculator)
: new Purchase(share, td.getWeek(), calculator);
archive.add(transaction);
}

// 6. Overwrite the balance with the saved value now that the
// history has been built up.
player.setMoney(BigDecimal.valueOf(save.getBalance()));
// 6. Overwrite the balance with the saved value now that the
// history has been built up.
player.setMoney(BigDecimal.valueOf(save.getBalance()));

// 7. Re-publish the float properties so the final loaded
// balance is visible to all listeners.
player.refreshProperties();
// 7. Re-publish the float properties so the final loaded
// balance is visible to all listeners.
player.refreshProperties();

this.activeSave = save;
this.activeSave = save;
} finally {
loading = false;
}
}

/**
Expand Down
6 changes: 0 additions & 6 deletions src/main/resources/saves/Halleluja.json

This file was deleted.

24 changes: 11 additions & 13 deletions src/main/resources/saves/Newbie.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
{
"name": "Newbie",
"balance": 388.6825,
"balance": 134.5153,
"startingCapital": 10000.0,
"stockDataPath": null,
"week": 5,
"week": 27,
"ownedShares": [
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 },
{ "symbol": "NVDA", "quantity": 5.0, "purchasePrice": 191.27 }
{ "symbol": "NVDA", "quantity": 50.0, "purchasePrice": 191.27 }
],
"transactions": [
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 },
Expand All @@ -26,6 +17,13 @@
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 }
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 5.0, "price": 191.27, "week": 1 },
{ "type": "SALE", "symbol": "NVDA", "quantity": 14.0, "price": 174.30, "week": 18 },
{ "type": "SALE", "symbol": "NVDA", "quantity": 14.0, "price": 174.30, "week": 18 },
{ "type": "SALE", "symbol": "NVDA", "quantity": 14.0, "price": 174.30, "week": 18 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 17.0, "price": 177.72, "week": 18 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 17.0, "price": 177.72, "week": 18 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 7.0, "price": 177.72, "week": 18 },
{ "type": "PURCHASE", "symbol": "NVDA", "quantity": 1.0, "price": 177.72, "week": 18 }
]
}
43 changes: 0 additions & 43 deletions src/main/resources/saves/Tommy.json

This file was deleted.

0 comments on commit 06707aa

Please sign in to comment.