Introduction
Mcrizzledizzle is an incredibly shitty yet somehow performant take on the classic Minecraft server.
Here you can find information about writing plugins and configuring the server.
Configuration
The config file is a regular toml file that is placed in the same directory that the program is run from. There's an example in the repo where all the available parameters have been set.
The config is split into two parts, one relating to server operations and another relating to world operations.
[server]
Under server you can set the port, motd and name of the server.
name = "server of ire"
motd = "Message of the day" # There's a 64 character limit on these so be careful (including colour escapes)
port = 25565 # default mc port
max_players = 255 # 255 is the maximum number
[world]
For the world you can set the path and size (for generation) of the world.
world = "world.wrld" # This is a custom world format that will not work with other servers
# Generator settings
size_x = 64
size_y = 32
size_z = 64
Installing Extensions
Extensions are distributed as rhai
files. As with all software that you install on your computer, it's important to make sure that you trust the program that you're running as they are quite powerful.
Extensions go into the auto-generated extension folder. Some official examples can be found in the extensions folder on the repository:
fill.rhai
- A worldedit like fill commandping-pong.rhai
- A very basic command, responds when you using /pingutils.rhai
- A set of utilities used for development of the extension interface
To see what commands are available you can use the /help
command. To see what extensions are installed and their versions you can use the /extensions
command.
Other extensions
There are some third-party extensions that are officially endorsed by mcrizzledizzle.
- williamist/rizzle-extensions - A great (set of) extension(s) written by a contributor
Extensions
The extensions interface uses the rhai programming language with some custom functionality to provide a full set of instructions for making extensions.
Extension Structure
All extensions must provide a metadata()
and init(players, world)
function. mcrizzledizzle uses these internally to populate information about the extension as well as register any commands or event listeners that the extension might want to use.
Example:
#![allow(unused)] fn main() { fn metadata() { Metadata("My Awesome Plugin's name!", "My Plugin's (less awesome) author", Version("1.0.0")) } fn init(players, world) { ... } }
The Metadata
struct expects a name string, description string and valid Version()
. The Version should be a valid semantic version otherwise the plugin will not load correctly.
Types
This contains a big list of structs and their available functions to call from rhai.
Metadata
This type tells mcrizzledizzle important imformation about the plugin.
The struct signature looks like this:
#![allow(unused)] fn main() { struct Metadata { name: String, author: String, version: Version, }; }
It should be used inside the metadata function like so:
#![allow(unused)] fn main() { fn metadata() { Metadata("Example Name", "Example Description", Version("1.0.0")) } }
Version
This type is stored internally as a complete semantic version, an easy constructor is provided that converts a valid semver to a set of parts, providing a display function.
Struct signature:
#![allow(unused)] fn main() { struct Version { major: u16, minor: u16, patch: u16, prerelease: String, build: String, }; }
Usually it would be used along with Metadata to setup an extension.
Player
The player struct probably shouldn't be modified by plugins, in any case, here's the struct definition:
#![allow(unused)] fn main() { struct Player { id: u8, }; }
PlayersWrapper
The PlayersWrapper struct wraps around the server's Player Data mutex. It provides a friendly interface for extensions.
#![allow(unused)] fn main() { struct PlayersWrapper(Arc<Mutex<[Player; 255]>>); }
You cannot instantiate a PlayersWrapper yourself, it is passed as the first argument of init() and can then be called upon from there.
Implementations
send_message
#![allow(unused)] fn main() { fn send_message( self, player: u8, message: String, ) }
This function expects a player id and a message to be passed as arguments. Keep in mind that the length limit for messages is 64 characters.
send_all
#![allow(unused)] fn main() { fn send_all(self, message: String) }
This function is like send_message
except it sends the message to all connected players.
username
#![allow(unused)] fn main() { fn username(self, player: u8) }
This function gets the username of a player from their id.
WorldWrapper
The WorldWrapper struct wraps around the server's World Data mutex. It provides a friendly interface for extensions.
#![allow(unused)] fn main() { struct WorldWrapper(Arc<Mutex<World>>); }
You cannot instantiate a WorldWrapper yourself, it is passed as the second argument of init() and can be called upon from there.
Implementations
set_block
#![allow(unused)] fn main() { fn set_block( self, players_wrapper: PlayersWrapper, position: Vec3, block_type: u8, ) }
This functions sets a block at the desired position. Since it uses the player data internally it requires the PlayersWrapper.
Context
The context is a struct that you can create to tell the server about what your plugin wants to do. You must create one if you want to register commands or add event listeners.
#![allow(unused)] fn main() { struct Context { commands: HashMap<String, FnPtr>, event_listener: HashMap<EventType, FnPtr>, }; }
Implementations
register_command
#![allow(unused)] fn main() { fn register_command(&mut self, name: String, callback: FnPtr) }
This is how you can register commands on the server. Your `callback`` likely should be a closure as you almost certainly want to capture information from the environment.
add_event_listener
#![allow(unused)] fn main() { fn add_event_listener(&mut self, event: &str, callback: FnPtr) }
This is how event listeners are created. `callback`` should probably be a closure because you almost certainly want information from the environment. The currently available event types are:
"block_break"
This is fired when a black is broken. This is interruptible."player_leave"
This is fired when a player leaves the server. This is not interruptible.
Vec3
Vec3s are used to store positions of blocks and players.
#![allow(unused)] fn main() { struct Vec3 { pub x: i16, pub y: i16, pub z: i16, } }
You can create one using the constructor:
#![allow(unused)] fn main() { Vec3(x: i64, y: i64, z: i64) }
Event
Events are structs that tell the extension about changes in server or player state.
#![allow(unused)] fn main() { struct Event { player: u8, position: Vec3, selected_block: u8, is_cancelled: bool, } }
Only certain parts of the struct are used for certain events. Since events are only returned to their corresponding handler, the event type is not provided in the struct. Available event types are:
"block_break"
This is fired when a black is broken. This is interruptible."player_leave"
This is fired when a player leaves the server. This is not interruptible.
Implementations
cancel
#![allow(unused)] fn main() { fn cancel(&mut self) }
This sets is_cancelled to true, cancelling interruptible events, like block breaking.
Functions
These functions can be called directly from an extension. They aren't tied to any structure.
Logging
These functions all go directly to the server logs, as you'd expect. They all take a message and handle the rest for you.
info
Signature:
#![allow(unused)] fn main() { fn info(msg: String) }
warn
Signature:
#![allow(unused)] fn main() { fn warn(msg: String) }
error
Signature:
#![allow(unused)] fn main() { fn error(msg: String) }
debug
Signature:
#![allow(unused)] fn main() { fn debug(msg: String) }