diff --git a/act/fill.go b/act/fill.go index 6d05299..400e337 100644 --- a/act/fill.go +++ b/act/fill.go @@ -33,14 +33,14 @@ type fillForm struct { } // Submit ... -func (s fillForm) Submit(submitter form.Submitter) { +func (s fillForm) Submit(submitter form.Submitter, tx *world.Tx) { p := submitter.(*player.Player) ph, _ := palette.LookupHandler(p) pal, ok := ph.Palette(s.Palette.Value()) - if !ok || len(pal.Blocks()) == 0 { + if !ok || len(pal.Blocks(tx)) == 0 { p.Message(text.Colourf("%v", msg.InvalidPalette)) return } held, otherHeld := p.HeldItems() - p.SetHeldItems(brush.New(s.s, Fill{b: pal.Blocks()}).Bind(held), otherHeld) + p.SetHeldItems(brush.New(s.s, Fill{b: pal.Blocks(tx)}).Bind(held), otherHeld) } diff --git a/act/replace.go b/act/replace.go index 16b80b7..fe8d099 100644 --- a/act/replace.go +++ b/act/replace.go @@ -44,19 +44,19 @@ type replaceForm struct { } // Submit ... -func (s replaceForm) Submit(submitter form.Submitter) { +func (s replaceForm) Submit(submitter form.Submitter, tx *world.Tx) { p := submitter.(*player.Player) ph, _ := palette.LookupHandler(p) pal, ok := ph.Palette(s.BlockPalette.Value()) - if !ok || len(pal.Blocks()) == 0 { + if !ok || len(pal.Blocks(tx)) == 0 { p.Message(text.Colourf("%v", msg.InvalidPalette)) return } rPal, ok := ph.Palette(s.ReplacedPalette.Value()) - if !ok || len(rPal.Blocks()) == 0 { + if !ok || len(rPal.Blocks(tx)) == 0 { p.Message(text.Colourf("%v", msg.InvalidPalette)) return } held, otherHeld := p.HeldItems() - p.SetHeldItems(brush.New(s.s, Replace{b: pal.Blocks(), old: rPal.Blocks()}).Bind(held), otherHeld) + p.SetHeldItems(brush.New(s.s, Replace{b: pal.Blocks(tx), old: rPal.Blocks(tx)}).Bind(held), otherHeld) } diff --git a/brush/brush.go b/brush/brush.go index 11333e4..7786f4f 100644 --- a/brush/brush.go +++ b/brush/brush.go @@ -39,26 +39,29 @@ func (b Brush) UUID() uuid.UUID { var bb = cube.Box(-0.125, -0.125, -0.125, 0.125, 0.125, 0.125) -func (b Brush) Use(p *player.Player) { +func (b Brush) Use(h *world.EntityHandle) { const ( maxDistance = 128 maxUndoCount = 40 ) - vec := p.Rotation().Vec3().Mul(maxDistance) - pos := p.Position().Add(mgl64.Vec3{0, p.EyeHeight()}) + h.ExecWorld(func(tx *world.Tx, e world.Entity) { + p := e.(*player.Player) + vec := p.Rotation().Vec3().Mul(maxDistance) + pos := p.Position().Add(mgl64.Vec3{0, p.EyeHeight()}) - final := pos.Add(vec) - if res, ok := trace.Perform(pos, final, p.World(), bb, func(w world.Entity) bool { return w == p }); ok { - final = res.Position() - } + final := pos.Add(vec) + if res, ok := trace.Perform(pos, final, tx, bb, nil); ok { + final = res.Position() + } - h, _ := LookupHandler(p) - revert := Perform(cube.PosFromVec3(final), b.s, b.a, p.World()) - if len(h.undo) == maxUndoCount { - h.undo = append(h.undo[1:], revert) - return - } - h.undo = append(h.undo, revert) + h, _ := LookupHandler(p) + revert := Perform(cube.PosFromVec3(final), b.s, b.a, tx.World()) + if len(h.undo) == maxUndoCount { + h.undo = append(h.undo[1:], revert) + return + } + h.undo = append(h.undo, revert) + }) } // Bind binds the Brush to the item.Stack i passed and returns a new item.Stack with the Brush bound to it. diff --git a/brush/cmd.go b/brush/cmd.go index a67b1fe..2e7a5c9 100644 --- a/brush/cmd.go +++ b/brush/cmd.go @@ -3,6 +3,7 @@ package brush import ( "github.com/df-mc/dragonfly/server/cmd" "github.com/df-mc/dragonfly/server/player" + "github.com/df-mc/dragonfly/server/world" "github.com/df-mc/we/internal/msg" "github.com/sandertv/gophertunnel/minecraft/text" ) @@ -14,7 +15,7 @@ type BindCommand struct { } // Run implements the binding of a Brush to the held item by sending a brush selection form. -func (BindCommand) Run(src cmd.Source, o *cmd.Output) { +func (BindCommand) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) { p := src.(*player.Player) held, _ := p.HeldItems() @@ -37,7 +38,7 @@ type UnbindCommand struct { } // Run implements the unbinding of a Brush bound to the item held. -func (c UnbindCommand) Run(src cmd.Source, o *cmd.Output) { +func (c UnbindCommand) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) { p := src.(*player.Player) held, other := p.HeldItems() @@ -56,7 +57,7 @@ type UndoCommand struct { } // Run implements the undoing of an action performed with a Brush. -func (c UndoCommand) Run(src cmd.Source, o *cmd.Output) { +func (c UndoCommand) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) { p := src.(*player.Player) h, _ := LookupHandler(p) if !h.UndoLatest() { diff --git a/brush/form.go b/brush/form.go index d48781e..5b96d1e 100644 --- a/brush/form.go +++ b/brush/form.go @@ -3,6 +3,7 @@ package brush import ( "github.com/df-mc/dragonfly/server/player" "github.com/df-mc/dragonfly/server/player/form" + "github.com/df-mc/dragonfly/server/world" "github.com/df-mc/we/internal/msg" ) @@ -25,7 +26,7 @@ type SelectionForm struct { } // Submit ... -func (s SelectionForm) Submit(submitter form.Submitter) { +func (s SelectionForm) Submit(submitter form.Submitter, _ *world.Tx) { p := submitter.(*player.Player) shape, action := shapeByName(shapeNames[s.Shape.Value()], int(s.Radius.Value())), actionByName(actionNames[s.Action.Value()]) diff --git a/brush/handler.go b/brush/handler.go index 614dfaf..b318adf 100644 --- a/brush/handler.go +++ b/brush/handler.go @@ -1,7 +1,6 @@ package brush import ( - "github.com/df-mc/dragonfly/server/event" "github.com/df-mc/dragonfly/server/player" "sync" ) @@ -11,7 +10,7 @@ var handlers sync.Map // LookupHandler finds the Handler of a specific player.Player, assuming it is currently online. func LookupHandler(p *player.Player) (*Handler, bool) { - v, _ := handlers.Load(p) + v, _ := handlers.Load(p.Name()) h, ok := v.(*Handler) return h, ok } @@ -19,14 +18,13 @@ func LookupHandler(p *player.Player) (*Handler, bool) { // Handler implements the brushing of players. It enables activation of brushes and stores the data needed to // undo/redo those actions. type Handler struct { - p *player.Player undo []func() } // NewHandler creates a new Handler for the *player.Player passed. func NewHandler(p *player.Player) *Handler { - h := &Handler{p: p} - handlers.Store(p, h) + h := &Handler{} + handlers.Store(p.Name(), h) return h } @@ -42,15 +40,15 @@ func (h *Handler) UndoLatest() bool { } // HandleItemUse activates the brush on a player's item if present. -func (h *Handler) HandleItemUse(ctx *event.Context) { - held, _ := h.p.HeldItems() +func (h *Handler) HandleItemUse(ctx *player.Context) { + held, _ := ctx.Val().HeldItems() if b, ok := find(held); ok { ctx.Cancel() - go b.Use(h.p) + go b.Use(ctx.Val().H()) } } // HandleQuit deletes the Handler from the handlers map. -func (h *Handler) HandleQuit() { - handlers.Delete(h.p) +func (h *Handler) HandleQuit(p *player.Player) { + handlers.Delete(p.Name()) } diff --git a/brush/perform.go b/brush/perform.go index 6d269e3..9b3451c 100644 --- a/brush/perform.go +++ b/brush/perform.go @@ -15,7 +15,9 @@ func Perform(pos cube.Pos, s Shape, a Action, w *world.World) (revert func()) { // The shapes measure according to a centre position, so the base of our structure is offset. base := pos.Add(cube.Pos{-d[0] / 2, -d[1] / 2, -d[2] / 2}) st := &structure{base: base, s: s, a: a, d: d, w: w, cx: pos[0], cy: pos[1], cz: pos[2], m: make(map[cube.Pos]world.Block), r: rand.New(rand.NewSource(time.Now().UnixNano()))} - w.BuildStructure(base, st) + w.Exec(func(tx *world.Tx) { + tx.BuildStructure(base, st) + }) return st.Revert } @@ -64,7 +66,9 @@ func (s *structure) blockAt(x, y, z int) world.Block { // Revert reverts the placement of the structure, placing back all blocks that were changed by the initial // placement. func (s *structure) Revert() { - s.w.BuildStructure(s.base, &structureRevert{d: s.d, m: s.m}) + s.w.Exec(func(tx *world.Tx) { + tx.BuildStructure(s.base, &structureRevert{d: s.d, m: s.m}) + }) } // structureRevert represents a structure that handles the reverting of a normal structure. diff --git a/go.mod b/go.mod index e62d504..2aba873 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,12 @@ module github.com/df-mc/we -go 1.16 +go 1.23 + +toolchain go1.23.4 require ( - github.com/df-mc/dragonfly v0.8.7-0.20221114015915-8da5b55600ab - github.com/go-gl/mathgl v1.0.0 - github.com/google/uuid v1.3.0 - github.com/sandertv/gophertunnel v1.25.0 -) + github.com/df-mc/dragonfly v0.10.1 + github.com/go-gl/mathgl v1.2.0 + github.com/google/uuid v1.6.0 + github.com/sandertv/gophertunnel v1.43.1 +) \ No newline at end of file diff --git a/go.sum b/go.sum index 594e669..343c4ae 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,7 @@ github.com/df-mc/atomic v1.10.0 h1:0ZuxBKwR/hxcFGorKiHIp+hY7hgY+XBTzhCYD2NqSEg= github.com/df-mc/atomic v1.10.0/go.mod h1:Gw9rf+rPIbydMjA329Jn4yjd/O2c/qusw3iNp4tFGSc= github.com/df-mc/dragonfly v0.8.7-0.20221114015915-8da5b55600ab h1:Ds8T76rCcoyYqqurhBQQqiBcnJF7meLHRygaOQkL9gE= github.com/df-mc/dragonfly v0.8.7-0.20221114015915-8da5b55600ab/go.mod h1:3/1Ji5EBWu7Af4M/iI45xhFSsyqK0s+hq7d6V3SUGUo= +github.com/df-mc/dragonfly v0.10.1/go.mod h1:dC7UmEAMcKU4tcVsDiF/VzxS2wyfOZIRYT7LZFyzP5c= github.com/df-mc/goleveldb v1.1.9/go.mod h1:+NHCup03Sci5q84APIA21z3iPZCuk6m6ABtg4nANCSk= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -63,6 +64,7 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/mathgl v1.0.0 h1:t9DznWJlXxxjeeKLIdovCOVJQk/GzDEL7h/h+Ro2B68= github.com/go-gl/mathgl v1.0.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ= +github.com/go-gl/mathgl v1.2.0/go.mod h1:pf9+b5J3LFP7iZ4XXaVzZrCle0Q/vNpB/vDe5+3ulRE= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -117,6 +119,7 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -146,6 +149,7 @@ github.com/sandertv/go-raknet v1.12.0 h1:olUzZlIJyX/pgj/mrsLCZYjKLNDsYiWdvQ4NIm3 github.com/sandertv/go-raknet v1.12.0/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y= github.com/sandertv/gophertunnel v1.25.0 h1:XvHDhYtfn2B3TgCl2KqzD0Ifhefb7L7jIH/EUndEBXw= github.com/sandertv/gophertunnel v1.25.0/go.mod h1:dYFetA6r62huhc1EgR9p8VFAFtKOuGgVE/iXf5CzZ4o= +github.com/sandertv/gophertunnel v1.43.1/go.mod h1:XuEJo+ARim+NKiD90Z56sQRcDtCOErz26e2bt3LEd9I= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= diff --git a/handler.go b/handler.go index ab72e66..1be1cfe 100644 --- a/handler.go +++ b/handler.go @@ -2,7 +2,6 @@ package we import ( "github.com/df-mc/dragonfly/server/block/cube" - "github.com/df-mc/dragonfly/server/event" "github.com/df-mc/dragonfly/server/item" "github.com/df-mc/dragonfly/server/player" _ "github.com/df-mc/we/act" @@ -21,19 +20,19 @@ func NewHandler(p *player.Player) *Handler { return &Handler{ph: palette.NewHandler(p), bh: brush.NewHandler(p)} } -func (h *Handler) HandleItemUse(ctx *event.Context) { +func (h *Handler) HandleItemUse(ctx *player.Context) { h.bh.HandleItemUse(ctx) } -func (h *Handler) HandleItemUseOnBlock(ctx *event.Context, pos cube.Pos, face cube.Face, vec mgl64.Vec3) { +func (h *Handler) HandleItemUseOnBlock(ctx *player.Context, pos cube.Pos, face cube.Face, vec mgl64.Vec3) { h.ph.HandleItemUseOnBlock(ctx, pos, face, vec) } -func (h *Handler) HandleBlockBreak(ctx *event.Context, pos cube.Pos, drops *[]item.Stack) { - h.ph.HandleBlockBreak(ctx, pos, drops) +func (h *Handler) HandleBlockBreak(ctx *player.Context, pos cube.Pos, drops *[]item.Stack, xp *int) { + h.ph.HandleBlockBreak(ctx, pos, drops, xp) } -func (h *Handler) HandleQuit() { - h.bh.HandleQuit() - h.ph.HandleQuit() +func (h *Handler) HandleQuit(p *player.Player) { + h.bh.HandleQuit(p) + h.ph.HandleQuit(p) } diff --git a/palette/blocks.go b/palette/blocks.go index 979a06d..ba29667 100644 --- a/palette/blocks.go +++ b/palette/blocks.go @@ -29,6 +29,6 @@ func (b Blocks) Write(w io.Writer) error { } // Blocks returns all world.Block passed to the NewBlocks function upon creation of the palette. -func (b Blocks) Blocks() []world.Block { +func (b Blocks) Blocks(_ *world.Tx) []world.Block { return b.b } diff --git a/palette/cmd.go b/palette/cmd.go index 4bf7e88..e3104b3 100644 --- a/palette/cmd.go +++ b/palette/cmd.go @@ -3,6 +3,7 @@ package palette import ( "github.com/df-mc/dragonfly/server/cmd" "github.com/df-mc/dragonfly/server/player" + "github.com/df-mc/dragonfly/server/world" "github.com/df-mc/we/internal/msg" "github.com/sandertv/gophertunnel/minecraft/text" ) @@ -15,10 +16,11 @@ type SetCommand struct { } // Run enables palette selection for the *player.Player that runs the command. -func (c SetCommand) Run(src cmd.Source, o *cmd.Output) { +func (c SetCommand) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) { p := src.(*player.Player) h, _ := LookupHandler(p) + h.selecting = 2 o.Printf(text.Colourf("%v", msg.StartPaletteSelection)) } @@ -34,7 +36,7 @@ type SaveCommand struct { // Run allows a *player.Player to save the Selection previously created using /palette to disk with a specific name, // so that it can be re-used. -func (s SaveCommand) Run(src cmd.Source, o *cmd.Output) { +func (s SaveCommand) Run(src cmd.Source, o *cmd.Output, tx *world.Tx) { p := src.(*player.Player) h, _ := LookupHandler(p) @@ -48,7 +50,7 @@ func (s SaveCommand) Run(src cmd.Source, o *cmd.Output) { o.Errorf(msg.NoPaletteSelected) return } - h.palettes.Store(s.Name, NewBlocks(h.m.Blocks())) + h.palettes.Store(s.Name, NewBlocks(h.m.Blocks(tx))) o.Printf(text.Colourf("%v", msg.PaletteSaved), h.m.Min, h.m.Max, s.Name) } @@ -62,7 +64,7 @@ type DeleteCommand struct { } // Run allows a *player.Player to delete a palette previously saved using /palette save. -func (d DeleteCommand) Run(src cmd.Source, o *cmd.Output) { +func (d DeleteCommand) Run(src cmd.Source, o *cmd.Output, _ *world.Tx) { p := src.(*player.Player) name := string(d.Name) diff --git a/palette/handler.go b/palette/handler.go index 12a3aee..97719ac 100644 --- a/palette/handler.go +++ b/palette/handler.go @@ -3,7 +3,6 @@ package palette import ( "fmt" "github.com/df-mc/dragonfly/server/block/cube" - "github.com/df-mc/dragonfly/server/event" "github.com/df-mc/dragonfly/server/item" "github.com/df-mc/dragonfly/server/player" "github.com/df-mc/we/internal/msg" @@ -18,14 +17,13 @@ var handlers sync.Map // LookupHandler finds the Handler of a specific player.Player, assuming it is currently online. func LookupHandler(p *player.Player) (*Handler, bool) { - v, _ := handlers.Load(p) + v, _ := handlers.Load(p.Name()) h, ok := v.(*Handler) return h, ok } // Handler handles the selection and storage of palettes during the session of a player. type Handler struct { - p *player.Player close chan struct{} palettes sync.Map @@ -37,9 +35,9 @@ type Handler struct { // NewHandler creates a Handler for the *player.Player passed. func NewHandler(p *player.Player) *Handler { - h := &Handler{p: p, close: make(chan struct{})} + h := &Handler{close: make(chan struct{})} go h.visualisePalette() - handlers.Store(p, h) + handlers.Store(p.Name(), h) return h } @@ -59,25 +57,25 @@ func (h *Handler) Palette(name string) (Palette, bool) { } // HandleItemUseOnBlock handles selection of a block for the palette. -func (h *Handler) HandleItemUseOnBlock(ctx *event.Context, pos cube.Pos, _ cube.Face, _ mgl64.Vec3) { +func (h *Handler) HandleItemUseOnBlock(ctx *player.Context, pos cube.Pos, _ cube.Face, _ mgl64.Vec3) { h.handleSelection(ctx, pos) } // HandleBlockBreak handles selection of a block for the palette. -func (h *Handler) HandleBlockBreak(ctx *event.Context, pos cube.Pos, _ *[]item.Stack) { +func (h *Handler) HandleBlockBreak(ctx *player.Context, pos cube.Pos, _ *[]item.Stack, _ *int) { h.handleSelection(ctx, pos) } // HandleQuit deletes the Handler from the handlers map. -func (h *Handler) HandleQuit() { +func (h *Handler) HandleQuit(p *player.Player) { close(h.close) - handlers.Delete(h.p) + handlers.Delete(p.Name()) } // handleSelection handles the selection of a point for a palette. If no palette is currently being selected, // handleSelection returns immediately. If the second point was selected, the palette is finalised and // stored with the name "M". -func (h *Handler) handleSelection(ctx *event.Context, pos cube.Pos) { +func (h *Handler) handleSelection(ctx *player.Context, pos cube.Pos) { if h.selecting == 0 { // Not currently selecting, return immediately. return @@ -88,13 +86,13 @@ func (h *Handler) handleSelection(ctx *event.Context, pos cube.Pos) { if h.selecting == 1 { // Selecting the first point: Store it in the handler and return. h.first = pos - h.p.Message(fmt.Sprintf(msg.FirstPointSelected, pos)) + ctx.Val().Message(fmt.Sprintf(msg.FirstPointSelected, pos)) return } // First point was selected, we now have a second point so we can create a palette. - h.p.Message(fmt.Sprintf(msg.SecondPointSelected, pos)) - h.m = NewSelection(h.first, pos, h.p.World()) - h.p.Message(text.Colourf(""+msg.PaletteCreated+"", h.m.Min, h.m.Max)) + ctx.Val().Message(fmt.Sprintf(msg.SecondPointSelected, pos)) + h.m = NewSelection(h.first, pos, ctx.Val().Tx().World()) + ctx.Val().Message(text.Colourf(""+msg.PaletteCreated+"", h.m.Min, h.m.Max)) } // visualisePalette continuously visualises the palette through particles in the world. diff --git a/palette/palette.go b/palette/palette.go index 634a47d..fd6ef2f 100644 --- a/palette/palette.go +++ b/palette/palette.go @@ -8,5 +8,5 @@ import ( type Palette interface { // Blocks returns the list of world.Block that should be used as palette for a world edit action. Blocks can // return the same world.Block multiple times to change the occurrence of one block vs another block. - Blocks() []world.Block + Blocks(tx *world.Tx) []world.Block } diff --git a/palette/selection.go b/palette/selection.go index 92c7341..cc0a6da 100644 --- a/palette/selection.go +++ b/palette/selection.go @@ -26,13 +26,13 @@ func (p Selection) Zero() bool { } // Blocks returns all world.Block present between two corners in the world passed to NewSelection upon creation. -func (p Selection) Blocks() []world.Block { +func (p Selection) Blocks(tx *world.Tx) []world.Block { if p.Zero() { return nil } m := make([]world.Block, 0, p.Dx()*p.Dy()*p.Dz()) p.Range(func(x, y, z int) { - m = append(m, p.w.Block(cube.Pos{x, y, z})) + m = append(m, tx.Block(cube.Pos{x, y, z})) }) return m }