Minecraft Websocket Integration

Description

Allows websockets to run commands on your server.

Building

$ mvn

The output plugin will be in target/

Simple Getting Started

Tutorial:

1. Connecting to the WebSocket Server

  1. Inside Streamer.bot, navigate to the Servers/Clients tab.
  2. Click the sub-tab Websocket Clients.
  3. Inside the window, add a new Host, by right-clicking and pressing Add.
  4. Inside the popup window, set the Name to Minecraft WebSocket Server.
  5. Inside the popup window, set the Host to ws://{localhost}:{8887}. (please replace {localhost} with your host, and {8887} with your port number)
  6. Click Ok.

You will be changing message actions later. Don’t worry!

2. Setting up Actions

In this guide, you will be setting up the ‘basics’ of connecting to the WebSocket server, listening to events, and sending commands.

If this sounds like a lot, don’t worry! 99% of this is already done for you!


  1. Import the actions above.
  2. Navigate to the MC WS Message action, you should see the following:

  1. If you have a authentication token on the server, you need to change the %authenticationBearerToken% to the token.

AuthBearerToken

  1. Go back to the Websocket Clients tab, and edit the Minecraft WebSocket Server client. Change the Message to the MC WS Message action.

WSMessage

  1. Connect the websocket client to the server.

3. Setting up events

  1. Create a new action named MC WS Event-{event name}.
  2. Add any sub-actions you want to the action.

4. Sending Commands

You have 2 ways to send commands to the server.

C#:

CPH.WebsocketSend("Command {command}");

Sub-Actions:

  1. Define a variable named cmd and set it to the command you want to send.
  2. Add a C# Method subaction, and call MC WS Message Handler, and set the method to SendCommand.

Complete Getting Started

Setting up the server

  1. Create a new Minecraft server running a version of Spigot
    • currently only tested with 1.18.1
  2. Put the Plugin in the server’s plugins folder, and restart the server.
  3. Set up the config file in the server’s plugins folder.

Connecting to WebSocket Server

  1. Connect to the WebSocket Server
    • If you don’t know how to do this please read This Wiki
  2. Once you have connected to the WebSocket Server, you will receive a message from the Server.
  3. If you receive a message from the Server, you will see one the following:
    • Authentication not required...
    • Authentication needed... Send as "Bearer {Auth token}"
  4. If you received the 2nd message, you will need to authenticate with the Server.
    1. You will need to send the Bearer token to the Server.
    2. The Server will send back a message with the Authentication Status, you will see one of the following:
      • Successfully Authenticated...
      • Incorrect Authentication Bearer token supplied!
    3. If you received the 2nd message, your token that you sent was incorrect.
      Otherwise, you have successfully authenticated with the Server.
  5. You will now be able to send commands to the Server.

Sending Commands to the Server

There are a few commands that you can send to the Server.

  • Minecraft commands
    • These commands are default commands that Minecraft has, and Plugin commands installed on the Server.
    • These commands are sent as Command {Command}
      • For example, Command say Hello World
        • This will send the command say Hello World to the Server, and will result in Hello World will be sent to all players.
  • Event commands
  • These commands allow your client to opt-in/out of events on the server
    • These commands are sent as Listen {Event} and Ignore {Event}

Minecraft Events

Listening

  • From a connected client run Listen <EventName>
    • Example: Listen PlayerDeathEvent

Stop Listening

  • From a connected client, that is already listening to an event, run Ignore <EventName>
    • Example: Ignore PlayerDeathEvent

List of Events, and arguments

Events are formatted like Event <EventName> <Json Object of arguments>

  • Example: Event PlayerDeathEvent {"player":{"username":"KK964", "uuid":"793b1b35-18ba-419c-b735-024b63d24715"}, "message":"KK964 died of a heart attack", "location":{"world":"world", "x":-9.5, "y":67, "z":-9.5}}

Unchanging arguments:

These arguments are formatted the same for all events. In event descriptions it will just be labeled as "<key>": <Player,Location,Block,Entity>

  • Player:
    • username: The username of the player
    • uuid: The UUID of the player
  • Location:
    • world: The world the event is in
    • x: The x coordinate of event
    • y: The y coordinate of event
    • z: The z coordinate of event
  • Block:
    • x: The x coordinate of the block
    • y: The y coordinate of the block
    • z: The z coordinate of the block
    • type: The type of block, ex: stone
  • Entity:
    • type: The type of entity, ex: creeper
    • name: The name of the entity
    • location: The location of the entity

Player Events

PlayerDeathEvent

This event is triggered when a player dies

Event PlayerDeathEvent {"player": Player, "message": String, "location": Location}

Arguments:

  • player - The [Player][player] that died
  • message - The death message
  • location - The [Location][location] of the death
PlayerJoinEvent

This event is triggered when a player joins

Event PlayerJoinEvent {"player": Player}

Arguments:

  • player - The [Player][player] that joined
PlayerQuitEvent

This event is triggered when a player leaves

Event PlayerQuitEvent {"player": Player}

Arguments:

  • player - The [Player][player] that left
PlayerChatEvent

This event is triggered when a player chats

Event PlayerChatEvent {"player": Player, "message": String}

Arguments:

  • player - The [Player][player] that sent the message
  • message - The message that was sent
PlayerDamageEvent

This event is triggered when a player takes damage

Event PlayerDamageEvent {"player": Player, "damage": Number, "health": Number, "cause": String}

Arguments:

  • player - The [Player][player] that took damage
  • damage - The amount of damage that was taken
  • health - The amount of health the player has left
  • cause - The cause of the damage List of causes
PlayerHealEvent

This event is triggered when a player regains health

Event PlayerHealEvent {"player": Player, "regained": Number, "health": Number, "cause": String}

Arguments:

  • player - The [Player][player] that was healed
  • regained - The amount of health that was regained
  • health - The amount of health the player has
  • cause - The cause of the regeneration List of causes
PlayerAdvancementDoneEvent

This event is triggered when a player completes an advancement

Event PlayerAdvancementDoneEvent {"player": Player, "advancement": String}

Arguments:

  • player - The [Player][player] that completed the advancement
  • advancement - The advancement completed List of advancements
PlayerChangedWorldEvent

This event is triggered when a player changes worlds

Event Name {"player": Player, "world": String, "fromWorld": String}

Arguments:

  • player - The [Player][player] that changed worlds
  • world - The world the player changed to
  • fromWorld - The world the player changed from
PlayerFoodChangeEvent

This event is triggered when a players food level changes

Event Name {"player": Player, "food": Number, "saturation": Number}

Arguments:

  • player - The [Player][player] that changed food level
  • food - New food level
  • saturation? - The current saturation level, may not be returned if version is below 1.16
PlayerDamagePlayerEvent

This event is triggered when a player damages another player

Event Name {"player": Player, "damager": Player, "damage": Number, "health": Number, "damagerHealth": Number}

Arguments:

  • player - Player that was damaged
  • damager - Player that damaged the player
  • damage - Amount of damage that was dealt
  • health - The amount of health the player has left
  • damagerHealth - The amount of health the damager has left
PlayerStatusChangeEvent

This event is triggered when one of the following changes:

  • Player is swimming / no longer swimming
  • Player is flying / no longer flying
  • Player is freezing / no longer freezing
  • Player is burning / no longer burning
  • Player is gliding / no longer gliding (elytra)

PlayerStatusChangeEvent {"player": Player, "status": Status, "oldStatus": Status}

Arguments:

  • player - The [Player][player] that changed status
  • status - The new status
  • oldStatus - The old status
  • status - {"isSwimming":bool,"isFreezing":bool,"isBurning":bool,"isFlying":bool,"isGliding":bool}
    • isFreezing - may not be returned if version is below 1.18
PlayerMoveEvent

This event is triggered when a player moves (only when the block changes)

PlayerMoveEvent {"player": Player, "location": Location, "fromLocation": Location, "block": Block, "standingOn": Block}

Arguments:

  • player - The [Player][player] that moved
  • location - The [Location][location] the player moved to
  • fromLocation - The [Location][location] the player moved from
  • block - The [Block][block] the players feet are in
  • standingOn - The [Block][block] the player is standing on
PlayerExpChangeEvent

This event is triggered when a player gains or loses experience

Event PlayerExpChangeEvent {"player": Player, "level": Number, "oldLevel": Number, "xp": Number, "neededToLevelUp": Number}

Arguments:

  • player - The [Player][player] that gained or lost experience
  • level - The amount of experience the player has
  • oldLevel - The amount of experience the player had
  • xp - The amount of experience points total
  • neededToLevelUp - The amount of experience points needed to level up
EventName

This event is triggered when

Event Name {}

Arguments:

  • **** -
PlayerKillEntityEvent

This event is triggered when a player kills an entity

Event PlayerKillEntityEvent {"player": Player, "entity": Entity}

Arguments:

  • player - The [Player][player] that killed the entity
  • entity - The [Entity][entity] that was killed

World Events

BlockPlaceEvent

This event is triggered when a player places a block

Event BlockPlaceEvent {"player": Player, "block": Block}

Arguments:

  • player - The [Player][player] that placed the block
  • block - The [Block][block] that was placed
BlockBreakEvent

This event is triggered when a player breaks a block

Event BlockBreakEvent {"player": Player, "block": Block}

Arguments:

  • player - The [Player][player] that broke the block
  • block - The [Block][block] that was broken

Using the Plugin in Streamer.bot

Make sure that you have Streamer.bot installed before following guide!


Setting up default actions

  1. Inside Streamer.bot, navigate to the Actions tab.
  2. Right click on the Actions tab and select Add.
  3. Create a group for the action called Minecraft Websocket.
  4. Name the action MC WS Connected.
  5. Then press Ok.
  6. Add 2 more actions to the group, called MC WS Disconnected and MC WS Message.

Connecting to the WebSocket Server

  1. Inside Streamer.bot, navigate to the Servers/Clients tab.
  2. Click the sub-tab Websocket Clients.
  3. Inside the window, add a new Host, by right-clicking and pressing Add.
  4. Inside the popup window, set the Name to Minecraft WebSocket Server.
  5. Inside the popup window, set the Host to ws://{localhost}:{8887}. (please replace {localhost} with your host, and {8887} with your port number)
  6. Set the Action Connected to MC WS Connected.
  7. Set the Action Disconnected to MC WS Disconnected.
  8. Set the Action Message to MC WS Message.
  9. Click Ok.

Setting up Actions

In this guide, the following will be the flowchart of the actions:

Example workflow:

WS Connect

  • Log to file

WS Message

  • Authenticate
  • Subscribe to events
  • Send events to WS Events

WS Disconnect

  • Log to file

WS Events

  • Get event ran
  • Run WS Event-{event ran}

WS Event-{events}

  • Convert event data to Json
  • Send message in twitch chat

1. MC WS Connected

  1. Make a sub action FileWrite to file, make a new file called WS_Logs.txt, and set it to append to the file, with the text %date% %time% - WS Connected.

2. MC WS Disconnected

  1. Make a sub action FileWrite to file, select the file called WS_Logs.txt, and set it to append to the file, with the text %date% %time% - WS Disconnected.

3. MC WS Message

This is where the magic starts!

  1. Make a sub action FileWrite to file, select the file called WS_Logs.txt, and set it to append to the file, with the text %date% %time% - WS Message: %message%.
  2. Make a sub action C#Run C# code
    • inside the C# window, add the following inside Execute():
string auth = ""; // Add your authentication token here
string[] listeners = { // Add the events you want to listen to here
  "PlayerDeathEvent",
};

string msg = args["message"].ToString();

if (msg.StartsWith("Authentication needed")) {
  // Send authentication message
  // Set connection to the 0-based index of your Minecraft websocket client.
  CPH.WebsocketSend("Bearer " + auth, connection: 0);
  return true;
}
if (msg.StartsWith("Authentication not required") || msg.StartsWith("Successfully Authenticated")) {
  // Subscribe to events
  string listenString = "Listen " + String.Join("\nListen ", listeners);

  // Set connection to the 0-based index of your Minecraft websocket client.
  CPH.WebsocketSend(listenString, connection: 0);
  return true;
}

if (msg.StartsWith("Event ")) {
  // Event received
  CPH.SetArgument("event", msg.Substring("Event ".Length));
  CPH.RunAction("MC WS Event Handler");
}
return true;
  1. This will handle all messages between the server and the client.

MC WS Event Handler

  1. Make a sub action C#Run C# code
    • inside the C# window, add the following inside Execute():
string ev = args["event"].ToString();
string evRun = ev.Split(' ')[0];
string unParsedJson = ev.Substring(evRun.Length);
CPH.SetArgument("event-json", unParsedJson);
CPH.RunAction("MC WS Event-" + evRun);
return true;
  1. This will forward the event to the correct action.

MC WS Event-{event ran}

  1. Replace {event ran} with the event name you want to handle.
  2. Handle the event
  3. Example with PlayerDeathEvent: (making the action name MC WS Event-PlayerDeathEvent)
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

public class CPHInline
{

  public class Player
  {
    public string username { get; set; }
    public string uuid { get; set; }
  }

  public class Location
  {
    public string world { get; set; }
    public double x { get; set; }
    public double y { get; set; }
    public double z { get; set; }
  }

  public class Death
  {
    public Player player { get; set; }
    public string message { get; set; }
    public Location location { get; set; }
  }

  public bool Execute()
  {
    Death death = JsonConvert.DeserializeObject<Death>(args["event-json"].ToString());
    Player player = death.player;
    Location location = death.location;
    CPH.SendMessage(death.message);
    CPH.SendMessage(player.username + " died in " + location.world + ", at " + location.x + ", " + location.y + ", " + location.z);
    return true;
  }
}

Forwarding Twitch Chat to Minecraft Chat

  1. Inside Streamer.bot, navigate to the Actions tab.
  2. Make an action called Forward Twitch Chat to Minecraft Chat.
  3. Navigate to the SettingsEvents tab.
  4. Set Chat Message to Forward Twitch Chat to Minecraft Chat.
  5. Go back to the Forward Twitch Chat to Minecraft Chat action.
  6. Make a sub action C#Run C# code
    • inside the C# window, add the following inside Execute():
string msg = args["message"].ToString();
// Make sure to remove bad characters from the message, if you don't, users can break out of tellraw, and other commands
msg = msg.Replace("\\", "");
msg = msg.Replace("\"", "");

string user = args["user"].ToString();

// Set connection to the 0-based index of your Minecraft websocket client.
CPH.WebsocketSend("Command say ["+user+"] " + msg, connection: 0);
return true;
  1. This will forward the message to the Minecraft server.
4 Likes