Vanilla Data Extractor
The Pumpkin Extractor is a dedicated Fabric mod written in Kotlin that introspects a running vanilla Minecraft server or client to dump authoritative game registries and runtime metadata into structured JSON files.
These JSON dumps are consumed by pumpkin-codegen to generate strongly-typed Rust code in pumpkin-data and pumpkin-world.
Datapacks vs. Extractor: Our Data Philosophy
Before creating a new extractor, it is crucial to understand Pumpkin's data hierarchy:
IMPORTANT
We preferably use vanilla datapacks whenever possible. If vanilla Minecraft already exposes a registry or system through official datapack JSON files, we consume the datapack directly rather than writing custom extractor code.
When to Use Datapacks vs. When to Use the Extractor
| Source | When to Use | Examples |
|---|---|---|
| Vanilla Datapacks (Preferred) | Any data officially serialized as JSON by Mojang in data/minecraft/. | Recipes, tags (blocks, items, fluids), biomes, dimension types, damage types, trim materials, worldgen noise parameters. |
| Fabric Extractor (Only when necessary) | Game data hardcoded in Java bytecode that cannot be exported from raw datapack files. | Block collision shapes, AABB bounding boxes, block hardness, packet ID-to-state mappings, entity tracked data IDs, fuel burn durations, composter chances, and flower pot conversion tables. |
Extractor Mod Architecture
The Extractor runs on top of the Fabric loader using official Fabric Yarn mappings:
- Mod Entry Point (
src/main/kotlin/de/snowii/extractor/Extractor.kt): Registers with Fabric'sServerLifecycleEvents.SERVER_STARTEDevent. When the headless server finishes booting, it invokes all registered extractors and dumps files torun/pumpkin_extractor_output/. - Extractor Interface: Every data extractor implements the
Extractor.Extractorinterface:kotlininterface Extractor { fun fileName(): String @Throws(Exception::class) fun extract(server: MinecraftServer): JsonElement // Returns true if output belongs in tests/ rather than the root output folder fun isTest(): Boolean = false } - Output Directory: JSON files are saved to
pumpkin_extractor_output/encoded in UTF-8 without HTML escaping.
How to Add a New Extractor
Follow this step-by-step workflow when you need to extract new hardcoded vanilla mechanics:
Step 1: Verify the Data Cannot Be Sourced from Datapacks
Inspect the official Minecraft client/server JAR or Mojang's data reports:
- Check
data/minecraft/for existing registries, tags, or JSON definitions. - If the data is present in the datapack, add it directly to
Pumpkin/assets/datapacks/instead of writing an extractor.
Step 2: Create the Extractor Class
If the data is hardcoded in Java methods, create a new Kotlin class in:
src/main/kotlin/de/snowii/extractor/extractors/<ExtractorName>.ktImplement the Extractor.Extractor interface:
package de.snowii.extractor.extractors
import com.google.gson.JsonElement
import com.google.gson.JsonObject
import com.google.gson.JsonPrimitive
import de.snowii.extractor.Extractor
import net.minecraft.core.registries.BuiltInRegistries
import net.minecraft.server.MinecraftServer
import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack
class Fuels : Extractor.Extractor {
override fun fileName(): String {
return "fuels.json"
}
override fun extract(server: MinecraftServer): JsonElement {
val fuelsJson = JsonObject()
// Query vanilla runtime methods
server.fuelValues().fuelItems().forEach { fuel ->
val itemId = BuiltInRegistries.ITEM.getKey(fuel).toString()
val burnDuration = server.fuelValues().burnDuration(ItemStack(fuel))
fuelsJson.add(itemId, JsonPrimitive(burnDuration))
}
return fuelsJson
}
}Step 3: Register the Extractor
Open src/main/kotlin/de/snowii/extractor/Extractor.kt and add an instance of your class to the extractors array:
val extractors = arrayOf(
// ... existing extractors ...
Blocks(),
Items(),
Entities(),
Fuels(),
)Step 4: Run the Extractor
Execute the headless server task in the Extractor repository:
./gradlew runServerOnce the extraction finishes, locate your new JSON file in:
run/pumpkin_extractor_output/<your_file>.jsonStep 5: Integrate with pumpkin-codegen
- Move the generated JSON file into Pumpkin:bash
cp run/pumpkin_extractor_output/fuels.json ../Pumpkin/assets/ - In the
Pumpkinrepository, opentools/pumpkin-codegen:- Create a parser for
<your_file>.json. - Write a code generation template to produce the corresponding Rust structs or static lookup tables in
crates/pumpkin-data.
- Create a parser for
- Run code generation:bash
cargo run -p pumpkin-codegen - Verify that
pumpkin-datacompiles and passes all unit tests:bashcargo test -p pumpkin-data
Best Practices for Extractor Contributions
- Sort Keys Deterministically: When generating JSON objects or lists, sort entries by numeric registry ID or alphabetically by identifier (
minecraft:stone,minecraft:dirt). This prevents noisy git diffs when re-running extraction across updates. - Prefer Standard Types: Use vanilla identifiers (
net.minecraft.resources.Identifier) as string keys instead of arbitrary integers where possible. - Access Wideners: If private vanilla fields or methods need to be accessed, declare an access widener in
src/main/resources/extractor.accesswidenerrather than resorting to brittle runtime reflection.