From 7bdc91614e2a1199b6966a2f750b3c04bce77a84 Mon Sep 17 00:00:00 2001 From: RestartFU Date: Sun, 28 Apr 2024 12:02:06 -0400 Subject: [PATCH 01/21] fix staticcheck --- server/item/recipe/vanilla.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/item/recipe/vanilla.go b/server/item/recipe/vanilla.go index af3a9dd07..9c1ae55b6 100644 --- a/server/item/recipe/vanilla.go +++ b/server/item/recipe/vanilla.go @@ -42,7 +42,7 @@ func init() { panic(err) } - for _, s := range append(craftingRecipes.Shapeless) { + for _, s := range craftingRecipes.Shapeless { input, ok := s.Input.Items() output, okTwo := s.Output.Stacks() if !ok || !okTwo { From 2317db53f8692672b8256ba1b63e2661ec6cd601 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 21:47:02 -0400 Subject: [PATCH 02/21] hoppers --- server/block/chest.go | 11 ++ server/block/hash.go | 6 + server/block/hopper.go | 289 +++++++++++++++++++++++++++++++++++++++ server/block/register.go | 2 + server/session/player.go | 2 + server/session/world.go | 2 + 6 files changed, 312 insertions(+) create mode 100644 server/block/hopper.go diff --git a/server/block/chest.go b/server/block/chest.go index db723f75b..7a691b054 100644 --- a/server/block/chest.go +++ b/server/block/chest.go @@ -148,6 +148,17 @@ func (c Chest) FlammabilityInfo() FlammabilityInfo { return newFlammabilityInfo(0, 0, true) } +// ExtractItem ... +func (c Chest) ExtractItem() (item.Stack, int) { + for i, it := range c.inventory.Slots() { + if it.Empty() { + continue + } + return it, i + } + return item.Stack{}, 0 +} + // DecodeNBT ... func (c Chest) DecodeNBT(data map[string]any) any { facing := c.Facing diff --git a/server/block/hash.go b/server/block/hash.go index 66284c6bb..ce27a096a 100644 --- a/server/block/hash.go +++ b/server/block/hash.go @@ -81,6 +81,7 @@ const ( hashGrindstone hashHayBale hashHoneycomb + hashHopper hashInvisibleBedrock hashIron hashIronBars @@ -568,6 +569,11 @@ func (Honeycomb) Hash() uint64 { return hashHoneycomb } +// Hash ... +func (h Hopper) Hash() uint64 { + return hashHopper | uint64(h.Facing)<<8 | uint64(boolByte(h.Powered))<<11 +} + // Hash ... func (InvisibleBedrock) Hash() uint64 { return hashInvisibleBedrock diff --git a/server/block/hopper.go b/server/block/hopper.go new file mode 100644 index 000000000..9f9962694 --- /dev/null +++ b/server/block/hopper.go @@ -0,0 +1,289 @@ +package block + +import ( + "fmt" + "github.com/df-mc/dragonfly/server/block/cube" + "github.com/df-mc/dragonfly/server/block/model" + "github.com/df-mc/dragonfly/server/internal/nbtconv" + "github.com/df-mc/dragonfly/server/item" + "github.com/df-mc/dragonfly/server/item/inventory" + "github.com/df-mc/dragonfly/server/world" + "github.com/go-gl/mathgl/mgl64" + "strings" + "sync" +) + +// Hopper is a low-capacity storage block that can be used to collect item entities directly above it, as well as to +// transfer items into and out of other containers. +// TODO: Functionality! +type Hopper struct { + transparent + sourceWaterDisplacer + + // Facing is the direction the hopper is facing. + Facing cube.Face + // Powered is whether the hopper is powered or not. + Powered bool + // CustomName is the custom name of the hopper. This name is displayed when the hopper is opened, and may include + // colour codes. + CustomName string + + // LastTick is the last world tick that the hopper was ticked. + LastTick int64 + // TransferCooldown is the duration until the hopper can transfer items again. + TransferCooldown int64 + + inventory *inventory.Inventory + viewerMu *sync.RWMutex + viewers map[ContainerViewer]struct{} +} + +// NewHopper creates a new initialised hopper. The inventory is properly initialised. +func NewHopper() Hopper { + m := new(sync.RWMutex) + v := make(map[ContainerViewer]struct{}, 1) + return Hopper{ + inventory: inventory.New(5, func(slot int, _, item item.Stack) { + m.RLock() + defer m.RUnlock() + for viewer := range v { + viewer.ViewSlotChange(slot, item) + } + }), + viewerMu: m, + viewers: v, + } +} + +// Model ... +func (Hopper) Model() world.BlockModel { + // TODO: Implement me. + return model.Solid{} +} + +// SideClosed ... +func (Hopper) SideClosed(cube.Pos, cube.Pos, *world.World) bool { + return false +} + +// BreakInfo ... +func (h Hopper) BreakInfo() BreakInfo { + return newBreakInfo(3, pickaxeHarvestable, pickaxeEffective, oneOf(h)) +} + +// Inventory returns the inventory of the hopper. +func (h Hopper) Inventory() *inventory.Inventory { + return h.inventory +} + +// WithName returns the hopper after applying a specific name to the block. +func (h Hopper) WithName(a ...any) world.Item { + h.CustomName = strings.TrimSuffix(fmt.Sprintln(a...), "\n") + return h +} + +// AddViewer adds a viewer to the hopper, so that it is updated whenever the inventory of the hopper is changed. +func (h Hopper) AddViewer(v ContainerViewer, _ *world.World, _ cube.Pos) { + h.viewerMu.Lock() + defer h.viewerMu.Unlock() + h.viewers[v] = struct{}{} +} + +// RemoveViewer removes a viewer from the hopper, so that slot updates in the inventory are no longer sent to it. +func (h Hopper) RemoveViewer(v ContainerViewer, _ *world.World, _ cube.Pos) { + h.viewerMu.Lock() + defer h.viewerMu.Unlock() + delete(h.viewers, v) +} + +// Activate ... +func (Hopper) Activate(pos cube.Pos, _ cube.Face, _ *world.World, u item.User, _ *item.UseContext) bool { + if opener, ok := u.(ContainerOpener); ok { + opener.OpenBlockContainer(pos) + return true + } + return false +} + +// UseOnBlock ... +func (h Hopper) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) bool { + pos, _, used := firstReplaceable(w, pos, face, h) + if !used { + return false + } + + //noinspection GoAssignmentToReceiver + h = NewHopper() + h.Facing = cube.FaceDown + if h.Facing != face { + h.Facing = face.Opposite() + } + + place(w, pos, h, user, ctx) + return placed(ctx) +} + +// Tick ... +func (h Hopper) Tick(currentTick int64, pos cube.Pos, w *world.World) { + h.TransferCooldown-- + h.LastTick = currentTick + if !h.Powered { + h.extractItemEntity(pos, w) + } + if h.TransferCooldown > 0 { + w.SetBlock(pos, h, nil) + return + } + + h.TransferCooldown = 0 + if h.Powered { + w.SetBlock(pos, h, nil) + return + } + + inserted := h.insertItem(pos, w) + extracted := h.extractItem(pos, w) + if inserted || extracted { + h.TransferCooldown = 8 + w.SetBlock(pos, h, nil) + } +} + +// insertItem ... +func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { + // TODO + return false +} + +// HopperExtractable represents a block that can have its contents extracted by a hopper. +type HopperExtractable interface { + Container + + // ExtractItem attempts to extract a single item from the container. If the extraction was successful, the item is + // returned. If the extraction was unsuccessful, the item stack returned will be empty. ExtractItem by itself does + // should not remove the item from the container, but instead return the item that would be removed. + ExtractItem() (item.Stack, int) +} + +// extractItem ... +func (h Hopper) extractItem(pos cube.Pos, w *world.World) bool { + origin, ok := w.Block(pos.Side(cube.FaceUp)).(Container) + if !ok { + return false + } + + var ( + targetSlot int + targetStack item.Stack + ) + if e, ok := origin.(HopperExtractable); !ok { + for slot, stack := range origin.Inventory().Items() { + if stack.Empty() { + continue + } + targetStack, targetSlot = stack, slot + break + } + } else { + targetStack, targetSlot = e.ExtractItem() + } + if targetStack.Empty() { + // We don't have any items to extract. + return false + } + + _, err := h.inventory.AddItem(targetStack.Grow(-targetStack.Count() + 1)) + if err != nil { + // The hopper is full. + return false + } + _ = origin.Inventory().SetItem(targetSlot, targetStack.Grow(-1)) + return true +} + +// itemEntity ... +type itemEntity interface { + world.Entity + + Item() item.Stack + SetItem(item.Stack) +} + +// extractItemEntity ... +func (h Hopper) extractItemEntity(pos cube.Pos, w *world.World) { + for _, e := range w.EntitiesWithin(cube.Box(0, 1, 0, 1, 2, 1).Translate(pos.Vec3()), func(entity world.Entity) bool { + _, ok := entity.(itemEntity) + return !ok + }) { + i := e.(itemEntity) + + stack := i.Item() + count, _ := h.inventory.AddItem(stack) + if count == 0 { + // We couldn't add any of the item to the inventory, so we continue to the next item entity. + continue + } + + if stack = stack.Grow(-count); stack.Empty() { + _ = i.Close() + return + } + i.SetItem(stack) + return + } +} + +// EncodeItem ... +func (Hopper) EncodeItem() (name string, meta int16) { + return "minecraft:hopper", 0 +} + +// EncodeBlock ... +func (h Hopper) EncodeBlock() (string, map[string]any) { + return "minecraft:hopper", map[string]any{ + "facing_direction": int32(h.Facing), + "toggle_bit": h.Powered, + } +} + +// EncodeNBT ... +func (h Hopper) EncodeNBT() map[string]any { + if h.inventory == nil { + facing, powered, customName := h.Facing, h.Powered, h.CustomName + //noinspection GoAssignmentToReceiver + h = NewHopper() + h.Facing, h.Powered, h.CustomName = facing, powered, customName + } + m := map[string]any{ + "Items": nbtconv.InvToNBT(h.inventory), + "TransferCooldown": int32(h.TransferCooldown), + "id": "Hopper", + } + if h.CustomName != "" { + m["CustomName"] = h.CustomName + } + return m +} + +// DecodeNBT ... +func (h Hopper) DecodeNBT(data map[string]any) any { + facing, powered := h.Facing, h.Powered + //noinspection GoAssignmentToReceiver + h = NewHopper() + h.Facing = facing + h.Powered = powered + h.CustomName = nbtconv.String(data, "CustomName") + h.TransferCooldown = int64(nbtconv.Int32(data, "TransferCooldown")) + nbtconv.InvFromNBT(h.inventory, nbtconv.Slice[any](data, "Items")) + return h +} + +// allHoppers ... +func allHoppers() (hoppers []world.Block) { + for _, f := range cube.Faces() { + for _, p := range []bool{false, true} { + hoppers = append(hoppers, Hopper{Facing: f, Powered: p}) + } + } + return hoppers +} diff --git a/server/block/register.go b/server/block/register.go index 36b89fa5d..91257038a 100644 --- a/server/block/register.go +++ b/server/block/register.go @@ -147,6 +147,7 @@ func init() { registerAll(allGlazedTerracotta()) registerAll(allGrindstones()) registerAll(allHayBales()) + registerAll(allHoppers()) registerAll(allItemFrames()) registerAll(allKelp()) registerAll(allLadders()) @@ -257,6 +258,7 @@ func init() { world.RegisterItem(Grindstone{}) world.RegisterItem(HayBale{}) world.RegisterItem(Honeycomb{}) + world.RegisterItem(Hopper{}) world.RegisterItem(InvisibleBedrock{}) world.RegisterItem(IronBars{}) world.RegisterItem(Iron{}) diff --git a/server/session/player.go b/server/session/player.go index 0552af589..9abcb62a6 100644 --- a/server/session/player.go +++ b/server/session/player.go @@ -233,6 +233,8 @@ func (s *Session) invByID(id int32) (*inventory.Inventory, bool) { return s.openedWindow.Load(), true } else if _, enderChest := b.(block.EnderChest); enderChest { return s.openedWindow.Load(), true + } else if _, hopper := b.(block.Hopper); hopper { + return s.openedWindow.Load(), true } } case protocol.ContainerBarrel: diff --git a/server/session/world.go b/server/session/world.go index 18d9deab5..897c3554f 100644 --- a/server/session/world.go +++ b/server/session/world.go @@ -1017,6 +1017,8 @@ func (s *Session) openNormalContainer(b block.Container, pos cube.Pos) { containerType = protocol.ContainerTypeBlastFurnace case block.Smoker: containerType = protocol.ContainerTypeSmoker + case block.Hopper: + containerType = protocol.ContainerTypeHopper } s.writePacket(&packet.ContainerOpen{ From 16e66729677d72d759a8124e938dabaf794d586f Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 22:12:25 -0400 Subject: [PATCH 03/21] insert item --- server/block/chest.go | 11 ----------- server/block/hopper.go | 45 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/server/block/chest.go b/server/block/chest.go index 7a691b054..db723f75b 100644 --- a/server/block/chest.go +++ b/server/block/chest.go @@ -148,17 +148,6 @@ func (c Chest) FlammabilityInfo() FlammabilityInfo { return newFlammabilityInfo(0, 0, true) } -// ExtractItem ... -func (c Chest) ExtractItem() (item.Stack, int) { - for i, it := range c.inventory.Slots() { - if it.Empty() { - continue - } - return it, i - } - return item.Stack{}, 0 -} - // DecodeNBT ... func (c Chest) DecodeNBT(data map[string]any) any { facing := c.Facing diff --git a/server/block/hopper.go b/server/block/hopper.go index 9f9962694..69ea11a1d 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -149,10 +149,51 @@ func (h Hopper) Tick(currentTick int64, pos cube.Pos, w *world.World) { } } +// HopperInsertable represents a block that can have its contents inserted into by a hopper. +type HopperInsertable interface { + Container + + // InsertItem attempts to insert a single item into the container. If the insertion was successful, the item is + // returned. If the insertion was unsuccessful, the item stack returned will be empty. InsertItem by itself does + // should not add the item to the container, but instead return the item that would be added. + InsertItem(item.Stack) (item.Stack, int) +} + // insertItem ... func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { - // TODO - return false + dest, ok := w.Block(pos.Side(h.Facing)).(Container) + if !ok { + return false + } + + var ( + sourceSlot int + sourceStack item.Stack + + //targetStack item.Stack + //targetSlot int + ) + + for slot, stack := range h.inventory.Slots() { + if stack.Empty() { + continue + } + sourceStack, sourceSlot = stack, slot + break + } + + if sourceStack.Empty() { + // We don't have any items to insert. + return false + } + + _, err := dest.Inventory().AddItem(sourceStack.Grow(-sourceStack.Count() + 1)) + if err != nil { + // The destination is full. + return false + } + _ = h.inventory.SetItem(sourceSlot, sourceStack.Grow(-1)) + return true } // HopperExtractable represents a block that can have its contents extracted by a hopper. From 3eb264e8b4d80c7994d17144a6911462f73bf957 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 22:24:00 -0400 Subject: [PATCH 04/21] Update hopper.go --- server/block/hopper.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index 69ea11a1d..ff2201c3a 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -169,15 +169,13 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { var ( sourceSlot int sourceStack item.Stack - - //targetStack item.Stack - //targetSlot int ) - for slot, stack := range h.inventory.Slots() { + for slot, stack := range h.inventory.Items() { if stack.Empty() { continue } + fmt.Println(stack, slot) sourceStack, sourceSlot = stack, slot break } @@ -187,11 +185,21 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { return false } - _, err := dest.Inventory().AddItem(sourceStack.Grow(-sourceStack.Count() + 1)) - if err != nil { - // The destination is full. - return false + if e, ok := dest.(HopperInsertable); !ok { + _, err := dest.Inventory().AddItem(sourceStack) + if err != nil { + // The destination is full. + return false + } + } else { + targetStack, targetSlot := e.InsertItem(sourceStack) + if targetStack.Empty() { + // The destination is full. + return false + } + _ = dest.Inventory().SetItem(targetSlot, targetStack) } + _ = h.inventory.SetItem(sourceSlot, sourceStack.Grow(-1)) return true } From d12a505ce46117502d4c6b4ed8d5d71b0ff2556d Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 22:28:21 -0400 Subject: [PATCH 05/21] Update hopper.go --- server/block/hopper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index ff2201c3a..28391c5fe 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -171,7 +171,7 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { sourceStack item.Stack ) - for slot, stack := range h.inventory.Items() { + for slot, stack := range h.inventory.Slots() { if stack.Empty() { continue } From 36909150c9a2a902f1633b47b085925cec53b83e Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 22:32:06 -0400 Subject: [PATCH 06/21] Update hopper.go --- server/block/hopper.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index 28391c5fe..414856832 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -175,7 +175,6 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { if stack.Empty() { continue } - fmt.Println(stack, slot) sourceStack, sourceSlot = stack, slot break } @@ -226,7 +225,7 @@ func (h Hopper) extractItem(pos cube.Pos, w *world.World) bool { targetStack item.Stack ) if e, ok := origin.(HopperExtractable); !ok { - for slot, stack := range origin.Inventory().Items() { + for slot, stack := range origin.Inventory().Slots() { if stack.Empty() { continue } From 6f4a481a8e27b4a960f0fe873d3c3573bd962af9 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 23:21:04 -0400 Subject: [PATCH 07/21] Update item_behaviour.go --- server/entity/item_behaviour.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/entity/item_behaviour.go b/server/entity/item_behaviour.go index 61de607d1..c7641509a 100644 --- a/server/entity/item_behaviour.go +++ b/server/entity/item_behaviour.go @@ -57,6 +57,11 @@ type ItemBehaviour struct { pickupDelay time.Duration } +// SetItem sets the item stack held by the entity to i. +func (i *ItemBehaviour) SetItem(stack item.Stack) { + i.i = stack +} + // Item returns the item.Stack held by the entity. func (i *ItemBehaviour) Item() item.Stack { return i.i From 23c72823cf4768316684c2f4c263fa4f6ecc5324 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 23:43:58 -0400 Subject: [PATCH 08/21] add entity items into hoppers --- server/entity/item_behaviour.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/server/entity/item_behaviour.go b/server/entity/item_behaviour.go index c7641509a..5c9509a04 100644 --- a/server/entity/item_behaviour.go +++ b/server/entity/item_behaviour.go @@ -1,6 +1,8 @@ package entity import ( + "github.com/df-mc/dragonfly/server/block" + "github.com/df-mc/dragonfly/server/block/cube" "github.com/df-mc/dragonfly/server/internal/nbtconv" "github.com/df-mc/dragonfly/server/item" "github.com/df-mc/dragonfly/server/world" @@ -57,11 +59,6 @@ type ItemBehaviour struct { pickupDelay time.Duration } -// SetItem sets the item stack held by the entity to i. -func (i *ItemBehaviour) SetItem(stack item.Stack) { - i.i = stack -} - // Item returns the item.Stack held by the entity. func (i *ItemBehaviour) Item() item.Stack { return i.i @@ -70,6 +67,22 @@ func (i *ItemBehaviour) Item() item.Stack { // Tick moves the entity, checks if it should be picked up by a nearby collector // or if it should merge with nearby item entities. func (i *ItemBehaviour) Tick(e *Ent) *Movement { + w := e.World() + pos := cube.PosFromVec3(e.Position()) + + bl, ok := w.Block(pos.Side(cube.FaceDown)).(block.Hopper) + if ok && !bl.Powered { + _, err := bl.Inventory().AddItem(i.i.Grow(-i.i.Count() + 1)) + if err != nil { + // We couldn't add any of the item to the inventory, so we continue to the next item entity. + return i.passive.Tick(e) + } + + if i.i = i.i.Grow(-1); i.i.Empty() { + _ = e.Close() + return nil + } + } return i.passive.Tick(e) } From 3949ec6b73c3965baeff20944013a58b0505bfa8 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 23:44:04 -0400 Subject: [PATCH 09/21] Update hopper.go --- server/block/hopper.go | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index 414856832..8c1ea86dd 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -127,9 +127,6 @@ func (h Hopper) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world. func (h Hopper) Tick(currentTick int64, pos cube.Pos, w *world.World) { h.TransferCooldown-- h.LastTick = currentTick - if !h.Powered { - h.extractItemEntity(pos, w) - } if h.TransferCooldown > 0 { w.SetBlock(pos, h, nil) return @@ -185,7 +182,7 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { } if e, ok := dest.(HopperInsertable); !ok { - _, err := dest.Inventory().AddItem(sourceStack) + _, err := dest.Inventory().AddItem(sourceStack.Grow(-sourceStack.Count() + 1)) if err != nil { // The destination is full. return false @@ -249,38 +246,6 @@ func (h Hopper) extractItem(pos cube.Pos, w *world.World) bool { return true } -// itemEntity ... -type itemEntity interface { - world.Entity - - Item() item.Stack - SetItem(item.Stack) -} - -// extractItemEntity ... -func (h Hopper) extractItemEntity(pos cube.Pos, w *world.World) { - for _, e := range w.EntitiesWithin(cube.Box(0, 1, 0, 1, 2, 1).Translate(pos.Vec3()), func(entity world.Entity) bool { - _, ok := entity.(itemEntity) - return !ok - }) { - i := e.(itemEntity) - - stack := i.Item() - count, _ := h.inventory.AddItem(stack) - if count == 0 { - // We couldn't add any of the item to the inventory, so we continue to the next item entity. - continue - } - - if stack = stack.Grow(-count); stack.Empty() { - _ = i.Close() - return - } - i.SetItem(stack) - return - } -} - // EncodeItem ... func (Hopper) EncodeItem() (name string, meta int16) { return "minecraft:hopper", 0 From 9d698d7f1cab63fbaf7f7874b8d20cb541b0a2b7 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 28 May 2024 23:44:47 -0400 Subject: [PATCH 10/21] Update item_behaviour.go --- server/entity/item_behaviour.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/entity/item_behaviour.go b/server/entity/item_behaviour.go index 5c9509a04..30b8ca54c 100644 --- a/server/entity/item_behaviour.go +++ b/server/entity/item_behaviour.go @@ -74,7 +74,7 @@ func (i *ItemBehaviour) Tick(e *Ent) *Movement { if ok && !bl.Powered { _, err := bl.Inventory().AddItem(i.i.Grow(-i.i.Count() + 1)) if err != nil { - // We couldn't add any of the item to the inventory, so we continue to the next item entity. + // We couldn't add any of the item to the inventory, so we ignore it. return i.passive.Tick(e) } From 87a894fc2dce3be08819af5ccf682f233aa81257 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Wed, 29 May 2024 00:03:56 -0400 Subject: [PATCH 11/21] model --- server/block/hopper.go | 3 +-- server/block/model/hopper.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 server/block/model/hopper.go diff --git a/server/block/hopper.go b/server/block/hopper.go index 8c1ea86dd..c6d68eee9 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -57,8 +57,7 @@ func NewHopper() Hopper { // Model ... func (Hopper) Model() world.BlockModel { - // TODO: Implement me. - return model.Solid{} + return model.Hopper{} } // SideClosed ... diff --git a/server/block/model/hopper.go b/server/block/model/hopper.go new file mode 100644 index 000000000..52e836ff2 --- /dev/null +++ b/server/block/model/hopper.go @@ -0,0 +1,18 @@ +package model + +import ( + "github.com/df-mc/dragonfly/server/block/cube" + "github.com/df-mc/dragonfly/server/world" +) + +type Hopper struct{} + +// BBox returns a physics.BBox that spans a full block. +func (Hopper) BBox(cube.Pos, *world.World) []cube.BBox { + return []cube.BBox{full} +} + +// FaceSolid only returns true for the top face of the hopper. +func (Hopper) FaceSolid(_ cube.Pos, face cube.Face, _ *world.World) bool { + return face == cube.FaceUp +} From f006ec0d3cdfb5c13772421e72893e81340cb444 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Wed, 29 May 2024 01:10:03 -0400 Subject: [PATCH 12/21] furnaces --- server/block/furnace.go | 20 ++++++++++++++++++++ server/block/hopper.go | 16 +++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/server/block/furnace.go b/server/block/furnace.go index 4c758bc64..2af7089e5 100644 --- a/server/block/furnace.go +++ b/server/block/furnace.go @@ -45,6 +45,26 @@ func (f Furnace) Tick(_ int64, pos cube.Pos, w *world.World) { } } +// InsertItem ... +func (f Furnace) InsertItem(it item.Stack, face cube.Face) (bool, int) { + if face != cube.FaceDown { + _, ok := it.Item().(item.Fuel) + return ok, 1 + } + + return true, 0 +} + +// ExtractItem ... +func (f Furnace) ExtractItem() (item.Stack, int) { + cooked, _ := f.inventory.Item(2) + if cooked.Empty() { + return item.Stack{}, 0 + } + + return cooked, 2 +} + // EncodeItem ... func (f Furnace) EncodeItem() (name string, meta int16) { return "minecraft:furnace", 0 diff --git a/server/block/hopper.go b/server/block/hopper.go index c6d68eee9..ea798c155 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -152,7 +152,7 @@ type HopperInsertable interface { // InsertItem attempts to insert a single item into the container. If the insertion was successful, the item is // returned. If the insertion was unsuccessful, the item stack returned will be empty. InsertItem by itself does // should not add the item to the container, but instead return the item that would be added. - InsertItem(item.Stack) (item.Stack, int) + InsertItem(item.Stack, cube.Face) (bool, int) } // insertItem ... @@ -187,12 +187,18 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { return false } } else { - targetStack, targetSlot := e.InsertItem(sourceStack) - if targetStack.Empty() { - // The destination is full. + stack := sourceStack.Grow(-sourceStack.Count() + 1) + allowed, targetSlot := e.InsertItem(stack, h.Facing) + it, _ := e.Inventory().Item(targetSlot) + if !allowed || !sourceStack.Comparable(it) { + // The items are not the same. return false } - _ = dest.Inventory().SetItem(targetSlot, targetStack) + if !it.Empty() { + stack = it.Grow(1) + } + + _ = dest.Inventory().SetItem(targetSlot, stack) } _ = h.inventory.SetItem(sourceSlot, sourceStack.Grow(-1)) From 8589ab634621fd9ff5de2e8af1de78de21fb896f Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Wed, 29 May 2024 01:13:52 -0400 Subject: [PATCH 13/21] blastfurnace --- server/block/furnace.go | 20 -------------------- server/block/smelter.go | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/server/block/furnace.go b/server/block/furnace.go index 2af7089e5..4c758bc64 100644 --- a/server/block/furnace.go +++ b/server/block/furnace.go @@ -45,26 +45,6 @@ func (f Furnace) Tick(_ int64, pos cube.Pos, w *world.World) { } } -// InsertItem ... -func (f Furnace) InsertItem(it item.Stack, face cube.Face) (bool, int) { - if face != cube.FaceDown { - _, ok := it.Item().(item.Fuel) - return ok, 1 - } - - return true, 0 -} - -// ExtractItem ... -func (f Furnace) ExtractItem() (item.Stack, int) { - cooked, _ := f.inventory.Item(2) - if cooked.Empty() { - return item.Stack{}, 0 - } - - return cooked, 2 -} - // EncodeItem ... func (f Furnace) EncodeItem() (name string, meta int16) { return "minecraft:furnace", 0 diff --git a/server/block/smelter.go b/server/block/smelter.go index 26b1a6fe2..8970b157c 100644 --- a/server/block/smelter.go +++ b/server/block/smelter.go @@ -38,6 +38,26 @@ func newSmelter() *smelter { return s } +// InsertItem ... +func (s *smelter) InsertItem(it item.Stack, face cube.Face) (bool, int) { + if face != cube.FaceDown { + _, ok := it.Item().(item.Fuel) + return ok, 1 + } + + return true, 0 +} + +// ExtractItem ... +func (s *smelter) ExtractItem() (item.Stack, int) { + cooked, _ := s.inventory.Item(2) + if cooked.Empty() { + return item.Stack{}, 0 + } + + return cooked, 2 +} + // Durations returns the remaining, maximum, and cook durations of the smelter. func (s *smelter) Durations() (remaining time.Duration, max time.Duration, cook time.Duration) { s.mu.Lock() From 723668ed3a3d8fb14d72deb677b5d584cfbf7f55 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Wed, 29 May 2024 01:21:44 -0400 Subject: [PATCH 14/21] various changes --- server/block/hopper.go | 57 +++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index ea798c155..245755f7f 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -162,47 +162,36 @@ func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { return false } - var ( - sourceSlot int - sourceStack item.Stack - ) - - for slot, stack := range h.inventory.Slots() { - if stack.Empty() { + for sourceSlot, sourceStack := range h.inventory.Slots() { + if sourceStack.Empty() { continue } - sourceStack, sourceSlot = stack, slot - break - } - if sourceStack.Empty() { - // We don't have any items to insert. - return false - } + if e, ok := dest.(HopperInsertable); !ok { + _, err := dest.Inventory().AddItem(sourceStack.Grow(-sourceStack.Count() + 1)) + if err != nil { + // The destination is full. + continue + } + } else { + stack := sourceStack.Grow(-sourceStack.Count() + 1) + allowed, targetSlot := e.InsertItem(stack, h.Facing) + it, _ := e.Inventory().Item(targetSlot) + if !allowed || !sourceStack.Comparable(it) { + // The items are not the same. + continue + } + if !it.Empty() { + stack = it.Grow(1) + } - if e, ok := dest.(HopperInsertable); !ok { - _, err := dest.Inventory().AddItem(sourceStack.Grow(-sourceStack.Count() + 1)) - if err != nil { - // The destination is full. - return false - } - } else { - stack := sourceStack.Grow(-sourceStack.Count() + 1) - allowed, targetSlot := e.InsertItem(stack, h.Facing) - it, _ := e.Inventory().Item(targetSlot) - if !allowed || !sourceStack.Comparable(it) { - // The items are not the same. - return false - } - if !it.Empty() { - stack = it.Grow(1) + _ = dest.Inventory().SetItem(targetSlot, stack) } - _ = dest.Inventory().SetItem(targetSlot, stack) + _ = h.inventory.SetItem(sourceSlot, sourceStack.Grow(-1)) + return true } - - _ = h.inventory.SetItem(sourceSlot, sourceStack.Grow(-1)) - return true + return false } // HopperExtractable represents a block that can have its contents extracted by a hopper. From d696790150de67b291c994561b30cc9f9689e23a Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Wed, 29 May 2024 01:28:41 -0400 Subject: [PATCH 15/21] comments --- server/block/hopper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index 245755f7f..27104e673 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -155,7 +155,7 @@ type HopperInsertable interface { InsertItem(item.Stack, cube.Face) (bool, int) } -// insertItem ... +// insertItem inserts an item into a container from the hopper. func (h Hopper) insertItem(pos cube.Pos, w *world.World) bool { dest, ok := w.Block(pos.Side(h.Facing)).(Container) if !ok { @@ -204,7 +204,7 @@ type HopperExtractable interface { ExtractItem() (item.Stack, int) } -// extractItem ... +// extractItem extracts an item from a container into the hopper. func (h Hopper) extractItem(pos cube.Pos, w *world.World) bool { origin, ok := w.Block(pos.Side(cube.FaceUp)).(Container) if !ok { From 8124f84f80a2658b0cb0efd9f5d0707362396c71 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Thu, 30 May 2024 23:54:04 -0400 Subject: [PATCH 16/21] Update hopper.go --- server/block/hopper.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index 27104e673..b8bde1e83 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -15,7 +15,6 @@ import ( // Hopper is a low-capacity storage block that can be used to collect item entities directly above it, as well as to // transfer items into and out of other containers. -// TODO: Functionality! type Hopper struct { transparent sourceWaterDisplacer From f113cb0c781028ae7d4ebbb1146fa7b3634c95d5 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Thu, 30 May 2024 23:55:59 -0400 Subject: [PATCH 17/21] Update hopper.go --- server/block/model/hopper.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/block/model/hopper.go b/server/block/model/hopper.go index 52e836ff2..d2598a65b 100644 --- a/server/block/model/hopper.go +++ b/server/block/model/hopper.go @@ -5,6 +5,7 @@ import ( "github.com/df-mc/dragonfly/server/world" ) +// Hopper is a model used by hoppers. type Hopper struct{} // BBox returns a physics.BBox that spans a full block. From fe750f0862894d4a94c3cfb82c8d966c2ae2fb0b Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Sat, 1 Jun 2024 16:15:55 -0400 Subject: [PATCH 18/21] hopper changes --- server/entity/item_behaviour.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/server/entity/item_behaviour.go b/server/entity/item_behaviour.go index 30b8ca54c..f23d07ac7 100644 --- a/server/entity/item_behaviour.go +++ b/server/entity/item_behaviour.go @@ -72,16 +72,13 @@ func (i *ItemBehaviour) Tick(e *Ent) *Movement { bl, ok := w.Block(pos.Side(cube.FaceDown)).(block.Hopper) if ok && !bl.Powered { - _, err := bl.Inventory().AddItem(i.i.Grow(-i.i.Count() + 1)) + _, err := bl.Inventory().AddItem(i.i) if err != nil { // We couldn't add any of the item to the inventory, so we ignore it. return i.passive.Tick(e) } - if i.i = i.i.Grow(-1); i.i.Empty() { - _ = e.Close() - return nil - } + _ = e.Close() } return i.passive.Tick(e) } From ffe1703648d0cecabdaf336c42ae74bdd8e54525 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:30:01 -0400 Subject: [PATCH 19/21] collectcooldown --- server/block/hopper.go | 7 ++++++- server/entity/item_behaviour.go | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index b8bde1e83..dcc49ae7b 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -31,6 +31,8 @@ type Hopper struct { LastTick int64 // TransferCooldown is the duration until the hopper can transfer items again. TransferCooldown int64 + // CollectCooldown is the duration until the hopper can collect items again. + CollectCooldown int64 inventory *inventory.Inventory viewerMu *sync.RWMutex @@ -124,13 +126,16 @@ func (h Hopper) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world. // Tick ... func (h Hopper) Tick(currentTick int64, pos cube.Pos, w *world.World) { h.TransferCooldown-- + h.CollectCooldown-- h.LastTick = currentTick - if h.TransferCooldown > 0 { + + if h.TransferCooldown > 0 || h.CollectCooldown >= 0 { w.SetBlock(pos, h, nil) return } h.TransferCooldown = 0 + h.CollectCooldown = 0 if h.Powered { w.SetBlock(pos, h, nil) return diff --git a/server/entity/item_behaviour.go b/server/entity/item_behaviour.go index f23d07ac7..89f9b5600 100644 --- a/server/entity/item_behaviour.go +++ b/server/entity/item_behaviour.go @@ -69,9 +69,10 @@ func (i *ItemBehaviour) Item() item.Stack { func (i *ItemBehaviour) Tick(e *Ent) *Movement { w := e.World() pos := cube.PosFromVec3(e.Position()) + blockPos := pos.Side(cube.FaceDown) - bl, ok := w.Block(pos.Side(cube.FaceDown)).(block.Hopper) - if ok && !bl.Powered { + bl, ok := w.Block(blockPos).(block.Hopper) + if ok && !bl.Powered && bl.CollectCooldown <= 0 { _, err := bl.Inventory().AddItem(i.i) if err != nil { // We couldn't add any of the item to the inventory, so we ignore it. @@ -79,6 +80,8 @@ func (i *ItemBehaviour) Tick(e *Ent) *Movement { } _ = e.Close() + bl.CollectCooldown = 4 + w.SetBlock(blockPos, bl, nil) } return i.passive.Tick(e) } From 7d5ad5b2a522e99955384e598ee79287e41e35f9 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:57:35 -0400 Subject: [PATCH 20/21] Update server/block/hopper.go Co-authored-by: DaPigGuy --- server/block/hopper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index dcc49ae7b..b159d0cbf 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -68,7 +68,7 @@ func (Hopper) SideClosed(cube.Pos, cube.Pos, *world.World) bool { // BreakInfo ... func (h Hopper) BreakInfo() BreakInfo { - return newBreakInfo(3, pickaxeHarvestable, pickaxeEffective, oneOf(h)) + return newBreakInfo(3, pickaxeHarvestable, pickaxeEffective, oneOf(h)).withBlastResistance(24) } // Inventory returns the inventory of the hopper. From 3cbb0d7bbb8760b23c05b358afd28e8a94de7489 Mon Sep 17 00:00:00 2001 From: Restart <45609733+RestartFU@users.noreply.github.com> Date: Tue, 4 Jun 2024 23:57:57 -0400 Subject: [PATCH 21/21] Update server/block/hopper.go Co-authored-by: DaPigGuy --- server/block/hopper.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/server/block/hopper.go b/server/block/hopper.go index b159d0cbf..6c3fe1204 100644 --- a/server/block/hopper.go +++ b/server/block/hopper.go @@ -292,9 +292,8 @@ func (h Hopper) DecodeNBT(data map[string]any) any { // allHoppers ... func allHoppers() (hoppers []world.Block) { for _, f := range cube.Faces() { - for _, p := range []bool{false, true} { - hoppers = append(hoppers, Hopper{Facing: f, Powered: p}) - } + hoppers = append(hoppers, Hopper{Facing: f}) + hoppers = append(hoppers, Hopper{Facing: f, Powered: true}) } return hoppers }