Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions projects/Games/docs/GUILD_TABLES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Guild-house tables connect blackjack operation to guild permissions, auto-dealer

Bank money reaches the felt only through `BankAccount`, as a leg of a wager transaction. See [WAGER_ENGINE.md](WAGER_ENGINE.md).

Games **softdepends SimpleFactions** and may call guild / bank / modifiers. SimpleFactions **does not** import Games, persist table ids, or listen to table events. **No Bukkit events** for create, dealer, or bank.
Games requires DenarEconomy and **softdepends SimpleFactions** for guild identity, modifiers and profit bookkeeping. SimpleFactions **does not** import Games, persist table ids, or listen to table events. **No Bukkit events** for create, dealer, or bank.

## Modes

Expand All @@ -26,21 +26,26 @@ Staff auto needs `games.autodealer.staff`. It is not the default for a normal pl
On place, store:

- `ownerPlayer` (placer UUID)
- `ownerGuildId` (guild id at place time, or null if no SF / no guild)
- `ownerGuildId` (guild id at place time, or null for a personal table)
- `ownerGuildIncarnation` (the owning guild's permanent UUID)

Cap and bank always use **that guild id**, not "whoever is standing here." Re-resolve the guild object on cover / pickup. If the guild is gone: refuse auto cover, and on pickup skip bank deposit (chips still despawn / given per existing teardown).
Guild membership and leadership use the active character. Editing or picking up a guild table requires that character to lead the captured guild incarnation, or staff permission. The placer account alone gives no guild-table rights. The account remains the host of a personal table.

The captured incarnation selects the `guild:<uuid>` Denars account. A deleted guild's later namesake cannot use its tables, bank or expansion slots. Missing guilds, unavailable faction services and unresolved incarnations refuse funding; tray settlement retains the table and chips for review instead of dropping money through a failure fallback.

Existing guild tables wait for `SimpleFactionsApi.ready()`. Migration preserves each original JSON file in `migrations/guild-tables/backup/` and writes a complete migration plan before applying it. Each table resolves its guild id once. Restart reuses that plan; an unresolved guild remains unresolved even if a namesake appears later. Deferred loads retry every five seconds without reloading already active tables.

## Cap

SF `GuildModifier.AUTO_DEALER_TABLES` from an **expansion upgrade** (not a branch). `allowed-types`: `guild` and `realm`. Stacks with upgrade level via existing `Guild.getModifier`.

A table counts against the cap if `autoDealer && !staffMint` and `ownerGuildId` matches.
A non-staff guild table counts against the cap when its guild id and captured incarnation match the current guild.

Refuse (do not place, or do not turn auto on) when `count >= cap`. Cap `0` means guild auto is off. Missing SF: guild auto off; staff mint still works.

If upgrades drop so `count > cap`, **do not** pick up tables or cancel a live round. Every counted table of that guild **cannot start a new round** until `count <= cap` (turn auto off or pick up extras). A bet window that was already open refunds and does not deal.

Toggling auto **off** frees the slot immediately. Human takeover of a guild-auto table (between rounds) does the same.
Human takeover changes who deals; guild ownership and its slot remain.

## House float (any backed table)

Expand All @@ -49,11 +54,11 @@ No "please top up" wait. Cover is withdraw-or-refuse.
1. During the bet window, after a legal chip-in, `need = max(0, action - tray)`. Only auto tables run a bet window, so on a human-dealt table the round reserve at step 5 is the only cover step.
2. If `need == 0`, do nothing.
3. Staff auto: spawn `need` (today).
4. Guild auto: if bank wealth `< need` or bankrupt / no bank, **do not accept that chip-in** (restore item, message). Else `withdraw(need)`, spawn on tray.
4. Guild auto: if bank wealth `< need` or bankrupt / no bank, **do not accept that chip-in** (restore item, message). Else post the guild debit through Denars, then materialize the planned chips on the tray.
5. When bets close, blackjack reserves the round's worst case: `sum(boxStake) * max-hands-per-box * 2`, rounded up to a whole coin. Withdraw-or-refuse again, but at round scope: if the bank cannot supply it the round does not start and every box is refunded. Splits and doubles inside the round then take their cover from the reserve and never touch the bank. `closeBets` is the gate for both modes: the bet timer calls it on auto tables, and a human dealer reaches it with `/games bet close`, which is also the only way their round starts.
6. Player wins peel the tray. The settle shortfall path still exists but the reserve should make it unreachable, so it logs a mismatch when `wager.audit-log` is on.
7. Round end (settled or abandoned): the whole tray `deposit`s back to the owning guild bank, so the float is zero between rounds and house wins are banked each round rather than piling up as chips. Staff mint burns it. A table with no guild returns the float to its dealer instead.
8. Pickup / teardown: any remaining tray on a backed table `deposit`s to the owning guild bank; if that guild is gone, drop the tray items. Staff mint tray is despawned, not dropped. Player pots still drop.
8. Pickup / teardown: any remaining tray on a backed table `deposit`s to the owning guild bank; if the guild or posting is unavailable, retain the table and tray for review. Staff mint tray is despawned, not dropped. Player pots still drop.

A guild running several tables shares one bank, so reserving per round is also what stops two tables from both counting the same denars.

Expand All @@ -73,7 +78,7 @@ Right-click shoe (existing claim path):

- Already this player: **unset** dealer.
- Empty seat, human table: **set** if the player is in `ownerGuildId` (or staff). No guild on the table: placer / staff only.
- Guild auto, between rounds: **takeover** - become human dealer, `autoDealer=false`, tray stays, slot freed.
- Guild auto, between rounds: **takeover** - become human dealer, `autoDealer=false`, tray and guild ownership stay.
- Staff auto: guild members **cannot** takeover. Staff can turn mint off from options (when not live) or pick up the table.

Leave-distance still does not clear dealer. Logout / pickup still does (existing).
Expand Down Expand Up @@ -101,6 +106,6 @@ Default `SHOE`. Engine stays dumb; blackjack asks the table for policy.

## Isolation

One Games class (same idea as `RpNames`): plugin present + enabled, then `FactionManager` / `Guild` / `Bank`. Catch `LinkageError`. Do not scatter SF types through `BlackjackGame`.
Guild access checks plugin presence, enabled state and `SimpleFactionsApi.ready()` before character membership and incarnation lookups. Errors fail closed. Denars owns money posting; SimpleFactions only reads identity/modifiers and records idempotent casino profit. New rounds wait for `Denars.taxReady()`.

SimpleFactions integration: `GuildModifier` entry + `upgrades.yml` row. No Games dependency in SF `pom` / `plugin.yml`.
2 changes: 1 addition & 1 deletion projects/Games/docs/HOLDEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@ Play:
- Each hand collects the ante from every seat as dead money, then posts the blinds. With a blind interval above `0`, blinds double every interval after the first hand, and each new level is collected from the next hand dealt; `0` keeps them fixed.
- `call` takes the chips needed to match automatically; a short stack goes all in. Players with no chips sit out until they rebuy.
- Leaving or being kicked before the first hand refunds the buy-in. After play starts it forfeits the entry.
- When Games is disabled (server stop or plugin reload), tables reset to idle: tournaments end, Denar stakes still on the table return to their owners through the table's refund path (dropped at the table for offline owners), and chip stacks are cleared. Tournament settings persist.
- When Games is disabled (server stop or plugin reload), settled tables reset to idle: tournaments end, Denar stakes still on the table return to their owners through the table's refund path (dropped at the table for offline owners), and chip stacks are cleared. Tournament settings persist. Tables with unresolved identity or money operations remain frozen for review; see [wager recovery](WAGER_ENGINE.md#character-ownership-and-recovery).
6 changes: 3 additions & 3 deletions projects/Games/docs/SYSTEM.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Tabletop plugin. Engines are dumb: they cannot tell poker from blackjack. Games only call engines.

Games provides blackjack, [Tenceur Hold'em](HOLDEM.md) (`poker`) and [Five-Draw](FIVEDRAW.md) (`draw`). Tables persist locations and house settings; stopping or restarting the plugin resets sessions to idle.
Games provides blackjack, [Tenceur Hold'em](HOLDEM.md) (`poker`) and [Five-Draw](FIVEDRAW.md) (`draw`). Tables persist locations and house settings; stopping or restarting resets settled sessions to idle; unresolved money operations retain frozen tables for review.


## Config folder layout
Expand Down Expand Up @@ -106,9 +106,9 @@ Ace file and IA id is `_1` or `1`, not 14. Ace-high ranking is a poker flag, not

## Dependencies

`TLibs`, `ItemsAdder`, `ProtocolLib`. DenarEconomy softdepend (wager). RPCharacters softdepend (character names and voice). SimpleFactions softdepend (guild auto cap + bank; [GUILD_TABLES.md](GUILD_TABLES.md)). SF does not depend on Games.
`TLibs`, `ItemsAdder`, `ProtocolLib` and `DenarEconomy` are required. RPCharacters softdepend (character names and voice). SimpleFactions softdepend (guild auto cap + bank; [GUILD_TABLES.md](GUILD_TABLES.md)). SF does not depend on Games.

The build pins TLibs **2.3.0** and RPCharacters **2.16.0**. Names use the shared
The build pins TLibs **2.4.0**, DenarEconomy **0.3.0**, SimpleFactions **4.0.0** and RPCharacters **2.16.0**. Names use the shared
character identity service; voice still uses RPCharacters' chat API. Deploy the
pinned providers with Games and restart to activate them.

Expand Down
13 changes: 12 additions & 1 deletion projects/Games/docs/TEST_MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ See [BLACKJACK.md](BLACKJACK.md).
- [ ] 3:2 natural, double, split, DAS
- [ ] Auto: 10s after first min bet, spawn pays
- [ ] Voice via RPCharacters `dispatch`, not `/rp` command
- [ ] With TLibs 2.3.0 and RPCharacters 2.16.0, table labels and game messages show the current mask/alias; changing it or switching characters updates the next rendered name without revealing a canonical name
- [ ] With TLibs 2.4.0 and RPCharacters 2.16.0, table labels and game messages show the current mask/alias; changing it or switching characters updates the next rendered name without revealing a canonical name
- [ ] An online player with no active character shows the RPCharacters no-character label (`Unknown` by default), matching chat
- [ ] Without the character provider, online labels use account names; offline names use the last known account name or `-`; gameplay and wagers still work

Expand All @@ -126,3 +126,14 @@ See [GUILD_TABLES.md](GUILD_TABLES.md).
- [ ] Guild cover withdraws shortfall only; empty bank restores the chip; pickup deposits tray
- [ ] Dealer: guild member set/unset; no mid-round; takeover auto frees slot; no takeover of staff mint
- [ ] Shuffle `ROUND` vs `SHOE` matches policy after a full round

## Ledger and identity failure checks

- [ ] While installed SimpleFactions is waiting, new rounds and guild migration stay closed; readiness permits them without restarting Games.
- [ ] Switching characters on one account cannot collect or edit the other character's guild table/stakes; a later settled round can bind the new character.
- [ ] A deleted guild's namesake cannot claim the old table or bank, including after restarting migration.
- [ ] A bank-funded win and its actual withheld chip tax produce one balanced Denars posting; refused posting changes no items, float or casino profit.
- [ ] After a posting, interrupt table save or profit bookkeeping; restart retains a frozen table and intent without delivering money/items again.
- [ ] Missing winning character, mid-round tax failure and partial payout retain the remaining obligation and prevent round clear/pickup.

Run automated checks with `tfmc-mvn -o -B --no-transfer-progress clean verify`. Journal tests inject posting, storage and bookkeeping failures; they do not prove atomic Minecraft inventory persistence or replace server integration checks.
Loading