Initial commit
This commit is contained in:
178
internal/world/block.go
Normal file
178
internal/world/block.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package world
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"edgaru089.ml/go/gl01/internal/util/itype"
|
||||
)
|
||||
|
||||
// BlockRenderType is an enum describing the rendering process of a block
|
||||
type BlockRenderType int
|
||||
|
||||
const (
|
||||
OneTexture BlockRenderType = iota // Render with one texture of the same on all faces, "Name.png"
|
||||
ThreeTexture // Render with one texture on the top, one around the sides, and one on the bottom, "Name_top/side/bot.png,"
|
||||
SixTexture // Render with six different textures on six faces, "Name_x+/x-/y+/y-/z+/z-.png"
|
||||
CustomRendering // Rendering calls BlockAppearance.CustomRenderAppend()
|
||||
)
|
||||
|
||||
// BlockAppearance describes basic appearance of a kind of block.
|
||||
type BlockAppearance struct {
|
||||
Name string // A short name, like "stone" or "dirt", used for texture lookups
|
||||
Transparent bool // Is block transparent?
|
||||
NotSolid bool // Is block not solid, i.e., has no solid hitbox? (this makes the zero value reasonable)
|
||||
Light int // The light level it emits, 0 is none
|
||||
|
||||
Hitbox itype.Boxd // Hitbox, in block-local coordinates; empty slice means a default hitbox of 1x1x1
|
||||
|
||||
RenderType BlockRenderType // Rendering type, defaults to OneTexture (zero value)
|
||||
|
||||
// Called on render if RenderType == CustomRendering.
|
||||
//
|
||||
// Be sure to return vertexArray at the end of the function (in case it got reallocated)!!!!
|
||||
CustomRenderAppend func(
|
||||
position itype.Vec3i,
|
||||
aux int,
|
||||
data itype.Dataset,
|
||||
vertexArray []Vertex,
|
||||
) []Vertex
|
||||
}
|
||||
|
||||
// BlockBehaviour describes a kind of block of the same Major ID.
|
||||
type BlockBehaviour interface {
|
||||
|
||||
// Static returns if the Behaviour is "static", i.e., the Appearance does not
|
||||
// change with position, Minor ID or Dataset. Static Behaviours are cached
|
||||
// by the renderer and only generated once.
|
||||
//
|
||||
// Static implies RequireDataset = false and RequireBlockUpdate = false.
|
||||
Static() bool
|
||||
|
||||
// RequireDataset returns if the type of block requires a Dataset attached.
|
||||
RequireDataset() bool
|
||||
|
||||
// RequireBlockUpdate return if BlockUpdate should be called if a neighboring
|
||||
// block has changed. Blocks not requiring BlockUpdate does not change at all.
|
||||
RequireBlockUpdate() bool
|
||||
|
||||
// Appearance returns the Appearance of the block at global position Position,
|
||||
// with Minor ID aux, and Dataset data.
|
||||
//
|
||||
// If RequireDataset if false, data is nil.
|
||||
Appearance(position itype.Vec3i, aux int, data itype.Dataset) BlockAppearance
|
||||
|
||||
// BlockUpdate is called when RequireBlockUpdate is true and the block at
|
||||
// global position Position, with Minor ID aux, and Dataset data has a neighbor
|
||||
// that changed state. A block will only be updated once in a tick.
|
||||
//
|
||||
// If RequireDataset if false, data is nil.
|
||||
//
|
||||
// Return true if this block also changed state, false otherwise.
|
||||
BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset) bool
|
||||
}
|
||||
|
||||
type blockBehaviourStatic struct {
|
||||
app BlockAppearance
|
||||
}
|
||||
|
||||
func (blockBehaviourStatic) Static() bool { return true }
|
||||
func (blockBehaviourStatic) RequireDataset() bool { return false }
|
||||
func (blockBehaviourStatic) RequireBlockUpdate() bool { return false }
|
||||
func (b blockBehaviourStatic) Appearance(position itype.Vec3i, aux int, data itype.Dataset) BlockAppearance {
|
||||
return b.app
|
||||
}
|
||||
func (blockBehaviourStatic) BlockUpdate(position itype.Vec3i, aux int, data itype.Dataset) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// BlockBehaviourStatic returns a Static BlockBehaviour that has the given BlockAppearance.
|
||||
func BlockBehaviourStatic(app BlockAppearance) BlockBehaviour {
|
||||
return blockBehaviourStatic{app: app}
|
||||
}
|
||||
|
||||
var behaviour map[int]BlockBehaviour = make(map[int]BlockBehaviour)
|
||||
var appearance map[int]BlockAppearance = make(map[int]BlockAppearance)
|
||||
var behaviourDoneRegister bool
|
||||
|
||||
// RegisterBlockBehaviour registers behaviour with the given id.
|
||||
//
|
||||
// If the id is already taken, or id == 0, false is returned and nothing is done.
|
||||
// Otherwise, true is returned and the block is registered.
|
||||
func RegisterBlockBehaviour(id int, b BlockBehaviour) bool {
|
||||
if _, ok := behaviour[id]; behaviourDoneRegister || id == 0 || ok {
|
||||
return false
|
||||
}
|
||||
|
||||
behaviour[id] = b
|
||||
return true
|
||||
}
|
||||
|
||||
// DoneRegisteringBlockBehaviour is to be called after Registering BlockBehaviour,
|
||||
// i.e., in Post-Init() initializations.
|
||||
func DoneRegisteringBlockBehaviour() {
|
||||
for id, b := range behaviour {
|
||||
if b.Static() {
|
||||
appearance[id] = b.Appearance(itype.Vec3i{}, 0, nil)
|
||||
}
|
||||
}
|
||||
|
||||
behaviourDoneRegister = true
|
||||
}
|
||||
|
||||
// GetBlockAppearance gets the block appearance of the given block in the fastest way possible.
|
||||
func GetBlockAppearance(position itype.Vec3i, id, aux int, data itype.Dataset) BlockAppearance {
|
||||
if app, ok := appearance[id]; ok { // Cache
|
||||
if app.Hitbox == (itype.Boxd{}) {
|
||||
app.Hitbox = itype.Boxd{
|
||||
OffX: 0, OffY: 0, OffZ: 0,
|
||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||
}
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// Slow way
|
||||
b, ok := behaviour[id]
|
||||
if !ok {
|
||||
panic(fmt.Sprint("invalid block type ", id))
|
||||
}
|
||||
|
||||
app := b.Appearance(position, aux, data)
|
||||
if app.Hitbox == (itype.Boxd{}) {
|
||||
app.Hitbox = itype.Boxd{
|
||||
OffX: 0, OffY: 0, OffZ: 0,
|
||||
SizeX: 1, SizeY: 1, SizeZ: 1,
|
||||
}
|
||||
}
|
||||
return app
|
||||
}
|
||||
|
||||
// GetBlockBehaviour gets the block behaviour of the given id, or nil if not present.
|
||||
func GetBlockBehaviour(id int) BlockBehaviour {
|
||||
return behaviour[id]
|
||||
}
|
||||
|
||||
// Block is a structure to store and pass Blocks around.
|
||||
type Block struct {
|
||||
Id, Aux int
|
||||
Dataset itype.Dataset
|
||||
Behaviour BlockBehaviour
|
||||
}
|
||||
|
||||
// Appearance is a shortcut for Behaviour.Appearance().
|
||||
// It returns the Appearance of the block with the given parameters.
|
||||
func (b *Block) Appearance(position itype.Vec3i) BlockAppearance {
|
||||
return b.Behaviour.Appearance(position, b.Aux, b.Dataset)
|
||||
}
|
||||
|
||||
// BlockUpdate is a shortcut for Behaviour.BlockUpdate().
|
||||
// It is called when RequireBlockUpdate is true and the block at
|
||||
// global position Position, with Minor ID aux, and Dataset data has a neighbor
|
||||
// that changed state. A block will only be updated once in a tick.
|
||||
//
|
||||
// If RequireDataset if false, data is nil.
|
||||
//
|
||||
// Return true if this block also changed state, false otherwise.
|
||||
func (b *Block) BlockUpdate(position itype.Vec3i) bool {
|
||||
return b.Behaviour.BlockUpdate(position, b.Aux, b.Dataset)
|
||||
}
|
||||
Reference in New Issue
Block a user