1
0
Fork 0
mirror of https://github.com/dragonfireclient/hydra-dragonfire.git synced 2024-11-21 10:24:01 -05:00
hydra-dragonfire/pathfind.go
2022-06-03 17:42:59 +02:00

176 lines
3.1 KiB
Go

package main
import (
"github.com/anon55555/mt"
"math"
"sync"
)
type PathfindEdge struct {
src, dst [3]int16
weight float64
}
const pfMaxtp float64 = 4.317 * 10.0 * 0.5
const pfMaxtpSq float64 = pfMaxtp * pfMaxtp
var pfDirs = [6][3]int16{
[3]int16{+1, 0, 0},
[3]int16{-1, 0, 0},
[3]int16{0, +1, 0},
[3]int16{0, -1, 0},
[3]int16{0, 0, +1},
[3]int16{0, 0, -1},
}
func pfRidx(idx int) int {
if idx%2 == 0 {
return idx + 1
} else {
return idx - 1
}
}
func pfCenterFindAir(blk *MapBlk, pos [3]int16, chans [6]chan [3]int16, done *bool) {
for _, ch := range chans {
if ch != nil {
defer close(ch)
}
}
for x := uint16(0); x < 16; x++ {
for z := uint16(0); z < 16; z++ {
for y := uint16(0); y < 16; y++ {
if *done {
return
}
if blk.data.Param0[x|(y<<4)|(z<<8)] == mt.Air {
for _, ch := range chans {
if ch != nil {
ch <- [3]int16{int16(x) + pos[0], int16(y) + pos[1], int16(z) + pos[2]}
}
}
break
}
}
}
}
}
func pfMakeEdge(src [3]int16, dst [3]int16, vertical bool, edge **PathfindEdge) bool {
var distSq float64
for i, v := range dst {
if vertical == (i == 1) {
abs := math.Abs(float64(v - src[i]))
if abs > 0 {
abs -= 1
}
distSq += math.Pow(abs, 2)
}
}
if vertical || distSq <= pfMaxtpSq {
*edge = &PathfindEdge{
src: src,
dst: dst,
weight: math.Sqrt(distSq),
}
return true
}
return false
}
func pfNeighFindAir(blk *MapBlk, pos [3]int16, ch chan [3]int16, wg *sync.WaitGroup, vertical bool, edge **PathfindEdge) {
defer wg.Done()
var prev [][3]int16
for x := uint16(0); x < 16; x++ {
for z := uint16(0); z < 16; z++ {
for y := uint16(0); y < 16; y++ {
if blk.data.Param0[x|(y<<4)|(z<<8)] == mt.Air {
dst := [3]int16{int16(x) + pos[0], int16(y) + pos[1], int16(z) + pos[2]}
for _, src := range prev {
if pfMakeEdge(dst, src, vertical, edge) {
return
}
}
for ch != nil {
src, ok := <-ch
if ok {
if pfMakeEdge(dst, src, vertical, edge) {
return
} else {
prev = append(prev, src)
}
} else {
ch = nil
if len(prev) == 0 {
return
}
}
}
}
}
}
}
}
func pfPreprocess(mp *Map, blkpos [3]int16, blk *MapBlk) {
println("preprocess")
var chans [6]chan [3]int16
var blks [6]*MapBlk
var wg sync.WaitGroup
var pos [3]int16
for k, v := range blkpos {
pos[k] = v * 16
}
for i := range chans {
npos := pos
nblkpos := blkpos
for j, v := range pfDirs[i] {
npos[j] += v * 16
nblkpos[j] += v
}
if nblk, ok := mp.blocks[nblkpos]; ok {
blks[i] = nblk
chans[i] = make(chan [3]int16, 4096)
wg.Add(1)
go pfNeighFindAir(blk, npos, chans[i], &wg, i == 2 || i == 3, &blk.edges[i])
}
}
var done bool
go pfCenterFindAir(blk, pos, chans, &done)
wg.Wait()
done = true
for i, nblk := range blks {
if nblk != nil {
edge := blk.edges[i]
ri := pfRidx(i)
if edge == nil {
nblk.edges[ri] = nil
} else {
nblk.edges[ri] = &PathfindEdge{
src: edge.dst,
dst: edge.src,
weight: edge.weight,
}
}
}
}
println("finish preprocess")
}