26ed99fda6
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
99 lines
3.5 KiB
Go
99 lines
3.5 KiB
Go
package entity
|
|
|
|
import (
|
|
"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/item/enchantment"
|
|
"github.com/df-mc/dragonfly/server/item/potion"
|
|
"github.com/df-mc/dragonfly/server/world"
|
|
"github.com/df-mc/dragonfly/server/world/sound"
|
|
)
|
|
|
|
// NewArrow creates a new Arrow and returns it. It is equivalent to calling NewTippedArrow with `potion.Potion{}` as
|
|
// tip.
|
|
func NewArrow(opts world.EntitySpawnOpts, owner world.Entity) *world.EntityHandle {
|
|
return NewTippedArrowWithDamage(opts, 2.0, owner, potion.Potion{})
|
|
}
|
|
|
|
// NewArrowWithDamage creates a new Arrow with the given base damage, and returns it. It is equivalent to calling
|
|
// NewTippedArrowWithDamage with `potion.Potion{}` as tip.
|
|
func NewArrowWithDamage(opts world.EntitySpawnOpts, damage float64, owner world.Entity) *world.EntityHandle {
|
|
return NewTippedArrowWithDamage(opts, damage, owner, potion.Potion{})
|
|
}
|
|
|
|
// NewTippedArrow creates a new Arrow with a potion effect added to an entity when hit.
|
|
func NewTippedArrow(opts world.EntitySpawnOpts, owner world.Entity, tip potion.Potion) *world.EntityHandle {
|
|
return NewTippedArrowWithDamage(opts, 2.0, owner, tip)
|
|
}
|
|
|
|
// NewTippedArrowWithDamage creates a new Arrow with a potion effect added to an entity when hit and, and returns it.
|
|
// It uses the given damage as the base damage.
|
|
func NewTippedArrowWithDamage(opts world.EntitySpawnOpts, damage float64, owner world.Entity, tip potion.Potion) *world.EntityHandle {
|
|
conf := arrowConf
|
|
conf.Damage = damage
|
|
conf.Potion = tip
|
|
conf.Owner = owner.H()
|
|
return opts.New(ArrowType, conf)
|
|
}
|
|
|
|
var arrowConf = ProjectileBehaviourConfig{
|
|
Gravity: 0.05,
|
|
Drag: 0.01,
|
|
Damage: 2.0,
|
|
Sound: sound.ArrowHit{},
|
|
SurviveBlockCollision: true,
|
|
}
|
|
|
|
// boolByte returns 1 if the bool passed is true, or 0 if it is false.
|
|
func boolByte(b bool) uint8 {
|
|
if b {
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ArrowType is a world.EntityType implementation for Arrow.
|
|
var ArrowType arrowType
|
|
|
|
type arrowType struct{}
|
|
|
|
func (t arrowType) Open(tx *world.Tx, handle *world.EntityHandle, data *world.EntityData) world.Entity {
|
|
return &Ent{tx: tx, handle: handle, data: data}
|
|
}
|
|
|
|
func (arrowType) EncodeEntity() string { return "minecraft:arrow" }
|
|
func (arrowType) BBox(world.Entity) cube.BBox {
|
|
return cube.Box(-0.125, 0, -0.125, 0.125, 0.25, 0.125)
|
|
}
|
|
|
|
func (arrowType) DecodeNBT(m map[string]any, data *world.EntityData) {
|
|
conf := arrowConf
|
|
conf.Damage = float64(nbtconv.Float32(m, "Damage"))
|
|
conf.Potion = potion.From(nbtconv.Int32(m, "auxValue") - 1)
|
|
conf.DisablePickup = !nbtconv.Bool(m, "player")
|
|
if !nbtconv.Bool(m, "isCreative") {
|
|
conf.PickupItem = item.NewStack(item.Arrow{Tip: conf.Potion}, 1)
|
|
}
|
|
conf.KnockBackForceAddend = enchantment.Punch.KnockBackMultiplier() * float64(nbtconv.Uint8(m, "enchantPunch"))
|
|
conf.CollisionPosition = nbtconv.Pos(m, "StuckToBlockPos")
|
|
|
|
data.Data = conf.New()
|
|
}
|
|
|
|
func (arrowType) EncodeNBT(data *world.EntityData) map[string]any {
|
|
b := data.Data.(*ProjectileBehaviour)
|
|
m := map[string]any{
|
|
"Damage": float32(b.conf.Damage),
|
|
"enchantPunch": byte(b.conf.KnockBackForceAddend / enchantment.Punch.KnockBackMultiplier()),
|
|
"auxValue": int32(b.conf.Potion.Uint8() + 1),
|
|
"player": boolByte(!b.conf.DisablePickup),
|
|
"isCreative": boolByte(b.conf.PickupItem.Empty()),
|
|
}
|
|
// TODO: Save critical flag if Minecraft ever saves it?
|
|
if b.collided {
|
|
m["StuckToBlockPos"] = nbtconv.PosToInt32Slice(b.collisionPos)
|
|
}
|
|
return m
|
|
}
|