Gameplay API

Плагинный gameplay API для игроков, предметов, инвентарей, эффектов, блоков, миров и сущностей.

В этом разделе

Другие страницы раздела:

Точки входа

Эта страница описывает API gameplay для плагинов: игроков, предметов, инвентарей, эффектов, блоков, миров и сущностей. Для мутаций используйте ctx.Gameplay() и серверные сервисы.

entry-points.go
func (p *Plugin) Init(ctx plugin.Context) error {	gameplay := ctx.Gameplay()	players := gameplay.Players()	worlds := gameplay.Worlds()	entities := gameplay.Entities()	_ = players	_ = worlds	_ = entities	return nil}

Игроки

Найдите игрока по ID, имени, XUID или UUID, затем используйте handle-методы для операций.

players.go
playerHandle, ok := ctx.Gameplay().Players().Resolve("Steve")if !ok {	return fmt.Errorf("player not found")}identity, _ := playerHandle.Identity()position, _ := playerHandle.Position()worldHandle, _ := playerHandle.World()sessionHandle, hasSession := playerHandle.Session()err := playerHandle.SendMessage("Welcome")err = playerHandle.SendPopup("Round starting")err = playerHandle.SendTip("3...")err = playerHandle.SendToast("Duel", "Opponent found")err = playerHandle.Teleport(entity.Position{X: 0, Y: 80, Z: 0})err = playerHandle.Transfer("arena-1")err = playerHandle.SetHealth(20)err = playerHandle.SetMaxHealth(20)err = playerHandle.SetGameMode("creative")if hasSession {	protocol := sessionHandle.ProtocolID()	extra := sessionHandle.ExtraData()	_ = protocol	_ = extra}_ = identity_ = position_ = worldHandle

Identity, Position, World, Session, Network возвращают snapshot или handle. Изменение сырых объектов напрямую не всегда синхронизируется с клиентом.

Инвентарь и предметы

Собирайте предметы через core/item. Для мутаций инвентаря используйте PlayerHandle.Inventory(), для алиасов и кулдаунов — ctx.Items().

inventories.go
inventory := playerHandle.Inventory()_, err := inventory.Give(item.New("diamond_sword").	Enchant(item.Sharpness(5)).	NameTag("Arena Blade").	Lore("Bound to the arena").	NBTTag("pulse:owner", "Steve").	Component("minecraft:foil", true).	Stack())_, err = inventory.Take(item.New("diamond").Count(1).Stack())err = inventory.Set(0, item.New("stone").Count(64).Stack())_, err = inventory.Move(0, 1, 16)_, err = inventory.Swap(1, 2)_, err = inventory.ClearSlot(2)err = inventory.SetHeldSlot(1)err = inventory.Resync()held, err := inventory.HeldItem()slot, err := inventory.HeldSlot()snapshot, err := inventory.Snapshot()_ = held_ = slot_ = snapshot
items-cooldown.go
err := ctx.Items().Alias("pearl", "minecraft:ender_pearl")ctx.Items().SetCooldown(playerHandle.ID(), "pearl", 20)if ctx.Items().Ready(playerHandle.ID(), "pearl") {	// allow use}

Эффекты

Эффекты — server-owned и синхронизируются с Bedrock через effect service.

effects.go
_, err := playerHandle.AddEffect(effect.New("speed").	Seconds(30).	Amplifier(1).	Particles(true))active := playerHandle.Effects()_, err = playerHandle.RemoveEffect(effect.EffectSpeed)err = playerHandle.ClearEffects()_ = active

Кастомные эффекты регистрируются в Init через ctx.RegisterEffect(content.DefineEffect(...)).

custom-effect.go
_, err := ctx.RegisterEffect(content.DefineEffect("practice:focus").	BedrockID(200).	Spec())

Эффекты применяются и снимаются как для игроков, так и для сущностей.

Миры и блоки

Через WorldHandle выполняются операции чтения/записи блоков и world-effects.

blocks-worlds.go
worldHandle, ok := ctx.Gameplay().Worlds().ByName("Overworld")if !ok {	return fmt.Errorf("world not found")}pos := world.Pos{X: 10, Y: 64, Z: 10}blockState := block.New("chest").	String("minecraft:cardinal_direction", "north").	Block()current, exists, err := worldHandle.Block(pos)err = worldHandle.SetBlock(pos, blockState)err = worldHandle.UpdateProperties(pos, map[string]any{	"open_bit": true,})_ = current_ = exists
world-activity.go
placed, err := worldHandle.PlaceBlock(playerHandle.ID(), pos, block.New("stone").Block())broken, err := worldHandle.BreakBlock(playerHandle.ID(), pos, item.New("diamond_pickaxe").Stack())err = worldHandle.AddSound(entity.Position{X: 10, Y: 64, Z: 10}, gameplay.SoundEffect{Type: 1})err = worldHandle.AddParticle(entity.Position{X: 10, Y: 64, Z: 10}, gameplay.ParticleEffect{Type: 2001})err = worldHandle.LevelEvent(entity.Position{X: 10, Y: 64, Z: 10}, gameplay.LevelEvent{Type: 2001})_ = placed_ = broken
world-queries.go
players := worldHandle.Players()nearbyPlayers := worldHandle.PlayersNear(entity.Position{X: 0, Y: 64, Z: 0}, 16, 5)nearbyEntities := worldHandle.NearbyEntities(entity.Position{X: 0, Y: 64, Z: 0}, 16, 10)zombies := worldHandle.EntitiesByType("minecraft:zombie")_ = players_ = nearbyPlayers_ = nearbyEntities_ = zombies

Кастомные блоки

Регистрируйте блоки в Init, задавайте поведение через content hooks.

custom-blocks.go
_, err := ctx.RegisterBlock(content.DefineBlock("practice:ruby_block").	Hardness(4).	Tool("pickaxe").	Drop(item.New("practice:ruby").Stack()).	OnPlace(func(event content.BlockContext) error {		if event.Player != nil {			if handle, ok := ctx.Gameplay().Players().Get(event.Player.Identity().ID); ok {				return handle.SendMessage("Placed ruby")			}		}		return nil	}).	OnBreak(func(event content.BlockContext) error {		return nil	}).	OnInteract(func(event content.BlockContext) error {		if event.World == nil {			return nil		}		worldHandle, ok := ctx.Gameplay().Worlds().Get(event.World.ID())		if !ok {			return nil		}		return worldHandle.SetBlock(event.Pos, block.New("gold_block").Block())	}).	Spec())

BlockContext включает player, world, pos, block и item для интеракций.

containers.go
_, err := ctx.RegisterBlock(content.DefineBlock("practice:crate").	Container(27).	Drop(item.New("practice:crate").Stack()).	Spec())container := worldHandle.ContainerAt(pos, 27)_, err := container.Give(item.New("diamond").Count(8).Stack())err = container.OpenFor(playerHandle.ID())err = container.Resync()

Кастомные предметы

Для предметов доступны OnUse, OnUseOnBlock, OnAttack с обработкой ItemContext.

custom-items.go
_, err := ctx.RegisterItem(content.DefineItem("practice:wand").	MaxCount(1).	Component("minecraft:foil", true).	OnUse(func(event content.ItemContext) error {		event.Result.Consume(1)		if event.Player == nil {			return nil		}		playerHandle, ok := ctx.Gameplay().Players().Get(event.Player.Identity().ID)		if !ok {			return nil		}		return playerHandle.SendMessage("Used wand")	}).	OnUseOnBlock(func(event content.ItemContext) error {		if event.World == nil {			return nil		}		worldHandle, ok := ctx.Gameplay().Worlds().Get(event.World.ID())		if !ok {			return nil		}		return worldHandle.SetBlock(event.ClickedBlock, block.New("gold_block").Block())	}).	OnAttack(func(event content.ItemContext) error {		return nil	}).	Spec())

ItemContext хранит player/world/pos/block и изменяемое поле Result.

item-result.go
event.Result.Cancel("not allowed")event.Result.Consume(1)event.Result.Damage(1)event.Result.Replace(item.New("bucket").Stack())event.Result.Return(item.New("glass_bottle").Stack())

Projectile-предметы

Projectile items задают силу броска, cooldown, тип снаряда и обработчик попадания.

projectiles.go
_, err := ctx.RegisterItem(content.DefineProjectileItem("practice:fireball").	MaxCount(16).	Cooldown(20).	ThrowForce(1.5).	Projectile("practice:fireball_projectile").	OnHit(func(event content.ProjectileHitContext) error {		if event.World == nil {			return nil		}		worldHandle, ok := ctx.Gameplay().Worlds().Get(event.World.ID())		if !ok {			return nil		}		return worldHandle.LevelEvent(entity.Position{			X: float64(event.Pos.X),			Y: float64(event.Pos.Y),			Z: float64(event.Pos.Z),		}, gameplay.LevelEvent{Type: 2001})	}).	Spec())

Сущности

Через world handle выполняйте spawn, movement, health, эффекты, урон и despawn.

entities.go
mob, err := worldHandle.SpawnMob(entity.Zombie().	At(12, 65, 10).	Health(20))err = mob.SetNameTag("Target")err = mob.SetProperty("pulse:arena", "duel-1")err = mob.Teleport(entity.Position{X: 20, Y: 65, Z: 20})_, err = mob.Knockback(entity.Position{X: 0, Y: 65, Z: 0}, 0.4, 0.36)err = mob.Damage(2, "practice")err = mob.Despawn()

Scoreboards и формы

Scoreboard для HUD-состояний, формы для структуры взаимодействия с игроком.

scoreboards.go
board := playerHandle.Scoreboard()err := board.Set("Duel", "Map: nodebuff", "Ping: 20ms")err = board.SetTitle("Ranked Duel")err = board.SetLine(1, "Ping: 18ms")err = board.Remove()result, err := playerHandle.SendForm(formRef)err = playerHandle.CloseForms()_ = result

События и хуки

  • Content hooks: OnUse, OnUseOnBlock, OnAttack, OnPlace, OnBreak, OnInteract, и хуки попадания снаряда.
  • Event bus: ctx.On(...), ctx.OnPriority(...), ctx.OnWithOptions(...).
  • Для логики предмета/блока используйте content hooks; для cross-cutting поведения — event bus.

Совместимость

Request-style методы plugin.Gameplay оставлены для старых плагинов и адаптеров.

  • GiveStack
  • SetSlot
  • SetHeldSlot
  • ResyncInventory
  • SetBlockAt
  • PlaceBlock
  • BreakBlock
  • AddPlayerEffect
  • RemoveEffect
  • ClearEffects
  • Teleport
  • SetHealth
  • SetGameMode

Примечания стабильности

  • Handles — это фасады серверных сервисов, а не ссылки на конкретные объекты.
  • Snapshot-методы возвращают клоны данных; изменение клона не меняет состояние сервера.
  • Кастомный контент регистрируйте только в Init.
  • Имена кастомного контента должны быть namespaced.
  • Прямая мутация может обновиться на сервере, но не попасть в Bedrock без server services.