aoi.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. package aoi
  2. //"gopkg.in/fatih/set.v0"
  3. import (
  4. "math"
  5. "rocommon/util"
  6. "roserver/baseserver/set"
  7. "sort"
  8. "sync"
  9. "time"
  10. )
  11. const (
  12. LISTTYPE_X = 1
  13. LISTTYPE_Y = 2
  14. FIND_NUM_MAX = 10
  15. )
  16. type AoiVector2 struct {
  17. X float32
  18. Y float32
  19. Z float32
  20. }
  21. //set https://studygolang.com/articles/16224?fr=sidebar
  22. //https://github.com/qq362946/AOI
  23. type aoiInfo struct {
  24. MoveSet set.Interface
  25. MoveOnlySet set.Interface
  26. EnterSet set.Interface
  27. LeaveSet set.Interface
  28. MoveNoNtfSet set.Interface
  29. }
  30. type aoiLinkNode struct {
  31. Next *AoiObject
  32. Pre *AoiObject
  33. }
  34. type AoiObject struct {
  35. Id uint64
  36. Pos *AoiVector2
  37. AoiInfo *aoiInfo
  38. node *Node
  39. updateCount int32
  40. rect *QuadBounds
  41. }
  42. func NewAoiObject(id uint64, x, y float32, z float32) *AoiObject {
  43. obj := new(AoiObject)
  44. obj.Id = id
  45. obj.Pos = &AoiVector2{X: x, Y: y, Z: z}
  46. obj.updateCount = 0
  47. obj.AoiInfo = &aoiInfo{}
  48. obj.AoiInfo.MoveSet = set.New(set.NonThreadSafe)
  49. obj.AoiInfo.MoveOnlySet = set.New(set.NonThreadSafe)
  50. obj.AoiInfo.EnterSet = set.New(set.NonThreadSafe)
  51. obj.AoiInfo.LeaveSet = set.New(set.NonThreadSafe)
  52. obj.AoiInfo.MoveNoNtfSet = set.New(set.NonThreadSafe)
  53. return obj
  54. }
  55. func (this *AoiObject) SetNode(node *Node) {
  56. this.node = node
  57. }
  58. func (this *AoiObject) SetPosition(x, y float32) {
  59. this.Pos.X = x
  60. this.Pos.Y = y
  61. }
  62. func (this *AoiObject) GetMoveSize() int32 {
  63. return int32(this.AoiInfo.MoveSet.Size())
  64. }
  65. ///////////////////////
  66. type Aoi struct {
  67. nodes map[uint64]*AoiObject
  68. xNodeList *SkipList
  69. yNodeList *SkipList
  70. AoiArea *AoiVector2
  71. quadTree *QuadTreeNode
  72. }
  73. var newNodePool = sync.Pool{
  74. New: func() interface{} {
  75. node := &Node{Forward: make([]*Node, SKIPLIST_MAXLEVEL)}
  76. node.ValueList = make(map[uint64]*AoiObject)
  77. //v.(*AoiObject).SetNode(node)
  78. //node.addValue(v.(*AoiObject))
  79. return node
  80. },
  81. }
  82. func NewAoi() *Aoi {
  83. aoi := &Aoi{}
  84. aoi.nodes = make(map[uint64]*AoiObject)
  85. aoi.xNodeList = NewSkipList(LISTTYPE_X)
  86. aoi.yNodeList = NewSkipList(LISTTYPE_Y)
  87. aoi.quadTree = NewQuadTree(8, &QuadBounds{-10000, -10000, 10000, 10000})
  88. aoi.AoiArea = &AoiVector2{10, 10, 0}
  89. return aoi
  90. }
  91. func (this *Aoi) GetNode(uid uint64) *AoiObject {
  92. if data, ok := this.nodes[uid]; ok {
  93. return data
  94. }
  95. return nil
  96. }
  97. func (this *Aoi) GetAllNode() map[uint64]*AoiObject {
  98. return this.nodes
  99. }
  100. func (this *Aoi) PrintStackList() {
  101. this.xNodeList.PrintSkipList()
  102. }
  103. /**
  104. 新加入AOI
  105. */
  106. func (this *Aoi) Enter(uid uint64, callback func(*AoiObject), x, y, z float32, forceUpdate bool, isMaster bool) *AoiObject {
  107. if data, ok := this.nodes[uid]; ok {
  108. return data
  109. }
  110. //todo...可以使用pool
  111. obj := NewAoiObject(uid, x, y, z)
  112. this.xNodeList.Insert(obj)
  113. //this.yNodeList.Insert(obj)
  114. this.nodes[uid] = obj
  115. if obj.node == nil {
  116. util.InfoF("enter error") //insert操作失败
  117. }
  118. this.updateWithArea(obj, callback, *this.AoiArea, x, y, forceUpdate, isMaster)
  119. //this.PrintStackList()
  120. return obj
  121. }
  122. var profileTime time.Duration
  123. var nowTime = util.GetCurrentTimeNow()
  124. var profileCount int32 = 0
  125. //更新节点
  126. func (this *Aoi) Update(id uint64, callback func(*AoiObject), area AoiVector2, x, y float32, isMaster bool) (*AoiObject, bool) {
  127. if data, ok := this.nodes[id]; ok {
  128. profileCount++
  129. //nowTime := time.Now()
  130. obj, ret := this.updateWithArea(data, callback, area, x, y, false, isMaster)
  131. //this.PrintStackList()
  132. //return this.updateWithArea(data, area,x ,y)
  133. //profileTime += time.Now().Sub(nowTime)
  134. if util.GetCurrentTimeNow().Sub(nowTime) > time.Second {
  135. nowTime = util.GetCurrentTimeNow()
  136. /*
  137. oobb := this.nodes[6735728018393727041]
  138. log.Println("aoiUpdate[1000]:", oobb.Id,profileTime,
  139. len(oobb.AoiInfo.MoveSet.List()),
  140. len(oobb.AoiInfo.EnterSet.List()),
  141. len(oobb.AoiInfo.LeaveSet.List()),
  142. len(oobb.AoiInfo.MoveOnlySet.List()))
  143. */
  144. profileCount = 0
  145. profileTime = 0
  146. }
  147. return obj, ret
  148. }
  149. return nil, false
  150. }
  151. //callback 处理必须可见玩家列表(目前只包括情侣)
  152. func (this *Aoi) updateWithArea(obj *AoiObject, callback func(*AoiObject), area AoiVector2, x, y float32, forceUpdate bool, isMaster bool) (*AoiObject, bool) {
  153. //移动到新的位置
  154. this.move(obj, x, y)
  155. //减少更新频率,发3次移动包,做一次视野更新
  156. //obj.updateCount++
  157. //if obj.updateCount%3 != 0 && !forceUpdate {
  158. // return obj, false
  159. //}
  160. //obj.updateCount = 0
  161. //把AOI节点转换到旧的节点里
  162. tempMoveSet := obj.AoiInfo.MoveSet.Copy()
  163. //obj.AoiInfo.MoveOnlySet = obj.AoiInfo.MoveSet.Copy()
  164. //ghost不做处理
  165. if !isMaster {
  166. return obj, true
  167. }
  168. //查找范围坐标
  169. this.find(obj, area)
  170. if callback != nil {
  171. callback(obj)
  172. }
  173. //差集计算(属于MoveSet,不属于MoveOnlySet)
  174. obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, tempMoveSet)
  175. //属于MoveSet,不属于EnterSet
  176. obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
  177. obj.AoiInfo.LeaveSet = set.Difference(tempMoveSet, obj.AoiInfo.MoveOnlySet)
  178. /*
  179. //差集计算(属于MoveSet,不属于MoveOnlySet)
  180. //obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.MoveOnlySet)
  181. //obj.AoiInfo.LeaveSet = set.Difference(obj.AoiInfo.MoveOnlySet, obj.AoiInfo.MoveSet)
  182. //属于MoveSet,不属于EnterSet
  183. obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
  184. */
  185. //把自己加入别的玩家的进入列表中,否则别的玩家移动时如果离开你的视野不会发送离开消息
  186. //可以用主动跟新自己的方式来避免
  187. for _, data := range obj.AoiInfo.EnterSet.List() {
  188. otherNode := this.GetNode(data.(uint64))
  189. if otherNode != nil {
  190. if otherNode.GetMoveSize() >= FIND_NUM_MAX {
  191. //obj.AoiInfo.MoveNoNtfSet.Add(otherNode.Id)
  192. otherNode.AoiInfo.MoveNoNtfSet.Add(obj.Id) //用来标记当前玩家的移动不需要发送给otherNode玩家
  193. }
  194. otherNode.AoiInfo.MoveSet.Add(obj.Id)
  195. }
  196. }
  197. return obj, true
  198. }
  199. //更新节点
  200. func (this *Aoi) UpdateNew(id uint64, callback func(*AoiObject), area AoiVector2, x, y float32, isMaster bool) (*AoiObject, bool) {
  201. if data, ok := this.nodes[id]; ok {
  202. profileCount++
  203. //nowTime := time.Now()
  204. obj, ret := this.updateWithAreaNew(data, callback, area, x, y, false, isMaster)
  205. //this.PrintStackList()
  206. //return this.updateWithArea(data, area,x ,y)
  207. //profileTime += time.Now().Sub(nowTime)
  208. if util.GetCurrentTimeNow().Sub(nowTime) > time.Second {
  209. nowTime = util.GetCurrentTimeNow()
  210. /*
  211. oobb := this.nodes[6735728018393727041]
  212. log.Println("aoiUpdate[1000]:", oobb.Id,profileTime,
  213. len(oobb.AoiInfo.MoveSet.List()),
  214. len(oobb.AoiInfo.EnterSet.List()),
  215. len(oobb.AoiInfo.LeaveSet.List()),
  216. len(oobb.AoiInfo.MoveOnlySet.List()))
  217. */
  218. profileCount = 0
  219. profileTime = 0
  220. }
  221. return obj, ret
  222. }
  223. return nil, false
  224. }
  225. func (this *Aoi) updateWithAreaNew(obj *AoiObject, callback func(*AoiObject), area AoiVector2, x, y float32, forceUpdate bool, isMaster bool) (*AoiObject, bool) {
  226. //移动到新的位置
  227. this.move(obj, x, y)
  228. //减少更新频率,发3次移动包,做一次视野更新
  229. //obj.updateCount++
  230. //if obj.updateCount%3 != 0 && !forceUpdate {
  231. // return obj, false
  232. //}
  233. //obj.updateCount = 0
  234. //把AOI节点转换到旧的节点里
  235. tempMoveSet := obj.AoiInfo.MoveSet.Copy()
  236. //obj.AoiInfo.MoveOnlySet = obj.AoiInfo.MoveSet.Copy()
  237. //ghost不做处理
  238. if !isMaster {
  239. return obj, true
  240. }
  241. //查找范围坐标
  242. this.find(obj, area)
  243. if callback != nil {
  244. callback(obj)
  245. }
  246. //差集计算(属于MoveSet,不属于MoveOnlySet)
  247. obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, tempMoveSet)
  248. //属于MoveSet,不属于EnterSet
  249. obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
  250. obj.AoiInfo.LeaveSet = set.Difference(tempMoveSet, obj.AoiInfo.MoveOnlySet)
  251. /*
  252. //差集计算(属于MoveSet,不属于MoveOnlySet)
  253. //obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.MoveOnlySet)
  254. //obj.AoiInfo.LeaveSet = set.Difference(obj.AoiInfo.MoveOnlySet, obj.AoiInfo.MoveSet)
  255. //属于MoveSet,不属于EnterSet
  256. obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
  257. */
  258. //把自己加入别的玩家的进入列表中,否则别的玩家移动时如果离开你的视野不会发送离开消息
  259. //可以用主动跟新自己的方式来避免
  260. //for _, data := range obj.AoiInfo.EnterSet.List() {
  261. // otherNode := this.GetNode(data.(uint64))
  262. // if otherNode != nil {
  263. // if otherNode.GetMoveSize() >= FIND_NUM_MAX {
  264. // //obj.AoiInfo.MoveNoNtfSet.Add(otherNode.Id)
  265. // otherNode.AoiInfo.MoveNoNtfSet.Add(obj.Id) //用来标记当前玩家的移动不需要发送给otherNode玩家
  266. // }
  267. // otherNode.AoiInfo.MoveSet.Add(obj.Id)
  268. // }
  269. //}
  270. return obj, true
  271. }
  272. func (this *Aoi) move(obj *AoiObject, x, y float32) {
  273. //移动x
  274. this.moveX(obj, x)
  275. //移动y
  276. //this.moveY(obj, y)
  277. obj.SetPosition(x, y)
  278. }
  279. func (this *Aoi) moveX(obj *AoiObject, x float32) {
  280. if math.Abs(float64(obj.Pos.X-x)) <= 0 {
  281. return
  282. }
  283. this.xNodeList.RemoveNode(obj)
  284. obj.Pos.X = x
  285. this.xNodeList.Insert(obj)
  286. }
  287. func (this *Aoi) moveY(obj *AoiObject, y float32) {
  288. if math.Abs(float64(obj.Pos.Y-y)) <= 0 {
  289. return
  290. }
  291. this.yNodeList.RemoveNode(obj)
  292. obj.Pos.Y = y
  293. this.yNodeList.Insert(obj)
  294. }
  295. func (this *Aoi) find(obj *AoiObject, area AoiVector2) *AoiObject {
  296. obj.AoiInfo.MoveSet.Clear()
  297. //查找X轴时会考虑Y轴的数值,所有这边只需要找X轴即可
  298. this.findX(obj, area)
  299. //this.findY(obj, area)
  300. //当前节点列表(节点上所在的玩家列表)
  301. if len(obj.node.ValueList) > 1 {
  302. for id, _ := range obj.node.ValueList {
  303. if id == obj.Id {
  304. continue
  305. }
  306. if !obj.AoiInfo.MoveSet.Has(id) {
  307. obj.AoiInfo.MoveSet.Add(id)
  308. }
  309. }
  310. }
  311. return obj
  312. }
  313. type aoiDistance struct {
  314. objUid uint64
  315. dis float32
  316. }
  317. func (this *Aoi) findX(obj *AoiObject, area AoiVector2) {
  318. bNextOut := false
  319. bPreOut := false
  320. findNum := FIND_NUM_MAX
  321. //查找过程中扫描个数上限
  322. //processLimitNum := findNum
  323. processLimitNumPre := findNum
  324. processLimitNumNext := findNum
  325. var rangeDisList []*aoiDistance
  326. //向后查找
  327. curNext := obj.node.Forward[0]
  328. //向前查找
  329. curPre := obj.node.Pre
  330. for {
  331. if !bNextOut {
  332. if curNext == nil || curNext.Value == nil {
  333. bNextOut = true
  334. continue
  335. }
  336. if this.getDeltaValue(obj.Pos.X, curNext.Value.Pos.X) > area.X {
  337. bNextOut = true
  338. continue
  339. } else {
  340. if len(curNext.ValueList) > 1 {
  341. for id, tmpObj := range curNext.ValueList {
  342. //todo...后续添加做好友处理
  343. tmpDis := this.distance(obj.Pos, tmpObj.Pos)
  344. rangeDisList = append(rangeDisList, &aoiDistance{objUid: id, dis: tmpDis})
  345. processLimitNumNext--
  346. if processLimitNumNext <= 0 {
  347. break
  348. }
  349. //obj.AoiInfo.MoveSet.Add(id)
  350. //findNum--
  351. //if findNum <= 0 {
  352. // break
  353. //}
  354. }
  355. } else {
  356. dis := this.distance(obj.Pos, curNext.Value.Pos)
  357. if dis <= area.X {
  358. rangeDisList = append(rangeDisList, &aoiDistance{objUid: curNext.Value.Id, dis: dis})
  359. processLimitNumNext--
  360. //obj.AoiInfo.MoveSet.Add(curNext.Value.Id)
  361. //findNum--
  362. }
  363. }
  364. }
  365. curNext = curNext.Forward[0]
  366. if processLimitNumNext <= 0 {
  367. break
  368. }
  369. }
  370. if !bPreOut {
  371. //id==0为header节点
  372. if curPre == nil || curPre.Value == nil || curPre.Value.Id <= 0 {
  373. bPreOut = true
  374. continue
  375. }
  376. if this.getDeltaValue(obj.Pos.X, curPre.Value.Pos.X) > area.X {
  377. bPreOut = true
  378. continue
  379. } else {
  380. if len(curPre.ValueList) > 1 {
  381. for id, tmpObj := range curPre.ValueList {
  382. tmpDis := this.distance(obj.Pos, tmpObj.Pos)
  383. rangeDisList = append(rangeDisList, &aoiDistance{objUid: id, dis: tmpDis})
  384. processLimitNumPre--
  385. if processLimitNumPre <= 0 {
  386. break
  387. }
  388. //obj.AoiInfo.MoveSet.Add(id)
  389. //findNum--
  390. //if findNum <= 0 {
  391. // break
  392. //}
  393. }
  394. } else {
  395. dis := this.distance(obj.Pos, curPre.Value.Pos)
  396. if dis <= area.X {
  397. rangeDisList = append(rangeDisList, &aoiDistance{objUid: curPre.Value.Id, dis: dis})
  398. processLimitNumPre--
  399. //obj.AoiInfo.MoveSet.Add(curPre.Value.Id)
  400. //findNum--
  401. }
  402. }
  403. }
  404. curPre = curPre.Pre
  405. if processLimitNumPre <= 0 {
  406. break
  407. }
  408. }
  409. if bNextOut && bPreOut {
  410. break
  411. }
  412. }
  413. if len(rangeDisList) > 0 {
  414. sort.Slice(rangeDisList, func(i, j int) bool {
  415. if math.Abs(float64(rangeDisList[i].dis-rangeDisList[j].dis)) < 0.0001 {
  416. return rangeDisList[i].objUid < rangeDisList[j].objUid
  417. } else {
  418. return rangeDisList[i].dis < rangeDisList[j].dis
  419. }
  420. })
  421. tmpLen := len(rangeDisList)
  422. if tmpLen > findNum {
  423. tmpLen = findNum
  424. }
  425. for idx := 0; idx < tmpLen; idx++ {
  426. obj.AoiInfo.MoveSet.Add(rangeDisList[idx].objUid)
  427. }
  428. }
  429. //test
  430. //this.PrintStackList()
  431. }
  432. func (this *Aoi) findY(obj *AoiObject, area AoiVector2) {
  433. //向后查找
  434. curNext := obj.node.Forward[0]
  435. for {
  436. if curNext == nil || curNext.Value == nil {
  437. break
  438. }
  439. if this.getDeltaValue(obj.Pos.Y, curNext.Value.Pos.Y) > area.Y {
  440. break
  441. } else if this.getDeltaValue(obj.Pos.X, curNext.Value.Pos.X) <= area.X {
  442. if this.distance(obj.Pos, curNext.Value.Pos) <= area.Y {
  443. for id, _ := range curNext.ValueList {
  444. obj.AoiInfo.MoveSet.Add(id)
  445. }
  446. }
  447. }
  448. curNext = curNext.Forward[0]
  449. }
  450. //向前查找
  451. curPre := obj.node.Pre
  452. for {
  453. if curPre == nil || curPre.Value == nil || curPre.Value.Id <= 0 {
  454. break
  455. }
  456. if this.getDeltaValue(obj.Pos.Y, curPre.Value.Pos.Y) > area.Y {
  457. break
  458. } else if this.getDeltaValue(obj.Pos.X, curPre.Value.Pos.X) <= area.X {
  459. if this.distance(obj.Pos, curPre.Value.Pos) <= area.Y {
  460. for id, _ := range curPre.ValueList {
  461. obj.AoiInfo.MoveSet.Add(id)
  462. }
  463. }
  464. }
  465. curPre = curPre.Pre
  466. }
  467. }
  468. func (this *Aoi) LeaveNode(uid uint64) []interface{} {
  469. node := this.GetNode(uid)
  470. if node == nil {
  471. return nil
  472. }
  473. this.xNodeList.RemoveNode(node)
  474. //this.yNodeList.RemoveNode(node)
  475. delete(this.nodes, uid)
  476. for _, data := range node.AoiInfo.MoveSet.List() {
  477. if otherNode := this.GetNode(data.(uint64)); otherNode != nil {
  478. otherNode.AoiInfo.LeaveSet.Add(uid)
  479. }
  480. }
  481. return node.AoiInfo.MoveSet.List()
  482. }
  483. func (this *Aoi) distance(a, b *AoiVector2) float32 {
  484. deltaX := a.X - b.X
  485. deltaY := a.Y - b.Y
  486. //使用近似距离
  487. //return float32(math.Abs(float64(deltaX)) + math.Abs(float64(deltaY)))
  488. return float32(math.Sqrt(float64(deltaX*deltaX + deltaY*deltaY)))
  489. }
  490. func (this *Aoi) getDeltaValue(f1, f2 float32) float32 {
  491. deltaValue := f1 - f2
  492. if deltaValue <= 0 {
  493. return -deltaValue
  494. }
  495. return deltaValue
  496. }