Guides

Focused recipes for common plugin and server tasks.

In this section

Related section pages:

First Plugin

Start with the lifecycle shape, register one command, then move gameplay work behind handles. Keep registration in Init so reload cleanup remains predictable.

plugin.go
package minimalpluginimport (	"context"	"fmt"	"github.com/pulse-core/Pulse/core/command"	"github.com/pulse-core/Pulse/core/content"	"github.com/pulse-core/Pulse/core/gameplay"	"github.com/pulse-core/Pulse/core/item"	"github.com/pulse-core/Pulse/core/player"	"github.com/pulse-core/Pulse/core/plugin")type Plugin struct {	ctx        plugin.Context	unregister func()}func New() plugin.Plugin { return &Plugin{} }func init() {	plugin.MustRegisterFactory("minimalplugin", New)}func (p *Plugin) Name() string { return "minimalplugin" }func (p *Plugin) Init(ctx plugin.Context) error {	p.ctx = ctx	if _, err := ctx.RegisterBlock(content.BlockSpec{Name: "minimalplugin:ruby_block"}); err != nil {		return err	}	if _, err := ctx.RegisterItem(content.ItemSpec{Name: "minimalplugin:ruby", MaxCount: 64}); err != nil {		return err	}	unregister, err := ctx.Commands().Register(command.Definition{		Name: "ruby",		Handler: p.giveRuby,	})	if err != nil {		return err	}	p.unregister = unregister	return nil}func (p *Plugin) Start(context.Context) error { return nil }func (p *Plugin) Stop(context.Context) error {	if p.unregister != nil {		p.unregister()	}	return nil}func (p *Plugin) giveRuby(ctx context.Context, exec command.Execution) (command.Result, error) {	_, err := p.ctx.Gameplay().GiveItem(gameplay.InventoryGiveRequest{		PlayerID: player.ID(exec.Source.PlayerID),		Stack: item.Stack{			Item: item.State{Name: "minimalplugin:ruby"},			Count: 1,		},	})	if err != nil {		return command.Result{}, err	}	return command.Result{Messages: []string{fmt.Sprintf("Gave ruby to %s.", exec.Source.Username)}}, nil}

Give Items Safely

Resolve the player through gameplay handles, build an item stack, then call Inventory().Give. The runtime handles validation and client sync.

give-items.go
playerHandle, ok := ctx.Gameplay().Players().ByName("Steve")if !ok {	return fmt.Errorf("player not found")}target, ok := ctx.Gameplay().Players().Resolve("Steve") // ID, name, XUID, or UUID_ = target_ = ok_, err := playerHandle.Inventory().Give(item.New("diamond_sword").	Enchant(item.Sharpness(5)).	NameTag("Arena Blade").	Stack())worldHandle, ok := ctx.Gameplay().Worlds().ByName("Hub")if !ok {	return fmt.Errorf("world not found")}container := worldHandle.ContainerAt(world.Pos{X: 10, Y: 64, Z: 10}, 27)_, err = container.Give(item.New("diamond").Count(8).Stack())

Register Custom Content

Use content builders when a custom block or item has runtime hooks, drops, container metadata, or Bedrock components.

content.go
ctx.RegisterBlock(content.DefineBlock("example:crate").	Container(27).	Hardness(4).	Tool("axe").	Drop(item.New("example:ruby").Stack()).	OnInteract(func(event content.BlockContext) error {		return nil	}).	Spec())ctx.RegisterItem(content.DefineItem("example:wand").	MaxCount(1).	Component("minecraft:foil", true).	OnUseOnBlock(func(event content.ItemContext) error {		return event.World.SetBlock(event.Pos, block.New("gold_block").Block())	}).	Spec())ctx.RegisterEffect(content.DefineEffect("example:focus").	BedrockID(200).	Spec())