This example demonstrates how to create a simple Gate plugin from scratch, including plugin initialization, event handling, and command registration.
Overview
This example creates a plugin that:
- Welcomes players when they join
- Adds a
/ping command to check player latency
- Listens to server connection events
- Shows proper plugin structure and initialization
Complete Example
Project Structure
simple-plugin/
├── go.mod
└── main.go
go.mod
Create a new Go module for your plugin:
module simple-plugin
go 1.24
require (
github.com/robinbraemer/event v0.1.1
go.minekube.com/brigodier v0.0.2
go.minekube.com/common v0.3.0
go.minekube.com/gate v0.62.3
)
main.go
package main
import (
"context"
"fmt"
"github.com/robinbraemer/event"
"go.minekube.com/brigodier"
"go.minekube.com/common/minecraft/color"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/gate/cmd/gate"
"go.minekube.com/gate/pkg/command"
"go.minekube.com/gate/pkg/edition/java/proxy"
)
func main() {
// Register the plugin with Gate
proxy.Plugins = append(proxy.Plugins, proxy.Plugin{
Name: "SimplePlugin",
Init: func(ctx context.Context, p *proxy.Proxy) error {
return initPlugin(p)
},
})
// Execute Gate's entrypoint (blocking until shutdown)
gate.Execute()
}
func initPlugin(p *proxy.Proxy) error {
// Register commands
registerCommands(p)
// Register event listeners
registerEvents(p)
return nil
}
func registerCommands(p *proxy.Proxy) {
// Register a simple /ping command
p.Command().Register(
brigodier.Literal("ping").Executes(
command.Command(func(c *command.Context) error {
player, ok := c.Source.(proxy.Player)
if !ok {
return c.Source.SendMessage(&component.Text{
Content: "Pong!",
})
}
return player.SendMessage(&component.Text{
Content: fmt.Sprintf("Pong! Your ping is %s", player.Ping()),
S: component.Style{Color: color.Green},
})
}),
),
)
}
func registerEvents(p *proxy.Proxy) {
// Subscribe to the PostLogin event to welcome players
event.Subscribe(p.Event(), 0, func(e *proxy.PostLoginEvent) {
player := e.Player()
_ = player.SendMessage(&component.Text{
Content: fmt.Sprintf("Welcome to the server, %s!", player.Username()),
S: component.Style{Color: color.Gold},
})
})
// Subscribe to ServerPostConnect to notify on server switches
event.Subscribe(p.Event(), 0, func(e *proxy.ServerPostConnectEvent) {
player := e.Player()
currentServer := player.CurrentServer()
if currentServer == nil {
return
}
_ = player.SendMessage(&component.Text{
Content: fmt.Sprintf("Connected to %s", currentServer.Server().ServerInfo().Name()),
S: component.Style{Color: color.Aqua},
})
})
}
Building and Running
Initialize the module
go mod init simple-plugin
go mod tidy
Build the plugin
go build -o simple-plugin
Run the plugin
Gate will start with your plugin loaded. You can now:
- Join the proxy to see the welcome message
- Use
/ping to check your latency
- Connect to backend servers to see connection messages
Configuration
To configure backend servers, create a config.yml file:
config:
bind: 0.0.0.0:25565
servers:
lobby:
address: localhost:25566
survival:
address: localhost:25567
try:
- lobby
Key Concepts
Plugin Registration
Plugins are registered by appending to proxy.Plugins before calling gate.Execute()
Initialization Hook
The Init function is called after the proxy initializes but before it starts accepting connections
Event System
Use event.Subscribe() to listen to proxy events with a priority value (0 is normal)
Command Registration
Commands are registered using Brigadier’s fluent API via proxy.Command().Register()
Next Steps
The context.Context passed to the Init function is canceled when the proxy shuts down. Use it for graceful cleanup!