Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions server/block/hash.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

76 changes: 76 additions & 0 deletions server/block/ice.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
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/item/enchantment"
"github.com/df-mc/dragonfly/server/world"
)

// Ice is a translucent solid block that melts into water when a bright light source is placed next to it.
type Ice struct {
solid
}

// Friction ...
func (Ice) Friction() float64 {
return 0.98
}

// LightDiffusionLevel ...
func (Ice) LightDiffusionLevel() uint8 {
return 2
}

// RandomTick ...
func (i Ice) RandomTick(pos cube.Pos, tx *world.Tx, _ *rand.Rand) {
for _, f := range cube.Faces() {
if tx.BlockLight(pos.Side(f)) > 11 {
i.melt(pos, tx)
return
}
}
}

// BreakInfo ...
func (i Ice) BreakInfo() BreakInfo {
return newBreakInfo(0.5, alwaysHarvestable, pickaxeEffective, silkTouchOnlyDrop(i)).withBreakHandler(func(pos cube.Pos, tx *world.Tx, u item.User) {
if u == nil {
return
}
if gm, ok := u.(interface{ GameMode() world.GameMode }); ok && gm.GameMode().CreativeInventory() {
return
}
held, _ := u.HeldItems()
if _, ok := held.Enchantment(enchantment.SilkTouch); ok {
return
}
below := pos.Side(cube.FaceDown)
b := tx.Block(below)
if _, liquid := b.(world.Liquid); !liquid && !b.Model().FaceSolid(below, cube.FaceUp, tx) {
return
}
i.melt(pos, tx)
})
}

// melt ...
func (Ice) melt(pos cube.Pos, tx *world.Tx) {
if tx.World().Dimension().WaterEvaporates() {
tx.SetBlock(pos, nil, nil)
return
}
tx.SetBlock(pos, Water{Still: true, Depth: 8}, nil)
}

// EncodeItem ...
func (Ice) EncodeItem() (name string, meta int16) {
return "minecraft:ice", 0
}

// EncodeBlock ...
func (Ice) EncodeBlock() (string, map[string]any) {
return "minecraft:ice", nil
}
2 changes: 2 additions & 0 deletions server/block/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ func init() {
world.RegisterBlock(Grass{})
world.RegisterBlock(Gravel{})
world.RegisterBlock(Honeycomb{})
world.RegisterBlock(Ice{})
world.RegisterBlock(InfestedStone{})
world.RegisterBlock(InfestedCobblestone{})
for _, b := range allInfestedStoneBricks() {
Expand Down Expand Up @@ -339,6 +340,7 @@ func init() {
world.RegisterItem(HayBale{})
world.RegisterItem(Honeycomb{})
world.RegisterItem(Hopper{})
world.RegisterItem(Ice{})
world.RegisterItem(InfestedStone{})
world.RegisterItem(InfestedCobblestone{})
for _, t := range StoneBricksTypes() {
Expand Down
5 changes: 5 additions & 0 deletions server/world/chunk/chunk.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ func (chunk *Chunk) SkyLight(x uint8, y int16, z uint8) uint8 {
return chunk.SubChunk(y).SkyLight(x&15, uint8(y&15), z&15)
}

// BlockLight returns the block light level at a specific position in the chunk.
func (chunk *Chunk) BlockLight(x uint8, y int16, z uint8) uint8 {
return chunk.SubChunk(y).BlockLight(x&15, uint8(y&15), z&15)
}

// HighestLightBlocker iterates from the highest non-empty sub chunk downwards to find the Y value of the
// highest block that completely blocks any light from going through. If none is found, the value returned is
// the minimum height.
Expand Down
8 changes: 8 additions & 0 deletions server/world/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,14 @@ func (tx *Tx) SkyLight(pos cube.Pos) uint8 {
return tx.skyLight(pos)
}

// BlockLight returns the block light level at the position passed. This light
// level is only influenced by blocks that emit light, such as torches, and
// ignores the light of the sky. Like SkyLight, BlockLight loads or generates
// the chunk at the position if it is not currently loaded.
func (tx *Tx) BlockLight(pos cube.Pos) uint8 {
return tx.blockLight(pos)
}

// SetBiome sets the Biome at the position passed. If a chunk is not yet loaded
// at that position, the chunk is first loaded or generated if it could not be
// found in the world save.
Expand Down
10 changes: 10 additions & 0 deletions server/world/world.go
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,16 @@ func (tx *Tx) skyLight(pos cube.Pos) uint8 {
return tx.chunk(chunkPosFromBlockPos(pos)).SkyLight(uint8(pos[0]), int16(pos[1]), uint8(pos[2]))
}

// blockLight returns the block light level at the position passed. Unlike light, this level is not
// influenced by the light of the sky.
func (tx *Tx) blockLight(pos cube.Pos) uint8 {
w := tx.World()
if pos[1] < w.ra[0] || pos[1] > w.ra[1] {
return 0
}
return tx.chunk(chunkPosFromBlockPos(pos)).BlockLight(uint8(pos[0]), int16(pos[1]), uint8(pos[2]))
}

// Time returns the current time of the world. The time is incremented every
// 1/20th of a second, unless World.StopTime() is called.
func (w *World) Time() int {
Expand Down