From 16a98cd8df8f270bcd3e44e314bdc25e39c15b81 Mon Sep 17 00:00:00 2001 From: Ryan Barlow <7389646+ryanbarlow97@users.noreply.github.com> Date: Wed, 23 Sep 2026 16:05:41 +0000 Subject: [PATCH] docs: remove local manuals and obsolete checks --- .github/pull_request_template.md | 3 +- .github/workflows/docs.yml | 27 ---- docs/README.md | 45 ------ docs/architecture/bootstrap.md | 66 -------- docs/architecture/integrations.md | 110 -------------- docs/architecture/persistence.md | 67 --------- docs/crops.md | 3 - docs/decisions/0001-food-vs-nutrition.md | 24 --- docs/decisions/0002-source-of-truth.md | 20 --- docs/how-to/add-config-option.md | 8 - docs/how-to/add-food-type.md | 8 - docs/how-to/add-husbandry-or-crop.md | 18 --- docs/how-to/add-station-recipe.md | 9 -- docs/how-to/update-docs.md | 21 --- docs/husbandry.md | 3 - docs/impact-waiver.md | 10 -- docs/manifest.json | 164 -------------------- docs/reference/commands-permissions.md | 23 --- docs/reference/configuration.md | 35 ----- docs/reference/external-assets.md | 51 ------- docs/reference/item-pdc.md | 41 ----- docs/systems/cooking-stations.md | 81 ---------- docs/systems/crops-and-farming.md | 134 ----------------- docs/systems/food-items.md | 93 ------------ docs/systems/freshness-tags.md | 75 ---------- docs/systems/husbandry.md | 183 ----------------------- docs/systems/nutrition.md | 88 ----------- docs/systems/portions-and-servings.md | 94 ------------ docs/systems/processing-stations.md | 85 ----------- docs/systems/quality-composition.md | 86 ----------- scripts/check-doc-impact.py | 25 ---- scripts/check-links.py | 40 ----- scripts/doclib.py | 183 ----------------------- scripts/test_doc_manifest.py | 120 --------------- src/main/resources/crops.yml | 2 +- 35 files changed, 2 insertions(+), 2043 deletions(-) delete mode 100644 .github/workflows/docs.yml delete mode 100644 docs/README.md delete mode 100644 docs/architecture/bootstrap.md delete mode 100644 docs/architecture/integrations.md delete mode 100644 docs/architecture/persistence.md delete mode 100644 docs/crops.md delete mode 100644 docs/decisions/0001-food-vs-nutrition.md delete mode 100644 docs/decisions/0002-source-of-truth.md delete mode 100644 docs/how-to/add-config-option.md delete mode 100644 docs/how-to/add-food-type.md delete mode 100644 docs/how-to/add-husbandry-or-crop.md delete mode 100644 docs/how-to/add-station-recipe.md delete mode 100644 docs/how-to/update-docs.md delete mode 100644 docs/husbandry.md delete mode 100644 docs/impact-waiver.md delete mode 100644 docs/manifest.json delete mode 100644 docs/reference/commands-permissions.md delete mode 100644 docs/reference/configuration.md delete mode 100644 docs/reference/external-assets.md delete mode 100644 docs/reference/item-pdc.md delete mode 100644 docs/systems/cooking-stations.md delete mode 100644 docs/systems/crops-and-farming.md delete mode 100644 docs/systems/food-items.md delete mode 100644 docs/systems/freshness-tags.md delete mode 100644 docs/systems/husbandry.md delete mode 100644 docs/systems/nutrition.md delete mode 100644 docs/systems/portions-and-servings.md delete mode 100644 docs/systems/processing-stations.md delete mode 100644 docs/systems/quality-composition.md delete mode 100644 scripts/check-doc-impact.py delete mode 100644 scripts/check-links.py delete mode 100644 scripts/doclib.py delete mode 100644 scripts/test_doc_manifest.py diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index efeb7e8..7f4b31d 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -4,8 +4,7 @@ ## Documentation impact -- [ ] System docs updated for every owned path in `docs/manifest.json` -- [ ] Or `docs/impact-waiver.md` changed in this PR with `docs-impact: none` and a reason +- Central [Cooking documentation](https://github.com/TF-Minecraft/Docs/tree/main/projects/Cooking): no change / updated (link) ## Contract diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 0406b05..0000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: docs - -on: - pull_request: - push: - branches: [main] - -permissions: - contents: read - -jobs: - documentation: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v7 - with: - fetch-depth: 0 - persist-credentials: false - - uses: actions/setup-python@v7 - with: - python-version: '3.12' - - name: Validate documentation manifest - run: python scripts/test_doc_manifest.py - - name: Check internal links - run: python scripts/check-links.py - - name: Check documentation impact - run: python scripts/check-doc-impact.py diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 9f4218c..0000000 --- a/docs/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Cooking internal docs - -These files describe how the plugin works. The player wiki describes how to play. - -If behavior, tests, config, and these docs disagree, the change is not done. - -## Map - -| System | Document | Primary code | Config | -| --- | --- | --- | --- | -| Bootstrap and reload | [architecture/bootstrap.md](architecture/bootstrap.md) | `Cooking.java` | all shipped YAML | -| Persistence | [architecture/persistence.md](architecture/persistence.md) | `husbandry/`, `item/` | `Data/husbandry.db`, item PDC | -| Integrations | [architecture/integrations.md](architecture/integrations.md) | bridges and listeners | furniture and item paths in `config.yml` | -| Food items | [systems/food-items.md](systems/food-items.md) | `item/`, `utils/FoodParser.java` | `types.yml`, `models.yml`, `naming.yml` | -| Tags and aging | [systems/freshness-tags.md](systems/freshness-tags.md) | `manager/TagManager.java` | `tags.yml` | -| Quality and conversions | [systems/quality-composition.md](systems/quality-composition.md) | `quality/` | `quality.yml`, `composition.yml`, `conversions.yml`, `permission_effects.yml` | -| Active cooking and heat | [systems/cooking-stations.md](systems/cooking-stations.md) | `cooking/`, `heat/`, `oven/`, `liquid/`, `manager/PlateManager.java` | `config.yml` heat and furniture ids | -| Processing stations | [systems/processing-stations.md](systems/processing-stations.md) | `crafting/`, `baking/`, `milling/`, `mixing/`, `churn/`, `sausagemaker/`, `hook/`, `trough/` | `crafting-stations.yml`, `baking-trays.yml`, `milling-recipes.yml` | -| Portions | [systems/portions-and-servings.md](systems/portions-and-servings.md) | `carve/`, `cooking/PotReference.java` | `carve-sequences.yml`, `pot-soup-scoops` | -| Nutrition | [systems/nutrition.md](systems/nutrition.md) | `nutrition/` | `config.yml` `nutrition:` | -| Crops and farming | [systems/crops-and-farming.md](systems/crops-and-farming.md) | `crops/`, `farming/` | `crops.yml`, `farming.yml` | -| Husbandry | [systems/husbandry.md](systems/husbandry.md) | `husbandry/` | `husbandry.yml` | - -Reference: [reference/configuration.md](reference/configuration.md), [reference/item-pdc.md](reference/item-pdc.md), [reference/commands-permissions.md](reference/commands-permissions.md), [reference/external-assets.md](reference/external-assets.md). - -How-to: [how-to/add-food-type.md](how-to/add-food-type.md), [how-to/add-station-recipe.md](how-to/add-station-recipe.md), [how-to/add-config-option.md](how-to/add-config-option.md), [how-to/add-husbandry-or-crop.md](how-to/add-husbandry-or-crop.md), [how-to/update-docs.md](how-to/update-docs.md). - -Decisions: [decisions/0001-food-vs-nutrition.md](decisions/0001-food-vs-nutrition.md), [decisions/0002-source-of-truth.md](decisions/0002-source-of-truth.md). - -Ownership used by CI: [manifest.json](manifest.json). - -## Template for a system doc - -1. Purpose -2. Vocabulary -3. Invariants -4. Inputs and outputs -5. State and persistence -6. Runtime flow -7. Configuration -8. Integrations -9. Edge cases -10. Source map -11. Tests -12. Change checklist diff --git a/docs/architecture/bootstrap.md b/docs/architecture/bootstrap.md deleted file mode 100644 index 4da35e8..0000000 --- a/docs/architecture/bootstrap.md +++ /dev/null @@ -1,66 +0,0 @@ -# Bootstrap and reload - -## Purpose - -`Cooking` is wiring only. It creates the data folder, copies missing resources, loads YAML into static registries, registers listeners, and starts periodic tasks. - -## Vocabulary - -- **Resource:** a file in `src/main/resources`, packaged in the jar. -- **Data file:** the copy under the server plugin folder. Created only when missing (`saveResource(s, false)`). -- **Reload:** `loadConfigs()` plus station rebuild and nutrition/husbandry task restart. It does not reopen SQLite. - -## Invariants - -- `src/main/resources` is the repo source. `target/classes` is compiler output. -- An existing server YAML is not overwritten by a jar update. -- `/cooking reload` reloads YAML and applies husbandry `stats-revision`. It does not run SQLite migrations again. -- `cookware.yml` is copied on first install and is not passed to a loader. -- `/cooking qualitytest compose2` prints composition lineage mains and extras. - -## Inputs and outputs - -Enable reads every file listed in `Cooking.createConfigs()` and `Cooking.loadConfigs()`. Disable stops nutrition, husbandry, oven, liquid, and churn tasks, flushes loaded husbandry rows, and unregisters the TLibs `c` path handler. - -## State and persistence - -Husbandry SQLite opens in `onEnable` and closes in `onDisable`. Item PDC is not loaded here. Furniture slot contents belong to InteractibleFurniture. - -## Runtime flow - -1. `plugin = this` -2. `createFolders()` (`Data/`) -3. `createConfigs()` -4. `loadConfigs()` in this order: `config.yml`, `models.yml`, `types.yml`, `baking-trays.yml`, `milling-recipes.yml`, `crafting-stations.yml`, `tags.yml`, `naming.yml`, `quality.yml`, `composition.yml`, `permission_effects.yml`, `conversions.yml`, `farming.yml`, `crops.yml`, `husbandry.yml`, `carve-sequences.yml`, `custom-fishing.yml` -5. `registerListeners()` -6. Deferred starts: cooking manager, nutrition drain, husbandry tick, item scan subscriptions for tag aging and leftover fish, path handler `c` - -## Configuration - -See [../reference/configuration.md](../reference/configuration.md). - -## Integrations - -Hard plugin dependencies are declared in `plugin.yml`: TLibs, InteractibleFurniture, TFMCCore. Soft: RPCharacters, MMOCore, CustomCrops, SimpleFactions, CustomFishing. The CustomFishing listener is registered only when that plugin is already enabled. - -## Edge cases - -- Opening `husbandry.db` throws and fails enable if SQLite cannot open. -- Reload while players hold food does not rewrite existing item PDC by itself. Tag scan and item update paths do that later. The leftover-fish scan converts a matching `COD` in an open inventory on the same item-scan pass. -- Version strings: `plugin.yml` `version: 1.0`, Maven `0.1.5-ALPHA`. Both are currently true and inconsistent. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/Cooking.java` -- `src/main/java/net/tfminecraft/cooking/loader/ConfigLoader.java` -- `src/main/java/net/tfminecraft/cooking/manager/CommandManager.java` (`reload`) - -## Tests - -No bootstrap test. Documentation impact is `scripts/test_doc_manifest.py`. - -## Change checklist - -- New YAML file: add it to `createConfigs()`, `loadConfigs()`, the configuration reference, and `docs/manifest.json`. -- New listener: register it in `registerListeners()` and name the owning system doc. -- Do not point agents at `target/`. diff --git a/docs/architecture/integrations.md b/docs/architecture/integrations.md deleted file mode 100644 index 15efad2..0000000 --- a/docs/architecture/integrations.md +++ /dev/null @@ -1,110 +0,0 @@ -# Integrations - -## Purpose - -Cooking owns food items, station behavior, crop quality math, and livestock records. Other plugins own items, furniture placement, characters, crop blocks, and province fertility. - -## Platform contract - -Cooking on `main` targets **Minecraft 1.21.10 and Java 21**. Maven compiles with -`maven.compiler.release=21` against the provided Paper 1.21.10 API, and -`plugin.yml` declares `api-version: 1.21.10`. - -Use the TLibs and InteractibleFurniture versions declared in `pom.xml`. -Resolve the committed dependency versions through the shared installer in pinned -mode and its checksum verification. The source POM defines the build inputs. - -The build and its tests verify compilation and covered behavior. Validate the -configured integrations below on the intended Minecraft 1.21.10 server before -deployment. - -Legacy integer item models are read through `LegacyModelData`, using the first -custom-model-data float. String-only, flag-only, and color-only components do -not identify a legacy fish model. The model IDs and fish-conversion rules stay -the same. - -## Vocabulary - -- **TLibs path:** a string such as `v.wheat`, `ia.tfmc_cooking:tomato`, `m.materials.leather`, or `c.grain(type=wheat)`. -- **Furniture id:** the InteractibleFurniture type key stored in `config.yml` (`pot: pot`). - -## Invariants - -- Cooking registers the TLibs path prefix `c` and unregisters it on disable. -- `c` paths match food only. They are not seeds. -- CustomCrops YAML must not contain fertility rules. Affection comes from `crops.yml`. -- Province fertility is a 0-100 read from SimpleFactions. Missing plugin, disabled map, or unmapped land is 0 for harvest. -- Nutrition numbers are applied to the active RPCharacters character. Cooking does not invent a second character store. -- MMOCore crop XP still needs a drop-less `BlockBreakEvent` on hoe harvest. Cooking does not calculate that XP. - -## Inputs and outputs - -| Plugin | Cooking reads | Cooking writes | -| --- | --- | --- | -| TLibs | item match, create, names | path handler `c` | -| InteractibleFurniture | place, click, slot events | slot display updates | -| TFMCCore | `ItemScanService` | tag aging subscription | -| RPCharacters | active character | food level and nutrition attribute | -| CustomCrops | harvest and grow events | wrapped grow-conditions, converted drops | -| SimpleFactions | province fertility, battle state | none | -| MMOCore | none directly | break event so crop XP can fire | -| ItemsAdder | custom item ids and models | none | -| CustomFishing | loot id, size in cm, and rod id from `FishingLootSpawnEvent`. Leftover fish also expose item tags `CustomFishing.id` and `CustomFishing.size` | replaces a configured catch, or a leftover cod, with `seafood_whole` | - -## State and persistence - -External plugins keep their own data. Cooking must not duplicate CustomCrops plant rows or faction claims. - -## Runtime flow - -See the system docs for each bridge. Startup order is [bootstrap.md](bootstrap.md). - -## Configuration - -Furniture and tool ids are the top of `config.yml`. IA namespaces are `tfmc_cooking` unless a crop seed path says `playbox_custom_crops`. - -## Integrations - -Asset packs shipped beside the plugin: - -- `ItemsAdder/tfmc_cooking/` -- `CustomCrops/` - -Those trees are content, not generated class files. `target/` is generated. - -## Edge cases - -- Soft-depend missing: nutrition, fertility, CustomCrops, MMOCore, or CustomFishing features no-op or use the documented fallback. Do not crash enable for a soft depend. -- CustomFishing 2.3.27 is optional. Cooking reads `loot.id()`, `ContextKeys.SIZE`, and `ContextKeys.ROD` on a new catch. Unconfigured loot is left alone, and Cooking does not cancel CustomFishing actions or read its silver/golden star groups. -- A configured catch with a missing, non-finite, or non-positive size is logged and left unchanged. Stored centimetres use `Math.round`. -- Rod quality bands are in `custom-fishing.yml`: basic 1-2, steel 2-3, abyssalite 3-4, mythril 4-5. An unknown rod uses the `unknown-rod` band (1-5), then the normal pickup permission adjustment. -- A leftover `COD` already in an inventory is converted on item scan, and a dropped one on pickup. Cooking reads the `CustomFishing` item tags `id` and `size` when that plugin is enabled. Otherwise it uses `model-data` in `custom-fishing.yml`. A stack that already has `food_id` is left alone. Lore is not read. An unknown loot id is left alone. Silver and golden model numbers map to the same species and do not set Cooking quality. A missing size uses `legacy-size-cm` (45). Quality is the normal pickup roll. -- Plain vanilla cod, salmon, tropical fish, and pufferfish become `seafood_whole` on pickup using the `vanilla` sizes in `custom-fishing.yml` and the normal pickup-quality roll. A stack with custom model data is not treated as vanilla cod. The whole item stays edible and keeps the type food and nutrition. -- Cutting a whole seafood item uses the `cutting` output type in `custom-fishing.yml`. One whole item becomes one portion. Food and nutrition stay the portion type's levels: 6 and 6 for a fish filet, 5 and 5 for jellyfish, 7 and 7 for octopus. Size is still stored on the item. -- Nutmeg seeds are `ia.playbox_custom_crops:nut_seeds`, not `nutmeg_seeds`. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/item/CookingPathHandler.java` -- `src/main/java/net/tfminecraft/cooking/crops/CropCustomCropsBridge.java` -- `src/main/java/net/tfminecraft/cooking/crops/CropFertility.java` -- `src/main/java/net/tfminecraft/cooking/fishing/CustomFishingBridge.java` -- `src/main/java/net/tfminecraft/cooking/fishing/CustomFishingCatchListener.java` -- `src/main/java/net/tfminecraft/cooking/fishing/LegacyFishScan.java` -- `src/main/java/net/tfminecraft/cooking/nutrition/NutritionService.java` -- `src/main/resources/plugin.yml` -- `src/main/resources/custom-fishing.yml` - -## Tests - -- `CookingPathHandlerTest` -- `CropsConfigTest` -- `CustomFishingCatchTest` -- `VanillaFishTest` -- `LegacyFishTest` -- `SeafoodCuttingTest` - -## Change checklist - -- New external id: update [../reference/external-assets.md](../reference/external-assets.md) and the station or crop doc. -- Do not add a hard depend for a plugin listed as `softdepend` unless enable truly cannot run without it. diff --git a/docs/architecture/persistence.md b/docs/architecture/persistence.md deleted file mode 100644 index 4723175..0000000 --- a/docs/architecture/persistence.md +++ /dev/null @@ -1,67 +0,0 @@ -# Persistence and state ownership - -## Purpose - -Cooking state is split across item PDC, husbandry SQLite, and InteractibleFurniture slot data. Each store has one owner. - -## Vocabulary - -- **PDC:** Bukkit persistent data on an `ItemStack` or entity. -- **Base override:** `food_base` and `food_nutrition_base` stored on an item because code called `setBaseFood` or `setBaseNutrition`. -- **Row:** one livestock record in `Data/husbandry.db`. - -## Invariants - -- Food identity and quality travel on the item. They are not in SQLite. Catch size, cut class, and CustomFishing id travel on that same item. -- Livestock genetics, care, owners, timers, and affliction live in SQLite. Entity PDC is only a flag/link, not the database. -- Unloaded owned animals keep their row. Unowned listed types are removed on chunk load, with the horse-family enroll exception documented in [../systems/husbandry.md](../systems/husbandry.md). -- Furniture inventories are not Cooking tables. -- `slot_data` PDC on a scooped soup stores encoded pot slots for display/name context. It is not the pot's live inventory. -- `food_lineage` stores versioned main and extra origins. Missing lineage on an old item falls back to `food_origin` at the next composition. `food_ingredients` remains the short name list. -- Player PDC `variety_history` stores the rolling meals used for nutrition variety. It is account-wide. Raw and effective diet stay on the RPCharacter (`raw-diet-score`, `diet-score`). - -## Inputs and outputs - -`ItemBuilder.stamp` writes item PDC. `FoodItem.fromItem` reads it. `HusbandryRepository` is the only SQLite API. Migrations run when the connection opens, keyed by `PRAGMA user_version`. - -## State and persistence - -Item keys: [../reference/item-pdc.md](../reference/item-pdc.md). - -Database file: `plugins/Cooking/Data/husbandry.db` (WAL). Main thread only. - -Husbandry migrations through `user_version` 7 are listed in [../systems/husbandry.md](../systems/husbandry.md). They do not re-run on `/cooking reload`. - -## Runtime flow - -Chunk unload stamps `unloaded_at` and upserts. Disable flushes loaded animals. Death deletes the animal and owner rows. - -## Configuration - -`husbandry.yml` `stats-revision` resets gene/care fields when the id changes. It does not wipe owners, name, neuter, maturity, or harvest timers. - -## Integrations - -Paper saves entity PDC. Cooking still must not treat that PDC as the livestock record. - -## Edge cases - -- A missing entity with an owned row is kept for later reconcile. -- `Bukkit.getEntity == null` must not delete an owned row. -- Server YAML that already exists is not replaced when the jar ships a new default. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/utils/Keys.java` -- `src/main/java/net/tfminecraft/cooking/utils/ItemBuilder.java` -- `src/main/java/net/tfminecraft/cooking/husbandry/HusbandryRepository.java` -- `src/main/java/net/tfminecraft/cooking/Cooking.java` (`openHusbandryDatabase`) - -## Tests - -- `HusbandryRepositoryTest` - -## Change checklist - -- New item field: add a `NamespacedKey`, stamp it, read it back, and update the PDC reference. -- New SQLite column: bump `user_version` in the repository migration, not in reload. diff --git a/docs/crops.md b/docs/crops.md deleted file mode 100644 index 5e44667..0000000 --- a/docs/crops.md +++ /dev/null @@ -1,3 +0,0 @@ -# Moved - -The crop and farming spec is [systems/crops-and-farming.md](systems/crops-and-farming.md). diff --git a/docs/decisions/0001-food-vs-nutrition.md b/docs/decisions/0001-food-vs-nutrition.md deleted file mode 100644 index cbee903..0000000 --- a/docs/decisions/0001-food-vs-nutrition.md +++ /dev/null @@ -1,24 +0,0 @@ -# 0001 Food amount versus nutrition level - -## Status - -Implemented. Current behavior is [../systems/portions-and-servings.md](../systems/portions-and-servings.md). - -## Decision - -Food is how much a serving fills the character food pool. A whole roast or a full pot is a larger amount than one slice or one scoop. - -Nutrition is the level of that food. A slice has the same nutrition as the roast it came from. A soup scoop has the same nutrition as the pot. Splitting the batch does not dilute the level. - -Diet already treats nutrition as a target level (`NutritionService` lerps diet toward `getFinalNutrition`). Dividing nutrition before that call feeds the diet system the wrong target. - -## Consequences - -- Soup: `pot-soup-scoops` divides template food. It does not divide nutrition. The height divisor stays visual. -- Carve: divide food by edible cuts. Copy nutrition onto the piece and leave the leftover roast's nutrition at the batch level. -- Sausage: summing every meat's nutrition into one chain, then dividing by link count, fights this decision. The chain level should be chosen as a level (for example a composed or averaged level), and each link should keep it. -- Plain roast display that sums per-cut nutrition is also a pile, not a level. - -## Not in this decision - -Star multipliers, tag multipliers, and sauce added on top still apply to whatever level the portion has. Those are modifiers, not portion splits. diff --git a/docs/decisions/0002-source-of-truth.md b/docs/decisions/0002-source-of-truth.md deleted file mode 100644 index a2633a0..0000000 --- a/docs/decisions/0002-source-of-truth.md +++ /dev/null @@ -1,20 +0,0 @@ -# 0002 Which artifact wins - -## Status - -Accepted. - -## Decision - -`src/main/resources` is the config source. `target/` is generated and must not be edited. - -Player wiki pages explain play. `docs/systems` explains implementation. They can both be updated when a player-visible rule changes. The wiki is not a reason to skip the system doc. - -When code, tests, YAML, and docs disagree, the change is blocked until a person states the intended contract and the artifacts match it. An old sentence in the crop and husbandry specs said "if they disagree, change the code." That blanket rule is retired. Locked formulas in those docs are still the contract until an explicit decision replaces them. - -`docs/manifest.json` decides which system doc must move when a path changes. `docs/impact-waiver.md` is the only no-impact escape, and only when that file itself changes in the diff. - -## Consequences - -- Do not copy nutrition or food numbers into a second hand-maintained table when the YAML file is the number. Docs state the rule and the committed value when agents must not guess. -- Known mismatches (`plugin.yml` version versus `pom.xml`, unloaded `cookware.yml`) stay documented until a change is dedicated to them. diff --git a/docs/how-to/add-config-option.md b/docs/how-to/add-config-option.md deleted file mode 100644 index 19d3c9d..0000000 --- a/docs/how-to/add-config-option.md +++ /dev/null @@ -1,8 +0,0 @@ -# Add a config option - -1. Add the key to the YAML in `src/main/resources`, not to a file already copied on the server. Say so in the change notes: existing servers keep the old file until the key is added there. -2. Read it in the loader with a default that matches the behavior you want when the key is missing. -3. Add the file and key to [../reference/configuration.md](../reference/configuration.md) if it is a new file or a new contract. -4. Map the file in `docs/manifest.json` if it is new. -5. Do not load `cookware.yml` for new heat keys. Use `config.yml`. -6. `/cooking reload` picks up YAML. It does not apply SQLite migrations. diff --git a/docs/how-to/add-food-type.md b/docs/how-to/add-food-type.md deleted file mode 100644 index 6981f5c..0000000 --- a/docs/how-to/add-food-type.md +++ /dev/null @@ -1,8 +0,0 @@ -# Add a food type - -1. Add a key to `src/main/resources/types.yml` with `name`, `food`, `nutrition`, and `model` if it has a custom model. -2. Add the model to `models.yml` and the ItemsAdder item if players must see it. -3. If the item should age, set `age` and rely on `tags.yml`. If it must not be rewritten by the scanner, set `update: false`. -4. If another item turns into it, add a `conversions.yml` line or a station output string. -5. Update [../systems/food-items.md](../systems/food-items.md) only if the template rules changed. A new id that follows the existing shape does not need a new paragraph, but the diff still touches `types.yml`, so either update the system doc with a one-line note or file an impact waiver. Prefer a short note in the system doc when the type changes eat math. -6. Run `mvn test` if you touched Java. diff --git a/docs/how-to/add-husbandry-or-crop.md b/docs/how-to/add-husbandry-or-crop.md deleted file mode 100644 index 75d26bf..0000000 --- a/docs/how-to/add-husbandry-or-crop.md +++ /dev/null @@ -1,18 +0,0 @@ -# Add husbandry or crop behavior - -## Crop - -1. Add `crops.yml` with `source`, `block` or CustomCrops id, `seed`, and `affection`. -2. Add the produce conversion in `conversions.yml`. -3. Leave seeds unconverted. Nutmeg seeds are `nut_seeds`. -4. Do not add fertility to CustomCrops YAML. -5. Extend `CropHarvestQualityTest` or `CropGrowthChanceTest` when the formula changes. -6. Update [../systems/crops-and-farming.md](../systems/crops-and-farming.md). - -## Husbandry - -1. Add `species.` capabilities in `husbandry.yml`. -2. New persistence needs a `user_version` migration. -3. A gene-rule change that must reset live animals bumps `stats-revision`. -4. Keep genetics, care, yield, and stars distinct. -5. Update [../systems/husbandry.md](../systems/husbandry.md) and the nearest `Husbandry*Test`. diff --git a/docs/how-to/add-station-recipe.md b/docs/how-to/add-station-recipe.md deleted file mode 100644 index 02d725e..0000000 --- a/docs/how-to/add-station-recipe.md +++ /dev/null @@ -1,9 +0,0 @@ -# Add a station recipe - -1. Pick the station doc: [../systems/cooking-stations.md](../systems/cooking-stations.md) or [../systems/processing-stations.md](../systems/processing-stations.md). -2. Data-only recipes go in `crafting-stations.yml`, `milling-recipes.yml`, or `baking-trays.yml`. -3. Mixing, churn, sausage, and pot counts go in `config.yml`. -4. If the recipe composes stars, confirm the `CompositionContext` and `composition.yml` roles. -5. If the output is carved or scooped, update [../systems/portions-and-servings.md](../systems/portions-and-servings.md). -6. Update the player wiki station table when the click or the result changes. -7. Register a new listener in `Cooking.registerListeners` and the processing doc. diff --git a/docs/how-to/update-docs.md b/docs/how-to/update-docs.md deleted file mode 100644 index c008627..0000000 --- a/docs/how-to/update-docs.md +++ /dev/null @@ -1,21 +0,0 @@ -# Update docs with code - -1. Open `docs/manifest.json` and list every document whose `paths` match your files. -2. Read those documents before editing. -3. Change the doc in the same commit as the behavior. -4. If the change cannot affect behavior (format, comment, rename with no contract change), edit `docs/impact-waiver.md` in that same commit: - -```text -docs-impact: none -reason: Reformatted FoodItem imports only. -``` - -The checker ignores a waiver that was not part of the diff. Replace the reason every time. Do not leave a stale waiver as a permanent bypass. - -5. Run: - -```text -python scripts/test_doc_manifest.py -python scripts/check-links.py -python scripts/check-doc-impact.py -``` diff --git a/docs/husbandry.md b/docs/husbandry.md deleted file mode 100644 index 3595c1e..0000000 --- a/docs/husbandry.md +++ /dev/null @@ -1,3 +0,0 @@ -# Moved - -The husbandry spec is [systems/husbandry.md](systems/husbandry.md). diff --git a/docs/impact-waiver.md b/docs/impact-waiver.md deleted file mode 100644 index 901e63a..0000000 --- a/docs/impact-waiver.md +++ /dev/null @@ -1,10 +0,0 @@ -# Documentation impact waiver - -This file is a bypass only when the same diff that skips system docs also changes this file. - -Leave the marker below unset so a normal behavior change cannot pass by accident. - -```text -docs-impact: none -reason: Paper marks the existing legacy text and serialization APIs deprecated. These source edits add documented method-scoped compatibility annotations only; gameplay, stored data, and configuration remain unchanged. Build changes explicitly retain annotation processing and provide an SLF4J logger for tests. -``` diff --git a/docs/manifest.json b/docs/manifest.json deleted file mode 100644 index af388bb..0000000 --- a/docs/manifest.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "generated_excludes": [ - "target/**" - ], - "known_unloaded": [ - "src/main/resources/cookware.yml" - ], - "satisfy": "any-owner", - "documents": [ - { - "id": "bootstrap", - "document": "docs/architecture/bootstrap.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/Cooking.java", - "src/main/java/net/tfminecraft/cooking/loader/**", - "src/main/java/net/tfminecraft/cooking/cache/**", - "src/main/java/net/tfminecraft/cooking/manager/CommandManager.java" - ] - }, - { - "id": "persistence", - "document": "docs/architecture/persistence.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/husbandry/HusbandryRepository.java" - ] - }, - { - "id": "integrations", - "document": "docs/architecture/integrations.md", - "paths": [ - "src/main/resources/plugin.yml", - "src/main/resources/custom-fishing.yml", - "src/main/java/net/tfminecraft/cooking/fishing/**", - "src/main/java/net/tfminecraft/cooking/crops/CropCustomCropsBridge.java", - "src/main/java/net/tfminecraft/cooking/crops/CropFertility.java" - ] - }, - { - "id": "food-items", - "document": "docs/systems/food-items.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/item/**", - "src/main/java/net/tfminecraft/cooking/utils/FoodParser.java", - "src/main/java/net/tfminecraft/cooking/utils/ItemBuilder.java", - "src/main/java/net/tfminecraft/cooking/utils/ItemUpdater.java", - "src/main/java/net/tfminecraft/cooking/utils/Keys.java", - "src/main/java/net/tfminecraft/cooking/enums/**", - "src/main/resources/types.yml", - "src/main/resources/models.yml", - "src/main/resources/naming.yml" - ] - }, - { - "id": "freshness-tags", - "document": "docs/systems/freshness-tags.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/manager/TagManager.java", - "src/main/java/net/tfminecraft/cooking/utils/WarmthUtils.java", - "src/main/resources/tags.yml" - ] - }, - { - "id": "quality-composition", - "document": "docs/systems/quality-composition.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/quality/**", - "src/main/java/net/tfminecraft/cooking/manager/ConversionManager.java", - "src/main/resources/quality.yml", - "src/main/resources/composition.yml", - "src/main/resources/conversions.yml", - "src/main/resources/permission_effects.yml" - ] - }, - { - "id": "cooking-stations", - "document": "docs/systems/cooking-stations.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/cooking/**", - "src/main/java/net/tfminecraft/cooking/heat/**", - "src/main/java/net/tfminecraft/cooking/oven/**", - "src/main/java/net/tfminecraft/cooking/liquid/**", - "src/main/java/net/tfminecraft/cooking/manager/PlateManager.java", - "src/main/java/net/tfminecraft/cooking/events/**", - "src/main/resources/config.yml" - ] - }, - { - "id": "processing-stations", - "document": "docs/systems/processing-stations.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/crafting/**", - "src/main/java/net/tfminecraft/cooking/baking/**", - "src/main/java/net/tfminecraft/cooking/milling/**", - "src/main/java/net/tfminecraft/cooking/mixing/**", - "src/main/java/net/tfminecraft/cooking/churn/**", - "src/main/java/net/tfminecraft/cooking/sausagemaker/**", - "src/main/java/net/tfminecraft/cooking/hook/**", - "src/main/java/net/tfminecraft/cooking/trough/**", - "src/main/resources/crafting-stations.yml", - "src/main/resources/baking-trays.yml", - "src/main/resources/milling-recipes.yml", - "src/main/resources/config.yml" - ] - }, - { - "id": "portions", - "document": "docs/systems/portions-and-servings.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/carve/**", - "src/main/resources/carve-sequences.yml" - ] - }, - { - "id": "nutrition", - "document": "docs/systems/nutrition.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/nutrition/**", - "src/main/java/net/tfminecraft/cooking/cup/**", - "src/main/resources/config.yml" - ] - }, - { - "id": "crops", - "document": "docs/systems/crops-and-farming.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/crops/**", - "src/main/java/net/tfminecraft/cooking/farming/**", - "src/main/resources/crops.yml", - "src/main/resources/farming.yml", - "src/main/resources/conversions.yml", - "CustomCrops/**" - ] - }, - { - "id": "husbandry", - "document": "docs/systems/husbandry.md", - "paths": [ - "src/main/java/net/tfminecraft/cooking/husbandry/**", - "src/main/resources/husbandry.yml" - ] - }, - { - "id": "configuration-reference", - "document": "docs/reference/configuration.md", - "paths": [ - "src/main/resources/plugin.yml" - ] - }, - { - "id": "commands", - "document": "docs/reference/commands-permissions.md", - "paths": [ - "src/main/resources/plugin.yml" - ] - }, - { - "id": "external-assets", - "document": "docs/reference/external-assets.md", - "paths": [ - "ItemsAdder/tfmc_cooking/contents/**" - ] - } - ] -} diff --git a/docs/reference/commands-permissions.md b/docs/reference/commands-permissions.md deleted file mode 100644 index b9b53e5..0000000 --- a/docs/reference/commands-permissions.md +++ /dev/null @@ -1,23 +0,0 @@ -# Commands and permissions - -Players have no Cooking command. The wiki records that on purpose. - -Bukkit command: `cooking`. Permission: `cooking.admin` (default op). - -| Usage | Role | -| --- | --- | -| `/cooking reload` | reload YAML, rebuild stations, restart drain and husbandry ticks, apply stats revision | -| `/cooking builditem ` | create a food from a FoodParser string, with or without `c.` | -| `/cooking preview ...` | admin preview. Mixing bowl is the supported target | -| `/cooking food ...` | admin food debug | -| `/cooking husbandry spawn [genetics] [care]` | spawn an untamed row | -| `/cooking husbandry save` | flush loaded animals | -| `/cooking heat` | heat debug | -| `/cooking nametest` | name debug | -| `/cooking qualitytest` | quality debug | - -There is no `/cooking crop` and no BreedingBuddies command. - -Permission nodes that change rolls live in `permission_effects.yml`. Crop pickup uses `tfmc.cooking.better_crops` after the harvest roll. - -`plugin.yml` does not list every subcommand. `CommandManager` is the list that runs. diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md deleted file mode 100644 index 85c74ca..0000000 --- a/docs/reference/configuration.md +++ /dev/null @@ -1,35 +0,0 @@ -# Configuration reference - -Repo source: `src/main/resources`. Server copies are created only if missing. Load order is [../architecture/bootstrap.md](../architecture/bootstrap.md). - -| File | Loader | Owns | -| --- | --- | --- | -| `config.yml` | `ConfigLoader`, `NutritionConfig`, heat and item caches | furniture ids, tools, mixing, oven, liquids, trough, nutrition and variety, logging | -| `models.yml` | `ModelLoader` | item model stages | -| `types.yml` | `FoodLoader` | food templates | -| `baking-trays.yml` | `BakingTrayLoader` | oven mould recipes | -| `milling-recipes.yml` | `MillingRecipeLoader` | milling stone recipes | -| `crafting-stations.yml` | `CraftingStationLoader` | cutting board and similar | -| `tags.yml` | `TrackLoader` | tag tracks and multipliers | -| `naming.yml` | `NamingLoader` | name tokens | -| `quality.yml` | `QualityConfigLoader` | star multipliers and pickup range | -| `composition.yml` | `CompositionConfigLoader` | roles and modifiers | -| `permission_effects.yml` | `PermissionEffectsLoader` | post-roll permission bumps | -| `conversions.yml` | `ConversionLoader` | vanilla/IA to Cooking food | -| `farming.yml` | `FarmingLoader` | vanilla hoe crop list | -| `crops.yml` | `CropsLoader` | affection, seed, source | -| `husbandry.yml` | `HusbandryLoader` | livestock tuning | -| `carve-sequences.yml` | `CarveSequenceLoader` | roast and sausage cuts | -| `plugin.yml` | Bukkit | name, version, depend, command | -| `custom-fishing.yml` | `CustomFishingCatalog` | live catch ids, cut class, rod quality bands, vanilla fish default sizes, seafood cutting yield, `model-data`, `legacy-size-cm` | -| `cookware.yml` | none | shipped, not loaded. Heat lives in `config.yml` | - -## Packaging - -Maven filters `plugin.yml`'s `${project.version}` into the embedded plugin version. CI development builds use `DEV-YYYYMMDD-HHmm` in UTC; numeric release tags must match the POM version. Other resource files are copied without Maven filtering. - -Private compile dependencies are pinned in `.github/scripts/prepare-release.sh` and `.github/dependencies.sha256`. See the [shared pipeline guide](https://github.com/TF-Minecraft/Docs/blob/main/PIPELINES.md) for dependency access and release artifacts. - -## Adding a key - -[../how-to/add-config-option.md](../how-to/add-config-option.md). diff --git a/docs/reference/external-assets.md b/docs/reference/external-assets.md deleted file mode 100644 index 69431af..0000000 --- a/docs/reference/external-assets.md +++ /dev/null @@ -1,51 +0,0 @@ -# External asset ids - -Cooking config stores ids. The resource packs store the models and items. They must match. - -## ItemsAdder - -Namespace `tfmc_cooking` under `ItemsAdder/tfmc_cooking/`. - -Contents YAML: - -- `contents/items.yml` -- `contents/ingredients.yml` -- `contents/intermediates.yml` -- `contents/furniture.yml` -- `contents/categories.yml` - -Typical paths in `config.yml`: `ia.tfmc_cooking:ladle`, `cutting_knife`, `water`, `flour`, `butter`. - -CustomCrops seeds use `ia.playbox_custom_crops:_seeds`, except nutmeg: `ia.playbox_custom_crops:nut_seeds`. - -Produce items are `tfmc_cooking:` (example `tfmc_cooking:tomato`). - -Seafood portions use raw, cooked, burnt, boiled, and rotten items: `fish_filet_*`, `jellyfish_cubes_*`, and `octopus_*`. Red-meat steak and poultry filet also have `red_meat_steak_boiled` and `poultry_roast_filet_boiled`. There is no boiled poultry-leg or pork item. - -## InteractibleFurniture - -Type ids in `config.yml` match furniture definitions: `frying_pan`, `saucepan`, `pot`, `bowl`, `mixing_bowl`, `milling_stone`, `trough`, `butter_churn`, `butter_plate`, `fire_pit`, `meat_hook`, `sausage_maker`, `oven_bottom`, `oven_top`, `liquid_container`, `plate`. - -## CustomCrops - -Crop ids in `crops.yml` `source: customcrops` match `CustomCrops/contents/crops/.yml`. - -Do not put fertility keys in those YAML files. - -Keep downloaded CustomCrops libraries out of Git. To distribute the current -tracked configuration, create an archive from the commit you are deploying: - -```sh -git archive --format=zip --output=CustomCrops.zip HEAD CustomCrops -``` - -The generated ZIP and `CustomCrops/libs/` are ignored; the YAML files in -`CustomCrops/` are the source of truth. - -## Vanilla TLibs - -`v.water_bucket`, `v.wheat_seeds`, `v.shears`, `v.bone`, and similar. `m.` paths are the materials plugin, used by husbandry drops. - -## Generated files - -Do not edit `target/`. Do not treat `ItemsAdder/**/resourcepack/**` model JSON as the gameplay spec. Behavior lives in Java and the YAML listed in [configuration.md](configuration.md). diff --git a/docs/reference/item-pdc.md b/docs/reference/item-pdc.md deleted file mode 100644 index 1b06484..0000000 --- a/docs/reference/item-pdc.md +++ /dev/null @@ -1,41 +0,0 @@ -# Item persistent data - -Namespace is the Cooking plugin. Keys are declared in `src/main/java/net/tfminecraft/cooking/utils/Keys.java`. - -| Key | Stores | -| --- | --- | -| `food_id` | type id | -| `food_category` | category | -| `food_origin` | origin | -| `food_quality` | star | -| `food_base` | overridden food amount | -| `food_nutrition_base` | overridden nutrition level | -| `food_state` | extra state string | -| `food_model` | model id | -| `tags` | serialized tracks | -| `age_remainder` | fractional age | -| `last_update` | last aging timestamp | -| `lore_index` | lore lines owned by the plugin | -| `sauce` | linked sauce item data | -| `sauce_name` | sauce display name | -| `carve_sequence` | sequence id | -| `carve_next_index` | next cut | -| `carve_remaining` | cuts left including non-food | -| `slot_data` | encoded station slots on a scooped item | -| `food_ingredients` | short name ingredient list | -| `food_lineage` | versioned main and extra origins | -| `cook_method` | active cook method | -| `cook_time` | cook progress | -| `catch_size_cm` | rounded catch length in centimetres | -| `seafood_cut_type` | `fish`, `octopus`, or `jellyfish` | -| `custom_fishing_id` | CustomFishing loot id | - -Player PDC, same Cooking namespace: - -| Key | Stores | -| --- | --- | -| `variety_history` | rolling eaten meals for nutrition variety | - -`food_base` and `food_nutrition_base` are removed when the item has no base override. - -Entity PDC used by husbandry is separate and listed in [../systems/husbandry.md](../systems/husbandry.md). diff --git a/docs/systems/cooking-stations.md b/docs/systems/cooking-stations.md deleted file mode 100644 index f506983..0000000 --- a/docs/systems/cooking-stations.md +++ /dev/null @@ -1,81 +0,0 @@ -# Active cooking, heat, liquids, plates - -## Purpose - -Heated furniture turns ingredients into cooked food: frying pan, saucepan, pot, oven, and liquid containers. Plates and bowls serve an item a player can eat. - -## Vocabulary - -- **Heat source / consumer:** ids in `config.yml` `heat`. A pan or pot cooks only when a source below it is hot. -- **Pot scoop:** one ladle serving. Count is `pot-soup-scoops` (committed value 3). The visual drain uses `pot-soup-height-divisor` (committed value 4) and is not the food split. -- **Bowl:** furniture the player pours a scooped soup into before eating. - -## Invariants - -- Cooking time in station config is real seconds, ticked about once per second by `CookingManager`. -- Frying burns when left past the method's burn time. -- Soup exists only after a pot slot is mashed (`Tag.MASHED`). Ladle before that does nothing useful (`scoop` returns immediately). -- A mash applies to any `mashable` item already in the pot. It sets that item's `cooked` track to `3` (boiled), stops the pot timer so burn cannot replace it, and the ladle copies every visible pot ingredient, including mashed ones, onto the bowl. -- The pot has five main slots (`input_1` through `input_5`). A sixth main is refused. After the pot is soup, one garnish, one spice, one salt, and one pepper are stored on the pot with no visible slot (`pot.extras`). They still season the scoop. They are not copied onto the bowl model. -- Each soup scoop clones the `soup` type, then sets food to template food / `pot-soup-scoops`. Nutrition stays the template level. A valuable ingredient adds Flavourful (+10% nutrition, food unchanged). See portions. -- Sauce scoops clone the `sauce` type: full template food and nutrition, quality from composition. A valuable ingredient adds Flavourful the same way as soup. Soup and sauce store the slot origins as lineage. A nested sauce keeps that lineage on the plated food. -- Oven fuel and burn rates are `config.yml` oven keys, not `cookware.yml`. - -## Inputs and outputs - -Players place items through InteractibleFurniture. Water bucket fills a pot (`pot-water-input`). Ladle and masher ids are `config.yml` `ladle` and `masher`. - -Pot output is one soup item in the ladle hand, with seasoning/addon tags and a thickness track copied from the pot. - -## State and persistence - -Live station contents stay in the furniture. Scooped soup may store encoded slot data in `slot_data` PDC. - -Liquid containers track block fill (`liquid-blocks-per-bucket`, `liquid-max-blocks`, `liquid-blocks-per-cup`) and age while stored. - -## Runtime flow - -```text -furniture click - -> station reference (FryingReference, SauceReference, PotReference) - -> heat gate - -> cook seconds advance - -> take or scoop builds a FoodItem - -> DishCookedEvent -``` - -Oven: `OvenBurnManager` consumes fuel and exposes heat to consumers. Bread trays are a processing station that only bake while the oven is lit. - -## Configuration - -Furniture ids and heat graph: `config.yml`. - -Food method times: `types.yml` `cooking-options` (`fire_pit`, `frying_pan`, and similar). - -## Integrations - -InteractibleFurniture type ids must match `config.yml`. ItemsAdder ids must match ladle, masher, water, and liquid blocks. - -## Edge cases - -- `pot-soup-height-divisor` can differ from `pot-soup-scoops`. Do not use the height divisor as a food divider. -- Empty-hand take versus tool use is station-specific. Read the reference class before changing a click. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/cooking/` -- `src/main/java/net/tfminecraft/cooking/heat/` -- `src/main/java/net/tfminecraft/cooking/oven/` -- `src/main/java/net/tfminecraft/cooking/liquid/` -- `src/main/java/net/tfminecraft/cooking/manager/PlateManager.java` -- `src/main/java/net/tfminecraft/cooking/nutrition/BowlEatHandler.java` -- `src/main/resources/config.yml` - -## Tests - -`IngredientLineageTest` covers soup, sauce, and frying lineage. `PotMashTest` covers mash acceptance. Nutrition death food is covered by `NutritionDeathFoodTest`. - -## Change checklist - -- New furniture id: `config.yml`, external asset reference, player wiki if the click changes. -- Soup serving math: portions doc and `PotReference.scoop`. diff --git a/docs/systems/crops-and-farming.md b/docs/systems/crops-and-farming.md deleted file mode 100644 index eb67d55..0000000 --- a/docs/systems/crops-and-farming.md +++ /dev/null @@ -1,134 +0,0 @@ -# Crops and farming - -## Purpose - -Crop stars and growth cancel live in Cooking. CustomCrops is the plant engine for custom crops. SimpleFactions owns province fertility (0-100 lookup only). Vanilla hoe crops use `farming.yml`. - -Seeds stay dumb ItemsAdder or vanilla items: no `food_quality`, no planted-crop SQL, no plant-to-harvest lineage. - -## Vocabulary - -- **Produce:** the drop that becomes Cooking food. -- **Seed:** the drop left as a seed. Not Cooking food. -- **Affection:** per-crop weight in `crops.yml`, used for both harvest stress and grow chance. -- **H:** harvest star in 1-5 before the item is built. - -## Invariants - -| Piece | What it is | What it is not | -| --- | --- | --- | -| Seeds | IA/vanilla seed stacks from CustomCrops yield and Dowsing | Not Cooking food. Not `food_quality`. Not `c.seed` | -| Harvest food | Conversion of dropped IA/vanilla produce at quality H | Not a `food:` line on the crop. Not MMOItems. Not IA star variants | -| Harvest roll | Weighted 1-5 from fertility times affection, then pickup permissions | Not planted-seed lineage. Never zero weight on 5 | -| Growth gate | `(fertility/100)^affection` per grow tick. Fertility 0 never grows; 100 always grows | Not harvest stars. Not bone meal | -| Fertility | SimpleFactions province 0-100 at the block | Not a second weight file in SimpleFactions | -| Permissions | `tfmc.cooking.better_crops` and other pickup effects after the roll | Does not affect grow ticks | - -Generic pickup conversion of farm produce is still quality 1 via `CropsConfig.isFarmFood`. Potato and carrot are produce, not seeds, for that pickup path. - -If this document and the code disagree, stop and reconcile them. Do not treat either as automatically winning. - -## Inputs and outputs - -CustomCrops loot drops `tfmc_cooking` produce and IA seeds. Cooking converts produce through `conversions.yml` at H. Configured seed drops stay unchanged. - -Dowsing farm tables drop plain IA seeds (`ia.playbox_custom_crops:..._seeds`). - -## State and persistence - -No crop SQL. Fertility is read at the block when a tick or harvest happens. - -## Runtime flow - -Harvest: - -```text -Province fertility 0-100 x crops.yml affection - -> stress = (1 - fertility/100) * affection - -> lerp rich -> poor star weights - -> sample H in 1-5 (every star weight > 0) - -> OriginQualityResolver.applyPickupPermissions - -> (hoe) HoeQualityBonus - -> convert produce via conversions.yml at H - -> leave seed-only drops unchanged - (wheat, beetroot, melon, pumpkin seeds) -``` - -Potato and carrot are produce. Hoe harvest reserves one vanilla stack for replant, then converts leftover drops. Nether wart is still harvested and replanted, and the drop stays vanilla. - -Growth: - -```text -growth-gate.enabled and SimpleFactions map active - -> affection from crops.yml - -> growChance = (fertility/100) ^ affection - -> vanilla: cancel BlockGrowEvent on fail - -> CustomCrops: Cooking wraps loaded grow-conditions -``` - -Unlisted blocks are not gated. `growth-gate.enabled: false` or map off: all ticks allowed. Growth does not cancel when the map is off. - -## Configuration - -`crops.yml`: `seed`, `source`, `block`, `affection`. No `food:` on crops. - -Stress is 0 at fertility 100. At fertility 0, stress equals affection. Missing or invalid affection uses 0.5, clamped to `(0, 1]`. - -Default star weights in code/config (rich then poor, stars 1-5): - -- rich: `8, 16, 28, 28, 20` -- poor: `40, 28, 18, 10, 4` - -After lerp, each weight is clamped above 0, normalized, and sampled. - -`farming.yml` lists vanilla hoe crops: wheat, potatoes, carrots, beetroots, nether wart. Melon and pumpkin fruit harvest is out of scope. Stems are growth-gated. - -## Integrations - -| | Vanilla hoe | CustomCrops | -| --- | --- | --- | -| Crop id | lowercase block, e.g. `wheat` | CC id, e.g. `tomato` | -| Seed path | `v.wheat_seeds`, `v.potato`, ... | `ia.playbox_custom_crops:tomato_seeds` | -| Nutmeg seed | n/a | `ia.playbox_custom_crops:nut_seeds` (not `nutmeg_seeds`) | -| Produce | vanilla item | `tfmc_cooking:` | -| Harvest | hoe: roll H, convert produce, leave seeds. Drop-less `BlockBreakEvent` so MMOCore crop XP still applies | `CropBreakEvent` / mature interact | -| Growth | `CropGrowthListener` | wrapped grow-conditions; affection only from `crops.yml` | - -Cooking injects the fertility check on enable and on `/customcrops reload`. CustomCrops YAML must not mention fertility. - -Deploy the tracked `CustomCrops/` configuration. Downloaded libraries and the old -configuration ZIP are not versioned; regenerate any deployment archive using the -[external asset instructions](../reference/external-assets.md#customcrops) so old -fertility rules cannot replace the current YAML. - -TLibs `c` paths: see [food-items.md](food-items.md). There is no `c.seed` path and no `/cooking crop` command. - -## Edge cases - -- Potato and carrot `seed:` is the same vanilla item as produce. Do not skip conversion just because the drop matches `seed:`. Nether wart uses the same item as its seed and is not converted. -- Hoe harvest still keeps one untagged stack to replant. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/crops/` -- `src/main/java/net/tfminecraft/cooking/farming/` -- `src/main/resources/crops.yml` -- `src/main/resources/farming.yml` -- `src/main/resources/conversions.yml` - -## Tests - -- `CropsConfigTest` -- `CropHarvestQualityTest` -- `CropGrowthGateTest` -- `CropGrowthChanceTest` -- `CropHarvestItemsTest` - -## Change checklist - -- New crop: [../how-to/add-husbandry-or-crop.md](../how-to/add-husbandry-or-crop.md). -- Out of scope: seed quality, planted-crop SQLite, soil tending that changes quality while growing. - -## Player wiki - -`/wiki/farming` and `/wiki/harvesting`. This file remains the implementation spec. diff --git a/docs/systems/food-items.md b/docs/systems/food-items.md deleted file mode 100644 index 0c1c262..0000000 --- a/docs/systems/food-items.md +++ /dev/null @@ -1,93 +0,0 @@ -# Food items - -## Purpose - -A Cooking food item is a Bukkit stack plus PDC. `types.yml` is the template. Runtime code may override food, nutrition, quality, origin, tags, sauce, and carve progress. - -## Vocabulary - -- **Type id:** key under `types.yml`, stored as `food_id`. -- **Origin:** ingredient or species name (`Chicken`, `Beef`, `Mixed`). Overrides pick name, model, and carve sequence. `Mixed` is a display placeholder, not an ingredient. -- **Lineage:** ordered main and extra origins stored on the item. The short `ingredients` list is only for dish names. -- **Category:** grouping used by composition roles (`meat`, `seasoning`, `dairy`). -- **Base override:** item-specific `food_base` / `food_nutrition_base`, set when code calls `setBaseFood` or `setBaseNutrition`. -- **Final food / final nutrition:** base value after quality and tag multipliers, plus sauce. - -## Invariants - -- Templates come from `types.yml`. A crop entry does not define a second `food:` stat. -- `update: false` on a type skips the live item-scan rewrite. Default is true (`FoodItem` reads `update`, default true). Seasoning and sweetener templates set `update: false`. -- `valuable: true` marks CustomCrops produce (`vegetable_2`, `vegetable_cut_2`, `vegetable_chopped_2`, `fruit_2`). Vanilla `vegetable_1` and `fruit_1` are not valuable. Soup and sauce turn that flag into the Flavourful tag. -- `edible: false` marks an intermediate item. `seafood_whole` is a CustomFishing catch or a plain vanilla fish: it keeps the source material and model, stores size and cut class, and can be eaten raw. Its food is 6 and its nutrition is 6, with freshness 2.33, the same shape as a raw carrot. Its name is `#6fa8dc{inherit}`, so a plain vanilla name such as Cod or Salmon is coloured like the other ingredients. A catch that already has a coloured display name keeps that colour. CustomFishing also stores the loot id. Cutting it produces one `seafood_fish_filet` (food 6, nutrition 6), one `seafood_jellyfish` (food 5, nutrition 5), or one `seafood_octopus` (food 7, nutrition 7). Those portions stay edible. Their models include cooked, burnt, and boiled states, and rotten still wins over those states. Those models do not set a display rotation, same as cut carrot, so the piece lies flat on the cutting board. Each portion has a pot option (`tag: 3`, 15 seconds, burn at 30). Default edible is true. -- `mashable: true` marks a type the pot can mash after it is boiled. That is `vegetable_cut`, `vegetable_cut_2`, `meat_red_meat`, `meat_poultry`, and the three seafood portions. `meat_red_meat` and `meat_poultry` keep their frying-pan options and gain the same pot option. `meat_poultry_leg`, `meat_pork`, and `seafood_whole` are not mashable and have no pot option. Default mashable is false. -- A raw item with no lineage contributes its origin when it is composed. Blank origins and `Mixed` are ignored. An item that already has lineage keeps those main and extra buckets. -- `IngredientLineage.forEat` is what nutrition records: the item lineage, or its origin when that list is empty, merged with the nested sauce. -- Quality stars multiply nutrition through `quality.yml` `nutrition-from-quality`. Food uses `1.0 + (stars - 1) * 0.20`. -- Tag steps multiply food and nutrition separately (`food-mult`, `nutrition-mult`). -- Sauce food and nutrition are added after those multipliers. -- A carvable item with remaining cuts reports food and nutrition from [portions-and-servings.md](portions-and-servings.md), not the raw template, while `carve_remaining > 0`. - -## Inputs and outputs - -Input: TLibs path or FoodParser string (`meat(type=roast;origin=Chicken)`), optionally prefixed `c.`. - -Output: one stamped `ItemStack`. `/cooking builditem` accepts the string with or without `c.`. - -## State and persistence - -See [../reference/item-pdc.md](../reference/item-pdc.md). Lore is rebuilt from tracks and final stats. `lore_index` remembers which lore lines the plugin owns. - -## Runtime flow - -1. `FoodLoader` builds templates. -2. `FoodParser` clones a template and applies origin, tags, and quality range. -3. `ItemBuilder` stamps PDC and lore. -4. Later edits go through `ItemUpdater` so the stack and `FoodItem` stay aligned. - -## Configuration - -- `types.yml`: id, name, model, food, nutrition, category, age, cooking-options, overrides, carve-sequence, update, edible, mashable -- `models.yml`: ItemsAdder model data per stage and tag -- `naming.yml`: prefix/filler tokens used in display names - -## Integrations - -TLibs creates the visual item. ItemsAdder supplies models. Path prefix `c` is food only. - -## Edge cases - -- Missing model falls back inside `FoodModel`. -- `quality=2` is exact. `quality=1-3` rolls inclusive. -- Extra path fields (`quality`, `origin`, `tags`) are ignored when matching an existing item. They matter when creating. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/item/FoodItem.java` -- `src/main/java/net/tfminecraft/cooking/utils/FoodParser.java` -- `src/main/java/net/tfminecraft/cooking/utils/ItemBuilder.java` -- `src/main/java/net/tfminecraft/cooking/utils/ItemUpdater.java` -- `src/main/java/net/tfminecraft/cooking/item/CookingPathHandler.java` -- `src/main/java/net/tfminecraft/cooking/loader/FoodLoader.java` -- `src/main/resources/types.yml` -- `src/main/resources/models.yml` -- `src/main/resources/naming.yml` - -## Tests - -- `CookingPathHandlerTest` -- `FoodItemUpdateFlagTest` -- `PortionRulesTest` -- `ValuableIngredientTest` -- `IngredientLineageTest` -- `SeafoodWholeItemTest` -- `CookStateAssetsTest` -- `PotMashTest` -- `StackNormalizerTest` -- `ItemLoreRebuildTest` -- `ItemCacheOriginTest` - -## Change checklist - -- New type: follow [../how-to/add-food-type.md](../how-to/add-food-type.md). -- New PDC field: persistence doc and PDC reference. -- Changing final-stat math: update this doc and nutrition, because eat uses `getFinalFood` and `getFinalNutrition`. diff --git a/docs/systems/freshness-tags.md b/docs/systems/freshness-tags.md deleted file mode 100644 index 5960319..0000000 --- a/docs/systems/freshness-tags.md +++ /dev/null @@ -1,75 +0,0 @@ -# Freshness, tags, and aging - -## Purpose - -Tag tracks are named meters on a food item: freshness, cooked, warmth, sauce thickness, soup thickness, and similar. Steps inside a track change the name, model, and food/nutrition multipliers. - -## Vocabulary - -- **Track:** one meter (`freshness`). -- **Step:** a threshold on that meter (`fresh`, `stale`, `rotten`) with multipliers. -- **Age scale:** `types.yml` `age.` speeds or slows that track for one type. -- **Remainder:** fractional age stored so slow tracks do not lose progress to integer ticks. - -## Invariants - -- `tags.yml` defines the tracks. `types.yml` `age` only scales them. -- Food multipliers and nutrition multipliers are independent. A consistency step can raise food more than nutrition. -- `flavourful` is nutrition-mult 1.1 and food-mult 1.0. One valuable ingredient on a soup or sauce applies it. It does not replace aromatic, rounded, or seasoning. -- Rotten freshness is a cook-tag override for roast models (`CarvableRoastUtils.resolveCookTag`). -- Types with `update: false` do not get scan rewrites. Do not rely on aging for those templates. -- Warmth is a track, not a second plugin. - -## Inputs and outputs - -`TagManager` subscribes to TFMCCore `ItemScanService`. Each scan advances age from `last_update` and remainder, then `ItemUpdater` rewrites lore and model. - -Stations add or copy tracks (cooked, warmth, thickness) when they finish a step. - -## State and persistence - -PDC: `tags`, `age_remainder`, `last_update`. - -## Runtime flow - -```text -scan tick - -> elapsed since last_update - -> add remainder - -> advance each track by age scale - -> store new remainder and timestamp - -> rebuild lore -``` - -## Configuration - -`tags.yml` steps include `name`, `value`, `food-mult`, and `nutrition-mult`. - -Committed consistency nutrition multipliers (light, creamy, velvety, thick) are lower than their food multipliers. Read the file before assuming they match. - -## Integrations - -TFMCCore must be present. Cooking does not run its own global item scanner. - -## Edge cases - -- Held warmth logic is in `WarmthUtils`, covered by `WarmthUtilsTest`. -- Copying tracks onto a carved piece copies cooked, freshness, and warmth only (`CarvableRoastUtils.copyInheritedTracks`). - -## Source map - -- `src/main/java/net/tfminecraft/cooking/manager/TagManager.java` -- `src/main/java/net/tfminecraft/cooking/item/tag/` -- `src/main/java/net/tfminecraft/cooking/utils/WarmthUtils.java` -- `src/main/resources/tags.yml` - -## Tests - -- `AgeScaleTest` -- `WarmthUtilsTest` -- `ItemLoreRebuildTest` - -## Change checklist - -- New track: `tags.yml`, loader, and any station that should apply it. -- Multiplier change: this doc if the rule changes; the YAML file is the number. diff --git a/docs/systems/husbandry.md b/docs/systems/husbandry.md deleted file mode 100644 index bc29d98..0000000 --- a/docs/systems/husbandry.md +++ /dev/null @@ -1,183 +0,0 @@ -# Husbandry - -## Purpose - -Livestock lives in Cooking. BreedingBuddies is a reference for genetics, ownership, and mounts only. Do not port friendship, stable chunks, bundles, IRL day-change, or async simulation. - -Numbers below that name a committed value were read from `src/main/resources/husbandry.yml`. If the YAML changes, this section's numbers must change in the same diff. Formulas are the contract even when tuning changes. - -If this document and the code disagree, stop and reconcile them. - -The anvil naming listener reads rename text from `AnvilView` on the supported -1.21.10 API. Blank names leave the result unchanged; a matching tame item keeps -the entered name through its existing persistent-data field. - -## Vocabulary - -| Stat | What it is | What it is not | -| --- | --- | --- | -| Genetics | 0-1000, from breeding (wild roll up to `initial-genetic-max`, committed 20). Mount health/speed/jump use genetics and care. Stored genes do not drift from the animal's own care | Not a food-quality field. Parent care only scales the offspring gene bonus | -| Care | 0 to `care-max` (committed 200). Loaded happy time raises it. Neglect lowers it | Does not rewrite genes. Does not pick star quality | -| Hungry / Dirty | Negative states. Stop care-up. After grace, cause decay. Block breeding | Not friendship | -| Yield | `care / care-max`. Multiplies amount (roast cuts, wool count) | Does not change stars | -| Stars | `food_quality` 1-5 from raw genetics via `quality-from-genetics` | Not averaged with care | - -Effective genetics for amounts: `genetics * (care / care-max)`. Care 0 yields 0% amount, still honoring `min-roast-cuts` (committed 1). Care 100 of 200 yields 50%. Care 200 yields 100%. - -GUI yield percent is `round(100 * effectiveGenetics / max-genetics)` where `effectiveGenetics = floor(genetics * care / care-max)`. - -## Invariants - -Kept from the BreedingBuddies idea, scaled to 0-1000: - -- Child genes: parent average, plus variance, plus slowdown when parents are already high, plus parent care. -- Committed breeding tuning: `genetic-variance-multiplier` 0.2, `genetic-slowdown-divisor` 0.6, `care-influence` 0.02 (about +20 at genetics cap 1000 when care is full). -- Ownership and co-ownership tokens. Tame plus name. Mount ranges. Neutering for every husbandry species. Inspect GUI with care and genetics bars. - -Not in this plugin: friendship, stable chunks, bundles, UTC day-change, async world work, MMOItems ids, deleting a row because `Bukkit.getEntity` is null. - -The old 6-arg constructor bug that forced the name `???` must not return. Persist `name` and call `setCustomName`. Never default to `???`. - -## Inputs and outputs - -Owned mature death: `slaughter.meat` plus star-gated `slaughter.drops`. Immature: no Cooking roast. Unowned `remove-unowned` types: no drops. - -Stars from raw genetics. Amount from effective genetics, including `carve_remaining` on roasts. Counted drop tables use that yield. Minimum roast cuts still apply. - -Sheep: vanilla wool always on shear. If `wool_ready_at` is due, also roll `shear.drops`, then reset the timer. Committed global `wool-timer` is 4h. A species may override it. - -Milk: species `milk: true`, `milk-cooldown` (committed 20m), mature only, empty bucket. Result is cooking `milk_bucket` with quality from the animal and Cow or Goat origin from the entity. `MilkBucketConverter` must use that animal. - -Eggs: chickens with `egg` set, loaded, mature, and happy, after `egg-timer` (committed 10m) on the 1-minute tick. `vanilla` means `Material.EGG`. Managed chickens do not also drop vanilla eggs. - -Shed: species with `shed.drops`, same gates, `shed-chance` (committed 0.15) after `shed-timer` (committed 4h). - -## State and persistence - -SQLite file `Data/husbandry.db` is the record. Main thread, WAL. Write on ownership change, tick flush, death, chunk unload, and disable. - -PDC on the entity is not the database. Flags: `managed`, `tame_name`, `linked_animal`. - -Do not delete an owned row because the entity is unloaded. Unowned listed types are deleted on chunk load, except horse, donkey, mule, and camel that already have a row (enroll on first interact; they stay until tamed). - -Owned entities: `setPersistent(true)`, `setRemoveWhenFarAway(false)`. - -### Schema - -`animals`: `uuid`, `type`, `name`, `genetics`, `care`, `stats_revision`, `hungry_since`, `dirty_since`, `last_processed_at`, `unloaded_at`, `affliction_elapsed`, `affliction_at`, `last_milk_at`, `wool_ready_at`, `shed_ready_at`, `egg_ready_at`, `mature_at` (null means adult), `neutered`, plus care remainders added by migration. - -`owners`: `animal_uuid`, `player_uuid`, `role` (`owner` or `coowner`). Unique pair. Count versus `max-animals` (committed 15). Co-ownership counts for every owner. - -### Migrations - -Run when the database opens, not on `/cooking reload`. - -| user_version | Change | -| --- | --- | -| 0 to 2 | Existing genetics divided by 10, cap 1000 | -| 2 to 3 | `mature_at` | -| 3 to 4 | `shed_ready_at` | -| 4 to 5 | `egg_ready_at` | -| 5 to 6 | care up/down remainders | -| 6 to 7 | `stats_revision` | - -`stats-revision` (committed `"1"`) wild-resets genetics and care when the stored id differs. Blank skips the wipe. Owners, name, state, neuter, `mature_at`, and harvest timers stay. Bump the id when gene rules change. - -Bred but untamed animals get an UNTAMED row for the same loaded visit. They despawn on chunk load if still unowned. Tame with no row inserts wild genetics then claims. Death deletes animal and owner rows. - -## Runtime flow - -Care simulation runs on chunk load (`HusbandrySimulator.catchUp`) and on a 1-minute tick while loaded. Egg and shed harvest run on the tick only, not on catch-up. Maturity runs on both. - -```text -elapsed = now - last_processed_at -unloaded = unloaded_at set ? min(elapsed, now - unloaded_at) : 0 -loaded_part = elapsed - unloaded -``` - -Order: - -1. Decay first, full elapsed, no cap, if Hungry and/or Dirty already existed. After `min(since) + decay-grace`, lose care by `floor(decay_seconds / care.down.interval) * care.down.amount`. Keep original `*_since`. -2. Unloaded care gain only if they were happy at unload, capped by `offline-care`. If a negative already existed, unloaded gain is zero. -3. If `unloaded > long-unload-force` and still no negative, apply Hungry or Dirty 50/50. If one exists, add the other. Do not move the old `since`. -4. Loaded affliction uses `loaded_part` after `min-loaded`. At `affliction_at`, apply a missing state. Reroll the next threshold between `affliction.min` and `affliction.max`. -5. Loaded care gain while happy has no cap. -6. Stamp `last_processed_at`. Clear `unloaded_at` while loaded. Set it on unload. - -Committed clocks: care up +1 per 1m while happy; care down -1 per 10h; `min-loaded` 60s; `decay-grace` 24h; `offline-care` 8h; `long-unload-force` 8h; affliction mean 6h, min 4h, max 8h. - -Pulse-loading under `min-loaded` counts as still unloaded. - -Happy means neither Hungry nor Dirty. Feed clears Hungry and consumes 1. Glove clears Dirty and is not consumed. Clearing a state does not add care. - -Breeding: - -```text -avg = (mother + father) / 2 -child = clamp(avg + bonus * careRatio + careExtra, 0, maxGenetics) -``` - -`careRatio` is average parent care / `care-max`. Cancel if either parent is Hungry, Dirty, neutered, or still growing. Baby care starts at 0. Global `grow-up` is 1h. Species may override (chickens in config may use a shorter value). Immature animals can be tamed and cannot breed, milk, shear, lay, or drop a Cooking roast. - -`max-animals` 15. `cooking.admin` bypasses the cap only. Chickens and llamas count. Bees are vanilla and are not wiped. Vanilla-tameable species must be vanilla-tamed before plugin ownership. - -Mounts: all `AbstractHorse`. Stat blocks committed for HORSE, DONKEY, MULE, CAMEL. LLAMA has no `mounts` block until one is added. Formula: `max * (min-pct + genetics-pct * genetics/max-genetics + care-pct * care/care-max)`, floored at the type min. Untamed mounts stay rideable. Owned mounts are owner, co-owner, or staff. - -Damage flags in `husbandry.yml` `damage` apply to entities with a row. `other-players: false` would cancel foreign player damage. Read the file for the committed booleans. - -Inspect GUI: sneak empty-hand, or `items.inspect` when set. 54-slot inventory. Care bar and genetics bar. Products icon only if the species has slaughter, shear, shed, milk, or egg. Stars are not shown in the GUI. - -World cleanup: on chunk load, `remove-unowned` types with no owner are removed and orphan rows deleted, except enrolled horse, donkey, mule, and camel. - -## Configuration - -Keys are the tables above. Durations are TLibs strings (`4h`, `20m`, `60s`). Legacy `*-hours` keys still load with a warning. - -Per species: `milk`, `slaughter.meat`, `slaughter.drops`, `shear.drops`, `shed.drops`, `egg`, `grow-up`, `wool-timer`, optional `exp.min` and `exp.max`. - -A successful feed or clean grants a random integer of MMOCore profession experience. `profession` is the profession id (committed `farming`). `exp.min` and `exp.max` are the default bracket (committed 6 and 8), inclusive. A species `exp` block replaces that bracket. A blank profession id, a missing profession, or MMOCore disabled grants nothing. - -Also `remove-unowned`, `quality-from-genetics`, `amount-from-genetics`, `breeding`, `damage`, `mounts`. - -Meat strings in the committed file use `meat(type=roast;origin=Beef)` style names, not the older `food(...;origin=BEEF)` form. - -## Integrations - -Items are TLibs paths in `husbandry.yml` (`items.tame`, `co-own`, `feed`, `glove`, `neuter`). Not MMOItems. - -## Edge cases - -- Admin `/cooking husbandry spawn` is optional. Spawned livestock with no owner still despawn on chunk load unless they are an enrolled horse-family row. -- `/cooking husbandry save` upserts loaded animals and checkpoints WAL. -- `/cooking reload` reloads YAML and stats revision. It does not reopen SQLite. - -## Source map - -Package `net.tfminecraft.cooking.husbandry`. - -| Area | Classes | -| --- | --- | -| DB | `HusbandryRepository`, `HusbandryAnimal` | -| Lifecycle | `HusbandryLifecycleListener`, `HusbandryTickTask` | -| Care | `HusbandrySimulator`, `HusbandryCareListener` | -| Ownership | `HusbandryTamingListener` | -| Breed | `HusbandryBreedListener`, `HusbandryNeuterListener`, `HusbandryGenetics` | -| Harvest | `HusbandryDeathListener`, `HusbandryHarvestListener`, `HusbandryHarvest`, `HusbandryDropRoller` | -| Mounts | `HusbandryMounts`, `HusbandryMountListener`, `HusbandryDamageListener` | -| GUI | `HusbandryInspectGui`, `HusbandryInspectListener` | - -## Tests - -`HusbandryRepositoryTest`, `HusbandryGeneticsTest`, `HusbandryWoolTimerTest`, `HusbandryEntitiesCacheTest`, `HusbandrySimulatorTest`, `HusbandryMilkTimerTest`, `HusbandryProductsTest`, `HusbandryDropRollerTest`, `HusbandryMountSpeedTest`, `HusbandrySlaughterDropsTest`, `HusbandryQualityRangeTest`, `HusbandryMountEnrollTest`. - -## Change checklist - -- Gene rule change: bump `stats-revision` if live animals must wild-reset. -- New column: migration `user_version`, not reload. -- New species output: `husbandry.yml` plus this doc if a new capability key appears. -- Player wiki: `/wiki/animal-husbandry` when a player-visible step changes. - -Commands require `cooking.admin`: - -- `/cooking husbandry spawn [genetics] [care]` -- `/cooking husbandry save` diff --git a/docs/systems/nutrition.md b/docs/systems/nutrition.md deleted file mode 100644 index d8320c8..0000000 --- a/docs/systems/nutrition.md +++ /dev/null @@ -1,88 +0,0 @@ -# Nutrition and diet - -## Purpose - -Eating a Cooking food raises the active character's food value and moves their diet score toward that item's nutrition level. Vanilla saturation and some regeneration are suppressed so this system stays in charge. - -## Vocabulary - -- **Food value:** a pool on the RPCharacters character, capped by `nutrition.max-food` (committed 200). This is hunger storage, fed by `FoodItem.getFinalFood`. -- **Nutrition level:** `FoodItem.getFinalNutrition`. It is the diet target, not a second pool added on eat. -- **Raw diet:** unclamped character value the eat lerp moves. It can sit above `nutrition.max-diet`. -- **Diet score:** effective value after the variety penalty, then clamped to `nutrition.max-diet` (committed 40). Tiers and the nutrition attribute use this value. -- **Variety:** a per-player rolling history of eaten main and extra origins. Low variety is a percent penalty on raw diet before the clamp. -- **Respawn food:** `nutrition.respawn-food` (committed 80). Code default is also 80 if the key is absent. - -## Invariants - -- Eat gain is `ceil(getFinalFood)`, then clamped to `max-food`. Zero gain skips diet and variety. -- Diet lerp moves raw diet toward the item nutrition: `(itemNutrition - rawDiet) * (actualFoodGain / maxFood) * lerp-step-rate`. -- Effective diet is `clamp(rawDiet * (1 - varietyPenalty), 0, max-diet)`. The penalty is not applied to a score that was already clamped. -- Variety uses the last `history-meals` (committed 32). Mains weigh `main-weight` (1.0) and extras weigh `extra-weight` (0.25). Target spread is `target-ingredients` (8). `max-penalty-percent` (60) is the penalty at one effective ingredient. An empty history has no penalty yet. -- A nutrition tier change also shows the variety tier and the exact penalty percent, using the same `diet-tiers` labels. A variety change by itself does not send that message. -- If carve or sausage code has already divided nutrition, this service never sees the original level. Fix the portion math, not this lerp, when a slice should match the roast. -- Battle blocks eating through SimpleFactions (`BattleFoodGate`). -- Drain removes `drain-amount` on `drain-interval` seconds while the plugin tasks are running. Legacy key `drain-interval-ticks` is still read if the seconds key is absent (`ticks / 20`). -- No active character, or RPCharacters disabled: eat is logged and skipped. - -## Inputs and outputs - -`FoodConsumeListener` and `DrinkConsumeListener` call `NutritionService.tryApplyEat`. Bowls go through `BowlEatHandler`. An empty-hand click drinks soup in a bowl. A sneaking click does not, so the bowl can be carried. A Cooking item with `edible: false` cancels consumption and tells the player it needs to be prepared. `seafood_whole` is edible and applies its type food and nutrition. - -Death/respawn handling is `NutritionLifecycleListener` (see `NutritionDeathFoodTest`). - -Logs: `plugins/Cooking/logs/nutrition.log` when `logging` is on. `wipe-log: true` clears that file on enable. - -## State and persistence - -Character food, raw diet, and effective diet belong to RPCharacters (`raw-diet-score` and `diet-score`). Variety history belongs to the player PDC key `variety_history`. Cooking writes the effective diet to the nutrition attribute named by `attribute-name`. - -## Runtime flow - -```text -consume - -> ceil(final food) added to character food - -> raw diet lerps toward final nutrition - -> meal appended to player variety history - -> effective diet = raw after the variety penalty, then clamped - -> tier notify, save, display sync, attribute bridge -``` - -`NutritionDrainTask` and `SaturationGuard` / `RegenBlocker` / `FoodLevelChangeGuard` keep vanilla hunger from fighting the character value. - -## Configuration - -`config.yml` `nutrition`: - -- `max-food`, `respawn-food`, `max-diet` -- `attribute-name` -- `drain-amount`, `drain-interval`, `lerp-step-rate` -- `diet-tiers` (`id`, `min-percent`, `label`) -- `variety.enabled`, `variety.history-meals`, `variety.target-ingredients`, `variety.max-penalty-percent`, `variety.main-weight`, `variety.extra-weight` - -## Integrations - -Soft depend RPCharacters. Soft depend SimpleFactions for battle. Attribute display uses the configured attribute name. - -## Edge cases - -- Food at cap: no diet lerp, because actual gain is 0. -- Quality and tag multipliers already sit inside `getFinalNutrition` before the lerp. -- Sauce nutrition is included in `getFinalNutrition`. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/nutrition/` -- `src/main/resources/config.yml` (`nutrition`, `logging`, `wipe-log`) - -## Tests - -- `NutritionDeathFoodTest` -- `VarietyRulesTest` - -Eat battle gate has no unit test. - -## Change checklist - -- New nutrition config key: `NutritionConfig`, this doc, configuration reference. -- Do not store diet in item PDC. diff --git a/docs/systems/portions-and-servings.md b/docs/systems/portions-and-servings.md deleted file mode 100644 index d644e15..0000000 --- a/docs/systems/portions-and-servings.md +++ /dev/null @@ -1,94 +0,0 @@ -# Portions and servings - -## Purpose - -A roast, sausage chain, or pot is one prepared batch. Players take pieces or scoops. Food measures how much of the batch a serving is. Nutrition measures the level of that food. - -## Vocabulary - -- **Edible cut:** a `carve-sequences.yml` entry with a food `output`. Bone `item` cuts are not edible. -- **Start remaining:** `start-remaining` on a sequence, including non-food cuts. Poultry 6, red meat 8, sausage 5. -- **Base override:** the roast or chain stored its own food and nutrition on the item. -- **Scoop:** one ladle serving from a mashed pot. Count is `pot-soup-scoops`. - -## Invariants - -- Food splits across portions. Nutrition stays the batch level on every portion and on what remains. -- A carved edible piece copies the roast lineage, then composition records the same origins on the piece. -- Soup food per scoop is template food divided by `pot-soup-scoops`. Soup nutrition stays the template level. `pot-soup-height-divisor` is visual only. -- One whole seafood item becomes one portion. Food and nutrition stay the portion type levels: 6 and 6 for a fish filet, 5 and 5 for jellyfish, and 7 and 7 for octopus. Size stays on the item and does not change the stack or the food. -- Sauce scoops still copy the full sauce template food and nutrition. A valuable ingredient adds the Flavourful tag there too. -- A plain roast (no stored base) shows remaining food as the sum of cut `food` values still on it. Its nutrition is the roast type level, not that sum. The cut piece uses the piece type's own food and nutrition. -- A roast with a stored base splits food by edible cuts still left. Bones stay in the sequence and do not take a share of the food. Piece nutrition and leftover nutrition are `getBaseNutrition()`. -- A sausage chain sums input base food and averages input base nutrition. Carve then splits only the food. - -See [../decisions/0001-food-vs-nutrition.md](../decisions/0001-food-vs-nutrition.md). - -## Inputs and outputs - -| Action | Food | Nutrition | -| --- | --- | --- | -| Ladle soup | template food / `pot-soup-scoops` | template nutrition | -| Ladle sauce | full `sauce` food | full `sauce` nutrition | -| Carve, no override | piece type food; roast shows sum of remaining cut food | piece type nutrition; roast shows its type level | -| Carve, override | stored food times edible cuts left / edible cuts | stored nutrition, on the piece and on the leftover | -| Cut seafood | portion type food, one piece | portion type nutrition | - -## State and persistence - -`carve_sequence`, `carve_next_index`, `carve_remaining` on the roast. Initialized from the sequence when the roast is built. - -## Runtime flow - -```text -knife on meat hook - -> CarveHandler reads next CarveCut - -> food cut: clone output template, copy cooked/freshness/warmth - -> if roast.hasBaseOverride: piece food = stored food / edible cuts; piece nutrition = stored level - -> advance index and remaining - -> item cut: resolve TLibs/vanilla item, no food stats -``` - -```text -ladle on mashed pot - -> clone soup template - -> composition stars and freshness only - -> food = template food / pot-soup-scoops - -> remaining servings - 1 - -> clear pot at 0 -``` - -## Configuration - -- `carve-sequences.yml` -- `types.yml` roast `carve-sequence` overrides and soup/sauce `food` / `nutrition` -- `config.yml` `pot-soup-scoops`, `pot-soup-height-divisor`, `carve-tool` - -## Integrations - -Meat hook furniture id: `meat-hook`. Knife: `carve-tool`. - -## Edge cases - -- `hasBaseOverride` is sticky once either setter runs. Copying nutrition onto a piece stores that level; it does not divide it. -- Eating a leftover roast uses `getFinalFood` / `getFinalNutrition`. Food follows portions still left. Nutrition is the batch level, then quality and tag multipliers. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/carve/CarveHandler.java` -- `src/main/java/net/tfminecraft/cooking/carve/CarvableRoastUtils.java` -- `src/main/java/net/tfminecraft/cooking/carve/CarveSequence.java` -- `src/main/java/net/tfminecraft/cooking/sausagemaker/SausageItems.java` -- `src/main/java/net/tfminecraft/cooking/cooking/PotReference.java` -- `src/main/java/net/tfminecraft/cooking/cooking/SauceReference.java` -- `src/main/resources/carve-sequences.yml` - -## Tests - -- `PortionRulesTest` -- `IngredientLineageTest` - -## Change checklist - -- Sequence length change: update edible-count assumptions and the player wiki carving table. -- Scoop count change: `pot-soup-scoops` is the food divisor. Do not use `pot-soup-height-divisor` for food. diff --git a/docs/systems/processing-stations.md b/docs/systems/processing-stations.md deleted file mode 100644 index d77cac4..0000000 --- a/docs/systems/processing-stations.md +++ /dev/null @@ -1,85 +0,0 @@ -# Processing stations - -## Purpose - -These stations transform items without the frying/pot heat loop: cutting board, fire pit carve setup, baking trays, milling, mixing, butter churn, sausage maker, meat hook, and trough. - -## Vocabulary - -- **Crafting station:** a recipe in `crafting-stations.yml` (cutting board and similar). -- **Carve sequence:** ordered cuts in `carve-sequences.yml`, used after a roast exists. -- **Stir / crank / churn:** a counted interaction (`mixing-stir-count`, sausage crank, `butter-churn-count`). - -## Invariants - -- Cutting-board slots that share a recipe must be the same ingredient. Vanilla vegetables use `cut_vegetables` / `chop_vegetables`. CustomCrops vegetables use `cut_vegetables_2` / `chop_vegetables_2`, which keep `valuable: true` on `vegetable_cut_2` and `vegetable_chopped_2`. The output lineage is the composed input origins. -- `cut_seafood` cuts one `seafood_whole` per knife use into one portion. A stack larger than one is decremented in place. Other slots stay. Food and nutrition stay the portion type levels. Quality, origin, lineage, size, cut class, and CustomFishing id are copied. -- Dough, flour, butter, and sausage keep main and extra origins through their station state. A loaf copies the dough lineage. The display ingredient list stays the short name phrase. -- Milling recipes are data in `milling-recipes.yml`, not Java switches. -- Mixing dough needs the configured flour, water, and yeast inputs, then `mixing-stir-count` stirs (committed value 3). -- Butter churn loads milk and finishes after `butter-churn-count` (committed value 3) onto a butter plate. -- Sausage maker sums input meat food and averages input nutrition on the chain, then carve splits the food. See portions. -- Trough accepts vegetables and completes into universal feed (`trough-feed`). It does not cook food. -- Meat hook carving uses `carve-tool`. - -## Inputs and outputs - -| Station | Config | Output | -| --- | --- | --- | -| Cutting board | `crafting-stations.yml` | cut or chopped food, composition stars. Seafood is one portion per whole item | -| Baking tray | `baking-trays.yml` | bread while oven heat is present | -| Milling stone | `milling-recipes.yml` | flour or other mill output | -| Mixing bowl | `config.yml` `mixing-*` | dough | -| Butter churn | `config.yml` `butter-*` | butter item | -| Sausage maker | `config.yml` `sausage-maker-*` | sausage chain | -| Meat hook | `carve-sequences.yml` | one cut per knife click | -| Trough | `config.yml` `trough*` | universal feed | - -Fire pit roasting of a whole joint is a crafting/cooking path that leaves a carvable roast. Cuts are not produced by the fire pit itself. - -## State and persistence - -Station progress lives on the furniture or on the item (carve index, cook time PDC). Baking and churn also run aging tasks while the plugin is enabled. - -## Runtime flow - -Handlers listen for InteractibleFurniture events, validate the held tool, mutate slots, and build the result with `ItemBuilder` plus `CompositionQualityResolver` where several foods are inputs. - -## Configuration - -Keys listed above. Visual wobble and cooldown ticks are config, not gameplay nutrition. - -## Integrations - -Same furniture and ItemsAdder ids as [cooking-stations.md](cooking-stations.md). - -## Edge cases - -- `cookware.yml` is not this system. Heat and tools are `config.yml`. -- Sausage nutrition is an average of the meats. Soup does not take nutrition from the pot ingredients. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/crafting/` -- `src/main/java/net/tfminecraft/cooking/baking/` -- `src/main/java/net/tfminecraft/cooking/milling/` -- `src/main/java/net/tfminecraft/cooking/mixing/` -- `src/main/java/net/tfminecraft/cooking/churn/` -- `src/main/java/net/tfminecraft/cooking/sausagemaker/` -- `src/main/java/net/tfminecraft/cooking/hook/` -- `src/main/java/net/tfminecraft/cooking/trough/` -- `src/main/resources/crafting-stations.yml` -- `src/main/resources/baking-trays.yml` -- `src/main/resources/milling-recipes.yml` - -## Tests - -- `TroughIngredientsTest` -- `IngredientLineageTest` - -Other stations have no unit tests. - -## Change checklist - -- New recipe: [../how-to/add-station-recipe.md](../how-to/add-station-recipe.md). -- New station class: register the listener in `Cooking.registerListeners` and add a row to this doc. diff --git a/docs/systems/quality-composition.md b/docs/systems/quality-composition.md deleted file mode 100644 index 183da39..0000000 --- a/docs/systems/quality-composition.md +++ /dev/null @@ -1,86 +0,0 @@ -# Quality, composition, and conversions - -## Purpose - -Stars are 1-5. They come from a roll (pickup, harvest, genetics) or from mixing several inputs. Conversions turn a vanilla or ItemsAdder stack into a Cooking food at a chosen star. - -Conversion and composition code obtains item operations through -`TLibs.getItemAPI()`. This is the typed accessor for the same item API; quality -rolls, item matching, and lineage rules are unchanged. - -## Vocabulary - -- **Pickup quality:** roll in `quality.yml` `pickup.min` / `max` (1-5). -- **Harvest quality H:** crop roll before permission effects. See crops doc. -- **Composition:** station result stars from input stars and roles. -- **Legacy mode:** `composition.yml` `legacy-mode: false` makes `roles` authoritative. The exclude list in `quality.yml` applies only when legacy mode is on. -- **Permission effect:** a luck-style bump after the roll (`permission_effects.yml`). The result is `rolled + best bias`, then at least the best minimum (pickup min or a granted min), then clamped to 1-5. A null player skips permission nodes. - -## Invariants - -- Stars are not care, fertility, or nutrition. Nutrition multipliers per star live in `quality.yml` `nutrition-from-quality`. -- Composition does not, by itself, add ingredient food or nutrition onto soup, sauce, or fried output. Those outputs keep the type template unless some other code calls `setBaseFood` / `setBaseNutrition`. -- `CompositionQualityResolver.compose` also builds ingredient lineage from the same main, extra, and neutral roles. Nested lineage keeps its buckets. A raw input uses its origin in the role for that station. Neutral inputs are left out. `CompositionApplier` writes quality, freshness, and lineage onto the output. -- Sausage chains are the exception that sums meat food and nutrition. See portions doc. -- Farm produce pickup through the generic converter is quality 1 (`CropsConfig.isFarmFood`). Harvest conversion passes H explicitly. Potato and carrot are produce, not a 5-star backdoor. -- Every harvest star weight stays above 0. Fertility never forbids 5 stars. - -## Inputs and outputs - -`OriginQualityResolver` handles pickup and permissions. - -`CompositionQualityResolver.compose(player, inputs, context)` returns final stars, freshness tracks, and ingredient lineage. Contexts include `SOUP_SCOOP`, `SAUCE_SCOOP`, `FRYING_PAN`, `CUTTING_BOARD`, `CARVE`, `MIXING_BOWL`, `SAUSAGE_MAKER`, `CHURN`. - -`ConversionManager` rewrites matching stacks using `conversions.yml`. Plain vanilla fish are handled from `custom-fishing.yml`, because that path stores a default size the generic food string cannot carry. A `COD` with custom model data, or a CustomFishing item id, is converted by the legacy fish path before that vanilla check. A stack that already has `food_id` is skipped. - -## State and persistence - -Stars are `food_quality` PDC (min used for display and multipliers). - -## Runtime flow - -```text -roll or compose stars - -> optional permission bump - -> ItemBuilder stamps quality - -> FoodItem.applyMultipliers on eat and lore -``` - -Role overrides per context are `composition.yml` `context-overrides`. - -## Configuration - -- `quality.yml` -- `composition.yml` -- `permission_effects.yml` -- `conversions.yml` - -## Integrations - -Permissions are Bukkit permission nodes. Crop permission `tfmc.cooking.better_crops` is applied after the harvest roll, not on grow ticks. - -## Edge cases - -- Chef or craft bonuses are modifier keys in `composition.yml` (`gap-up-chance-per-star`, `craft-quality-pct-bonus`). Read that file before changing odds. -- `/cooking qualitytest` is an admin debug command, not a player feature. - -## Source map - -- `src/main/java/net/tfminecraft/cooking/quality/` -- `src/main/java/net/tfminecraft/cooking/manager/ConversionManager.java` -- `src/main/java/net/tfminecraft/cooking/loader/ConversionLoader.java` -- `src/main/resources/quality.yml` -- `src/main/resources/composition.yml` -- `src/main/resources/conversions.yml` -- `src/main/resources/permission_effects.yml` - -## Tests - -- `IngredientLineageTest` -- `VanillaFishTest` -- `LegacyFishTest` - -## Change checklist - -- New compose context: add an enum value, a `context-overrides` block if roles differ, and this doc. -- New conversion line: `conversions.yml` only, unless matching rules change. CustomCrops produce uses `vegetable_2` and `fruit_2`. Vanilla carrot, potato, beetroot, pumpkin, apple, and melon stay on type 1. Nether wart is not converted. diff --git a/scripts/check-doc-impact.py b/scripts/check-doc-impact.py deleted file mode 100644 index cec34be..0000000 --- a/scripts/check-doc-impact.py +++ /dev/null @@ -1,25 +0,0 @@ -"""Fail when owned code or config changes without a system doc or a waiver.""" - -import sys -from pathlib import Path - -sys.path.insert(0, str(Path(__file__).resolve().parent)) - -from doclib import git_changed, impact_errors, repo_root - - -def main() -> int: - root = repo_root() - changed = git_changed(root) - errors = impact_errors(root, set(changed)) - if errors: - print("documentation impact check failed:") - for error in errors: - print(f" {error}") - return 1 - print(f"documentation impact check passed ({len(changed)} changed paths)") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/scripts/check-links.py b/scripts/check-links.py deleted file mode 100644 index 9fe126e..0000000 --- a/scripts/check-links.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Check relative Markdown links inside the cooking docs.""" - -import re -import sys -from pathlib import Path - -sys.path.insert(0, str(Path(__file__).resolve().parent)) - -from doclib import repo_root - -LINK = re.compile(r"\[[^\]]+\]\(([^)]+)\)") - - -def main() -> int: - root = repo_root() - files = [root / "README.md", * (root / "docs").rglob("*.md")] - errors: list[str] = [] - for path in files: - text = path.read_text(encoding="utf-8") - for match in LINK.finditer(text): - target = match.group(1).strip() - if target.startswith(("http://", "https://", "mailto:")): - continue - target = target.split("#", 1)[0].strip() - if not target: - continue - resolved = (path.parent / target).resolve() - if not resolved.exists(): - errors.append(f"{path.relative_to(root).as_posix()} -> {target}") - if errors: - print("broken links:") - for error in errors: - print(f" {error}") - return 1 - print(f"link check passed ({len(files)} files)") - return 0 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/scripts/doclib.py b/scripts/doclib.py deleted file mode 100644 index 0571046..0000000 --- a/scripts/doclib.py +++ /dev/null @@ -1,183 +0,0 @@ -"""Shared documentation ownership checks. No third-party packages.""" - -from __future__ import annotations - -import json -import re -import subprocess -from pathlib import Path - -WAIVER = "docs/impact-waiver.md" -RESOURCE_GLOB = "src/main/resources" - - -def repo_root() -> Path: - return Path(__file__).resolve().parents[1] - - -def load_manifest(root: Path | None = None) -> dict: - root = root or repo_root() - return json.loads((root / "docs" / "manifest.json").read_text(encoding="utf-8")) - - -def glob_to_re(pattern: str) -> re.Pattern[str]: - pattern = pattern.replace("\\", "/") - parts: list[str] = ["^"] - i = 0 - while i < len(pattern): - if pattern.startswith("**", i): - parts.append(".*") - i += 2 - if i < len(pattern) and pattern[i] == "/": - i += 1 - elif pattern[i] == "*": - parts.append("[^/]*") - i += 1 - else: - parts.append(re.escape(pattern[i])) - i += 1 - parts.append("$") - return re.compile("".join(parts)) - - -def matches(pattern: str, rel: str) -> bool: - rel = rel.replace("\\", "/") - return glob_to_re(pattern).match(rel) is not None - - -def owners_for(manifest: dict, rel: str) -> list[str]: - found: list[str] = [] - for doc in manifest["documents"]: - if any(matches(pattern, rel) for pattern in doc["paths"]): - found.append(doc["document"].replace("\\", "/")) - return found - - -def resource_yaml(root: Path) -> list[str]: - base = root / "src" / "main" / "resources" - return sorted( - path.relative_to(root).as_posix() - for path in base.glob("*.yml") - ) - - -def validate_manifest(root: Path | None = None) -> list[str]: - root = root or repo_root() - manifest = load_manifest(root) - errors: list[str] = [] - if manifest.get("satisfy") != "any-owner": - errors.append("manifest satisfy must be any-owner") - - known = {item.replace("\\", "/") for item in manifest.get("known_unloaded", [])} - if "src/main/resources/cookware.yml" not in known: - errors.append("cookware.yml must stay listed in known_unloaded") - - for excluded in manifest.get("generated_excludes", []): - if not excluded.startswith("target"): - errors.append(f"unexpected generated exclude: {excluded}") - if any(matches(excluded, doc["document"]) for doc in manifest["documents"]): - errors.append(f"generated exclude covers a document: {excluded}") - - for doc in manifest["documents"]: - document = root / doc["document"] - if not document.is_file(): - errors.append(f"missing document {doc['document']}") - if doc["document"].replace("\\", "/").startswith("target/"): - errors.append(f"document points at target: {doc['document']}") - for pattern in doc["paths"]: - if pattern.startswith("target"): - errors.append(f"{doc['id']} owns generated path {pattern}") - matched = [ - path.relative_to(root).as_posix() - for path in root.rglob("*") - if path.is_file() and "target" not in path.relative_to(root).parts - and matches(pattern, path.relative_to(root).as_posix()) - ] - if not matched: - errors.append(f"{doc['id']} pattern matches nothing: {pattern}") - - mapped: set[str] = set() - for rel in resource_yaml(root): - if owners_for(manifest, rel): - mapped.add(rel) - elif rel not in known: - errors.append(f"runtime yaml is not mapped or known_unloaded: {rel}") - if "src/main/resources/cookware.yml" in mapped: - errors.append("cookware.yml is unloaded and must not be an owned runtime config") - return errors - - -def waiver_allows(root: Path, changed: set[str]) -> bool: - if WAIVER not in changed: - return False - text = (root / WAIVER).read_text(encoding="utf-8") - if "docs-impact: none" not in text: - return False - for line in text.splitlines(): - if line.lower().startswith("reason:"): - reason = line.split(":", 1)[1].strip() - return len(reason) >= 12 and reason.lower() != "none" - return False - - -def impact_errors(root: Path, changed: set[str]) -> list[str]: - manifest = load_manifest(root) - changed = {item.replace("\\", "/") for item in changed} - if waiver_allows(root, changed): - return [] - errors: list[str] = [] - for rel in sorted(changed): - if rel.startswith("target/"): - errors.append(f"do not commit generated output: {rel}") - continue - owners = owners_for(manifest, rel) - if not owners: - continue - if any(owner in changed for owner in owners): - continue - errors.append( - f"{rel} needs one of: {', '.join(owners)} " - f"(or a same-diff {WAIVER} with docs-impact: none and a reason)" - ) - return errors - - -def git_changed(root: Path) -> list[str]: - import os - base = os.environ.get("GITHUB_BASE_REF", "").strip() - if base: - names = _git(root, ["diff", "--name-only", f"origin/{base}...HEAD"]) - if names is not None: - return _split(names) - if os.environ.get("GITHUB_EVENT_NAME") == "push": - names = _git(root, ["diff", "--name-only", "HEAD~1", "HEAD"]) - if names is not None: - return _split(names) - names = _git(root, ["diff", "--name-only", "HEAD"]) - staged = _git(root, ["diff", "--name-only", "--cached"]) - untracked = _git(root, ["ls-files", "--others", "--exclude-standard"]) - files: set[str] = set() - for blob in (names, staged, untracked): - if blob: - files.update(_split(blob)) - return sorted(files) - - -def _git(root: Path, args: list[str]) -> str | None: - try: - result = subprocess.run( - ["git", *args], - cwd=root, - check=False, - capture_output=True, - text=True, - ) - except OSError: - return None - if result.returncode != 0: - return None - return result.stdout - - -def _split(blob: str) -> list[str]: - return [line.strip().replace("\\", "/") for line in blob.splitlines() if line.strip()] diff --git a/scripts/test_doc_manifest.py b/scripts/test_doc_manifest.py deleted file mode 100644 index f59b0be..0000000 --- a/scripts/test_doc_manifest.py +++ /dev/null @@ -1,120 +0,0 @@ -"""Manifest and documentation-impact tests. Run: python scripts/test_doc_manifest.py""" - -import sys -import tempfile -import unittest -from pathlib import Path - -sys.path.insert(0, str(Path(__file__).resolve().parent)) - -from doclib import glob_to_re, impact_errors, matches, repo_root, validate_manifest - - -class ManifestTests(unittest.TestCase): - def test_manifest_matches_repo(self) -> None: - errors = validate_manifest(repo_root()) - self.assertEqual(errors, [], "\n".join(errors)) - - def test_glob_does_not_match_target_by_pattern_intent(self) -> None: - self.assertTrue(matches("src/main/resources/types.yml", "src/main/resources/types.yml")) - self.assertFalse(matches("src/main/java/net/tfminecraft/cooking/item/**", "target/classes/types.yml")) - self.assertTrue( - matches( - "src/main/java/net/tfminecraft/cooking/carve/**", - "src/main/java/net/tfminecraft/cooking/carve/CarveHandler.java", - ) - ) - self.assertIsNotNone(glob_to_re("target/**").match("target/classes/config.yml")) - - def test_config_change_requires_an_owner_doc(self) -> None: - errors = impact_errors( - repo_root(), - {"src/main/resources/husbandry.yml"}, - ) - self.assertTrue(any("husbandry.md" in error for error in errors)) - - def test_owner_doc_in_the_same_change_passes(self) -> None: - errors = impact_errors( - repo_root(), - { - "src/main/resources/husbandry.yml", - "docs/systems/husbandry.md", - }, - ) - self.assertEqual(errors, []) - - def test_unmapped_comment_file_passes(self) -> None: - errors = impact_errors(repo_root(), {"README.md"}) - self.assertEqual(errors, []) - - def test_waiver_must_change_and_explain(self) -> None: - root = repo_root() - waiver = root / "docs" / "impact-waiver.md" - original = waiver.read_text(encoding="utf-8") - try: - self.assertNotEqual( - impact_errors(root, {"src/main/resources/crops.yml"}), - [], - ) - waiver.write_text( - "docs-impact: none\nreason: comment only in a crop loader\n", - encoding="utf-8", - ) - self.assertEqual( - impact_errors( - root, - {"src/main/resources/crops.yml", "docs/impact-waiver.md"}, - ), - [], - ) - waiver.write_text("docs-impact: none\nreason: none\n", encoding="utf-8") - self.assertNotEqual( - impact_errors( - root, - {"src/main/resources/crops.yml", "docs/impact-waiver.md"}, - ), - [], - ) - finally: - waiver.write_text(original, encoding="utf-8") - - def test_generated_path_is_rejected(self) -> None: - errors = impact_errors(repo_root(), {"target/classes/config.yml"}) - self.assertTrue(any("generated" in error for error in errors)) - - -class IsolatedTests(unittest.TestCase): - def test_missing_pattern_is_reported(self) -> None: - with tempfile.TemporaryDirectory() as tmp: - root = Path(tmp) - docs = root / "docs" - docs.mkdir() - (docs / "only.md").write_text("ok", encoding="utf-8") - resources = root / "src" / "main" / "resources" - resources.mkdir(parents=True) - (resources / "types.yml").write_text("a: 1\n", encoding="utf-8") - (resources / "cookware.yml").write_text("old: true\n", encoding="utf-8") - (docs / "manifest.json").write_text( - """ - { - "generated_excludes": ["target/**"], - "known_unloaded": ["src/main/resources/cookware.yml"], - "satisfy": "any-owner", - "documents": [ - { - "id": "missing", - "document": "docs/only.md", - "paths": ["src/main/java/no/such/**"] - } - ] - } - """, - encoding="utf-8", - ) - errors = validate_manifest(root) - self.assertTrue(any("matches nothing" in error for error in errors)) - self.assertTrue(any("types.yml" in error for error in errors)) - - -if __name__ == "__main__": - unittest.main() diff --git a/src/main/resources/crops.yml b/src/main/resources/crops.yml index c4fe7e9..9f294ce 100644 --- a/src/main/resources/crops.yml +++ b/src/main/resources/crops.yml @@ -1,4 +1,4 @@ -# Crop harvest quality + growth gate (Cooking). Spec: docs/crops.md +# Crop harvest quality + growth gate (Cooking). Spec: https://github.com/TF-Minecraft/Docs/blob/main/projects/Cooking/docs/crops.md # Produce stars roll from province fertility × crop affection, then pickup permissions. # Growth ticks use the same affection: chance = (fertility/100) ^ affection. # Seeds stay untagged IA/vanilla. CustomCrops one-seed drops stay yield/balance.