76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
|
|
package model
|
||
|
|
|
||
|
|
import (
|
||
|
|
"github.com/df-mc/dragonfly/server/block/cube"
|
||
|
|
"github.com/df-mc/dragonfly/server/world"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Fence is a model used by fences of any type. It can attach to blocks with solid faces and other fences of the same
|
||
|
|
// type and has a model height just slightly over 1.
|
||
|
|
type Fence struct {
|
||
|
|
// Wood specifies if the Fence is made from wood. This field is used to check if two fences are able to attach to
|
||
|
|
// each other.
|
||
|
|
Wood bool
|
||
|
|
}
|
||
|
|
|
||
|
|
const (
|
||
|
|
fenceHeight = 1.5
|
||
|
|
fenceInset = 0.375
|
||
|
|
)
|
||
|
|
|
||
|
|
// BBox returns multiple physics.BBox depending on how many connections it has with the surrounding blocks.
|
||
|
|
func (f Fence) BBox(pos cube.Pos, s world.BlockSource) []cube.BBox {
|
||
|
|
boxes := make([]cube.BBox, 0, 2)
|
||
|
|
|
||
|
|
connectWest, connectEast := f.checkConnection(pos, cube.FaceWest, s), f.checkConnection(pos, cube.FaceEast, s)
|
||
|
|
connectNorth, connectSouth := f.checkConnection(pos, cube.FaceNorth, s), f.checkConnection(pos, cube.FaceSouth, s)
|
||
|
|
|
||
|
|
// Check if we have any connections on the Z axis
|
||
|
|
if connectWest || connectEast {
|
||
|
|
sideBox := cube.Box(0, 0, 0, 1, fenceHeight, 1).Stretch(cube.Z, -fenceInset)
|
||
|
|
if connectWest {
|
||
|
|
boxes = append(boxes, sideBox.ExtendTowards(cube.FaceEast, -fenceInset))
|
||
|
|
}
|
||
|
|
if connectEast {
|
||
|
|
boxes = append(boxes, sideBox.ExtendTowards(cube.FaceWest, -fenceInset))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if we have any connections on the X axis
|
||
|
|
if connectNorth || connectSouth {
|
||
|
|
sideBox := cube.Box(0, 0, 0, 1, fenceHeight, 1).Stretch(cube.X, -fenceInset)
|
||
|
|
if connectNorth {
|
||
|
|
boxes = append(boxes, sideBox.ExtendTowards(cube.FaceSouth, -fenceInset))
|
||
|
|
}
|
||
|
|
if connectSouth {
|
||
|
|
boxes = append(boxes, sideBox.ExtendTowards(cube.FaceNorth, -fenceInset))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// If no connections, create a center post box
|
||
|
|
if len(boxes) == 0 {
|
||
|
|
boxes = append(boxes, cube.Box(fenceInset, 0, fenceInset, 1-fenceInset, fenceHeight, 1-fenceInset))
|
||
|
|
}
|
||
|
|
|
||
|
|
return boxes
|
||
|
|
}
|
||
|
|
|
||
|
|
// FaceSolid returns true if the face is cube.FaceDown or cube.FaceUp.
|
||
|
|
func (f Fence) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
|
||
|
|
return face == cube.FaceDown || face == cube.FaceUp
|
||
|
|
}
|
||
|
|
|
||
|
|
// checkConnection checks if the block at the given position and face has a connection to the current fence block.
|
||
|
|
func (f Fence) checkConnection(pos cube.Pos, face cube.Face, src world.BlockSource) bool {
|
||
|
|
sidePos := pos.Side(face)
|
||
|
|
sideBlock := src.Block(sidePos)
|
||
|
|
if fence, ok := sideBlock.Model().(Fence); ok && fence.Wood == f.Wood {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
if sideBlock.Model().FaceSolid(sidePos, face.Opposite(), src) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
_, ok := sideBlock.Model().(FenceGate)
|
||
|
|
return ok
|
||
|
|
}
|