up3
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

This commit is contained in:
2026-07-09 08:33:57 +08:00
commit 26ed99fda6
845 changed files with 75419 additions and 0 deletions
+273
View File
@@ -0,0 +1,273 @@
package block
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/block/model"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
)
// RedstoneWire is a block that is used to transfer a charge between objects. Charged objects can be used to open doors
// or activate certain items. This block is the placed form of redstone which can be found by mining redstone ore with
// an iron pickaxe or better. Deactivated redstone wire will appear dark red, but activated redstone wire will appear
// bright red with a sparkling particle effect.
type RedstoneWire struct {
empty
transparent
// Power is the current power level of the redstone wire. It ranges from 0 to 15.
Power int
}
// HasLiquidDrops ...
func (RedstoneWire) HasLiquidDrops() bool {
return true
}
// BreakInfo ...
func (r RedstoneWire) BreakInfo() BreakInfo {
return newBreakInfo(0, alwaysHarvestable, nothingEffective, oneOf(RedstoneWire{})).withBreakHandler(func(pos cube.Pos, tx *world.Tx, _ item.User) {
updateStrongRedstone(pos, tx)
})
}
// EncodeBlock ...
func (r RedstoneWire) EncodeBlock() (string, map[string]any) {
return "minecraft:redstone_wire", map[string]any{
"redstone_signal": int32(r.Power),
}
}
// EncodeItem ...
func (RedstoneWire) EncodeItem() (name string, meta int16) {
return "minecraft:redstone", 0
}
// UseOnBlock ...
func (r RedstoneWire) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, tx *world.Tx, user item.User, ctx *item.UseContext) bool {
pos, _, used := firstReplaceable(tx, pos, face, r)
if !used {
return false
}
belowPos := pos.Side(cube.FaceDown)
if !tx.Block(belowPos).Model().FaceSolid(belowPos, cube.FaceUp, tx) {
return false
}
r.Power = r.calculatePower(pos, tx)
place(tx, pos, r, user, ctx)
if placed(ctx) {
updateStrongRedstone(pos, tx)
return true
}
return false
}
// NeighbourUpdateTick ...
func (r RedstoneWire) NeighbourUpdateTick(pos, neighbour cube.Pos, tx *world.Tx) {
if pos == neighbour {
// Ignore the self-update sent after this wire's block state changes.
return
}
below := pos.Side(cube.FaceDown)
if !tx.Block(below).Model().FaceSolid(below, cube.FaceUp, tx) {
breakBlock(r, pos, tx)
return
}
if changed, ok := r.updateFromNeighbour(pos, tx); ok && !changed {
updateStrongRedstone(pos, tx)
}
}
// RedstoneUpdate ...
func (r RedstoneWire) RedstoneUpdate(pos cube.Pos, tx *world.Tx) {
r.updatePower(pos, tx)
}
// updateFromNeighbour updates the wire after a neighbour change. changed reports whether the wire's power changed,
// and ok reports whether the update was allowed by the redstone update handler.
func (r RedstoneWire) updateFromNeighbour(pos cube.Pos, tx *world.Tx) (changed bool, ok bool) {
if redstoneUpdateCancelled(pos, tx) {
return false, false
}
return r.updatePower(pos, tx), true
}
// updatePower recalculates the wire's power and propagates the network when the power changes.
func (r RedstoneWire) updatePower(pos cube.Pos, tx *world.Tx) bool {
if power := r.calculatePower(pos, tx); r.Power != power {
r.Power = power
tx.SetBlock(pos, r, &world.SetOpts{DisableBlockUpdates: true})
updateStrongRedstone(pos, tx)
return true
}
return false
}
// RedstoneSource ...
func (RedstoneWire) RedstoneSource() bool {
return false
}
// WeaklyPowersBlocks returns true because powered redstone dust weakly powers conductive blocks it points into or rests on top of.
func (RedstoneWire) WeaklyPowersBlocks() bool {
return true
}
// WeakPower returns the power emitted by the wire toward a neighbouring receiver. Dust powers upward, never powers
// downward, and only powers horizontal receivers in connected directions. A powered wire with no horizontal
// connections behaves as an unconnected cross and powers every horizontal side.
func (r RedstoneWire) WeakPower(pos cube.Pos, face cube.Face, tx *world.Tx, accountForDust bool) int {
if !accountForDust {
return 0
}
if face == cube.FaceUp {
return r.Power
}
if face == cube.FaceDown {
return 0
}
if !r.hasHorizontalRedstoneConnection(pos, tx) {
return r.Power
}
if r.connection(pos, face.Opposite(), tx) {
return r.Power
}
if r.connection(pos, face, tx) && !r.connection(pos, face.RotateLeft(), tx) && !r.connection(pos, face.RotateRight(), tx) {
return r.Power
}
return 0
}
// StrongPower returns 0 because redstone dust weakly powers conductive blocks rather than strongly powering them.
func (RedstoneWire) StrongPower(cube.Pos, cube.Face, *world.Tx, bool) int {
return 0
}
// calculatePower returns the highest level of received redstone power at the provided position.
func (r RedstoneWire) calculatePower(pos cube.Pos, tx *world.Tx) int {
return calculateRedstoneWirePower(pos, tx, tx.Block)
}
// calculateRedstoneWirePower returns the highest level of received redstone power at the provided position. blockAt is
// injected so direct updates and the BFS wire network share the same rules while the BFS path may still read cached
// node state.
func calculateRedstoneWirePower(pos cube.Pos, tx *world.Tx, blockAt func(cube.Pos) world.Block) int {
aboveBlocksVerticalTravel := blocksRedstoneWireVerticalTravel(blockAt(pos.Side(cube.FaceUp)))
var blockPower, wirePower int
for _, side := range cube.Faces() {
neighbourPos := pos.Side(side)
neighbour := blockAt(neighbourPos)
wirePower = maxRedstoneWirePower(neighbour, wirePower)
blockPower = max(blockPower, tx.RedstonePower(neighbourPos, side, false))
if side.Axis() == cube.Y {
// Only check horizontal neighbours from here on.
continue
}
if canRedstoneWireStepDown(pos, neighbourPos, neighbour, tx) && !aboveBlocksVerticalTravel {
wirePower = maxRedstoneWirePower(blockAt(neighbourPos.Side(cube.FaceUp)), wirePower)
}
if canRedstoneWireStepDown(neighbourPos.Side(cube.FaceDown), neighbourPos, neighbour, tx) && !blocksRedstoneWireVerticalTravel(neighbour) {
wirePower = maxRedstoneWirePower(blockAt(neighbourPos.Side(cube.FaceDown)), wirePower)
}
if _, neighbourSolid := neighbour.Model().(model.Solid); !neighbourSolid {
wirePower = maxRedstoneWirePower(blockAt(neighbourPos.Side(cube.FaceDown)), wirePower)
}
}
return max(blockPower, wirePower-1)
}
// hasHorizontalRedstoneConnection checks if the dust connects horizontally to redstone wire or a redstone source. It
// does not include passive receivers such as doors, trapdoors, or note blocks.
func (r RedstoneWire) hasHorizontalRedstoneConnection(pos cube.Pos, tx *world.Tx) bool {
for _, face := range cube.HorizontalFaces() {
if r.connection(pos, face, tx) {
return true
}
}
return false
}
// connection returns true if the dust shape connects through the given face to another wire or a redstone source. It
// also accounts for valid one-block vertical wire connections.
func (r RedstoneWire) connection(pos cube.Pos, face cube.Face, tx *world.Tx) bool {
sidePos := pos.Side(face)
sideBlock := tx.Block(sidePos)
if r.connectsAbove(pos, sidePos, sideBlock, tx) || r.connectsTo(sideBlock, true) {
return true
}
return r.connectsBelow(sidePos, sideBlock, tx)
}
// connectsAbove checks if the redstone wire can connect to the block above it.
func (r RedstoneWire) connectsAbove(pos, sidePos cube.Pos, sideBlock world.Block, tx *world.Tx) bool {
if blocksRedstoneWireVerticalTravel(tx.Block(pos.Side(cube.FaceUp))) || !r.canRunOnTop(tx, sidePos, sideBlock) {
return false
}
return r.connectsTo(tx.Block(sidePos.Side(cube.FaceUp)), false)
}
// connectsBelow checks if the redstone wire can connect to the block below it.
func (r RedstoneWire) connectsBelow(sidePos cube.Pos, sideBlock world.Block, tx *world.Tx) bool {
_, sideSolid := sideBlock.Model().(model.Solid)
return !sideSolid && r.connectsTo(tx.Block(sidePos.Side(cube.FaceDown)), false)
}
// connectsTo reports whether a block is part of the redstone wire connection graph. Passive redstone receivers are not
// connections; direct source conductors count only when allowDirectSources is true.
func (RedstoneWire) connectsTo(block world.Block, allowDirectSources bool) bool {
if _, ok := block.(RedstoneWire); ok {
return true
}
c, ok := block.(world.Conductor)
return ok && allowDirectSources && c.RedstoneSource()
}
// canRunOnTop checks whether redstone dust can be placed on top of the block.
func (RedstoneWire) canRunOnTop(tx *world.Tx, pos cube.Pos, block world.Block) bool {
return block.Model().FaceSolid(pos, cube.FaceUp, tx)
}
// blocksRedstoneWireVerticalTravel checks if the block above redstone wire blocks vertical wire travel.
func blocksRedstoneWireVerticalTravel(block world.Block) bool {
if _, ok := block.Model().(model.Solid); !ok {
return false
}
diffuser, ok := block.(LightDiffuser)
return !ok || diffuser.LightDiffusionLevel() != 0
}
// canRedstoneWireStepDown checks if redstone dust can provide power while travelling down around the side block.
func canRedstoneWireStepDown(from, side cube.Pos, block world.Block, tx *world.Tx) bool {
if stepDowner, ok := block.(RedstoneWireStepDowner); ok {
return stepDowner.CanRedstoneWireStepDown(side, from, tx)
}
for _, face := range cube.Faces() {
if !block.Model().FaceSolid(side, face, tx) {
return false
}
}
return true
}
// TrimMaterial delegates to item.RedstoneWire so the block form stays valid for smithing trim decoding too.
func (RedstoneWire) TrimMaterial() string {
return item.RedstoneWire{}.TrimMaterial()
}
// MaterialColour delegates to item.RedstoneWire to keep trim metadata defined in one place.
func (RedstoneWire) MaterialColour() string {
return item.RedstoneWire{}.MaterialColour()
}
// allRedstoneWires returns a list of all redstone dust states.
func allRedstoneWires() (all []world.Block) {
for i := range 16 {
all = append(all, RedstoneWire{Power: i})
}
return
}