promotional bannermobile promotional banner

Singularity Iteration

Singularity Iteration is a tech mod inspired by the Industrial Craft 2, bringing a relatively complete yet streamlined industrialization experience to Minecraft.
Back to Files

[SI] SingularityIteration-0.1.7.15-beta.jar

File name[SI] SingularityIteration-0.1.7.15-beta.jar
Uploader
MioPhaSideMioPhaSide
Uploaded
Sep 30, 2026
Downloads
45
Size
8.6 MB
Mod Loaders
NeoForge
File ID
9020845
Type
B
Beta
Supported game versions
  • 1.21.1

Curse Maven Snippet

NeoForge

implementation "curse.maven:singularity-iteration-1617642:9020845"

Learn more about Curse Maven

What's new

# Changelog v0.1.7.15 (English)

## Crossbreeding Agriculture Aligned with IC2 Experimental

- Restored the level, five attributes, stages, environmental requirements and harvest of the 52 corresponding crops from the local IC2 2.8.221-ex112; project extensions such as titanium and uranium are kept.
- Restored the 256-tick crop cycle, environmental supply/demand with low-environment death, four-parent weighted crossbreeding, genetic mutation, single-plant spread, weed infestation and Weed-EX protection.
- Completed double-rack crossbreeding, right-click harvest, left-click seed extraction, deep mineral roots, and manual hydration/fertilizing/herbicide; fixed nether wart accumulating progress without advancing stages. Base flowers and mushrooms now consume 4 plantings each.
- Corrected Gaussian yields and per-portion byproducts; removed empty-bag living-plant duplication, planting bag return, duplicate yield boosts and extra log drops from saplings; restored red wheat signal/glow, poisonous flowers, man-eating flowers and wart transformations.
- Added small diamond dust, ender pearl dust, milk wart, oil berry, Bob berry and the associated powder resources.
- Aligned the analyzer's tiered charging and output waiting, and added addon seed interfaces; aligned the manager/harvester's point-by-point scanning, energy use, restocking, water tank, upgrade slots and GUI.
- Kept legacy registration IDs and seed attributes; legacy IC2 crops with old-unit stage progress are cleared to the stage baseline once on first load. Crop sticks now require farmland, so legacy direct-ore-planting layouts need adjustment.
- Added 15 server-side agricultural regression tests; full scope, migration rules and verification boundaries are in the [implementation record](../docs/crop_ic2_alignment_progress.md).

## Geothermal Generator Alignment Audit (2026-09-30)

This section is an **audit conclusion**; no geothermal generator code was changed in this round.

- Baseline: IC2 1.12.2 `TileEntityGeoGenerator` + `TileEntityBaseGenerator`, plus the pre-refactor `source/用作修复2/…/mio_icif_geo_generator.java`.
- Parameters already aligned: 20 EU/t generation (vanilla `super(20.0D, …)` corresponds to `ENERGY_GENERATION_RATE = 20L`), 2400 storage, LV voltage with 32 EU/packet output, 8000 mB lava tank, lava only, 10 EU/mB conversion (vanilla `drainInternal(2)`/tick × 20 EU equivalent), 10000 EU per bucket, and the input (27,21) / output (27,54) / battery (117,49) slot coordinates.
- Not aligned: the `balance/energyfix/generator/geothermal` config multiplier is missing (currently hard-coded 20), the `Generators/GeothermalLoop.ogg` running sound is not implemented, and the 1000 mB lava spill on break (`FluidSpilledEvent`) is not implemented.
- Fuel loss on the non-takeover path: the current "pre-deduct a whole bucket, then count down" model means that when the buffer is full `generateEnergy()` does not run but `burnTime` still decreases, and the ungenerated remainder is cleared at zero; a single full-buffer tick loses hundreds of mB of lava without producing EU. Vanilla guarantees not a single drop is drawn while full via `needsFuel()` / `isConverting()`. This defect matches `用作修复2` and is a historical leftover, not introduced by this refactor.
- The takeover path adds `checkNearbyLavaBlocks()` adjacent-lava generation (1 EU/t per face), which conflicts with the accepted contract in `source/用作修复/SCEX-R28.md:11` ("adjacent world lava does not generate while takeover is enabled"). Adjacent-lava generation is an SI-specific extension absent from vanilla IC2, so keeping it on the non-takeover path is by design. This item needs confirmation as either a regression or a deliberate contract upgrade.
- Other: the comment "40,000FE per bucket" at `mio_icif_Block_Geo_Generator.java:28` is wrong — the actual constant is `ENERGY_PER_BUCKET = 10000`; after the parent changed to `AbstractGeneratorBlockEntity`, external energy supply is handled by `EnergyCompatibility.findEuStorage` / `pushDirect`. The file currently compiles without errors.

## Reactor Heat Extraction Chain Review (2026-09-30)

This section is a **review and naming clarification**; no related code was changed in this round.

### Heat Exchanger vs. Heat Conductor

- Naming clarification: the in-reactor component "heat exchanger" is `item_reactor_heat_switch`, while the "heat conductor" used in the heat exchanger machine's slot is `item_heatconductor` — two different items. The heat exchanger source comment calling that slot a "heat exchanger slot" is inaccurate; `canPlaceItem` actually validates `mio_icif_resources.HEATCONDUCTOR`, so a heat exchanger cannot go in.
- The in-reactor heat exchanger moves heat inside the reactor: `ReactorComponentType.HEAT_EXCHANGER` absorbs heat from fuel rods, passes it along chains of adjacent components to component vents, and melts down if its own heat buffer overflows. The four models are: basic heat exchanger 2500 storage, 12 to adjacent, 4 to the hull; component heat exchanger 5000, 36 to adjacent, none to the hull; reactor heat exchanger 5000, none to adjacent, 72 to the hull; advanced heat exchanger 10000, 24 to adjacent, 8 to the hull.
- "To adjacent" builds the conduction bridge fuel rod → heat exchanger chain → component vent; "to reactor" dumps heat into the hull and is the key part for heat-extraction power layouts. Separately, `mio_icif_heat_exchanger`, despite its class name, is actually a single/triple/hexa **coolant cell** — a different component class.
- The heat exchanger machine (`block_heat_source_fluid`) converts hot coolant into coolant and outputs HU: each heat conductor installed provides 10 HU/t, ten full slots cap it at 100 HU/t, and an empty machine produces nothing. Hot coolant is counted at 20 HU/mB (the same constant in `FluidReactorCycle` and the machine's `HU_PER_MB`).

### Heat Extraction Efficiency Comparison

- EU per HU: advanced stirling generator 0.85; stirling kinetic generator + basic kinetic generator 0.75 (4 HU + 1 mB water → 12 KU; basic kinetic generator 4 KU = 1 EU); stirling generator 0.5; steam generator → steam turbine → basic kinetic generator ≈ 0.499; with a turbine or twin turbine only 0.085 / 0.12, because `isNaturalKineticSource()` only recognizes water and wind, so this KU is treated as artificial kinetic and takes the 10% penalty.
- Without the advanced stirling generator, the recommended chain is **heat exchanger → stirling kinetic generator → basic kinetic generator**. The per-group cap is 250 EU/t: KU is output only from the front face, and the basic kinetic generator's `KineticReceiverStorage(10000, 1000)` accepts at most 1000 KU per tick; this consumes 333 HU/t and 83 mB water/t, and the equal amount of hot water produced must be drained continuously, otherwise the fluid heat tank fills up and the machine stops.
- If the stirling kinetic generator is also skipped, the stirling generator (0.5) and the steam chain (0.499) are essentially equal; choosing the stirling generator avoids the water supply, condenser, distilled-water slot clogging and overpressure explosion risk.
- The common bottleneck remains the heat exchanger machine: 100 HU/t per unit and heat is output only from the front face, regardless of the chosen power scheme.
- Verification boundary: the efficiencies above are derived by reading the code; in-game verification so far only covers a reactor with nine heat exchanger machines and a steam generator (see the [user nine-machine coolant loop fix](../docs/user_reactor_coolant_loop_fix.md)). The power chains after the heat exchanger machine have no GameTest backing yet; run one group at small scale before scaling up.

## Construction Foam / Scaffold / CF Sprayer Aligned with IC2 1.12.2 (2026-09-30)

Based on the local `source/IC2Code 1.12.2` (industrialcraft-2-2.8.221-ex112), this round refactors foam, scaffolds and the CF sprayer.

### Construction Foam `mio_icif_block_foam`

- Hardening now follows IC2 `BlockFoam.updateTick`'s **random-tick** formula: `chance = 1/(hardenTime*(16-light)*20) * 4096/randomTickSpeed`, with `hardenTime` 300 for normal and 600 for reinforced; light is the max of the block's own and adjacent block light. It is very slow in the dark but not absolutely impossible (matching the source).
- Block properties aligned: hardness 0.01, blast resistance 10, wool sound; before hardening there is no collision box and entities can pass through (matching `getCollisionBoundingBox` returning null).
- Right-clicking with sand hardens immediately and consumes 1 sand (matching `onBlockActivated`).
- Drops and products follow `FoamType`: normal foam hardens into a **CF wall** and drops **nothing** when broken; reinforced foam hardens into **reinforced stone (blast-proof stone)** and drops **1 iron scaffold** when broken.

### New block: CF wall `build/block_cf_wall`

- Registered `CONSTRUCTION_FOAM_WALL` (`mio_icif_blocks`) as the hardening product of normal foam.
- Completed resources: blockstate, block model (reusing the `block_foam` texture), item model, loot table, Chinese/English names (建筑泡沫墙 / CF Wall), and the `mineable/pickaxe` and `needs_stone_tool` tags.

### Scaffold `mio_icif_block_scaffold`

- Overhang strength aligned with IC2 `ScaffoldType`: wood 2 / iron 5; the project's extra tiers continue as steel 8 / carbon fibre 12 (extending IC2's reinforced wood 5 and reinforced iron 12).
- Added the `reinforced` blockstate and **right-click reinforcement**: wood scaffold + 2 sticks → reinforced (strength 5); iron scaffold + 1 iron fence → reinforced (strength 12); must be on a pillar connected to the ground; steel/carbon tiers cannot be reinforced (matching `onBlockActivated` + `isPillar`).
- Drops aligned: a reinforced scaffold additionally returns the reinforcement material when broken (wood scaffold +2 sticks / iron scaffold +1 iron fence).
- Climbing aligned with `BlockScaffold`: switched to `entityInside` (reset fall distance, horizontal speed cap ±0.15, sneak 0.08 (0.02 in water), against a wall 0.2, otherwise ≥ -0.07) together with `isLadder`, and removed the old `EntityTickEvent` reflection-based climbing event; the random tick is now a 1/8-probability fallback support check, and the placement check follows IC2's wood strength rule.
- Updated the 5 scaffold blockstate files (wood/iron/steel/carbon/titanium) to include the `reinforced` variant.

### CF sprayer `CFSprayerItem`

- Switched to IC2 `ItemSprayer`'s **fluid model**: capacity 8000 mB, 100 mB construction foam fluid per block; registers `Capabilities.FluidHandler.ITEM` in `mio_icif_capacities`.
- Keeps only IC2's two modes: normal (BFS flood up to **10 blocks**) and single (**1 block**), toggled with Shift+right-click.
- Targeting and placement follow `sprayFoam`: prefer scaffolds/cables, otherwise spray on the face adjacent to the click; **iron scaffolds → reinforced foam plus an iron fence drop**, wood scaffolds → normal foam; cables are encapsulated in foam.
- The durability bar, tooltip and the creative-tab full-loaded variant now display fluid amounts.
- The canning machine (`mio_icif_canner_elc`) now tops up the sprayer through the sprayer's fluid interface (up to 1000 mB of construction foam per operation).

### Migration and verification

- **Migration note**: the sprayer's stored amount changed from the old "256 durability points" to fluid NBT (`FluidId` / `FluidAmount`); foam values in old saves are not migrated and must be refilled in a canning machine. Scaffolds gain a `reinforced` state; old scaffolds default to unreinforced.
- This round's changes were reviewed line by line; Gradle compiles only `src/main/java` (+ `core`) and does not include any historical snapshot directory.
- Note: if the IDE reports "`fillFluid` / four-argument constructor undefined"-style errors, that is usually the Java language server indexing duplicate copies of same-named classes in same-named packages under `backup/` and `source/`. Those directories are already excluded via `java.import.exclusions` in `.vscode/settings.json`; restart the language server and the errors disappear — unrelated to the source.

## Tick Performance and Stability Refactor (2026-09-30)

This round merged the `source/修复代码` branch (base 0.1.7.14-beta, 2 commits, 36 files). **The merge ported each change by comparing them individually rather than overwriting whole files**: the `src` side has many local modifications, and a whole-file overwrite would lose them, so only the call sites involved were ported and everything else was kept as-is in `src`.

### Performance

- **Recipe lookup caching**: added `core/runtime/processing/RecipeLookupCache`. When the item, components and count of the input slot match the previous query it returns the previous result directly, skipping the full `getRecipeFor` scan; hits are verified with a hash check against `RecipeManager#byKey` so stale recipes are not returned after `/reload`; negative results are cached for `NEGATIVE_TTL_TICKS = 20` ticks (1 second), cutting idle or stalled machines' lookup cost to 1/20; on a miss it first retries the previously matched recipe before falling back to a full scan.
- **Coverage**: 14 machine files, each call site with its own cache instance (so different operations in the same machine do not evict each other) — compressor, macerator, extractor, electric furnace, induction furnace, washer, thermal centrifuge, block cutting machine, metal former (3 modes), molecular transformer, blast furnace (normal/advanced), industrial workbench, batch crafter. One static method call in `mio_icif_batch_crafter` was left unchanged because it has no instance. The canner's `CannerRecipeCache` is an existing implementation and is out of scope.
- **Reduced per-tick cost in the machine base class** (`AbstractProcessingMachineBlockEntity`): `hasAutomationUpgrade()` returns early when no insert/eject upgrade is installed, skipping block registry lookups, slot iteration and neighbour queries; the energy profile result is memoized once per instance (`standardProcessor`; the block type cannot change).
- **Neighbour capability lookups now use caches**: one NeoForge `BlockCapabilityCache` per face (one set for items, one for fluids), invalidated automatically by the engine when the neighbour changes; the original contract of "only operate when a block entity is adjacent" is preserved, and non-adjacent special positions plus client-side calls still use the original path.
- **Tank client sync throttling**: added `core/runtime/sync/ClientSyncThrottle` (`MIN_INTERVAL_TICKS = 5`). The first change after going idle is sent immediately; subsequent changes within 5 ticks are merged into one and flushed in `ServerTickEvent.Post`, guaranteeing the final state is always delivered with at most 5 ticks of HUD fluid delay; non-main-thread calls are sent as-is immediately, and removed blocks are cleaned up automatically.

### Defect fixes and crash prevention

- **Jetpack multi-thread concurrency**: `JetpackFlightController` removed the redundant `flyingPlayers` (that `WeakHashMap` was written concurrently by both client and server threads in single-player, and the value written was read back in the same call and always equalled the local variable); the flight-tick record `ACTIVE_TICKS` was split into `SERVER_ACTIVE_TICKS` / `CLIENT_ACTIVE_TICKS`, two `ConcurrentHashMap`s, fixing `isFlying()` flicker caused by both sides overwriting each other for the same UUID in single-player.
- **Advanced quantum chestplate**: removed the static `flyingPlayers` that was only ever `remove()`d and never read, plus the unused import.
- **Multiblock registry thread safety**: `register` / `unregister` / `getStructureAt` / `getStructureByController` / `getAllStructures` / `isControllerAt` in `ActiveMultiblocks` are all `synchronized`; `getAllStructures` returns a `List.copyOf` snapshot instead of a live view, avoiding `ConcurrentModificationException` when structures change during external iteration.

### Mojibake comment fixes

- Fixed GBK/UTF-8 mangled comments in 14 files, restoring the original Chinese/Japanese; only comments were touched, no code logic or string literals.
- Cross-check: conversion results containing out-of-order charsets were discarded to avoid damaging genuinely correct Chinese. Characters whose bytes were already lost at the mangled stage were not guessed (e.g. a missing character in "完全依靠能工作"), and the 34 occurrences in `mio_icif_solar_distiller.java` that could not be confirmed were left as-is.

### Not changed and verification boundaries

- **Energy network left as-is**: existing logic such as `IndependentSiEnergy` already has a per-tick computation cap; to avoid power outages or computation anomalies without in-game testing, no invasive change was made this round.
- **No build executed**: the conclusions above come from file-by-file comparison and IDE diagnostics (0 errors), not from a real run. Although the upstream cloud build reported BUILD SUCCESSFUL, its Linux-side lwjgl/netty are empty-JAR placeholders and it never actually ran the client.
- **Pending in-game verification**: continuous processing machines, tank pipe injection and multi-stage combined injection, jetpack flight and landing toggling, multiblock formation and teardown.
- **Leftover**: mojibake comments were logged as 17 files / 57 lines; this round located 14 by mojibake feature words, leaving 3 unlocated (comments only, no runtime impact).

## Batch Crafter Aligned with IC2 1.12.2 (2026-09-30)

Baseline: the local `source/IC2Code 1.12.2` (industrialcraft-2-2.8.221-ex112) `TileEntityBatchCrafter` / `ContainerBatchCrafter` / `GuiBatchCrafter` / `InvSlotUpgrade`; compared files: `mio_icif_batch_crafter`, `BatchCrafterMenu`, `mio_icif_gui_batch_crafter`, `mio_icif_block_batch_crafter`, `JEIPlugin`.

### Audited items (consistent this round, no changes)

- Properties: 20000 EU storage, tier 1 (= MV), 2 EU/t energy use, 40-tick base cycle, 4 upgrade slots, upgrade traits Processing / Transformer / EnergyStorage / ItemConsuming / ItemProducing.
- Slot layout and coordinates: phantom 3×3 grid (30+x·18, 17+y·18), output slot (124,35), 9 ingredient slots (8+i·18, 84), 9 container-return slots (8+i·18, 102), 4 upgrade slots (152, 8+i·18), battery slot (8,62), GUI height 206, progress bar (90,35), output preview (94,14).
- Crafting recipe `" I "/"ACA"/"HWH"` (industrial workbench + advanced circuit + advanced machine casing + hammer + wrench), block hardness 2.0 / resistance 10.0 / requires correct tool, Chinese/English names (批量工作台 / Batch Crafter).

### Restored execution model

- **Overclock model**: switched to `StandardProcessingTiming` (`ops = ceil(1/duration)`, `ticks = round(duration·ops)`), value-for-value equivalent to IC2's `getOpsPerTick` / `getOperationLength` / `getEnergyDemand`. Before the fix it added `ceil(1/mult)` progress per tick with a constant 40-tick cycle and only one item per operation; at 1 overclocker the measured figure was 20 ticks / 60 EU per item versus IC2's 28 ticks / 84 EU per item. Capacity now follows IC2's formula `20000 + cycle×energy + 10000/storage upgrade`, and IC2's non-existent `OVERCLOCKER_ENERGY_BONUS` was removed; the cycle length is written to the save (`scex_operation_ticks`) and progress is restored proportionally on load, so changing the overclocker count loses no progress and does not overflow.
- **Per-tick sequence**: a self-implemented `tickProduction()` restores IC2 `updateEntityServer`'s order — energy is paid once per tick, `++progress` reaching `operationLength` produces on the same tick, and `operations()` crafts are performed within the cycle. Before the fix it produced on the tick after reaching the end (effectively 41 ticks/item) and produced only one item per cycle.
- **Progress reset condition**: only "no recipe in the phantom grid" resets progress; a full output, insufficient energy or temporarily missing ingredients all preserve progress. `checkInputChanged()` is overridden as a no-op, removing the previous "ingredient slot change resets progress" behaviour.
- **Container-return slots**: restored IC2 `InvSlot.InvSide.NOTSIDE` — no longer extractable from the side and not participating in ejector as an automatic output slot.
- **Output gating**: the product is only written to `CRAFTING_OUTPUT_SLOT`, removing the previous "overflow into the 9 container slots" logic and restoring IC2 `craftingOutput.canAdd()`'s gate.
- **Ingredient balancing**: `balanceIngredients()` is now a `StackUtil.balanceStacks` equivalent (evenly redistribute the group total, skip slots holding other items, write back via `setStackInSlot` + `setChanged`); it is triggered every tick (`onTick`), on grid change (`matrixChange`) and on ingredient-row content change (a new `createItemHandler` override). Before the fix it was a pairwise `diff/2` heuristic whose only trigger, `ingredientChanged()`, had no callers.
- **Menu shift-click**: added `moveIngredientsBalanced()`, polling layer by layer to balance across all acceptable slots, corresponding to IC2 `ContainerBatchCrafter.handlePlayerSlotShiftClick`, replacing the previous sequential fill.
- **Comparator output**: added `getComparatorLevel()` = `progress * 15 / cycle`, wired on the block side through `hasAnalogOutputSignal` / `getAnalogOutputSignal`, matching IC2 `comparator.setUpdate`.

### Per-tick lookup optimization

- `canCraft()` gained an ingredient-row snapshot (item, components and count of the 9 slots), recomputed only after a grid change / row content change / completed craft / load, equivalent to IC2's `newChange` semantics; the steady-state per-tick cost drops from "build a crafting container + linearly scan the recipe table" to 9 reference comparisons.
- Added a static `gridMatches()` validation entry point for JEI transfers.

### JEI recipe transfer

- Added `BatchCrafterTransferHandler` (corresponding to IC2 `TransferHandlerBatchCrafter`): JEI's "+" writes the recipe layout into the 3×3 phantom grid template via `setCraftingGridStack()`, **without consuming the player's inventory** (the built-in `addRecipeTransferHandler` implementation moves items and is blocked by `PhantomSlot.mayPlace`, hence the custom handler).
- Layout restoration is more robust than IC2: first lay out in JEI input slot order and validate with `gridMatches()`; on mismatch, enumerate all legal offsets within the 3×3 for a `ShapedRecipe` and take the first real match; representative items prefer ones already in the player's inventory.
- Registered in `JEIPlugin.registerRecipeTransferHandlers`: `addRecipeTransferHandler(new BatchCrafterTransferHandler(), RecipeTypes.CRAFTING)`.

### Migration and verification boundaries

- **Save compatibility**: phantom grid, progress and cycle length are all persisted; the cycle length scales proportionally with the overclocker count. If an existing layout relies on "hoppers pulling container returns" or "products overflowing into container slots", it must be changed to taking items only from the output slot and retrieving container returns manually.
- **Verified**: `gradlew compileJava` BUILD SUCCESSFUL; all changes are per-site replacements based on the source, with no whole-file overwrites.
- **Pending in-game smoke test**: ① no overclocker → 40 ticks/item, 80 EU/item; ② 2 overclockers → 20 ticks/item, about 100 EU/item with a multi-craft cycle; ③ hoppers cannot pull container returns and products do not flow into container slots; ④ shift-click and pipe input spread evenly across the 9 slots; ⑤ JEI "+" writes into the phantom grid and does not consume inventory items.
- **Left as-is**: no new GameTest; the boundary where the same ingredient row matches a different recipe after `/reload` is still covered by `RecipeLookupCache`'s 20-tick negative cache and the `byKey` check, matching IC2.

## Crop Harvester / Crop Matron Realigned to IC2 1.7.10 (2026-09-30)

The baseline was **changed** from `source/IC2Code 1.12.2` (2.8.221-ex112) to `source/IC2CodeNew` (industrialcraft-2-2.2.828-experimental, 1.7.10). Compared files: `TileEntityCropHavester` / `TileEntityCropmatron` / `ContainerCropHavester` / `ContainerCropmatron` and `TileEntityCrop.harvest_automated` / `applyFertilizer` / `applyHydration` / `applyWeedEx`. All parameters that the previous version based on 1.12.2 are rewritten to 1.7.10 in this round.

### Harvester `mio_icif_harvest_elc`

- **Scan range** 9×3×9 (243) → **11×3×11 (363)**: ±5 horizontally, -1..1 vertically, stepping in exactly the same order as vanilla's `scanX/scanY/scanZ`.
- **Rhythm and energy**: from "scan every 10 ticks, threshold 21 EU" to **"scan every tick, threshold 201 EU"**; harvest cost 20 → **100 EU per drop**, plus another **100 EU per drop** when a crop analyzer is installed.
- **Harvest rule** changed to match 1.7.10 `harvest_automated(boolean optimal)`: **without an analyzer** it harvests as soon as `canBeHarvested()` is true; **with an analyzer** it enters optimal mode and additionally requires `growthStage == getOptimalHarvestStage()`. (The previous 1.12.2 rule was `size == optimal || size == max`.)
- **Restored the crop analyzer slot** (1 slot, automation input from the top only, matching `InvSlotConsumableId`'s `InvSide.TOP`); **upgrade slots 4 → 1**.
- **Upgrade traits** narrowed from Transformer / EnergyStorage / ItemProducing to **`ITEM_PRODUCING` only**.
- Slots are: `0–14` harvest storage (`InvSlot.Access.IO`, insertable and extractable), `15` crop analyzer, `16` battery (extension), `17` upgrade — **18** in total.

### Crop matron `mio_icif_matron_elc`

- **Storage 10000 → 1000 EU** (1.7.10 `super(1000, 1, 0, 2)`; tank capacity = 1000 × 2 = 2000).
- **Scan range → 363, rhythm changed to every tick**, start threshold still 31 EU (1 scan + 3×10 operations).
- **Weeding aligned with `applyWeedEx`**: from "top up to 150" to **"add a fixed +50 each time, stopping at 150"**.
- **Herbicide slots 1 → 7**; **removed the separate empty-container output slot for herbicide** (herbicide uses durability containers that vanish when exhausted, producing no empty container).
- Slots are: `0` battery (extension), `1` water container input (top), `2` empty container output, `3–9` fertilizer (7), `10–16` herbicide (7), `17–20` upgrades (4, extension) — **21** in total.
- Unchanged: fertilizing `+90` (cap 100), watering refills 200, farmland moisture to 7, water tank 2000 mB, fertilizer accepts only the dedicated crop fertilizer item, fluid containers are automation-input from the top only.

### Retained extensions and implementation notes

- The **battery slot** (1 each in both machines) and the **matron's 4 upgrade slots** are deliberate project extensions — 1.7.10 has neither; upgrade slots are not exposed to automation (matching vanilla `InvSlotUpgrade`), and the upgrade traits keep the 1.12.2 set (Transformer / EnergyStorage / ItemConsuming / FluidConsuming), filtered by `isSuitableFor`.
- **Herbicide chain**: retains "item → `weedExTank` buffer → consume 50 each time"; `MatronHerbicideItem` is 64 durability × 50, so **1 durability point corresponds to exactly 1 weeding**, equivalent to 1.7.10's per-use consumption.
- **Analyzer slot count**: 1.7.10 declares `cropnalyzerSlot` as 7 slots but only uses slot 0 (and the GUI shows only 1), so it is implemented as 1 slot here; the analyzer is a placeholder item and does not consume durability.
- Weeds are still naturally excluded by `canBeHarvested()` (matching vanilla `CropWeed#canBeHarvested` returning false), with no hard-coded check.

### Impact and verification boundaries

- **Migration note**: slot indices and counts change for both machines (harvester 20 → 18, matron 16 → 21), so machines already placed in old saves need their item slots rearranged; the matron's storage cap drops from 10000 to 1000.
- **Verified**: `gradlew compileJava` BUILD SUCCESSFUL, 0 errors.
- **Pending in-game smoke test**: ① harvester harvests by `canBeHarvested` without an analyzer and only optimal-size crops with one installed, at the extra 201 EU/scan threshold; ② matron adds +50 per weeding with a 150 cap, one herbicide durability per use; ③ when fully charged it scans one cell per tick, 363 ticks per pass.

## Ore Generation Count Balance (2026-09-30)

Using the vanilla 1.21 Java main vein `count` values as reference — copper `ore_copper` 16, iron `ore_iron_middle` 10, gold `ore_gold` 4, diamond `ore_diamond` 7 — the relative rarity of this project's tin, lead, uranium, titanium and niobium is adjusted. Only `minecraft:count` is changed; `size` (ore per vein) and the height ranges stay the same.

### Adjusted counts

Ore Overworld shallow Overworld deep Twilight Forest shallow/deep Reference
Tin 16 → **12** 12 → **2** 16/8 → **12/2** copper 16 > tin 12 > iron 10
Lead 12 → **4** 10 → **2** 12/6 → **4/2** gold 4 (plus `ore_gold_lower` 1)
Uranium 8 → **3** 6 → **2** 4/2 → **3/2** lead 4/2 (one less in total)
Niobium 4 → **3** 3 → **1** 4/3 → **3/1** rarer than gold 4 (the rarest)
Titanium 20 → **7** 20 → **4** 20/20 → **7/4** diamond 7 / `ore_diamond_buried` 4

- **Tin**: shallow 16 → 12, deep 12 → 2, 14 veins in total. Shallow is above iron's main vein `ore_iron_middle` (10) and below copper `ore_copper` (16); the deep count is compressed to 2 so that shallow + deep do not overtake copper (the original 16/12 totalled 28 veins, already more than copper).
- **Lead**: reduced from 12 to 4, the same order of magnitude as gold — the original value was about 3× `ore_gold`, clearly too abundant.
- **Uranium**: shallow 8 → 3, deep 6 → 2, 5 veins in total, below lead (4/2 = 6 veins).
- **Titanium**: changed from 20/20 to 7/4, matching diamond's `ore_diamond` / `ore_diamond_buried` item by item (swapping tiers with niobium). `size` is 9, about 99 blocks per chunk.
- **Niobium**: changed from 4/3 to 3/1, replacing titanium as the rarest ore in the mod (swapping tiers with titanium). `size` is 6, about 24 blocks per chunk.
- **Twilight Forest variants**: the original values did not match the Overworld (uranium 4/2, lead deep 6, tin deep 8); this round unifies them to the same Overworld count set. Titanium and niobium Twilight variants also use the same values as the Overworld.

### Affected files

The 20 JSON files under `src/main/resources/data/mio_icif/worldgen/placed_feature/`: `tin_ore_placed`, `tin_ore_deep_placed`, `tin_ore_twilight_forest_placed`, `tin_ore_deep_twilight_forest_placed`, `lead_ore_placed`, `lead_ore_deep_placed`, `lead_ore_twilight_forest_placed`, `lead_ore_deep_twilight_forest_placed`, `uran_ore_placed`, `uran_ore_deep_placed`, `uran_ore_twilight_forest_placed`, `uran_ore_deep_twilight_forest_placed`, `titanium_ore_placed`, `titanium_ore_deep_placed`, `titanium_ore_twilight_forest_placed`, `titanium_ore_deep_twilight_forest_placed`, `niobium_ore_placed`, `niobium_ore_deep_placed`, `niobium_ore_twilight_forest_placed`, `niobium_ore_deep_twilight_forest_placed`; the corresponding `configured_feature` and `neoforge:biome_modifier` files are unchanged.

### Verification boundaries

- Only data pack JSON values were changed; no build was executed and there was no in-game verification.
- **Migration note**: vein counts are written when a chunk is **first generated**, so already-generated chunks do not change; new chunks or new chunk areas are required.
- The "shallow / deep" columns are two `placed_feature` entries split from the same ore in this project, so **the actual veins per chunk are their sum** (e.g. tin 12 + 2 = 14).
- The reference values are vanilla Java 1.21; if biome-specific bonuses such as `ore_copper_large` (dripstone cave, 16×20) or `ore_iron_upper` (mountains, 90) are introduced later, the effective ratio will deviate from the table above.

## Rubber Tree System API Exposure (2026-09-30)

The rubber wood / resin harvesting logic previously inside the `common` package was extracted into `core` and interfaces were exposed, so addons can build resin-tapping tools, define custom rubber wood and reuse the harvesting flow.

### Core logic extraction

- Added `core/runtime/world/RubberTreeSystem`: pure logic decoupled from registry content, centralizing tool/block checks, drop-count rolls, harvesting (durability or energy cost, resin drop, clearing the resin state) and random-tick regrowth. The resin item is passed in by the caller as an `Item`, so `core` does not depend on `common`.
- Regrowth chance, drop ranges and other constants/rules are maintained in this one place only; the block and the API share the same implementation, removing the two previously duplicated harvesting/drop code paths in `BlockRubberWood` and `mio_icif_have_rub_wood`.

### New public interfaces (core.api)

- `core.api.world.IRubberTreeAPI`: the system entry point, providing `getResinItem` / `createResinStack`, `isTreeTap` / `isElectricTreeTap` / `isRubberWood` / `hasResin` / `isTappable` / `canHarvest` / `canUseTapOn`, `tryHarvest` / `rollResinCount` / `dropResin` / `tryRegrowResin` / `getResinRegrowChance`.
- `core.api.world.RubberHarvestResult`: harvesting result record (`harvested` / `resinCount`).
- `core.api.block.IRubberWood`: rubber wood block interface (`hasResin` / `isTappable` / `withResin` / `canRegrowResin`); addons implementing it on a custom log get handled uniformly by this mod's collectors.
- `core.api.item.ITreeTapItem`: extended from an empty marker interface with default harvesting parameters `getDurabilityCost()` (default 1), `getResinDropMin()` (1) and `getResinDropMax()` (3), all `default`, so existing implementations compile unchanged.
- `MioIcifAPI` gained `getRubberTreeAPI()`; the capability list at the top of `MioIcifAPI` and the `core.api` `package-info` were updated accordingly.

### Implementation and wiring

- Added `common/service/world/RubberTreeAPIImpl`: delegates to `RubberTreeSystem` and only binds the resin item `mio_icif_resources.HARZ` (`resource/item_harz`).
- `common/bootstrap/CommonApiServices` gained lazy loading of `getRubberTreeAPI()`, following the existing holder/lazy-singleton pattern.

### Block refactor

- `BlockRubberWood` and `mio_icif_have_rub_wood` now `implements IRubberWood`; `useItemOn` checks via `RubberTreeSystem.canUseTapOn` (harvestable + tool + energy) and `randomTick` delegates to `RubberTreeSystem.tryRegrowResin`.
- Removed the fragile item-name string check (`itemName.contains("treetap")`) in favour of `ITreeTapItem` interface checks.

### Harvester parameters

Tree tap Durability/use Energy/use Drop
Wooden `item_tool_wooden_treetap` 1 — 1~3
Electric `item_tool_treetap_elc` 0 10 EU 2~4

- `mio_icif_treetap_elc` overrides the `ITreeTapItem` parameters: `getDurabilityCost() = 0`, drop 2~4; the wooden one keeps the defaults of 1 durability and 1~3. Behaviour matches the state before this refactor.

### Compatibility and migration

- **Behaviour change**: rubber wood harvesting switched from "item name contains `treetap`" to the `ITreeTapItem` interface, so third-party items relying on the naming convention no longer work and must implement the interface.
- The new `ITreeTapItem` methods are all `default`, so it is backward compatible; existing implementations need no changes.
- The public API is purely additive; no existing method signatures or registration IDs were changed, and save data is unaffected.

### Affected files

- Added: `core/api/world/IRubberTreeAPI.java`, `core/api/world/RubberHarvestResult.java`, `core/api/block/IRubberWood.java`, `core/runtime/world/RubberTreeSystem.java`, `common/service/world/RubberTreeAPIImpl.java`.
- Modified: `core/api/item/ITreeTapItem.java`, `core/api/MioIcifAPI.java`, `core/api/package-info.java`, `common/bootstrap/CommonApiServices.java`, `common/block/environment/BlockRubberWood.java`, `common/block/environment/mio_icif_have_rub_wood.java`, `common/item/tools/mio_icif_treetap_elc.java`.
- Docs: `docs/addon_development_guide.md` gained section 10 "Rubber tree system (rubber wood and resin harvesting)" with the old sections 10~19 renumbered to 11~20; the API table in section 3, the API quick-reference table, the threading constraints and the common errors table were updated as well.

### Verification boundaries

- `gradlew compileJava` BUILD SUCCESSFUL, 0 errors (only the pre-existing deprecation warnings).
- No in-game smoke test; suggested checks: ① drops and energy cost of the wooden/electric tap on `block_rub_wood` and `block_have_rub_wood`; ② after harvesting the block becomes resin-less and regrows by random tick at 5%; ③ the electric tap stops harvesting when out of energy.
- Rubber tree world generation (`common/world/feature/*` and biome modifiers) is unchanged in this round and remains in `common`.

## Full Decoupling of Armor Features (2026-09-30)

Armor "feature declaration / state read-write / tooltip rendering / feature management GUI / command and network sync" was previously scattered across `common` with hard-coded parts, so addons building jet armor hit unreadable state, unclickable tooltips, unusable mode features and no back-slot management. This round converges it into public `core` contracts.

### core additions and adjustments

- Added `core.prefab.item.ArmorFeatureState`: unified storage for toggle features (CustomData key `feat_`, **enabled by default when absent**), independent of any concrete item/registry.
- Added `core.prefab.item.ArmorFeatures`: the unified dispatch entry point — declaration queries (`features`/`find`/`isDeclared`/`isToggleFeature`/`isModeFeature`) and `isEnabled`/`setEnabled`/`toggle`/`cycleMode`/`toggleOrCycle`.
- Added `core.prefab.item.ArmorFeatureTooltip`: unified **clickable** tooltip rendering (toggle inversion / mode cycling, command `/mio_icif toggle `).
- Added `core.api.item.IArmorModeFeatureItem`: generic mode-type feature switching interface (`cycleMode`).
- `IJetpackItem` now extends `IBatteryItem, IArmorModeFeatureItem`, adds the constant `FEATURE_MODE_KEY`, and provides a default `cycleMode` (hover ↔ flight); jetpacks need no extra code to be recognized by the generic GUI.
- `IItemAPI` gained `isArmorFeatureEnabled` / `setArmorFeatureEnabled` / `cycleArmorFeature` / `getArmorFeatureInfo` (previously only `toggleArmorFeature` could write, never read).
- `AbstractElectricArmor`: tooltips are now rendered uniformly by `ArmorFeatureTooltip` (with its own click handling), `isFeatureEnabled` delegates to `ArmorFeatureState`, and the **default value is unified from false to true**, matching the semantics the GUI/command/item logic actually used.
- The flight base moved from `core.runtime.flight` to **`core.prefab.flight`** (`JetpackFlightController` / `JetpackKeyHandler`) so addons can legitimately reuse lift, hover, height limits and key input.

### common adjustments

- `ArmorFeatureToggle` was downgraded to a **delegating shell** (marked `@Deprecated`), forwarding everything to `core`; existing armor classes calling `ArmorFeatureToggle.isEnabled(…)` need no changes and behave identically.
- Added `common.item.armor.ArmorFeatureSlots`: uniformly provides "equipment slots with manageable features" — the four vanilla slots plus an optional Curios `back` slot (reflective `JetpackCuriosAdapter`, degrading automatically without Curios).
- Added `ArmorFeatureCyclePacket` and `mio_icif_Network.sendArmorFeatureCycle(…)`; `ArmorFeatureTogglePacket`'s slot field changed from `EquipmentSlot` to the generic slot identifier `String` (`head/chest/legs/feet/back`) and now supports a "fall back to searching all slots when the declared slot differs from the actual one" path.
- The feature management GUI (`mio_icif_gui_armor_features`): removed the `jetpack_mode` and `IJetpackItem` special cases and switched to generic toggle/cycle dispatch; the row count is computed dynamically from the actual slots and includes the Curios back slot.
- `ToggleCommand`: removed the hard-coded `ARMOR_FEATURES` and feature-name maps; the feature list and completions now come entirely from `ArmorFeatures.features(…)`, and slot completion gained `back`.
- `TooltipInteractionHandler`: removed the `IJetpackItem` special case and switched to generic `ArmorFeatures.toggleOrCycle`.
- `JetpackModeSwitchPacket`: now reuses `ArmorFeatureSlots` + `ArmorFeatures.cycleMode`, dropping its own Curios reflective lookup.
- `JetpackCuriosAdapter`: added read/write for the back-slot item (`backFeatureStack` / `writeBackFeatureStack`).
- `mio_icif_chestplate_quantum`: `jetpack_mode` corrected from a toggle declaration to a **mode** declaration carrying the current mode name, so it displays and switches correctly in the generic GUI.
- The language files gained `gui.mio_icif.armor_features.empty_back`.

### Compatibility and migration

- **Toggle default unified to "enabled"**: the `AbstractElectricArmor` default changed from false to true; previously it only appeared as false when addons overrode the tooltip themselves, which was an inconsistency.
- **Network packet format change**: `ArmorFeatureTogglePacket`'s slot field went from `EquipmentSlot` to `String`; client and server on the same version, so no save migration is needed.
- `ArmorFeatureToggle` and its `FeatureInfo` record are kept but deprecated; use `IItemAPI` or `core.prefab`'s `ArmorFeatures` / `ArmorFeatureState` / `ArmorFeatureTooltip` instead.
- Old behaviour preserved: `jetpack_mode` is still the hover↔flight toggle; the K key, the tooltip click command path and the `/mio_icif toggle` argument format are unchanged.

### Affected files

- core added: `api/item/IArmorModeFeatureItem.java`, `prefab/item/ArmorFeatureState.java`, `prefab/item/ArmorFeatures.java`, `prefab/item/ArmorFeatureTooltip.java`, `prefab/flight/JetpackFlightController.java`, `prefab/flight/JetpackKeyHandler.java`.
- core modified: `api/item/IJetpackItem.java`, `api/item/IItemAPI.java`, `prefab/item/AbstractElectricArmor.java`; removed `core/runtime/flight/*`.
- common added: `item/armor/ArmorFeatureSlots.java`, `network/ArmorFeatureCyclePacket.java`.
- common modified: `item/armor/ArmorFeatureToggle.java`, `item/armor/mio_icif_armor_elc.java`, `item/armor/mio_icif_chestplate_quantum.java`, `service/item/ItemAPIImpl.java`, `client/screen/mio_icif_gui_armor_features.java`, `client/TooltipInteractionHandler.java`, `command/ToggleCommand.java`, `network/ArmorFeatureTogglePacket.java`, `network/JetpackModeSwitchPacket.java`, `network/mio_icif_Network.java`, `integration/curios/JetpackCuriosAdapter.java`, `integration/curios/ElectricFlightRingCurio.java`, `client/mio_icif_ClientEvents.java`, `event/mio_icif_events.java`, `network/mio_icif_KeyboardManager.java`, `network/JetpackKeyStatePacket.java`, `Singularity_Iteration.java`.
- Resources: `assets/mio_icif/lang/zh_cn.json` and `en_us.json` gained `gui.mio_icif.armor_features.empty_back`.
- Docs: `docs/addon_development_guide.md` gained "9.5 Armor features and jet armor" plus package-boundary/API table/query table/threading/common-error updates; `docs/core_addon_guide.md` gained "7. Item and equipment contracts" and the package boundary table lists equipment and the flight base.

### Verification boundaries

- `gradlew compileJava`, `gradlew checkCoreArchitecture` and `gradlew compileAddonExampleJava` are all BUILD SUCCESSFUL with 0 errors (only pre-existing deprecation warnings).
- No in-game smoke test; suggested checks: ① tooltip click toggles and mode lines for the quantum/nano series; ② the Alt GUI showing and switching (toggle inversion, mode cycling); ③ with Curios installed the back-slot jetpack appears on GUI row 5 and its mode can be switched; ④ the K key and the tooltip click paths produce the same state; ⑤ new items default to feature "on".

## Charge-Carrying Recipe JEI Shape Fix and Electric Tree Tap Made Shapeless (2026-09-30)

### Root cause: shaped "charge carrying" recipes were drawn as one row in JEI / EMI

- `ChargeCarryingRecipe` (`mio_icif:charge_carrying`) previously only `implements CraftingRecipe`. The crafting table, recipe book, JEI and EMI rely on `instanceof ShapedRecipe` to get `getWidth()` / `getHeight()` for the real shape; without a shape they can only lay `getIngredients()` out in a single row, producing the misalignment "JEI shows two materials side by side on the first row while the craft actually requires a vertical layout", and the "+" one-click fill placed items in the wrong slots.
- Fix: `ChargeCarryingRecipe` now `extends ShapedRecipe` (`super(group, CraftingBookCategory.MISC, pattern, result)`). The recipe JSON format, matching logic and charge settlement are all unchanged; `getSerializer` / `assemble` / `getRemainingItems` remain overridden, while `matches` / `canCraftInDimensions` / `category` / `getIngredients` / `isSpecial` are handed back to the parent. About 60 shaped charge-carrying recipes (all electric tools) are affected.
- `ChargeCarryingShapelessRecipe` (`mio_icif:charge_carrying_shapeless`) is **unchanged**: it is still the mod's own implementation, not vanilla `ShapelessRecipe`. Shapeless recipes are shown as "one row of materials" in viewers, which already matches shapeless semantics, so there is no misalignment.

### Electric tree tap recipe changed to "charge carrying - shapeless"

- `data/mio_icif/recipe/shaped_315_treetap_elc.json` → `shapeless_315_treetap_elc.json`: `type` changed to `mio_icif:charge_carrying_shapeless`, `transfer_charge: true` retained, materials are **wooden tree tap + small drive handle + LV cable**, placeable in any of the three slots; the old 1×2 shaped recipe file was deleted and has no remaining references in the project (the same product no longer shows two recipe pages).
- The temporary form used during investigation (removing the wooden tree tap from the recipe) was reverted, and the wooden tree tap is a required material again.

## Lightning Energy Icon Rendering and Energy Cap Clamping (2026-09-30)

- **Constant semantics clarified**: `LIGHTNING_WIDTH/HEIGHT` are the icon's width and height, while `LIGHTNING_TEXTURE_X/Y` are the icon's top-left pixel position in the atlas. Fixed the reversed u/v in the base class `mio_icif_screen` (`textureV` mistakenly used `LIGHTNING_TEXTURE_X`), which made `drawLightningEnergyFill` sample from the wrong row.
- **Render-layer defence**: `drawLightningEnergyFill`'s fill height is clamped to `LIGHTNING_HEIGHT`, and `drawProgressArrowFill`'s fill width is clamped to `ARROW_WIDTH`. Even if `energy > maxEnergy` data appears again, it will only show a full bar instead of sampling beyond the atlas component upward/rightward (the previous symptom was "a large area of atlas content painted above the lightning icon, clearly not 14px").
- **Root-cause fix**: `CustomEUEnergyStorage.setCapacity` now clamps the stored amount when the capacity shrinks (`scexSetWholePreservingFraction(min(energy, capacity))`), fixing `energy > capacity` caused by "charging to a high value with an overclocker / storage upgrade installed → removing the upgrade drops the cap but not the stored amount". Storages hosted by the independent energy grid use the same strategy via `setEnergy` (the nominal capacity is not a cap); the deposit refund in `InternalPayment.cancel` does not go through capacity clamping.
- **Behaviour change**: after removing a storage / overclocker upgrade, the EU above the new cap is clamped away (consistent with IC2 machine buffers); machines already out of range in old saves self-heal on the next load (`loadAdditional`'s `apiSetEnergy` runs after `recalculateUpgradeStats`).

## Recipe and JEI Item List Fixes (2026-09-30)

- **Irradiant uranium ingot recipe now uses a tag**: in `asp_irradiant_uranium_ingot.json` the uranium ingot changed from the hard-coded `mio_icif:resource/item_uranium_ingot` to the tag `c:ingots/uranium`. This mod already provides that tag in `data/c/tags/item/ingots/uranium.json`; crafting with this mod's own ingot is unchanged, and other mods' uranium ingots also work. The other recipes that use the irradiant uranium ingot as a **material** (`asp_irradiant_glass_pane`, `asp_enriched_sunnarium`) are unchanged.
- **Raw silver ore not searchable in JEI**: the root cause is that JEI collects its item list from the **creative tab's displayItems** (log line `mezz.jei.library.plugins.vanilla.ingredients.ItemStackListFactory: Items from this group will be missing from the JEI ingredient list`), and `mio_icif_resources.RAW_SILVER` (`resource/item_raw_silver_ore`, Chinese name "粗银矿", with model / texture / localization all present and no log errors) was the only raw ore item never `output.accept`ed into the creative tab — raw tin / lead / uranium / niobium / titanium all appear in their own subsections. Fix: added `output.accept(mio_icif_resources.RAW_SILVER.get())` to the silver subsection in `mio_icif_creativeTabs`.
- **Lesson**: new items must be `output.accept`ed into the creative tab, otherwise JEI silently cannot find them and reports nothing; this mod has no "raw silver ore block" (`BLOCK_RAW_*` covers only tin / lead / uranium / niobium / titanium), so no block is needed.

### Affected files

- Code: `common/recipe/charge_carrying/ChargeCarryingRecipe.java`, `common/item/mio_icif_creativeTabs.java`, `core/runtime/energy/CustomEUEnergyStorage.java`, `common/client/screen/mio_icif_screen.java`.
- Data pack: added `data/mio_icif/recipe/shapeless_315_treetap_elc.json`, deleted `shaped_315_treetap_elc.json`, modified `data/mio_icif/recipe/asp_irradiant_uranium_ingot.json`.

### Verification boundaries

- `gradlew compileJava --offline` EXIT=0 (only the pre-existing `mio_icif_bat` deprecation warnings), 0 linter entries.
- Data pack changes need `F3+T` or re-entering the world; creative tab / JEI changes need a client restart.
- Pending in-game verification: ① shaped charge-carrying recipes show their real 3×3 layout in JEI and "+" fills the right slots; ② the electric tree tap crafts with its three materials in any arrangement and inherits charge; ③ after removing an overclocker / storage upgrade the stored amount does not exceed the new cap and the lightning icon no longer paints outside its frame; ④ the irradiant uranium ingot can be crafted from other mods' uranium ingots; ⑤ raw silver ore is searchable in both the creative tab and JEI.

## Recipe Ingredient Tag Conversion (2026-10-01)

### Hard-coded `mio_icif:resource/item_*` replaced with common tags

- A full scan of the **963** recipe files under `data/mio_icif/recipe` found **202** ingredients still hard-coded as `mio_icif:resource/item_*`; **127** of them had a semantically equivalent tag and were converted to `"tag"` form across **116 files**.
- Only **ingredients** (`key` / `ingredient` / `input` / `ingredients`) were changed; every `result.id` output is left untouched. Only tags 1:1 equivalent to the item were used, to avoid widening the recipe semantics.
- Main mappings:

Hard-coded item Replaced with
`item_rubber` (30 occurrences) `c:rubber`
`item_*_dust_small` `c:dusts/small_`
`item_diamond_dust_small` / `item_emerald_dust_small` `c:tiny_dusts/diamond` / `c:tiny_dusts/emerald` (no matching `small_` tag)
`item_*_ore_crushed` / `_purified` `c:crushed_ores/` / `c:purified_ores/`
`item_*_denseplate` `c:dense_plates/`
`item_*_shaft` / `*_rotor_blade` / `item_carbon_rotorblade` `c:shafts/` / `c:rotor_blades/`
`item_ingot_tin` / `item_silver_ingot` / `item_alloy_ingot` / `item_niobium_titanium_ingot` `c:ingots/tin` / `c:ingots/silver` / `c:ingots/alloy` / `c:ingots/niobium_titanium`
`item_cf_dust` `c:dusts/cf`
`item_irradiant_uranium_ingot` `mio_icif:irradiant_uranium`
`item_nano_living_metal` / `item_plant_extract` `mio_icif:nano_living_metals` / `mio_icif:plant_extracts`

- **Deliberately left hard-coded** (75 occurrences):
  1. `item_harz` — its tag `c:slime_balls` would let other mods' slime balls through, and sticky dynamite and rubber production from the extractor are required to keep accepting only this mod's resin;
  2. items with no corresponding tag at all (`item_motor`, `item_heatconductor`, `item_iridium`, `item_coil`, the `item_sunnarium` family, `item_coal_*`, `item_zip_coal_block`, `item_copper_boiler`, `item_quantum_core`, `item_shard_iridium`, …);
  3. nuclear materials found only in the aggregate tag `c:nuclear` (24 entries) — `item_uran` / `item_uran_235` / `item_uran_238` / `item_mox` / `item_plutonium` / `item_rtg_pellet` and friends — which would make recipes accept any nuclear material.

### `normal` namespace circuit boards switched to circuit tags

- `mio_icif:normal/item_circuit` → `c:circuits/basic`, `item_advcircuit` → `c:circuits/advanced`, `item_super_circuit` → `c:circuits/elite`, `item_living_circuit` → `c:circuits/ultimate`, **18 occurrences across 18 files** (advanced drop generator, quantum generator, the various solar panels and solar helmets, molecular transformer, super lapotron crystal, lithium battery, geomagnetic detector, electric wireless manager, EU detector cable, and more).
- Note: part of the recipes were already using `c:` tags (such as `c:ingots/iron`, `c:dusts/small_niobium`); this round fills in the remaining hard-coded items to match the existing convention.

## Generator Blockstates, JEI Item List and Profession Texture Fixes (2026-10-01)

### Generator blockstates: vertical variants removed

- Symptom: every launch logged **20** `Unknown value: 'up'/'down' for blockstate property: 'facing' [north, south, west, east]` warnings across `generator/block_drop_generator`, `block_advanced_drop_generator`, `block_experience_generator`, `block_advanced_experience_generator` and `block_advanced_semifluid_generator`.
- Root cause: these blocks extend `mio_icif_entity_block`, whose `FACING = HorizontalDirectionalBlock.FACING` (east/south/west/north only), yet their blockstate files still declared `facing=up` / `facing=down`. `block_stirling_generator`, `wiring/block_cesu` and others that also declare vertical variants produce no warning because they declare their own six-direction `DirectionalBlock.FACING`.
- Fix: removed the `facing=up` and `facing=down` variants from both the `active=false` and `active=true` sets in those five files, keeping only the 8 horizontal variants; no block class was changed.
- Impact: those vertical variants were unreachable at runtime anyway, so model loading no longer errors and the resource pack's missing list stays cleaner.

### JEI "奇点迭代" creative tab: 45 duplicate entries

- Symptom: `45 duplicate items were found in '奇点迭代' creative tab's: displayItems` (the AE2 / TFMG / Twilight Forest entries logged alongside come from third-party mods and are unrelated).
- Detection rule (verified against the JEI sources in `ItemStackListFactory.addFromTab`): JEI deduplicates by the UID from `StackHelper.getUidForStack`, where `UID = item` (when no effective interpreter exists) or `List.of(item, subtypeData)`; and `LegacyInterpreterAdapter.getSubtypeData` treats an interpreter returning an **empty string** as "no interpreter". Consequently ① an item that never registered a subtype interpreter degrades to a UID of the item itself, so `accept`ing it twice marks it as a duplicate; ② an interpreter returning the same string for both variants marks it as a duplicate too. The old `damageInterpreter` returned only the damage value, giving `"0"` for both the empty and the full variant, so all electric tools, armor and trinkets were affected.
- Fix (**both the empty and the full variant are kept**, JEI is simply taught to tell them apart):
  - `damageInterpreter` → `energyInterpreter`, returning `current energy/max energy` (falling back to the damage value for non-energy items), e.g. `0/400000` versus `400000/400000`;
  - `CF_SPRAYER` switched to `fluidCellInterpreter` (its "full load" writes construction foam into `CUSTOM_DATA`, unrelated to energy);
  - registered the previously missing `CROP_ANALYZER`, `DIAMOND_DRILLER` and `TOOL_LASER_MINER`;
  - registered the 6 charger blocks (`BATBOX` / `CESU` / `MFE` / `MFSU` / `LESU` / `EESU_CHARGER`) with `nbtInterpreter`, telling them apart by the energy in `BLOCK_ENTITY_DATA`.
- Verification: a script compared the 45 item ids reported in the log against the updated registration table, **45 matched with 0 missing**; `JEIPlugin.java` has no lint errors, and this is the only place in the project registering subtype interpreters, so there are no duplicate registrations.

### Zombie villager profession texture added

- Symptom: rendering the "future trader" in zombie villager form logged `Failed to load texture: mio_icif:textures/entity/zombie_villager/profession/future_trader.png` (`FileNotFoundException` plus a full stack trace). `VillagerProfessionLayer` looks up `textures/entity//profession/.png` separately, and this mod only shipped the villager version.
- Fix: copied `villager/profession/future_trader.png` (64×64, RGBA) into `zombie_villager/profession/`, which restores functionality immediately; the zombie villager profession look currently reuses the villager colouring (a little bright).
- Requirements for a later redraw: keep 64×64 with an alpha channel, lowercase file name, and fully transparent pixels where the overlay should be transparent (this texture is the profession overlay drawn on top of the zombie villager base skin); prefer the zombie palette of vanilla `zombie_villager/profession/*.png`, and keep the villager and zombie versions independent.

### Affected files

- Data pack: **116** recipe JSON files (resource item tagging) and **18** recipe JSON files (circuit board tagging) under `data/mio_icif/recipe/`.
- Resources: `block_drop_generator.json`, `block_advanced_drop_generator.json`, `block_experience_generator.json`, `block_advanced_experience_generator.json` and `block_advanced_semifluid_generator.json` under `assets/mio_icif/blockstates/generator/`; added `assets/mio_icif/textures/entity/zombie_villager/profession/future_trader.png`.
- Code: `common/client/integration/jei/JEIPlugin.java`.

### Verification boundaries

- No Gradle build was run this round; the conclusions come from the in-game session log and static review.
- **Measured**: in the session restarted after the fixes (01:51–01:58, exited normally) — blockstate vertical-variant warnings 20 → **0**; "奇点迭代" duplicate entries 45 → **0**; profession texture `Failed to load texture` 1 → **0**; `mio_icif` ERROR/FATAL **0**; `Loaded 13177 recipes` with no parse errors.
- Effective after: data pack and resource changes need re-entering the world / `F3+T`; JEI subtype changes need a client restart.
- Pending in-game verification: ① whether other mods' iron ingots / rubber / small dusts can substitute for this mod's materials in the corresponding recipes; ② sticky dynamite and rubber production from the extractor still accept only this mod's resin; ③ the five generators display correctly in all orientations and in both the "working" and "idle" models; ④ JEI shows both the empty and the full subtype for electric tools / armor / trinkets with no duplicate warning.

This mod has no additional files