Overview
This example creates commands with:- String arguments with phrase support
- Tab completion suggestions
- Argument validation and parsing
- Player-only command restrictions
- Multiple argument types (literals, strings, integers)
Complete Example
Project Structure
command-plugin/
├── go.mod
└── main.go
go.mod
go.mod
module command-plugin
go 1.24
require (
go.minekube.com/brigodier v0.0.2
go.minekube.com/common v0.3.0
go.minekube.com/gate v0.62.3
)
main.go
main.go
package main
import (
"context"
"fmt"
"go.minekube.com/brigodier"
"go.minekube.com/common/minecraft/color"
"go.minekube.com/common/minecraft/component"
"go.minekube.com/common/minecraft/component/codec/legacy"
"go.minekube.com/gate/cmd/gate"
"go.minekube.com/gate/pkg/command"
"go.minekube.com/gate/pkg/edition/java/proxy"
)
var legacyCodec = &legacy.Legacy{Char: legacy.AmpersandChar}
func main() {
proxy.Plugins = append(proxy.Plugins, proxy.Plugin{
Name: "CommandPlugin",
Init: func(ctx context.Context, p *proxy.Proxy) error {
registerCommands(p)
return nil
},
})
gate.Execute()
}
func registerCommands(p *proxy.Proxy) {
registerBroadcastCommand(p)
registerAlertCommand(p)
registerServerCommand(p)
}
// /broadcast <message> - Broadcast a message to all players
func registerBroadcastCommand(p *proxy.Proxy) {
p.Command().Register(
brigodier.Literal("broadcast").Then(
brigodier.Argument("message", brigodier.StringPhrase).
// Add tab completion suggestions
Suggests(command.SuggestFunc(func(
c *command.Context,
b *brigodier.SuggestionsBuilder,
) *brigodier.Suggestions {
// Suggest personalized messages for players
if player, ok := c.Source.(proxy.Player); ok {
b.Suggest(fmt.Sprintf("&oI am &6&l%s", player.Username()))
}
b.Suggest("&eHello everyone!")
b.Suggest("&aWelcome to the server")
b.Suggest("&cServer will restart in 5 minutes")
return b.Build()
})).
Executes(command.Command(func(c *command.Context) error {
// Parse the message with legacy color codes
message, err := legacyCodec.Unmarshal([]byte(c.String("message")))
if err != nil {
return c.Source.SendMessage(&component.Text{
Content: fmt.Sprintf("Error formatting message: %v", err),
S: component.Style{Color: color.Red},
})
}
// Broadcast to all players
for _, player := range p.Players() {
// Send in goroutine to avoid blocking on slow connections
go func(pl proxy.Player) {
_ = pl.SendMessage(message)
}(player)
}
return c.Source.SendMessage(&component.Text{
Content: "Broadcast sent!",
S: component.Style{Color: color.Green},
})
})),
),
)
}
// /alert <player> <message> - Send an alert to a specific player
func registerAlertCommand(p *proxy.Proxy) {
p.Command().Register(
brigodier.Literal("alert").Then(
brigodier.Argument("player", brigodier.String).
// Suggest online player names
Suggests(command.SuggestFunc(func(
c *command.Context,
b *brigodier.SuggestionsBuilder,
) *brigodier.Suggestions {
for _, player := range p.Players() {
b.Suggest(player.Username())
}
return b.Build()
})).
Then(
brigodier.Argument("message", brigodier.StringPhrase).
Executes(command.Command(func(c *command.Context) error {
playerName := c.String("player")
messageText := c.String("message")
// Find the target player
target := p.Player(playerName)
if target == nil {
return c.Source.SendMessage(&component.Text{
Content: fmt.Sprintf("Player %s not found", playerName),
S: component.Style{Color: color.Red},
})
}
// Parse and send the alert
message, err := legacyCodec.Unmarshal([]byte(messageText))
if err != nil {
return c.Source.SendMessage(&component.Text{
Content: fmt.Sprintf("Error formatting message: %v", err),
S: component.Style{Color: color.Red},
})
}
_ = target.SendMessage(&component.Text{
S: component.Style{Color: color.Yellow, Bold: component.True},
Extra: []component.Component{
&component.Text{Content: "[ALERT] "},
message,
},
})
return c.Source.SendMessage(&component.Text{
Content: fmt.Sprintf("Alert sent to %s", playerName),
S: component.Style{Color: color.Green},
})
})),
),
),
)
}
// /server [server] - Connect to a server or list servers
func registerServerCommand(p *proxy.Proxy) {
p.Command().Register(
brigodier.Literal("server").
// /server with no arguments - list servers
Executes(command.Command(func(c *command.Context) error {
player, ok := c.Source.(proxy.Player)
if !ok {
return c.Source.SendMessage(&component.Text{
Content: "Only players can use this command",
S: component.Style{Color: color.Red},
})
}
servers := p.Servers()
if len(servers) == 0 {
return player.SendMessage(&component.Text{
Content: "No servers available",
S: component.Style{Color: color.Yellow},
})
}
msg := &component.Text{
Content: "Available servers: ",
S: component.Style{Color: color.Green},
}
for i, server := range servers {
if i > 0 {
msg.Extra = append(msg.Extra, &component.Text{
Content: ", ",
})
}
msg.Extra = append(msg.Extra, &component.Text{
Content: server.ServerInfo().Name(),
S: component.Style{Color: color.Aqua},
})
}
return player.SendMessage(msg)
})).
// /server <name> - connect to server
Then(
brigodier.Argument("name", brigodier.String).
// Suggest available servers
Suggests(command.SuggestFunc(func(
c *command.Context,
b *brigodier.SuggestionsBuilder,
) *brigodier.Suggestions {
for _, server := range p.Servers() {
b.Suggest(server.ServerInfo().Name())
}
return b.Build()
})).
Executes(command.Command(func(c *command.Context) error {
player, ok := c.Source.(proxy.Player)
if !ok {
return c.Source.SendMessage(&component.Text{
Content: "Only players can use this command",
S: component.Style{Color: color.Red},
})
}
serverName := c.String("name")
server := p.Server(serverName)
if server == nil {
return player.SendMessage(&component.Text{
Content: fmt.Sprintf("Server %s not found", serverName),
S: component.Style{Color: color.Red},
})
}
// Connect player to server
player.CreateConnectionRequest(server).Connect()
return nil
})),
),
)
}
Building and Running
# Initialize module
go mod init command-plugin
go mod tidy
# Build
go build -o command-plugin
# Run
./command-plugin
Command Usage
Once running, try these commands in-game:/broadcast &eHello everyone!
/alert Steve &cThis is an important message
/server
/server lobby
Key Features Explained
Argument Types
brigodier.Argument("name", brigodier.String)
// Captures a single word: /cmd word
brigodier.Argument("message", brigodier.StringPhrase)
// Captures everything after: /cmd hello world!
brigodier.Argument("count", brigodier.Integer)
// Captures an integer: /cmd 42
Tab Completion
Provide suggestions to help users:Suggests(command.SuggestFunc(func(
c *command.Context,
b *brigodier.SuggestionsBuilder,
) *brigodier.Suggestions {
b.Suggest("option1")
b.Suggest("option2")
return b.Build()
}))
Legacy Color Codes
Gate supports Minecraft’s legacy color codes (& format):
// Parse color codes like &e, &a, &c, etc.
message, err := legacyCodec.Unmarshal([]byte("&eYellow &aGreen"))
&0-9, a-f- Colors&l- Bold&m- Strikethrough&n- Underline&o- Italic&r- Reset
Player-Only Commands
Restrict commands to players:player, ok := c.Source.(proxy.Player)
if !ok {
return c.Source.SendMessage(&component.Text{
Content: "Only players can use this command",
})
}
Command Context
Retrieve arguments from the command context:// String arguments
playerName := c.String("player")
// Integer arguments
count := c.Int("count")
// Boolean arguments
enabled := c.Bool("enabled")
Advanced Topics
Command Permissions
Add permission checks to commands
Brigadier API
Deep dive into Brigadier’s command system
Command Aliases
Register multiple names for commands
Custom Arguments
Create custom argument types
Next Steps
- See Event Listener Example for event handling
- Learn about Command Overview
- Explore Simple Plugin Example for basics
Always validate user input! Check that players exist, servers are available, and arguments are in valid ranges.

