# pkl4mc

First mod to bring the [PKL](https://pkl-lang.org) lang to Minecraft.

> [DISCLAIMER]
> This was originally a dumb idea I had and built for self use and to learn more about PKL runtime and JVM. If it's useful to you too, great.

Unfinished docs -> [nothingseries.org/pkl4mc/](https://docs.nothingseries.org/pkl4mc/)

## What the hell is PKL?

PKL (Pickle) is a typed, composable configuration language by Apple in 2024. It gives autocomplete, type checking and reusable schemas.

## Why PKL?

Minecrafts datapack files are JSON. JSON has no variables, no comments, no types and no reuse. Typo a field name? Silent failure, you will probably find out when your loot table doesn't drop anything, or your ore doesn't generate.

PKL kinda fixes this, it will catche the typo before the world loads and lets you define shared logic once.

Here is a smelting recipe in JSON:

```json
{
  "type": "minecraft:smelting",
  "category": "misc",
  "ingredient": { "item": "minecraft:sea_pickle" },
  "result": "nothingcore:cooked_sea_pickle",
  "experience": 0.7,
  "cookingtime": 200
}
```

And here in PKL:

```pkl
import "pklmc:recipe.pkl" as recipe

local r: recipe.SmeltingRecipe = new {
  category = "misc"
  ingredient { item = "minecraft:sea_pickle" }
  result = "nothingcore:cooked_sea_pickle"
  experience = 0.7
  cookingtime = 200
}

output { renderer = new JsonRenderer {}; value = r }
```

Type a field wrong in PKL and it tells you immediately.

## Features

### Virtual Datapack

Drop .pkl files in config/pkl4mc/data/ and they get evaluated and injected into the data system on world load. No datagen, kinda like KubeJS.

### Zip & Folder Datapacks

Same structure as vanilla world/datapacks/, just with .pkl files inside instead of JSON.

```
config/pkl4mc/
  data/                     ← loose .pkl files (KubeJS-like)
    <namespace>/
      recipes/
      loot_tables/
  datapacks/
    pack.zip              ← zip datapack with .pkl files inside
    pack/                 ← folder datapack with .pkl files
      <namespace>/
        recipes/
        loot_tables/
```

### Commands

| Command                     | Description                                 |
| --------------------------- | ------------------------------------------- |
| /pkl errors                 | PKL evaluation errors since last reload     |
| /pkl reload                 | Reload all PKL datapacks without restarting |
| /pkl convert namespace:path | Convert any loaded JSON resource to PKL     |

The convert command is a migration tool which dumps any vanilla or mod JSON as PKL to config/pkl4mc/data/. Good starting point if you're porting anything.

```
/pkl convert minecraft:recipes/stick
/pkl convert minecraft:loot_tables/chests/ancient_city
/pkl convert nothingcore:cooked_sea_pickle
```

### Schemas

PKL schemas for vanilla data formats ship inside the jar. IDE autocompletes and type validations work via PKL's language server. _(schema coverage is still a wip btw)_

#### Amends style (set fields directly)

| Schema          | Usage                               |
| --------------- | ----------------------------------- |
| Advancements    | `amends "pklmc:advancement.pkl"`    |
| Tags            | `amends "pklmc:tag.pkl"`            |
| Dimension types | `amends "pklmc:dimension_type.pkl"` |
| Biomes          | `amends "pklmc:biome.pkl"`          |
| Placed features | `amends "pklmc:placed_feature.pkl"` |
| Structures      | `amends "pklmc:structure.pkl"`      |
| Structure sets  | `amends "pklmc:structure_set.pkl"`  |
| Noise settings  | `amends "pklmc:noise_settings.pkl"` |

#### Import style (pick a typed class):

| Schema              | Usage                                            |
| ------------------- | ------------------------------------------------ |
| Recipes             | `import "pklmc:recipe.pkl" as recipe`            |
| Loot tables         | `import "pklmc:loot_table.pkl" as loot`          |
| Configured features | `import "pklmc:configured_feature.pkl" as cf`    |
| Configured carvers  | `import "pklmc:configured_carver.pkl" as carver` |

### Config API

So... now that your datapacks are already in PKL, why go back to TOML for configs? For mod devs evaluate PKL files directly to typed Kotlin (or Java) objects.

```kotlin
@Serializable
data class MyConfig(val tickRate: Int, val enabled: Boolean)

val config = PklConfig.load<MyConfig>(
    FMLPaths.CONFIGDIR.get().resolve("mymod/config.pkl")
)
```

## So who is this for?

Probably for modpack or datapack devs, who wanna try something new and maybe hate json for some reason.
Also for mod devs who wanna depend on pkl4mc as a library and use PklConfig.

## Stack

|                  | Version                          |
| ---------------- | -------------------------------- |
| Minecraft        | 1.20.1 Forge                     |
| Kotlin for Forge | 4.12.0                           |
| pkl-core         | 0.31.1 (shaded, ANTLR relocated) |

## License

- [OSL-3.0](https://opensource.org/license/osl-3-0-php) (pkl4mc)
- [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0) (pkl-core)
