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
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:
@@ -0,0 +1,262 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"image"
|
||||
"math/rand/v2"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/block/customblock"
|
||||
)
|
||||
|
||||
// Block is a block that may be placed or found in a world. In addition, the block may also be added to an
|
||||
// inventory: It is also an item.
|
||||
// Every Block implementation must be able to be hashed as key in a map.
|
||||
type Block interface {
|
||||
// EncodeBlock encodes the block to a string ID such as 'minecraft:grass' and properties associated
|
||||
// with the block.
|
||||
EncodeBlock() (string, map[string]any)
|
||||
// Hash returns two different identifiers for the block. The first is the base hash which is unique for
|
||||
// each type of block at runtime. For vanilla blocks, this is an auto-incrementing constant and for custom
|
||||
// blocks, you can call block.NextHash() to get a unique identifier. The second is the hash of the block's
|
||||
// own state and does not need to worry about colliding with other types of blocks. This is later combined
|
||||
// with the base hash to create a unique identifier for the full block.
|
||||
Hash() (uint64, uint64)
|
||||
// Model returns the BlockModel of the Block.
|
||||
Model() BlockModel
|
||||
}
|
||||
|
||||
// CustomBlock represents a block that is non-vanilla and requires a resource pack and extra steps to show it to the
|
||||
// client.
|
||||
type CustomBlock interface {
|
||||
Block
|
||||
Properties() customblock.Properties
|
||||
}
|
||||
|
||||
type CustomBlockBuildable interface {
|
||||
CustomBlock
|
||||
// Name is the name displayed to clients using the block.
|
||||
Name() string
|
||||
// Geometry is the geometries for the block that define the shape of the block. If false is returned, no custom
|
||||
// geometry will be applied. Permutation-specific geometry can be defined by returning a map of permutations to
|
||||
// geometry.
|
||||
Geometry() []byte
|
||||
// Textures is a map of images indexed by their target, used to map textures on to the block. Permutation-specific
|
||||
// textures can be defined by returning a map of permutations to textures.
|
||||
Textures() map[string]image.Image
|
||||
}
|
||||
|
||||
// Liquid represents a block that can be moved through and which can flow in the world after placement. There
|
||||
// are two liquids in vanilla, which are lava and water.
|
||||
type Liquid interface {
|
||||
Block
|
||||
// LiquidDepth returns the current depth of the liquid.
|
||||
LiquidDepth() int
|
||||
// SpreadDecay returns the amount of depth that is subtracted from the liquid's depth when it spreads to
|
||||
// a next block.
|
||||
SpreadDecay() int
|
||||
// WithDepth returns the liquid with the depth passed.
|
||||
WithDepth(depth int, falling bool) Liquid
|
||||
// LiquidFalling checks if the liquid is currently considered falling down.
|
||||
LiquidFalling() bool
|
||||
// BlastResistance is the blast resistance of the liquid, which influences the liquid's ability to withstand an
|
||||
// explosive blast.
|
||||
BlastResistance() float64
|
||||
// LiquidType returns an int unique for the liquid, used to check if two liquids are considered to be
|
||||
// of the same type.
|
||||
LiquidType() string
|
||||
// Harden checks if the block should harden when looking at the surrounding blocks and sets the position
|
||||
// to the hardened block when adequate. If the block was hardened, the method returns true.
|
||||
Harden(pos cube.Pos, tx *Tx, flownIntoBy *cube.Pos) bool
|
||||
// LiquidRemoveBlock is called when the liquid flows into and removes the block passed.
|
||||
LiquidRemoveBlock(pos cube.Pos, tx *Tx, removed Block)
|
||||
}
|
||||
|
||||
// Conductor represents a block that can conduct a redstone signal.
|
||||
type Conductor interface {
|
||||
Block
|
||||
// RedstoneSource returns true if the conductor is a signal source.
|
||||
RedstoneSource() bool
|
||||
|
||||
// WeakPower returns the weak power level emitted by this conductor toward a neighbouring receiver.
|
||||
// The face argument is relative to the receiving block, not this conductor.
|
||||
// Weak power can pass through a solid block to power redstone components on the other side, but
|
||||
// cannot power solid blocks themselves or travel further.
|
||||
// The accountForDust parameter indicates whether redstone dust should be considered when
|
||||
// calculating power levels.
|
||||
WeakPower(pos cube.Pos, face cube.Face, tx *Tx, accountForDust bool) int
|
||||
|
||||
// StrongPower returns the strong power level emitted by this conductor toward a neighbouring
|
||||
// receiver. The face argument uses the same convention as WeakPower.
|
||||
// Strong power can be transmitted through solid blocks. When a solid block receives strong power
|
||||
// through one of its faces, it can provide weak power to adjacent redstone components on all other
|
||||
// faces. Strong power can also directly power any redstone component.
|
||||
// The accountForDust parameter indicates whether redstone dust should be considered when
|
||||
// calculating power levels.
|
||||
StrongPower(pos cube.Pos, face cube.Face, tx *Tx, accountForDust bool) int
|
||||
}
|
||||
|
||||
// WeakBlockPowerer represents a conductor whose weak power may weakly power an adjacent conductive block. Weakly
|
||||
// powered blocks may activate mechanisms and repeaters, but do not power adjacent redstone dust. For example,
|
||||
// dust pointing into a stone block opens a door on the stone's far side, but a second stretch of dust there stays
|
||||
// dark.
|
||||
type WeakBlockPowerer interface {
|
||||
Conductor
|
||||
// WeaklyPowersBlocks returns true if this conductor's WeakPower can make an adjacent conductive block weakly powered.
|
||||
WeaklyPowersBlocks() bool
|
||||
}
|
||||
|
||||
// RedstonePowerRelayer represents a block with custom behaviour for whether
|
||||
// neighbouring redstone power may be relayed through it by Tx.RedstonePower.
|
||||
type RedstonePowerRelayer interface {
|
||||
Block
|
||||
// RelaysRedstonePowerThrough reports whether this non-conductor block may
|
||||
// relay neighbouring redstone power through itself to receivers on its other sides.
|
||||
RelaysRedstonePowerThrough() bool
|
||||
}
|
||||
|
||||
// RedstoneUpdater represents a block that reacts to nearby redstone power changes.
|
||||
type RedstoneUpdater interface {
|
||||
Block
|
||||
// RedstoneUpdate is called when a change in redstone signal is computed.
|
||||
RedstoneUpdate(pos cube.Pos, tx *Tx)
|
||||
}
|
||||
|
||||
// RegisterBlock registers the Block passed in the DefaultBlockRegistry.
|
||||
//
|
||||
// This function exists for backwards compatibility and works well for the common "single server per process" setup,
|
||||
// where all worlds share the global default registry.
|
||||
//
|
||||
// If you run multiple servers/registries in a single process, prefer creating a registry using NewBlockRegistry() and
|
||||
// registering blocks on that instance (e.g. conf.Blocks.RegisterBlock(...)) before calling Finalize().
|
||||
func RegisterBlock(b Block) {
|
||||
DefaultBlockRegistry.RegisterBlock(b)
|
||||
}
|
||||
|
||||
// BlockHash returns a unique identifier of the block including the block states using the DefaultBlockRegistry.
|
||||
// This function is used internally to convert a block to a single integer which can be used in map lookups. The hash
|
||||
// produced therefore does not need to match anything in the game, but it must be unique among all registered blocks.
|
||||
// The tool in `/cmd/blockhash` may be used to automatically generate block hashes of blocks in a package.
|
||||
//
|
||||
// If you use a non-default registry (NewBlockRegistry), use your registry instance's BlockHash(...) instead so the
|
||||
// hash is consistent with that registry.
|
||||
func BlockHash(b Block) uint64 {
|
||||
return DefaultBlockRegistry.BlockHash(b)
|
||||
}
|
||||
|
||||
// BlockRuntimeID attempts to return a runtime ID of a block previously registered using RegisterBlock() on the
|
||||
// DefaultBlockRegistry.
|
||||
// If the runtime ID cannot be found because the Block wasn't registered, BlockRuntimeID will panic.
|
||||
// If you use a non-default registry (NewBlockRegistry), use your registry instance's BlockRuntimeID(...) instead.
|
||||
func BlockRuntimeID(b Block) uint32 {
|
||||
return DefaultBlockRegistry.BlockRuntimeID(b)
|
||||
}
|
||||
|
||||
// BlockByRuntimeID attempts to return a Block by its runtime ID using the DefaultBlockRegistry. If not found, the bool
|
||||
// returned is false. If found, the block is non-nil and the bool true.
|
||||
// If you use a non-default registry (NewBlockRegistry), use your registry instance's BlockByRuntimeID(...) instead.
|
||||
func BlockByRuntimeID(rid uint32) (Block, bool) {
|
||||
return DefaultBlockRegistry.BlockByRuntimeID(rid)
|
||||
}
|
||||
|
||||
// BlockByName attempts to return a Block by its name and properties using the DefaultBlockRegistry. If not found, the
|
||||
// bool returned is false.
|
||||
// If you use a non-default registry (NewBlockRegistry), use your registry instance's BlockByName(...) instead.
|
||||
func BlockByName(name string, properties map[string]any) (Block, bool) {
|
||||
return DefaultBlockRegistry.BlockByName(name, properties)
|
||||
}
|
||||
|
||||
// Blocks returns a slice of all blocks registered in the DefaultBlockRegistry.
|
||||
// If you use a non-default registry (NewBlockRegistry), use your registry instance's Blocks() instead.
|
||||
func Blocks() []Block {
|
||||
return DefaultBlockRegistry.Blocks()
|
||||
}
|
||||
|
||||
// CustomBlocks returns a map of all custom blocks registered with their names as keys in the DefaultBlockRegistry.
|
||||
// If you use a non-default registry (NewBlockRegistry), use your registry instance's CustomBlocks() instead.
|
||||
func CustomBlocks() map[string]CustomBlock {
|
||||
return DefaultBlockRegistry.CustomBlocks()
|
||||
}
|
||||
|
||||
// RandomTicker represents a block that executes an action when it is ticked randomly. Every 20th of a second,
|
||||
// one random block in each sub chunk are picked to receive a random tick.
|
||||
type RandomTicker interface {
|
||||
// RandomTick handles a random tick of the block at the position passed. Additionally, a rand.RandSource
|
||||
// instance is passed which may be used to generate values randomly without locking.
|
||||
RandomTick(pos cube.Pos, tx *Tx, r *rand.Rand)
|
||||
}
|
||||
|
||||
// ScheduledTicker represents a block that executes an action when it has a block update scheduled, such as
|
||||
// when a block adjacent to it is broken.
|
||||
type ScheduledTicker interface {
|
||||
// ScheduledTick handles a scheduled tick initiated by an event in one of the neighbouring blocks, such as
|
||||
// when a block is placed or broken. Additionally, a rand.RandSource instance is passed which may be used to
|
||||
// generate values randomly without locking.
|
||||
ScheduledTick(pos cube.Pos, tx *Tx, r *rand.Rand)
|
||||
}
|
||||
|
||||
// TickerBlock is an implementation of NBTer with an additional Tick method that is called on every world
|
||||
// tick for loaded blocks that implement this interface.
|
||||
type TickerBlock interface {
|
||||
NBTer
|
||||
Tick(currentTick int64, pos cube.Pos, tx *Tx)
|
||||
}
|
||||
|
||||
// NeighbourUpdateTicker represents a block that is updated when a block adjacent to it is updated, either
|
||||
// through placement or being broken.
|
||||
type NeighbourUpdateTicker interface {
|
||||
// NeighbourUpdateTick handles a neighbouring block being updated. The position of that block and the
|
||||
// position of this block is passed.
|
||||
NeighbourUpdateTick(pos, changedNeighbour cube.Pos, tx *Tx)
|
||||
}
|
||||
|
||||
// NBTer represents either an item or a block which may decode NBT data and encode to NBT data. Typically,
|
||||
// this is done to store additional data.
|
||||
type NBTer interface {
|
||||
// DecodeNBT returns the (new) item, block or Entity, depending on which of those the NBTer was, with the NBT data
|
||||
// decoded into it.
|
||||
DecodeNBT(data map[string]any) any
|
||||
// EncodeNBT encodes the Entity into a map which can then be encoded as NBT to be written.
|
||||
EncodeNBT() map[string]any
|
||||
}
|
||||
|
||||
// LiquidDisplacer represents a block that is able to displace a liquid to a different world layer, without
|
||||
// fully removing the liquid.
|
||||
type LiquidDisplacer interface {
|
||||
// CanDisplace specifies if the block is able to displace the liquid passed.
|
||||
CanDisplace(b Liquid) bool
|
||||
// SideClosed checks if a position on the side of the block placed in the world at a specific position is
|
||||
// closed. When this returns true (for example, when the side is below the position and the block is a
|
||||
// slab), liquid inside the displacer won't flow from pos into side.
|
||||
SideClosed(pos, side cube.Pos, tx *Tx) bool
|
||||
}
|
||||
|
||||
// lightEmitter is identical to a block.LightEmitter.
|
||||
type lightEmitter interface {
|
||||
LightEmissionLevel() uint8
|
||||
}
|
||||
|
||||
// lightDiffuser is identical to a block.LightDiffuser.
|
||||
type lightDiffuser interface {
|
||||
LightDiffusionLevel() uint8
|
||||
}
|
||||
|
||||
// replaceableBlock represents a block that may be replaced by another block automatically. An example is
|
||||
// grass, which may be replaced by clicking it with another block.
|
||||
type replaceableBlock interface {
|
||||
// ReplaceableBy returns a bool which indicates if the block is replaceable by another block.
|
||||
ReplaceableBy(b Block) bool
|
||||
}
|
||||
|
||||
// replaceable checks if the block at the position passed is replaceable with the block passed.
|
||||
func replaceable(w *World, c *Column, pos cube.Pos, with Block) bool {
|
||||
if r, ok := w.blockInChunk(c, pos).(replaceableBlock); ok {
|
||||
return r.ReplaceableBy(with)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// BlockAction represents an action that may be performed by a block. Typically, these actions are sent to
|
||||
// viewers in a world so that they can see these actions.
|
||||
type BlockAction interface {
|
||||
BlockAction()
|
||||
}
|
||||
Reference in New Issue
Block a user