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