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
+22
View File
@@ -0,0 +1,22 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Anvil is a model used by anvils.
type Anvil struct {
// Facing is the direction that the anvil is facing.
Facing cube.Direction
}
// BBox ...
func (a Anvil) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{full.Stretch(a.Facing.RotateLeft().Face().Axis(), -0.125)}
}
// FaceSolid ...
func (Anvil) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Bed is a model used for beds. This model works for both parts of the bed.
type Bed struct{}
// BBox ...
func (b Bed) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.5625, 1)}
}
// FaceSolid ...
func (Bed) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+22
View File
@@ -0,0 +1,22 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// BrewingStand is a model used by brewing stands.
type BrewingStand struct{}
// BBox ...
func (b BrewingStand) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{
full.ExtendTowards(cube.FaceUp, -0.875),
full.Stretch(cube.X, -0.4375).Stretch(cube.Z, -0.4375).ExtendTowards(cube.FaceDown, 0.125),
}
}
// FaceSolid ...
func (b BrewingStand) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Cactus is the model for a Cactus. It is just barely not a full block, having a slightly reduced width and depth.
type Cactus struct{}
// BBox returns a physics.BBox that is slightly smaller than a full block.
func (Cactus) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.025, 0, 0.025, 0.975, 1, 0.975)}
}
// FaceSolid always returns false.
func (Cactus) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+24
View File
@@ -0,0 +1,24 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Cake is a model used by cake blocks.
type Cake struct {
// Bites is the amount of bites that were taken from the cake. A cake can have up to 7 bites taken from it, before
// being consumed entirely.
Bites int
}
// BBox returns an BBox with a size that depends on the amount of bites taken.
func (c Cake) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.0625, 0, 0.0625, 0.9375, 0.5, 0.9375).
ExtendTowards(cube.FaceWest, -(float64(c.Bites) / 8))}
}
// FaceSolid always returns false.
func (c Cake) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Campfire is the model used by campfires.
type Campfire struct{}
// BBox returns a flat BBox with a height of 0.4375.
func (Campfire) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.4375, 1)}
}
// FaceSolid returns true if the face is down.
func (Campfire) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
return face == cube.FaceDown
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Carpet is a model for carpet-like extremely thin blocks.
type Carpet struct{}
// BBox returns a flat BBox with a width of 0.0625.
func (Carpet) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.0625, 1)}
}
// FaceSolid always returns false.
func (Carpet) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+22
View File
@@ -0,0 +1,22 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Chain is a model used by chain blocks.
type Chain struct {
// Axis is the axis which the chain faces.
Axis cube.Axis
}
// BBox ...
func (c Chain) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.40625, 0.40625, 0.40625, 0.59375, 0.59375, 0.59375).Stretch(c.Axis, 0.40625)}
}
// FaceSolid ...
func (Chain) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+20
View File
@@ -0,0 +1,20 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Chest is the model of a chest. It is just barely not a full block, having a slightly reduced with on all
// axes.
type Chest struct{}
// BBox returns a physics.BBox that is slightly smaller than a full block.
func (Chest) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.025, 0, 0.025, 0.975, 0.95, 0.975)}
}
// FaceSolid always returns false.
func (Chest) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+30
View File
@@ -0,0 +1,30 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// CocoaBean is a model used by cocoa bean blocks.
type CocoaBean struct {
// Facing is the face that the cocoa bean faces. It is the opposite of the face that the CocoaBean is attached to.
Facing cube.Direction
// Age is the age of the CocoaBean. The age influences the size of the CocoaBean. The maximum age value of a cocoa
// bean is 3.
Age int
}
// BBox returns a single physics.BBox whose size depends on the age of the CocoaBean.
func (c CocoaBean) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{full.
Stretch(c.Facing.RotateRight().Face().Axis(), -(6-float64(c.Age))/16).
ExtendTowards(cube.FaceUp, -0.25).
ExtendTowards(cube.FaceDown, -((7-float64(c.Age)*2)/16)).
ExtendTowards(c.Facing.Face(), -0.0625).
ExtendTowards(c.Facing.Opposite().Face(), -((11 - float64(c.Age)*2) / 16))}
}
// FaceSolid always returns false.
func (c CocoaBean) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+32
View File
@@ -0,0 +1,32 @@
package model
import (
"math"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Composter is a model used by composter blocks. It is solid on all sides apart from the top, and the height of the
// inside area depends on the level of compost inside the composter.
type Composter struct {
// Level is the level of compost inside the composter.
Level int
}
// BBox ...
func (c Composter) BBox(_ cube.Pos, _ world.BlockSource) []cube.BBox {
compostHeight := math.Abs(math.Min(float64(c.Level), 7)*0.125 - 0.0625)
return []cube.BBox{
cube.Box(0, 0, 0, 1, 1, 0.125),
cube.Box(0, 0, 0.875, 1, 1, 1),
cube.Box(0.875, 0, 0, 1, 1, 1),
cube.Box(0, 0, 0, 0.125, 1, 1),
cube.Box(0.125, 0, 0.125, 0.875, 0.125+compostHeight, 0.875),
}
}
// FaceSolid returns true for all faces other than the top.
func (Composter) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
return face != cube.FaceUp
}
+20
View File
@@ -0,0 +1,20 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// DecoratedPot is the model for a DecoratedPot. It is just barely not a full block, having a slightly reduced width and
// depth.
type DecoratedPot struct{}
// BBox returns a physics.BBox that is slightly smaller than a full block.
func (DecoratedPot) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.025, 0, 0.025, 0.975, 1, 0.975)}
}
// FaceSolid always returns true for the top and bottom face, and false for all other faces.
func (DecoratedPot) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
return face.Axis() == cube.Y
}
+5
View File
@@ -0,0 +1,5 @@
// Package model has world.BlockModel implementations for each world.Block implementation in the block package. These
// models may be reused by blocks that share the same model.
// Some block models require additional fields and knowledge about the surrounding blocks to calculate the correct
// model.
package model
+34
View File
@@ -0,0 +1,34 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Door is a model used for doors. It has no solid faces and a bounding box that changes depending on
// the direction of the door, whether it is open, and the side of its hinge.
type Door struct {
// Facing is the direction that the door is facing when closed.
Facing cube.Direction
// Open specifies if the Door is open. The direction it opens towards depends on the Right field.
Open bool
// Right specifies the attachment side of the door and, with that, the direction it opens in.
Right bool
}
// BBox returns a physics.BBox that depends on if the Door is open, what direction it is facing and whether it is
// attached to the right/left side of a block.
func (d Door) BBox(cube.Pos, world.BlockSource) []cube.BBox {
if d.Open {
if d.Right {
return []cube.BBox{full.ExtendTowards(d.Facing.RotateLeft().Face(), -0.8125)}
}
return []cube.BBox{full.ExtendTowards(d.Facing.RotateRight().Face(), -0.8125)}
}
return []cube.BBox{full.ExtendTowards(d.Facing.Face(), -0.8125)}
}
// FaceSolid always returns false.
func (d Door) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Empty is a model that is completely empty. It has no collision boxes or solid faces.
type Empty struct{}
// BBox returns an empty slice.
func (Empty) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return nil
}
// FaceSolid always returns false.
func (Empty) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// EnchantingTable is a model used by enchanting tables.
type EnchantingTable struct{}
// BBox ...
func (EnchantingTable) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.75, 1)}
}
// FaceSolid ...
func (EnchantingTable) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+22
View File
@@ -0,0 +1,22 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// EndRod is a model used by end rod blocks.
type EndRod struct {
// Axis is the axis which the end rod faces.
Axis cube.Axis
}
// BBox ...
func (e EndRod) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.375, 0.375, 0.375, 0.625, 0.625, 0.625).Stretch(e.Axis, 0.375)}
}
// FaceSolid ...
func (EndRod) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+75
View File
@@ -0,0 +1,75 @@
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
}
+28
View File
@@ -0,0 +1,28 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// FenceGate is a model used by fence gates. The model is completely zero-ed when the FenceGate is opened.
type FenceGate struct {
// Facing is the facing direction of the FenceGate. A fence gate can only be opened in this direction or the
// direction opposite to it.
Facing cube.Direction
// Open specifies if the FenceGate is open. In this case, BBox returns an empty slice.
Open bool
}
// BBox returns up to one physics.BBox depending on the facing direction of the FenceGate and whether it is open.
func (f FenceGate) BBox(cube.Pos, world.BlockSource) []cube.BBox {
if f.Open {
return nil
}
return []cube.BBox{cube.Box(0, 0, 0, 1, 1.5, 1).Stretch(f.Facing.Face().Axis(), -0.375)}
}
// FaceSolid always returns false.
func (f FenceGate) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+22
View File
@@ -0,0 +1,22 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Grindstone is a model used by grindstones.
type Grindstone struct {
// Axis is the axis the grindstone is attached to.
Axis cube.Axis
}
// BBox ...
func (g Grindstone) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.125, 0.125, 0.125, 0.825, 0.825, 0.825).Stretch(g.Axis, 0.125)}
}
// FaceSolid always returns false.
func (g Grindstone) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+23
View File
@@ -0,0 +1,23 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Hopper is a model used by hoppers.
type Hopper struct{}
// BBox returns a physics.BBox that spans a full block.
func (h Hopper) BBox(cube.Pos, world.BlockSource) []cube.BBox {
bbox := []cube.BBox{full.ExtendTowards(cube.FaceUp, -0.375)}
for _, f := range cube.HorizontalFaces() {
bbox = append(bbox, full.ExtendTowards(f, -0.875))
}
return bbox
}
// FaceSolid only returns true for the top face of the hopper.
func (Hopper) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
return face == cube.FaceUp
}
+22
View File
@@ -0,0 +1,22 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Ladder is the model for a ladder block.
type Ladder struct {
// Facing is the side opposite to the block the Ladder is currently attached to.
Facing cube.Direction
}
// BBox returns one physics.BBox that depends on the facing direction of the Ladder.
func (l Ladder) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{full.ExtendTowards(l.Facing.Face(), -0.8125)}
}
// FaceSolid always returns false.
func (l Ladder) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+25
View File
@@ -0,0 +1,25 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Lantern is a model for the lantern block. It can be placed on the ground or hanging from the ceiling.
type Lantern struct {
// Hanging specifies if the lantern is hanging from a block or if it's placed on the ground.
Hanging bool
}
// BBox returns a physics.BBox attached to either the ceiling or to the ground.
func (l Lantern) BBox(cube.Pos, world.BlockSource) []cube.BBox {
if l.Hanging {
return []cube.BBox{cube.Box(0.3125, 0.125, 0.3125, 0.6875, 0.625, 0.6875)}
}
return []cube.BBox{cube.Box(0.3125, 0, 0.3125, 0.6875, 0.5, 0.6875)}
}
// FaceSolid always returns false.
func (l Lantern) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+20
View File
@@ -0,0 +1,20 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Leaves is a model for leaves-like blocks. These blocks have a full collision box, but none of their faces
// are solid.
type Leaves struct{}
// BBox returns a physics.BBox that spans a full block.
func (Leaves) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{full}
}
// FaceSolid always returns false.
func (Leaves) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Lectern is a model used by lecterns.
type Lectern struct{}
// BBox ...
func (Lectern) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.9, 1)}
}
// FaceSolid ...
func (Lectern) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// LilyPad is a model for the lily pad block.
type LilyPad struct{}
// BBox ...
func (LilyPad) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0.0625, 0, 0.0625, 0.9375, 0.015625, 0.9375)}
}
// FaceSolid ...
func (LilyPad) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+28
View File
@@ -0,0 +1,28 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Skull is a model used by skull blocks.
type Skull struct {
// Direction is the direction the skull is facing.
Direction cube.Face
// Hanging specifies if the Skull is hanging on a wall.
Hanging bool
}
// BBox ...
func (s Skull) BBox(cube.Pos, world.BlockSource) []cube.BBox {
box := cube.Box(0.25, 0, 0.25, 0.75, 0.5, 0.75)
if !s.Hanging {
return []cube.BBox{box}
}
return []cube.BBox{box.TranslateTowards(s.Direction.Opposite(), 0.25).TranslateTowards(cube.FaceUp, 0.25)}
}
// FaceSolid ...
func (Skull) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+37
View File
@@ -0,0 +1,37 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Slab is the model of a slab-like block, which is either a half block or a full block, depending on if the
// slab is double.
type Slab struct {
// Double and Top specify if the Slab is a double slab and if it's in the top slot respectively. If Double is true,
// the BBox returned is always a full block.
Double, Top bool
}
// BBox returns either a physics.BBox spanning a full block or a half block in the top/bottom part of the block,
// depending on the Double and Top fields.
func (s Slab) BBox(cube.Pos, world.BlockSource) []cube.BBox {
if s.Double {
return []cube.BBox{full}
}
if s.Top {
return []cube.BBox{cube.Box(0, 0.5, 0, 1, 1, 1)}
}
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.5, 1)}
}
// FaceSolid returns true if the Slab is double, or if the face is cube.FaceUp when the Top field is true, or if the
// face is cube.FaceDown when the Top field is false.
func (s Slab) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
if s.Double {
return true
} else if s.Top {
return face == cube.FaceUp
}
return face == cube.FaceDown
}
+23
View File
@@ -0,0 +1,23 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Solid is the model of a fully solid block. Blocks with this model, such as stone or wooden planks, have a
// 1x1x1 collision box.
type Solid struct{}
// full is a BBox that occupies a full block.
var full = cube.Box(0, 0, 0, 1, 1, 1)
// BBox returns a physics.BBox spanning a full block.
func (Solid) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{full}
}
// FaceSolid always returns true.
func (Solid) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return true
}
+118
View File
@@ -0,0 +1,118 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
)
// Stair is a model for stair-like blocks. These have different solid sides depending on the direction the
// stairs are facing, the surrounding blocks and whether it is upside down or not.
type Stair struct {
// Facing specifies the direction that the full side of the Stair faces.
Facing cube.Direction
// UpsideDown turns the Stair upside-down, meaning the full side of the Stair is turned to the top side of the
// block.
UpsideDown bool
}
// BBox returns a slice of physics.BBox depending on if the Stair is upside down and which direction it is facing.
// Additionally, these BBoxs depend on the Stair blocks surrounding this one, which can influence the model.
func (s Stair) BBox(pos cube.Pos, bs world.BlockSource) []cube.BBox {
b := []cube.BBox{cube.Box(0, 0, 0, 1, 0.5, 1)}
if s.UpsideDown {
b[0] = cube.Box(0, 0.5, 0, 1, 1, 1)
}
t := s.cornerType(pos, bs)
face, oppositeFace := s.Facing.Face(), s.Facing.Opposite().Face()
switch t {
case noCorner, cornerRightInner, cornerLeftInner:
b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
ExtendTowards(face, 0.5).
Stretch(s.Facing.RotateRight().Face().Axis(), 0.5))
}
switch t {
case cornerRightOuter:
b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
ExtendTowards(face, 0.5).
ExtendTowards(s.Facing.RotateLeft().Face(), 0.5))
case cornerLeftOuter:
b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
ExtendTowards(face, 0.5).
ExtendTowards(s.Facing.RotateRight().Face(), 0.5))
case cornerRightInner:
b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
ExtendTowards(oppositeFace, 0.5).
ExtendTowards(s.Facing.RotateRight().Face(), 0.5))
case cornerLeftInner:
b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
ExtendTowards(oppositeFace, 0.5).
ExtendTowards(s.Facing.RotateLeft().Face(), 0.5))
}
if s.UpsideDown {
for i := range b[1:] {
b[i+1] = b[i+1].Translate(mgl64.Vec3{0, -0.5})
}
}
return b
}
// FaceSolid returns true for all faces of the Stair that are completely filled.
func (s Stair) FaceSolid(pos cube.Pos, face cube.Face, bs world.BlockSource) bool {
// Stairs always have a closed side at the top or bottom based on their orientation.
if (face == cube.FaceUp && s.UpsideDown) || (face == cube.FaceDown && !s.UpsideDown) {
return true
}
switch t := s.cornerType(pos, bs); t {
case cornerRightOuter, cornerLeftOuter:
// Small corner blocks, they do not block water flowing out horizontally.
return false
case noCorner:
// Not a corner, so only block directly behind the stairs.
return s.Facing.Face() == face
case cornerRightInner:
return face == s.Facing.RotateRight().Face() || face == s.Facing.Face()
default:
return face == s.Facing.RotateLeft().Face() || face == s.Facing.Face()
}
}
const (
noCorner = iota
cornerRightInner
cornerLeftInner
cornerRightOuter
cornerLeftOuter
)
// cornerType returns the type of the corner that the stairs form, or 0 if it does not form a corner with any
// other stairs.
func (s Stair) cornerType(pos cube.Pos, bs world.BlockSource) uint8 {
rotatedFacing := s.Facing.RotateRight()
if closedSide, ok := bs.Block(pos.Side(s.Facing.Face())).Model().(Stair); ok && closedSide.UpsideDown == s.UpsideDown {
if closedSide.Facing == rotatedFacing {
return cornerLeftOuter
} else if closedSide.Facing == rotatedFacing.Opposite() {
// This will only form a corner if there is not a stair on the right of this one with the same
// direction.
if side, ok := bs.Block(pos.Side(s.Facing.RotateRight().Face())).Model().(Stair); !ok || side.Facing != s.Facing || side.UpsideDown != s.UpsideDown {
return cornerRightOuter
}
return noCorner
}
}
if openSide, ok := bs.Block(pos.Side(s.Facing.Opposite().Face())).Model().(Stair); ok && openSide.UpsideDown == s.UpsideDown {
if openSide.Facing == rotatedFacing {
// This will only form a corner if there is not a stair on the right of this one with the same
// direction.
if side, ok := bs.Block(pos.Side(s.Facing.RotateRight().Face())).Model().(Stair); !ok || side.Facing != s.Facing || side.UpsideDown != s.UpsideDown {
return cornerRightInner
}
} else if openSide.Facing == rotatedFacing.Opposite() {
return cornerLeftInner
}
}
return noCorner
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Stonecutter is a model used by stonecutters.
type Stonecutter struct{}
// BBox ...
func (Stonecutter) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.5625, 1)}
}
// FaceSolid ...
func (Stonecutter) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return false
}
+66
View File
@@ -0,0 +1,66 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Thin is a model for thin, partial blocks such as a glass pane or an iron bar. It changes its bounding box depending
// on solid faces next to it.
type Thin struct{}
const (
thinHeight = 1
thinInset = 7.0 / 16.0
)
// BBox returns a slice of physics.BBox that depends on the blocks surrounding the Thin block. Thin blocks can connect
// to any other Thin block, wall or solid faces of other blocks.
func (t Thin) BBox(pos cube.Pos, s world.BlockSource) []cube.BBox {
boxes := make([]cube.BBox, 0, 2)
// Check if we have any connections on the Z axis
connectWest, connectEast := t.checkConnection(pos, cube.FaceWest, s), t.checkConnection(pos, cube.FaceEast, s)
if connectWest || connectEast {
box := cube.Box(0, 0, 0, 1, thinHeight, 1).Stretch(cube.Z, -thinInset)
if !connectWest {
box = box.ExtendTowards(cube.FaceWest, -thinInset)
} else if !connectEast {
box = box.ExtendTowards(cube.FaceEast, -thinInset)
}
boxes = append(boxes, box)
}
// Check if we have any connections on the X axis
connectNorth, connectSouth := t.checkConnection(pos, cube.FaceNorth, s), t.checkConnection(pos, cube.FaceSouth, s)
if connectNorth || connectSouth {
box := cube.Box(0, 0, 0, 1, thinHeight, 1).Stretch(cube.X, -thinInset)
if !connectNorth {
box = box.ExtendTowards(cube.FaceNorth, -thinInset)
} else if !connectSouth {
box = box.ExtendTowards(cube.FaceSouth, -thinInset)
}
boxes = append(boxes, box)
}
// If no connections, create a center post box
if len(boxes) == 0 {
boxes = append(boxes, cube.Box(0, 0, 0, 1, thinHeight, 1).Stretch(cube.X, -thinInset).Stretch(cube.Z, -thinInset))
}
return boxes
}
// FaceSolid returns true if the face passed is cube.FaceDown.
func (t Thin) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
return face == cube.FaceDown
}
// checkConnection checks if the block at the given position and face has a connection to the current thin block.
func (t Thin) checkConnection(pos cube.Pos, face cube.Face, s world.BlockSource) bool {
sidePos := pos.Side(face)
sideBlock := s.Block(sidePos)
_, isThin := sideBlock.Model().(Thin)
_, isWall := sideBlock.Model().(Wall)
return isThin || isWall || sideBlock.Model().FaceSolid(sidePos, face.Opposite(), s)
}
+19
View File
@@ -0,0 +1,19 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// TilledGrass is a model used for grass that has been tilled in some way, such as dirt paths and farmland.
type TilledGrass struct{}
// BBox returns a physics.BBox that spans an entire block.
func (TilledGrass) BBox(cube.Pos, world.BlockSource) []cube.BBox {
return []cube.BBox{full.ExtendTowards(cube.FaceUp, -0.0625)}
}
// FaceSolid always returns true.
func (TilledGrass) FaceSolid(cube.Pos, cube.Face, world.BlockSource) bool {
return true
}
+37
View File
@@ -0,0 +1,37 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Trapdoor is a model used for trapdoors. It has no solid faces and a bounding box that changes depending on
// the direction of the trapdoor.
type Trapdoor struct {
// Facing is the facing direction of the Trapdoor. In addition to the texture, it influences the direction in which
// the Trapdoor is opened.
Facing cube.Direction
// Open and Top specify if the Trapdoor is opened and if it's in the top or bottom part of a block respectively.
Open, Top bool
}
// BBox returns a physics.BBox that depends on the facing direction of the Trapdoor and whether it is open and in the
// top part of the block.
func (t Trapdoor) BBox(cube.Pos, world.BlockSource) []cube.BBox {
if t.Open {
return []cube.BBox{full.ExtendTowards(t.Facing.Face(), -0.8125)}
} else if t.Top {
return []cube.BBox{cube.Box(0, 0.8125, 0, 1, 1, 1)}
}
return []cube.BBox{cube.Box(0, 0, 0, 1, 0.1875, 1)}
}
// FaceSolid returns true if the face is completely filled with the trapdoor.
func (t Trapdoor) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
if t.Open {
return t.Facing.Face().Opposite() == face
} else if t.Top {
return face == cube.FaceUp
}
return face == cube.FaceDown
}
+47
View File
@@ -0,0 +1,47 @@
package model
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
)
// Wall is a model used by all wall types.
type Wall struct {
// NorthConnection is the height of the connection for the north direction.
NorthConnection float64
// EastConnection is the height of the connection for the east direction.
EastConnection float64
// SouthConnection is the height of the connection for the south direction.
SouthConnection float64
// WestConnection is the height of the connection for the west direction.
WestConnection float64
// Post is if the wall is the full height of a block or not.
Post bool
}
// BBox ...
func (w Wall) BBox(cube.Pos, world.BlockSource) []cube.BBox {
postHeight := 0.8125
if w.Post {
postHeight = 1
}
boxes := []cube.BBox{cube.Box(0.25, 0, 0.25, 0.75, postHeight, 0.75)}
if w.NorthConnection > 0 {
boxes = append(boxes, cube.Box(0.25, 0, 0, 0.75, w.NorthConnection, 0.25))
}
if w.EastConnection > 0 {
boxes = append(boxes, cube.Box(0.75, 0, 0.25, 1, w.EastConnection, 0.75))
}
if w.SouthConnection > 0 {
boxes = append(boxes, cube.Box(0.25, 0, 0.75, 0.75, w.SouthConnection, 1))
}
if w.WestConnection > 0 {
boxes = append(boxes, cube.Box(0, 0, 0.25, 0.25, w.WestConnection, 0.75))
}
return boxes
}
// FaceSolid returns true if the face is in the Y axis.
func (w Wall) FaceSolid(_ cube.Pos, face cube.Face, _ world.BlockSource) bool {
return face.Axis() == cube.Y
}