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.