26ed99fda6
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
156 lines
3.9 KiB
Go
156 lines
3.9 KiB
Go
package block
|
|
|
|
import (
|
|
"math/rand/v2"
|
|
|
|
"github.com/df-mc/dragonfly/server/block/cube"
|
|
"github.com/df-mc/dragonfly/server/item"
|
|
"github.com/df-mc/dragonfly/server/world"
|
|
"github.com/go-gl/mathgl/mgl64"
|
|
)
|
|
|
|
// Kelp is an underwater block which can grow on top of solids underwater.
|
|
type Kelp struct {
|
|
empty
|
|
transparent
|
|
sourceWaterDisplacer
|
|
|
|
// Age is the age of the kelp block which can be 0-25. If age is 25, kelp won't grow any further.
|
|
Age int
|
|
}
|
|
|
|
// SmeltInfo ...
|
|
func (k Kelp) SmeltInfo() item.SmeltInfo {
|
|
return newFoodSmeltInfo(item.NewStack(item.DriedKelp{}, 1), 0.1)
|
|
}
|
|
|
|
// BoneMeal ...
|
|
func (k Kelp) BoneMeal(pos cube.Pos, tx *world.Tx) item.BoneMealResult {
|
|
for y := pos.Y(); y <= tx.Range()[1]; y++ {
|
|
currentPos := cube.Pos{pos.X(), y, pos.Z()}
|
|
block := tx.Block(currentPos)
|
|
if kelp, ok := block.(Kelp); ok {
|
|
if kelp.Age == 25 {
|
|
break
|
|
}
|
|
continue
|
|
}
|
|
if water, ok := block.(Water); ok && water.Depth == 8 {
|
|
tx.SetBlock(currentPos, Kelp{Age: k.Age + 1}, nil)
|
|
return item.BoneMealResultSmall
|
|
}
|
|
break
|
|
}
|
|
return item.BoneMealResultNone
|
|
}
|
|
|
|
// BreakInfo ...
|
|
func (k Kelp) BreakInfo() BreakInfo {
|
|
return newBreakInfo(0, alwaysHarvestable, nothingEffective, oneOf(k))
|
|
}
|
|
|
|
// CompostChance ...
|
|
func (Kelp) CompostChance() float64 {
|
|
return 0.3
|
|
}
|
|
|
|
// EncodeItem ...
|
|
func (Kelp) EncodeItem() (name string, meta int16) {
|
|
return "minecraft:kelp", 0
|
|
}
|
|
|
|
// EncodeBlock ...
|
|
func (k Kelp) EncodeBlock() (name string, properties map[string]any) {
|
|
return "minecraft:kelp", map[string]any{"kelp_age": int32(k.Age)}
|
|
}
|
|
|
|
// SideClosed will always return false since kelp doesn't close any side.
|
|
func (Kelp) SideClosed(cube.Pos, cube.Pos, *world.Tx) bool {
|
|
return false
|
|
}
|
|
|
|
// withRandomAge returns a new Kelp block with its age value randomized between 0 and 24.
|
|
func (k Kelp) withRandomAge() Kelp {
|
|
k.Age = rand.IntN(25)
|
|
return k
|
|
}
|
|
|
|
// UseOnBlock ...
|
|
func (k Kelp) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) (used bool) {
|
|
pos, _, used = firstReplaceable(tx, pos, face, k)
|
|
if !used {
|
|
return
|
|
}
|
|
|
|
below := pos.Side(cube.FaceDown)
|
|
belowBlock := tx.Block(below)
|
|
if _, kelp := belowBlock.(Kelp); !kelp {
|
|
if !belowBlock.Model().FaceSolid(below, cube.FaceUp, tx) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
liquid, ok := tx.Liquid(pos)
|
|
if !ok {
|
|
return false
|
|
} else if _, ok := liquid.(Water); !ok || liquid.LiquidDepth() < 8 {
|
|
return false
|
|
}
|
|
|
|
// When first placed, kelp gets a random age between 0 and 24.
|
|
place(tx, pos, k.withRandomAge(), user, ctx)
|
|
return placed(ctx)
|
|
}
|
|
|
|
// NeighbourUpdateTick ...
|
|
func (k Kelp) NeighbourUpdateTick(pos, changedNeighbour cube.Pos, tx *world.Tx) {
|
|
if _, ok := tx.Liquid(pos); !ok {
|
|
breakBlock(k, pos, tx)
|
|
return
|
|
}
|
|
if changedNeighbour[1]-1 == pos.Y() {
|
|
// When a kelp block is broken above, the kelp block underneath it gets a new random age.
|
|
tx.SetBlock(pos, k.withRandomAge(), nil)
|
|
}
|
|
|
|
below := pos.Side(cube.FaceDown)
|
|
belowBlock := tx.Block(below)
|
|
if _, kelp := belowBlock.(Kelp); !kelp {
|
|
if !belowBlock.Model().FaceSolid(below, cube.FaceUp, tx) {
|
|
breakBlock(k, pos, tx)
|
|
}
|
|
}
|
|
}
|
|
|
|
// RandomTick ...
|
|
func (k Kelp) RandomTick(pos cube.Pos, tx *world.Tx, r *rand.Rand) {
|
|
// Every random tick, there's a 14% chance for Kelp to grow if its age is below 25.
|
|
if r.IntN(100) < 15 && k.Age < 25 {
|
|
abovePos := pos.Side(cube.FaceUp)
|
|
|
|
liquid, ok := tx.Liquid(abovePos)
|
|
|
|
// For kelp to grow, there must be only water above.
|
|
if !ok {
|
|
return
|
|
} else if _, ok := liquid.(Water); ok {
|
|
switch tx.Block(abovePos).(type) {
|
|
case Air, Water:
|
|
tx.SetBlock(abovePos, Kelp{Age: k.Age + 1}, nil)
|
|
if liquid.LiquidDepth() < 8 {
|
|
// When kelp grows into a water block, the water block becomes a source block.
|
|
tx.SetLiquid(abovePos, Water{Still: true, Depth: 8, Falling: false})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// allKelp returns all possible states of a kelp block.
|
|
func allKelp() (b []world.Block) {
|
|
for i := 0; i < 26; i++ {
|
|
b = append(b, Kelp{Age: i})
|
|
}
|
|
return
|
|
}
|