github.com/df-mc/dragonfly@v0.9.13/server/block/model/stair.go (about)

     1  package model
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/df-mc/dragonfly/server/world"
     6  	"github.com/go-gl/mathgl/mgl64"
     7  )
     8  
     9  // Stair is a model for stair-like blocks. These have different solid sides depending on the direction the
    10  // stairs are facing, the surrounding blocks and whether it is upside down or not.
    11  type Stair struct {
    12  	// Facing specifies the direction that the full side of the Stair faces.
    13  	Facing cube.Direction
    14  	// UpsideDown turns the Stair upside-down, meaning the full side of the Stair is turned to the top side of the
    15  	// block.
    16  	UpsideDown bool
    17  }
    18  
    19  // BBox returns a slice of physics.BBox depending on if the Stair is upside down and which direction it is facing.
    20  // Additionally, these BBoxs depend on the Stair blocks surrounding this one, which can influence the model.
    21  func (s Stair) BBox(pos cube.Pos, w *world.World) []cube.BBox {
    22  	b := []cube.BBox{cube.Box(0, 0, 0, 1, 0.5, 1)}
    23  	if s.UpsideDown {
    24  		b[0] = cube.Box(0, 0.5, 0, 1, 1, 1)
    25  	}
    26  	t := s.cornerType(pos, w)
    27  
    28  	face, oppositeFace := s.Facing.Face(), s.Facing.Opposite().Face()
    29  	if t == noCorner || t == cornerRightInner || t == cornerLeftInner {
    30  		b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
    31  			ExtendTowards(face, 0.5).
    32  			Stretch(s.Facing.RotateRight().Face().Axis(), 0.5))
    33  	}
    34  	if t == cornerRightOuter {
    35  		b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
    36  			ExtendTowards(face, 0.5).
    37  			ExtendTowards(s.Facing.RotateLeft().Face(), 0.5))
    38  	} else if t == cornerLeftOuter {
    39  		b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
    40  			ExtendTowards(face, 0.5).
    41  			ExtendTowards(s.Facing.RotateRight().Face(), 0.5))
    42  	} else if t == cornerRightInner {
    43  		b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
    44  			ExtendTowards(oppositeFace, 0.5).
    45  			ExtendTowards(s.Facing.RotateRight().Face(), 0.5))
    46  	} else if t == cornerLeftInner {
    47  		b = append(b, cube.Box(0.5, 0.5, 0.5, 0.5, 1, 0.5).
    48  			ExtendTowards(oppositeFace, 0.5).
    49  			ExtendTowards(s.Facing.RotateLeft().Face(), 0.5))
    50  	}
    51  	if s.UpsideDown {
    52  		for i := range b[1:] {
    53  			b[i+1] = b[i+1].Translate(mgl64.Vec3{0, -0.5})
    54  		}
    55  	}
    56  	return b
    57  }
    58  
    59  // FaceSolid returns true for all faces of the Stair that are completely filled.
    60  func (s Stair) FaceSolid(pos cube.Pos, face cube.Face, w *world.World) bool {
    61  	if !s.UpsideDown && face == cube.FaceDown {
    62  		// Non-upside-down stairs have a closed side at the bottom.
    63  		return true
    64  	} else if s.UpsideDown && face == cube.FaceUp {
    65  		// Upside-down stairs always have a closed side at the top.
    66  		return true
    67  	}
    68  	t := s.cornerType(pos, w)
    69  	if t == cornerRightOuter || t == cornerLeftOuter {
    70  		// Small corner blocks, they do not block water flowing out horizontally.
    71  		return false
    72  	} else if t == noCorner {
    73  		// Not a corner, so only block directly behind the stairs.
    74  		return s.Facing.Face() == face
    75  	}
    76  	if t == cornerRightInner {
    77  		return face == s.Facing.RotateRight().Face() || face == s.Facing.Face()
    78  	}
    79  	return face == s.Facing.RotateLeft().Face() || face == s.Facing.Face()
    80  }
    81  
    82  const (
    83  	noCorner = iota
    84  	cornerRightInner
    85  	cornerLeftInner
    86  	cornerRightOuter
    87  	cornerLeftOuter
    88  )
    89  
    90  // cornerType returns the type of the corner that the stairs form, or 0 if it does not form a corner with any
    91  // other stairs.
    92  func (s Stair) cornerType(pos cube.Pos, w *world.World) uint8 {
    93  	rotatedFacing := s.Facing.RotateRight()
    94  	if closedSide, ok := w.Block(pos.Side(s.Facing.Face())).Model().(Stair); ok && closedSide.UpsideDown == s.UpsideDown {
    95  		if closedSide.Facing == rotatedFacing {
    96  			return cornerLeftOuter
    97  		} else if closedSide.Facing == rotatedFacing.Opposite() {
    98  			// This will only form a corner if there is not a stair on the right of this one with the same
    99  			// direction.
   100  			if side, ok := w.Block(pos.Side(s.Facing.RotateRight().Face())).Model().(Stair); !ok || side.Facing != s.Facing || side.UpsideDown != s.UpsideDown {
   101  				return cornerRightOuter
   102  			}
   103  			return noCorner
   104  		}
   105  	}
   106  	if openSide, ok := w.Block(pos.Side(s.Facing.Opposite().Face())).Model().(Stair); ok && openSide.UpsideDown == s.UpsideDown {
   107  		if openSide.Facing == rotatedFacing {
   108  			// This will only form a corner if there is not a stair on the right of this one with the same
   109  			// direction.
   110  			if side, ok := w.Block(pos.Side(s.Facing.RotateRight().Face())).Model().(Stair); !ok || side.Facing != s.Facing || side.UpsideDown != s.UpsideDown {
   111  				return cornerRightInner
   112  			}
   113  		} else if openSide.Facing == rotatedFacing.Opposite() {
   114  			return cornerLeftInner
   115  		}
   116  	}
   117  	return noCorner
   118  }