Files
mc/server/block/sea_pickle.go
T
TarnaWijaya 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
up3
2026-07-09 08:33:57 +08:00

184 lines
4.3 KiB
Go

package block
import (
"math"
"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"
)
// SeaPickle is a small stationary underwater block that emits light, and is typically found in colonies of up to
// four sea pickles.
type SeaPickle struct {
empty
transparent
sourceWaterDisplacer
// AdditionalCount is the amount of additional sea pickles clustered together.
AdditionalCount int
// Dead is whether the sea pickles are not alive. Sea pickles are only considered alive when inside of water. While
// alive, sea pickles emit light & can be grown with bone meal.
Dead bool
}
// canSurvive ...
func (SeaPickle) canSurvive(pos cube.Pos, tx *world.Tx) bool {
below := tx.Block(pos.Side(cube.FaceDown))
if !below.Model().FaceSolid(pos.Side(cube.FaceDown), cube.FaceUp, tx) {
return false
}
if liquid, ok := tx.Liquid(pos); ok {
if _, ok = liquid.(Water); !ok || liquid.LiquidDepth() != 8 {
return false
}
}
if emitter, ok := below.(LightDiffuser); ok && emitter.LightDiffusionLevel() != 15 {
return false
}
return true
}
// BoneMeal ...
func (s SeaPickle) BoneMeal(pos cube.Pos, tx *world.Tx) item.BoneMealResult {
if s.Dead {
return item.BoneMealResultNone
}
if coral, ok := tx.Block(pos.Side(cube.FaceDown)).(CoralBlock); !ok || coral.Dead {
return item.BoneMealResultNone
}
if s.AdditionalCount != 3 {
s.AdditionalCount = 3
tx.SetBlock(pos, s, nil)
}
for x := -2; x <= 2; x++ {
distance := -int(math.Abs(float64(x))) + 2
for z := -distance; z <= distance; z++ {
for y := -1; y < 1; y++ {
if (x == 0 && y == 0 && z == 0) || rand.IntN(6) != 0 {
continue
}
newPos := pos.Add(cube.Pos{x, y, z})
if _, ok := tx.Block(newPos).(Water); !ok {
continue
}
if coral, ok := tx.Block(newPos.Side(cube.FaceDown)).(CoralBlock); !ok || coral.Dead {
continue
}
tx.SetBlock(newPos, SeaPickle{AdditionalCount: rand.IntN(3) + 1}, nil)
}
}
}
return item.BoneMealResultSmall
}
// UseOnBlock ...
func (s SeaPickle) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) bool {
if existing, ok := tx.Block(pos).(SeaPickle); ok {
if existing.AdditionalCount >= 3 {
return false
}
existing.AdditionalCount++
place(tx, pos, existing, user, ctx)
return placed(ctx)
}
pos, _, used := firstReplaceable(tx, pos, face, s)
if !used {
return false
}
if !s.canSurvive(pos, tx) {
return false
}
s.Dead = true
if liquid, ok := tx.Liquid(pos); ok {
_, ok = liquid.(Water)
s.Dead = !ok
}
place(tx, pos, s, user, ctx)
return placed(ctx)
}
// NeighbourUpdateTick ...
func (s SeaPickle) NeighbourUpdateTick(pos, _ cube.Pos, tx *world.Tx) {
if !s.canSurvive(pos, tx) {
breakBlock(s, pos, tx)
return
}
alive := false
if liquid, ok := tx.Liquid(pos); ok {
_, alive = liquid.(Water)
}
if s.Dead == alive {
s.Dead = !alive
tx.SetBlock(pos, s, nil)
}
}
// HasLiquidDrops ...
func (SeaPickle) HasLiquidDrops() bool {
return true
}
// SideClosed ...
func (SeaPickle) SideClosed(cube.Pos, cube.Pos, *world.Tx) bool {
return false
}
// LightEmissionLevel ...
func (s SeaPickle) LightEmissionLevel() uint8 {
if s.Dead {
return 0
}
return uint8(6 + s.AdditionalCount*3)
}
// BreakInfo ...
func (s SeaPickle) BreakInfo() BreakInfo {
return newBreakInfo(0, alwaysHarvestable, nothingEffective, simpleDrops(item.NewStack(s, s.AdditionalCount+1)))
}
// FlammabilityInfo ...
func (SeaPickle) FlammabilityInfo() FlammabilityInfo {
return newFlammabilityInfo(15, 100, true)
}
// SmeltInfo ...
func (SeaPickle) SmeltInfo() item.SmeltInfo {
return newSmeltInfo(item.NewStack(item.Dye{Colour: item.ColourLime()}, 1), 0.1)
}
// CompostChance ...
func (SeaPickle) CompostChance() float64 {
return 0.65
}
// EncodeItem ...
func (SeaPickle) EncodeItem() (name string, meta int16) {
return "minecraft:sea_pickle", 0
}
// EncodeBlock ...
func (s SeaPickle) EncodeBlock() (string, map[string]any) {
return "minecraft:sea_pickle", map[string]any{"cluster_count": int32(s.AdditionalCount), "dead_bit": s.Dead}
}
// allSeaPickles ...
func allSeaPickles() (b []world.Block) {
for i := 0; i <= 3; i++ {
b = append(b, SeaPickle{AdditionalCount: i})
b = append(b, SeaPickle{AdditionalCount: i, Dead: true})
}
return
}