github.com/df-mc/dragonfly@v0.9.13/server/block/sugar_cane.go (about)

     1  package block
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/df-mc/dragonfly/server/item"
     6  	"github.com/df-mc/dragonfly/server/world"
     7  	"github.com/df-mc/dragonfly/server/world/particle"
     8  	"github.com/go-gl/mathgl/mgl64"
     9  	"math/rand"
    10  )
    11  
    12  // SugarCane is a plant block that generates naturally near water.
    13  type SugarCane struct {
    14  	empty
    15  	transparent
    16  
    17  	// Age is the growth state of sugar cane. Values range from 0 to 15.
    18  	Age int
    19  }
    20  
    21  // UseOnBlock ensures the placement of the block is OK.
    22  func (c SugarCane) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
    23  	pos, _, used = firstReplaceable(w, pos, face, c)
    24  	if !used {
    25  		return false
    26  	}
    27  	if !c.canGrowHere(pos, w, true) {
    28  		return false
    29  	}
    30  
    31  	place(w, pos, c, user, ctx)
    32  	return placed(ctx)
    33  }
    34  
    35  // NeighbourUpdateTick ...
    36  func (c SugarCane) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) {
    37  	if !c.canGrowHere(pos, w, true) {
    38  		w.SetBlock(pos, nil, nil)
    39  		w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: c})
    40  		dropItem(w, item.NewStack(c, 1), pos.Vec3Centre())
    41  	}
    42  }
    43  
    44  // RandomTick ...
    45  func (c SugarCane) RandomTick(pos cube.Pos, w *world.World, r *rand.Rand) {
    46  	if c.Age < 15 {
    47  		c.Age++
    48  	} else if c.Age == 15 {
    49  		c.Age = 0
    50  		if c.canGrowHere(pos.Side(cube.FaceDown), w, false) {
    51  			for y := 1; y < 3; y++ {
    52  				if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Air); ok {
    53  					w.SetBlock(pos.Add(cube.Pos{0, y}), SugarCane{}, nil)
    54  					break
    55  				} else if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(SugarCane); !ok {
    56  					break
    57  				}
    58  			}
    59  		}
    60  	}
    61  	w.SetBlock(pos, c, nil)
    62  }
    63  
    64  // BoneMeal ...
    65  func (c SugarCane) BoneMeal(pos cube.Pos, w *world.World) bool {
    66  	for _, ok := w.Block(pos.Side(cube.FaceDown)).(SugarCane); ok; _, ok = w.Block(pos.Side(cube.FaceDown)).(SugarCane) {
    67  		pos = pos.Side(cube.FaceDown)
    68  	}
    69  	if c.canGrowHere(pos.Side(cube.FaceDown), w, false) {
    70  		for y := 1; y < 3; y++ {
    71  			if _, ok := w.Block(pos.Add(cube.Pos{0, y})).(Air); ok {
    72  				w.SetBlock(pos.Add(cube.Pos{0, y}), SugarCane{}, nil)
    73  			}
    74  		}
    75  		return true
    76  	}
    77  	return false
    78  }
    79  
    80  // canGrowHere implements logic to check if sugar cane can live/grow here.
    81  func (c SugarCane) canGrowHere(pos cube.Pos, w *world.World, recursive bool) bool {
    82  	if _, ok := w.Block(pos.Side(cube.FaceDown)).(SugarCane); ok && recursive {
    83  		return c.canGrowHere(pos.Side(cube.FaceDown), w, recursive)
    84  	}
    85  
    86  	if supportsVegetation(c, w.Block(pos.Sub(cube.Pos{0, 1}))) {
    87  		for _, face := range cube.HorizontalFaces() {
    88  			if liquid, ok := w.Liquid(pos.Side(face).Side(cube.FaceDown)); ok {
    89  				if _, ok := liquid.(Water); ok {
    90  					return true
    91  				}
    92  			}
    93  		}
    94  	}
    95  	return false
    96  }
    97  
    98  // HasLiquidDrops ...
    99  func (c SugarCane) HasLiquidDrops() bool {
   100  	return true
   101  }
   102  
   103  // BreakInfo ...
   104  func (c SugarCane) BreakInfo() BreakInfo {
   105  	return newBreakInfo(0, alwaysHarvestable, nothingEffective, oneOf(c))
   106  }
   107  
   108  // EncodeItem ...
   109  func (c SugarCane) EncodeItem() (name string, meta int16) {
   110  	return "minecraft:sugar_cane", 0
   111  }
   112  
   113  // EncodeBlock ...
   114  func (c SugarCane) EncodeBlock() (name string, properties map[string]any) {
   115  	return "minecraft:reeds", map[string]any{"age": int32(c.Age)}
   116  }
   117  
   118  // allSugarCane returns all possible states of a sugar cane block.
   119  func allSugarCane() (b []world.Block) {
   120  	for i := 0; i < 16; i++ {
   121  		b = append(b, SugarCane{Age: i})
   122  	}
   123  	return
   124  }