Remote control your Redstone contraptions using WebSockets.
This mod is inspired by a YouTube video by Fundy, in which he briefly shows a custom Redstone block that can be controlled via a browser. This part of the video never got released as a standalone mod, so this is where Webstone comes in.
The mod opens up a WebSocket server on port 4321, which then lets you connect with any WebSocket client (like this one - or the hosted client at http://webstone.festival.tf) to toggle registered blocks or change their output signal strength.
You can find the Webstone Remote Block under the "Redstone Blocks" tab in Creative Mode (no Survival recipe yet). To register it, right-click it with an empty hand (if successful, you'll see a message above your hotbar). To toggle it locally, right-click the block while sneaking.
Starting with Webstone 1.0.1, the Webstone Remote Block can be crafted outside of Creative:
Webstone has its own configuration file, located at .minecraft/config/webstone-config.toml
. You can set the following options:
Key | Default value | Description |
---|---|---|
Passphrase |
"" |
Passphrase to allow only authorized users. |
WebSocketPort |
4321 |
Port used by the Webstone WebSocket Server. |
SecureWebSocket |
false |
Specifies if the WebSocket should use a secure connection. |
CertificateFilename |
cert.pem |
Filename of the certificate public key inside .minecraft/data . |
CertificateKeyFilename |
key.pem |
Filename of the certificate private key inside .minecraft/data . |
CertificateKeyPass |
"" |
Passphrase used for the private key. |
Server → Client
If the WebSocket server needs a passphrase to connect to, clients need to supply it encoded as a hex string in the Sec-WebSocket-Protocol
header. Using JavaScript, you can add it to an array as a second parameter when creating a WebSocket instance, following the connection URL:
const socket = new WebSocket('ws://<IP address or FQDN>:4321', ['<your passphrase>']);
When connecting to the WebSocket server, the connecting client receives a list of currently registered blocks (including their display name, the current powered state, the output signal strength and the assigned group's id, if any), as well as block groups.
{
"type": "block_list",
"data": [
{
"blockId": "00000000-0000-0000-0000-000000000000",
"name": "Example",
"power": 15,
"powered": false,
"groupId": "00000000-0000-0000-0000-000000000000"
},
// ...
]
}
{
"type": "block_groups",
"data": [
{
"groupId": "00000000-0000-0000-0000-000000000000",
"name": "Example Group",
"blockIds": [
//...
]
},
// ...
]
}
If any block or group is updated, their data will broadcast to every connected client.
{
"type": "block_updated",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000",
"name": "Example",
"power": 15,
"powered": false,
"groupId": "00000000-0000-0000-0000-000000000000"
}
}
{
"type": "group_updated",
"data":
"groupId": "00000000-0000-0000-0000-000000000000",
"name": "Example Group",
"blockIds": [
//...
]
}
}
Client → Server
{
"type": "block_state",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000",
"powered": false // Can be either true or false
}
}
{
"type": "block_power",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000",
"power": 7 // Can be anything between 0 and 15
}
}
{
"type": "rename_block",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000",
"name": "My Example Block"
}
}
{
"type": "unregister_block",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000"
}
}
{
"type": "change_group",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000",
"groupId": "00000000-0000-0000-0000-000000000000"
}
}
This only affects a block if it has been assigned to a group.
{
"type": "move_block",
"data": {
"blockId": "00000000-0000-0000-0000-000000000000",
"newIndex": "2"
}
}
{
"type": "create_group",
"data": {
"name": "My awesome group"
}
}
{
"type": "create_group",
"data": {
"groupId": "00000000-0000-0000-0000-000000000000",
"name": "My awesome (renamed) group"
}
}
{
"type": "delete_group",
"data": {
"groupId": "00000000-0000-0000-0000-000000000000"
}
}
{
"type": "move_group",
"data": {
"groupId": "00000000-0000-0000-0000-000000000000",
"newIndex": 2
}
}
In Webstone 1.0.2, two security options have been added: an optional passphrase required to connect to the WebSocket server, as well as support for Secure WebSockets using SSL certificates.
In order to protect your server from unauthorized access, you can add an optional passphrase that clients need to submit before connecting to the WebSocket Server. This passphrase needs to be hashed using Bcrypt, so you don't have to store your passphrase in plain text.
To generate a Bcrypt hash, you can use mkpasswd
on Debian-based systems (available in the whois
package):
$ mkpasswd -m bcrypt <your password>
$2b$05$aHZ8W4AL3o.GnXN5ocSWXumD0Qlu0fU5jLGseYdLzbDW5N1d21Poa
The result then needs to be added to the configuration using the Passphrase
key.
As described in the API Reference, connecting to the WebSocket server then needs the Sec-WebSocket-Protocol
header to be set client-side to the hex-encoded passphrase in order for the connection to not be rejected.
By default, the traffic between the WebSocket server and clients is unencrypted. To encrypt the traffic, you'll need a domain name and a SSL certificate for that domain specifically, including the private and the public key. Both keys need to be stored in .minecraft/data
as cert.pem
(public key) and key.pem
(private key) respectively. If the private key requires its own passphrase, you can set the CertificateKeyPass
key in the config.
To enable or disable Secure WebSocket, set the SecureWebSocket
key to either true
or false
.
Currently, only Forge is supported. Feel free to port this over to any other mod loader you like, as long as you clearly state this project as the original one.
The mod has been tested on Minecraft 1.20.1, but should also work on newer versions. It also may or may not work on older versions of Minecraft.
Fundy - Original idea, textures (probably)
Kaupenjoe - Creating a tutorial series that made this mod possible in the first place