Gameplay API
Плагинный gameplay API для игроков, предметов, инвентарей, эффектов, блоков, миров и сущностей.
В этом разделе
Другие страницы раздела:
Точки входа
Эта страница описывает API gameplay для плагинов: игроков, предметов, инвентарей, эффектов, блоков, миров и сущностей. Для мутаций используйте ctx.Gameplay() и серверные сервисы.
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-методы для операций.
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_ = worldHandleIdentity, Position, World, Session, Network возвращают snapshot или handle. Изменение сырых объектов напрямую не всегда синхронизируется с клиентом.
Инвентарь и предметы
Собирайте предметы через core/item. Для мутаций инвентаря используйте PlayerHandle.Inventory(), для алиасов и кулдаунов — ctx.Items().
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_ = snapshoterr := 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.
_, 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(...)).
_, err := ctx.RegisterEffect(content.DefineEffect("practice:focus"). BedrockID(200). Spec())Эффекты применяются и снимаются как для игроков, так и для сущностей.
Миры и блоки
Через WorldHandle выполняются операции чтения/записи блоков и world-effects.
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_ = existsplaced, 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_ = brokenplayers := 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.
_, 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 для интеракций.
_, 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.
_, 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.
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, тип снаряда и обработчик попадания.
_, 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.
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-состояний, формы для структуры взаимодействия с игроком.
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.