### Head did not change in the animation menu
- `updateAnimationFrame` changed the inventory on the server side but the client never received the update.
- Added `player.updateInventory()` after each slot modification to force sending to the client.
### Negative or zero bets allowed
- A player could enter a negative or zero bet, bypassing the min/max check.
- Added a `bet <= 0` check in `GuiListener` (CREATE_GAME), `CoinFlipCommand` (create, private).
- New message `commands.invalid-bet` added in `messages.yml`.
### Double debit of the loser
-
`finishGame` still withdrew the loser's stake even though it was already debited at the join.
- Removed `EconomyUtils.withdraw(loser)` in `finishGame` — only the winner receives the pot.
### Formatting amounts according to `number-formatting.mode`
- All amounts displayed in messages and GUIs used `String.
valueOf((long) amount)` without any formatting.
- Redesigned `MessageUtils.formatNumber` with 3 modes:
- **Mode 0**: comma separator — `1,000,000` (pattern configurable via `formatted`)
- **Mode 1**: short format — `1k`, `10k`, `1M`, `1B`
- **Mode 2**: space separator — `1 000 000`
- Added `ConfigManager.
formatAmount(double)` which reads the mode and pattern from `config.yml` and formats the amount.
- All `%amount%` in `GameManager`, `GuiListener`, `CoinFlipCommand` and `GuiManager` now go through `formatAmount`.
### Automatically add missing keys in config.yml and messages.yml
-
If a key is present in the default file (bundled in the jar) but absent from the server file, it is added automatically at startup and at `/cf reload`.
- Existing values are never overwritten.
- Works recursively for all nested sections.
-
A message is logged in the console when keys are added: `Added missing keys to config.yml`.
- Implemented in `FileManager` via `addMissingKeys()` and `copyMissing()`.
---
#CoinFlips — 6.1.0
## Major additions & fixes
### Folia Compatibility
- New `utils/SchedulerUtils file.
java`: automatically detects at startup whether the server is running on Folia (`RegionizedServer`) or Paper/Spigot.
- Exposes unified methods: `runAsync`, `runAsyncTimer`, `cancelAsyncTimer`, `runLater`, `runLaterForPlayer`, `runTimer`, `cancelTimer`.
- On Paper/Spigot → delegates to the classic `BukkitScheduler`.
-
On Folia → delegates to `AsyncScheduler` (async tasks) and `GlobalRegionScheduler` (sync tasks).
- `GameManager`: rotating animation and game cleaning use `SchedulerUtils.runTimer` / `runLater`. Type `BukkitTask` replaced by `Object` to be agnostic.
- `DiscordWebhook`: sending webhook via `SchedulerUtils.runAsync`.
-
`UpdateChecker`: update check via `SchedulerUtils.runAsync` / `runAsyncTimer` / `cancelAsyncTimer`.
- The plugin now works on **Paper, Spigot and Folia** without changing the business logic.
### Animation — head rotating to the winner
- The animation displayed a static head.
The head now alternates between the creator and the opponent every 4 ticks (~0.2s) for 3 seconds, then freezes on the winner's head for 1 second before displaying the result.
- Added `updateAnimationFrame(Player, String)` in `GuiManager` to change the header in real time in the open inventory.
-
`openAnimationMenu` now accepts `creatorName` and `opponentName` as parameters.
### Checking balance before creating/joining
- A player without enough money could create or join a game without their balance being verified.
- Added `EconomyUtils.hasBalance()` check in `GuiListener` (CREATE_GAME,
JOIN_GAME) and `CoinFlipCommand` (create, join, private).
- The balance is now debited **at creation** of the game (creator) and **at join** (opponent).
- `finishGame` only credits the winner the full amount (stake × multiplier) — no more double debit.
-
`/cf cancel` correctly reimburses the creator since the stake is already debited.
- New message `commands.not-enough-money` added in `messages.yml`.
---
# CoinFlips — 6.0.2
## Minor fixes
### Animation menu opened when joining a coinflip
- When a player joins a game,
`startGame` opened the main menu (`openMainMenu`) instead of the animation menu.
- Added the `openAnimationMenu(Player)` method in `GuiManager` which opens the `animation` GUI defined in `guis.yml` with the `%player%` placeholder.
- `GameManager.startGame()` now uses `openAnimationMenu` + `GuiType.
ANIMATION for both players (creator and opponent) from the start of the game.
---
# CoinFlips — 6.0.1
## Minor fixes
### GUI does not open when accepting a coinflip
- The `startGame` logic did not open any GUI for players, it just sent messages in the chat after a delay
.
- The `startGame` method has been moved to `GameManager` and now opens the main menu for both players (creator and joiner) upon starting the game.
- Both players' inventories are automatically closed once the result is displayed.
-
The `JOIN_GAME` action in `GuiListener` did not call `startGame` after joining the game — fixed.
### Cleaning parts on disconnection
- `PlayerListener` only handled the `PlayerJoinEvent` event, without any processing on disconnection.
- Added a `PlayerQuitEvent` handler which:
- Removes the player from GUI tracking (`GuiTracker`)
- Removes any pending challenges linked to the player
- Cancels the player's game if it is still in `WAITING` state (games already `RUNNING` resolve normally)