Build, run and hot reload
The loop
Section titled “The loop”-
Start the server once, with a plugins folder, and leave it running:
Terminal window cd run../build/bin/ramjet --data-dir ../data --plugins plugins -
In your plugin project, with
RAMJET_PLUGINSset (see create a plugin), build:Terminal window dotnet build -c Release -
The build copies
Homes.dll,Homes.pdbandplugin.jsonintorun/plugins/Homes/. The server notices, waits 250 ms for the write to finish, and reloads the plugin:[INFO] hot reloading Homes.dll[INFO] [Homes] enabled v1.0.1 (id 1)[INFO] [Homes] disabledThe new version is enabled before the old one is released, so there is no window in which your commands or event handlers are missing. Edit, build, test again: a few seconds per cycle.
If you do not set RAMJET_PLUGINS, copy bin/Release/net10.0/Homes.dll, Homes.pdb and plugin.json into plugins/Homes/ yourself.
What survives a reload
Section titled “What survives a reload”- ECS components with an unchanged layout keep their values on every entity. Change a field type or order and the values are dropped (and the component recreated), but only if the reloading plugin is the only one bound to the same component key; otherwise the registration fails and the log says why.
- Entities are not owned by plugins, they survive.
- Files in the plugin’s data folder (
plugins/homes/data/) survive. - Plugin-owned objects (your fields, caches, timers) are gone: the plugin is a new instance. Keep state that must outlive a reload in components or in the data folder. See hot reload for the full rules.
A failed build changes nothing
Section titled “A failed build changes nothing”The new assembly is loaded first and the old one is unloaded only if that worked. A compile error never produces a dll; an exception in the new OnEnable is logged and the previous version keeps running:
[ERROR] failed to load plugin .../Homes.dll ...[WARN] reload of .../Homes.dll failed (code -3); keeping the previous versionPlugins added while the server runs
Section titled “Plugins added while the server runs”A plugin folder copied into plugins/ while the server runs is picked up without a restart. The plugin worker has to grant a new plugin its data folder before the plugin can load, so the server then restarts the worker: every plugin in it is disabled and loaded again, and plugin fields are reset as they are on any reload.
/plugins shows the state of the plugin worker. /plugins reload restarts it on demand; it needs operator level 4.
Debug logging
Section titled “Debug logging”Log.Debug("..."); // visible when the server runs with --verboseLog.Info($"...");Plugin log lines carry the plugin name: [Homes] ....
Test against a scratch server
Section titled “Test against a scratch server”Do not use a server people play on. Start a throw-away one on a free port and bind loopback only, which is the default:
server-ip=127.0.0.1server-port=25640online-mode=falselevel-type=flat # instant superflat world, nothing saved: ideal for plugin testsview-distance=4simulation-distance=4level-type=flat skips world generation and persistence. Startup then spends its time loading the datapack and recipes, which takes anywhere from seconds to a couple of minutes depending on the machine.
To get a player into the server without a Minecraft client, use the repository’s headless load-test client; it speaks the real protocol:
build/bin/botswarm --port 25640 --bots 1 --duration 20 --behaviour chat:100 --chat-interval 5The bot joins, so your PlayerJoinEvent handler runs, and chat bots send chat messages, which exercises PlayerChatEvent.
The repository also contains an automated version of this walk-through: docs-site/scripts/verify-template.mjs instantiates the template, builds it, starts a scratch server, rebuilds the plugin to check the hot reload and joins a bot (npm run verify:template).
Stop the server
Section titled “Stop the server”Type stop in the server console. On shutdown every plugin gets OnDisable in turn and its registrations are released.