Files
TarnaWijaya 26ed99fda6
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
up3
2026-07-09 08:33:57 +08:00

65 lines
1.9 KiB
Go

package trace
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
"iter"
"math"
)
// Result represents the result of a ray trace collision with a bounding box.
type Result interface {
// BBox returns the bounding box collided with.
BBox() cube.BBox
// Position returns where the ray first collided with the bounding box.
Position() mgl64.Vec3
// Face returns the face of the bounding box that was collided on.
Face() cube.Face
}
type EntityFilter func(iter.Seq[world.Entity]) iter.Seq[world.Entity]
// Perform performs a ray trace between start and end, checking if any blocks or entities collided with the
// ray. The physics.BBox that's passed is used for checking if any entity within the bounding box collided
// with the ray.
func Perform(start, end mgl64.Vec3, tx *world.Tx, box cube.BBox, filter EntityFilter) (hit Result, ok bool) {
// Check if there's any blocks that we may collide with.
TraverseBlocks(start, end, func(pos cube.Pos) (cont bool) {
b := tx.Block(pos)
// Check if we collide with the block's model.
if result, ok := BlockIntercept(pos, tx, b, start, end); ok {
hit = result
end = hit.Position()
return false
}
return true
})
// Now check for any entities that we may collide with.
dist := math.MaxFloat64
bb := box.Translate(start).Extend(end.Sub(start))
entities := tx.EntitiesWithin(bb.Grow(8.0))
if filter != nil {
entities = filter(entities)
}
for entity := range entities {
if !entity.H().Type().BBox(entity).Translate(entity.Position()).IntersectsWith(bb) {
continue
}
// Check if we collide with the entities bounding box.
result, ok := EntityIntercept(entity, start, end)
if !ok {
continue
}
if distance := start.Sub(result.Position()).LenSqr(); distance < dist {
dist = distance
hit = result
}
}
return hit, hit != nil
}