github.com/df-mc/dragonfly@v0.9.13/server/block/leaves.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/go-gl/mathgl/mgl64"
     8  	"math/rand"
     9  )
    10  
    11  // Leaves are blocks that grow as part of trees which mainly drop saplings and sticks.
    12  type Leaves struct {
    13  	leaves
    14  	sourceWaterDisplacer
    15  
    16  	// Wood is the type of wood of the leaves. This field must have one of the values found in the material
    17  	// package.
    18  	Wood WoodType
    19  	// Persistent specifies if the leaves are persistent, meaning they will not decay as a result of no wood
    20  	// being nearby.
    21  	Persistent bool
    22  
    23  	ShouldUpdate bool
    24  }
    25  
    26  // UseOnBlock makes leaves persistent when they are placed so that they don't decay.
    27  func (l Leaves) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
    28  	pos, _, used = firstReplaceable(w, pos, face, l)
    29  	if !used {
    30  		return
    31  	}
    32  	l.Persistent = true
    33  
    34  	place(w, pos, l, user, ctx)
    35  	return placed(ctx)
    36  }
    37  
    38  // findLog ...
    39  func findLog(pos cube.Pos, w *world.World, visited *[]cube.Pos, distance int) bool {
    40  	for _, v := range *visited {
    41  		if v == pos {
    42  			return false
    43  		}
    44  	}
    45  	*visited = append(*visited, pos)
    46  
    47  	if log, ok := w.Block(pos).(Log); ok && !log.Stripped {
    48  		return true
    49  	}
    50  	if _, ok := w.Block(pos).(Leaves); !ok || distance > 6 {
    51  		return false
    52  	}
    53  	logFound := false
    54  	pos.Neighbours(func(neighbour cube.Pos) {
    55  		if !logFound && findLog(neighbour, w, visited, distance+1) {
    56  			logFound = true
    57  		}
    58  	}, w.Range())
    59  	return logFound
    60  }
    61  
    62  // RandomTick ...
    63  func (l Leaves) RandomTick(pos cube.Pos, w *world.World, _ *rand.Rand) {
    64  	if !l.Persistent && l.ShouldUpdate {
    65  		if findLog(pos, w, &[]cube.Pos{}, 0) {
    66  			l.ShouldUpdate = false
    67  			w.SetBlock(pos, l, nil)
    68  		} else {
    69  			w.SetBlock(pos, nil, nil)
    70  		}
    71  	}
    72  }
    73  
    74  // NeighbourUpdateTick ...
    75  func (l Leaves) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) {
    76  	if !l.Persistent && !l.ShouldUpdate {
    77  		l.ShouldUpdate = true
    78  		w.SetBlock(pos, l, nil)
    79  	}
    80  }
    81  
    82  // FlammabilityInfo ...
    83  func (l Leaves) FlammabilityInfo() FlammabilityInfo {
    84  	return newFlammabilityInfo(30, 60, true)
    85  }
    86  
    87  // BreakInfo ...
    88  func (l Leaves) BreakInfo() BreakInfo {
    89  	return newBreakInfo(0.2, alwaysHarvestable, func(t item.Tool) bool {
    90  		return t.ToolType() == item.TypeShears || t.ToolType() == item.TypeHoe
    91  	}, func(t item.Tool, enchantments []item.Enchantment) []item.Stack {
    92  		if t.ToolType() == item.TypeShears || hasSilkTouch(enchantments) {
    93  			return []item.Stack{item.NewStack(l, 1)}
    94  		}
    95  		var drops []item.Stack
    96  		if (l.Wood == OakWood() || l.Wood == DarkOakWood()) && rand.Float64() < 0.005 {
    97  			drops = append(drops, item.NewStack(item.Apple{}, 1))
    98  		}
    99  		// TODO: Saplings and sticks can drop along with apples
   100  		return drops
   101  	})
   102  }
   103  
   104  // CompostChance ...
   105  func (Leaves) CompostChance() float64 {
   106  	return 0.3
   107  }
   108  
   109  // EncodeItem ...
   110  func (l Leaves) EncodeItem() (name string, meta int16) {
   111  	switch l.Wood {
   112  	case OakWood(), SpruceWood(), BirchWood(), JungleWood():
   113  		return "minecraft:leaves", int16(l.Wood.Uint8())
   114  	case AcaciaWood(), DarkOakWood():
   115  		return "minecraft:leaves2", int16(l.Wood.Uint8() - 4)
   116  	default:
   117  		return "minecraft:" + l.Wood.String() + "_leaves", 0
   118  	}
   119  }
   120  
   121  // LightDiffusionLevel ...
   122  func (Leaves) LightDiffusionLevel() uint8 {
   123  	return 1
   124  }
   125  
   126  // SideClosed ...
   127  func (Leaves) SideClosed(cube.Pos, cube.Pos, *world.World) bool {
   128  	return false
   129  }
   130  
   131  // EncodeBlock ...
   132  func (l Leaves) EncodeBlock() (name string, properties map[string]any) {
   133  	switch l.Wood {
   134  	case OakWood(), SpruceWood(), BirchWood(), JungleWood():
   135  		return "minecraft:leaves", map[string]any{"old_leaf_type": l.Wood.String(), "persistent_bit": l.Persistent, "update_bit": l.ShouldUpdate}
   136  	case AcaciaWood(), DarkOakWood():
   137  		return "minecraft:leaves2", map[string]any{"new_leaf_type": l.Wood.String(), "persistent_bit": l.Persistent, "update_bit": l.ShouldUpdate}
   138  	default:
   139  		return "minecraft:" + l.Wood.String() + "_leaves", map[string]any{"persistent_bit": l.Persistent, "update_bit": l.ShouldUpdate}
   140  	}
   141  }
   142  
   143  // allLogs returns a list of all possible leaves states.
   144  func allLeaves() (leaves []world.Block) {
   145  	f := func(persistent, update bool) {
   146  		for _, w := range WoodTypes() {
   147  			if w != CrimsonWood() && w != WarpedWood() {
   148  				leaves = append(leaves, Leaves{Wood: w, Persistent: persistent, ShouldUpdate: update})
   149  			}
   150  		}
   151  	}
   152  	f(true, true)
   153  	f(true, false)
   154  	f(false, true)
   155  	f(false, false)
   156  	return
   157  }