From bc173dc99e5117e4ee30651a81bd61866f40dd66 Mon Sep 17 00:00:00 2001 From: HashimTheArab Date: Mon, 16 Mar 2026 03:05:59 -0400 Subject: [PATCH 1/5] feat: add wind charges --- server/block/wood_fence_gate.go | 2 +- server/entity/register.go | 2 + server/entity/wind_charge.go | 97 +++++++++++++++++++++++++++++++++ server/item/register.go | 1 + server/item/wind_charge.go | 37 +++++++++++++ server/session/world.go | 7 +++ server/world/entity.go | 1 + server/world/particle/entity.go | 3 + server/world/sound/item.go | 3 + 9 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 server/entity/wind_charge.go create mode 100644 server/item/wind_charge.go diff --git a/server/block/wood_fence_gate.go b/server/block/wood_fence_gate.go index 60ff01dae..be74b9bb9 100644 --- a/server/block/wood_fence_gate.go +++ b/server/block/wood_fence_gate.go @@ -80,7 +80,7 @@ func (f WoodFenceGate) shouldBeLowered(pos cube.Pos, tx *world.Tx) bool { // Activate ... func (f WoodFenceGate) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, u item.User, _ *item.UseContext) bool { f.Open = !f.Open - if f.Open && f.Facing.Opposite() == u.Rotation().Direction() { + if f.Open && u != nil && f.Facing.Opposite() == u.Rotation().Direction() { f.Facing = f.Facing.Opposite() } tx.SetBlock(pos, f, nil) diff --git a/server/entity/register.go b/server/entity/register.go index e9c54922e..e6db53755 100644 --- a/server/entity/register.go +++ b/server/entity/register.go @@ -25,6 +25,7 @@ var DefaultRegistry = conf.New([]world.EntityType{ SplashPotionType, TNTType, TextType, + WindChargeType, }) var conf = world.EntityRegistryConfig{ @@ -35,6 +36,7 @@ var conf = world.EntityRegistryConfig{ EnderPearl: NewEnderPearl, FallingBlock: NewFallingBlock, Lightning: NewLightning, + WindCharge: NewWindCharge, Firework: func(opts world.EntitySpawnOpts, firework world.Item, owner world.Entity, sidewaysVelocityMultiplier, upwardsAcceleration float64, attached bool) *world.EntityHandle { return newFirework(opts, firework.(item.Firework), owner, sidewaysVelocityMultiplier, upwardsAcceleration, attached) }, diff --git a/server/entity/wind_charge.go b/server/entity/wind_charge.go new file mode 100644 index 000000000..ab345fff3 --- /dev/null +++ b/server/entity/wind_charge.go @@ -0,0 +1,97 @@ +package entity + +import ( + "github.com/df-mc/dragonfly/server/block" + "github.com/df-mc/dragonfly/server/block/cube" + "github.com/df-mc/dragonfly/server/block/cube/trace" + "github.com/df-mc/dragonfly/server/world" + "github.com/df-mc/dragonfly/server/world/particle" + "github.com/df-mc/dragonfly/server/world/sound" +) + +// windChargeBurstRadius is the radius within which entities are knocked back +// by a wind charge burst. +const windChargeBurstRadius = 2.0 + +// NewWindCharge creates a wind charge entity at a position with an owner +// entity. Wind charges fly in a straight line (no gravity) and create a burst +// of wind on impact that knocks back nearby entities and toggles certain +// interactive blocks. +func NewWindCharge(opts world.EntitySpawnOpts, owner world.Entity) *world.EntityHandle { + conf := windChargeConf + conf.Owner = owner.H() + return opts.New(WindChargeType, conf) +} + +var windChargeConf = ProjectileBehaviourConfig{ + Gravity: 0, + Drag: 0.01, + Damage: -1, + Particle: particle.WindExplosion{}, + Sound: sound.WindChargeBurst{}, + Hit: windChargeBurst, +} + +// windChargeBurst is called when a wind charge hits a target. It deals 1 HP +// damage on a direct entity hit, knocks back all living entities within the +// burst radius, and toggles interactive blocks at the impact point. +func windChargeBurst(e *Ent, tx *world.Tx, target trace.Result) { + pos := target.Position() + owner, _ := e.Behaviour().(*ProjectileBehaviour).Owner().Entity(tx) + + // Deal flat 1 HP damage to the directly-hit entity. + if er, ok := target.(trace.EntityResult); ok { + if l, ok := er.Entity().(Living); ok { + l.Hurt(1, ProjectileDamageSource{Projectile: e, Owner: owner}) + } + } + + // Knock back all living entities within the burst radius, including the + // directly-hit entity which receives both damage and burst knockback. + box := e.H().Type().BBox(e).Translate(pos).Grow(windChargeBurstRadius) + for other := range tx.EntitiesWithin(box) { + if other.H() == e.H() { + continue + } + l, ok := other.(Living) + if !ok || other.Position().Sub(pos).LenSqr() > windChargeBurstRadius*windChargeBurstRadius { + continue + } + l.KnockBack(pos, 0.45, 0.3608) + } + + // Toggle interactive blocks at the impact point. + if r, ok := target.(trace.BlockResult); ok { + toggleWindChargeBlock(r.BlockPosition(), r.Face(), tx) + } +} + +// toggleWindChargeBlock toggles a block at pos if it is a door, trapdoor or +// fence gate. Other activatable blocks (chests, crafting tables, etc.) are not +// affected. +func toggleWindChargeBlock(pos cube.Pos, face cube.Face, tx *world.Tx) { + b := tx.Block(pos) + switch b.(type) { + case block.WoodDoor, block.CopperDoor, block.WoodTrapdoor, block.CopperTrapdoor, block.WoodFenceGate: + b.(block.Activatable).Activate(pos, face, tx, nil, nil) + } +} + +// WindChargeType is a world.EntityType implementation for WindCharge. +var WindChargeType windChargeType + +type windChargeType struct{} + +func (windChargeType) Open(tx *world.Tx, handle *world.EntityHandle, data *world.EntityData) world.Entity { + return &Ent{tx: tx, handle: handle, data: data} +} + +func (windChargeType) EncodeEntity() string { return "minecraft:wind_charge_projectile" } +func (windChargeType) BBox(world.Entity) cube.BBox { + return cube.Box(-0.15625, 0, -0.15625, 0.15625, 0.3125, 0.15625) +} + +func (windChargeType) DecodeNBT(_ map[string]any, data *world.EntityData) { + data.Data = windChargeConf.New() +} +func (windChargeType) EncodeNBT(*world.EntityData) map[string]any { return nil } diff --git a/server/item/register.go b/server/item/register.go index 7e18533c0..3b5cf17ca 100644 --- a/server/item/register.go +++ b/server/item/register.go @@ -124,6 +124,7 @@ func init() { world.RegisterItem(TurtleShell{}) world.RegisterItem(WarpedFungusOnAStick{}) world.RegisterItem(Wheat{}) + world.RegisterItem(WindCharge{}) world.RegisterItem(WrittenBook{}) for _, t := range ArmourTiers() { world.RegisterItem(Helmet{Tier: t}) diff --git a/server/item/wind_charge.go b/server/item/wind_charge.go new file mode 100644 index 000000000..25f602294 --- /dev/null +++ b/server/item/wind_charge.go @@ -0,0 +1,37 @@ +package item + +import ( + "github.com/df-mc/dragonfly/server/world" + "github.com/df-mc/dragonfly/server/world/sound" + "time" +) + +// WindCharge is a throwable item that creates a burst of wind on impact, knocking back nearby entities and +// toggling certain blocks such as doors, trapdoors and fence gates. +type WindCharge struct{} + +// Use ... +func (WindCharge) Use(tx *world.Tx, user User, ctx *UseContext) bool { + create := tx.World().EntityRegistry().Config().WindCharge + opts := world.EntitySpawnOpts{Position: eyePosition(user), Velocity: user.Rotation().Vec3().Mul(1.5)} + tx.AddEntity(create(opts, user)) + tx.PlaySound(user.Position(), sound.ItemThrow{}) + + ctx.SubtractFromCount(1) + return true +} + +// Cooldown ... +func (WindCharge) Cooldown() time.Duration { + return time.Millisecond * 500 +} + +// MaxCount ... +func (WindCharge) MaxCount() int { + return 64 +} + +// EncodeItem ... +func (WindCharge) EncodeItem() (name string, meta int16) { + return "minecraft:wind_charge", 0 +} diff --git a/server/session/world.go b/server/session/world.go index 2b9dab62e..e88ec7912 100644 --- a/server/session/world.go +++ b/server/session/world.go @@ -483,6 +483,11 @@ func (s *Session) ViewParticle(pos mgl64.Vec3, p world.Particle) { EventType: packet.LevelEventParticleLegacyEvent | 88, Position: vec64To32(pos), }) + case particle.WindExplosion: + s.writePacket(&packet.LevelEvent{ + EventType: packet.LevelEventParticlesWindExplosion, + Position: vec64To32(pos), + }) } } @@ -652,6 +657,8 @@ func (s *Session) playSound(pos mgl64.Vec3, t world.Sound, disableRelative bool) case sound.Dream(): pk.SoundType = packet.SoundEventGoatCall7 } + case sound.WindChargeBurst: + pk.SoundType = packet.SoundEventWindChargeBurst case sound.FireExtinguish: pk.SoundType = packet.SoundEventExtinguishFire case sound.Ignite: diff --git a/server/world/entity.go b/server/world/entity.go index dcc415ce9..a8bfab7c0 100644 --- a/server/world/entity.go +++ b/server/world/entity.go @@ -373,6 +373,7 @@ type EntityRegistryConfig struct { LingeringPotion func(opts EntitySpawnOpts, t any, owner Entity) *EntityHandle Snowball func(opts EntitySpawnOpts, owner Entity) *EntityHandle SplashPotion func(opts EntitySpawnOpts, t any, owner Entity) *EntityHandle + WindCharge func(opts EntitySpawnOpts, owner Entity) *EntityHandle Lightning func(opts EntitySpawnOpts) *EntityHandle } diff --git a/server/world/particle/entity.go b/server/world/particle/entity.go index f7d7e253a..434e6bf07 100644 --- a/server/world/particle/entity.go +++ b/server/world/particle/entity.go @@ -32,3 +32,6 @@ type Effect struct { // EntityFlame is a particle shown when an entity is set on fire. type EntityFlame struct{ particle } + +// WindExplosion is a particle shown when a wind charge bursts on impact. +type WindExplosion struct{ particle } diff --git a/server/world/sound/item.go b/server/world/sound/item.go index 69ddda6a2..a3837b84b 100644 --- a/server/world/sound/item.go +++ b/server/world/sound/item.go @@ -94,5 +94,8 @@ type GoatHorn struct { // blaze shoots a fireball. type FireCharge struct{ sound } +// WindChargeBurst is a sound played when a wind charge bursts on impact. +type WindChargeBurst struct{ sound } + // Totem is a sound played when a player uses a totem. type Totem struct{ sound } From f7468fb400639907fe1fdb9311749b34f2ef6145 Mon Sep 17 00:00:00 2001 From: HashimTheArab Date: Mon, 16 Mar 2026 03:39:50 -0400 Subject: [PATCH 2/5] fix: incorrect physics values --- server/entity/wind_charge.go | 35 +++++++++++++++++++++++++++-------- server/item/wind_charge.go | 2 +- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/server/entity/wind_charge.go b/server/entity/wind_charge.go index ab345fff3..a985aba68 100644 --- a/server/entity/wind_charge.go +++ b/server/entity/wind_charge.go @@ -7,11 +7,17 @@ import ( "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" ) -// windChargeBurstRadius is the radius within which entities are knocked back -// by a wind charge burst. -const windChargeBurstRadius = 2.0 +const ( + // windChargeBurstRadius is the radius within which entities are knocked + // back by a wind charge burst. + windChargeBurstRadius = 2.0 + // windChargeBurstForce is the force applied to entities in the direction + // from the impact point to the entity. + windChargeBurstForce = 1.1 +) // NewWindCharge creates a wind charge entity at a position with an owner // entity. Wind charges fly in a straight line (no gravity) and create a burst @@ -25,7 +31,7 @@ func NewWindCharge(opts world.EntitySpawnOpts, owner world.Entity) *world.Entity var windChargeConf = ProjectileBehaviourConfig{ Gravity: 0, - Drag: 0.01, + Drag: 0, Damage: -1, Particle: particle.WindExplosion{}, Sound: sound.WindChargeBurst{}, @@ -46,18 +52,31 @@ func windChargeBurst(e *Ent, tx *world.Tx, target trace.Result) { } } - // Knock back all living entities within the burst radius, including the - // directly-hit entity which receives both damage and burst knockback. + // Apply directional knockback to all living entities within the burst + // radius. The force is applied in the direction from impact to entity, + // so pointing straight down launches vertically while hitting a wall + // pushes horizontally. box := e.H().Type().BBox(e).Translate(pos).Grow(windChargeBurstRadius) for other := range tx.EntitiesWithin(box) { if other.H() == e.H() { continue } l, ok := other.(Living) - if !ok || other.Position().Sub(pos).LenSqr() > windChargeBurstRadius*windChargeBurstRadius { + if !ok { + continue + } + // Use the entity's BBox center for direction so that ground-level + // impacts always have an upward component. + bb := other.H().Type().BBox(other) + center := other.Position().Add(mgl64.Vec3{0, (bb.Min()[1] + bb.Max()[1]) / 2, 0}) + dir := center.Sub(pos) + if dir.LenSqr() > windChargeBurstRadius*windChargeBurstRadius { continue } - l.KnockBack(pos, 0.45, 0.3608) + if dir.LenSqr() == 0 { + dir = mgl64.Vec3{0, 1, 0} + } + l.SetVelocity(l.Velocity().Add(dir.Normalize().Mul(windChargeBurstForce))) } // Toggle interactive blocks at the impact point. diff --git a/server/item/wind_charge.go b/server/item/wind_charge.go index 25f602294..f05b15e00 100644 --- a/server/item/wind_charge.go +++ b/server/item/wind_charge.go @@ -13,7 +13,7 @@ type WindCharge struct{} // Use ... func (WindCharge) Use(tx *world.Tx, user User, ctx *UseContext) bool { create := tx.World().EntityRegistry().Config().WindCharge - opts := world.EntitySpawnOpts{Position: eyePosition(user), Velocity: user.Rotation().Vec3().Mul(1.5)} + opts := world.EntitySpawnOpts{Position: eyePosition(user), Velocity: user.Rotation().Vec3().Mul(3.0)} tx.AddEntity(create(opts, user)) tx.PlaySound(user.Position(), sound.ItemThrow{}) From bd94e902bd7667529e8d934ab9f3eac17924ca7a Mon Sep 17 00:00:00 2001 From: HashimTheArab Date: Mon, 16 Mar 2026 03:55:58 -0400 Subject: [PATCH 3/5] refactor: physics logic --- server/entity/wind_charge.go | 47 +++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/server/entity/wind_charge.go b/server/entity/wind_charge.go index a985aba68..3b09d4e80 100644 --- a/server/entity/wind_charge.go +++ b/server/entity/wind_charge.go @@ -7,17 +7,11 @@ import ( "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" ) -const ( - // windChargeBurstRadius is the radius within which entities are knocked - // back by a wind charge burst. - windChargeBurstRadius = 2.0 - // windChargeBurstForce is the force applied to entities in the direction - // from the impact point to the entity. - windChargeBurstForce = 1.1 -) +// windChargeBurstRadius is the maximum radius within which entities are +// knocked back by a wind charge burst. +const windChargeBurstRadius = 2.5 // NewWindCharge creates a wind charge entity at a position with an owner // entity. Wind charges fly in a straight line (no gravity) and create a burst @@ -52,10 +46,9 @@ func windChargeBurst(e *Ent, tx *world.Tx, target trace.Result) { } } - // Apply directional knockback to all living entities within the burst - // radius. The force is applied in the direction from impact to entity, - // so pointing straight down launches vertically while hitting a wall - // pushes horizontally. + // Apply knockback to all living entities within the burst radius. Impact + // scales with distance (closer = stronger) and is split into horizontal + // and vertical components. box := e.H().Type().BBox(e).Translate(pos).Grow(windChargeBurstRadius) for other := range tx.EntitiesWithin(box) { if other.H() == e.H() { @@ -65,18 +58,28 @@ func windChargeBurst(e *Ent, tx *world.Tx, target trace.Result) { if !ok { continue } - // Use the entity's BBox center for direction so that ground-level - // impacts always have an upward component. - bb := other.H().Type().BBox(other) - center := other.Position().Add(mgl64.Vec3{0, (bb.Min()[1] + bb.Max()[1]) / 2, 0}) - dir := center.Sub(pos) - if dir.LenSqr() > windChargeBurstRadius*windChargeBurstRadius { + entityPos := other.Position() + dist := entityPos.Sub(pos).Len() + impact := 1.3 - dist/windChargeBurstRadius + if impact <= 0 { continue } - if dir.LenSqr() == 0 { - dir = mgl64.Vec3{0, 1, 0} + + vel := l.Velocity() + // If the entity is directly above the impact, apply a flat upward + // boost. Otherwise split into horizontal and vertical components. + dx := entityPos[0] - pos[0] + dz := entityPos[2] - pos[2] + if dx*dx+dz*dz < 0.01 { + vel[1] += 1.1 + } else { + dir := entityPos.Sub(pos) + dir[1] = 0 + dir = dir.Normalize() + vel = vel.Add(dir.Mul(impact)) + vel[1] += impact * 0.4 } - l.SetVelocity(l.Velocity().Add(dir.Normalize().Mul(windChargeBurstForce))) + l.SetVelocity(vel) } // Toggle interactive blocks at the impact point. From afb92e8734455dca471e08525ac6481482af2d61 Mon Sep 17 00:00:00 2001 From: HashimTheArab Date: Fri, 20 Mar 2026 19:33:12 -0400 Subject: [PATCH 4/5] comments --- server/entity/wind_charge.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server/entity/wind_charge.go b/server/entity/wind_charge.go index 3b09d4e80..141c7eefc 100644 --- a/server/entity/wind_charge.go +++ b/server/entity/wind_charge.go @@ -23,6 +23,8 @@ func NewWindCharge(opts world.EntitySpawnOpts, owner world.Entity) *world.Entity return opts.New(WindChargeType, conf) } +// TODO: Wind charges should have increased drag when travelling through water +// or lava, but per-medium drag is not yet supported by ProjectileBehaviour. var windChargeConf = ProjectileBehaviourConfig{ Gravity: 0, Drag: 0, @@ -89,8 +91,8 @@ func windChargeBurst(e *Ent, tx *world.Tx, target trace.Result) { } // toggleWindChargeBlock toggles a block at pos if it is a door, trapdoor or -// fence gate. Other activatable blocks (chests, crafting tables, etc.) are not -// affected. +// fence gate. +// TODO: Buttons, levers, bells and candles should also be toggled. func toggleWindChargeBlock(pos cube.Pos, face cube.Face, tx *world.Tx) { b := tx.Block(pos) switch b.(type) { From 7544b8e37eace4a02062eee6f7f48221daecc56f Mon Sep 17 00:00:00 2001 From: HashimTheArab Date: Fri, 20 Mar 2026 20:03:09 -0400 Subject: [PATCH 5/5] add interface and remove maxcount --- server/block/block.go | 8 ++++++++ server/block/copper_door.go | 3 +++ server/block/copper_trapdoor.go | 3 +++ server/block/wood_door.go | 3 +++ server/block/wood_fence_gate.go | 3 +++ server/block/wood_trapdoor.go | 3 +++ server/entity/wind_charge.go | 16 ++++------------ server/item/wind_charge.go | 8 ++------ 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/server/block/block.go b/server/block/block.go index c89d76304..70bccf391 100644 --- a/server/block/block.go +++ b/server/block/block.go @@ -20,6 +20,14 @@ type Activatable interface { Activate(pos cube.Pos, clickedFace cube.Face, tx *world.Tx, u item.User, ctx *item.UseContext) bool } +// WindChargeAffected represents a block that is toggled by a wind charge +// burst, such as doors, trapdoors and fence gates. +// TODO: Buttons, levers, bells and candles should also implement this. +type WindChargeAffected interface { + Activatable + WindChargeAffected() +} + // Pickable represents a block that may give a different item then the block itself when picked. type Pickable interface { // Pick returns the item that is picked when the block is picked. diff --git a/server/block/copper_door.go b/server/block/copper_door.go index c73f3f312..b75c7d43f 100644 --- a/server/block/copper_door.go +++ b/server/block/copper_door.go @@ -150,6 +150,9 @@ func (d CopperDoor) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, _ item.Use return true } +// WindChargeAffected ... +func (CopperDoor) WindChargeAffected() {} + func (d CopperDoor) RandomTick(pos cube.Pos, tx *world.Tx, r *rand.Rand) { attemptOxidation(pos, tx, r, d) } diff --git a/server/block/copper_trapdoor.go b/server/block/copper_trapdoor.go index 919e1a091..6fbfc4088 100644 --- a/server/block/copper_trapdoor.go +++ b/server/block/copper_trapdoor.go @@ -93,6 +93,9 @@ func (t CopperTrapdoor) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, _ item return true } +// WindChargeAffected ... +func (CopperTrapdoor) WindChargeAffected() {} + func (t CopperTrapdoor) RandomTick(pos cube.Pos, tx *world.Tx, r *rand.Rand) { attemptOxidation(pos, tx, r, t) } diff --git a/server/block/wood_door.go b/server/block/wood_door.go index ea23271b7..072cfb97a 100644 --- a/server/block/wood_door.go +++ b/server/block/wood_door.go @@ -119,6 +119,9 @@ func (d WoodDoor) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, _ item.User, return true } +// WindChargeAffected ... +func (WoodDoor) WindChargeAffected() {} + // BreakInfo ... func (d WoodDoor) BreakInfo() BreakInfo { return newBreakInfo(3, alwaysHarvestable, axeEffective, oneOf(d)) diff --git a/server/block/wood_fence_gate.go b/server/block/wood_fence_gate.go index be74b9bb9..703be3b9c 100644 --- a/server/block/wood_fence_gate.go +++ b/server/block/wood_fence_gate.go @@ -92,6 +92,9 @@ func (f WoodFenceGate) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, u item. return true } +// WindChargeAffected ... +func (WoodFenceGate) WindChargeAffected() {} + // SideClosed ... func (f WoodFenceGate) SideClosed(cube.Pos, cube.Pos, *world.Tx) bool { return false diff --git a/server/block/wood_trapdoor.go b/server/block/wood_trapdoor.go index e525fe7a9..f3ab3e667 100644 --- a/server/block/wood_trapdoor.go +++ b/server/block/wood_trapdoor.go @@ -67,6 +67,9 @@ func (t WoodTrapdoor) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, _ item.U return true } +// WindChargeAffected ... +func (WoodTrapdoor) WindChargeAffected() {} + // BreakInfo ... func (t WoodTrapdoor) BreakInfo() BreakInfo { return newBreakInfo(3, alwaysHarvestable, axeEffective, oneOf(t)) diff --git a/server/entity/wind_charge.go b/server/entity/wind_charge.go index 141c7eefc..04fd6413e 100644 --- a/server/entity/wind_charge.go +++ b/server/entity/wind_charge.go @@ -86,18 +86,10 @@ func windChargeBurst(e *Ent, tx *world.Tx, target trace.Result) { // Toggle interactive blocks at the impact point. if r, ok := target.(trace.BlockResult); ok { - toggleWindChargeBlock(r.BlockPosition(), r.Face(), tx) - } -} - -// toggleWindChargeBlock toggles a block at pos if it is a door, trapdoor or -// fence gate. -// TODO: Buttons, levers, bells and candles should also be toggled. -func toggleWindChargeBlock(pos cube.Pos, face cube.Face, tx *world.Tx) { - b := tx.Block(pos) - switch b.(type) { - case block.WoodDoor, block.CopperDoor, block.WoodTrapdoor, block.CopperTrapdoor, block.WoodFenceGate: - b.(block.Activatable).Activate(pos, face, tx, nil, nil) + pos := r.BlockPosition() + if b, ok := tx.Block(pos).(block.WindChargeAffected); ok { + b.Activate(pos, r.Face(), tx, nil, nil) + } } } diff --git a/server/item/wind_charge.go b/server/item/wind_charge.go index f05b15e00..914a4b152 100644 --- a/server/item/wind_charge.go +++ b/server/item/wind_charge.go @@ -1,9 +1,10 @@ package item import ( + "time" + "github.com/df-mc/dragonfly/server/world" "github.com/df-mc/dragonfly/server/world/sound" - "time" ) // WindCharge is a throwable item that creates a burst of wind on impact, knocking back nearby entities and @@ -26,11 +27,6 @@ func (WindCharge) Cooldown() time.Duration { return time.Millisecond * 500 } -// MaxCount ... -func (WindCharge) MaxCount() int { - return 64 -} - // EncodeItem ... func (WindCharge) EncodeItem() (name string, meta int16) { return "minecraft:wind_charge", 0