diff --git a/server/block/action.go b/server/block/action.go index 5242340e6..f4faa4931 100644 --- a/server/block/action.go +++ b/server/block/action.go @@ -26,6 +26,14 @@ type ContinueCrackAction struct { // StopCrackAction is a world.BlockAction to make the cracks forming in a block stop and disappear. type StopCrackAction struct{ action } +// DecoratedPotWobbleAction is a world.BlockAction to make a decorated pot wobble when interacted with. +type DecoratedPotWobbleAction struct { + action + DecoratedPot DecoratedPot + // Success is whether an item was successfully inserted into the decorated pot. + Success bool +} + // action implements the Action interface. Structures in this package may embed it to gets its functionality // out of the box. type action struct{} diff --git a/server/block/decorated_pot.go b/server/block/decorated_pot.go index 51b632c04..13be891f1 100644 --- a/server/block/decorated_pot.go +++ b/server/block/decorated_pot.go @@ -7,6 +7,8 @@ import ( "github.com/df-mc/dragonfly/server/internal/nbtconv" "github.com/df-mc/dragonfly/server/item" "github.com/df-mc/dragonfly/server/world" + "github.com/df-mc/dragonfly/server/world/particle" + "github.com/df-mc/dragonfly/server/world/sound" "github.com/go-gl/mathgl/mgl64" ) @@ -66,10 +68,25 @@ func (p DecoratedPot) InsertItem(h Hopper, pos cube.Pos, tx *world.Tx) bool { return false } +// wobble ... +func (p DecoratedPot) wobble(pos cube.Pos, tx *world.Tx, success bool) { + for _, v := range tx.Viewers(pos.Vec3Centre()) { + v.ViewBlockAction(pos, DecoratedPotWobbleAction{DecoratedPot: p, Success: success}) + } + + if success { + tx.AddParticle(pos.Vec3Middle().Add(mgl64.Vec3{0, 1.25}), particle.DustPlume{}) + tx.PlaySound(pos.Vec3Centre(), sound.DecoratedPotInserted{}) + } else { + tx.PlaySound(pos.Vec3Centre(), sound.DecoratedPotInsertFailed{}) + } +} + // Activate ... func (p DecoratedPot) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, u item.User, ctx *item.UseContext) bool { held, _ := u.HeldItems() if held.Empty() || !p.Item.Comparable(held) || p.Item.Count() == p.Item.MaxCount() { + p.wobble(pos, tx, false) return false } @@ -79,6 +96,7 @@ func (p DecoratedPot) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, u item.U p.Item = p.Item.Grow(1) } tx.SetBlock(pos, p, nil) + p.wobble(pos, tx, true) ctx.SubtractFromCount(1) return true } diff --git a/server/session/world.go b/server/session/world.go index 41ba19b3d..410dec61c 100644 --- a/server/session/world.go +++ b/server/session/world.go @@ -453,6 +453,11 @@ func (s *Session) ViewParticle(pos mgl64.Vec3, p world.Particle) { EventType: packet.LevelEventParticleLegacyEvent | 10, Position: vec64To32(pos), }) + case particle.DustPlume: + s.writePacket(&packet.LevelEvent{ + EventType: packet.LevelEventParticleLegacyEvent | 88, + Position: vec64To32(pos), + }) } } @@ -810,6 +815,10 @@ func (s *Session) playSound(pos mgl64.Vec3, t world.Sound, disableRelative bool) EventType: packet.LevelEventSoundTotemUsed, Position: vec64To32(pos), }) + case sound.DecoratedPotInserted: + pk.SoundType = packet.SoundEventDecoratedPotInsert + case sound.DecoratedPotInsertFailed: + pk.SoundType = packet.SoundEventDecoratedPotInsertFail } s.writePacket(pk) } @@ -1152,6 +1161,14 @@ func (s *Session) ViewBlockAction(pos cube.Pos, a world.BlockAction) { Position: vec64To32(pos.Vec3()), EventData: int32(65535 / (t.BreakTime.Seconds() * 20)), }) + case block.DecoratedPotWobbleAction: + nbt := t.DecoratedPot.EncodeNBT() + nbt["x"], nbt["y"], nbt["z"] = blockPos.X(), blockPos.Y(), blockPos.Z() + nbt["animation"] = boolByte(t.Success) + 1 + s.writePacket(&packet.BlockActorData{ + Position: blockPos, + NBTData: nbt, + }) } } diff --git a/server/world/particle/block.go b/server/world/particle/block.go index d6b02b052..43130e2b3 100644 --- a/server/world/particle/block.go +++ b/server/world/particle/block.go @@ -81,6 +81,9 @@ type LavaDrip struct{ particle } // Lava is a particle that shows up randomly above lava. type Lava struct{ particle } +// DustPlume is a particle that shows up when an item is successfully inserted into a decorated pot. +type DustPlume struct{ particle } + // particle serves as a base for all particles in this package. type particle struct{} diff --git a/server/world/sound/block.go b/server/world/sound/block.go index d9a35c73d..62bd17498 100644 --- a/server/world/sound/block.go +++ b/server/world/sound/block.go @@ -200,6 +200,12 @@ type WaxRemoved struct{ sound } // CopperScraped is a sound played when a player scrapes a copper block to reduce its oxidation level. type CopperScraped struct{ sound } +// DecoratedPotInserted is a sound played when an item is successfully inserted into a decorated pot. +type DecoratedPotInserted struct{ sound } + +// DecoratedPotInsertFailed is a sound played when an item fails to be inserted into a decorated pot. +type DecoratedPotInsertFailed struct{ sound } + // sound implements the world.Sound interface. type sound struct{}