package trace import ( "github.com/df-mc/dragonfly/server/block/cube" "github.com/df-mc/dragonfly/server/block/model" "github.com/df-mc/dragonfly/server/world" "github.com/go-gl/mathgl/mgl64" "math" ) // BlockResult is the result of a ray trace collision with a block's model. type BlockResult struct { bb cube.BBox pos mgl64.Vec3 face cube.Face blockPos cube.Pos } // BBox returns the BBox that was collided within the block's model. func (r BlockResult) BBox() cube.BBox { return r.bb } // Position ... func (r BlockResult) Position() mgl64.Vec3 { return r.pos } // Face returns the hit block face. func (r BlockResult) Face() cube.Face { return r.face } // BlockPosition returns the block that was collided with. func (r BlockResult) BlockPosition() cube.Pos { return r.blockPos } // BlockIntercept performs a ray trace and calculates the point on the block model's edge nearest to the start position // that the ray collided with. // BlockIntercept returns a BlockResult with the block collided with and with the colliding vector closest to the start position, // if no colliding point was found, a zero BlockResult is returned and ok is false. func BlockIntercept(pos cube.Pos, src world.BlockSource, b world.Block, start, end mgl64.Vec3) (result BlockResult, ok bool) { bbs := b.Model().BBox(pos, src) if len(bbs) == 0 { return } var ( hit Result dist = math.MaxFloat64 ) for _, bb := range bbs { next, ok := BBoxIntercept(bb.Translate(pos.Vec3()), start, end) if !ok { continue } nextDist := next.Position().Sub(start).LenSqr() if nextDist < dist { hit = next dist = nextDist } } if hit == nil { return result, false } return BlockResult{bb: hit.BBox(), pos: hit.Position(), face: hit.Face(), blockPos: pos}, true } // BlockIntersects checks if the line segment from start to end intersects the block model of b at pos. Unlike // BlockIntercept, it only reports whether an intersection exists and does not calculate the closest hit position, face, // or bounding box. func BlockIntersects(pos cube.Pos, src world.BlockSource, b world.Block, start, end mgl64.Vec3) bool { m := b.Model() switch m.(type) { case model.Empty: return false case model.Solid: return BBoxIntersects(cube.Box(0, 0, 0, 1, 1, 1).Translate(pos.Vec3()), start, end) } for _, bb := range m.BBox(pos, src) { if BBoxIntersects(bb.Translate(pos.Vec3()), start, end) { return true } } return false }