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
2 changes: 2 additions & 0 deletions projects/SimpleFactions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Technical documentation is maintained here. Run commands from the source checkou
TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](../../PLATFORM.md) for runtime, build and validation conventions.

- [Overview](overview.md)
- [Character membership and migration](docs/characters.md)
- [Treasuries and financial recovery](docs/treasuries.md)
- [Installation trade and transport access](docs/installation-trade.md)
- [Espionage and special positions](docs/espionage.md)

Expand Down
99 changes: 99 additions & 0 deletions projects/SimpleFactions/docs/characters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Character membership

Membership, leadership, councils, votes, mercenary enrollment and stored member
references use character UUIDs. Two characters played by one Minecraft account
can belong to different guilds, including rival realms. A player without a ready
character session has no membership. Menus capture the opening character session
and close when that session is stale.

## Migration and readiness

SimpleFactions waits for RPCharacters' reviewed legacy heir map and DenarEconomy's
ledger before loading faction state. During that wait commands report startup, timers and persistence
are inactive, and dependent plugins must defer loading or saving faction-owned
state. `SimpleFactionsApi.ready()` reports availability and
`SimpleFactionsReadyEvent` signals startup completion.

`migrations/character-v1.json` records progress for each store. Originals are
backed up under `migrations/backup/`; interrupted writes restore their backup and
replay. Legacy aliases resolving to one heir are merged. Unresolved records keep
their original JSON, role and amounts in quarantine, with stable record IDs.
Unresolved leaders block succession and disbanding.

Staff commands:

```text
/f admin quarantine list
/f admin quarantine assign <recordId> <characterId>
```

Assignments take effect on the next startup. Back up faction data together with
RPCharacters and DenarEconomy data before a coordinated cutover or rollback.

## Plugin APIs

`FactionManager.getByMember`, `getByLeader`, `getGuildByMember` and
`getGuildByLeader` accept a `Player`, a character `UUID`, or a stored member-key
`String`. UUID arguments are character IDs. Nullable lookups cannot distinguish
startup unavailability from absence: check `SimpleFactionsApi.ready()` before
making persistence decisions. Player and UUID lookups are unavailable until
startup recovery completes. The same player and UUID lookups on
`SimpleFactionsApi` return `Optional` values and remain empty until ready.

`Members.key(player)` resolves the active character. `Members.display(key)` is
its display name; `Members.online(key)` resolves only an online player currently
playing that character. Use those helpers instead of passing stored member keys
to Bukkit's account-name lookup methods.

A guild's immutable `getIncarnationId()` identifies its treasury across renames.
`Bank.accountId()` exposes the ledger account name for transactional callers.
Disbanding and recreating a guild with the same name gives it another incarnation.

## Public map data

The nation export uses an explicit public projection. Leader display fields,
member display names and counts, provinces, banners, public relations and guild
branches remain available. Character member keys, account balances, loans,
ledgers, elections, espionage and other private saved state are excluded.

See [the character identity API](../../TLibs/README.md) and
[DenarEconomy](../../DenarEconomy/README.md) for the shared providers.

## Combat identity

Warbands and battle roster IDs remain Minecraft account UUIDs for live combat.
Each enrollment also captures its character reference. Rejoining restores only
that character's former participation; switching characters does not inherit it.
`BattleStartedEvent.getParticipants()` and `BattleEndedEvent.getParticipants()`
return the captured character references, including participants who have since
disconnected. `getParticipantIds()` remains available for account-scoped callers.

## Death and succession

Committed character deaths, startup reconciliation and hourly reconciliation
use the same durable death journal, keyed by RPCharacters' authoritative death
ID. Cleanup removes the deceased character's membership, offices, council and
voting rights, movement participation and captured warband participation. It
also ends a council session hosted by that character. Another character on the
same Minecraft account keeps its own rights.

Cleanup saves each affected faction or warband before acknowledging that step.
Fixed wages and the captured per-member dividend amount become payable claims
only after the original payout rights are durably removed. They survive guild
or faction dissolution and remain payable to the deceased character's bank.
Daily settlement records actual cents paid, including partial payments.

An ordinary guild leader's successor is the first living remaining member in
its original join order. Empty ordinary guilds disband. A completely empty
realm is removed while its ledger treasury remains. If the ruling guild empties
but another guild still has members, the realm and its treasuries remain:
elective governments start the normal election; a nonelective ruler remains
vacant for staff resolution. Unresolved quarantined leaders block succession
and disbanding. A later staff appointment is preserved during replay.

Dead warband leaders pass leadership to the captured first living participant,
or leave a vacant seat when none is available. Pending rejoin records still
identify the deceased character if its session ended before the death event.

See [treasury recovery](treasuries.md) for journal paths and coordinated backup
requirements.
137 changes: 137 additions & 0 deletions projects/SimpleFactions/docs/treasuries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Treasuries and financial recovery

SimpleFactions uses DenarEconomy's ledger for guild money. Each guild incarnation
has a `guild:<incarnation UUID>` account; its location and display name do not
identify its money. Recreating a disbanded guild gives it a different account.
`Bank.getWealth()` is a read-only denar view. Guild debt remains signed, and
moving or removing a bank does not transfer its balance.

Legacy treasury balances and accumulated citizen tax are imported once using
`import-guild:<incarnation>` and `import-tax:<incarnation>` operation IDs.
Citizen tax is withheld inside the earning transaction and credited to
`guildtax:<incarnation>`. SimpleFactions registers its tax policy only after
startup recovery completes. Consumers must defer taxable transactions while
that policy is unavailable.

## Daily settlement

The day counter tracks server uptime, rather than calendar dates. One balanced
posting, `sf:settle:<day>`, covers every realm's daily money movements. The
stored plan includes all cents, account IDs and resulting financial state;
recovery never recalculates a published plan.

Preparation records the calculation timestamp, upkeep decisions and the selected
province losses before applying nonfinancial changes. It then records exact
movement organization and offline-day values. Recovery finishes this same
prepared day before allowing new gameplay or death reconciliation.

The settlement preserves the order of army and installation upkeep, trade and
other income, inter-guild transfers, liquidation, dividends and wages, loan
and contract updates, and finally vehicle upkeep. Army upkeep can preserve debt.
Unaffordable installation upkeep downgrades or removes the installation without
charging it. Vehicle upkeep requires the full projected amount, including any
tax; insufficient funds leave the balance intact and record unpaid maintenance.
Personal vehicle payers are captured character IDs.

Available payout funds are shared between dividends and wages. Unpaid wages and
fixed claims owed to deceased characters remain owed. Death dividend claims
reserve part of the dividend pool before living members receive their shares;
they do not add another copy of that payout. Claims against a disbanded guild
can still use its preserved incarnation treasury.

All monetary legs post together. Only an `APPLIED` result permits the recorded
branch levels, loan balances, histories, maintenance state and payment receipts
to be saved. A failed save stops faction gameplay until recovery. The completed
day clock is persisted with these effects; a restart cannot pay that day twice.

## Other financial actions

Deposits, withdrawals, staff `addguildbank`, branch changes, loan acceptance and
repayment, mercenary formation, capital changes, relocation and pillage use
durable operation intents. They capture the actor's character session and the
participating guild incarnations. Confirmations cannot act for a new character
or a replacement guild.

Loan offer IDs are paid once. An offer book records the lending guild's
incarnation; books written before that binding existed, or whose lending guild
has been deleted and recreated under the same ID, are rejected as out of date
and the lender must issue a new agreement. Principal acceptance and its debt record recover
together. Manual repayments credit the lender directly and persist exact debt
and credit-score changes; they do not create another daily receipt. Pillage
uses the war identity and attacker incarnation to recover the same loot and
penalties. Capital and relocation recovery also repairs an interrupted change
across faction files before those files are loaded into domain objects.

Material deposits credit the captured character's bank and actual citizen tax
holding account in one posting. Materials are removed only after `APPLIED`.
Staff physical coin withdrawals record the proposed inventory change before
posting. An interrupted material removal or coin delivery requires staff
reconciliation: recovery does not repeat physical delivery automatically.

Games casino profit bookkeeping has its own durable intent. The money has
already reached the guild treasury; this records its taxable income once.
Startup finishes an incomplete bookkeeping save before daily settlement. An
exact retry after the profit has been settled does not tax it again.

## Vehicle finance

Vehicle payments use the selected living character. Construction and
maintenance capture a character session; handovers capture both participants,
so switching characters cannot redirect an armed payment. `Cache/vehicles_registry.json`
keeps PERSONAL records whose `playerUuid` is the payer character UUID; personal
daily upkeep and vehicle tax charge only that recorded payer, never the
account's current character. VehicleFramework owner tags still describe
physical ownership and are not migrated to characters.

On the first startup with VehicleFramework enabled, `identity/vehicle-payers.json`
records every player-owned vehicle from VehicleFramework's persisted
repository, mapping the account to its legacy heir character. Existing registry
records win, the plan is saved before the registry changes, and it never
reinterprets later owner-tag changes. Unresolved owners keep a null payer and
stay unpaid; there is no in-game command to reassign them, and the completed
plan must not be deleted to force a new mapping.

Fees, refunds and maintenance use durable intents in `vehicle-payments/`,
recovered at startup before realm settlement. `Cache/vehicle_fees.json` holds
outstanding build, claim and handover receipts; an unfinished receipt blocks
new ownership payments for its vehicle and leaves its daily upkeep unpaid,
rather than charging the previous payer. A construction refund pays the
originally captured character from the original guild incarnation, limited to
the treasury's positive balance. Maintenance explicitly selects bank or pouch
and never falls back to the other. Daily vehicle charges run last inside the
single `sf:settle:<day>` posting, as described above.

## Saved recovery state

Paths are relative to `plugins/SimpleFactions/`:

| Path | Purpose |
| --- | --- |
| `day-preparation/<day>.json` | Captured timestamp and nonfinancial day preparation |
| `settlements/<day>.json` | Immutable realm posting and exact financial after-values |
| `economy/callers/` | Interactive treasury and topology operation intents |
| `external-income/` | Idempotent external casino income bookkeeping |
| `deaths/` | Death cleanup, succession and outstanding character claims |
| `deaths/payments/` | Settlement acknowledgments for those claims |
| `vehicle-payments/` | Vehicle fee, refund and maintenance intents |
| `identity/vehicle-payers.json` | One-time legacy vehicle payer migration plan |
| `Cache/vehicles_registry.json` | Vehicle ownership scopes and personal payer characters |
| `Cache/vehicle_fees.json` | Outstanding vehicle payment receipts and owner history |
| `Cache/vehicle_maintenance.json` | Vehicle upkeep and unpaid maintenance state |

An intent is forced to storage before its dependent action. Completed intents
and receipts are financial history, not disposable retry files. Restoring a
completed receipt without its corresponding DenarEconomy posting is rejected.

For an unresolved operation, retain its file, operation ID and matching ledger
status. For physical items, also inspect the captured character, inventory
snapshot, item bytes and amount. There is no command to discard an ambiguous
physical intent. Correct the underlying persistence or data problem, reconcile
physical evidence where necessary, and restart to resume the saved intent.

Back up or roll back SimpleFactions, RPCharacters and DenarEconomy together using
a consistent stopped-server copy. Do not combine an old ledger with newer
faction journals or delete receipts to force another payment.

See [character membership](characters.md) and the shared
[DenarEconomy guide](../../DenarEconomy/README.md).