"sync"
)
+type MapBlk struct {
+ data *mt.MapBlk
+ edges [6]*PathfindEdge
+}
+
type Map struct {
mu sync.Mutex
- blocks map[[3]int16]*mt.MapBlk
+ pathfind bool
+ blocks map[[3]int16]*MapBlk
userdata *lua.LUserData
}
func newMap(l *lua.LState) *Map {
mp := &Map{}
- mp.blocks = map[[3]int16]*mt.MapBlk{}
+ mp.blocks = map[[3]int16]*MapBlk{}
mp.userdata = l.NewUserData()
mp.userdata.Value = mp
l.SetMetatable(mp.userdata, l.GetTypeMetatable("hydra.map"))
func (mp *Map) process(client *Client, pkt *mt.Pkt) {
switch cmd := pkt.Cmd.(type) {
case *mt.ToCltBlkData:
- mp.mu.Lock()
- mp.blocks[cmd.Blkpos] = &cmd.Blk
- mp.mu.Unlock()
+ go func() {
+ mp.mu.Lock()
+ defer mp.mu.Unlock()
+
+ blk := &MapBlk{}
+ blk.data = &cmd.Blk
+ if mp.pathfind {
+ pfPreprocess(mp, cmd.Blkpos, blk)
+ }
+
+ mp.blocks[cmd.Blkpos] = blk
+ }()
+
client.conn.SendCmd(&mt.ToSrvGotBlks{Blks: [][3]int16{cmd.Blkpos}})
}
}
func l_map(l *lua.LState) int {
mp := newMap(l)
+ mp.pathfind = l.ToBool(1)
l.Push(mp.userdata)
return 1
}
mp.mu.Lock()
defer mp.mu.Unlock()
- block, ok := mp.blocks[blkpos]
+ blk, ok := mp.blocks[blkpos]
if ok {
- l.Push(convert.PushMapBlk(l, *block))
+ l.Push(convert.PushMapBlk(l, *blk.data))
} else {
l.Push(lua.LNil)
}
mp.mu.Lock()
defer mp.mu.Unlock()
- block, block_exists := mp.blocks[blkpos]
- if block_exists {
- meta, meta_exists := block.NodeMetas[i]
- if !meta_exists {
+ blk, blk_ok := mp.blocks[blkpos]
+ if blk_ok {
+ meta, meta_ok := blk.data.NodeMetas[i]
+ if !meta_ok {
meta = &mt.NodeMeta{}
}
lnode := l.NewTable()
- l.SetField(lnode, "param0", lua.LNumber(block.Param0[i]))
- l.SetField(lnode, "param1", lua.LNumber(block.Param1[i]))
- l.SetField(lnode, "param2", lua.LNumber(block.Param2[i]))
+ l.SetField(lnode, "param0", lua.LNumber(blk.data.Param0[i]))
+ l.SetField(lnode, "param1", lua.LNumber(blk.data.Param1[i]))
+ l.SetField(lnode, "param2", lua.LNumber(blk.data.Param2[i]))
l.SetField(lnode, "meta", convert.PushNodeMeta(l, *meta))
l.Push(lnode)
} else {
--- /dev/null
+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")
+}