]> git.lizzy.rs Git - hydra-dragonfire.git/commitdiff
Pathfind: preprocessing pathfind
authorElias Fleckenstein <eliasfleckenstein@web.de>
Fri, 3 Jun 2022 15:42:59 +0000 (17:42 +0200)
committerElias Fleckenstein <eliasfleckenstein@web.de>
Fri, 3 Jun 2022 15:42:59 +0000 (17:42 +0200)
comp_map.go
example/pathfind.lua [new file with mode: 0755]
hydra.go
map.go
pathfind.go [new file with mode: 0644]

index c45155e3d58a114c9d7c8597df2baf10d69a7ae0..eed5039352aef08c631c5e36af9f467e523917ff 100644 (file)
@@ -7,7 +7,7 @@ import (
 
 type CompMap struct {
        client   *Client
-       mapdata *Map
+       mapdata  *Map
        userdata *lua.LUserData
 }
 
diff --git a/example/pathfind.lua b/example/pathfind.lua
new file mode 100755 (executable)
index 0000000..a9b0723
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env hydra-dragonfire
+local client = require("client")()
+
+client:enable("map")
+client.map:set(hydra.map(true))
+
+client:enable("pkts")
+client.pkts:subscribe("chat_msg")
+
+client:connect()
+
+while true do
+       local evt = client:poll()
+
+       if not evt or evt.type == "disconnect" or evt.type == "interrupt" then
+               break
+       elseif evt.type == "pkt" then
+               print("chatmsg")
+       end
+end
+
+client:close()
index 6da1822cc295ef5548288846c61a2b222efce393..6caff4cb48040c1cf79238ed7f2afabe2dcab3d8 100644 (file)
--- a/hydra.go
+++ b/hydra.go
@@ -40,7 +40,7 @@ var builtinFiles = []string{
 
 var hydraFuncs = map[string]lua.LGFunction{
        "client": l_client,
-       "map": l_map,
+       "map":    l_map,
        "dtime":  l_dtime,
        "poll":   l_poll,
        "close":  l_close,
diff --git a/map.go b/map.go
index 1ffae233dc6940a63cf58c1ca343261bc845c464..3ded174b4727bb3263ac32d7f13688b182c55461 100644 (file)
--- a/map.go
+++ b/map.go
@@ -7,9 +7,15 @@ import (
        "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
 }
 
@@ -24,7 +30,7 @@ func getMap(l *lua.LState, idx int) *Map {
 
 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"))
@@ -34,15 +40,26 @@ func newMap(l *lua.LState) *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
 }
@@ -55,9 +72,9 @@ func l_map_block(l *lua.LState) int {
        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)
        }
@@ -75,17 +92,17 @@ func l_map_node(l *lua.LState) int {
        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 {
diff --git a/pathfind.go b/pathfind.go
new file mode 100644 (file)
index 0000000..015ff7e
--- /dev/null
@@ -0,0 +1,176 @@
+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")
+}