From 54b294848e3c9a04f14b685f77dedc231da6e1f9 Mon Sep 17 00:00:00 2001 From: Ryan Barlow <7389646+ryanbarlow97@users.noreply.github.com> Date: Wed, 23 Sep 2026 11:20:58 +0000 Subject: [PATCH] docs: add Gathering, Infestations, Research and TrialRooms guides Add project indexes and behaviour guides for the four newly published plugins, list them in the project index, and add their build targets to the platform matrix. The guides describe current source behaviour; the batch plans and review notes that shipped with the plugins are not kept. Co-Authored-By: Claude Opus 5.5 (1M context) --- PLATFORM.md | 4 + README.md | 4 + projects/Gathering/README.md | 28 +++++ projects/Gathering/overview.md | 107 +++++++++++++++++++ projects/Infestations/README.md | 30 ++++++ projects/Infestations/overview.md | 160 +++++++++++++++++++++++++++ projects/Research/README.md | 30 ++++++ projects/Research/overview.md | 172 ++++++++++++++++++++++++++++++ projects/TrialRooms/README.md | 28 +++++ projects/TrialRooms/overview.md | 148 +++++++++++++++++++++++++ 10 files changed, 711 insertions(+) create mode 100644 projects/Gathering/README.md create mode 100644 projects/Gathering/overview.md create mode 100644 projects/Infestations/README.md create mode 100644 projects/Infestations/overview.md create mode 100644 projects/Research/README.md create mode 100644 projects/Research/overview.md create mode 100644 projects/TrialRooms/README.md create mode 100644 projects/TrialRooms/overview.md diff --git a/PLATFORM.md b/PLATFORM.md index 115d3e7..fcf2c36 100644 --- a/PLATFORM.md +++ b/PLATFORM.md @@ -84,10 +84,12 @@ consumer set. Source builds must pass clean verification before publication. | [DrinkBuilder](projects/DrinkBuilder/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Dowsing](projects/Dowsing/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Games](projects/Games/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | +| [Gathering](projects/Gathering/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [GeigerCounters](projects/GeigerCounters/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [GemInfusion](projects/GemInfusion/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Goldsmithing](projects/Goldsmithing/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [GunsAndGadgets](projects/GunsAndGadgets/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | +| [Infestations](projects/Infestations/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [InteractibleFurniture](projects/InteractibleFurniture/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Magic](projects/Magic/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [MarketBlock](projects/MarketBlock/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | @@ -96,6 +98,7 @@ consumer set. Source builds must pass clean verification before publication. | [PermCleaner](projects/PermCleaner/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [PointShop](projects/PointShop/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Recycler](projects/Recycler/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | +| [Research](projects/Research/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [RPCharacters](projects/RPCharacters/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [SimpleFactions](projects/SimpleFactions/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Surgery](projects/Surgery/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | @@ -103,6 +106,7 @@ consumer set. Source builds must pass clean verification before publication. | [TFMCWeb](projects/TFMCWeb/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Thievery](projects/Thievery/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [TLibs](projects/TLibs/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | +| [TrialRooms](projects/TrialRooms/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [VehicleFramework](projects/VehicleFramework/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [VFBuilders](projects/VFBuilders/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | | [Woodworking](projects/Woodworking/README.md) | 21 | `paper-api` | `1.21.10-R0.1-SNAPSHOT` | diff --git a/README.md b/README.md index dc28bb3..8c79aca 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,9 @@ Choose a project to open its technical documentation and source repository link. | [Archaeo](projects/Archaeo/README.md) | Archaeology, hidden ruins, excavation, and fragile finds. | | [Cooking](projects/Cooking/README.md) | Interactive cooking stations and custom food crafting. | | [Dowsing](projects/Dowsing/README.md) | Resource nodes, production chains, and faction-based gathering. | +| [Gathering](projects/Gathering/README.md) | Hidden gathering spots, character discovery, and weighted harvest drops. | | [GemInfusion](projects/GemInfusion/README.md) | Gem infusion and jewellery crafting mechanics. | +| [Research](projects/Research/README.md) | Research stations, item experiments, and hidden-recipe discovery. | | [Woodworking](projects/Woodworking/README.md) | Woodworking stations, crafting projects, and material quality. | ### Roleplay and activities @@ -67,7 +69,9 @@ Choose a project to open its technical documentation and source repository link. | Project | What it does | | --- | --- | | [GunsAndGadgets](projects/GunsAndGadgets/README.md) | Configurable firearms, ammunition, and gadgets. | +| [Infestations](projects/Infestations/README.md) | Province infestations, ambient monsters, and lure raids. | | [SimpleFactions](projects/SimpleFactions/README.md) | Nations, diplomacy, taxation, and ProvinceSystem map integration. | +| [TrialRooms](projects/TrialRooms/README.md) | Keyed dungeon rooms, levelled MythicMobs encounters, and rarity-rolled loot. | | [VehicleFramework](projects/VehicleFramework/README.md) | Configurable vehicles, movement physics, turrets, and weapons. | | [VFBuilders](projects/VFBuilders/README.md) | Vehicle construction stations and blueprints for VehicleFramework. | | [WorldBorder](projects/WorldBorder/README.md) | Configurable world borders, player warnings, and border damage. | diff --git a/projects/Gathering/README.md b/projects/Gathering/README.md new file mode 100644 index 0000000..0eca670 --- /dev/null +++ b/projects/Gathering/README.md @@ -0,0 +1,28 @@ +# Gathering + +[Source repository](https://github.com/TF-Minecraft/Gathering) · [All projects](../../README.md) + +Hidden world gathering spots that roleplay characters discover and harvest for weighted drops. + +TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](../../PLATFORM.md) for runtime, build and validation conventions. + +## Build and dependencies + +Gathering builds with Java **21** against +`io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT`. Install the pinned TLibs +`2.0.1` and RPCharacters `2.0.2` release artifacts with the shared dependency +installer. The build also prepares checksum-verified MMOCore `1.13.1` and +MythicLib `1.7` inputs from the private ServerAssets repository. + +At runtime, `plugin.yml` requires TLibs and RPCharacters. MMOCore is optional; +the profession bonus to discovery chance is only applied when that plugin is +enabled. MythicLib is a compile input only and is not declared in `plugin.yml`. + +## Guides + +- [Behaviour, configuration, and operations](overview.md) + +## Builds and releases + +See the [shared pipeline guide](../../PIPELINES.md) for development artifacts, +release tags, private dependency access, and release verification. diff --git a/projects/Gathering/overview.md b/projects/Gathering/overview.md new file mode 100644 index 0000000..20da458 --- /dev/null +++ b/projects/Gathering/overview.md @@ -0,0 +1,107 @@ +# Behaviour, configuration, and operations + +[Gathering documentation](README.md) · [All projects](../../README.md) + +## System model + +Gathering places invisible spots on existing surface blocks. A spot records its +world, block position, spot type, surface material, and the RPCharacters +characters that have discovered it. Each chunk holds at most one active spot. +Spots do not expire; a spot stays in place until someone gathers it. + +Every `spawn-interval-minutes`, the scheduler makes up to +`spawn-attempts-per-tick` attempts in each configured world. Each attempt picks a +random spot type that is below its `max-active` limit and outside its +`cooldown-minutes` spawn cooldown. It then picks a random chunk within that +world's bounds and skips it if the chunk already holds a spot, is on cooldown, or +is excluded. Otherwise, the chunk is loaded and up to `probe-column-attempts` +random columns are scanned from the top down. The first block that is solid, has +two air blocks above it, and matches the type's surface block, altitude, and +biome filters becomes the spot. This can be below the open surface, such as on +a cave floor. If no column matches, the chunk is excluded for every spot type. + +## Configuration files + +The plugin copies its defaults into `plugins/Gathering/` on first start. + +| File | Purpose | +| --- | --- | +| `config.yml` | Spawn interval, attempts, column probes, chunk cooldown, per-world chunk bounds (`worlds..chunk-x-min` and so on), passive discovery, attribute and profession weights, particle ring, and gather effects. | +| `categories.yml` | Named drop categories. Each is a `drops` list (or a bare list) of ` - ` lines. | +| `spot-types.yml` | Spot types with optional `biome` list, `altitude-min`, `altitude-max`, `spawn-block`, and `particle-dust`, plus `max-active`, `cooldown-minutes`, `profession-id`, and weighted `categories` entries (`id`, `weight`, and `drops` as `N` or `min-max` rolls). | + +Item paths are resolved through TLibs, so they use the prefixes understood by +TLibs and the installed item providers. Biomes use Minecraft biome keys, and +blocks use Bukkit material names. Unknown biomes, materials, and malformed drop +lines are logged and skipped. Category references are not checked at load time. + +Run `/gathering reload` after editing these files. Reloading re-reads all three +files but does not restart the scheduled tasks, so changes to +`spawn-interval-minutes`, `passive-discovery.interval-seconds`, and +`particles.interval-ticks` only apply after a restart. Existing spots keep their +spot type identifier. + +## Discovery and gathering + +Only players with an active RPCharacters character take part. When +`passive-discovery.enabled` is true, every `interval-seconds` the plugin rolls +once for each undiscovered spot within `radius` blocks of each such player. The +chance is `base-chance` plus wisdom × `wisdom-weight`, intelligence × +`intelligence-weight`, and, when `profession.enabled` is true and MMOCore is +enabled, the profession level × `level-weight`. The chance is capped at 100%. The +profession is the spot type's `profession-id`, or `profession.id` when that is +not set. On success, the character is recorded against the spot and receives the +configured message. + +Discovered spots within 32 blocks (or `radius`, if larger) show a two-particle +ring coloured by `particle-dust` or the surface block. Right-clicking the spot's +block with the main hand gathers it. The plugin chooses one weighted category, +rolls the configured number of drops from it, and pops the items out of the spot. +Harvesting a spot removes it and puts its chunk on cooldown for +`chunk-cooldown-minutes`. If nothing can be rolled, the player sees "Nothing to +gather here." and the spot remains. Interactions already cancelled by another +plugin are ignored. + +## Commands and permissions + +All subcommands require `gathering.admin`, which defaults to operators. + +| Command | Effect | +| --- | --- | +| `/gathering reload` | Reload `config.yml`, `categories.yml`, and `spot-types.yml`. | +| `/gathering status` | Show active spots, excluded chunks, and chunks on cooldown. | +| `/gathering clearcache [world]` | Clear excluded chunks for one world, or for all worlds. | +| `/gathering forcespawn [chunkX chunkZ]` | Probe the player's current chunk, or the given chunk in the player's world, for the type. This ignores world bounds, `max-active`, and cooldowns. A failed probe excludes the chunk. | +| `/gathering adminmode [on\|off]` | Toggle or set admin mode. Admin mode shows every nearby spot with an extra marker and allows gathering without a discovery or character. | + +Admin mode is held in memory and ends when the player leaves or the server stops. + +## Persistence and shutdown + +- Active spots and their character discoveries are stored in + `plugins/Gathering/Data/spots.json`. +- Chunk cooldowns and excluded chunks, with reasons, are stored in + `plugins/Gathering/Data/chunk-cache.json`. + +Changed state is written every 60 seconds and again on a normal plugin disable. +The per-type spawn cooldown is held in memory only and resets on restart. Back up +the complete `plugins/Gathering/` directory before renaming spot types or +migrating configuration, and stop the server cleanly before copying live state. + +## Validation + +For a server-side change, verify the following on Paper 1.21.10 with the pinned +dependency set: + +1. Start with both an empty data directory and a copy of representative existing + spot and chunk-cache data. +2. Confirm all definitions load without unknown biome, material, drop-line, or + item-path warnings. +3. Force-spawn each spot type, and confirm scheduled spawning respects world + bounds, `max-active`, type cooldowns, and chunk cooldowns. +4. Discover a spot with a character, with and without MMOCore, and confirm only + that character sees the particle ring. +5. Gather the spot, and check drops, the chunk cooldown, and `/gathering status`. +6. Exercise `adminmode`, `clearcache`, and `reload`. +7. Restart cleanly and confirm spots, discoveries, cooldowns, and excluded chunks + are restored. diff --git a/projects/Infestations/README.md b/projects/Infestations/README.md new file mode 100644 index 0000000..3abe09d --- /dev/null +++ b/projects/Infestations/README.md @@ -0,0 +1,30 @@ +# Infestations + +[Source repository](https://github.com/TF-Minecraft/Infestations) · [All projects](../../README.md) + +Province-scale MythicMobs infestations with ambient spawning, lure raids, and optional spread between SimpleFactions provinces. + +TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](../../PLATFORM.md) for runtime, build and validation conventions. + +## Build and dependencies + +Infestations builds with Java **21** against +`io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT`. Install the pinned TLibs +`2.0.1`, SimpleFactions `3.0.2`, and InteractibleFurniture `0.2.1` release +artifacts with the shared dependency installer. The build also prepares a +checksum-verified MythicMobs `5.8.0-SNAPSHOT` input from the private +ServerAssets repository. + +At runtime, `plugin.yml` requires TLibs, SimpleFactions, MythicMobs, +ItemsAdder, and InteractibleFurniture. The plugin code does not call ItemsAdder +directly; the default lure is an ItemsAdder item (`ia.tfmc:lure`) placed as +InteractibleFurniture. + +## Guides + +- [Behaviour, configuration, and operations](overview.md) + +## Builds and releases + +See the [shared pipeline guide](../../PIPELINES.md) for development artifacts, +release tags, private dependency access, and release verification. diff --git a/projects/Infestations/overview.md b/projects/Infestations/overview.md new file mode 100644 index 0000000..4082bb7 --- /dev/null +++ b/projects/Infestations/overview.md @@ -0,0 +1,160 @@ +# Behaviour, configuration, and operations + +[Infestations documentation](README.md) · [All projects](../../README.md) + +## System model + +An infestation belongs to one SimpleFactions province and has a mob group from +`groups.yml` and a severity: `mild`, `worrying`, `severe`, or `extreme`. Each +province holds at most one infestation. Only land provinces can be infested: +provinces with a terrain listed in `skip-terrains` are refused, and a group +with a `terrains` list is limited to those terrains. + +```mermaid +stateDiagram-v2 + [*] --> Idle: set or spread + Idle --> Joining: lure placed + Joining --> Active: join window ends + Joining --> Idle: committed player leaves + Active --> Idle: committed player leaves or party lost + Active --> [*]: remaining reaches zero + Idle --> [*]: admin clear +``` + +**Idle.** Every `ambient-interval-ticks`, each player in Survival or Adventure +inside an idle infested province triggers one spawn attempt, as long as the +province's tagged ambient mobs are below `ambient-cap`. Spots lie in a ring +between `ambient-ring-min` and `ambient-ring-max` blocks from the player, within +two blocks of the player's height, inside the same province, and at or above +the group's `min-y`. Each spot needs a clear 3×3×3 space over a solid 3×3 +floor. `night-only` groups spawn only while world time is 13000–22999. Mobs are +picked from the group's weighted MythicMobs list and tagged with the province +and kind. Killing ambient mobs never clears an infestation, and the plugin does +not remove spawned mobs. + +**Lure.** Placing InteractibleFurniture whose item path equals `lure-item` +starts a lure. Placement is cancelled unless the province is infested land with +no lure; placing the lure item as an ordinary block is always cancelled. The +placer joins automatically and other players in the province are notified. +During the `join-seconds` window, players in the province see an action-bar +countdown and join by right-clicking the lure. Ambient spawning stops for the +duration of the lure; existing ambient mobs stay. + +When the window ends, the lure releases up to `lure-count` mobs, paced evenly +across `lure-duration-seconds`, between 4 and `lure-spawn-radius` blocks from +the lure. The duration paces spawning; it is not a time limit. A floating text +display above the lure shows the countdown or the remaining count to players +within `hologram-view-range`. Any death of a lure-tagged mob reduces the +remaining count. Right-clicking an active lure makes the remaining lure mobs +glow for 10 seconds and commits a player who has not yet joined. Uncommitted +Survival and Adventure players in the province take `deserter-damage` every +second until they leave. + +- **Victory:** when the remaining count reaches zero, the lure is removed and + the infestation is cleared. +- **Failure:** the lure is removed and the infestation returns to idle at the + same severity if a committed player is outside the province, or, once the + lure is active, if no committed player is alive, online, or within the logout + grace period. +- **Logout:** a committed player who logs out has `logout-grace-seconds` to + return and remains committed. After the grace period, they are killed on + their next login. A committed player who dies leaves the lure. + +Players cannot break the lure, and explosions and pistons cannot move it. Lure +furniture that does not match saved lure state is removed on enable, reload, +chunk load, or when a player touches it. + +**Spread.** When `spread` is `true`, every `spread-interval-seconds` each idle +infestation rolls `worsen-chance` to rise one severity (up to `extreme`). It +then considers uninfested land neighbours its group may occupy, plus such land +on the far side of one adjacent `water` or `sea` province. Two-province hops are +not considered. Each candidate uses its easiest route (land, then water, then +sea); one candidate is chosen, weighted by route chance, and a single roll +against `spread-chance-` for the source severity decides whether it +becomes a new `mild` infestation of the same group. Infestations with a lure +neither worsen nor spread. + +## Configuration files + +The plugin copies its defaults into `plugins/Infestations/` on first start. + +| File | Purpose | +| --- | --- | +| `config.yml` | Debug and spawn-log switches, spread switch, interval and chances, lure item, join window, lure spawn radius, logout grace, deserter damage, hologram range, and `skip-terrains`. | +| `groups.yml` | Mob groups: `display` name, `night-only`, optional `min-y`, optional SimpleFactions `terrains`, weighted MythicMobs `mobs`, and per-severity `ambient-cap`, `ambient-interval-ticks`, `ambient-ring-min`, `ambient-ring-max`, `lure-count`, and `lure-duration-seconds`. | +| `messages.yml` | Chat, action-bar, and hologram text. `{prefix}` inserts the `prefix` entry; hex colours are formatted through TLibs. | + +Chances are values from 0 to 1. Groups without `mobs` are skipped with a +warning, unknown terrain names are reported but kept, and omitted severity rows +use built-in defaults. The default `swamp_mobs` group spawns `SwampGhoul` at +night in `bog` provinces. + +## Commands and permissions + +The command is `/infestation` (alias `/infestations`). Province arguments take +a numeric SimpleFactions province ID or `here` for the player's province. + +| Command | Permission | Effect | +| --- | --- | --- | +| `/infestation set ` | `infestations.admin` | Infest an uninfested land province that the group's terrain rules allow. | +| `/infestation clear ` | `infestations.admin` | Remove an infestation and any lure it has. | +| `/infestation list` | `infestations.admin` | List infestations by province, group, and severity, marking those with a lure. | +| `/infestation reload` | `infestations.admin.reload` | Reload all three files, then reload saved state from disk. | + +Both permissions default to operators, and `infestations.admin` grants +`infestations.admin.reload`. Because `plugin.yml` also requires +`infestations.admin` for the command itself, the reload permission alone is not +enough. Reloading re-reads `Data/infestations.json`, removes stray lure +furniture and text displays, recounts loaded ambient mobs, and re-exports the +map data. + +## Integrations + +- **SimpleFactions** supplies province lookups, terrain, neighbours, and the + province enter and leave events that govern lure commitment. +- **MythicMobs** spawns every ambient and lure mob. Unknown mob IDs are logged + and skipped. +- **InteractibleFurniture** hosts the lure; placement, interaction, and break + events drive the lure lifecycle. TLibs item paths identify the lure item. +- **Map export:** on start and whenever infestations are set, spread, cleared, + or reloaded, the plugin writes each province's ID, severity, group, and + display name to `MapAPI/infestation_data.json` and uploads it through the + SimpleFactions REST server as `infestation_data`. + +## Persistence and shutdown + +- Infestations and lure state, including committed players, logout grace, and + lure counters, are stored in `plugins/Infestations/Data/infestations.json`. +- The latest map export is `plugins/Infestations/MapAPI/infestation_data.json`. +- When `logging` is true, spawn decisions are appended to + `plugins/Infestations/logs/spawn.log`; `wipe-log` deletes it on each start + and reload. + +State is saved after each change and every five seconds. On a normal disable, +the plugin removes lure text displays and saves state. Lure timers use +wall-clock time, so a join window that expired during downtime activates immediately. +Stop the server before editing the data file, since periodic saves overwrite +manual changes. + +## Validation + +For a server-side change, verify the following on Paper 1.21.10 with the pinned +dependency set: + +1. Start with both an empty data directory and a copy of representative + infestation data, and confirm the configs load without group or terrain + warnings and every configured MythicMobs ID exists. +2. Set, list, and clear infestations with both a province ID and `here`, and + confirm refusals for water or sea, disallowed terrain, and provinces that + are already infested. +3. Confirm ambient mobs spawn in the configured ring inside the province, stop + at the cap, and honour `night-only` and `min-y`. +4. Place lures with and without an infestation, then exercise joining, the + countdown, activation, paced spawning, highlighting, and deserter damage. +5. Exercise victory, a committed player leaving, losing the whole party, and a + logout both within and beyond the grace period. +6. On a test server, enable `spread` with a short interval and confirm + worsening, land spread, single water and sea hops, and group terrain limits. +7. Confirm `MapAPI/infestation_data.json` is written and uploaded. +8. Reload and restart cleanly during a lure, and confirm infestations, the lure, + its text display, and its counters are restored without duplicates. diff --git a/projects/Research/README.md b/projects/Research/README.md new file mode 100644 index 0000000..5c4818a --- /dev/null +++ b/projects/Research/README.md @@ -0,0 +1,30 @@ +# Research + +[Source repository](https://github.com/TF-Minecraft/Research) · [All projects](../../README.md) + +Lectern research stations where characters run item experiments to uncover hidden aspects and research results. + +TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](../../PLATFORM.md) for runtime, build and validation conventions. + +## Build and dependencies + +Research builds with Java **21** against +`io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT`. Install the pinned TLibs +`2.0.1` and TFMCCore `2.0.1` release artifacts with the shared dependency +installer. The build also prepares checksum-verified MMOCore `1.13.1` and +MythicLib `1.7` inputs from the private ServerAssets repository. + +At runtime, `plugin.yml` requires MMOItems, MythicLib, ItemsAdder, TLibs, and +TFMCCore. The code reaches MMOItems and ItemsAdder only through TLibs item +paths. MMOCore is declared as a soft dependency, but the discovery attribute +lookup calls MMOCore classes directly, so install MMOCore wherever Research +runs. + +## Guides + +- [Behaviour, configuration, and operations](overview.md) + +## Builds and releases + +See the [shared pipeline guide](../../PIPELINES.md) for development artifacts, +release tags, private dependency access, and release verification. diff --git a/projects/Research/overview.md b/projects/Research/overview.md new file mode 100644 index 0000000..bdd603b --- /dev/null +++ b/projects/Research/overview.md @@ -0,0 +1,172 @@ +# Behaviour, configuration, and operations + +[Research documentation](README.md) · [All projects](../../README.md) + +## System model + +Research treats every block of the configured `station.block` (default +`LECTERN`) as a research station. A station holds at most one active project, +owned by the player who started it. The project records its input, the output +rolled from that input, the result item resolved at the start, the points and +state of each aspect, the items already tested, and which aspect sits in each of +the six menu rows. + +## Player flow + +**Starting.** A player right-clicks a free station while holding an enabled +input's `start_item`. Research rolls one of the input's outputs by weight, +resolves its result, and then consumes `start_item.amount` from the hand used. +If the rolled output is disabled or its result cannot be resolved, nothing is +consumed. Other players get an "in use" message; the owner reopens the menu. + +**Experimenting.** Clicking an item in the player's inventory moves one of it +into the experiment slot, and clicking the slot returns it. Only items listed in +an aspect's `primary_items` or `secondary_items` are accepted, and each item path +can be tested once per project. Preview slots show the item's aspects, their +status, and the points they would add. Confirming spends +`mental_points.experiment_cost`, returns the item, and adds +`experiment.primary_points` and `experiment.secondary_points` to the item's +primary and secondary aspects. When `external_modifiers.experiment.aspect_point_bonus_percent` +is set, each grant is increased by that fraction, rounded down. Points on +required aspects are capped at `required_points`. Aspects the output does not +need collect up to `experiment.reject_points` and are then rejected; an item +whose aspects are all rejected cannot be confirmed. + +**Discovery.** Each required aspect row has five panes; pane *k* fills at +`ceil(k × required_points / 5)`. With *A* as the player's total in the MMOCore +attribute `attributes.discovery.mmocore_id`: + +| Stage | Reached when points are at least | Row shows | +| --- | --- | --- | +| Hidden | — | Divider and inactive panes, like a decoy row. | +| Undiscovered | `required_points` × max(`min_reveal_percent`, `base_reveal_percent` − *A* × `reveal_percent_reduction_per_point`) | `aspect_tested_unknown` icon and unknown panes. | +| Confirmed | `required_points` × max(`min_confirm_percent`, `base_confirm_percent` − *A* × `confirm_percent_reduction_per_point`) | The aspect's display item and revealed panes. | + +The reveal values are under `aspect_discovery` and the confirm values under +`aspect_confirm`. The mystery display switches to the product display once the +number of confirmed required aspects reaches +`product_reveal.base_after_confirmed_aspects` minus the attribute bonus +(*A* × `product_reveal_bonus_per_point`, capped at `caps.product_reveal_bonus`), +rounded to the nearest whole number. Because halves round up, a bonus of 0.5 +or less, including the default cap, leaves the base unchanged. An output without +`product_reveal` reveals its product at the first confirmed aspect. + +**Completing.** The project completes when every required aspect is confirmed +and at full `required_points`. The result item pops above the station as a +dropped item that anyone can pick up, `ResearchCompleteEvent` fires, and the +station is cleared. If the result cannot be built or spawned, a warning is +logged and the project stays open. The scrap button asks for confirmation and +then discards the project without refunding the start item. Breaking the +station block scraps its project in the same way. + +## Station menu + +The menu is a six-row chest. The left panel holds the scrap button (slot 0), +the mystery or product display (10), the experiment slot (27), the primary and +secondary previews (28 and 37), the mental points display (45), and the confirm +button (47). Column 3 and columns 4–8 hold six aspect rows. Required aspects are +shuffled into random rows when the project starts, and the remaining rows are +decoys, so an output can require at most six aspects. After each experiment, a +pulse in the scoring aspect's `pulse_color` crosses the left panel. + +## Configuration files + +The plugin copies `config.yml`, `gui.yml`, and `messages.yml` into +`plugins/Research/` on first start and creates empty content folders; no +example content is shipped. + +| File | Purpose | +| --- | --- | +| `config.yml` | Station block and optional use permission, start and completion effects, result pop motion, experiment cost, experiment points and `reject_points`, discovery attribute and product-reveal bonus, reveal and confirm thresholds, and optional `external_modifiers`. | +| `gui.yml` | Menu item paths (`items`), titles and button labels (`labels`), and hex colour tokens (`colors`). Slot positions are fixed in code. | +| `messages.yml` | Chat and menu text, with a `prefix` added to chat messages. | +| `aspects/*.yml` | Aspects keyed by identifier: `name`, `lore`, `display.item`, `pulse_color` (or a `grid_color` name), `sounds` (`input`, `confirm`, `volume`, `pitch`), `primary_items`, and `secondary_items`. | +| `templates/*.yml` | Templates keyed by identifier, each with an `outputs` list of `item` and `weight`. An `item` may be another template as `t.`; cycles are rejected. | +| `outputs/*.yml` | Outputs keyed by identifier: `enabled`, `mystery_display.item`, `product_display.item`, `product_reveal.base_after_confirmed_aspects`, `aspects..required_points` (above zero), and a `result` with exactly one of `item` or `template: t.`. | +| `inputs/*.yml` | Inputs keyed by identifier: `enabled`, `start_item` (`item`, `amount`), and an `outputs` list of `id` and `weight`. | + +The folders load in the order aspects, templates, outputs, inputs, so outputs +may reference aspects and templates, and inputs reference outputs. Identifiers +must be unique within each folder, and each start item may belong to only one +input. If an item path is listed as primary (or secondary) on two aspects, the +conflict is logged and the aspect loaded last wins. + +Item paths use `vanilla.MATERIAL` (or TLibs `v.MATERIAL`), `m.TYPE.ID` for +MMOItems, and `ia.namespace:id` for ItemsAdder; other prefixes are rejected. +Paths that cannot be built are accepted with a warning. Sounds take Minecraft +sound keys such as `entity.player.levelup` or `namespace:id`, and particles +take Bukkit particle names. Text accepts `#RRGGBB` and `&` codes through TLibs. + +Run `/research reload` after editing these files. A reload reports failure when +any definition is invalid, but definitions that failed validation are still +registered, so fix every logged error. Reloading does not touch active stations, +which keep their rolled output and result, so keep input and output identifiers +in place while projects use them. Research recognises its menus by title; close +open station menus before changing `labels` titles or `colors.inventory_title`. + +## Commands and permissions + +| Command or setting | Effect | +| --- | --- | +| `/research reload` | Reload all configuration and content. Requires `research.admin`, which defaults to operators. | +| `station.permission` | Optional permission to use stations. When set, Research ignores clicks from players without it, and the block behaves normally. | + +## Integrations + +- **TFMCCore Focus.** Mental points are the TFMCCore Focus pool for the player's + active RPCharacters character, shared with Magic meditation. The cap and + regeneration, including attribute bonuses, are set in TFMCCore `focus.yml`. A + player without an active character has no points and cannot experiment. +- **MMOCore.** The discovery attribute is read as the attribute's total value; + a missing attribute counts as zero. +- **TLibs.** TLibs builds and matches every item path and formats text. +- **`ResearchCompleteEvent`.** Listen for + `net.tfminecraft.research.event.ResearchCompleteEvent`, which fires + synchronously after the result spawns and cannot be cancelled. It exposes + `getPlayer()`, `getInputId()`, `getOutputId()`, and `getResultItemRef()`, the + resolved item path rather than a `t.` template. `getProjectId()` is a + deprecated alias for `getOutputId()`. + +## Replacing AdvancedResearch + +Research replaces the archived AdvancedResearch plugin. It cancels right-clicks +on every station block, so do not run both plugins on the same lecterns. It +does not read AdvancedResearch data under `plugins/AdvancedResearch/`; rebuild +the content as aspects, outputs, inputs, and templates, and expect projects in +progress to be restarted. + +## Persistence and shutdown + +- Each active station is a JSON file under + `plugins/Research/data/stations/`, named `___.json`, holding + the owner, input, output, result path, product reveal, aspect points and + states, tested items, and row order. +- Station files are written when a project starts, after each confirmed + experiment, and on a normal plugin disable. They are deleted when a project + completes, is scrapped, or its block is broken. +- On start, files that reference an unknown input, output, or world are skipped + with a warning and left on disk. A missing or stale row order is reshuffled. + +Back up the complete `plugins/Research/` directory before renaming identifiers +or migrating configuration, and stop the server cleanly before copying live +state. + +## Validation + +For a server-side change, verify the following on Paper 1.21.10 with the pinned +dependency set: + +1. Start with both an empty data directory and a copy of representative station + data. +2. Confirm all aspects, templates, outputs, and inputs load, and that + `/research reload` succeeds without severe errors or unbuildable item paths. +3. Start a project with each start item, and confirm only the held item is + consumed and another player sees the station as in use. +4. Run experiments, checking previews, mental point spending, repeat-item + refusal, off-recipe rejection, and reveal timing at low and high values of + the discovery attribute. +5. Complete a project, and confirm the result spawns, a test listener receives + `ResearchCompleteEvent`, and the station is cleared. +6. Scrap one project and break the block under another. +7. Restart cleanly mid-project and confirm ownership, progress, tested items, + row order, and the rolled result are restored. diff --git a/projects/TrialRooms/README.md b/projects/TrialRooms/README.md new file mode 100644 index 0000000..662f34d --- /dev/null +++ b/projects/TrialRooms/README.md @@ -0,0 +1,28 @@ +# TrialRooms + +[Source repository](https://github.com/TF-Minecraft/TrialRooms) · [All projects](../../README.md) + +Keyed dungeon entrances, levelled MythicMobs spawner encounters, and key-opened loot chests. + +TFMC runs Minecraft **1.21.10**. See the [shared platform and build baseline](../../PLATFORM.md) for runtime, build and validation conventions. + +## Build and dependencies + +TrialRooms builds with Java **21** against +`io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT`. Install the pinned TLibs +`2.0.1` and DenarEconomy `0.2.1` release artifacts with the shared dependency +installer. The build also prepares a checksum-verified MythicMobs +`5.8.0-SNAPSHOT` input from the private ServerAssets repository. + +At runtime, `plugin.yml` requires MythicMobs, TLibs, and DenarEconomy. Magic is +not declared; `magic.` item paths in loot tables only resolve when Magic is +installed. + +## Guides + +- [Behaviour, configuration, and operations](overview.md) + +## Builds and releases + +See the [shared pipeline guide](../../PIPELINES.md) for development artifacts, +release tags, private dependency access, and release verification. diff --git a/projects/TrialRooms/overview.md b/projects/TrialRooms/overview.md new file mode 100644 index 0000000..87e0403 --- /dev/null +++ b/projects/TrialRooms/overview.md @@ -0,0 +1,148 @@ +# Behaviour, configuration, and operations + +[TrialRooms documentation](README.md) · [All projects](../../README.md) + +## System model + +TrialRooms builds combat rooms from in-world parts placed with the edit tool. +An **entrance** is a lodestone with a key item, a destination, and an optional +exit lodestone. A **spawner** is a block matching a `spawners.yml` definition, +with its own MythicMobs mob, amount, level, radii, cooldown, loot tables, and +**door blocks** that are present only while its encounter runs. **Loot chests** +open with keys and are either bound to a spawner or independent. Spawners cycle +through Idle, Active, Unlocking, and Cooldown. Text-display holograms label +spawners, chests, entrances, and exits while a player is within 96 blocks. + +## Configuration files + +The plugin copies missing defaults into `plugins/TrialRooms/` on start and never +overwrites existing files. There is no reload command; restart after editing. + +| File | Purpose | +| --- | --- | +| `config.yml` | Edit tool, key items, loot size, level scaling, key rarity model, mob-key chances, and Denar conversions. | +| `spawners.yml` | Spawner definitions: each top-level key sets a TLibs `block` path (default `v(spawner)`). | +| `loot-tables.yml` | Named loot tables used by spawner and mob keys. | + +Settings read from `config.yml`, with the defaults used when a key is absent: + +| Key | Default | Effect | +| --- | --- | --- | +| `edit-tool` | `v.blaze_rod` | TLibs item path of the administrator edit tool. | +| `spawner-key`, `mob-key` | `v.tripwire_hook` | Base items for spawner keys and mob keys. | +| `max-loot` | `24` | Maximum distinct loot entries recorded on a key. | +| `health-per-level`, `damage-per-level` | `10.0`, `0.5` | Extra mob health and extra damage to players per spawner level. | +| `mob-key-base-chance`, `mob-key-chance-per-level`, `mob-key-max-chance` | `0.02`, `0.0015`, `0.25` | Mob-key drop chance per spawner mob death. | +| `common-chance` … `legendary-chance` | `70`, `20`, `7`, `2.8`, `0.2` | Base key rarity weights. | +| `rarity-weight-model` | `EXP` | `LINEAR`, `EXP`, or `LOGISTIC` level scaling of rarity weights. | +| `rarity-*`, `jitter-max` | see [source](https://github.com/TF-Minecraft/TrialRooms/blob/main/src/main/java/net/tfminecraft/trialrooms/loader/ConfigLoader.java) | Model tuning; `rarity-bias-per-level` also sets loot-table level bias. | +| `conversions` | none | Lines of ` `. | +| `debug` | `false` | Broadcasts a 10,000-key rarity simulation instead of dropping spawner keys. | + +The shipped `config.yml` contains `bias-per-level`, which is not read. + +A loot table is either a list of ` - [tier]` lines, +or a section with that list under `drops` and `amounts` lines of +` -`. Tiers are `bad`, `common` (the default), `uncommon`, +`rare`, `epic`, and `legendary`. `amounts` sets how many items a key of each +rarity releases; without it a key releases 2–4. The default `artifact_test` table +uses `magic.` paths, which need Magic installed. + +## Building a room + +Hold the edit tool and right-click a block matching a spawner definition to +create or reopen its editor, a lodestone to register or reopen an entrance, or +an unregistered chest to register an independent loot chest. New entrances must +be at least 4 blocks from other entrances, exits, and destinations. + +The spawner editor sets the MythicMobs internal mob name (not validated), amount, +level, cooldown in seconds, spawn and activation radii, loot table, mob loot +table, bound chest, and door blocks. New spawners start with `rpg_skeleton`, 1 +mob, level 1, radii of 5, and a 10-second cooldown. Values are typed in chat and +`cancel` aborts. Binding a chest requires a loot table. Door blocks must be +within 32 blocks and not a chest; typing `remove` drops the latest one. The +entrance editor sets the key item path and, within 32 blocks of the entrance, a +destination block and an exit lodestone. + +Breaking a spawner or registered chest requires the edit tool. Breaking an +entrance lodestone removes the entrance, and breaking an exit or destination +block clears it, with or without the tool. Edit-tool actions are not +permission-checked, so choose an item ordinary players cannot obtain. + +## Encounters and keys + +Right-clicking within 1.5 blocks of an entrance with its key item in the main +hand consumes one and teleports the player to the destination; stepping within +1.5 blocks of the exit returns them. An idle spawner activates when a survival +or adventure player is within its activation radius and 2 blocks vertically. It +spawns its mobs 1–3 seconds apart on spots within the spawn radius with 3×3×3 +clear air over a solid 3×3 floor. If no player remains within 50 blocks, or the +chunk unloads, the mobs are removed and the spawner enters cooldown without a +key. + +When every mob is dead, the spawner unlocks for about 2.5 seconds, drops a +spawner key, and enters cooldown. Bound chests appear one second into cooldown +and hide when it ends. If a mob loot table is set, each spawner mob death may +also drop a mob key. + +Key rarity is rolled from the base weights and the spawner level. The key then +records up to `max-loot` distinct entries from its table, weighted by level, +tier, and key rarity, with higher tiers capped by rarity; its lore lists them +with their chances. Right-clicking a visible registered chest with any key +consumes it and releases the rolled number of distinct entries. Bound chests +stay hidden until the next cooldown; independent chests return after 5 seconds. + +## Dungeon rules and conversions + +Players count as inside after using an entrance, being in range when a spawner +activates, or taking damage from a spawner mob. Inside players do not regenerate +health from saturation and cannot damage each other. Leaving through the exit, +dying, or disconnecting clears the flag. + +Items matching a `conversions` line gain "converts on exit" lore when picked up. +Leaving through the exit removes them and credits their Denar value through +DenarEconomy. When any player dies, convertible items are removed from their +drops and inventory. + +## Commands and permissions + +| Command | Permission | Effect | +| --- | --- | --- | +| `/tr resetcooldowns` | `trialrooms.admin` | Set every cooling-down spawner to one second remaining. | + +`/tr` is player-only and has no tab completion. `plugin.yml` declares no +permissions, so `trialrooms.admin` falls back to the operator default. + +## Persistence and shutdown + +- Spawners, including state, cooldown, and doors: + `plugins/TrialRooms/data/spawners/.json`. +- Loot chests: `plugins/TrialRooms/data/chests/.json`. +- Entrances: `plugins/TrialRooms/data/entrances/entrance____.json`. + +Spawners and chests are written only on a normal plugin disable. Entrances are +autosaved within 10 seconds of being registered and are written on disable. +Records that cannot be read, reference an unloaded world, or name a missing +`spawners.yml` definition are skipped at start, and saving deletes their files. +Active or unlocking spawners resume in a full cooldown; chests whose spawner is +missing load as independent. + +Back up the complete `plugins/TrialRooms/` directory before renaming spawner +definitions or worlds, and stop the server cleanly before copying live state. + +## Validation + +For a server-side change, verify the following on Paper 1.21.10 with the pinned +dependency set: + +1. Start with both an empty data directory and a copy of representative existing + room data. +2. Confirm spawner definitions, loot tables, key items, and MythicMobs mob names + resolve without warnings. +3. Build an entrance, exit, spawner, door blocks, bound chest, and independent + chest with the edit tool. +4. Enter with the key item, clear the encounter, and confirm doors, level + scaling, keys, chest opening, cooldown, healing suppression, blocked PvP, + exit conversions, and death removal of convertible items. +5. Restart cleanly and confirm entrances, spawner settings, cooldowns, doors, + and chests are restored.