diff options
-rw-r--r-- | comp_map.go | 2 | ||||
-rwxr-xr-x | example/pathfind.lua | 22 | ||||
-rw-r--r-- | hydra.go | 2 | ||||
-rw-r--r-- | map.go | 45 | ||||
-rw-r--r-- | pathfind.go | 176 |
5 files changed, 231 insertions, 16 deletions
diff --git a/comp_map.go b/comp_map.go index c45155e..eed5039 100644 --- a/comp_map.go +++ b/comp_map.go @@ -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 index 0000000..a9b0723 --- /dev/null +++ b/example/pathfind.lua @@ -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() @@ -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, @@ -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 index 0000000..015ff7e --- /dev/null +++ b/pathfind.go @@ -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") +} |