bevi-df

module
v0.0.0-...-2a363d4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2025 License: MIT

README

bevi-df

A Bevi plugin that bridges Dragonfly with the Bevi runtime.

  • Fast, typed, cancellable events for most Dragonfly world.Handler and player.Handler callbacks
  • Automatic cancellation bridging: if any ECS system cancels a typed event, the underlying Dragonfly context is cancelled
  • ECS resource for the running Dragonfly server and an ECS component wrapper for players

What you get

  • A Bevi Plugin that:

    • Boots a Dragonfly server in PreStartup
    • Bridges Dragonfly world/player events into a Bevi EventBus
    • Exposes the running server as an ECS resource
    • Tracks connected players, creating an ECS entity per player and emitting join/quit events
  • Typed events for:

    • World: liquid flow/decay/harden, sounds, fire spread, block burn, crop trample, leaves decay, entity spawn/despawn, explosions, world close
    • Player: movement, teleport, change world, toggle sneak/sprint, chat, hunger, heal/hurt/death/respawn, skin change, block break/place/pick, item use/release/consume, attacks, XP gain, punch air, sign edit, lectern page turn, item damage/pickup/drop, held slot change, transfer, command execution, diagnostics, join/quit

Quick start (example server)

Clone this repository and run the example server:

# From the repository root
cd example/server

# Generate Bevi glue (systems registration, queries, access metadata)
go generate ./...

# Run the server
go run .

Connect using a Minecraft Bedrock client to see:

  • New players receive a welcome message; other players get a join broadcast
  • Saying "count" responds with the number of online players
  • Simple profanity filter blocks messages containing a placeholder “badword”
  • Periodic “Players online: N” broadcast every 10s
  • Attempts to break blocks are denied and cancelled

Install in your own module

Add Bevi and Bevi-DF:

go get github.com/oriumgames/bevi@latest
go get github.com/oriumgames/bevi-df@latest

Create an app, add the Dragonfly plugin, and wire your systems:

package main

//go:generate go run github.com/oriumgames/bevi/cmd/gen@latest

import (
	"log/slog"

	"github.com/df-mc/dragonfly/server"
	"github.com/oriumgames/bevi"
	"github.com/oriumgames/bevi-df/dragonfly"
)

func main() {
	cfg, err := server.DefaultConfig().Config(slog.Default())
	if err != nil {
		panic(err)
	}

	bevi.NewApp().
		AddPlugin(dragonfly.NewPlugin(cfg)). // start dragonfly + bridge events
		AddSystems(Systems).                 // generated by the bevi generator
		Run()
}

//bevi:system Update
func HelloOnJoin(r bevi.EventReader[dragonfly.PlayerJoin]) {
	for ev := range r.Iter() {
		ev.Player.Message("Welcome to the server!")
	}
}

Generate and run:

go generate ./...
go run .

How it works

At a glance:

  • The Bevi Plugin boots Dragonfly in the PreStartup stage and wires two handlers:
    • A worldHandler that translates world callbacks into typed Bevi events and cancels Dragonfly when ECS cancels the event
    • A playerHandler doing the same for player callbacks; it also emits internal create/remove notifications
  • A PreUpdate system creates an ECS entity for each newly accepted player, maps it with ecs.Map1[dragonfly.Player], and emits PlayerJoin; it also handles PlayerQuit by removing the entity
  • All user gameplay is modeled as Bevi systems:
    • You consume typed events via bevi.EventReader[T]
    • You can cancel them by calling reader.Cancel()
    • You can also emit your own events with bevi.EventWriter[T]
  • The Bevi scheduler runs systems in ordered, parallelizable batches and advances the event bus frame-by-frame

Cancellation bridging:

  • Many Dragonfly callbacks accept a *Context that can be cancelled to veto an action
  • The bridge emits a typed event and waits: if any ECS system calls Cancel() on the reader during that frame, Bevi marks the event as cancelled
  • The bridge observes cancellation and calls ctx.Cancel() on the Dragonfly side for that callback

Events reference (overview)

Events live under github.com/oriumgames/bevi-df/dragonfly and mirror Dragonfly handlers:

World (cancellable when noted):

  • WorldLiquidFlow, WorldLiquidDecay, WorldLiquidHarden (cancellable)
  • WorldSound (cancellable)
  • WorldFireSpread, WorldBlockBurn, WorldCropTrample, WorldLeavesDecay (cancellable)
  • WorldEntitySpawn, WorldEntityDespawn
  • WorldExplosion (cancellable)
  • WorldClose

Player (cancellable when noted):

  • PlayerMove (cancellable), PlayerJump, PlayerTeleport (cancellable), PlayerChangeWorld
  • PlayerToggleSprint (cancellable), PlayerToggleSneak (cancellable)
  • PlayerChat (cancellable)
  • PlayerFoodLoss (cancellable)
  • PlayerHeal (cancellable), PlayerHurt (cancellable), PlayerDeath, PlayerRespawn
  • PlayerSkinChange (cancellable), PlayerFireExtinguish
  • PlayerStartBreak (cancellable), PlayerBlockBreak (cancellable), PlayerBlockPlace (cancellable), PlayerBlockPick (cancellable)
  • PlayerItemUse (cancellable), PlayerItemUseOnBlock (cancellable), PlayerItemUseOnEntity (cancellable), PlayerItemRelease, PlayerItemConsume (cancellable)
  • PlayerAttackEntity (cancellable), PlayerExperienceGain (cancellable), PlayerPunchAir (cancellable)
  • PlayerSignEdit (cancellable), PlayerLecternPageTurn (cancellable)
  • PlayerItemDamage (cancellable), PlayerItemPickup (cancellable), PlayerItemDrop (cancellable)
  • PlayerHeldSlotChange
  • PlayerTransfer (cancellable), PlayerCommandExecution (cancellable)
  • PlayerDiagnostics
  • PlayerJoin (emitted by the plugin on accept), PlayerQuit

Cancellation:

  • To veto, call reader.Cancel() when iterating a cancellable event type
  • The bridge propagates this to Dragonfly’s *Context for the originating callback

Server resource and player wrapper

Resource:

  • The plugin registers an ECS resource of type dragonfly.Server that wraps Dragonfly’s *server.Server and tracks players

Convenience methods:

  • Player(uuid.UUID) (*dragonfly.Player, bool)
  • PlayerByName(string) (*dragonfly.Player, bool)
  • PlayerByXUID(string) (*dragonfly.Player, bool)

Player component:

  • dragonfly.Player wraps *player.Player and stores its ecs.Entity
  • You can fetch all players via ecs.Query1[dragonfly.Player] or ecs.Filter1[dragonfly.Player]

License

MIT — see license.md.

Directories

Path Synopsis
example
server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL