Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

double chest #872

Merged
merged 53 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
0755955
raptors double chest
xNatsuri May 21, 2024
2fa8b6b
fix drops
RestartFU May 22, 2024
59488bc
various fixes
RestartFU May 22, 2024
035e02b
Merge branch 'df-mc:master' into double-chest
xNatsuri May 23, 2024
82fcaed
fix drops
RestartFU May 24, 2024
104afa6
double chests
RestartFU May 24, 2024
e87f058
fix pairInv being nil after restart
xNatsuri May 25, 2024
e06374d
Merge remote-tracking branch 'origin/double-chest' into double-chest
xNatsuri May 25, 2024
08852f1
fix some comments
RestartFU May 26, 2024
25c4e59
Merge branch 'master' into double-chest
RestartFU May 26, 2024
7b3f8d1
upstream
cqdetdev May 27, 2024
c682161
Merge branch 'master' into double-chest
RestartFU May 29, 2024
9a84394
loL
cqdetdev May 29, 2024
5e72f9f
added alwaysDrops to BreakInfo
xNatsuri May 31, 2024
3041b4e
handle
cqdetdev May 31, 2024
5cb2e89
Revert "added alwaysDrops to BreakInfo"
xNatsuri Jun 1, 2024
df17739
move container drops
xNatsuri Jun 1, 2024
deca297
cleaned up some code
T14Raptor Jun 2, 2024
f69f1e9
remove scoreboard limit
cqdetdev Jun 5, 2024
d6514e0
hoppers
RestartFU Jun 7, 2024
7ca3302
Merge branch 'master' of ssh://github.com/moyai-network/libellule
RestartFU Jun 7, 2024
6d731f7
Update register.go
RestartFU Jun 7, 2024
513ff02
Update player.go
RestartFU Jun 7, 2024
7d6c34d
push
RestartFU Jun 7, 2024
1d1d395
Update hopper.go
RestartFU Jun 7, 2024
a091bb6
Update hopper.go
RestartFU Jun 7, 2024
2253e75
fixes for everything
T14Raptor Jun 7, 2024
d59257b
Merge branch 'df-mc:master' into double-chest
xNatsuri Jun 8, 2024
60746e0
prevent chest opening when paired chest is being blocked
xNatsuri Jun 8, 2024
3f1af73
feat: redstone?
cqdetdev Jun 12, 2024
09592e3
Update _hash.go
RestartFU Jun 17, 2024
03e4432
various changes
RestartFU Jun 17, 2024
a5f9fa8
Merge branch 'df-mc:master' into master
RestartFU Jun 17, 2024
c1c3227
Update hash_libellule.go
RestartFU Jun 17, 2024
1f55308
Update hash_libellule.go
RestartFU Jun 17, 2024
ad23c9b
is cadet just retarded 😭
RestartFU Jun 17, 2024
a54e6d7
fully implement pressure plates
cqdetdev Jun 17, 2024
0569f0b
add experimental save function
cqdetdev Jul 8, 2024
0b98dfb
add a way to savechunks without closing entities
cqdetdev Jul 8, 2024
2e72862
Merge branch 'df-mc:master' into master
cqdetdev Jul 10, 2024
f7d9ee0
revert world.go
cqdetdev Jul 10, 2024
65d9481
fix entity deadlock
cqdetdev Jul 10, 2024
6321516
Merge branch 'master' into master
RestartFU Jul 15, 2024
c0aa072
Fix generic issue
cqdetdev Jul 16, 2024
300568d
fix panic 1
RestartFU Jul 19, 2024
d36854d
Merge branch 'master' into double-chest
RestartFU Jul 20, 2024
66c6bf7
update to master
RestartFU Jul 20, 2024
8084859
fix drop panic
cqdetdev Jul 20, 2024
115ebac
Merge branch 'master' into double-chest
RestartFU Jul 20, 2024
0d4b124
Revert "Merge branch 'master' into double-chest"
RestartFU Jul 20, 2024
deb6d9c
Merge branch 'df-mc:master' into double-chest
xNatsuri Aug 15, 2024
3e5d290
fix container drops with explosions
xNatsuri Aug 15, 2024
78e96d8
block/chest.go: Fix formatting
TwistedAsylumMC Aug 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 135 additions & 9 deletions server/block/chest.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ type Chest struct {
// include colour codes.
CustomName string

paired bool
pairX, pairZ int
pairInv *inventory.Inventory

inventory *inventory.Inventory
viewerMu *sync.RWMutex
viewers map[ContainerViewer]struct{}
Expand All @@ -38,22 +42,28 @@ type Chest struct {
func NewChest() Chest {
m := new(sync.RWMutex)
v := make(map[ContainerViewer]struct{}, 1)
return Chest{
inventory: inventory.New(27, func(slot int, _, item item.Stack) {
m.RLock()
defer m.RUnlock()
for viewer := range v {
viewer.ViewSlotChange(slot, item)
}
}),

c := Chest{
viewerMu: m,
viewers: v,
}

c.inventory = inventory.New(27, func(slot int, _, item item.Stack) {
c.viewerMu.RLock()
defer c.viewerMu.RUnlock()
for viewer := range c.viewers {
viewer.ViewSlotChange(slot, item)
}
})
return c
}

// Inventory returns the inventory of the chest. The size of the inventory will be 27 or 54, depending on
// whether the chest is single or double.
func (c Chest) Inventory() *inventory.Inventory {
if c.paired {
return c.pairInv
}
return c.inventory
}

Expand All @@ -71,6 +81,9 @@ func (Chest) SideClosed(cube.Pos, cube.Pos, *world.World) bool {
// open opens the chest, displaying the animation and playing a sound.
func (c Chest) open(w *world.World, pos cube.Pos) {
for _, v := range w.Viewers(pos.Vec3()) {
if c.paired {
v.ViewBlockAction(c.PairPos(pos), OpenAction{})
}
v.ViewBlockAction(pos, OpenAction{})
}
w.PlaySound(pos.Vec3Centre(), sound.ChestOpen{})
Expand All @@ -79,6 +92,9 @@ func (c Chest) open(w *world.World, pos cube.Pos) {
// close closes the chest, displaying the animation and playing a sound.
func (c Chest) close(w *world.World, pos cube.Pos) {
for _, v := range w.Viewers(pos.Vec3()) {
if c.paired {
v.ViewBlockAction(c.PairPos(pos), CloseAction{})
}
v.ViewBlockAction(pos, CloseAction{})
}
w.PlaySound(pos.Vec3Centre(), sound.ChestClose{})
Expand Down Expand Up @@ -111,6 +127,12 @@ func (c Chest) RemoveViewer(v ContainerViewer, w *world.World, pos cube.Pos) {
// Activate ...
func (c Chest) Activate(pos cube.Pos, _ cube.Face, w *world.World, u item.User, _ *item.UseContext) bool {
if opener, ok := u.(ContainerOpener); ok {
if c.paired && c.pairInv == nil {
if ch, pair, ok := c.pair(w, pos, c.PairPos(pos)); ok {
w.SetBlock(pos, ch, nil)
w.SetBlock(c.PairPos(pos), pair, nil)
}
}
if d, ok := w.Block(pos.Side(cube.FaceUp)).(LightDiffuser); ok && d.LightDiffusionLevel() <= 2 {
opener.OpenBlockContainer(pos)
}
Expand All @@ -129,13 +151,29 @@ func (c Chest) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.W
c = NewChest()
c.Facing = user.Rotation().Direction().Opposite()

for _, dir := range []cube.Direction{c.Facing.RotateLeft(), c.Facing.RotateRight()} {
sidePos := pos.Side(dir.Face())
if ch, pair, ok := c.pair(w, pos, sidePos); ok {
place(w, pos, ch, user, ctx)
w.SetBlock(ch.PairPos(pos), pair, nil)
return placed(ctx)
}
}

place(w, pos, c, user, ctx)
return placed(ctx)
}

// BreakInfo ...
func (c Chest) BreakInfo() BreakInfo {
return newBreakInfo(2.5, alwaysHarvestable, axeEffective, oneOf(c))
return newBreakInfo(2.5, alwaysHarvestable, axeEffective, oneOf(c)).withBreakHandler(func(pos cube.Pos, w *world.World, u item.User) {
if c.paired {
pairPos := c.PairPos(pos)
if _, pair, ok := c.unpair(w, pos); ok {
w.SetBlock(pairPos, pair, nil)
}
}
})
}

// FuelInfo ...
Expand All @@ -155,6 +193,24 @@ func (c Chest) DecodeNBT(data map[string]any) any {
c = NewChest()
c.Facing = facing
c.CustomName = nbtconv.String(data, "CustomName")

pairX, ok := data["pairx"]
pairZ, ok2 := data["pairz"]
if ok && ok2 {
c.paired = true
// TODO: type assertion checks
c.pairX, c.pairZ = int(pairX.(int32)), int(pairZ.(int32))
c.pairInv = inventory.New(54, func(slot int, _, item item.Stack) {
T14Raptor marked this conversation as resolved.
Show resolved Hide resolved
c.viewerMu.RLock()
defer c.viewerMu.RUnlock()
for viewer := range c.viewers {
viewer.ViewSlotChange(slot, item)
}
})

nbtconv.InvFromNBT(c.pairInv, nbtconv.Slice(data, "Items"))
}

nbtconv.InvFromNBT(c.inventory, nbtconv.Slice(data, "Items"))
return c
}
Expand All @@ -174,9 +230,79 @@ func (c Chest) EncodeNBT() map[string]any {
if c.CustomName != "" {
m["CustomName"] = c.CustomName
}

if c.paired {
m["pairx"] = int32(c.pairX)
m["pairz"] = int32(c.pairZ)
}
return m
}

// pair pairs this chest with the given chest position.
func (c Chest) pair(w *world.World, pos, pairPos cube.Pos) (ch, pair Chest, ok bool) {
pair, ok = w.Block(pairPos).(Chest)
if !ok || c.Facing != pair.Facing || pair.paired && (pair.pairX != pos[0] || pair.pairZ != pos[2]) {
return c, pair, false
}
m := new(sync.RWMutex)
v := make(map[ContainerViewer]struct{})
left, right := c.inventory, pair.inventory
if pos.Side(c.Facing.RotateRight().Face()) == pairPos {
left, right = right, left
}
double := left.Merge(right, func(slot int, _, item item.Stack) {
if slot < 27 {
_ = left.SetItem(slot, item)
} else {
_ = right.SetItem(slot-27, item)
}
m.RLock()
defer m.RUnlock()
for viewer := range v {
viewer.ViewSlotChange(slot, item)
}
})

c.pairX, c.pairZ, c.paired = pairPos[0], pairPos[2], true
pair.pairX, pair.pairZ, pair.paired = pos[0], pos[2], true
c.viewerMu, pair.viewerMu = m, m
c.viewers, pair.viewers = v, v
c.pairInv, pair.pairInv = double, double
return c, pair, true
}

// unpair ...
xNatsuri marked this conversation as resolved.
Show resolved Hide resolved
func (c Chest) unpair(w *world.World, pos cube.Pos) (ch, pair Chest, ok bool) {
if !c.paired {
return c, Chest{}, false
}

pair, ok = w.Block(c.PairPos(pos)).(Chest)
if !ok || c.Facing != pair.Facing || pair.paired && (pair.pairX != pos[0] || pair.pairZ != pos[2]) {
return c, pair, false
}

if len(c.viewers) != 0 {
c.close(w, pos)
}

c.paired, pair.paired = false, false
c.viewerMu, pair.viewerMu = new(sync.RWMutex), new(sync.RWMutex)
c.viewers, pair.viewers = make(map[ContainerViewer]struct{}, 1), make(map[ContainerViewer]struct{}, 1)
c.pairInv, pair.pairInv = nil, nil
return c, pair, true
}

// PairPos ...
xNatsuri marked this conversation as resolved.
Show resolved Hide resolved
func (c Chest) PairPos(pos cube.Pos) cube.Pos {
return cube.Pos{c.pairX, pos[1], c.pairZ}
}

// Paired returns whether
xNatsuri marked this conversation as resolved.
Show resolved Hide resolved
func (c Chest) Paired() bool {
return c.paired
}

// EncodeItem ...
func (Chest) EncodeItem() (name string, meta int16) {
return "minecraft:chest", 0
Expand Down
13 changes: 13 additions & 0 deletions server/item/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,19 @@ func (inv *Inventory) ContainsItemFunc(n int, comparable func(stack item.Stack)
return n <= 0
}

// Merge merges two inventorys
T14Raptor marked this conversation as resolved.
Show resolved Hide resolved
func (inv *Inventory) Merge(inv2 *Inventory, f func(int, item.Stack, item.Stack)) *Inventory {
// note, this is most likely a temporary method
xNatsuri marked this conversation as resolved.
Show resolved Hide resolved
inv.mu.RLock()
defer inv.mu.RUnlock()
inv2.mu.RLock()
defer inv2.mu.RUnlock()

n := New(len(inv.slots)+len(inv2.slots), f)
n.slots = append(inv.slots, inv2.slots...)
return n
}

// Empty checks if the inventory is fully empty: It iterates over the inventory and makes sure every stack in
// it is empty.
func (inv *Inventory) Empty() bool {
Expand Down
32 changes: 26 additions & 6 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ func (p *Player) BreakBlock(pos cube.Pos) {
return
}
held, _ := p.HeldItems()
drops := p.drops(held, b)
drops := p.drops(held, b, pos)

xp := 0
if breakable, ok := b.(block.Breakable); ok && !p.GameMode().CreativeInventory() {
Expand Down Expand Up @@ -1835,22 +1835,42 @@ func (p *Player) BreakBlock(pos cube.Pos) {
}

// drops returns the drops that the player can get from the block passed using the item held.
func (p *Player) drops(held item.Stack, b world.Block) []item.Stack {
func (p *Player) drops(held item.Stack, b world.Block, pos cube.Pos) []item.Stack {
t, ok := held.Item().(item.Tool)
if !ok {
t = item.ToolNone{}
}
var drops []item.Stack
if container, ok := b.(block.Container); ok {
// If the block is a container, it should drop its inventory contents regardless whether the
// player is in creative mode or not.
drops = container.Inventory().Items()
if c, ok := b.(block.Chest); ok && c.Paired() {
pairPos := c.PairPos(pos)
left, right := pos, pairPos
if pos.Side(c.Facing.RotateRight().Face()) == pairPos {
left, right = right, left
}

for slot, i := range c.Inventory().Slots() {
if i.Empty() {
continue
}

if slot < 27 && pos == left {
drops = append(drops, i)
} else if slot > 26 && pos == right {
drops = append(drops, i)
}
}
} else {
// If the block is a container, it should drop its inventory contents regardless whether the
// player is in creative mode or not.
drops = container.Inventory().Items()
container.Inventory().Clear()
}
T14Raptor marked this conversation as resolved.
Show resolved Hide resolved
if breakable, ok := b.(block.Breakable); ok && !p.GameMode().CreativeInventory() {
if breakable.BreakInfo().Harvestable(t) {
drops = append(drops, breakable.BreakInfo().Drops(t, held.Enchantments())...)
}
}
container.Inventory().Clear()
} else if breakable, ok := b.(block.Breakable); ok && !p.GameMode().CreativeInventory() {
if breakable.BreakInfo().Harvestable(t) {
drops = breakable.BreakInfo().Drops(t, held.Enchantments())
Expand Down
Loading