diff --git a/website/src/jsMain/resources/markdown/doc/Configuration.md b/website/src/jsMain/resources/markdown/doc/Configuration.md new file mode 100644 index 00000000..357b6dfe --- /dev/null +++ b/website/src/jsMain/resources/markdown/doc/Configuration.md @@ -0,0 +1,38 @@ +--- +root: .components.layouts.MarkdownLayout +title: Configuration +nav-title: Configuration +description: A guide for configuring the output of a generated Minecraft datapack. +keywords: minecraft, datapack, kore, guide, configuration +date-created: 2024-04-06 +date-modified: 2024-04-06 +routeOverride: /docs/configuration +--- + +# DataPack Configuration + +The `configuration` function allows configuring the output of the generated datapack. + +## Example + +```kotlin +dataPack("mypack") { + configuration { + prettyPrint = true + prettyPrintIndent = " " + } + + // ... rest of datapack code +} +``` + +This will configure the JSON output to be pretty printed with two spaces for indentation. + +The available configuration options are: + +- `prettyPrint` - Whether to pretty print the JSON. Default is `false`. +- `prettyPrintIndent` - The string to use for indenting when pretty printing. Only whitespace characters are allowed. Default is empty + string. +- `generatedFunctionsFolder` - The folder where the generated functions are stored. Defaults to `"generated_scopes"`. + +Configuring a datapack is pretty useful for debugging. diff --git a/website/src/jsMain/resources/markdown/doc/Creating_A_Datapack.md b/website/src/jsMain/resources/markdown/doc/Creating_A_Datapack.md index 1ce718ed..dbad11e6 100644 --- a/website/src/jsMain/resources/markdown/doc/Creating_A_Datapack.md +++ b/website/src/jsMain/resources/markdown/doc/Creating_A_Datapack.md @@ -2,10 +2,10 @@ root: .components.layouts.MarkdownLayout title: Creating A Datapack nav-title: Creating A Datapack -description: A guide to creating a Minecraft datapack using Kore. +description: A guide for creating a Minecraft datapack using Kore. keywords: minecraft, datapack, kore, guide date-created: 2024-02-26 -date-modified: 2024-02-26 +date-modified: 2024-04-06 routeOverride: /docs/creating-a-datapack --- @@ -48,7 +48,7 @@ dataPack("my_datapack") { ## Configuration -See [Configuration](./Configuration) +See [Configuration](/docs/configuration) ## Pack Metadata diff --git a/website/src/jsMain/resources/markdown/doc/Functions.md b/website/src/jsMain/resources/markdown/doc/Functions.md new file mode 100644 index 00000000..7335d9bc --- /dev/null +++ b/website/src/jsMain/resources/markdown/doc/Functions.md @@ -0,0 +1,239 @@ +--- +root: .components.layouts.MarkdownLayout +title: Functions +nav-title: Functions +description: A guide for creating functions in a datapack using Kore. +keywords: minecraft, datapack, kore, guide, functions +date-created: 2024-04-06 +date-modified: 2024-04-06 +routeOverride: /docs/functions +--- + +# Functions + +Functions represent reusable pieces of logic callable in a datapack. + +Create a function with the `function` builder: + +```kotlin +function("my_function") { + say("Hello world!") +} +``` + +Then in game, call the function with `/function my_datapack:my_function`. + +The `function` builder returns a `FunctionArgument` object that you can reuse to call the function from other functions: + +```kotlin +val myFunction = function("my_function") { + say("Hello world!") +} + +function("my_second_function") { + function(myFunction) +} +``` + +## Tags + +You can set the tag of the current function you're working in with the `setTag` function: + +```kotlin +function("my_function") { + setTag(tagFile = "load", tagNamespace = "minecraft") +} +``` + +This will add the function to the `minecraft:load` tag. + +But you have simpler builders for the most common tags: + +```kotlin +load { + say("Hello world!") +} + +tick { + execute { + ifCondition(myPredicate) + + run { + say("Hello world!") + } + } +} +``` + +- `load` tag: `minecraft:load` +- `tick` tag: `minecraft:tick` + +This will create functions with randomly generated names, but you can also specify the name of the function: + +```kotlin +load("my_load_function") { + say("Hello world!") +} +``` + +# Commands + +Many common commands have convenience builders like `say`, `teleport`, etc. + +For example: + +```kotlin +function("commands") { + say("Hello!") // say command + teleport(player("Steve"), 100.0, 64.0, 100.0) // tp command +} +``` + +You can also build raw command strings and execute them: + +```kotlin +addLine("say Hello from raw command!") +``` + +> Note: This is not recommended, but can be useful for commands not yet supported by the DSL, or if you use [Macros](/docs/meacros). + +## Available Commands + +All commands from the version cited in the [README](https://github.com/Ayfri/Kore/README.md) are available. + +## Custom Commands + +You can pretty easily add new commands by creating your own builders. +For example, imagine you created a mod that adds a new command `/my_command` that takes a player name and a message as arguments. + +You can create a builder for this command like this: + +```kotlin +import io.github.ayfri.kore.functions.Function + +fun Function.myCommand(player: String, message: String) = addLine(command("my_command", literal(player), literal(message))) +``` + +Then you can use it like any other command: + +```kotlin +function("my_function") { + myCommand("Steve", "Hello!") +} +``` + +For commands that take complex types as arguments, you should use the `.asArg()` function inside `literal()` function. +For Argument types, you don't have to use this. + +See the code of the repository for more examples.
+[Link to `time` command.](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/commands/Time.kt)
+[Link to `weather` command.](https://github.com/Ayfri/Kore/blob/master/kore/src/main/kotlin/commands/Weather.kt) + +## Complex Commands + +Some commands are more complex and require more than just a few arguments. +For example, the `execute` or `data` commands. + +In that case, you can use complex builders that includes all the arguments of the command. +But the syntax may vary depending on the command and you should definitely check the tests to see how to use them. + +An example of the `execute` command: + +```kotlin +execute { + asTarget(allEntities { + limit = 3 + sort = Sort.RANDOM + }) + + ifCondition { + score(self(), "test") lessThan 10 + } + + run { // be sure to import the run function, do not use the one from kotlin. + teleport(entity) + } +} +``` + +You may also have commands where you can create "contexts", you only call once a function with a lambda, then inside the lambda, the context +is +reused for each call. + +An example of the `data` command: + +```kotlin +data(self()) { + modify("Health", 20) + modify("Inventory[0]", Items.DIAMOND_SWORD) +} +``` + +# Macros + +See [Macros](/docs/meacros). + +# Generated Functions + +The same way the `load` and `tick` builders generate functions with random names, the `execute` builder also generates a function with a +random name if you call multiple commands inside the `run` block. + +```kotlin +execute { + run { + say("Hello world!") + say("Hello world2!") + } +} +``` + +This will generate a function with a random name that will be called by the `execute` command. + +> Note: The generated functions will be generated inside a folder named `generated_scopes` in the `functions` folder. +> You can change the folder to whatever you want in [Configuration](/docs/ceonfiguration). + +> Note: The generated name will have this pattern `generated_${hashCode()}`, where `hashCode()` is the hash code of the function. +> This means that if you use the same `execute` builder multiple times, it will generate the same function name and reuse the same function. + +# Debugging + +You have multiple ways to debug your functions. +First, a `debug` function is available, it is pretty much the same as `tellraw` but always displaying the message to everyone. + +```kotlin +function("my_function") { + debug("Hello world!", Color.RED) +} +``` + +You also have a `debug` block for printing a log message to the console for each command you call inside the block. + +```kotlin +function("my_function") { + debug { + say("hello !") + } +} +``` + +This will add a command call to `tellraw` command, writing the exact command generated, clicking on the text will also call the command. +Example of what is generated: + +```mcfunction +say hello ! +tellraw @a {"text":"/say hello !","clickEvent":{"action":"suggest_command","value":"/say hello !"},"hoverEvent":{"action":"show_text","value":{"text":"Click to copy command","color":"gray","italic":true}}} +``` + +The last example is a function call to `startDebug()` (which is called by the `debug` block), this will add log messages to the start and +the end of the function, plus a log message for each command called inside the function. + +```mcfunction +tellraw @a [{"text":"Running function ","color":"gray","italic":true},{"text":"my_datapack:my_function","color":"white","bold":true,"clickEvent":{"action":"run_command","value":"/function my_datapack:my_function"},"hoverEvent":{"action":"show_text","value":{"text":"Click to execute function","color":"gray","italic":true}},"italic":true}] +say hello ! +tellraw @a {"text":"/say hello !","clickEvent":{"action":"suggest_command","value":"/say hello !"},"hoverEvent":{"action":"show_text","value":{"text":"Click to copy command","color":"gray","italic":true}}} +tellraw @a [{"text":"Finished running function ","color":"gray","italic":true},{"text":"my_datapack:my_function","color":"white","bold":true,"clickEvent":{"action":"run_command","value":"/function my_datapack:my_function"},"hoverEvent":{"action":"show_text","value":{"text":"Click to execute function","color":"gray","italic":true}},"italic":true}] +``` + +You can call the command by clicking on the debug texts added. + +Also running `toString()` in a function will return the generated function as a string, so you can manipulate it as you want. diff --git a/website/src/jsMain/resources/markdown/doc/Home.md b/website/src/jsMain/resources/markdown/doc/Home.md new file mode 100644 index 00000000..afe1dbfe --- /dev/null +++ b/website/src/jsMain/resources/markdown/doc/Home.md @@ -0,0 +1,17 @@ +--- +root: .components.layouts.MarkdownLayout +title: Home +nav-title: Home +description: Welcome to the Kore wiki! +keywords: minecraft, datapack, kore, guide +date-created: 2024-04-06 +date-modified: 2024-04-06 +routeOverride: /docs/home +--- + +# Kore + +**Welcome to the Kore wiki!** + +Kore is a Kotlin library for creating Minecraft datapacks. It provides a type-safe and concise way to generate Minecraft datapacks using +Kotlin DSL. diff --git a/website/src/jsMain/resources/markdown/doc/Scoreboards.md b/website/src/jsMain/resources/markdown/doc/Scoreboards.md new file mode 100644 index 00000000..fb59f1ee --- /dev/null +++ b/website/src/jsMain/resources/markdown/doc/Scoreboards.md @@ -0,0 +1,199 @@ +--- +root: .components.layouts.MarkdownLayout +title: Scoreboards +nav-title: Scoreboards +description: A guide for managing scoreboards in a Minecraft datapack using Kore. +keywords: minecraft, datapack, kore, guide, scoreboards +date-created: 2024-04-06 +date-modified: 2024-04-06 +routeOverride: /docs/scoreboards +--- + +# Scoreboards + +You can manage scoreboards with the `scoreboard` command: + +```kotlin +scoreboard.objectives.add("my_objective", ScoreboardCriteria.DUMMY) +``` + +## Creating objectives + +You have multiple forms of the `scoreboard` command: + +```kotlin +scoreboard { + objectives { + add("my_objective", ScoreboardCriteria.DUMMY) + // this form lets you manage multiple objectives at once + } +} + +scoreboard { + objective("my_objective") { + add(ScoreboardCriteria.DUMMY) + // this form lets you manage a single objective + } +} +``` + +## Managing objectives + +You can add, remove, set display name, set display slot, set render type of objectives: + +```kotlin +scoreboard { + objective("my_objective") { + add(ScoreboardCriteria.DUMMY, displayName = textComponent("My Objective", Color.GOLD)) + setDisplaySlot(DisplaySlots.sidebar) + setRenderType(RenderType.INTEGER) + } +} +``` + +## Manage players + +You can manage players with the `players` block: + +```kotlin +scoreboard { + players { + add(allPlayers(), "my_objective", 1) + remove(self(), "my_objective", 5) + reset(self(), "my_objective") + set(self(), "my_objective", 10) + + operation(self(), "my_objective", Operation.ADD, self(), "my_objective") + } + + player(self()) { + add("my_objective", 1) + remove("my_objective", 5) + reset("my_objective") + set("my_objective", 10) + + operation("my_objective", Operation.ADD, self(), "my_objective") + } +} +``` + +You can also manage an objective for multiple selectors at once: + +```kotlin +scoreboard { + players { + objective("my_objective") { + add(self(), 1) + remove(self(), 5) + reset(self()) + set(self(), 10) + + operation(self(), Operation.ADD, self(), objective) + } + } +} +``` + +Or also manage an objective for a single selector: + +```kotlin +scoreboard { + player(self()) { + objective("my_objective") { + add(1) + remove(5) + reset() + set(10) + + operation(Operation.ADD, self(), objective) + } + } +} +``` + +These methods offer a more readable way to manage objectives, and avoid repetition operations invoking multiple times the same +selector/objective. + +## Scoreboard Displays + +Scoreboard Displays are a new helper that let you manage right sidebar displays, like on servers. + +You can create a display with the `scoreboardDisplay` function: + +```kotlin +scoreboardDisplay("my_display") { + displayName = textComponent("My Display", Color.GOLD) + + setLine(0, textComponent("Line 1", Color.AQUA)) + appendLine(textComponent("Line 2", Color.AQUA)) + emptyLine() + appendLine("Line 4", Color.AQUA) + + appendLine(textComponent("Line 2", Color.AQUA)) { + createIf { // this line will only be created if the condition is true, this is executed in an `execute if` block + predicate("stonks") + } + } +} +``` + +You can also change the line numbers display: + +```kotlin +scoreboardDisplay("my_display") { + decreasing = false + startingScore = 0 +} +``` + +#### New since 1.20.3 + +You can now hide the values of the lines: + +```kotlin +scoreboardDisplay("my_display") { + appendLine("a") { + hideValue = true // this will hide the value of the line + } + + appendLine("b") + + hideValues() // this will hide the values of all lines + // you can also provide a range of indices for the lines to hide +} +``` + +Feel free to add feedback if you have any idea to improve this or to use other features from +the new `scoreboard players display numberformat` subcommand. + +### Resetting Scoreboard Displays + +You can reset all scoreboards with the `resetAll` function: + +```kotlin +ScoreboardDisplay.resetAll() +``` + +### Limitations + +Scoreboard Displays are displayed the same way to everyone, so you can't have different displays for different players. +You can at least have different displays for different team colors, but that's all (so there's a property to set the display slot). +The sidebar is limited to 15 lines, so you can't have more than 15 lines in a display. + +### How it works + +Scoreboard Displays are generated using fake players and teams, it will create teams with randomized numbers as name to avoid conflicts. +Each line = 1 team, and each team has a suffix with the line text, then a fake player is added to the team with the score of the line +number. +For dynamic animations of displays, there aren't any solution for that currently. +The only way to do that is to use a binary tree of functions, checking the score of the player between 0 and the middle of the maximum +score, then between the middle and the maximum, and split the function in two, and so on. +Then, when you arrive to the last function, you can call the `setLine` function to set the line text. +And you repeat this for each line. + +If you have a better solution, maybe using macros, feel free to create functions for that and create a pull request. + +#### New since 1.20.3 + +Now scoreboard displays can be created more easily as you can now customize the display of each player as a text component. +No teams are created anymore, and the display is generated using the `scoreboard players display name` command, achieving the same result. diff --git a/website/src/jsMain/resources/markdown/doc/functions/Macros.md b/website/src/jsMain/resources/markdown/doc/functions/Macros.md new file mode 100644 index 00000000..3166d9d9 --- /dev/null +++ b/website/src/jsMain/resources/markdown/doc/functions/Macros.md @@ -0,0 +1,107 @@ +--- +root: .components.layouts.MarkdownLayout +title: Macros +nav-title: Macros +description: A guide for using macros in Minecraft functions. +keywords: minecraft, datapack, kore, guide, macros, functions +date-created: 2024-04-06 +date-modified: 2024-04-06 +routeOverride: /docs/functions/macros +--- + +# Macros + +Macros recently added support for macros inside functions in Minecraft 1.20.2. + +## Using Macros + +To define a macro, use the `macro()` function: + +```kotlin +say("I'm gonna use the macro ${macro("foo")}") +``` + +Inside a Minecraft function: + +```kotlin +function("my_function") { + say("This is my macro: ${macro("bar")}") +} +``` + +When called, this will substitute the actual text of the macro. + +You can also evaluate a list of macros and have fully dynamic commands: + +```kotlin +eval("command", "arg1", "arg2") +// equals to minecraft code: +// $$(command) $(arg1) $(arg2) +``` + +## Calling functions with macros + +You can call a function with macros by using the new `arguments` argument. + +```kotlin +function("my_function", arguments = nbt { this["bar"] = "baz" }) +``` + +That can also be a DataArgument (block position/entity selector/storage). + +```kotlin +function( + "my_function", + arguments = allEntities { + type = EntityTypes.MARKER + name = "test" + }, + path = "data.test" // optional path is available +) +``` + +## Defining Macro Classes + +For more complex macro usage, you can create a `Macros` subclass to define your macros: + +```kotlin +class MyMacros : Macros() { + val myMacro by "my_macro" +} +``` + +Then pass an instance to your function: + +```kotlin +function("my_function", ::MyMacros) { + say(macros.myMacro) +} +``` + +Now you can access the macros on the `macros` property. + +This also allows validating macros that are required when calling the function with an NBT Compound. + +## Best Practice + +When using macros, you can create a function with arguments that calls the function with the macros: + +```kotlin +fun main() { + dataPack { + function("teleport_to_spawn") { + teleport(player(macro("player")), vec3()) + } + } +} + +fun Function.teleportToSpawn(player: String) { + function("teleport_to_spawn", arguments = nbt { this["player"] = player }) +} +``` + +Then you can call this function with your argument as a macro: + +```kotlin +teleportToSpawn("jeb_") +``` diff --git a/website/src/jsMain/resources/markdown/doc/helpers/Display_Entities.md b/website/src/jsMain/resources/markdown/doc/helpers/Display_Entities.md new file mode 100644 index 00000000..5c610c19 --- /dev/null +++ b/website/src/jsMain/resources/markdown/doc/helpers/Display_Entities.md @@ -0,0 +1,133 @@ +--- +root: .components.layouts.MarkdownLayout +title: Display Entities +nav-title: Display Entities +description: A guide for creating Dispaly Entities in the world. +keywords: minecraft, datapack, kore, guide, display-entities +date-created: 2024-04-06 +date-modified: 2024-04-06 +routeOverride: /docs/helpers/display-entities +--- + +# Display Entities + +## Entity Displays + +Entity displays are used to display blocks/items/text in the world. +You can define multiple properties for the display, such as transformation, billboard mode, shadow etc. + +```kotlin +val entityDisplay = blockDisplay { + blockState(Blocks.GRASS_BLOCK) { + properties { + this["snowy"] = true + } + } + + transformation { + leftRotation { + quaternionNormalized(0.0, 0.0, 0.0, 1.0) + } + + scale = vec3(2.0) + + translation { + y = 2.0 + } + } + + billboardMode = BillboardMode.CENTER + shadowRadius = 0.5f +} + +summon(entity = entityDisplay.entityType, pos = vec3(0, 0, 0), nbt = entityDisplay.toNbt()) +// will summon a grass block with snow on top, scaled by 2, rotated by 0 degrees and translated by 2 blocks on the y axis at the position 0, 0, 0 +``` + +## Block Displays + +Block displays are used to display blocks in the world. They are created by calling `blockDiplay()` DSL. + +```kotlin +val blockDisplay = blockDisplay { + blockState(Blocks.GRASS_BLOCK) { + properties { + this["snowy"] = true + } + } +} +``` + +## Item Displays + +Item displays are used to display items in the world. They are created by calling `itemDisplay()` DSL. + +```kotlin +val itemDisplay = itemDisplay { + item(Items.DIAMOND_SWORD) { + name = textComponent("test") + + enchantments { + Enchantments.SHARPNESS at 1 + Enchantments.UNBREAKING at 3 + } + + modifiers { + modifier(Attributes.GENERIC_ATTACK_DAMAGE, 1.0, AttributeModifierOperation.ADD) + } + } +} +``` + +## Text Displays + +Text displays are used to display text in the world. They are created by calling `textDisplay()` DSL. + +```kotlin +val textDisplay = textDisplay { + text("test", Color.RED) { + bold = true + } +} +``` + +## Transformations + +Transformations are used to modify the translation, left/right rotations and scale of displays. They are created by calling `transformation` +DSL. +You can also apply directly matrix transformations and use quaternions, axis angles or use Euler angles for rotations. + +```kotlin +transformation { + leftRotation { + quaternionNormalized(0.0, 0.0, 0.0, 1.0) + } + + scale = vec3(2.0) + + translation { + y = 2.0 + } +} +``` + +## Interpolations + +You can convert your display entity into an "interpolable" display entity by calling `interpolable()` on it. +This will allow you to interpolate between the current transformation and the target transformation in a given time. + +```kotlin +val interpolableEntityDisplay = blockDisplay { + blockState(Blocks.STONE_BLOCK) +}.interpolable(position = vec3(0, 0, 0)) + +interpolableEntityDisplay.summon() + +interpolableEntityDisplay.interpolateTo(duration = 2.seconds) { + translation { + y = 2.0 + } +} +``` + +I will later add more methods and maybe a complete DSL for making full animations.