-
Notifications
You must be signed in to change notification settings - Fork 140
/
result.go
57 lines (50 loc) · 1.77 KB
/
result.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package trace
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
"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
}
// 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, w *world.World, box cube.BBox, ignored func(world.Entity) bool) (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 := w.Block(pos)
// Check if we collide with the block's model.
if result, ok := BlockIntercept(pos, w, 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))
for _, entity := range w.EntitiesWithin(bb.Grow(8.0), ignored) {
if ignored != nil && ignored(entity) || !entity.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
}