> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/minekube/gate/llms.txt
> Use this file to discover all available pages before exploring further.

# Simple Plugin Example

> A complete working example showing how to create a basic Gate plugin with event handling and commands.

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:

```go go.mod theme={null}
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

```go main.go theme={null}
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

```bash theme={null}
go mod init simple-plugin
go mod tidy
```

### Build the plugin

```bash theme={null}
go build -o simple-plugin
```

### Run the plugin

```bash theme={null}
./simple-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:

```yaml config.yml theme={null}
config:
  bind: 0.0.0.0:25565
  servers:
    lobby:
      address: localhost:25566
    survival:
      address: localhost:25567
  try:
    - lobby
```

## Key Concepts

<Card title="Plugin Registration" icon="plug">
  Plugins are registered by appending to `proxy.Plugins` before calling `gate.Execute()`
</Card>

<Card title="Initialization Hook" icon="rocket">
  The `Init` function is called after the proxy initializes but before it starts accepting connections
</Card>

<Card title="Event System" icon="bolt">
  Use `event.Subscribe()` to listen to proxy events with a priority value (0 is normal)
</Card>

<Card title="Command Registration" icon="terminal">
  Commands are registered using Brigadier's fluent API via `proxy.Command().Register()`
</Card>

## Next Steps

* See [Command Plugin Example](/developers/examples/command-plugin) for advanced command handling
* See [Event Listener Example](/developers/examples/event-listener) for comprehensive event handling
* Explore the [Events API](/developers/events/overview) for all available events
* Learn about [Command Permissions](/developers/commands/permissions)

<Tip>
  The `context.Context` passed to the Init function is canceled when the proxy shuts down. Use it for graceful cleanup!
</Tip>
