Files
mc/server/block/blast_furnace.go
T
TarnaWijaya 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
up3
2026-07-09 08:33:57 +08:00

143 lines
4.3 KiB
Go

package block
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/world"
"github.com/df-mc/dragonfly/server/world/sound"
"github.com/go-gl/mathgl/mgl64"
"math/rand/v2"
"time"
)
// BlastFurnace is a block that smelts ores, raw metals, iron and gold armour and tools, similar to a furnace, but at
// twice the speed. It also serves as an armourer's job site block.
// The empty value of BlastFurnace is not valid. It must be created using block.NewBlastFurnace(cube.Face).
type BlastFurnace struct {
solid
bassDrum
*smelter
// Facing is the direction the blast furnace is facing.
Facing cube.Direction
// Lit is true if the blast furnace is lit.
Lit bool
}
// NewBlastFurnace creates a new initialised blast furnace. The smelter is properly initialised.
func NewBlastFurnace(face cube.Direction) BlastFurnace {
return BlastFurnace{
Facing: face,
smelter: newSmelter(),
}
}
// Tick is called to check if the blast furnace should update and start or stop smelting.
func (b BlastFurnace) Tick(_ int64, pos cube.Pos, tx *world.Tx) {
if b.Lit && rand.Float64() <= 0.016 { // Every three or so seconds.
tx.PlaySound(pos.Vec3Centre(), sound.BlastFurnaceCrackle{})
}
if lit := b.tickSmelting(time.Second*5, time.Millisecond*200, b.Lit, func(i item.SmeltInfo) bool {
return i.Ores
}); b.Lit != lit {
b.Lit = lit
tx.SetBlock(pos, b, nil)
}
}
// LightEmissionLevel ...
func (b BlastFurnace) LightEmissionLevel() uint8 {
if b.Lit {
return 13
}
return 0
}
// EncodeItem ...
func (b BlastFurnace) EncodeItem() (name string, meta int16) {
return "minecraft:blast_furnace", 0
}
// EncodeBlock ...
func (b BlastFurnace) EncodeBlock() (name string, properties map[string]interface{}) {
if b.Lit {
return "minecraft:lit_blast_furnace", map[string]interface{}{"minecraft:cardinal_direction": b.Facing.String()}
}
return "minecraft:blast_furnace", map[string]interface{}{"minecraft:cardinal_direction": b.Facing.String()}
}
// UseOnBlock ...
func (b BlastFurnace) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) bool {
pos, _, used := firstReplaceable(tx, pos, face, b)
if !used {
return false
}
place(tx, pos, NewBlastFurnace(user.Rotation().Direction().Opposite()), user, ctx)
return placed(ctx)
}
// BreakInfo ...
func (b BlastFurnace) BreakInfo() BreakInfo {
xp := b.Experience()
return newBreakInfo(3.5, alwaysHarvestable, pickaxeEffective, oneOf(BlastFurnace{})).withXPDropRange(xp, xp).withBreakHandler(func(pos cube.Pos, tx *world.Tx, u item.User) {
for _, i := range b.Inventory(tx, pos).Clear() {
dropItem(tx, i, pos.Vec3())
}
})
}
// Activate ...
func (b BlastFurnace) Activate(pos cube.Pos, _ cube.Face, tx *world.Tx, u item.User, _ *item.UseContext) bool {
if opener, ok := u.(ContainerOpener); ok {
opener.OpenBlockContainer(pos, tx)
return true
}
return false
}
// EncodeNBT ...
func (b BlastFurnace) EncodeNBT() map[string]interface{} {
if b.smelter == nil {
//noinspection GoAssignmentToReceiver
b = NewBlastFurnace(b.Facing)
}
remaining, maximum, cook := b.Durations()
return map[string]interface{}{
"BurnTime": int16(remaining.Milliseconds() / 50),
"CookTime": int16(cook.Milliseconds() / 50),
"BurnDuration": int16(maximum.Milliseconds() / 50),
"StoredXPInt": int16(b.Experience()),
"Items": nbtconv.InvToNBT(b.inventory),
"id": "BlastFurnace",
}
}
// DecodeNBT ...
func (b BlastFurnace) DecodeNBT(data map[string]interface{}) interface{} {
remaining := nbtconv.TickDuration[int16](data, "BurnTime")
maximum := nbtconv.TickDuration[int16](data, "BurnDuration")
cook := nbtconv.TickDuration[int16](data, "CookTime")
xp := int(nbtconv.Int16(data, "StoredXPInt"))
lit := b.Lit
//noinspection GoAssignmentToReceiver
b = NewBlastFurnace(b.Facing)
b.Lit = lit
b.setExperience(xp)
b.setDurations(remaining, maximum, cook)
nbtconv.InvFromNBT(b.inventory, nbtconv.Slice(data, "Items"))
return b
}
// allBlastFurnaces ...
func allBlastFurnaces() (furnaces []world.Block) {
for _, face := range cube.Directions() {
furnaces = append(furnaces, BlastFurnace{Facing: face})
furnaces = append(furnaces, BlastFurnace{Facing: face, Lit: true})
}
return
}