4 releases (stable)
2.0.0 | Jan 2, 2024 |
---|---|
1.0.3 | Feb 3, 2023 |
1.0.2 | Jan 29, 2023 |
0.1.0 | Dec 17, 2021 |
#159 in Debugging
Used in mcfunction-debug-adapter
315KB
7.5K
SLoC
Mcfunction-Debugger
Mcfunction-Debugger is a debugger for Minecraft's *.mcfunction files that does not require any Minecraft mods.
Mcfunction-Debugger implements the Debug Adapter Protocol to allow easy integration with different IDEs such as Eclipse or Vim (see the list of supporting IDEs). The corresponding Visual Studio Code extension can be found here: https://codeberg.org/vanilla-technologies/mcfunction-debugger-vscode
If you would like to implement such an integration for another IDE, you can find documentation in the For Developers chapter.
Contents
Debugging a Datapack
To debug a function the mcfunction file must be contained in a datapack and the datapack must not be a zip file.
The datapack doesn't have to be loaded in the Minecraft world since a debuggable version of the datapack will be generated anyways.
The special function tags minecraft:load
(defined in data/minecraft/tags/functions/load.json
) and minecraft:tick
(defined in data/minecraft/tags/functions/tick.json
) are currently ignored (see #8), so to start debugging you must specify a function.
The function will be executed with a schedule
command, so it runs without an @s
entity at the world's origin position.
To change this, you can create a new function that executes your function as the player or at a different position and debug this new function instead.
For example:
execute as @p at @s run function my_namespace:my_function
Because the debugged function is executed using a schedule
command it can behave slightly differently from a function executed by a player via the Minecraft chat or via the server console.
Unlike manually executed commands, commands that are executed via schedule
or command blocks run before the age of entities is incremented.
So if you notice different behaviour when executing a function through the debugger and when manually executing the function try to manually schedule the function to see if that makes a difference.
Features
Mcfunction-Debugger allows debugging datapacks in both singleplayer and multiplayer worlds for a wide range of Minecraft versions. This is achieved by using Minect to connect to a vanilla Minecraft instance.
Calling Functions
Functions can be called both with and without execute, but calls to function tags are not supported yet (see #12).
Almost all variants of execute (execute as, execute at, ...) are fully supported.
The only exception is execute store
for function calls (see #11), which will currently store an arbitrary result
/success
value.
# Supported
function my_namespace:my_function
execute ... run function my_namespace:my_function
# Not supported
execute store result score my_target my_objective run function my_namespace:my_function
function #my_namespace:my_function_tag
execute ... run function #my_namespace:my_function
Entity Selectors
Mcfunction-Debugger has full support for calling functions with entity selectors (such as execute as @e run function ...
).
Just like in regular Minecraft the called function will be executed completely for the first entity, then for the second entity and so on.
This differs from debugging approaches using command blocks that execute the first command of the called function for all entites, then the second command for all entities and so on.
Function execution context
A function is always executed within a context that is defined when calling the function. This context consists of:
- executor:
The entity executing the function is referred to by the entity selector
@s
. It is changed when calling a function withexecute as
. - position:
The position in the Minecraft world at which the function is executed is referred to by relative coordinates like
~ ~ ~
. It is changed when calling a function withexecute positioned
orexecute at
. - rotation:
The look rotation of the function is changed when calling a function with
execute rotated
orexecute at
. It affects local coordinates such as^ ^1 ^
. - dimension:
The dimension in which the function executes such as
overworld
,the_nether
andthe_end
. It is changed when calling a function withexecute in
orexecute at
. - anchor:
The anchor (
eyes
orfeet
) defines the origin of local coordinates. It defines whether a local position like^ ^ ^
is relative to the executors eyes or feet. It is changed when calling a function withexecute anchored
.
Mcfunction-Debugger correctly stores and restores the entire execution context of each function throughout the debugging session.
When execution is suspended, the position and rotation are marked using particles:
Missing and Invalid Functions
Both Minecraft and Mcfunction-Debugger completely skip the execution of functions that are missing or contain an invalid command. This means that breakpoints in an invalid function will be ignored. To highlight this fact Mcfunction-Debugger writes to the debug console whenever a function call is skipped.
Schedule and Timing
The schedule command is fully supported. While execution is suspended, all schedule timers are suspended too, so the datapack does not behave differently just because you hit a breakpoint. Additionally the age of all area effect clouds is frozen to make sure they don't die. The age of other entites and the gametime are currently not frozen (see #24 and #18) and the random tick speed is not yet set to zero (see #14).
Internal Debug Entities are Hidden
Mcfunction-Debugger internally uses various entities. To make sure they don't interfere with the debugged datapack these internal entities are hidden from all entity selectors.
There is one exception and that is Minects connection entity.
Minect requires an area effect cloud tagged minect_connection
to operate.
We do not hide this entity when using the debugger, because it is also visible when a player manually executes functions.
It is fine to kill the connection entity, since it will be recreated in the next tick.
So there is no problem if your datapack contains commands like kill @e[type=!player]
.
Just be aware that commands like execute as @e run ...
will target one more entity once Minect ist installed.
Caveats
Unfortunately a program can always behave slightly differently when being debugged. Here are some problems you might encounter with Mcfunction-Debugger.
Calling Functions in Other Datapacks is not Supported Yet
Currently Mcfunction-Debugger only considers the datapack that contains the debugged function (see #9). This means that calls to functions in other datapacks will be skipped as if the function was missing.
To work around this limitation you can merge all datapacks into one big datapack before debugging.
Operating on Dead Entities
In a Minecraft function you can kill an entity and then continue using it. For example, consider the following datapack:
example:sacrifice_pig
:
summon pig ~ ~ ~ {Tags: [sacrifice]}
execute as @e[type=pig,tag=sacrifice] run function example:perform_necromancy
example:perform_necromancy
:
say I am still alive
function example:kill_me
say I am dead inside
example:kill_me
:
kill @s
After the function example:kill_me
is executed the pig is dead, yet it speaks to us from the other side.
Currently this cannot be handled by the debugger.
If you try to debug the function example:sacrifice_pig
it will crash:
[Info] Started debugging example:sacrifice_pig
[Pig] I am still alive
[Error] Selected entity was killed!
Hitting the Maximum Command Chain Length
By default Minecraft only executes up to 65536 commands per tick. Since the debugger needs to run many commands in addition to the commands of your datapack, you might hit this limit when debugging a very large datapack. When this happens the debug session will be left in an undefined state. If there are no schedules, the development tool will wait indefinitely and you will have to manually terminate the debug session. If there are upcoming schedules they may crash the debug session or exhibit unexpected behaviour.
To avoid hitting the command limit you can add more breakpoints, step through the function line by line, or increase the command limit:
/gamerule maxCommandChainLength 2147483647
Chunkloading
If a chunk that contains an entity required for debugging is unloaded, while a function is suspended on a breakpoint, the debug session will crash, when you try to resume the execution.
This can for example happen if you go far away or if the function operates in a chunk that is only loaded temporarily (for instance by a teleport
command or by going through a portal).
Installation
Using precompiled binaries
Precompiled binaries are available under releases.
Installing from source
Mcfunction-Debugger is written in Rust so to build it from source you need to install Rust.
You can then install it from crates.io by running:
cargo install mcfunction-debugger
Or from Codeberg by running:
cargo install --git https://codeberg.org/vanilla-technologies/mcfunction-debugger.git
To uninstall run:
cargo uninstall mcfunction-debugger
For Developers
Mcfunction-Debugger only supports the single session mode with communication via stdin and stdout.
To start executing an mcfunction file the development tool needs to send a launch
request (the attach
request is not supported).
Launch Arguments
In order for the debug adapter to connect to Minecraft it needs a few arguments as part of the launch
request:
program
Path to the mcfunction file to debug.
The mcfunction file must be contained in a datapack with a pack.mcmeta
file.
minecraftWorldDir
The directory containing the Minecraft world the debug adapter should connect to.
For single player this is typically a directory within the saves directory:
- Windows:
%appdata%\.minecraft\saves\
- GNU/Linux:
~/.minecraft/saves/
- Mac:
~/Library/Application Support/minecraft/saves/
For servers it is specified in server.properties
.
minecraftLogFile
The path to Minecraft's log file.
For single player this is typically at these locations:
- Windows:
%appdata%\.minecraft\logs\latest.log
- GNU/Linux:
~/.minecraft/logs/latest.log
- Mac:
~/Library/Application Support/minecraft/logs/latest.log
For servers it is at logs/latest.log
in the server directory.
Example
{
"program": "C:/Users/Herobrine/my_datapack/data/my_namespace/functions/main.mcfunction",
"minecraftWorldDir": "C:/Users/Herobrine/AppData/Roaming/.minecraft/saves/New World",
"minecraftLogFile": "C:/Users/Herobrine/AppData/Roaming/.minecraft/logs/latest.log"
}
Command Line Interface
mcfunction-debugger [FLAGS] [OPTIONS]
Flags
--help
Prints help information.
--version
Prints version information.
Options
--log-file
Path to a log file. If specified the debug adapter will create this file on startup and write log messages to it.
--log-level
The log level can also be configured via the environment variable LOG_LEVEL
.
Defaults to INFO
.
Dependencies
~12–22MB
~367K SLoC