Compatibility
Minecraft: Java Edition
Platforms
Supported environments
Links
Tags
Creators
Details
PaletteAPI
A data-driven structure processor for Forge 1.20.1. It swaps a block you pick for a random one out of a weighted palette while your structures generate. You set the whole thing up in datapack JSON so you never have to touch Java to change a palette!
What it does
Say you build a ruin out of iron blocks. Drop PaletteAPI's processor on it and every iron block turns into cobble, or mossy cobble, or cracked bricks, whatever weights you hand it. The pick is locked to the world position too, so a chunk always comes back looking the same. No flickering when you reload.
Installation
It's a server side mod. All it does happens during world generation, so the client never needs it.
On a dedicated server, drop paletteapi-1.0.0.jar in the server's mods folder and you're done. People joining don't have to install anything, they can be on plain vanilla-ish clients and it still works. In singleplayer just put it in your own mods folder like normal, the game runs its own server behind the scenes so it all just works.
If you're making your own mod and you want to build palettes in code, add PaletteAPI as a dependency and you get the Java API further down.
Datapack API
This is the main way to use it. Make a processor list file here:
data/<your_namespace>/worldgen/processor_list/my_palette.json
That folder matters. It has to be worldgen/processor_list or the game just ignores your file and never tells you why.
{
"processors": [
{
"processor_type": "paletteapi:palette_randomizer",
"target": "minecraft:iron_block",
"palette": [
{ "data": { "Name": "minecraft:cobblestone" }, "weight": 70 },
{ "data": { "Name": "minecraft:mossy_cobblestone" }, "weight": 20 },
{ "data": { "Name": "minecraft:cracked_stone_bricks" }, "weight": 10 }
]
}
]
}
processor_type
Always paletteapi:palette_randomizer. This is what tells the game to use PaletteAPI.
target
The block to look for and replace, like minecraft:iron_block. It matches on the block itself, so a waterlogged or rotated version of your placeholder still gets caught. Air and anything that isn't your target gets left alone.
palette
The list of blocks your target can turn into. Every entry needs two things.
data: a full blockstate. For a plain block that's just { "Name": "minecraft:cobblestone" }. For something with states you add Properties, like { "Name": "minecraft:oak_stairs", "Properties": { "facing": "north" } }.
weight: how likely that block is. In the example up there cobble shows up around 70% of the time, mossy 20%, cracked 10%. The weights don't have to add up to 100, they're just relative to each other.
Heads up:
datais a full blockstate object, not just a name string. Leave off thedatawrapper or theweightand the file won't parse. If you get a "Failed to parse" in the log, that's the first thing to check.
Pointing a structure at it
Once your processor list exists, reference it from a template pool by its id. Note that processors is just the string id here, not the whole object.
{
"name": "yourmod:example_pool",
"fallback": "minecraft:empty",
"elements": [
{
"weight": 1,
"element": {
"element_type": "minecraft:single_pool_element",
"location": "yourmod:my_piece",
"processors": "yourmod:my_palette",
"projection": "rigid"
}
}
]
}
Java API
You don't need any of this for datapacks. It's only here if you want to build a processor straight in code from your own mod.
PaletteProcessorTypes.PALETTE_RANDOMIZER
The registered processor type. This is the thing other mods hook into.
new PaletteRandomizerProcessor(Block target, SimpleWeightedRandomList<BlockState> palette)
Builds a processor yourself. It's the same thing the JSON makes, just from Java.
var palette = SimpleWeightedRandomList.<BlockState>builder()
.add(Blocks.COBBLESTONE.defaultBlockState(), 70)
.add(Blocks.MOSSY_COBBLESTONE.defaultBlockState(), 20)
.add(Blocks.CRACKED_STONE_BRICKS.defaultBlockState(), 10)
.build();
var processor = new PaletteRandomizerProcessor(Blocks.IRON_BLOCK, palette);
Using it in another mod
If your mod wants to build palettes from code, you need PaletteAPI in two spots. One so your code compiles against it, and one so Forge makes players install it.
Get it onto your compile path first. The easiest way is the maven repo. Add it and the coordinate to your build.gradle:
repositories {
maven { url "https://raw.githubusercontent.com/TheCatsApplelol/PaletteAPI/main/repo" }
}
dependencies {
implementation fg.deobf("com.paletteapi:paletteapi:1.0.0")
}
Rather grab the jar by hand? Drop it into a libs folder in your project and point at the file instead:
dependencies {
implementation fg.deobf(files("libs/paletteapi-1.0.0.jar"))
}
Do not skip the fg.deobf wrapper. The jar ships in production names and that wrapper maps it back so it lines up with your dev code. A plain files(...) will compile and then die the second you run it.
Now make Forge require it. In your own META-INF/mods.toml, add a block and put your mod id where yourmodid is:
[[dependencies.yourmodid]]
modId="paletteapi"
mandatory=true
versionRange="[1.0.0,)"
ordering="AFTER"
side="BOTH"
mandatory=true keeps your mod from loading unless PaletteAPI is there, and it tells the player to go get it. ordering="AFTER" makes PaletteAPI load first so its processor type is ready before your code touches it.
Last thing, both jars go in the mods folder when someone actually plays. In dev the libs jar covers your test runs.
Testing it in game
There's a built in command so you can see it work without setting up a whole structure first.
/paletteapi test
Drops a 12 by 12 floor of iron blocks under you, runs it through the example palette, and prints the counts to chat. You should land somewhere near that 70 / 20 / 10 split. Run it on the same spot again and you get the exact same pattern back, that's the position locking doing its job.
/paletteapi test <size>
Same deal but you pick how big the floor is. /paletteapi test 24 gives you a bigger sample so the odds are easier to read.
Heads up: the command needs op (permission level 2). The example palette ships inside the jar already so there's nothing extra to install for it.
Why should i use this?
If you make structures and you're tired of them coming out identical every single time, this is for you. If you don't make structures, then no, you probably don't need it.


