github.com/df-mc/dragonfly@v0.9.13/server/block/blast_furnace.go (about) 1 package block 2 3 import ( 4 "github.com/df-mc/dragonfly/server/block/cube" 5 "github.com/df-mc/dragonfly/server/internal/nbtconv" 6 "github.com/df-mc/dragonfly/server/item" 7 "github.com/df-mc/dragonfly/server/world" 8 "github.com/df-mc/dragonfly/server/world/sound" 9 "github.com/go-gl/mathgl/mgl64" 10 "math/rand" 11 "time" 12 ) 13 14 // BlastFurnace is a block that smelts ores, raw metals, iron and gold armor and tools, similar to a furnace, but at 15 // twice the speed. It also serves as an armorer's job site block. 16 // The empty value of BlastFurnace is not valid. It must be created using block.NewBlastFurnace(cube.Face). 17 type BlastFurnace struct { 18 solid 19 bassDrum 20 *smelter 21 22 // Facing is the direction the blast furnace is facing. 23 Facing cube.Face 24 // Lit is true if the blast furnace is lit. 25 Lit bool 26 } 27 28 // NewBlastFurnace creates a new initialised blast furnace. The smelter is properly initialised. 29 func NewBlastFurnace(face cube.Face) BlastFurnace { 30 return BlastFurnace{ 31 Facing: face, 32 smelter: newSmelter(), 33 } 34 } 35 36 // Tick is called to check if the blast furnace should update and start or stop smelting. 37 func (b BlastFurnace) Tick(_ int64, pos cube.Pos, w *world.World) { 38 if b.Lit && rand.Float64() <= 0.016 { // Every three or so seconds. 39 w.PlaySound(pos.Vec3Centre(), sound.BlastFurnaceCrackle{}) 40 } 41 if lit := b.smelter.tickSmelting(time.Second*5, time.Millisecond*200, b.Lit, func(i item.SmeltInfo) bool { 42 return i.Ores 43 }); b.Lit != lit { 44 b.Lit = lit 45 w.SetBlock(pos, b, nil) 46 } 47 } 48 49 // EncodeItem ... 50 func (b BlastFurnace) EncodeItem() (name string, meta int16) { 51 return "minecraft:blast_furnace", 0 52 } 53 54 // EncodeBlock ... 55 func (b BlastFurnace) EncodeBlock() (name string, properties map[string]interface{}) { 56 if b.Lit { 57 return "minecraft:lit_blast_furnace", map[string]interface{}{"minecraft:cardinal_direction": b.Facing.String()} 58 } 59 return "minecraft:blast_furnace", map[string]interface{}{"minecraft:cardinal_direction": b.Facing.String()} 60 } 61 62 // UseOnBlock ... 63 func (b BlastFurnace) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) bool { 64 pos, _, used := firstReplaceable(w, pos, face, b) 65 if !used { 66 return false 67 } 68 69 place(w, pos, NewBlastFurnace(user.Rotation().Direction().Face().Opposite()), user, ctx) 70 return placed(ctx) 71 } 72 73 // BreakInfo ... 74 func (b BlastFurnace) BreakInfo() BreakInfo { 75 xp := b.Experience() 76 return newBreakInfo(3.5, alwaysHarvestable, pickaxeEffective, oneOf(b)).withXPDropRange(xp, xp) 77 } 78 79 // Activate ... 80 func (b BlastFurnace) Activate(pos cube.Pos, _ cube.Face, _ *world.World, u item.User, _ *item.UseContext) bool { 81 if opener, ok := u.(ContainerOpener); ok { 82 opener.OpenBlockContainer(pos) 83 return true 84 } 85 return false 86 } 87 88 // EncodeNBT ... 89 func (b BlastFurnace) EncodeNBT() map[string]interface{} { 90 if b.smelter == nil { 91 //noinspection GoAssignmentToReceiver 92 b = NewBlastFurnace(b.Facing) 93 } 94 remaining, maximum, cook := b.Durations() 95 return map[string]interface{}{ 96 "BurnTime": int16(remaining.Milliseconds() / 50), 97 "CookTime": int16(cook.Milliseconds() / 50), 98 "BurnDuration": int16(maximum.Milliseconds() / 50), 99 "StoredXPInt": int16(b.Experience()), 100 "Items": nbtconv.InvToNBT(b.Inventory()), 101 "id": "BlastFurnace", 102 } 103 } 104 105 // DecodeNBT ... 106 func (b BlastFurnace) DecodeNBT(data map[string]interface{}) interface{} { 107 remaining := nbtconv.TickDuration[int16](data, "BurnTime") 108 maximum := nbtconv.TickDuration[int16](data, "BurnDuration") 109 cook := nbtconv.TickDuration[int16](data, "CookTime") 110 111 xp := int(nbtconv.Int16(data, "StoredXPInt")) 112 lit := b.Lit 113 114 //noinspection GoAssignmentToReceiver 115 b = NewBlastFurnace(b.Facing) 116 b.Lit = lit 117 b.setExperience(xp) 118 b.setDurations(remaining, maximum, cook) 119 nbtconv.InvFromNBT(b.Inventory(), nbtconv.Slice(data, "Items")) 120 return b 121 } 122 123 // allBlastFurnaces ... 124 func allBlastFurnaces() (furnaces []world.Block) { 125 for _, face := range cube.HorizontalFaces() { 126 furnaces = append(furnaces, BlastFurnace{Facing: face}) 127 furnaces = append(furnaces, BlastFurnace{Facing: face, Lit: true}) 128 } 129 return 130 }