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

     1  package trace
     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  	"math"
     8  )
     9  
    10  // BlockResult is the result of a ray trace collision with a block's model.
    11  type BlockResult struct {
    12  	bb   cube.BBox
    13  	pos  mgl64.Vec3
    14  	face cube.Face
    15  
    16  	blockPos cube.Pos
    17  }
    18  
    19  // BBox returns the BBox that was collided within the block's model.
    20  func (r BlockResult) BBox() cube.BBox {
    21  	return r.bb
    22  }
    23  
    24  // Position ...
    25  func (r BlockResult) Position() mgl64.Vec3 {
    26  	return r.pos
    27  }
    28  
    29  // Face returns the hit block face.
    30  func (r BlockResult) Face() cube.Face {
    31  	return r.face
    32  }
    33  
    34  // BlockPosition returns the block that was collided with.
    35  func (r BlockResult) BlockPosition() cube.Pos {
    36  	return r.blockPos
    37  }
    38  
    39  // BlockIntercept performs a ray trace and calculates the point on the block model's edge nearest to the start position
    40  // that the ray collided with.
    41  // BlockIntercept returns a BlockResult with the block collided with and with the colliding vector closest to the start position,
    42  // if no colliding point was found, a zero BlockResult is returned and ok is false.
    43  func BlockIntercept(pos cube.Pos, w *world.World, b world.Block, start, end mgl64.Vec3) (result BlockResult, ok bool) {
    44  	bbs := b.Model().BBox(pos, w)
    45  	if len(bbs) == 0 {
    46  		return
    47  	}
    48  
    49  	var (
    50  		hit  Result
    51  		dist = math.MaxFloat64
    52  	)
    53  
    54  	for _, bb := range bbs {
    55  		next, ok := BBoxIntercept(bb.Translate(pos.Vec3()), start, end)
    56  		if !ok {
    57  			continue
    58  		}
    59  
    60  		nextDist := next.Position().Sub(start).LenSqr()
    61  		if nextDist < dist {
    62  			hit = next
    63  			dist = nextDist
    64  		}
    65  	}
    66  
    67  	if hit == nil {
    68  		return result, false
    69  	}
    70  
    71  	return BlockResult{bb: hit.BBox(), pos: hit.Position(), face: hit.Face(), blockPos: pos}, true
    72  }