github.com/df-mc/dragonfly@v0.9.13/server/block/smoker.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  // Smoker is a type of furnace that cooks food items, similar to a furnace, but twice as fast. It also serves as a
    15  // butcher's job site block.
    16  // The empty value of Smoker is not valid. It must be created using block.NewSmoker(cube.Face).
    17  type Smoker struct {
    18  	solid
    19  	bassDrum
    20  	*smelter
    21  
    22  	// Facing is the direction the smoker is facing.
    23  	Facing cube.Face
    24  	// Lit is true if the smoker is lit.
    25  	Lit bool
    26  }
    27  
    28  // NewSmoker creates a new initialised smoker. The smelter is properly initialised.
    29  func NewSmoker(face cube.Face) Smoker {
    30  	return Smoker{
    31  		Facing:  face,
    32  		smelter: newSmelter(),
    33  	}
    34  }
    35  
    36  // Tick is called to check if the smoker should update and start or stop smelting.
    37  func (s Smoker) Tick(_ int64, pos cube.Pos, w *world.World) {
    38  	if s.Lit && rand.Float64() <= 0.016 { // Every three or so seconds.
    39  		w.PlaySound(pos.Vec3Centre(), sound.SmokerCrackle{})
    40  	}
    41  	if lit := s.smelter.tickSmelting(time.Second*5, time.Millisecond*200, s.Lit, func(i item.SmeltInfo) bool {
    42  		return i.Food
    43  	}); s.Lit != lit {
    44  		s.Lit = lit
    45  		w.SetBlock(pos, s, nil)
    46  	}
    47  }
    48  
    49  // EncodeItem ...
    50  func (s Smoker) EncodeItem() (name string, meta int16) {
    51  	return "minecraft:smoker", 0
    52  }
    53  
    54  // EncodeBlock ...
    55  func (s Smoker) EncodeBlock() (name string, properties map[string]interface{}) {
    56  	if s.Lit {
    57  		return "minecraft:lit_smoker", map[string]interface{}{"minecraft:cardinal_direction": s.Facing.String()}
    58  	}
    59  	return "minecraft:smoker", map[string]interface{}{"minecraft:cardinal_direction": s.Facing.String()}
    60  }
    61  
    62  // UseOnBlock ...
    63  func (s Smoker) 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, s)
    65  	if !used {
    66  		return false
    67  	}
    68  
    69  	place(w, pos, NewSmoker(user.Rotation().Direction().Face().Opposite()), user, ctx)
    70  	return placed(ctx)
    71  }
    72  
    73  // BreakInfo ...
    74  func (s Smoker) BreakInfo() BreakInfo {
    75  	xp := s.Experience()
    76  	return newBreakInfo(3.5, alwaysHarvestable, pickaxeEffective, oneOf(s)).withXPDropRange(xp, xp)
    77  }
    78  
    79  // Activate ...
    80  func (s Smoker) 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 (s Smoker) EncodeNBT() map[string]interface{} {
    90  	if s.smelter == nil {
    91  		//noinspection GoAssignmentToReceiver
    92  		s = NewSmoker(s.Facing)
    93  	}
    94  	remaining, maximum, cook := s.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(s.Experience()),
   100  		"Items":        nbtconv.InvToNBT(s.Inventory()),
   101  		"id":           "Smoker",
   102  	}
   103  }
   104  
   105  // DecodeNBT ...
   106  func (s Smoker) 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 := s.Lit
   113  
   114  	//noinspection GoAssignmentToReceiver
   115  	s = NewSmoker(s.Facing)
   116  	s.Lit = lit
   117  	s.setExperience(xp)
   118  	s.setDurations(remaining, maximum, cook)
   119  	nbtconv.InvFromNBT(s.Inventory(), nbtconv.Slice(data, "Items"))
   120  	return s
   121  }
   122  
   123  // allSmokers ...
   124  func allSmokers() (smokers []world.Block) {
   125  	for _, face := range cube.HorizontalFaces() {
   126  		smokers = append(smokers, Smoker{Facing: face})
   127  		smokers = append(smokers, Smoker{Facing: face, Lit: true})
   128  	}
   129  	return
   130  }