aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--comp_map.go2
-rwxr-xr-xexample/pathfind.lua22
-rw-r--r--hydra.go2
-rw-r--r--map.go45
-rw-r--r--pathfind.go176
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()
diff --git a/hydra.go b/hydra.go
index 6da1822..6caff4c 100644
--- 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 1ffae23..3ded174 100644
--- 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
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")
+}