diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b9df6a..78610e94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,202 @@ # Changelog -## Unreleased — CraftTweaker integration +## Unreleased — 2.0.2 -Changes on `crafttweaker-integration` since `master-2.0-1.21.1-neo`. +- Update NeoForge to 21.1.265 (from 21.1.247); it is now the minimum NeoForge + version MMDLib requires. Update the Gradle wrapper to 9.9.1 (from 9.8.2). +- Machines (#105): + - Multiblocks, as an early proof of concept whose API will change: Java + machines can span several blocks, with placement from one item, rotation, + formation and dismantling, member links, ports that expose the controller's + storage, and requirement rules. See [multiblocks](docs/multiblocks.md); the + companion adds a test bench. + - XML machine appearances: a `model` preset beside `cube-front`, conditional + `` models and `` switches with optional emissive masks, + chosen by `when` conditions over the machine's processors, item groups, + tanks and energy (such as `$processors.worker.running`). Java machines + supply variables with `VisualVariableProvider`. + - Ghost inventories: sample-only item slots that recipes match without + consuming, with JEI's **+** button filling them. + - Recipe selection: a processor can be `selectable`, with an optional + `default-recipe`, chosen in screens through ``. + - Reusable recipe inputs: item and fluid inputs accept `"consumed": false`, + so they are required and reserved but not spent. + - Inline group colors (`color` on ``, `` and ``) and a + default palette. + - Machine-owned unavailable faces for side configuration and redstone + (`SideConfig.disabledFaces`, `RedstoneControl.disabledFaces`), shown as + blocked in the drawers. + - Ghost slot default items and fixed tank fluids are checked at startup, and + recipes asking a ghost group for more samples than it has slots fail to + load. + - The screen protocol is now 21, and the automation and redstone drawers 17; + clients and servers must both run 2.0.2. + - A local Maven repository can be configured for development builds; see + [local development](docs/local-development.md). +- Add data-driven sound events: each `mmdlib/sound/.json` registers the + sound event `:` at startup, with an optional fixed hearing `range`. + Audio comes from `sounds.json` as usual. MMDLib registers its own namespace's; + other mods queue theirs with `RuntimeContentRegistrar.queueSound`, and + `MMDLib.sounds()` lists them all. +- Play sounds from data: + - Blocks: a block's `sound` (or a material's `block_sound`) can now name a sound + set declared in `mmdlib/sound_type/.json`, choosing the break, step, + place, hit and fall sounds, volume and pitch, over a vanilla `base` set. + Vanilla names such as `"metal"` work as before. + - Screens: any element can have a `click-sound`, played for the player when it + is clicked. + - XML machines: `` takes a `running-sound`, looped at the machine + while a cycle runs, and a `finish-sound`, played when a cycle completes. + - Click sounds and machine sounds are set in their XML only. +- Add creative tabs from data: each `mmdlib/creative_tab/.json` describes + the tab `:`, with its contents in order (items, `#tags` and whole + materials, each item shown once), a translated title with an optional fallback, + an icon, `before`/`after` placement and an optional search bar. + `CreativeTabDefinition.builder()` builds the same in Java. MMDLib registers its + own namespace's; other mods queue theirs with `RuntimeContentRegistrar.queueTab`, + and `MMDLib.creativeTabs()` lists them all. +- CraftTweaker: `#loader mmdlib` scripts can make creative tabs with + `mods.mmdlib.CreativeTabBuilder`, and change tabs declared in JSON files with + `CreativeTabBuilder.edit(id)`: title, fallback, icon, placement, search bar, and + adding or removing items, tags and materials. `exists` and `declared` list the + file tabs. For code-built definition sources, `Definitions` now carries creative + tabs, and `MaterialExtensions.creativeTabFiles()` lets a source read the file + tabs; a source's tab with a file tab's ID replaces it. +- CraftTweaker: `#loader mmdlib` scripts can declare sound events + (`mods.mmdlib.SoundBuilder`, with `range`) and block sound sets + (`mods.mmdlib.SoundTypeBuilder`: base, break, step, place, hit and fall sounds, + volume, pitch), and change those declared in `mmdlib/sound/` and + `mmdlib/sound_type/` files with `edit(id)`; `exists` and `declared` list the file + definitions. A material's `blockSound` now accepts a sound set's ID, as a block's + `sound` already did. For code-built definition sources, `Definitions` carries + sound events and sound sets, and `MaterialExtensions.soundFiles()` and + `soundTypeFiles()` expose the file definitions; a source's definition with a + file's ID replaces it. +- CraftTweaker: scripts can supply screen click and hover handlers with + `mods.mmdlib.ScreenHandlers.onClick(name, function)` and `onHover(...)`, + registered as `mmdlib:` for screen XML (machines' screens included) to + name in `on-click` and its variants, or `on-hover`. Screens stay XML; their + handler IDs are checked at startup, after scripts run. A click handler runs on + the server with the player, block entity, screen, element, button, modifier keys + and option; a hover handler runs on the client. +- Screen value providers: `value` and `max` in screen XML can name a provider as + `@namespace:id`, registered with `ScreenValueProviders.GLOBAL.register(id, + valueType, blockEntity -> value)` and checked against the element at load like + a getter. CraftTweaker scripts register providers with + `mods.mmdlib.ScreenValues.whole`, `decimal`, `flag` and `text`, as + `mmdlib:`; each function gets the screen's block entity and runs on the + server. +- XML machine cycle events: a `` can name `on-start` and `on-finish` + handlers, new `machine-cycle-start` and `machine-cycle-finish` events run on the + server when a new cycle starts and when one finishes with its outputs placed. + Handlers get the machine, level, position, machine ID, recipe and cycle length, + and are registered in code, extension files, or CraftTweaker scripts + (`mods.mmdlib.MachineHandlers.onStart` / `onFinish`, as `mmdlib:`). Each + machine's handler IDs are checked when machines load. +- CraftTweaker machine recipes: recipe scripts can add and remove recipes of XML + machines' declared recipe types with CraftTweaker's own `` + manager (`addJsonRecipe`, `removeByName`, ...), or add them with the typed + `mods.mmdlib.MachineRecipeBuilder`: item, fluid and energy inputs (item and + fluid inputs optionally reusable, as `consumed: false`), item and fluid outputs + with chances, and time. The typed builder checks groups against the machines + using the type, as recipe reloads do; recipes added with `addJsonRecipe` are + not checked. `inputFluids` takes a fluid tag or several fluids. +- CraftTweaker recipe handler for machine recipes: `/ct recipes` dumps them as + `MachineRecipeBuilder` calls, and CraftTweaker's ingredient replacement + (`Replacer`) works on them, keeping each part's group, count and consumption; + energy is ``. +- CraftTweaker recipe generators: a `#loader mmdlib` script registers a generator + with `mods.mmdlib.RecipeGenerators.register(name, function)`, and machine XML + runs it with ``. On every data reload the function reads the + reload's item tags and the generator's attributes and adds recipes. +- Standalone fluids: each `mmdlib/standalone/fluid/.json` declares a fluid + with its own ID and no material, built from a fluid module with optional + `template`, `tint`, `temperature`, `density` and `viscosity` overrides: the fluid, + its flowing form, a liquid block and a bucket. MMDLib adds a plain water-like + `mmdlib:fluid` module beside `mmdlib:molten`. `MMDLib.standaloneFluids()` lists + them. CraftTweaker: `#loader mmdlib` scripts build them with + `mods.mmdlib.FluidBuilder` (type, flow and appearance values, block and bucket + switches, display name), with generated bucket models, blockstates and names. +- Remove the vanilla extensions: the fifteen bundled materials (wood, stone, iron, + gold, copper, diamond, coal, charcoal, emerald, ender, quartz, obsidian, lapis, + prismarine, redstone) with their tools, armor, decorative blocks, ammunition, + crackhammers, dusts, gears and molten fluids, plus their art, recipes, loot + tables and tags. They now live in BaseMetals 4.0. MMDLib registers no materials + of its own; script-defined and standalone content is unaffected. +- **Worlds:** items and blocks with the removed `mmdlib:` IDs (such as + `mmdlib:iron_crackhammer` or `mmdlib:copper_molten`) disappear from existing + worlds when MMDLib is updated. +- The release jar no longer contains the data generator for that content, which + ran an external Python script. +- The human detector's recipe needs `#c:gears`, which MMDLib no longer supplies; + it is craftable when another mod (such as BaseMetals) adds gears. +- MMDLib's creative tab is now titled "MMDLib" (it was "MMDLib: Vanilla + Extensions"); it holds MMDLib's standalone and script-defined items. +- CraftTweaker API docs: every script type is documented for CraftTweaker's docs + wiki. Compiling writes the pages (`docs.json` and one page per type, under Mods › + MMDLib) to `build/crafttweaker-docs`, with descriptions, parameters, return values + and example values for each member. See "Generated API docs" in + [CraftTweaker definitions](docs/crafttweaker.md). +- Build: the Java API Javadoc leaves out the CraftTweaker script classes, which the + wiki pages document instead. The formatter keeps `@param name description` on one + line, which the CraftTweaker docs need; files reformatted under it change only in + their Javadoc. +- For mods built on MMDLib: + - `MachineDefinition` has new components: `baseModel`, `modelParts`, + `faceTextures`, `recipeSelection` and `ghosts` (#105), then `sounds` and + `events`. The 2.0.x constructor remains, as do constructors without sounds + and events, which use `Sounds.NONE` and `Events.NONE`. + - `DefinitionLoader.Loaded`, `MaterialExtensions.Definitions` and + `Common.Clicks` have new components (standalone fluids among them); their + previous constructors remain. `FluidBuilder.setRegistryName` fixes a fluid's + ID, as for blocks and items. `MMDFluid.flowingId()` puts `flowing_` on the + last path segment (`test/flowing_syrup` for `test/syrup`); IDs without a + slash, such as every material fluid's, are unchanged. + - `StaticAssetRules`, which only served the removed artwork, is gone. + - New for code: `RecipeProcessor.startedCycles()`, `cycle()` and + `justFinished()`; a `ScreenBinder.bind` overload taking a + `ScreenValueProviders` registry, whose constructor is now public for + isolated binding and tests. `GeneratedMachineRecipes.validateGroups` is + public, for checking recipes added after a reload. +- Known issues, to be fixed by #105's author before release: + - Multiblock members must keep exactly their authored block state, so a member + whose state changes (connections, waterlogging, `lit`) breaks the structure, + and under `REMOVE_OWNED` removes it. + - Dismantling skips members in unloaded chunks, which keep stale links. + - Changing a multiblock definition's version or policy leaves existing + controllers unable to form again. + +## 2.0.1 — 2026-11-10 + +2.0.0 (2026-11-03) shipped without a changelog; this lists what 2.0.1 added. + +### Machines and screens + +- Shared machine recipe processor, with centralized input and output + reservations, compact pause and redstone controls above machine inventories, + and persistence fixes for in-place shift-click transfers (#90). +- Mod-defined interactive GUI widgets (#91). +- Coloured inventory and side-configuration drawers, with capability-driven + automation addons, filter editors and ghost samples (#92); player equipment and + optional inventory drawers, including Curios slots (#93). +- Per-face redstone controls and machine reservation overlays (#94). +- A provider-based statistics drawer and configurable generator panels (#95). +- A shared powered-machine entity and a reusable powered-machine screen template; + machine screens can inherit info panels and processor controls (#96). +- XML-defined machines, with generated recipes, recipe bundles, an XML lava + furnace, fluid recipe adapters and tank tooltips (#97). +- Extensible, self-contained machine UI elements; redstone dust connects to a + machine's configured redstone inputs and outputs (#103). + +### Fluids + +- A generic fluid capability lets glass bottles hold fluids in + `#mmdlib:bottleable`, unless another mod already gives glass bottles one (#99). +- Glass bottles filled with an experience fluid (`#c:experience`) become Bottles + o' Enchanting, 250 mB each (#101). + +### CraftTweaker - Add optional CraftTweaker support for defining materials, standalone blocks and items, and reusable block and item modules in ZenScript. @@ -22,11 +216,11 @@ Changes on `crafttweaker-integration` since `master-2.0-1.21.1-neo`. limitations in [CraftTweaker definitions](docs/crafttweaker.md) and [definition loading](docs/definition-loading.md). -+- Expose material repair/harvest settings, block runtime overrides, and named tool -+ stat methods to CraftTweaker. Add a typed helper for existing generic-tool factory -+ data, with script integration tests and an API/runtime capability inventory. -+ Per-tool durability scaling remains limited by vanilla TieredItem resetting the -+ computed durability to the material tier's uses; material durability works. +- Expose material repair/harvest settings, block runtime overrides, and named tool + stat methods to CraftTweaker. Add a typed helper for existing generic-tool factory + data, with script integration tests and an API/runtime capability inventory. + Per-tool durability scaling remains limited by vanilla TieredItem resetting the + computed durability to the material tier's uses; material durability works. - Add typed item/block/tag/module ID references and independent module snapshots for CraftTweaker. Snapshot copies rebind locally owned handlers; module tags are now available to subsequent builders during the same script run. @@ -38,3 +232,9 @@ Changes on `crafttweaker-integration` since `master-2.0-1.21.1-neo`. - Add a typed CraftTweaker manager for shared `mmdlib:crushing` recipes under a separate crusher integration package. Reuse standard recipe actions, removals, queries and reload handling; test script-added recipes through the crackhammer. + +### Build + +- Spotless formats the code: an Eclipse profile (4-space indent, 80-column + target) and import blocks, ratcheted so files are reformatted as they are + edited, with `-PformatAll` for a whole-tree pass (#102, #104). diff --git a/build.gradle b/build.gradle index 78708a83..d7c460cf 100644 --- a/build.gradle +++ b/build.gradle @@ -83,6 +83,17 @@ dependencies { } } +// CraftTweaker script API docs: the annotation processor writes pages for every +// @Document-annotated script type to build/crafttweaker-docs, in the CraftTweaker +// docs wiki's format (see docs/crafttweaker.md, "Generated API docs"). +def craftTweakerDocs = layout.buildDirectory.dir('crafttweaker-docs') +tasks.named('compileJava', JavaCompile) { + options.compilerArgs.add(craftTweakerDocs.map { + "-Acrafttweaker.processor.document.output_directory=${it.asFile}" + }.get()) + outputs.dir(craftTweakerDocs).withPropertyName('craftTweakerDocs') +} + neoForge { version = neoforge_version @@ -111,11 +122,6 @@ neoForge { } data { data() - systemProperty 'mmdlib.projectDir', project.layout.projectDirectory.asFile.absolutePath - systemProperty 'mmdlib.python', providers.gradleProperty('mmdlibPython').getOrElse('python3') - if (providers.gradleProperty('mmdlibMinecraftAssets').isPresent()) { - systemProperty 'mmdlib.minecraftAssets', providers.gradleProperty('mmdlibMinecraftAssets').get() - } programArguments.addAll '--mod', mod_id, '--all', '--output', file('src/generated/resources').absolutePath, '--existing', file('src/main/resources').absolutePath } @@ -221,6 +227,9 @@ apply from: 'scripts/companion.gradle' tasks.named('javadoc', Javadoc) { options.encoding = 'UTF-8' options.addStringOption('Xdoclint:all,-missing', '-quiet') + // The CraftTweaker script API is documented for CraftTweaker's wiki instead (its Javadoc + // holds script examples, such as brackets); see docs/crafttweaker.md. + exclude 'zone/moddev/mc/lib/compat/CraftTweaker/**' options.links('https://docs.oracle.com/en/java/javase/21/docs/api/') } diff --git a/docs/block-builder.md b/docs/block-builder.md index cfe11b3c..a12e02cf 100644 --- a/docs/block-builder.md +++ b/docs/block-builder.md @@ -59,6 +59,11 @@ boundary. The same codec supports NbtOps. Example: } ``` +`sound` is either one of vanilla's block sound sets by name (`stone`, `wood`, +`metal`, ...) or the ID of a sound set declared in `mmdlib/sound_type/` (see +[block sound sets](definition-loading.md#block-sound-sets)). A material's +`runtime.block_sound` takes the same values. + Name can come from the resource path via `new BlockParser(templateId, json)`; conflicting embedded names fail. Properties are nested under `properties`. `has_item` defaults true and cannot be false alongside an explicit item template. diff --git a/docs/code-format.md b/docs/code-format.md index a5b4b5c6..0aedb2ec 100644 --- a/docs/code-format.md +++ b/docs/code-format.md @@ -11,6 +11,9 @@ with these overrides: `./gradlew lineLimit` (part of `check`) warns with the file and line. It never fails the build: some lines read worse split than long. - **Wildcard imports are allowed**, static or not; in a mod they usually mean less code. +- **Javadoc block tags keep their first line together**: `@param name description` on one + line, continuing below. CraftTweaker's documentation processor reads a parameter's name up to + the line end, so the generated script docs depend on it. - **Keep methods short**: aim for 25 to 30 lines. This is a review guideline; no tool enforces it. - The other Google conventions (brace style, one statement per line, naming, `@Override` always, ...) still apply. diff --git a/docs/crafttweaker-api-inventory.md b/docs/crafttweaker-api-inventory.md index 2e148d3c..a4264faa 100644 --- a/docs/crafttweaker-api-inventory.md +++ b/docs/crafttweaker-api-inventory.md @@ -191,6 +191,37 @@ Source: [ScriptClickHandler](../src/main/java/zone/moddev/mc/lib/compat/CraftTwe - method `void handle(ClickContext context)` +### `CreativeTabBuilder` + +Source: [ScriptCreativeTabBuilder](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptCreativeTabBuilder.java). + +- constructor `CreativeTabBuilder(String name)` +- static method `CreativeTabBuilder edit(String id)` +- static method `boolean exists(String id)` +- static method `String[] declared()` +- get `name` — `String getName()` +- get `title` — `String getTitle()` +- set `title` — `void setTitle(String value)` +- get `titleFallback` — `String getTitleFallback()` +- set `titleFallback` — `void setTitleFallback(String value)` +- get `icon` — `String getIcon()` +- set `icon` — `void setIcon(String value)` +- get `searchBar` — `boolean getSearchBar()` +- set `searchBar` — `void setSearchBar(boolean value)` +- get `before` — `String[] getBefore()` +- set `before` — `void setBefore(String[] tabs)` +- get `after` — `String[] getAfter()` +- set `after` — `void setAfter(String[] tabs)` +- get `contents` — `String[] getContents()` +- method `CreativeTabBuilder addItems(String... items)` +- method `CreativeTabBuilder addTags(String... tags)` +- method `CreativeTabBuilder addMaterials(String... materials)` +- method `CreativeTabBuilder removeItems(String... items)` +- method `CreativeTabBuilder removeTags(String... tags)` +- method `CreativeTabBuilder removeMaterials(String... materials)` +- method `CreativeTabBuilder clearContents()` +- method `void build()` + ### `DefinitionProperties` Source: [ScriptDefinitionProperties](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptDefinitionProperties.java). @@ -207,6 +238,20 @@ Source: [ScriptDefinitionProperties](../src/main/java/zone/moddev/mc/lib/compat/ - method `DefinitionProperties addEvent(String event, String callback)` - method `DefinitionProperties removeEvents(String... events)` +### `FluidBuilder` + +Source: [ScriptFluidBuilder](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptFluidBuilder.java). + +- constructor `FluidBuilder(String name)`, from module `mmdlib:fluid` +- constructor `FluidBuilder(String name, String module)` +- getter `name` +- setters `density`, `viscosity`, `temperature`, `lightLevel` (int); `motionScale` (double) +- setters `canSwim`, `canDrown`, `canExtinguish`, `supportsBoating`, `canHydrate` (bool) +- setters `slopeFindDistance`, `levelDecreasePerBlock`, `tickRate` (int); `explosionResistance` (float); `canConvertToSource` (bool) +- setters `still`, `flowing`, `overlay` (string texture IDs); `tint` (int ARGB) +- setters `hasBlock`, `hasBucket` (bool); `displayName` (string) +- method `void build()` + ### `HitContext` Source: [ScriptHitContext](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptHitContext.java). @@ -331,6 +376,61 @@ Source: [ScriptItemUseHandler](../src/main/java/zone/moddev/mc/lib/compat/CraftT - method `void handle(ItemUseContext context)` +### `MachineCycleContext` + +Source: [ScriptMachineCycleContext](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptMachineCycleContext.java). + +- get `machine` — `BlockEntity getMachine()` +- get `level` — `Level getLevel()` +- get `pos` — `BlockPos getPos()` +- get `machineId` — `String getMachineId()` +- get `recipe` — `String getRecipe()` +- get `time` — `int getTime()` + +### `MachineCycleHandler` + +Source: [ScriptMachineCycleHandler](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptMachineCycleHandler.java). + +- method `void handle(MachineCycleContext cycle)` + +### `MachineHandlers` + +Source: [ScriptMachineHandlers](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptMachineHandlers.java). + +- static method `String onStart(String name, MachineCycleHandler handler)` +- static method `String onFinish(String name, MachineCycleHandler handler)` +- static method `boolean exists(String id)` + +### `MachineRecipeBuilder` + +Source: [ScriptMachineRecipeBuilder](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptMachineRecipeBuilder.java). Registered for the default `crafttweaker` loader (recipe scripts). + +- constructor `MachineRecipeBuilder(String recipeType)` +- method `MachineRecipeBuilder inputItems(String group, IIngredient ingredient, int count = 1, boolean consumed = true)` +- method `MachineRecipeBuilder inputFluid(String group, IFluidStack fluid, boolean consumed = true)` +- method `MachineRecipeBuilder inputFluids(String group, CTFluidIngredient fluids, boolean consumed = true)` +- method `MachineRecipeBuilder inputEnergy(String group, long energy)` +- method `MachineRecipeBuilder outputItem(String group, IItemStack stack, float chance = 1)` +- method `MachineRecipeBuilder outputFluid(String group, IFluidStack fluid, float chance = 1)` +- method `MachineRecipeBuilder time(int ticks)` +- method `void build(String name)` + +Machine recipes also have a CraftTweaker recipe handler +([MachineRecipeHandler](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/MachineRecipeHandler.java)): +dumps as builder calls, and decomposition into `crafttweaker:input/ingredients`, +`input/fluid_ingredients`, `output/chanced_items`, `output/fluids`, +`processing/time`, plus `mmdlib:machine/energy` and `mmdlib:machine/layout`. + +### `RecipeGenerators` + +Source: [ScriptRecipeGeneratorRegistry](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptRecipeGeneratorRegistry.java). Registered for the `mmdlib` loader; run on each data reload through [ScriptRecipeGenerator](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptRecipeGenerator.java). + +- static method `String register(String name, RecipeGeneratorFunction generator)` +- static method `boolean exists(String id)` +- `RecipeGeneratorFunction`: `void generate(RecipeGeneration generation)` +- `RecipeGeneration`: getter `recipeType`; methods `property(name, fallback = "")`, `intProperty(name, fallback)`, `doubleProperty(name, fallback)`, `tagIds(prefix)`, `hasTag(id)`, `tagItems(id)`, `recipe(name)` +- `GeneratedRecipe`: `inputItems`, `inputTag(group, tag, count = 1, consumed = true)`, `inputFluid`, `inputEnergy`, `outputItem`, `outputFluid`, `time`, `add()` + ### `MaterialBuilder` Source: [ScriptMaterialBuilder](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptMaterialBuilder.java). @@ -404,6 +504,127 @@ Source: [ScriptRedstoneHandler](../src/main/java/zone/moddev/mc/lib/compat/Craft - method `void handle(RedstoneContext context)` +### `ScreenClickContext` + +Source: [ScriptScreenClickContext](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenClickContext.java). + +- get `player` — `Player getPlayer()` +- get `blockEntity` — `BlockEntity getBlockEntity()` +- get `level` — `Level getLevel()` +- get `pos` — `BlockPos getPos()` +- get `screen` — `String getScreen()` +- get `element` — `String getElement()` +- get `button` — `int getButton()` +- get `shift` — `boolean getShift()` +- get `control` — `boolean getControl()` +- get `alt` — `boolean getAlt()` +- get `option` — `int getOption()` + +### `ScreenClickHandler` + +Source: [ScriptScreenClickHandler](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenClickHandler.java). + +- method `void handle(ScreenClickContext click)` + +### `ScreenHandlers` + +Source: [ScriptScreenHandlers](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenHandlers.java). + +- static method `String onClick(String name, ScreenClickHandler handler)` +- static method `String onHover(String name, ScreenHoverHandler handler)` +- static method `boolean exists(String id)` + +### `ScreenDecimalValue` + +Source: [ScriptScreenDecimalValue](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenDecimalValue.java). + +- method `double read(BlockEntity blockEntity)` + +### `ScreenFlagValue` + +Source: [ScriptScreenFlagValue](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenFlagValue.java). + +- method `boolean read(BlockEntity blockEntity)` + +### `ScreenHoverContext` + +Source: [ScriptScreenHoverContext](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenHoverContext.java). + +- get `blockEntity` — `BlockEntity getBlockEntity()` +- get `level` — `Level getLevel()` +- get `pos` — `BlockPos getPos()` +- get `screen` — `String getScreen()` +- get `element` — `String getElement()` +- get `entered` — `boolean getEntered()` + +### `ScreenHoverHandler` + +Source: [ScriptScreenHoverHandler](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenHoverHandler.java). + +- method `void handle(ScreenHoverContext hover)` + +### `ScreenTextValue` + +Source: [ScriptScreenTextValue](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenTextValue.java). + +- method `String read(BlockEntity blockEntity)` + +### `ScreenValues` + +Source: [ScriptScreenValues](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenValues.java). + +- static method `String whole(String name, ScreenWholeValue function)` +- static method `String decimal(String name, ScreenDecimalValue function)` +- static method `String flag(String name, ScreenFlagValue function)` +- static method `String text(String name, ScreenTextValue function)` +- static method `boolean exists(String id)` + +### `ScreenWholeValue` + +Source: [ScriptScreenWholeValue](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptScreenWholeValue.java). + +- method `long read(BlockEntity blockEntity)` + +### `SoundBuilder` + +Source: [ScriptSoundBuilder](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptSoundBuilder.java). + +- constructor `SoundBuilder(String name)` +- static method `SoundBuilder edit(String id)` +- static method `boolean exists(String id)` +- static method `String[] declared()` +- get `name` — `String getName()` +- get `range` — `float getRange()` +- set `range` — `void setRange(float value)` +- method `void build()` + +### `SoundTypeBuilder` + +Source: [ScriptSoundTypeBuilder](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptSoundTypeBuilder.java). + +- constructor `SoundTypeBuilder(String name)` +- static method `SoundTypeBuilder edit(String id)` +- static method `boolean exists(String id)` +- static method `String[] declared()` +- get `name` — `String getName()` +- get `base` — `String getBase()` +- set `base` — `void setBase(String value)` +- get `breakSound` — `String getBreakSound()` +- set `breakSound` — `void setBreakSound(String value)` +- get `stepSound` — `String getStepSound()` +- set `stepSound` — `void setStepSound(String value)` +- get `placeSound` — `String getPlaceSound()` +- set `placeSound` — `void setPlaceSound(String value)` +- get `hitSound` — `String getHitSound()` +- set `hitSound` — `void setHitSound(String value)` +- get `fallSound` — `String getFallSound()` +- set `fallSound` — `void setFallSound(String value)` +- get `volume` — `float getVolume()` +- set `volume` — `void setVolume(float value)` +- get `pitch` — `float getPitch()` +- set `pitch` — `void setPitch(float value)` +- method `void build()` + ### `ToolSettings` Source: [ScriptToolSettings](../src/main/java/zone/moddev/mc/lib/compat/CraftTweaker/ScriptToolSettings.java). @@ -475,7 +696,8 @@ from script callback execution are logged by the binding wrapper. | Runtime-supported through an existing generic script map | Tool stat overrides and generic tool settings; basic-item burn time | `MaterialStats`, `StandardItems.ToolSettings`, `StandardImplementations`; addSpecial/factoryData already reach them. Named stat methods and ToolSettings now wrap these existing paths; per-tool durability scaling is limited by TieredItem overriding durability. | | Schema-only in current standard runtime | food reference, lore, declared toolActions, general attributeModifiers, delayed-use onComplete/useFinishMode, creativeStacks | Stored in ItemTemplate/MMDItem; no standard runtime consumer found. Native tool attributes and generic tool abilities are separate implemented paths. | | Unavailable as a configurable definition capability | Item rarity/feature flags; advanced block predicates, piston reaction, instrument, offsets, solidity flags | Current definition/runtime property path does not represent and apply them. | -| Unavailable as a public script registration path | Custom sound events/types, independent tool tiers, user-defined creative tabs | Existing material tab/armor/tier machinery is not a general script builder API. | +| Unavailable as a public script registration path | Independent tool tiers, script fluid modules for materials | Existing material armor/tier machinery is not a general script builder API; scripts build standalone fluids, not modules materials select. | +| Script-exposed in 2.0.2 | Sound events and sound sets, creative tabs, standalone fluids, screen handlers and value providers, machine cycle handlers, machine recipes | `SoundBuilder`, `SoundTypeBuilder`, `CreativeTabBuilder`, `FluidBuilder`, `ScreenHandlers`, `ScreenValues`, `MachineHandlers`, `MachineRecipeBuilder`; each feeds the same definition or registry path as data files. | | Script-exposed in phase 3 | Typed ID references and module snapshot copies | New wrappers unwrap into existing consumers; copy rebinds locally owned callbacks with separate handler maps. | | Script-exposed in phase 4 | Fluent builder aliases, displayName, default/self/empty/referenced loot | Aliases use existing setters. Immutable ScriptResourceOptions metadata feeds the generated pack; external resources keep priority. | | Unavailable script conveniences | Arbitrary game-object property cloning | Module configuration copying does not clone registered game objects. | diff --git a/docs/crafttweaker-parity-plan.md b/docs/crafttweaker-parity-plan.md index 4c5e9998..cf248d1c 100644 --- a/docs/crafttweaker-parity-plan.md +++ b/docs/crafttweaker-parity-plan.md @@ -33,7 +33,8 @@ Do not claim parity merely because a value can be stored in a definition. | Gameplay callbacks | Retain current hooks and improve discovery/examples | No additional core event contracts | | Generated resources and drops | Expose names and simple loot options through the existing generated pack | Generated resources only; no change to block runtime loot-source properties | | Food, rarity, arbitrary attributes | Defer | RuntimeProperties does not apply these as configurable definition properties | -| Creative tabs and sound registration | Defer | No existing matching MMDLib public definition/registration path | +| Fluids | Done in 2.0.2 | Standalone fluids from data and `FluidBuilder`; materials still select fluid modules from files or code | +| Creative tabs and sound registration | Done in 2.0.2 | Script builders over the data-driven definitions; scripts can also edit file definitions | | Advanced block predicates/properties | Defer | Current block schema and runtime do not represent/apply them | ## Phase 1: establish the supported surface @@ -160,8 +161,12 @@ integration classes and excludes smoke classes/scripts/resources. See the currently applies only stack size, durability, fire resistance, and remainder. - Rarity, feature flags, general attribute configuration, lore, and new item actions: lack a complete applicable runtime path for this integration scope. -- Full CreativeTabBuilder, SoundEventBuilder, and custom SoundTypeFactory: would - require a new registration capability or a parallel integration-owned system. +- Creative tabs, sound events and sound sets: no longer deferred. 2.0.2 added + data-driven registration for each, and `CreativeTabBuilder`, `SoundBuilder` and + `SoundTypeBuilder` build on it. +- Fluids: no longer deferred. 2.0.2 added standalone fluids + (`mmdlib/standalone/fluid`) and a plain `mmdlib:fluid` module, and + `FluidBuilder` builds them from scripts. - State-dependent light/map color, spawning/suffocation/view/emissive predicates, piston reaction, instrument, offsets, and solidity flags: need new core property representation/application. `factoryData` alone cannot make these work. diff --git a/docs/crafttweaker.md b/docs/crafttweaker.md index fc931bb4..b84db9ba 100644 --- a/docs/crafttweaker.md +++ b/docs/crafttweaker.md @@ -69,7 +69,7 @@ runtime registration; sounds and map colors name vanilla constant keys. | `incorrectBlocks` | `minecraft:incorrect_for_iron_tool` | block tag this material's tools cannot harvest | | `baseBlock` | `minecraft:iron_block` | base behavior for factories such as stairs | | `blockSetType` | `minecraft:iron` | behavior for doors, buttons and pressure plates | -| `blockSound` | `""` | material block sound override, e.g. `wood`; empty keeps module sound | +| `blockSound` | `""` | material block sound override: a vanilla set such as `wood`, or a [sound set](#sounds) ID such as `mmdlib:steel_plate`; empty keeps module sound | | `mapColor` | `""` | material map-color override, e.g. `gold`; empty keeps module map color | Named methods `toolDurability(int)`, `toolEfficiency(double)`, @@ -143,7 +143,7 @@ is put in `minecraft:mineable/pickaxe`. | `friction`, `speedFactor`, `jumpFactor` | float | slipperiness (ice 0.98); walk and jump multipliers | | `lightLevel` | int | 0 to 15 | | `requiresCorrectTool`, `collision`, `occlusion`, `randomTicks`, `replaceable`, `hasItem` | bool | | -| `sound`, `mapColor` | string | such as `stone`, `wood`, `metal` | +| `sound`, `mapColor` | string | such as `stone`, `wood`, `metal`; `sound` may also be a [sound set](#sounds) ID | | `factoryData` | map | settings for the module's Java implementation | | `blockEntityData` | map, write-only | settings for a machine's block entity | | `baseBlock` | block ID | what stairs copy their behavior from | @@ -265,6 +265,47 @@ tin.build(); A module's tags go to every material part built from it. The part's art comes from the template of the module it was copied from, in the material color. +## Fluids + +`mods.mmdlib.FluidBuilder` builds a fluid with its own ID, like a +`mmdlib/standalone/fluid` file: the fluid, its flowing form, a liquid block and a +bucket. + +```zenscript +#loader mmdlib +import mods.mmdlib.FluidBuilder; + +var chocolate = new FluidBuilder("chocolate"); +chocolate.tint = 0xFF5C3A21; +chocolate.viscosity = 3000; +chocolate.canSwim = false; +chocolate.displayName = "Liquid Chocolate"; +chocolate.build(); + +var plasma = new FluidBuilder("plasma", "mmdlib:molten"); +plasma.lightLevel = 15; +plasma.hasBlock = false; +plasma.build(); +``` + +`new FluidBuilder(name)` starts from `mmdlib:fluid`, a plain water-like liquid with +water's textures; `new FluidBuilder(name, module)` starts from another fluid module, +such as `mmdlib:molten`. The fluid is `mmdlib:`, its flowing form +`mmdlib:flowing_` and its bucket `mmdlib:_bucket`. + +| Property | Sets | +| --- | --- | +| `density`, `viscosity`, `temperature`, `lightLevel`, `motionScale` | the fluid type's values; temperature in kelvin, water 300 | +| `canSwim`, `canDrown`, `canExtinguish`, `supportsBoating`, `canHydrate` | what entities and blocks can do with it | +| `slopeFindDistance`, `levelDecreasePerBlock`, `tickRate`, `explosionResistance`, `canConvertToSource` | how it flows | +| `still`, `flowing`, `overlay` | block-atlas textures, such as `"minecraft:block/water_still"`; an empty `overlay` removes it | +| `tint` | an ARGB tint over the textures; -1 for none | +| `hasBlock`, `hasBucket` | whether it has a liquid block (to be placed in the world) and a bucket | +| `displayName` | its English name; the bucket is "*name* Bucket" | + +MMDLib generates the bucket model, the liquid block's blockstate and the English +names; the textures are block-atlas textures, as in fluid module files. + ## Fluent conveniences and generated resource controls Property assignment remains supported. The following fluent aliases return their @@ -636,6 +677,389 @@ hammer.build(); Sneaking mines a single block. The game tests run this hammer (`src/runtimeTest/scripts/mmdlib_hooks.zs`). +## Screen handlers + +Screens, including XML machines' screens, are defined in XML; scripts can supply +what their click and hover handlers do. An element names a handler ID in +`on-click`, `on-right-click`, `on-shift-click`, `on-shift-right-click` or `on-hover` +(see [GUI screens](gui-screens.md)), and a script registers a function under that +ID: + +```zenscript +#loader mmdlib +import mods.mmdlib.ScreenHandlers; + +ScreenHandlers.onClick("eject", (click) => { + if (click.shift) { + click.player.addTag("ejected_all"); + } +}); + +ScreenHandlers.onHover("eject_hint", (hover) => { + println("Hovering " + hover.element); +}); +``` + +```xml +