From 304cd7cd8b934ed668df00a6796ce4644487afbf Mon Sep 17 00:00:00 2001 From: MEMOxiiii <189345814+MEMOxiiii@users.noreply.github.com> Date: Sun, 16 Aug 2026 14:19:35 +0300 Subject: [PATCH] add mycelium --- server/block/dirt.go | 34 ++++++++++++++++++++++++ server/block/grass.go | 31 +--------------------- server/block/hash.go | 5 ++++ server/block/mycelium.go | 47 ++++++++++++++++++++++++++++++++++ server/block/nether_sprouts.go | 4 +-- server/block/register.go | 2 ++ 6 files changed, 91 insertions(+), 32 deletions(-) create mode 100644 server/block/mycelium.go diff --git a/server/block/dirt.go b/server/block/dirt.go index c7573fba70..5a93e0d9cf 100644 --- a/server/block/dirt.go +++ b/server/block/dirt.go @@ -1,6 +1,9 @@ package block import ( + "math/rand/v2" + + "github.com/df-mc/dragonfly/server/block/cube" "github.com/df-mc/dragonfly/server/world" ) @@ -59,6 +62,37 @@ func (d Dirt) EncodeBlock() (string, map[string]any) { return "minecraft:dirt", nil } +// spreadDirt turns the block passed into dirt in low light and otherwise spreads it onto nearby dirt. It is +// the random tick behaviour shared by grass blocks and mycelium. minY is the lowest vertical offset a spread +// attempt may target. +func spreadDirt(b world.Block, pos cube.Pos, tx *world.Tx, r *rand.Rand, minY int) { + aboveLight := tx.Light(pos.Side(cube.FaceUp)) + if aboveLight < 4 { + tx.SetBlock(pos, Dirt{}, nil) + return + } + if aboveLight < 9 { + return + } + + // A single uint32 is enough as only 28 bits are needed, 7 per iteration. + n := r.Uint32() + + for range 4 { + x, y, z := int(n)%3, int(n>>2)%5, int(n>>5)%3 + n >>= 7 + + spreadPos := pos.Add(cube.Pos{x - 1, y + minY, z - 1}) + if tx.Light(spreadPos.Side(cube.FaceUp)) < 4 { + continue + } + if dirt, ok := tx.Block(spreadPos).(Dirt); !ok || dirt.Coarse { + continue + } + tx.SetBlock(spreadPos, b, nil) + } +} + // supportsVegetation checks if the vegetation can exist on the block. func supportsVegetation(vegetation, block world.Block) bool { soil, ok := block.(Soil) diff --git a/server/block/grass.go b/server/block/grass.go index 258aa703a8..0819eb86ba 100644 --- a/server/block/grass.go +++ b/server/block/grass.go @@ -47,36 +47,7 @@ func (g Grass) SoilFor(block world.Block) bool { // RandomTick handles the ticking of grass, which may or may not result in the spreading of grass onto dirt. func (g Grass) RandomTick(pos cube.Pos, tx *world.Tx, r *rand.Rand) { - aboveLight := tx.Light(pos.Side(cube.FaceUp)) - if aboveLight < 4 { - // The light above the block is too low: The grass turns to dirt. - tx.SetBlock(pos, Dirt{}, nil) - return - } - if aboveLight < 9 { - // Don't attempt to spread if the light level is lower than 9. - return - } - - // Generate a single uint32 as we only need 28 bits (7 bits each iteration). - n := r.Uint32() - - // Four attempts to spread to another block. - for i := 0; i < 4; i++ { - x, y, z := int(n)%3, int(n>>2)%5, int(n>>5)%3 - n >>= 7 - - spreadPos := pos.Add(cube.Pos{x - 1, y - 3, z - 1}) - // Don't spread grass to locations where dirt is exposed to hardly any light. - if tx.Light(spreadPos.Side(cube.FaceUp)) < 4 { - continue - } - b := tx.Block(spreadPos) - if dirt, ok := b.(Dirt); !ok || dirt.Coarse { - continue - } - tx.SetBlock(spreadPos, g, nil) - } + spreadDirt(g, pos, tx, r, -3) } // BoneMeal ... diff --git a/server/block/hash.go b/server/block/hash.go index a46a00eb5e..3447d28a02 100644 --- a/server/block/hash.go +++ b/server/block/hash.go @@ -138,6 +138,7 @@ const ( hashMud hashMudBricks hashMuddyMangroveRoots + hashMycelium hashNetherBrickFence hashNetherBricks hashNetherGoldOre @@ -768,6 +769,10 @@ func (m MuddyMangroveRoots) Hash() (uint64, uint64) { return hashMuddyMangroveRoots, uint64(m.Axis) } +func (Mycelium) Hash() (uint64, uint64) { + return hashMycelium, 0 +} + func (NetherBrickFence) Hash() (uint64, uint64) { return hashNetherBrickFence, 0 } diff --git a/server/block/mycelium.go b/server/block/mycelium.go new file mode 100644 index 0000000000..b813ffde11 --- /dev/null +++ b/server/block/mycelium.go @@ -0,0 +1,47 @@ +package block + +import ( + "math/rand/v2" + + "github.com/df-mc/dragonfly/server/block/cube" + "github.com/df-mc/dragonfly/server/world" +) + +// Mycelium is a variant of dirt that covers the surface of the mushroom fields biome. +type Mycelium struct { + solid +} + +// SoilFor ... +func (m Mycelium) SoilFor(block world.Block) bool { + switch block.(type) { + case ShortGrass, Fern, DoubleTallGrass, Flower, DoubleFlower, NetherSprouts, PinkPetals, SugarCane, DeadBush, BambooSapling, Bamboo: + return true + } + return false +} + +// RandomTick ... +func (m Mycelium) RandomTick(pos cube.Pos, tx *world.Tx, r *rand.Rand) { + spreadDirt(m, pos, tx, r, -2) +} + +// Shovel ... +func (Mycelium) Shovel() (world.Block, bool) { + return DirtPath{}, true +} + +// BreakInfo ... +func (m Mycelium) BreakInfo() BreakInfo { + return newBreakInfo(0.6, alwaysHarvestable, shovelEffective, silkTouchOneOf(Dirt{}, m)) +} + +// EncodeItem ... +func (Mycelium) EncodeItem() (name string, meta int16) { + return "minecraft:mycelium", 0 +} + +// EncodeBlock ... +func (Mycelium) EncodeBlock() (string, map[string]any) { + return "minecraft:mycelium", nil +} diff --git a/server/block/nether_sprouts.go b/server/block/nether_sprouts.go index 25ab662371..73bc4f2005 100644 --- a/server/block/nether_sprouts.go +++ b/server/block/nether_sprouts.go @@ -17,7 +17,7 @@ type NetherSprouts struct { // NeighbourUpdateTick ... func (n NetherSprouts) NeighbourUpdateTick(pos, _ cube.Pos, tx *world.Tx) { if !supportsVegetation(n, tx.Block(pos.Side(cube.FaceDown))) { - breakBlock(n, pos, tx) // TODO: Nylium & mycelium + breakBlock(n, pos, tx) // TODO: Nylium } } @@ -28,7 +28,7 @@ func (n NetherSprouts) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx return false } if !supportsVegetation(n, tx.Block(pos.Side(cube.FaceDown))) { - return false // TODO: Nylium & mycelium + return false // TODO: Nylium } place(tx, pos, n, user, ctx) diff --git a/server/block/register.go b/server/block/register.go index 084c586a1a..58c4a71199 100644 --- a/server/block/register.go +++ b/server/block/register.go @@ -86,6 +86,7 @@ func init() { world.RegisterBlock(MossCarpet{}) world.RegisterBlock(MudBricks{}) world.RegisterBlock(Mud{}) + world.RegisterBlock(Mycelium{}) world.RegisterBlock(NetherBrickFence{}) world.RegisterBlock(NetherGoldOre{}) world.RegisterBlock(NetherQuartzOre{}) @@ -366,6 +367,7 @@ func init() { world.RegisterItem(MudBricks{}) world.RegisterItem(MuddyMangroveRoots{}) world.RegisterItem(Mud{}) + world.RegisterItem(Mycelium{}) world.RegisterItem(NetherBrickFence{}) world.RegisterItem(NetherGoldOre{}) world.RegisterItem(NetherQuartzOre{})