├── .gitignore
├── .idea
├── GoYCServer.iml
├── dataSources.local.xml
├── modules.xml
├── vcs.xml
└── workspace.xml
├── README.md
├── bin
└── config
│ └── node_cfg.json
├── engine
├── BaseModule
│ └── NetModule
│ │ ├── API.go
│ │ └── Net.go
├── YAoi
│ ├── Aoi.go
│ ├── AoiManager.go
│ ├── AoiManager_test.go
│ ├── GoAoi.go
│ ├── GoAoiManager.go
│ ├── GoNineGridAoi.go
│ ├── GoNineGridAoiManager.go
│ ├── GoTowerAoi.go
│ └── GoTowerAoiManager.go
├── YAttr
│ ├── Attribute.go
│ └── AttributeTemplate.go
├── YConfig
│ └── Config.go
├── YConsul
│ └── Consul.md
├── YDecode
│ └── Decode.go
├── YEntity
│ ├── Entity.go
│ ├── Info.go
│ └── entity_test.go
├── YJson
│ └── json.go
├── YLog
│ └── Log.go
├── YModule
│ ├── Info.go
│ └── Module.go
├── YMsg
│ └── in_msg.go
├── YNet
│ ├── Connect.go
│ ├── Listen.go
│ ├── Message.go
│ ├── NetMsgManager.go
│ ├── NetMsgPack.go
│ └── Session.go
├── YNode
│ ├── API.go
│ ├── Info.go
│ └── Node.go
├── YPathFinding
│ ├── AStar.go
│ ├── AStar_test.go
│ └── GoAStarManager.go
├── YTimer
│ ├── Timer.go
│ ├── TimerAPI.go
│ ├── WheelTimer.go
│ └── timer_test.go
└── YTool
│ ├── DebugPrint.go
│ ├── position.go
│ ├── queue.go
│ ├── reactangle.go
│ ├── syncqueue.go
│ ├── timeter.go
│ ├── tool.go
│ ├── tools_test.go
│ └── uidFactory.go
├── examples
├── AoiAstarExample
│ ├── Client
│ │ ├── Client.go
│ │ ├── Game.go
│ │ └── Map.go
│ ├── Msg
│ │ └── msg.go
│ └── Server
│ │ ├── Logic
│ │ ├── Aoi
│ │ │ ├── Aoi.go
│ │ │ ├── AoiManager.go
│ │ │ ├── AoiManager_test.go
│ │ │ ├── GoAoi.go
│ │ │ ├── GoAoiManager.go
│ │ │ ├── GoNineGridAoi.go
│ │ │ └── GoNineGridAoiManager.go
│ │ └── Move
│ │ │ └── MoveControl.go
│ │ ├── Main.go
│ │ └── Module
│ │ ├── Map
│ │ ├── Map.go
│ │ └── README.md
│ │ ├── MapManager
│ │ └── MapManager.go
│ │ ├── README.md
│ │ └── UserManager
│ │ ├── UserInfo.go
│ │ └── UserManager.go
├── NetExample
│ ├── Client
│ │ └── Main.go
│ ├── Msg
│ │ └── Msg.go
│ └── Server
│ │ ├── Logic
│ │ ├── TestModule
│ │ │ └── TestModule.go
│ │ └── TestModule2
│ │ │ └── TestModule.go
│ │ └── Main.go
├── RPCCallListExample
│ ├── Logic
│ │ ├── TestModule
│ │ │ ├── TestModule.go
│ │ │ └── module_test.go
│ │ └── TestModule2
│ │ │ └── TestModule.go
│ └── Main.go
├── RPCExample
│ ├── Logic
│ │ ├── TestModule
│ │ │ ├── TestModule.go
│ │ │ └── module_test.go
│ │ └── TestModule2
│ │ │ └── TestModule.go
│ └── Main.go
└── SeamlessExample
│ ├── Client
│ ├── Client.go
│ ├── Game.go
│ └── Map.go
│ ├── Msg
│ └── msg.go
│ └── Server
│ ├── Logic
│ └── Move
│ │ └── MoveControl.go
│ ├── Main.go
│ ├── Module
│ ├── Map
│ │ ├── API.go
│ │ ├── Info.go
│ │ └── Map.go
│ ├── MapManager
│ │ └── MapManager.go
│ ├── README.md
│ └── UserManager
│ │ ├── UserInfo.go
│ │ └── UserManager.go
│ ├── ModuleRegister.go
│ ├── Util
│ └── Map.go
│ ├── 无缝地图切换方案.md
│ ├── 无缝地图动态创建方案.md
│ └── 无缝地图边缘处理方案.md
├── go.mod
└── go.sum
/.gitignore:
--------------------------------------------------------------------------------
1 | log
--------------------------------------------------------------------------------
/.idea/GoYCServer.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/dataSources.local.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### 项目目的
2 |
3 | - 实现一个基于无缝大地图模式的分布式`MMO`服务器项目
4 | - 实现`MMO`常有的游戏功能,包括技能,怪物,AI,副本,玩家间交互等内容
5 | - 希望以此能找到相关的工作
6 |
7 | ### 项目目标
8 |
9 | - 尽可能利用多核能力来提升效率
10 | - 逻辑尽可能的简单,便于后续维护
11 | - 不追求极致的性能,一切以提升开发效率优先
12 |
13 | #### 演示视频地址
14 |
15 | ```
16 | https://www.bilibili.com/video/BV1F44y1h7us
17 | ```
18 |
19 | #### 无缝地图演示
20 |
21 | ```
22 | https://www.bilibili.com/video/BV1Xq4y1o7S1
23 | ```
24 |
25 | #### todo:
26 |
27 | ```
28 | 1.重构框架底层架构,修改成无缝地图模式 (完成)
29 | 2.增加基对象Entity
30 | 3.增加战斗系统
31 | 4.增加怪物系统
32 | 5.增加道具系统
33 | ```
34 |
35 |
--------------------------------------------------------------------------------
/bin/config/node_cfg.json:
--------------------------------------------------------------------------------
1 | {
2 | "CfgList": [
3 | {
4 | "NodeID": 1,
5 | "Port": 20000,
6 | "PprofPort": 8000,
7 | "Modules":[
8 | "MapManager",
9 | "UserManager"
10 | ]
11 | },
12 | {
13 | "NodeID": 2,
14 | "Port": 20012,
15 | "PprofPort": 8012,
16 | "Modules":[]
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/engine/BaseModule/NetModule/API.go:
--------------------------------------------------------------------------------
1 | package NetModule
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNet"
7 | )
8 |
9 | func (m *NetModule) RPC_Close(s_ uint64) {
10 | _session := m.m_session_pool[s_]
11 | if _session == nil {
12 | return
13 | }
14 | _session.Close()
15 | delete(m.m_session_pool, s_)
16 | }
17 |
18 | func (m *NetModule) RPC_Listen(ip_port_ string) {
19 | err := YNet.ListenTcp4(ip_port_)
20 | if err != nil {
21 | panic(" ListenTcp4 err")
22 | }
23 | ylog.Info("[NetModule] Start Listen [%v]", ip_port_)
24 | }
25 |
26 | func (m *NetModule) RPC_Connect(ip_port_ string) {
27 | go func() {
28 | _new_connect := YNet.NewConnect()
29 | _new_connect.Connect(ip_port_)
30 | _conn_sesstion := _new_connect.GetSession()
31 | _conn_sesstion.StartLoop()
32 |
33 | _msg_pack := YNet.NewNetMsgPack()
34 | _msg_pack.M_msg_name = ip_port_
35 | _conn_msg := YNet.NewMessage(YNet.NET_SESSION_STATE_CONNECT_OTHER_SUCCESS, _conn_sesstion, _msg_pack)
36 | YNet.G_net_msg_chan <- _conn_msg
37 | }()
38 | }
39 |
40 | func (m *NetModule) RPC_SendNetMsgJson(s_ uint64, msg_ *YNet.NetMsgPack) {
41 | _session := m.m_session_pool[s_]
42 | if _session == nil {
43 | return
44 | }
45 | _session.Send(msg_)
46 | }
47 |
48 | func (m *NetModule) RPC_NetMsgRegister(msg_list_ []string, agent_ YMsg.Agent) {
49 | for _, _msg_it := range msg_list_ {
50 | _, exists := m.m_net_msg_pool[_msg_it]
51 | if !exists {
52 | m.m_net_msg_pool[_msg_it] = make([]YMsg.Agent, 0)
53 | }
54 | m.m_net_msg_pool[_msg_it] = append(m.m_net_msg_pool[_msg_it], agent_)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/engine/BaseModule/NetModule/Net.go:
--------------------------------------------------------------------------------
1 | package NetModule
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YModule"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNet"
7 | "github.com/yxinyi/YCServer/engine/YNode"
8 | "time"
9 | )
10 |
11 | type NetModule struct {
12 | YModule.BaseInter
13 | m_session_pool map[uint64]*YNet.Session
14 | m_net_msg_pool map[string][]YMsg.Agent
15 | }
16 |
17 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
18 | _info := &NetModule{
19 | m_session_pool: make(map[uint64]*YNet.Session),
20 | m_net_msg_pool: make(map[string][]YMsg.Agent),
21 | }
22 | _info.Info = YModule.NewInfo(node_)
23 | return _info
24 | }
25 | func (m *NetModule) Init() {
26 | m.Info.Init(m)
27 | }
28 |
29 |
30 |
31 | func (m *NetModule) Loop_100(time time.Time) {
32 | for more := true; more; {
33 | select {
34 | case _msg := <-YNet.G_net_msg_chan:
35 | switch _msg.M_msg_type {
36 | case YNet.NET_SESSION_STATE_CONNECT:
37 | m.m_session_pool[_msg.M_session.GetUID()] = _msg.M_session
38 | case YNet.NET_SESSION_STATE_CONNECT_OTHER_SUCCESS:
39 | _ip_port := _msg.M_net_msg.M_msg_name
40 | m.m_session_pool[_msg.M_session.GetUID()] = _msg.M_session
41 | m.Info.RPCCall(YMsg.ToAgent("YNode"), "RegisterOtherNode", _ip_port, _msg.M_session.GetUID())
42 | case YNet.NET_SESSION_STATE_MSG:
43 | for _, _agent_it := range m.m_net_msg_pool[_msg.M_net_msg.M_msg_name] {
44 | _net_msg := &YMsg.C2S_net_msg{
45 | _agent_it,
46 | _msg.M_session.GetUID(),
47 | _msg.M_net_msg,
48 | }
49 | m.NetToOther(_net_msg)
50 | }
51 | case YNet.NET_SESSION_STATE_CLOSE:
52 | delete(m.m_session_pool, _msg.M_session.GetUID())
53 | }
54 | default:
55 | more = false
56 | }
57 | }
58 | }
59 |
60 | func (m *NetModule) Close() {
61 | YNet.Stop()
62 | }
63 |
--------------------------------------------------------------------------------
/engine/YAoi/Aoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | type AoiCell struct {
4 | m_watch_list map[uint64]map[uint64]struct{}
5 | M_enter_callback AoiEnterCallBack
6 | M_quit_callback AoiQuitCallBack
7 | M_move_callback AoiMoveCallBack
8 | M_add_watch_callback AoiAddWatch
9 | }
10 |
11 | func NewAoiCell() *AoiCell {
12 | _cell := &AoiCell{
13 | m_watch_list: make(map[uint64]map[uint64]struct{}),
14 | }
15 |
16 | return _cell
17 | }
18 |
19 | func (cell *AoiCell) enterCell(enter_ uint64) {
20 | cell.m_watch_list[enter_] = make(map[uint64]struct{})
21 | }
22 | func (cell *AoiCell) notifyEnterCell(enter_ uint64) {
23 | for _it := range cell.m_watch_list {
24 | cell.M_enter_callback(_it, enter_)
25 | cell.M_enter_callback(enter_,_it)
26 | }
27 | }
28 |
29 | func (cell *AoiCell) quitCell(quit uint64) {
30 | delete(cell.m_watch_list, quit)
31 | }
32 | func (cell *AoiCell) notifyQuitCell(quit_ uint64) {
33 | for _it := range cell.m_watch_list {
34 | cell.M_quit_callback(_it, quit_)
35 | cell.M_quit_callback(quit_, _it)
36 | }
37 | }
38 |
39 | func (cell *AoiCell) updateCell(enter_ uint64) {
40 | for _it := range cell.m_watch_list {
41 | cell.M_move_callback(_it, enter_)
42 | cell.M_move_callback(enter_,_it)
43 | }
44 | }
45 |
46 | /*func (cell *AoiCell) watchTower(enter_ uint32) {
47 | cell.m_obj_list[enter_] = make(map[uint32]struct{})
48 | for _it := range cell.m_obj_list {
49 | if cell.M_add_watch_callback(enter_, _it) {
50 | cell.m_obj_list[enter_][_it] = struct{}{}
51 | cell.M_enter_callback(enter_, _it)
52 | }
53 | if cell.M_add_watch_callback(_it, enter_) {
54 | cell.m_obj_list[_it][enter_] = struct{}{}
55 | cell.M_enter_callback(_it, enter_)
56 | }
57 | }
58 | }
59 |
60 | func (cell *AoiCell) quitTower(enter_ uint32) {
61 | _watch_list := cell.m_obj_list[enter_]
62 | for _it := range _watch_list {
63 | if enter_== _it {
64 | delete(cell.m_obj_list[_it], enter_)
65 | continue
66 | }
67 | cell.M_quit_callback(enter_, _it)
68 | _, exists := cell.m_obj_list[_it][enter_]
69 | if exists {
70 | cell.M_quit_callback(_it, enter_)
71 | }
72 | delete(cell.m_obj_list[_it], enter_)
73 | }
74 | delete(cell.m_obj_list, enter_)
75 | }
76 |
77 | func (cell *AoiCell) updateCell(enter_ uint32) {
78 | for _it := range cell.m_obj_list {
79 | if cell.M_add_watch_callback(enter_, _it) {
80 | _, exists := cell.m_obj_list[enter_][_it]
81 | if exists {
82 | cell.M_move_callback(enter_, _it)
83 | } else {
84 | cell.m_obj_list[enter_][_it] = struct{}{}
85 | cell.M_enter_callback(enter_, _it)
86 | }
87 |
88 | } else {
89 | _, exists := cell.m_obj_list[enter_][_it]
90 | if exists {
91 | cell.M_quit_callback(enter_, _it)
92 | delete(cell.m_obj_list[enter_], _it)
93 | }
94 | }
95 |
96 | if cell.M_add_watch_callback(_it, enter_) {
97 | _, exists := cell.m_obj_list[_it][enter_]
98 | if exists {
99 | cell.M_move_callback(_it, enter_)
100 | } else {
101 | cell.m_obj_list[_it][enter_] = struct{}{}
102 | cell.M_enter_callback(_it, enter_)
103 | }
104 | } else {
105 | _, exists := cell.m_obj_list[_it][enter_]
106 | if exists {
107 | cell.M_quit_callback(_it, enter_)
108 | delete(cell.m_obj_list[_it], enter_)
109 | }
110 | }
111 |
112 | }
113 | }*/
114 |
--------------------------------------------------------------------------------
/engine/YAoi/AoiManager.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | )
6 |
7 | type AoiMoveCallBack func(move_, tar_ uint64)
8 | type AoiEnterCallBack func(move_, tar_ uint64)
9 | type AoiQuitCallBack func(move_, tar_ uint64)
10 | type AoiAddWatch func(move_, tar_ uint64) bool
11 |
12 | type AoiManager struct {
13 | M_height float64
14 | M_width float64
15 | m_aoi_list map[uint32]*AoiCell
16 | M_current_index map[uint64]uint32
17 | m_block_height float64
18 | m_block_width float64
19 | m_block_size float64
20 | }
21 |
22 | func NewAoiManager(width_, height_, block_size_ float64) *AoiManager {
23 | _mgr := &AoiManager{
24 | m_aoi_list: make(map[uint32]*AoiCell),
25 | M_current_index: make(map[uint64]uint32),
26 | }
27 | _mgr.M_height = height_
28 | _mgr.M_width = width_
29 | _mgr.m_block_height = height_ / block_size_
30 | _mgr.m_block_width = width_ / block_size_
31 | _mgr.m_block_size = block_size_
32 | return _mgr
33 | }
34 |
35 | func (mgr *AoiManager) Init(add_watch_call_ AoiAddWatch, move_call_ AoiMoveCallBack, enter_call_ AoiEnterCallBack, quit_call_ AoiQuitCallBack) {
36 | for _row_idx := uint32(0); _row_idx < uint32(mgr.m_block_size); _row_idx++ {
37 | for _col_idx := uint32(0); _col_idx < uint32(mgr.m_block_size); _col_idx++ {
38 | _cell := NewAoiCell()
39 | _cell.M_move_callback = move_call_
40 | _cell.M_enter_callback = enter_call_
41 | _cell.M_quit_callback = quit_call_
42 | _cell.M_add_watch_callback = add_watch_call_
43 | mgr.m_aoi_list[mgr.buildIndex(_row_idx, _col_idx)] = _cell
44 | }
45 | }
46 | }
47 |
48 | /*func getDiff(lhs_ map[uint32]struct{}, rhs_ map[uint32]struct{}) map[uint32]struct{} {
49 | _ret := make(map[uint32]struct{})
50 | for _it := range lhs_ {
51 | _ret[_it] = struct{}{}
52 | }
53 | for _it := range rhs_ {
54 | delete(_ret, _it)
55 | }
56 |
57 | return _ret
58 | }*/
59 |
60 | func (mgr *AoiManager) Enter(enter_ uint64, pos_ YTool.PositionXY) {
61 | _current_index := mgr.CalcIndex(pos_)
62 | _cell := mgr.m_aoi_list[_current_index]
63 | _cell.enterCell(enter_)
64 | _round_arr := mgr.getRoundBlock(_current_index)
65 | for _it := range _round_arr {
66 | _cell, exists := mgr.m_aoi_list[_it]
67 | if exists {
68 | _cell.notifyEnterCell(enter_)
69 | }
70 | }
71 | mgr.M_current_index[enter_] = _current_index
72 | }
73 |
74 | func (mgr *AoiManager) Quit(quit_ uint64, pos_ YTool.PositionXY) {
75 | _current_index := mgr.CalcIndex(pos_)
76 | _cell := mgr.m_aoi_list[_current_index]
77 | _cell.quitCell(quit_)
78 | _round_arr := mgr.getRoundBlock(_current_index)
79 | for _it := range _round_arr {
80 | _cell, exists := mgr.m_aoi_list[_it]
81 | if exists {
82 | _cell.notifyQuitCell(quit_)
83 | }
84 | }
85 | delete(mgr.M_current_index, quit_)
86 | }
87 |
88 | func (mgr *AoiManager) Move(move_ uint64, pos_ YTool.PositionXY) {
89 |
90 | _old_round_arr := mgr.getOldRoundBlock(move_)
91 |
92 | _current_index := mgr.CalcIndex(pos_)
93 | _new_round_arr := mgr.getRoundBlock(_current_index)
94 |
95 | if _current_index != mgr.M_current_index[move_] {
96 | _enter_cell := mgr.m_aoi_list[_current_index]
97 | _enter_cell.enterCell(move_)
98 |
99 | }
100 | _enter_cell := YTool.GetSetUint32Diff(_new_round_arr, _old_round_arr)
101 | for _it := range _enter_cell {
102 | _cell, exists := mgr.m_aoi_list[_it]
103 | if exists {
104 | _cell.notifyEnterCell(move_)
105 | }
106 | }
107 |
108 | _update_cell := YTool.GetSetUint32Diff(_new_round_arr, _enter_cell)
109 | for _it := range _update_cell {
110 | _cell, exists := mgr.m_aoi_list[_it]
111 | if exists {
112 | _cell.updateCell(move_)
113 | }
114 | }
115 | if _current_index != mgr.M_current_index[move_] {
116 | _quit_cell := mgr.m_aoi_list[mgr.M_current_index[move_]]
117 | _quit_cell.quitCell(move_)
118 | }
119 | _quit_cell := YTool.GetSetUint32Diff(_old_round_arr, _new_round_arr)
120 | for _it := range _quit_cell {
121 | _cell, exists := mgr.m_aoi_list[_it]
122 | if exists {
123 | _cell.notifyQuitCell(move_)
124 | }
125 | }
126 | mgr.M_current_index[move_] = _current_index
127 |
128 | }
129 |
130 | func (mgr *AoiManager) CalcIndex(xy_ YTool.PositionXY) uint32 {
131 | return mgr.buildIndex(uint32(xy_.M_x/mgr.m_block_width), uint32(xy_.M_y/mgr.m_block_height))
132 | }
133 |
134 | func (mgr *AoiManager) buildIndex(row_, col_ uint32) uint32 {
135 | return row_ + col_*uint32(mgr.m_block_size)
136 | }
137 |
138 | func (mgr *AoiManager) getOldRoundBlock(uid_ uint64) map[uint32]struct{} {
139 | _old_index := mgr.M_current_index[uid_]
140 | return mgr.getRoundBlock(_old_index)
141 | }
142 |
143 | func (mgr *AoiManager) getRoundBlock(cent_index_ uint32) map[uint32]struct{} {
144 | _ret_round := make(map[uint32]struct{})
145 | _cent_idex := int(cent_index_)
146 | _block_size := int(mgr.m_block_size)
147 |
148 | _max_idx := int(mgr.m_block_size * mgr.m_block_size)
149 |
150 | _cent_row := int(cent_index_ / uint32(mgr.m_block_size))
151 | _ret_round[cent_index_] = struct{}{}
152 | {
153 | _left_up := _cent_idex - _block_size - 1
154 | if _left_up >= 0 && (_left_up/_block_size+1) == _cent_row {
155 | _ret_round[uint32(_left_up)] = struct{}{}
156 | }
157 | }
158 |
159 | {
160 | _up := _cent_idex - _block_size
161 | if _up >= 0 && (_up/_block_size+1) == _cent_row {
162 | _ret_round[uint32(_up)] = struct{}{}
163 | }
164 | }
165 | {
166 | _up_right := _cent_idex - _block_size + 1
167 | if _up_right >= 0 && (_up_right/_block_size+1) == _cent_row {
168 | _ret_round[uint32(_up_right)] = struct{}{}
169 | }
170 | }
171 |
172 | {
173 | _left := _cent_idex - 1
174 | if _left >= 0 && (_left/_block_size) == _cent_row {
175 | _ret_round[uint32(_left)] = struct{}{}
176 | }
177 | }
178 | {
179 | _right := _cent_idex + 1
180 | if _right >= 0 && (_right/_block_size) == _cent_row {
181 | _ret_round[uint32(_right)] = struct{}{}
182 | }
183 | }
184 |
185 | {
186 | _down_left := _cent_idex + _block_size - 1
187 | if _down_left < _max_idx && (_down_left/_block_size-1) == _cent_row {
188 | _ret_round[uint32(_down_left)] = struct{}{}
189 | }
190 | }
191 |
192 | {
193 | _down := _cent_idex + _block_size
194 | if _down < _max_idx && (_down/_block_size-1) == _cent_row {
195 | _ret_round[uint32(_down)] = struct{}{}
196 | }
197 | }
198 | {
199 | _down_right := _cent_idex + _block_size + 1
200 | if _down_right < _max_idx && (_down_right/_block_size-1) == _cent_row {
201 | _ret_round[uint32(_down_right)] = struct{}{}
202 | }
203 | }
204 |
205 | return _ret_round
206 | }
207 |
--------------------------------------------------------------------------------
/engine/YAoi/AoiManager_test.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | "testing"
6 | )
7 |
8 | func roundTestHelp(cent_index_, block_ uint32, round_target_ []uint32) map[uint32]struct{} {
9 | _mgr := NewAoiManager(1280, 720, float64(block_))
10 | _sure_arr := make(map[uint32]struct{})
11 | for _, _it := range round_target_ {
12 | _sure_arr[_it] = struct{}{}
13 | }
14 | _round_arr := _mgr.getRoundBlock(cent_index_)
15 | for _it := range _round_arr {
16 | _, exists := _sure_arr[_it]
17 | if !exists {
18 | _sure_arr[_it] = struct{}{}
19 | }
20 | delete(_sure_arr, _it)
21 | }
22 | return _sure_arr
23 | }
24 |
25 | func TestAoiGetRoundIndex(t *testing.T) {
26 |
27 | _err_list := roundTestHelp(16, 5, []uint32{10, 11, 12, 15, 17, 20, 21, 22})
28 | if len(_err_list) > 0 {
29 | t.Fatalf("[%v]", _err_list)
30 | }
31 |
32 | _err_list = roundTestHelp(0, 5, []uint32{1, 5, 6})
33 | if len(_err_list) > 0 {
34 | t.Fatalf("[%v]", _err_list)
35 | }
36 |
37 | _err_list = roundTestHelp(4, 5, []uint32{3, 8, 9})
38 | if len(_err_list) > 0 {
39 | t.Fatalf("[%v]", _err_list)
40 | }
41 |
42 | _err_list = roundTestHelp(2, 5, []uint32{1, 6, 7, 8, 3})
43 | if len(_err_list) > 0 {
44 | t.Fatalf("[%v]", _err_list)
45 | }
46 |
47 | _err_list = roundTestHelp(20, 5, []uint32{15, 16, 21})
48 | if len(_err_list) > 0 {
49 | t.Fatalf("[%v]", _err_list)
50 | }
51 | _err_list = roundTestHelp(22, 5, []uint32{16, 17, 18, 21, 23})
52 | if len(_err_list) > 0 {
53 | t.Fatalf("[%v]", _err_list)
54 | }
55 | _err_list = roundTestHelp(24, 5, []uint32{18, 19, 23})
56 | if len(_err_list) > 0 {
57 | t.Fatalf("[%v]", _err_list)
58 | }
59 | }
60 |
61 | func TestAoiGetRoundIndex10(t *testing.T) {
62 |
63 | _err_list := roundTestHelp(0, 10, []uint32{1, 10, 11})
64 | if len(_err_list) > 0 {
65 | t.Fatalf("[%v]", _err_list)
66 | }
67 |
68 | _err_list = roundTestHelp(11, 10, []uint32{0, 1, 2, 10, 11, 12, 20, 21, 22})
69 | if len(_err_list) > 0 {
70 | t.Fatalf("[%v]", _err_list)
71 | }
72 | }
73 |
74 | func CalcIndexHelp(x_, y_ float64, tar_idx_ uint32) bool {
75 | _mgr := NewAoiManager(1280, 720, float64(10))
76 | _cal_idx := _mgr.CalcIndex(YTool.PositionXY{x_, y_})
77 | return _cal_idx == tar_idx_
78 | }
79 | func TestCalcIndex(t *testing.T) {
80 | if !CalcIndexHelp(0,0,0){
81 | t.Fatal()
82 | }
83 | if !CalcIndexHelp(128,0,1){
84 | t.Fatal()
85 | }
86 | if !CalcIndexHelp(128,73,11){
87 | t.Fatal()
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/engine/YAoi/GoAoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | )
6 |
7 | type GoAoiCellAction struct {
8 | m_action uint32
9 | m_action_obj GoAoiObj
10 | }
11 |
12 | const (
13 | GO_AOI_CELL_ACTION_ENTER = iota
14 | GO_AOI_CELL_ACTION_NOTIFY_ENTER
15 | GO_AOI_CELL_ACTION_UPDATE
16 | GO_AOI_CELL_ACTION_NOTIFY_QUIT
17 | GO_AOI_CELL_ACTION_QUIT
18 | )
19 |
20 | type GoAoiCell struct {
21 | m_obj_list map[uint64]GoAoiObj
22 | m_mgr_chan *YTool.SyncQueue
23 | M_obj_action chan GoAoiCellAction
24 | m_close chan struct{}
25 | }
26 |
27 | func NewGoAoiCell(mgr_chan_ *YTool.SyncQueue) *GoAoiCell {
28 | _cell := &GoAoiCell{
29 | m_obj_list: make(map[uint64]GoAoiObj),
30 | m_mgr_chan: mgr_chan_,
31 | M_obj_action: make(chan GoAoiCellAction, 1000),
32 | m_close: make(chan struct{}),
33 | }
34 | go func() {
35 | for {
36 | select {
37 | case <-_cell.M_obj_action:
38 | for _action := range _cell.M_obj_action {
39 | if len(_cell.M_obj_action) == 0 {
40 | break
41 | }
42 | switch _action.m_action {
43 | case GO_AOI_CELL_ACTION_ENTER:
44 | _cell.enterCell(_action.m_action_obj)
45 | case GO_AOI_CELL_ACTION_NOTIFY_ENTER:
46 | _cell.notifyEnterCell(_action.m_action_obj)
47 | case GO_AOI_CELL_ACTION_UPDATE:
48 | _cell.updateCell(_action.m_action_obj)
49 | case GO_AOI_CELL_ACTION_NOTIFY_QUIT:
50 | _cell.notifyQuitCell(_action.m_action_obj)
51 | case GO_AOI_CELL_ACTION_QUIT:
52 | _cell.quitCell(_action.m_action_obj)
53 | }
54 | }
55 |
56 | case <-_cell.m_close:
57 | return
58 | }
59 | }
60 | }()
61 | return _cell
62 | }
63 |
64 | func (cell *GoAoiCell) EnterCell(enter_ GoAoiObj) {
65 | cell.M_obj_action <- GoAoiCellAction{
66 | GO_AOI_CELL_ACTION_ENTER,
67 | enter_,
68 | }
69 | }
70 | func (cell *GoAoiCell) NotifyEnterCell(enter_ GoAoiObj) {
71 | cell.M_obj_action <- GoAoiCellAction{
72 | GO_AOI_CELL_ACTION_NOTIFY_ENTER,
73 | enter_,
74 | }
75 | }
76 | func (cell *GoAoiCell) QuitCell(quit_ GoAoiObj) {
77 | cell.M_obj_action <- GoAoiCellAction{
78 | GO_AOI_CELL_ACTION_QUIT,
79 | quit_,
80 | }
81 | }
82 | func (cell *GoAoiCell) NotifyQuitCell(enter_ GoAoiObj) {
83 | cell.M_obj_action <- GoAoiCellAction{
84 | GO_AOI_CELL_ACTION_NOTIFY_QUIT,
85 | enter_,
86 | }
87 | }
88 | func (cell *GoAoiCell) UpdateCell(enter_ GoAoiObj) {
89 | cell.M_obj_action <- GoAoiCellAction{
90 | GO_AOI_CELL_ACTION_UPDATE,
91 | enter_,
92 | }
93 | }
94 |
95 | func (cell *GoAoiCell) enterCell(enter_ GoAoiObj) {
96 | cell.m_obj_list[enter_.M_uid] = enter_
97 | /* _, exists := cell.m_obj_list[enter_.M_module_uid]
98 | if !exists {
99 | cell.m_obj_list[enter_.M_module_uid] = make(map[uint64]struct{})
100 | }*/
101 | }
102 |
103 | func (cell *GoAoiCell) notifyEnterCell(enter_ GoAoiObj) {
104 | _func := func(notify_, action_ GoAoiObj) {
105 | if notify_.PositionXY.Distance(&action_.PositionXY) < notify_.M_view_range {
106 | //cell.m_obj_list[notify_.M_module_uid][action_.M_module_uid] = struct{}{}
107 | cell.m_mgr_chan.Add(GoAoiAction{
108 | GO_AOI_ACTION_ENTER,
109 | notify_.M_uid,
110 | action_.M_uid,
111 | })
112 | }
113 | }
114 | for _, _it := range cell.m_obj_list {
115 | _func(_it, enter_)
116 | _func(enter_, _it)
117 | }
118 | }
119 |
120 | func (cell *GoAoiCell) quitCell(quit_ GoAoiObj) {
121 |
122 | delete(cell.m_obj_list, quit_.M_uid)
123 | }
124 |
125 | func (cell *GoAoiCell) notifyQuitCell(quit_ GoAoiObj) {
126 | for _, _it := range cell.m_obj_list {
127 | cell.m_mgr_chan.Add(GoAoiAction{
128 | GO_AOI_ACTION_QUIT,
129 | quit_.M_uid,
130 | _it.M_uid,
131 | })
132 | cell.m_mgr_chan.Add(GoAoiAction{
133 | GO_AOI_ACTION_QUIT,
134 | _it.M_uid,
135 | quit_.M_uid,
136 | })
137 | }
138 | }
139 |
140 | func (cell *GoAoiCell) updateCell(enter_ GoAoiObj) {
141 | _func := func(notify_, action_ GoAoiObj) {
142 | _, exists := cell.m_obj_list[enter_.M_uid]
143 | if exists {
144 | cell.m_obj_list[enter_.M_uid] = enter_
145 | }
146 | if action_.PositionXY.Distance(¬ify_.PositionXY) < action_.M_view_range {
147 |
148 | cell.m_mgr_chan.Add(GoAoiAction{
149 | GO_AOI_ACTION_UPDATE,
150 | action_.M_uid,
151 | notify_.M_uid,
152 | })
153 |
154 | } else {
155 |
156 | cell.m_mgr_chan.Add(GoAoiAction{
157 | GO_AOI_ACTION_QUIT,
158 | action_.M_uid,
159 | notify_.M_uid,
160 | })
161 |
162 | }
163 | }
164 | for _, _it := range cell.m_obj_list {
165 | _func(enter_, _it)
166 | _func(_it, enter_)
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/engine/YAoi/GoAoiManager.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
6 | )
7 |
8 | type GoAoiMoveCallBack func(notify_, action_ uint64)
9 | type GoAoiEnterCallBack func(notify_, action_ uint64)
10 | type GoAoiQuitCallBack func(notify_, action_ uint64)
11 |
12 | const (
13 | GO_AOI_ACTION_ENTER = iota
14 | GO_AOI_ACTION_UPDATE
15 | GO_AOI_ACTION_QUIT
16 | )
17 |
18 | type GoAoiObj struct {
19 | M_uid uint64
20 | M_current_index uint64
21 | YTool.PositionXY
22 | M_view_range float64
23 | M_dirty bool
24 | }
25 |
26 | type GoAoiAction struct {
27 | m_action uint32
28 | m_notify_obj uint64
29 | m_action_obj uint64
30 | }
31 |
32 | type GoAoiManager struct {
33 | M_height float64
34 | M_width float64
35 | m_aoi_list map[uint32]*GoAoiCell
36 | M_current_index map[uint64]uint32
37 | m_block_height float64
38 | m_block_width float64
39 | m_block_size float64
40 |
41 | m_enter_callback GoAoiEnterCallBack
42 | m_update_callback GoAoiMoveCallBack
43 | m_quit_callback GoAoiQuitCallBack
44 | //m_action_list chan GoAoiAction
45 | m_action_list *YTool.SyncQueue
46 | }
47 |
48 | func NewGoAoiManager(width_, height_, block_size_ float64) *GoAoiManager {
49 | _mgr := &GoAoiManager{
50 | m_aoi_list: make(map[uint32]*GoAoiCell),
51 | M_current_index: make(map[uint64]uint32),
52 | m_action_list: YTool.NewSyncQueue(),
53 | }
54 | _mgr.M_height = height_
55 | _mgr.M_width = width_
56 | _mgr.m_block_height = height_ / block_size_
57 | _mgr.m_block_width = width_ / block_size_
58 | _mgr.m_block_size = block_size_
59 | return _mgr
60 | }
61 |
62 | func (mgr *GoAoiManager) Init(move_call_ GoAoiMoveCallBack, enter_call_ GoAoiEnterCallBack, quit_call_ GoAoiQuitCallBack) {
63 |
64 | mgr.m_enter_callback = enter_call_
65 | mgr.m_update_callback = move_call_
66 | mgr.m_quit_callback = quit_call_
67 |
68 | for _row_idx := uint32(0); _row_idx < uint32(mgr.m_block_size); _row_idx++ {
69 | for _col_idx := uint32(0); _col_idx < uint32(mgr.m_block_size); _col_idx++ {
70 | _cell := NewGoAoiCell(mgr.m_action_list)
71 | mgr.m_aoi_list[mgr.buildIndex(_row_idx, _col_idx)] = _cell
72 | }
73 | }
74 | }
75 |
76 | func (mgr *GoAoiManager) Update() {
77 | for {
78 | if mgr.m_action_list.Len() == 0 {
79 | break
80 | }
81 | _act := mgr.m_action_list.Pop().(GoAoiAction)
82 | switch _act.m_action {
83 | case GO_AOI_ACTION_ENTER:
84 | mgr.m_enter_callback(_act.m_notify_obj, _act.m_action_obj)
85 | case GO_AOI_ACTION_UPDATE:
86 | mgr.m_update_callback(_act.m_notify_obj, _act.m_action_obj)
87 | case GO_AOI_ACTION_QUIT:
88 | mgr.m_quit_callback(_act.m_notify_obj, _act.m_action_obj)
89 | }
90 | }
91 |
92 | }
93 |
94 | func (mgr *GoAoiManager) Enter(enter_ GoAoiObj, pos_ Msg.PositionXY) {
95 | _current_index := mgr.CalcIndex(pos_)
96 | _cell := mgr.m_aoi_list[_current_index]
97 | _cell.EnterCell(enter_)
98 | _round_arr := mgr.getRoundBlock(_current_index)
99 | for _it := range _round_arr {
100 | _cell, exists := mgr.m_aoi_list[_it]
101 | if exists {
102 | _cell.NotifyEnterCell(enter_)
103 | }
104 | }
105 | mgr.M_current_index[enter_.M_uid] = _current_index
106 | }
107 |
108 | func (mgr *GoAoiManager) Quit(quit_ GoAoiObj, pos_ Msg.PositionXY) {
109 | _current_index := mgr.CalcIndex(pos_)
110 | _cell := mgr.m_aoi_list[_current_index]
111 | _cell.QuitCell(quit_)
112 | _round_arr := mgr.getRoundBlock(_current_index)
113 | for _it := range _round_arr {
114 | _cell, exists := mgr.m_aoi_list[_it]
115 | if exists {
116 | _cell.NotifyQuitCell(quit_)
117 | }
118 | }
119 | delete(mgr.M_current_index, quit_.M_uid)
120 | }
121 |
122 | func (mgr *GoAoiManager) Move(move_ GoAoiObj, pos_ Msg.PositionXY) {
123 |
124 | _old_round_arr := mgr.getOldRoundBlock(move_.M_uid)
125 |
126 | _current_index := mgr.CalcIndex(pos_)
127 | _new_round_arr := mgr.getRoundBlock(_current_index)
128 |
129 | if _current_index != mgr.M_current_index[move_.M_uid] {
130 | _enter_cell := mgr.m_aoi_list[_current_index]
131 | _enter_cell.EnterCell(move_)
132 |
133 | }
134 | _enter_cell := YTool.GetSetUint32Diff(_new_round_arr, _old_round_arr)
135 | for _it := range _enter_cell {
136 | _cell, exists := mgr.m_aoi_list[_it]
137 | if exists {
138 | _cell.NotifyEnterCell(move_)
139 | }
140 | }
141 |
142 | _update_cell := YTool.GetSetUint32Diff(_new_round_arr, _enter_cell)
143 | for _it := range _update_cell {
144 | _cell, exists := mgr.m_aoi_list[_it]
145 | if exists {
146 | _cell.UpdateCell(move_)
147 | }
148 | }
149 | if _current_index != mgr.M_current_index[move_.M_uid] {
150 | _quit_cell := mgr.m_aoi_list[mgr.M_current_index[move_.M_uid]]
151 | _quit_cell.QuitCell(move_)
152 | }
153 | _quit_cell := YTool.GetSetUint32Diff(_old_round_arr, _new_round_arr)
154 | for _it := range _quit_cell {
155 | _cell, exists := mgr.m_aoi_list[_it]
156 | if exists {
157 | _cell.NotifyQuitCell(move_)
158 | }
159 | }
160 | mgr.M_current_index[move_.M_uid] = _current_index
161 |
162 | }
163 |
164 | func (mgr *GoAoiManager) CalcIndex(xy_ Msg.PositionXY) uint32 {
165 | return mgr.buildIndex(uint32(xy_.M_x/mgr.m_block_width), uint32(xy_.M_y/mgr.m_block_height))
166 | }
167 |
168 | func (mgr *GoAoiManager) buildIndex(row_, col_ uint32) uint32 {
169 | return row_ + col_*uint32(mgr.m_block_size)
170 | }
171 |
172 | func (mgr *GoAoiManager) getOldRoundBlock(uid_ uint64) map[uint32]struct{} {
173 | _old_index := mgr.M_current_index[uid_]
174 | return mgr.getRoundBlock(_old_index)
175 | }
176 |
177 | func (mgr *GoAoiManager) getRoundBlock(cent_index_ uint32) map[uint32]struct{} {
178 | _ret_round := make(map[uint32]struct{})
179 | _cent_idex := int(cent_index_)
180 | _block_size := int(mgr.m_block_size)
181 |
182 | _max_idx := int(mgr.m_block_size * mgr.m_block_size)
183 |
184 | _cent_row := int(cent_index_ / uint32(mgr.m_block_size))
185 | _ret_round[cent_index_] = struct{}{}
186 | {
187 | _left_up := _cent_idex - _block_size - 1
188 | if _left_up >= 0 && (_left_up/_block_size+1) == _cent_row {
189 | _ret_round[uint32(_left_up)] = struct{}{}
190 | }
191 | }
192 |
193 | {
194 | _up := _cent_idex - _block_size
195 | if _up >= 0 && (_up/_block_size+1) == _cent_row {
196 | _ret_round[uint32(_up)] = struct{}{}
197 | }
198 | }
199 | {
200 | _up_right := _cent_idex - _block_size + 1
201 | if _up_right >= 0 && (_up_right/_block_size+1) == _cent_row {
202 | _ret_round[uint32(_up_right)] = struct{}{}
203 | }
204 | }
205 |
206 | {
207 | _left := _cent_idex - 1
208 | if _left >= 0 && (_left/_block_size) == _cent_row {
209 | _ret_round[uint32(_left)] = struct{}{}
210 | }
211 | }
212 | {
213 | _right := _cent_idex + 1
214 | if _right >= 0 && (_right/_block_size) == _cent_row {
215 | _ret_round[uint32(_right)] = struct{}{}
216 | }
217 | }
218 |
219 | {
220 | _down_left := _cent_idex + _block_size - 1
221 | if _down_left < _max_idx && (_down_left/_block_size-1) == _cent_row {
222 | _ret_round[uint32(_down_left)] = struct{}{}
223 | }
224 | }
225 |
226 | {
227 | _down := _cent_idex + _block_size
228 | if _down < _max_idx && (_down/_block_size-1) == _cent_row {
229 | _ret_round[uint32(_down)] = struct{}{}
230 | }
231 | }
232 | {
233 | _down_right := _cent_idex + _block_size + 1
234 | if _down_right < _max_idx && (_down_right/_block_size-1) == _cent_row {
235 | _ret_round[uint32(_down_right)] = struct{}{}
236 | }
237 | }
238 |
239 | return _ret_round
240 | }
241 |
--------------------------------------------------------------------------------
/engine/YAoi/GoNineGridAoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | type GoNineGirdAoiCell struct {
4 | m_watch_list map[uint64]struct{}
5 | }
6 |
7 | func NewGoNineGirdAoiCell() *GoNineGirdAoiCell {
8 | _cell := &GoNineGirdAoiCell{
9 | m_watch_list: make(map[uint64]struct{}),
10 | }
11 | return _cell
12 | }
13 | func (cell *GoNineGirdAoiCell)GetWatch()map[uint64]struct{}{
14 | return cell.m_watch_list
15 | }
16 | func (cell *GoNineGirdAoiCell)Watch(uid_ uint64){
17 | cell.m_watch_list[uid_] = struct{}{}
18 | }
19 |
20 | func (cell *GoNineGirdAoiCell)Forget(uid_ uint64){
21 | delete(cell.m_watch_list, uid_)
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/engine/YAoi/GoTowerAoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import "github.com/yxinyi/YCServer/engine/YTool"
4 |
5 | type GoTowerAoiObj struct {
6 | M_uid uint64
7 | M_current_index uint64
8 | *YTool.PositionXY
9 | M_view_range float64
10 | M_dirty bool
11 | M_watch_list map[uint64]struct{} //当前关注哪些对象
12 | M_watch_tower_list map[uint64]struct{} //当前关注哪些塔
13 | }
14 |
15 | func (obj *GoTowerAoiObj) InViewRange(rhs_ *GoTowerAoiObj) bool {
16 | return obj.PositionXY.Distance(rhs_.PositionXY) < obj.M_view_range
17 | }
18 | func NewGoTowerAoiObj() *GoTowerAoiObj {
19 | _obj := &GoTowerAoiObj{
20 | M_watch_list: make(map[uint64]struct{}),
21 | M_watch_tower_list: make(map[uint64]struct{}),
22 | }
23 | return _obj
24 | }
25 |
26 | type AoiTower struct {
27 | m_index uint64
28 | m_obj_list map[uint64]struct{} //当前灯塔范围内有多少人
29 | m_watch_this_obj map[uint64]struct{} //当前有多少人监控该灯塔,也就是需要将该灯塔的视野内信息进行同步
30 | m_position *YTool.PositionXY
31 | m_view_range float64 //当玩家进入这个范围后就算成当前灯塔内的玩家
32 | }
33 |
34 | func NewGoTowerAoiCell() *AoiTower {
35 | _cell := &AoiTower{
36 | m_obj_list: make(map[uint64]struct{}),
37 | m_watch_this_obj: make(map[uint64]struct{}),
38 | }
39 | return _cell
40 | }
41 | func (tower *AoiTower) GetWatch() map[uint64]struct{} {
42 | return tower.m_watch_this_obj
43 | }
44 | func (tower *AoiTower) AddWatch(uid_ uint64) {
45 | tower.m_watch_this_obj[uid_] = struct{}{}
46 | }
47 |
48 | func (tower *AoiTower) RemoveWatch(uid_ uint64) {
49 | delete(tower.m_watch_this_obj, uid_)
50 | }
51 |
52 | func (tower *AoiTower) GetObjs() map[uint64]struct{} {
53 | return tower.m_obj_list
54 | }
55 |
56 | func (tower *AoiTower) Add(uid_ uint64) bool {
57 | _, exists := tower.m_obj_list[uid_]
58 | if exists {
59 | return false
60 | }
61 | tower.m_obj_list[uid_] = struct{}{}
62 | return true
63 | }
64 |
65 | func (tower *AoiTower) Remove(uid_ uint64) bool {
66 | _, exists := tower.m_obj_list[uid_]
67 | if !exists {
68 | return false
69 | }
70 | delete(tower.m_obj_list, uid_)
71 | return true
72 | }
73 |
--------------------------------------------------------------------------------
/engine/YAttr/Attribute.go:
--------------------------------------------------------------------------------
1 | package YAttr
2 |
3 | import (
4 | "fmt"
5 | "reflect"
6 | )
7 |
8 | type AttributeValue struct {
9 | M_entity_name string
10 | M_attr_name string
11 | M_value_stream []byte
12 | M_value reflect.Value
13 | M_value_steam_convert bool
14 | }
15 |
16 |
17 | func (av *AttributeValue) GetTemplate() *Template {
18 | return nil
19 | }
20 |
21 | func (av *AttributeValue) GetDebugString() string {
22 | _ret_str := ""
23 | _ret_str += fmt.Sprintf("[name:%v][value:%v]", av.M_attr_name,av.M_value.String())
24 | return _ret_str
25 | }
26 |
27 | type AttributeValuePanel struct {
28 | M_name string
29 | M_attr_list map[string]*AttributeValue
30 | }
31 |
32 | func NewAttributeValuePanel()*AttributeValuePanel{
33 | _panel := &AttributeValuePanel{}
34 | _panel.M_attr_list = make(map[string]*AttributeValue)
35 | return _panel
36 | }
37 |
38 | func (p *AttributeValuePanel) GetAttr(route_ string) interface{} {
39 | _attr, _exists := p.M_attr_list[route_]
40 | if !_exists {
41 | return nil
42 | }
43 | if _attr.M_value.CanAddr(){
44 | return _attr.M_value.Addr().Interface()
45 | }
46 | return _attr.M_value.Interface()
47 | }
48 |
--------------------------------------------------------------------------------
/engine/YAttr/AttributeTemplate.go:
--------------------------------------------------------------------------------
1 | package YAttr
2 |
3 | import (
4 | jsoniter "github.com/json-iterator/go"
5 | "reflect"
6 | )
7 |
8 | type Template struct {
9 | M_entity_name string
10 | M_attr_name string
11 | M_attr_type_ref reflect.Type
12 | M_defalut_value reflect.Value //
13 | M_save bool
14 | M_sync_to_ghost bool
15 | M_sync_to_self_client bool
16 | M_sync_to_other_client bool
17 | }
18 |
19 | func Tmpl(name_ string, attr_type_ interface{}, to_save_, to_ghost, to_self_cli, to_other_cli bool) *Template {
20 | _tmpl := &Template{}
21 | _attr_ref_val := reflect.ValueOf(attr_type_)
22 | _tmpl.M_entity_name = name_
23 | _tmpl.M_attr_type_ref = _attr_ref_val.Type()
24 | _tmpl.M_defalut_value = _attr_ref_val
25 | _tmpl.M_save = to_save_
26 | _tmpl.M_sync_to_ghost = to_ghost
27 | _tmpl.M_sync_to_self_client = to_self_cli
28 | _tmpl.M_sync_to_other_client = to_other_cli
29 | return _tmpl
30 | }
31 | func (tmpl *Template) New() *AttributeValue {
32 | _attr_val := &AttributeValue{}
33 | _attr_val.M_entity_name = tmpl.M_entity_name
34 | _attr_val.M_attr_name = tmpl.M_attr_name
35 |
36 | _tmp_new_val := reflect.New(tmpl.M_defalut_value.Type()).Elem()
37 |
38 | _tmp_new_val.Set(tmpl.M_defalut_value)
39 | _attr_val.M_value = _tmp_new_val
40 |
41 | _bytes, _err := jsoniter.Marshal(_attr_val.M_value.Interface())
42 | _attr_val.M_value_stream = _bytes
43 | if _err != nil {
44 | panic(_err.Error())
45 | }
46 | return _attr_val
47 | }
48 |
49 | type TemplatePanel struct {
50 | M_entity_name string
51 | M_attr_tmpl_list map[string]*Template
52 | }
53 |
54 | func NewTemplatePanel() *TemplatePanel {
55 | _panel := &TemplatePanel{}
56 | _panel.M_attr_tmpl_list = make(map[string]*Template)
57 | return _panel
58 | }
59 |
60 | func Define(name_ string, attr_list_ ...*Template) *TemplatePanel {
61 | _panel := NewTemplatePanel()
62 | for _, _it := range attr_list_ {
63 | _key := name_ + "." + _it.M_entity_name
64 | _it.M_attr_name = _key
65 | _panel.M_attr_tmpl_list[_key] = _it
66 | }
67 |
68 | return _panel
69 | }
70 |
71 | func (panel *TemplatePanel) New() *AttributeValuePanel {
72 | _value_panel := NewAttributeValuePanel()
73 | _value_panel.M_name = panel.M_entity_name
74 | for _, _tmpl_it := range panel.M_attr_tmpl_list {
75 | _value_panel.M_attr_list[_tmpl_it.M_attr_name] = _tmpl_it.New()
76 | }
77 | return _value_panel
78 | }
79 |
80 | type AttrTmplPanelManager struct {
81 | m_tmpl_panel_list map[string]*TemplatePanel
82 | }
83 |
84 | func NewAttrTmplPanelManager() *AttrTmplPanelManager {
85 | _mgr := &AttrTmplPanelManager{
86 | m_tmpl_panel_list: make(map[string]*TemplatePanel),
87 | }
88 | return _mgr
89 | }
90 |
91 | func (mgr *AttrTmplPanelManager) RegisterEntityAttr(entity_name_ string, panel *TemplatePanel) {
92 | _, _exists := mgr.m_tmpl_panel_list[entity_name_]
93 | if !_exists {
94 | mgr.m_tmpl_panel_list[entity_name_] = &TemplatePanel{
95 | entity_name_,
96 | make(map[string]*Template),
97 | }
98 | }
99 | for _, _attr_it := range panel.M_attr_tmpl_list {
100 | _attr_it.M_entity_name = entity_name_
101 | mgr.m_tmpl_panel_list[entity_name_].M_attr_tmpl_list[_attr_it.M_attr_name] = _attr_it
102 | }
103 |
104 | }
105 |
106 | func (mgr *AttrTmplPanelManager) New(type_str_ string) *AttributeValuePanel {
107 | _prototype, _exists := mgr.m_tmpl_panel_list[type_str_]
108 | if !_exists {
109 | return nil
110 | }
111 | return _prototype.New()
112 | }
113 |
--------------------------------------------------------------------------------
/engine/YConfig/Config.go:
--------------------------------------------------------------------------------
1 | package YConfig
2 |
3 | import "github.com/spf13/viper"
4 |
5 | const DEFAULT_PATH = "./config"
6 |
7 |
8 | func Load(name_ string, core_ interface{}) error {
9 | _viper := viper.New()
10 | _viper.SetConfigName(name_) // name of config file (without extension)
11 | _viper.SetConfigType("json") // REQUIRED if the config file does not have the extension in the name
12 | _viper.AddConfigPath(DEFAULT_PATH) // path to look for the config file in
13 | _viper.ReadInConfig()
14 | return _viper.Unmarshal(core_)
15 | }
16 |
--------------------------------------------------------------------------------
/engine/YConsul/Consul.md:
--------------------------------------------------------------------------------
1 | ## 启动
2 |
3 | ```
4 | consul agent -dev
5 | ```
6 |
7 | ## 查看当前运行中的consul
8 |
9 | ```
10 | consul members
11 | ```
12 |
13 | ## 关闭
14 |
15 | ```
16 | consul leave
17 | ```
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/engine/YDecode/Decode.go:
--------------------------------------------------------------------------------
1 | package YDecode
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | )
6 |
7 | const (
8 | DECODE_TYPE_JSON uint32 = 0
9 | )
10 |
11 | type Inter interface {
12 | Marshal(interface{}) ([]byte, error)
13 | Unmarshal([]byte, interface{}) error
14 | }
15 |
16 | var g_decode_pool = make(map[uint32]Inter)
17 |
18 | func init() {
19 | g_decode_pool[DECODE_TYPE_JSON] = &Json{}
20 | }
21 |
22 | type Json struct{}
23 |
24 | func (j *Json) Marshal(val interface{}) ([]byte, error) {
25 | return jsoniter.Marshal(val)
26 | }
27 | func (j *Json) Unmarshal(data_ []byte, val_ interface{}) error {
28 | return jsoniter.Unmarshal(data_, val_)
29 | }
30 |
31 | func Marshal(type_ uint32,val interface{} )([]byte, error){
32 | return g_decode_pool[type_].Marshal(val)
33 | }
34 |
35 | func Unmarshal(type_ uint32,data_ []byte, val_ interface{})error{
36 | return g_decode_pool[type_].Unmarshal(data_,val_)
37 | }
--------------------------------------------------------------------------------
/engine/YEntity/Entity.go:
--------------------------------------------------------------------------------
1 | package YEntity
2 |
3 | import "github.com/yxinyi/YCServer/engine/YAttr"
4 |
5 | var g_attr_tmpl_mgr = YAttr.NewAttrTmplPanelManager()
6 |
7 | func RegisterEntityAttr(entity_name_ string, panel_list_ ...*YAttr.TemplatePanel) {
8 | for _, _panel_it := range panel_list_ {
9 | g_attr_tmpl_mgr.RegisterEntityAttr(entity_name_, _panel_it)
10 | }
11 | }
12 |
13 | func New(type_str_ string) *Info {
14 | _info := NewInfo()
15 | _attr := g_attr_tmpl_mgr.New(type_str_)
16 | if _attr == nil {
17 | return nil
18 | }
19 | _info.M_entity_type = type_str_
20 | _info.AttributeValuePanel = _attr
21 | return _info
22 | }
23 |
24 | func NewWithUID(type_str_ string, entity_uid_ uint64) *Info {
25 | _info := New(type_str_)
26 | if _info == nil {
27 | return nil
28 | }
29 | _info.M_uid = entity_uid_
30 | return _info
31 | }
32 |
--------------------------------------------------------------------------------
/engine/YEntity/Info.go:
--------------------------------------------------------------------------------
1 | package YEntity
2 |
3 | import (
4 | "fmt"
5 | attr "github.com/yxinyi/YCServer/engine/YAttr"
6 | )
7 |
8 | type Info struct {
9 | M_uid uint64
10 | M_entity_type string
11 | M_is_ghost bool
12 | *attr.AttributeValuePanel
13 | }
14 |
15 | func NewInfo() *Info {
16 | _info := &Info{}
17 | return _info
18 | }
19 |
20 | func (e *Info) GetInfo() *Info {
21 | return e
22 | }
23 |
24 | func (e *Info) GetDebugString() string {
25 | _ret_str := ""
26 | _ret_str += fmt.Sprintf("[UID:%v][EntityType:%v][IsGhost:%v]\n",e.M_uid,e.M_entity_type,e.M_is_ghost)
27 | for _,_attr_it := range e.M_attr_list{
28 | _ret_str+= _attr_it.GetDebugString()
29 | }
30 |
31 | return _ret_str
32 | }
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/engine/YEntity/entity_test.go:
--------------------------------------------------------------------------------
1 | package YEntity
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YAttr"
5 | "testing"
6 | )
7 |
8 | type TmpStruct struct {
9 | M_val int
10 | }
11 |
12 | func TestEntity(t *testing.T) {
13 | RegisterEntityAttr("Test",
14 | YAttr.Define("AttrPanel_1",
15 | YAttr.Tmpl("attr_1", TmpStruct{M_val: 9}, true, true, true, true),
16 | ),
17 | YAttr.Define("AttrPanel_2",
18 | YAttr.Tmpl("attr_1", []uint32{1,2,3}, true, true, true, true),
19 | YAttr.Tmpl("attr_2", uint32(2), true, true, true, true),
20 | YAttr.Tmpl("attr_3", uint32(3), true, true, true, true),
21 | YAttr.Tmpl("attr_4", uint32(4), true, true, true, true),
22 | YAttr.Tmpl("attr_5", uint32(5), true, true, true, true),
23 | ))
24 | _entity_1 := NewWithUID("Test", 1)
25 | {
26 | _tmp, _err := _entity_1.GetAttr("AttrPanel_1.attr_1").(*TmpStruct)
27 | if !_err {
28 | t.Errorf("[%v]", _err)
29 | return
30 | }
31 | t.Logf("[%v]", _tmp.M_val)
32 | _tmp.M_val = 100
33 | }
34 | {
35 | _tmp, _ := _entity_1.GetAttr("AttrPanel_1.attr_1").(*TmpStruct)
36 | t.Logf("[%v]", _tmp.M_val)
37 | }
38 | {
39 | _tmp, _ := _entity_1.GetAttr("AttrPanel_2.attr_1").(*[]uint32)
40 | t.Logf("[%v]", *_tmp)
41 | }
42 | {
43 | _tmp, _ := _entity_1.GetAttr("AttrPanel_2.attr_2").(*uint32)
44 | t.Logf("[%v]", *_tmp)
45 | *_tmp = 1000
46 | }
47 | {
48 | _tmp, _ := _entity_1.GetAttr("AttrPanel_2.attr_3").(*uint32)
49 | t.Logf("[%v]", *_tmp)
50 | }
51 | {
52 | _tmp, _ := _entity_1.GetAttr("AttrPanel_2.attr_4").(*uint32)
53 | t.Logf("[%v]", *_tmp)
54 | }
55 | {
56 | _tmp, _ := _entity_1.GetAttr("AttrPanel_2.attr_5").(*uint32)
57 | t.Logf("[%v]", *_tmp)
58 | }
59 | {
60 | _tmp, _ := _entity_1.GetAttr("AttrPanel_2.attr_2").(*uint32)
61 | t.Logf("[%v]", *_tmp)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/engine/YJson/json.go:
--------------------------------------------------------------------------------
1 | package YJson
2 |
3 | import (
4 | "fmt"
5 | jsoniter "github.com/json-iterator/go"
6 | )
7 |
8 | var g_ghost_json = jsoniter.Config{TagKey: "SG", OnlyTaggedField: true}.Froze()
9 | var g_save_json = jsoniter.Config{TagKey: "SA", OnlyTaggedField: true}.Froze()
10 | var g_sync_self_json = jsoniter.Config{TagKey: "SS", OnlyTaggedField: true}.Froze()
11 | var g_sync_other_json = jsoniter.Config{TagKey: "SO", OnlyTaggedField: true}.Froze()
12 |
13 | var g_print_json = jsoniter.Config{SortMapKeys: true, MarshalFloatWith6Digits: true, IndentionStep: 4}.Froze()
14 |
15 | func GetPrintStr(val interface{}) string {
16 | _print_str, _err := g_print_json.MarshalToString(val)
17 | if _err != nil {
18 | return fmt.Sprintf("Marshal err [%v]", _err.Error())
19 | }
20 | return _print_str
21 | }
22 |
23 | func UnMarshal(str_ string,val_ interface{}) (error) {
24 | return jsoniter.UnmarshalFromString(str_,val_)
25 | }
26 |
27 | func GhostMarshal(val_ interface{}) (string, error) {
28 | return g_ghost_json.MarshalToString(val_)
29 | }
30 |
31 |
32 |
33 | func SaveMarshal(val_ interface{}) (string, error) {
34 | return g_save_json.MarshalToString(val_)
35 | }
36 | func SyncOtherMarshal(val_ interface{}) (string, error) {
37 | return g_sync_other_json.MarshalToString(val_)
38 | }
39 | func SyncSelfMarshal(val_ interface{}) (string, error) {
40 | return g_sync_self_json.MarshalToString(val_)
41 | }
42 |
--------------------------------------------------------------------------------
/engine/YLog/Log.go:
--------------------------------------------------------------------------------
1 | package ylog
2 |
3 | import (
4 | "fmt"
5 | "github.com/lestrrat/go-file-rotatelogs"
6 | "go.uber.org/zap"
7 | "go.uber.org/zap/zapcore"
8 | "io"
9 | "os"
10 | "time"
11 | )
12 |
13 | var Logger *zap.SugaredLogger
14 |
15 | var Erro func(template string, args ...interface{})
16 | var Info func(template string, args ...interface{})
17 | var Warn func(template string, args ...interface{})
18 |
19 |
20 |
21 | /*func Erro(template string, args ...interface{}){
22 | Logger.Errorf(template,args...)
23 | }
24 | func Info(template string, args ...interface{}){
25 | Logger.Infof(template,args...)
26 | }
27 | func Warn(template string, args ...interface{}){
28 | Logger.Warnf(template,args...)
29 | }*/
30 | func init() {
31 | initLogger()
32 |
33 | }
34 | func initLogger() {
35 | logPath := "./server"
36 | if !exists(logPath) {
37 | file, err := os.Create(logPath)
38 | defer file.Close()
39 | if err != nil {
40 | fmt.Println("mkdir logPath err! [%v]", err.Error())
41 | return
42 | }
43 | }
44 |
45 | encoder := initEncoder()
46 |
47 | // 想要将日常文件区分开来,可以实现多个日志等级接口
48 | /*infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
49 | return lvl < zapcore.WarnLevel
50 | })*/
51 | debugLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
52 | return lvl >= zapcore.DebugLevel
53 | })
54 |
55 | // 获取 info、warn日志文件的io.Writer
56 | warnIoWriter := getWriter(logPath)
57 |
58 | // 创建Logger
59 | core := zapcore.NewTee(
60 | zapcore.NewCore(encoder, zapcore.AddSync(warnIoWriter), debugLevel),
61 | zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), debugLevel),
62 | )
63 | logger := zap.New(core, zap.AddCaller()) // 需要传入 zap.AddCaller() 才会显示打日志点的文件名和行数
64 | Logger = logger.Sugar()
65 |
66 | Erro = Logger.Errorf
67 | Info = Logger.Infof
68 | Warn = Logger.Warnf
69 |
70 | }
71 |
72 | //初始化Encoder
73 | func initEncoder() zapcore.Encoder {
74 | return zapcore.NewConsoleEncoder(zapcore.EncoderConfig{
75 | MessageKey: "msg",
76 | LevelKey: "level",
77 | TimeKey: "time",
78 | CallerKey: "file",
79 | EncodeLevel: zapcore.CapitalLevelEncoder, //基本zapcore.LowercaseLevelEncoder。将日志级别字符串转化为小写
80 | EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
81 | enc.AppendString(t.Format("2006-01-02 15:04:05"))
82 | },
83 | EncodeCaller: zapcore.ShortCallerEncoder, //一般zapcore.ShortCallerEncoder,以包/文件:行号 格式化调用堆栈
84 | EncodeDuration: func(d time.Duration, enc zapcore.PrimitiveArrayEncoder) { //一般zapcore.SecondsDurationEncoder,执行消耗的时间转化成浮点型的秒
85 | enc.AppendInt64(int64(d) / 1000000)
86 | },
87 | })
88 | }
89 |
90 | //日志文件切割
91 | func getWriter(filename string) io.Writer {
92 | // 保存30天内的日志,每24小时(整点)分割一次日志
93 | hook, err := rotatelogs.New(
94 | filename+".%M_y%m%d",
95 | rotatelogs.WithLinkName(filename),
96 | rotatelogs.WithMaxAge(time.Hour*24*30),
97 | rotatelogs.WithRotationTime(time.Hour*24),
98 | )
99 |
100 | if err != nil {
101 | panic(err)
102 | }
103 | return hook
104 | }
105 |
106 | //查看文件/文件夹是否存在
107 | func exists(path string) bool {
108 | _, err := os.Stat(path)
109 | if err != nil {
110 | if os.IsExist(err) {
111 | return true
112 | }
113 | return false
114 | }
115 | return true
116 | }
117 |
--------------------------------------------------------------------------------
/engine/YModule/Info.go:
--------------------------------------------------------------------------------
1 | package YModule
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YDecode"
5 | "github.com/yxinyi/YCServer/engine/YEntity"
6 | ylog "github.com/yxinyi/YCServer/engine/YLog"
7 | "github.com/yxinyi/YCServer/engine/YMsg"
8 | "github.com/yxinyi/YCServer/engine/YTool"
9 | "reflect"
10 | "time"
11 | )
12 |
13 | type Inter interface {
14 | GetInfo() *Info
15 | Init()
16 | Loop_1(time time.Time)
17 | Loop_10(time time.Time)
18 | Loop_100(time time.Time)
19 | Close()
20 | }
21 |
22 | type BaseInter struct {
23 | *Info
24 | }
25 |
26 | func (b *BaseInter) GetInfo() *Info { return b.Info }
27 | func (b *BaseInter) Loop_1(time time.Time) {}
28 | func (b *BaseInter) Loop_10(time time.Time) {}
29 | func (b *BaseInter) Loop_100(time time.Time) {}
30 | func (b *BaseInter) Init() {}
31 | func (b *BaseInter) Close() {}
32 |
33 | type RPCFunc struct {
34 | M_rpc_name string
35 | M_fn reflect.Value
36 | M_param []reflect.Type
37 | M_back_param []reflect.Type
38 | }
39 |
40 | type NetFunc struct {
41 | M_net_name string
42 | M_fn reflect.Value
43 | m_msg_data reflect.Type
44 | }
45 |
46 | type RemoteNodeER interface {
47 | RPCToOther(msg *YMsg.S2S_rpc_msg)
48 | NetToOther(msg *YMsg.C2S_net_msg)
49 | }
50 |
51 | type Info struct {
52 | RemoteNodeER
53 | M_agent YMsg.Agent
54 | /*M_name string
55 | M_module_uid uint64*/
56 |
57 | M_entity_pool map[uint64]YEntity.Info
58 | M_rpc_queue *YTool.SyncQueue
59 | M_net_queue *YTool.SyncQueue
60 |
61 | M_rpc_func_map map[string]*RPCFunc
62 | M_net_func_map map[string]*NetFunc
63 | m_cb_list_cancel bool
64 | M_back_fun map[uint64]*RPCCommandList
65 | }
66 |
67 | type RPCCommand struct {
68 | M_uid uint64
69 | M_tar_agent YMsg.Agent
70 | M_tar_rpc_func_name string
71 | M_tar_rpc_param_list []interface{}
72 | M_need_back bool
73 | M_back_func reflect.Value
74 | M_back_param []reflect.Type
75 | }
76 |
77 | func NewRPCMsg(tar_agent_ YMsg.Agent, tar_func_name_ string, param_list_ ...interface{}) *YMsg.S2S_rpc_msg {
78 | return NewRPCCommand(tar_agent_, tar_func_name_, param_list_...).ToRPCMsg()
79 | }
80 |
81 |
82 |
83 | func NewRPCCommand(tar_agent_ YMsg.Agent, tar_func_name_ string, param_list_ ...interface{}) *RPCCommand {
84 | _rpc_cmd := &RPCCommand{}
85 | _rpc_cmd.M_uid = YTool.BuildUIDUint64()
86 | _rpc_cmd.M_tar_agent = tar_agent_
87 | _rpc_cmd.M_tar_rpc_func_name = tar_func_name_
88 |
89 | if len(param_list_) > 0 {
90 | _cb_func_value := reflect.ValueOf(param_list_[len(param_list_)-1])
91 | if _cb_func_value.Type().Kind() == reflect.Func {
92 | _rpc_cmd.M_need_back = true
93 | _rpc_cmd.M_back_func = _cb_func_value
94 | _rpc_cmd.M_back_param = YTool.GetFuncInTypeList(_cb_func_value)
95 | _rpc_cmd.M_tar_rpc_param_list = param_list_[:len(param_list_)-1]
96 | } else {
97 | _rpc_cmd.M_tar_rpc_param_list = param_list_
98 | }
99 | }
100 |
101 | return _rpc_cmd
102 | }
103 |
104 | type RPCCommandList struct {
105 | M_uid uint64
106 | M_cur_idx uint32
107 | m_command_list []*RPCCommand
108 | }
109 |
110 | func NewRPCCommandList() *RPCCommandList {
111 | _cmd_list := &RPCCommandList{}
112 | _cmd_list.M_uid = YTool.BuildUIDUint64()
113 | _cmd_list.m_command_list = make([]*RPCCommand, 0)
114 | return _cmd_list
115 | }
116 |
117 | func NewInfo(node_ RemoteNodeER) *Info {
118 | _info := &Info{
119 | M_entity_pool: make(map[uint64]YEntity.Info),
120 | M_rpc_func_map: make(map[string]*RPCFunc),
121 | M_net_func_map: make(map[string]*NetFunc),
122 | M_rpc_queue: YTool.NewSyncQueue(),
123 | M_net_queue: YTool.NewSyncQueue(),
124 | M_back_fun: make(map[uint64]*RPCCommandList),
125 | RemoteNodeER: node_,
126 | }
127 | return _info
128 | }
129 |
130 | func (cmd *RPCCommand) ToRPCMsg() *YMsg.S2S_rpc_msg {
131 | _rpc_msg := &YMsg.S2S_rpc_msg{
132 | M_uid: cmd.M_uid,
133 | M_tar: cmd.M_tar_agent,
134 | M_marshal_type: YDecode.DECODE_TYPE_JSON,
135 | M_func_name: cmd.M_tar_rpc_func_name,
136 | }
137 | if len(cmd.M_tar_rpc_param_list) > 0 {
138 | _rpc_msg.M_func_parameter = make([][]byte, 0, len(cmd.M_tar_rpc_param_list))
139 | for _, _param_it := range cmd.M_tar_rpc_param_list {
140 | _param_byte, _err := YDecode.Marshal(_rpc_msg.M_marshal_type, _param_it)
141 | if _err != nil {
142 | ylog.Erro("[RPCToOther] tar [%v:%v] [%v]", cmd.M_tar_agent.DebugString(), _err.Error())
143 | return nil
144 | }
145 | _rpc_msg.M_func_parameter = append(_rpc_msg.M_func_parameter, _param_byte)
146 | }
147 | }
148 | return _rpc_msg
149 | }
150 |
151 | func (list *RPCCommandList) AppendCmdObj(cmd *RPCCommand) *RPCCommandList {
152 | cmd.M_uid = list.M_uid
153 | if len(list.m_command_list) == 0 {
154 | cmd.M_need_back = true
155 | }
156 | list.m_command_list = append(list.m_command_list, cmd)
157 | return list
158 | }
159 |
160 | func (list *RPCCommandList) AfterRPC(tar_agent_ YMsg.Agent, func_ string, param_list_ ...interface{}) *RPCCommandList {
161 | return list.AppendCmdObj(NewRPCCommand(tar_agent_, func_, param_list_...))
162 | }
163 |
164 | func (list *RPCCommandList) getCurCmd() *RPCCommand {
165 | return list.m_command_list[list.M_cur_idx]
166 | }
167 |
168 | func (list *RPCCommandList) call(param_val_ []reflect.Value) {
169 | if list.getCurCmd().M_back_func.IsValid() {
170 | list.getCurCmd().M_back_func.Call(param_val_)
171 | }
172 |
173 | list.M_cur_idx++
174 | }
175 | func (list *RPCCommandList) isOver() bool {
176 | return list.M_cur_idx >= uint32(len(list.m_command_list))
177 | }
178 |
179 | func (list *RPCCommandList) popMsg() *YMsg.S2S_rpc_msg {
180 | _cur_cmd := list.getCurCmd()
181 | _rpc_msg := _cur_cmd.ToRPCMsg()
182 | _rpc_msg.M_need_back = true
183 | if list.isOver() {
184 | if !_cur_cmd.M_back_func.IsValid() {
185 | _rpc_msg.M_need_back = false
186 | }
187 | }
188 |
189 | return _rpc_msg
190 | }
191 |
--------------------------------------------------------------------------------
/engine/YModule/Module.go:
--------------------------------------------------------------------------------
1 | package YModule
2 |
3 | import (
4 | "fmt"
5 | "github.com/json-iterator/go"
6 | ylog "github.com/yxinyi/YCServer/engine/YLog"
7 | "github.com/yxinyi/YCServer/engine/YMsg"
8 | "github.com/yxinyi/YCServer/engine/YNet"
9 | "reflect"
10 | "runtime/debug"
11 | "strings"
12 | )
13 |
14 | func (i *Info) PushRpcMsg(msg_ *YMsg.S2S_rpc_msg) {
15 | i.M_rpc_queue.Add(msg_)
16 | }
17 | func (i *Info) PushNetMsg(msg_ *YMsg.C2S_net_msg) {
18 | i.M_net_queue.Add(msg_)
19 | }
20 |
21 | func (i *Info) buildRPCFunc(func_name_ string, method_val_ reflect.Value) *RPCFunc {
22 | _func := &RPCFunc{
23 | M_rpc_name: func_name_,
24 | M_fn: method_val_,
25 | }
26 | if method_val_.Type().NumIn() > 0 {
27 | _func.M_param = make([]reflect.Type, 0)
28 | for _in_idx := 0; _in_idx < method_val_.Type().NumIn(); _in_idx++ {
29 | _func.M_param = append(_func.M_param, method_val_.Type().In(_in_idx))
30 | }
31 | }
32 | if method_val_.Type().NumOut() > 0 {
33 | _func.M_back_param = make([]reflect.Type, 0)
34 | for _out_idx := 0; _out_idx < method_val_.Type().NumOut(); _out_idx++ {
35 | _func.M_back_param = append(_func.M_back_param, method_val_.Type().Out(_out_idx))
36 | }
37 | }
38 | return _func
39 | }
40 |
41 | func (i *Info) buildNetFunc(func_name_ string, method_val_ reflect.Value) *NetFunc {
42 | if method_val_.Type().NumIn() != 2 {
43 | return nil
44 | }
45 | _func := &NetFunc{
46 | M_net_name: func_name_,
47 | M_fn: method_val_,
48 | }
49 | _func.m_msg_data = method_val_.Type().In(1)
50 | return _func
51 | }
52 |
53 | func (i *Info) CancelCBList() {
54 | i.m_cb_list_cancel = true
55 | }
56 |
57 | func (i *Info) Init(core Inter) {
58 | _ref_val := reflect.ValueOf(core)
59 | _method_num := _ref_val.NumMethod()
60 | for idx := 0; idx < _method_num; idx++ {
61 | _method_val := _ref_val.Method(idx)
62 | _func_name := _ref_val.Type().Method(idx).Name
63 | {
64 | _prefix_str := "RPC_"
65 | _str_idx := strings.Index(_func_name, _prefix_str)
66 | if _str_idx != -1 {
67 | _func := i.buildRPCFunc(_func_name, _method_val)
68 | i.M_rpc_func_map[_func.M_rpc_name[_str_idx+len(_prefix_str):]] = _func
69 | }
70 | }
71 | {
72 | _prefix_str := "MSG_"
73 | _str_idx := strings.Index(_func_name, _prefix_str)
74 | if _str_idx != -1 {
75 | _func := i.buildNetFunc(_func_name, _method_val)
76 | i.M_net_func_map[_func.M_net_name[_str_idx+len(_prefix_str):]] = _func
77 | }
78 | }
79 | }
80 | if len(i.M_net_func_map) > 0 {
81 | _msg_name_list := make([]string, 0)
82 | for _k_it := range i.M_net_func_map {
83 | _msg_name_list = append(_msg_name_list, _k_it)
84 | }
85 | i.RPCCall(YMsg.ToAgent("NetModule"), "NetMsgRegister", _msg_name_list, i.GetAgent())
86 | }
87 | }
88 |
89 | func (i *Info) DebugPrint() {
90 | for _name_it, _func_it := range i.M_rpc_func_map {
91 | ylog.Info("#############")
92 | ylog.Info("[name] [%v] [func] [%v]", _name_it, _func_it.M_fn.String())
93 | for _, _param_it := range _func_it.M_param {
94 | ylog.Info("param [%v]", _param_it.String())
95 | }
96 | }
97 | }
98 | func (i *Info) paramUnmarshalWithTypeSlice(bytes_list_ [][]byte, type_list_ []reflect.Type) []reflect.Value {
99 | _param_list := make([]reflect.Value, 0)
100 | for _idx := 0; _idx < len(type_list_); _idx++ {
101 | _param_val := reflect.New(type_list_[_idx]).Interface()
102 | err := jsoniter.Unmarshal(bytes_list_[_idx], _param_val)
103 | if err != nil {
104 | ylog.Erro("RPC unmarshal err [%v] ", err.Error())
105 | return nil
106 | }
107 | _param_list = append(_param_list, reflect.ValueOf(_param_val).Elem())
108 | }
109 | return _param_list
110 | }
111 |
112 | func (i *Info) msgUnmarshalParamList(msg *YMsg.S2S_rpc_msg) []reflect.Value {
113 | _func, _exists := i.M_rpc_func_map[msg.M_func_name]
114 | if !_exists {
115 | ylog.Erro("[%v] RPC param miss method [%v]", msg.M_tar.M_module_name, msg.M_func_name)
116 | return nil
117 | }
118 |
119 | if len(_func.M_param) != len(msg.M_func_parameter) {
120 | ylog.Erro("[%v]RPC [%v]param count err right [%v] err [%v]", msg.M_tar.M_module_name, msg.M_func_name, len(_func.M_param), len(msg.M_func_parameter))
121 | return nil
122 | }
123 | return i.paramUnmarshalWithTypeSlice(msg.M_func_parameter, _func.M_param)
124 | }
125 |
126 | func (i *Info) call(msg_ *YMsg.S2S_rpc_msg, val_list_ []reflect.Value) []reflect.Value {
127 | _func := i.M_rpc_func_map[msg_.M_func_name]
128 | if _func == nil {
129 | panic(string(debug.Stack()))
130 | }
131 | return _func.M_fn.Call(val_list_)
132 | }
133 |
134 | func (i *Info) DoRPCMsg(msg_ *YMsg.S2S_rpc_msg) {
135 | if msg_.M_is_back {
136 | _call_back_cmd_list := i.M_back_fun[msg_.M_uid]
137 | if _call_back_cmd_list == nil {
138 | return
139 | }
140 | _param_value := i.paramUnmarshalWithTypeSlice(msg_.M_func_parameter, _call_back_cmd_list.getCurCmd().M_back_param)
141 | _call_back_cmd_list.call(_param_value)
142 | if i.m_cb_list_cancel {
143 | i.m_cb_list_cancel = false
144 | delete(i.M_back_fun, msg_.M_uid)
145 | return
146 | }
147 | if _call_back_cmd_list.isOver() {
148 | delete(i.M_back_fun, msg_.M_uid)
149 | return
150 | }
151 |
152 | _rpc_msg := _call_back_cmd_list.popMsg()
153 | if !_rpc_msg.M_need_back {
154 | delete(i.M_back_fun, msg_.M_uid)
155 | }
156 | _rpc_msg.M_source = i.GetAgent()
157 | //_rpc_msg.M_tar = msg_.M_tar
158 | i.RPCToOther(_rpc_msg)
159 | return
160 | }
161 |
162 | _param_list := i.msgUnmarshalParamList(msg_)
163 | if _param_list == nil {
164 | return
165 | }
166 | _back_param := i.call(msg_, _param_list)
167 | if msg_.M_need_back {
168 | _back_param_inter_list := make([]interface{}, 0, len(_back_param))
169 | for _, _it := range _back_param {
170 | _back_param_inter_list = append(_back_param_inter_list, _it.Interface())
171 | }
172 | _rpc_cmd := NewRPCCommand(msg_.M_source, msg_.M_func_name, _back_param_inter_list...)
173 | _rpc_msg := _rpc_cmd.ToRPCMsg()
174 | _rpc_msg.M_is_back = true
175 | _rpc_msg.M_uid = msg_.M_uid
176 | i.RPCToOther(_rpc_msg)
177 | }
178 | }
179 | func (i *Info) DonNetMsg(msg_ *YMsg.C2S_net_msg) {
180 | _net_func_obj := i.M_net_func_map[msg_.M_net_msg.M_msg_name]
181 | if _net_func_obj == nil {
182 | return
183 | }
184 |
185 | _json_data := reflect.New(_net_func_obj.m_msg_data).Interface()
186 | err := jsoniter.Unmarshal(msg_.M_net_msg.M_msg_data, _json_data)
187 | if err != nil {
188 | ylog.Erro("[%v] decode err [%v]", msg_.M_net_msg.M_msg_data, err.Error())
189 | return
190 | }
191 |
192 | _net_func_obj.M_fn.Call([]reflect.Value{
193 | reflect.ValueOf(msg_.M_session_id),
194 | reflect.ValueOf(_json_data).Elem(),
195 | })
196 | }
197 |
198 | func (i *Info) Loop_Msg() {
199 | for {
200 | if i.M_net_queue.Len() == 0 {
201 | break
202 | }
203 | _msg := i.M_net_queue.Pop().(*YMsg.C2S_net_msg)
204 | i.DonNetMsg(_msg)
205 | }
206 | for {
207 | if i.M_rpc_queue.Len() == 0 {
208 | break
209 | }
210 | _msg := i.M_rpc_queue.Pop().(*YMsg.S2S_rpc_msg)
211 | i.DoRPCMsg(_msg)
212 | }
213 | }
214 |
215 | func (i *Info) GetAgent() YMsg.Agent {
216 | return i.M_agent
217 | }
218 |
219 | func (i *Info) DebugString() string {
220 | return fmt.Sprintf("[%v]", i.GetAgent().DebugString())
221 | }
222 |
223 | func (i *Info) SendNetMsgJson(session_id_ uint64, json_msg_ interface{}) {
224 | _msg := YNet.NewNetMsgPackWithJson(json_msg_)
225 | if _msg == nil {
226 | ylog.Erro("[%v:SendNetMsgJson] err [%v]", i.GetAgent().GetKeyStr(), reflect.TypeOf(json_msg_).String())
227 | return
228 | }
229 | i.RPCCall(YMsg.ToAgent("NetModule"), "SendNetMsgJson", session_id_, _msg)
230 | }
231 |
232 | func (i *Info) RPCCall(tar_agent YMsg.Agent, func_ string, param_list_ ...interface{}) *RPCCommandList {
233 | _rpc_command_list := NewRPCCommandList()
234 | _rpc_command_list.AfterRPC(tar_agent, func_, param_list_...)
235 | _rpc_msg := _rpc_command_list.popMsg()
236 | if _rpc_msg.M_need_back {
237 | _rpc_msg.M_source = i.GetAgent()
238 | i.M_back_fun[_rpc_command_list.M_uid] = _rpc_command_list
239 | }
240 | i.RPCToOther(_rpc_msg)
241 | return _rpc_command_list
242 | }
243 |
244 | func (i *Info) RegisterModule(module_name_ string, id_ uint64) {
245 | i.RPCCall(YMsg.ToAgent("YNode"), "NewModule", module_name_, id_)
246 | }
247 |
--------------------------------------------------------------------------------
/engine/YMsg/in_msg.go:
--------------------------------------------------------------------------------
1 | package YMsg
2 |
3 | import (
4 | "fmt"
5 | "github.com/yxinyi/YCServer/engine/YNet"
6 | )
7 |
8 | type Agent struct {
9 | M_module_name string
10 | M_module_uid uint64
11 | }
12 |
13 | type S2S_rpc_msg struct {
14 | M_uid uint64
15 | M_source Agent
16 | M_tar Agent
17 | M_marshal_type uint32
18 | M_func_name string
19 | M_func_parameter [][]byte
20 | M_need_back bool
21 | M_is_back bool
22 | }
23 |
24 | type C2S_net_msg struct {
25 | M_tar Agent
26 | M_session_id uint64
27 | M_net_msg *YNet.NetMsgPack
28 | }
29 |
30 | func (m *S2S_rpc_msg) DebugString() string {
31 | return fmt.Sprintf("Tar [%v] Func [%v]", m.M_tar.DebugString(), m.M_func_name)
32 | }
33 |
34 | type TestParam struct {
35 | M_val uint32
36 | M_val_str string
37 | M_val_int []int
38 | }
39 |
40 | func ToAgent(args ...interface{}) Agent {
41 | _agent := Agent{}
42 | if len(args) >= 1 {
43 | _agent.M_module_name = args[0].(string)
44 | }
45 | if len(args) >= 2 {
46 | _module_uid := uint64(0)
47 | switch args[1].(type) {
48 | case uint64:
49 | _module_uid = args[1].(uint64)
50 | case uint32:
51 | _module_uid = uint64(args[1].(uint32))
52 | case int:
53 | _module_uid = uint64(args[1].(int))
54 | }
55 | _agent.M_module_uid = _module_uid
56 | }
57 | return _agent
58 | }
59 |
60 | func (a Agent) DebugString() string {
61 | return fmt.Sprintf("Tar [%v:%v]", a.M_module_name, a.M_module_uid)
62 | }
63 | func (a Agent) GetKeyStr() string {
64 | return fmt.Sprintf("%v:%v", a.M_module_name, a.M_module_uid)
65 | }
66 |
--------------------------------------------------------------------------------
/engine/YNet/Connect.go:
--------------------------------------------------------------------------------
1 | package YNet
2 |
3 | import (
4 | "net"
5 | "sync"
6 | "time"
7 | )
8 |
9 | const (
10 | MAX_PACKAGE_LEN uint32 = 1000
11 | )
12 |
13 | type Connect struct {
14 | m_conn net.Conn
15 | m_session *Session
16 | m_wg sync.WaitGroup
17 | }
18 |
19 | func NewConnect() *Connect {
20 | return &Connect{}
21 | }
22 |
23 | func (c *Connect) Connect(ip_port_ string) bool {
24 | var _conn net.Conn
25 | for {
26 | _tmp_conn, _err := net.Dial("tcp4", ip_port_)
27 | if _err != nil {
28 | time.Sleep(1 * time.Second)
29 | continue
30 | }
31 | _conn = _tmp_conn
32 | break
33 | }
34 | c.m_conn = _conn
35 | c.m_conn.(*net.TCPConn).SetNoDelay(true)
36 | c.m_session = NewSession(_conn)
37 | return true
38 | }
39 |
40 | /*func (c *Connect) SendMsg(msg_id_ uint32, msg_ interface{}) {
41 | _net_msg := NewNetMsgPack()
42 | _net_msg.M_msg_id = msg_id_
43 | json_data, err := jsoniter.Marshal(msg_)
44 | if err == nil {
45 | _net_msg.M_msg_data = json_data
46 | _net_msg.M_msg_length = uint32(len(json_data))
47 | }
48 | c.m_session.Send(_net_msg)
49 | }*/
50 |
51 | func (c *Connect) SendJson(msg_ interface{}) {
52 | if c.m_session == nil {
53 | return
54 | }
55 | c.m_session.SendJson(msg_)
56 | }
57 | func (c *Connect) GetSession() *Session {
58 | return c.m_session
59 | }
60 | func (c *Connect) Start() bool {
61 | c.m_session.StartLoop()
62 | return true
63 | }
64 |
65 | func (c *Connect) End() bool {
66 | c.m_session.Close()
67 | return true
68 | }
69 |
--------------------------------------------------------------------------------
/engine/YNet/Listen.go:
--------------------------------------------------------------------------------
1 | package YNet
2 |
3 | import (
4 | "errors"
5 | "fmt"
6 | "net"
7 | )
8 |
9 | var g_listener net.Listener
10 | var G_close = make(chan struct{})
11 | var g_connect_list = make(map[uint64]*Session)
12 |
13 | var G_net_msg_chan = make(chan *Message,100)
14 |
15 |
16 | func ListenTcp4(ip_port_ string) error {
17 | listen, err := net.Listen("tcp4", ip_port_)
18 | if err != nil {
19 | return errors.New("listen err [%v]" + err.Error())
20 | }
21 | go func() {
22 | for {
23 | select {
24 | case <-G_close:
25 | return
26 | default:
27 | _conn, err := listen.Accept()
28 | if err != nil {
29 | fmt.Printf("accept err " + err.Error())
30 | continue
31 | }
32 | _session := NewSession(_conn)
33 | g_connect_list[_session.m_uid] = _session
34 | _session.StartLoop()
35 |
36 | connMsg := NewMessage(NET_SESSION_STATE_CONNECT,_session,nil)
37 | G_net_msg_chan <- connMsg
38 | }
39 |
40 | }
41 | }()
42 |
43 | return nil
44 | }
45 |
46 | func Stop() {
47 | G_close <- struct{}{}
48 | }
49 |
--------------------------------------------------------------------------------
/engine/YNet/Message.go:
--------------------------------------------------------------------------------
1 | package YNet
2 |
3 | import "sync/atomic"
4 |
5 | const (
6 | NET_SESSION_STATE_CONNECT uint8 = iota
7 | NET_SESSION_STATE_MSG
8 | NET_SESSION_STATE_CLOSE
9 | NET_SESSION_STATE_CONNECT_OTHER_SUCCESS
10 | )
11 |
12 | type Message struct {
13 | M_msg_type uint8
14 | M_uid uint64
15 | M_session *Session
16 | M_net_msg *NetMsgPack
17 | }
18 |
19 | var g_msg_unique_id = uint64(0)
20 |
21 | func NewMessage(type_ uint8, s_ *Session, pack_ *NetMsgPack) *Message {
22 | atomic.AddUint64(&g_msg_unique_id, 1)
23 | return &Message{
24 | M_msg_type: type_,
25 | M_uid: g_msg_unique_id,
26 | M_session: s_,
27 | M_net_msg: pack_,
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/engine/YNet/NetMsgManager.go:
--------------------------------------------------------------------------------
1 | package YNet
2 |
3 | import (
4 | "fmt"
5 | "github.com/json-iterator/go"
6 | "reflect"
7 | "strings"
8 | )
9 |
10 | type NetMsgHandler struct {
11 | m_msg_name string
12 | m_fn reflect.Value
13 | m_msg_data reflect.Type
14 | }
15 |
16 | var net_msg_list = make(map[string]*NetMsgHandler)
17 |
18 | func Register(fn_ interface{}) {
19 |
20 | _handler := &NetMsgHandler{
21 | m_fn: reflect.ValueOf(fn_),
22 | }
23 | _handler.m_msg_data = reflect.TypeOf(fn_).In(1)
24 | _msg_name := _handler.m_msg_data.String()
25 | _split_idx := strings.Index(_msg_name,".")
26 | _msg_name = _msg_name[_split_idx+1:]
27 | net_msg_list[_msg_name] = _handler
28 | }
29 |
30 | func Dispatch(s_ *Session, net_msg_ *NetMsgPack) error {
31 | if net_msg_ == nil {
32 | return nil
33 | }
34 | _handler, exists := net_msg_list[net_msg_.M_msg_name]
35 | if !exists {
36 | return fmt.Errorf("[%v] miss call back ", net_msg_.M_msg_name)
37 | }
38 | fmt.Printf("[Dispatch] [%v] \n",net_msg_.M_msg_name)
39 | //可以传入不同的解析类型,进行解析
40 | _json_data := reflect.New(_handler.m_msg_data).Interface()
41 | err := jsoniter.Unmarshal(net_msg_.M_msg_data, _json_data)
42 | if err != nil {
43 | return fmt.Errorf("[%v] decode err [%v]", net_msg_.M_msg_data, err.Error())
44 | }
45 |
46 | _handler.m_fn.Call([]reflect.Value{
47 | reflect.ValueOf(s_).Elem(),
48 | reflect.ValueOf(_json_data).Elem(),
49 | })
50 |
51 | return nil
52 | }
53 |
--------------------------------------------------------------------------------
/engine/YNet/NetMsgPack.go:
--------------------------------------------------------------------------------
1 | package YNet
2 |
3 | import (
4 | "encoding/binary"
5 | "github.com/json-iterator/go"
6 | "io"
7 | "reflect"
8 | "strings"
9 | "unsafe"
10 | )
11 |
12 | const (
13 | MESSAGE_TYPE_JSON = 1
14 | MESSAGE_TYPE_PROTO = 2
15 | )
16 |
17 | type NetMsgPack struct {
18 | M_msg_name string
19 | M_msg_data []byte
20 | }
21 |
22 | const (
23 | const_type_size = int(unsafe.Sizeof(uint32(0)))
24 | const_length_size = int(unsafe.Sizeof(uint32(0)))
25 | )
26 |
27 | func NewNetMsgPack() *NetMsgPack {
28 | return &NetMsgPack{
29 | }
30 | }
31 | func NewNetMsgPackWithJson(json_ interface{}) *NetMsgPack {
32 | _msg := NewNetMsgPack()
33 |
34 | _msg_name := reflect.TypeOf(json_).String()
35 | _split_idx := strings.Index(_msg_name,".")
36 | _msg_name = _msg_name[_split_idx+1:]
37 | _msg.M_msg_name = _msg_name
38 | _byte, _err := jsoniter.Marshal(json_)
39 | if _err != nil {
40 | return nil
41 | }
42 | _msg.M_msg_data = _byte
43 | return _msg
44 | }
45 |
46 | func (pack *NetMsgPack) ToByteStream() []byte {
47 | _name_length := len(pack.M_msg_name)
48 | _data_length := len(pack.M_msg_data)
49 |
50 | _total_length := const_type_size + const_length_size + _name_length + _data_length
51 | _stream_byte := make([]byte, _total_length)
52 |
53 | binary.LittleEndian.PutUint32(_stream_byte, uint32(_name_length))
54 | binary.LittleEndian.PutUint32(_stream_byte[const_type_size:], uint32(_data_length))
55 | copy(_stream_byte[uint32(const_type_size+const_length_size):], pack.M_msg_name[:])
56 | copy(_stream_byte[uint32(const_type_size+const_length_size+_name_length):], pack.M_msg_data[:])
57 | return _stream_byte
58 | }
59 |
60 | func (pack *NetMsgPack) InitFromIO(io_ io.Reader) bool {
61 | _type_byte := make([]byte, const_type_size+const_length_size)
62 |
63 | _len, err := io.ReadFull(io_, _type_byte)
64 | if _len == 0 {
65 | return false
66 | }
67 | if err != nil {
68 | return false
69 | }
70 |
71 | _name_length := binary.LittleEndian.Uint32(_type_byte[0:const_type_size])
72 | _data_length := binary.LittleEndian.Uint32(_type_byte[const_type_size : const_type_size+const_type_size])
73 |
74 | _msg_name_byte := make([]byte, _name_length)
75 | _len, err = io.ReadFull(io_, _msg_name_byte)
76 | if err != nil {
77 | return false
78 | }
79 | pack.M_msg_name = string(_msg_name_byte)
80 |
81 | pack.M_msg_data = make([]byte, _data_length)
82 | _len, err = io.ReadFull(io_, pack.M_msg_data)
83 | if err != nil {
84 | return false
85 | }
86 |
87 | return true
88 | }
89 |
--------------------------------------------------------------------------------
/engine/YNet/Session.go:
--------------------------------------------------------------------------------
1 | package YNet
2 |
3 | import (
4 | "fmt"
5 | "net"
6 | "sync/atomic"
7 | )
8 |
9 | type Session struct {
10 | m_uid uint64
11 | m_conn net.Conn
12 | m_stop chan struct{}
13 | m_send_msg_chan chan *NetMsgPack
14 | M_is_rotbot bool
15 | }
16 |
17 | var g_uni_id = uint64(0)
18 |
19 | func NewSession(conn_ net.Conn) *Session {
20 | atomic.AddUint64(&g_uni_id, 1)
21 | return &Session{
22 | m_uid: g_uni_id,
23 | m_conn: conn_,
24 | m_send_msg_chan: make(chan *NetMsgPack, MAX_PACKAGE_LEN),
25 | m_stop: make(chan struct{}),
26 | }
27 | }
28 |
29 | func (s *Session) GetUID() uint64 {
30 | return s.m_uid
31 | }
32 |
33 | func (s *Session) Close() {
34 | close(s.m_send_msg_chan)
35 | close(s.m_stop)
36 | }
37 |
38 | func (s *Session) SendJson(json_ interface{}) error {
39 | if s.M_is_rotbot {
40 | return nil
41 | }
42 | _msg := NewNetMsgPackWithJson(json_)
43 | if _msg == nil {
44 | return fmt.Errorf("[Session:SendJson] pack error")
45 | }
46 | s.Send(_msg)
47 | return nil
48 | }
49 |
50 | func (s *Session) Send(msg_ *NetMsgPack) bool {
51 | if s.M_is_rotbot {
52 | return true
53 | }
54 | if s.m_send_msg_chan == nil {
55 | return false
56 | }
57 | s.m_send_msg_chan <- msg_
58 | return true
59 | }
60 |
61 | func (s *Session) StartLoop() {
62 | go func() {
63 | for {
64 | select {
65 | case <-s.m_stop:
66 | return
67 | case pack, ok := <-s.m_send_msg_chan:
68 | if !ok {
69 | s.m_conn.Close()
70 | return
71 | }
72 | _msg_byte := pack.ToByteStream()
73 | _, err := s.m_conn.Write(_msg_byte)
74 | if err != nil {
75 | break
76 | }
77 | }
78 | }
79 | }()
80 | go func() {
81 | for {
82 | select {
83 | case <-s.m_stop:
84 | return
85 | default:
86 | _msg_pack := NewNetMsgPack()
87 | if !_msg_pack.InitFromIO(s.m_conn) {
88 | connMsg := NewMessage(NET_SESSION_STATE_CLOSE, s, nil)
89 | G_net_msg_chan <- connMsg
90 | return
91 | }
92 |
93 | connMsg := NewMessage(NET_SESSION_STATE_MSG, s, _msg_pack)
94 | G_net_msg_chan <- connMsg
95 | }
96 | }
97 | }()
98 | }
99 |
--------------------------------------------------------------------------------
/engine/YNode/API.go:
--------------------------------------------------------------------------------
1 | package YNode
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YJson"
5 | ylog "github.com/yxinyi/YCServer/engine/YLog"
6 | "github.com/yxinyi/YCServer/engine/YMsg"
7 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
8 | )
9 |
10 | func (n *Info) RPC_NewModule(create_func_name string, uid_ uint64) {
11 | _new_module := NewModuleInfo(create_func_name, uid_)
12 | G_node_obj.register(_new_module)
13 | //n.SyncModulesKey()
14 | go G_node_obj.startModule(_new_module)
15 | }
16 |
17 | func (n *Info) SyncModulesKey(session_ uint64) {
18 | _keys := make([]string, 0)
19 | for _, _mo_it := range n.M_module_pool {
20 | _keys = append(_keys, _mo_it.GetInfo().GetAgent().GetKeyStr())
21 | }
22 |
23 | n.SendNetMsgJson(session_, Msg.S2S_SyncOtherNodeRPC{
24 | _keys,
25 | n.M_node_id,
26 | })
27 | }
28 |
29 | func (n *Info) RPC_RegisterOtherNode(ip_port_ string, session_ uint64) {
30 | _node_id, exists := n.M_node_ip_to_id[ip_port_]
31 | if !exists {
32 | n.RPCCall(YMsg.ToAgent("NetModule", uint64(n.M_node_id)), "Close", session_)
33 | return
34 | }
35 | n.M_node_id_to_session[_node_id] = session_
36 | n.SyncModulesKey(session_)
37 | }
38 |
39 | func (n *Info) MSG_S2S_SyncOtherNodeRPC(s_ uint64, msg_ Msg.S2S_SyncOtherNodeRPC) {
40 | ylog.Info("[%v]", YJson.GetPrintStr(msg_))
41 | for _, _msg_it := range msg_.M_net_msg {
42 | n.M_other_node_module_key_str_to_node_id[_msg_it] = msg_.M_node_id
43 | }
44 | }
45 |
46 | func (n *Info) MSG_C2S_net_msg(s_ uint64, msg_ YMsg.C2S_net_msg) {
47 | n.PushNetMsg(&msg_)
48 | }
49 |
--------------------------------------------------------------------------------
/engine/YNode/Info.go:
--------------------------------------------------------------------------------
1 | package YNode
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YModule"
5 | )
6 |
7 | type Info struct {
8 | M_node_id uint32
9 | M_module_pool map[string]YModule.Inter
10 |
11 | M_node_ip_to_id map[string]uint32
12 | M_node_id_to_session map[uint32]uint64
13 |
14 | M_other_node_module_key_str_to_node_id map[string]uint32
15 |
16 | YModule.BaseInter
17 |
18 | m_moduele_factory map[string]func(node_ *Info, uid uint64) YModule.Inter
19 | }
20 |
21 | func newInfo() *Info {
22 | info := &Info{
23 | M_module_pool: make(map[string]YModule.Inter),
24 | m_moduele_factory: make(map[string]func(node_ *Info, uid uint64) YModule.Inter),
25 |
26 | M_node_ip_to_id: make(map[string]uint32),
27 | M_node_id_to_session: make(map[uint32]uint64),
28 |
29 | M_other_node_module_key_str_to_node_id: make(map[string]uint32),
30 | }
31 | return info
32 | }
33 |
--------------------------------------------------------------------------------
/engine/YNode/Node.go:
--------------------------------------------------------------------------------
1 | package YNode
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YMsg"
7 | "reflect"
8 | "runtime/debug"
9 | "strings"
10 | "time"
11 | )
12 |
13 | var G_node_obj = newInfo()
14 | var g_stop = make(chan struct{})
15 |
16 | func init() {
17 | G_node_obj.Info = YModule.NewInfo(G_node_obj)
18 | }
19 |
20 | func (n *Info) findNode(key_str_ string) uint64 {
21 | _node_id, _exists := n.M_other_node_module_key_str_to_node_id[key_str_]
22 | if !_exists {
23 | return 0
24 | }
25 |
26 | return n.M_node_id_to_session[_node_id]
27 | }
28 |
29 | /*func (n *Info) GetModuleName(module_name_ string, module_uid_ uint64) string {
30 | return fmt.Sprintf("%s:%d", module_name_, module_uid_)
31 | }*/
32 |
33 | func (n *Info) register(info YModule.Inter) {
34 | G_node_obj.M_module_pool[info.GetInfo().GetAgent().GetKeyStr()] = info
35 | info.Init()
36 | }
37 |
38 | func (n *Info) RPCToOther(msg *YMsg.S2S_rpc_msg) {
39 | G_node_obj.PushRpcMsg(msg)
40 | }
41 | func (n *Info) NetToOther(msg *YMsg.C2S_net_msg) {
42 | G_node_obj.PushNetMsg(msg)
43 | }
44 |
45 | func (n *Info) dispatchNet(msg_ *YMsg.C2S_net_msg) bool {
46 | _tar_key_st := msg_.M_tar.GetKeyStr()
47 | _, exists := G_node_obj.M_module_pool[_tar_key_st]
48 | if !exists {
49 | ylog.Erro("[YNode:dispatchNet] miss module uid [%v]", _tar_key_st)
50 | return false
51 | }
52 | G_node_obj.M_module_pool[_tar_key_st].GetInfo().PushNetMsg(msg_)
53 | return true
54 | }
55 |
56 | func (n *Info) dispatchRpc(msg_ *YMsg.S2S_rpc_msg) bool {
57 | _module_name_uid_str := msg_.M_tar.GetKeyStr()
58 | _, exists := G_node_obj.M_module_pool[_module_name_uid_str]
59 | if !exists {
60 | ylog.Erro("[YNode:dispatchRpc] miss module uid [%v][%v]", G_node_obj.M_module_pool,_module_name_uid_str)
61 | return false
62 | }
63 |
64 | //ylog.Info("[Node:%v] dispatch RPC [%v]", G_node_obj.M_module_pool[msg_.M_tar.M_entity_name][msg_.M_tar.M_node_id].GetInfo().M_entity_name, msg_.M_func_name)
65 | G_node_obj.M_module_pool[_module_name_uid_str].GetInfo().PushRpcMsg(msg_)
66 | return true
67 | }
68 |
69 | func (n *Info) close() {
70 | for _, _module_it := range G_node_obj.M_module_pool {
71 | _module_it.Close()
72 | }
73 | }
74 | func (n *Info) startModule(module_ YModule.Inter) {
75 | defer func() {
76 | if err := recover(); err != nil {
77 | ylog.Erro("%v", err)
78 | ylog.Erro("stack:%s", debug.Stack())
79 | }
80 | }()
81 |
82 | _100_last_print_time := time.Now().Unix()
83 | _10_last_print_time := time.Now().Unix()
84 | _1_last_print_time := time.Now().Unix()
85 | _100_fps_count := 0
86 | _10_fps_count := 0
87 | _1_fps_count := 0
88 |
89 | ///////////
90 |
91 | _100_fps_timer := time.NewTicker(time.Millisecond * 10)
92 | defer _100_fps_timer.Stop()
93 | _10_fps_timer := time.NewTicker(time.Millisecond * 100)
94 | defer _10_fps_timer.Stop()
95 | _1_fps_timer := time.NewTicker(time.Millisecond * 1000)
96 | defer _10_fps_timer.Stop()
97 | for {
98 | select {
99 | case _time := <-_100_fps_timer.C:
100 | _100_fps_count++
101 | module_.Loop_100(_time)
102 | module_.GetInfo().Loop_Msg()
103 | if (_time.Unix() - _100_last_print_time) >= 60 {
104 | _second_fps := _100_fps_count / int(_time.Unix()-_100_last_print_time)
105 | if _second_fps < 80 {
106 | ylog.Erro("[Module:%v] 100 fps [%v]", module_.GetInfo().GetAgent().DebugString(), _100_fps_count/int(_time.Unix()-_100_last_print_time))
107 | }
108 | _100_last_print_time = _time.Unix()
109 | _100_fps_count = 0
110 | }
111 | case _time := <-_10_fps_timer.C:
112 | _10_fps_count++
113 | module_.Loop_10(_time)
114 | if (_time.Unix() - _10_last_print_time) >= 60 {
115 | _second_fps := _10_fps_count / int(_time.Unix()-_10_last_print_time)
116 | if _second_fps < 8 {
117 | ylog.Info("[Module:%v] 10 fps [%v]", module_.GetInfo().GetAgent().DebugString(), _10_fps_count/int(_time.Unix()-_10_last_print_time))
118 | }
119 |
120 | _10_last_print_time = _time.Unix()
121 | _10_fps_count = 0
122 | }
123 | case _time := <-_1_fps_timer.C:
124 | _1_fps_count++
125 | module_.Loop_1(_time)
126 | if (_time.Unix() - _1_last_print_time) >= 60 {
127 | _second_fps := _1_fps_count / int(_time.Unix()-_1_last_print_time)
128 | if _second_fps < 1 {
129 | ylog.Info("[Module:%v] 10 fps [%v]", module_.GetInfo().GetAgent().DebugString(), _1_fps_count/int(_time.Unix()-_1_last_print_time))
130 | }
131 |
132 | _1_last_print_time = _time.Unix()
133 | _1_fps_count = 0
134 | }
135 | }
136 |
137 | }
138 | }
139 | func (n *Info) start() {
140 | for _, _module_it := range G_node_obj.M_module_pool {
141 | go n.startModule(_module_it)
142 | }
143 | //主逻辑
144 | G_node_obj.register(G_node_obj)
145 | G_node_obj.GetInfo().Init(G_node_obj)
146 | n.loop()
147 | }
148 |
149 | func (n *Info) loop() {
150 | for {
151 | select {
152 | case <-g_stop:
153 | return
154 | default:
155 |
156 | if G_node_obj.M_net_queue.Len() > 0 {
157 | for {
158 | if G_node_obj.M_net_queue.Len() == 0 {
159 | break
160 | }
161 | _msg := G_node_obj.M_net_queue.Pop().(*YMsg.C2S_net_msg)
162 | if _msg.M_tar.M_module_name == "YNode" {
163 | n.DonNetMsg(_msg)
164 | continue
165 | }
166 | if n.dispatchNet(_msg) {
167 | continue
168 | }
169 | }
170 | }
171 |
172 | if G_node_obj.M_rpc_queue.Len() > 0 {
173 | for {
174 | if G_node_obj.M_rpc_queue.Len() == 0 {
175 | break
176 | }
177 | //ylog.Info("[Node:RPC_QUEUE] [%v]", G_node_obj.M_rpc_queue.Len())
178 | _msg := G_node_obj.M_rpc_queue.Pop().(*YMsg.S2S_rpc_msg)
179 | if _msg.M_tar.M_module_name == "YNode" {
180 | n.DoRPCMsg(_msg)
181 | continue
182 | }
183 | if n.dispatchRpc(_msg) {
184 | continue
185 | }
186 | G_node_obj.Info.SendNetMsgJson(n.findNode(_msg.M_tar.GetKeyStr()), *_msg)
187 | }
188 | }
189 | }
190 | }
191 | }
192 |
193 | func Register(info_list_ ...YModule.Inter) {
194 | for _, _it := range info_list_ {
195 | G_node_obj.register(_it)
196 | }
197 | }
198 |
199 | func RPCCall(msg_ *YMsg.S2S_rpc_msg) {
200 |
201 | G_node_obj.RPCToOther(msg_)
202 | }
203 |
204 | func Obj() *Info {
205 | return G_node_obj
206 | }
207 |
208 | func Close() {
209 | G_node_obj.close()
210 | }
211 |
212 | func Start() {
213 | G_node_obj.start()
214 | }
215 |
216 | func ModuleCreateFuncRegister(name_ string, func_ func(node_ *Info, uid uint64) YModule.Inter) {
217 | G_node_obj.registerToFactory(name_, func_)
218 | }
219 |
220 | func (n *Info) registerToFactory(name_ string, func_ func(node_ *Info, uid uint64) YModule.Inter) {
221 | n.m_moduele_factory[name_] = func_
222 | }
223 |
224 | func RegisterNodeIpStr2NodeId(ip_port_ string, node_id_ uint32) {
225 | G_node_obj.M_node_ip_to_id[ip_port_] = node_id_
226 | }
227 |
228 | func SetNodeID(node_id_ uint32) {
229 | G_node_obj.M_node_id = node_id_
230 | G_node_obj.GetInfo().M_agent = YMsg.ToAgent("YNode", uint64(0))
231 | }
232 |
233 | func NewModuleInfo(module_str_ string, module_uid_ uint64) YModule.Inter {
234 | _new_module := G_node_obj.m_moduele_factory[module_str_](G_node_obj, module_uid_)
235 | _new_module.GetInfo().M_agent = YMsg.ToAgent(strings.Split(reflect.TypeOf(_new_module).Elem().String(), ".")[0], module_uid_)
236 | return _new_module
237 | }
238 |
--------------------------------------------------------------------------------
/engine/YPathFinding/GoAStarManager.go:
--------------------------------------------------------------------------------
1 | package YPathFinding
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YTool"
6 | )
7 |
8 | type aStarCallbackMsg struct {
9 | m_uid uint32
10 | m_st int
11 | m_ed int
12 | m_search_path []int
13 | }
14 |
15 | func NewAStarCallbackMsg() *aStarCallbackMsg {
16 | return &aStarCallbackMsg{}
17 | }
18 |
19 | func (a *aStarCallbackMsg) Init(uid_ uint32, st_, ed_ int, search_path_ []int) {
20 | a.m_uid = uid_
21 | a.m_st = st_
22 | a.m_ed = ed_
23 | a.m_search_path = search_path_
24 | }
25 |
26 | type aStarCallback func([]int)
27 |
28 | type AStarManager struct {
29 | M_map_uid uint64
30 | m_maze [][]float64
31 | m_queue *YTool.SyncQueue
32 |
33 | m_cache_path map[uint64][]int
34 |
35 | m_call_back_idx uint32
36 | m_call_back map[uint32]aStarCallback
37 | }
38 |
39 | func NewAStarManager() *AStarManager {
40 | return &AStarManager{
41 | m_queue: YTool.NewSyncQueue(),
42 | m_call_back: make(map[uint32]aStarCallback),
43 | m_cache_path: make(map[uint64][]int),
44 | }
45 | }
46 |
47 | func (mgr *AStarManager) GetMaze() [][]float64 {
48 | return mgr.m_maze
49 | }
50 |
51 | func (mgr *AStarManager) Init(maze_ [][]float64) {
52 | mgr.m_maze = maze_
53 | }
54 |
55 | func (mgr *AStarManager) IsBlock(index_ int) bool {
56 | _col := index_ / len(mgr.m_maze[0])
57 | _row := index_ % len(mgr.m_maze[0])
58 | if _col < 0 || _col > len(mgr.m_maze)-1 {
59 | return false
60 | }
61 | if _row < 0 || _row > len(mgr.m_maze[0])-1 {
62 | return false
63 | }
64 | return mgr.m_maze[_col][_row] != 0
65 | }
66 |
67 | func (mgr *AStarManager) Search(st_, ed_ int, cb_ aStarCallback) {
68 | ylog.Info("[%v:%v]", st_, ed_)
69 | /* _cache_path, exists := mgr.m_cache_path[uint64(st_)<<32|uint64(ed_)]
70 | if exists {
71 | cb_(_cache_path)
72 | return append(_final_path, before_path_[_loop_idx])
73 | }*/
74 |
75 | _tmp_idx := mgr.m_call_back_idx
76 | mgr.m_call_back_idx++
77 | mgr.m_call_back[_tmp_idx] = cb_
78 | go func() {
79 | _a := NewAStar()
80 | _a.Init(mgr.m_maze)
81 | _ret := _a.SearchBetterWithIndex(st_, ed_)
82 | _msg := NewAStarCallbackMsg()
83 | _msg.Init(_tmp_idx, st_, ed_, _ret)
84 | mgr.m_queue.Add(_msg)
85 | }()
86 | }
87 |
88 | func (mgr *AStarManager) Update() {
89 | for {
90 | if mgr.m_queue.Len() == 0 {
91 | break
92 | }
93 | _msg := mgr.m_queue.Pop().(*aStarCallbackMsg)
94 | mgr.m_call_back[_msg.m_uid](_msg.m_search_path)
95 | /* ylog.Info("###### [%v:%v]", _msg.m_st, _msg.m_ed)
96 | mgr.m_cache_path[uint64(_msg.m_st)<<32|uint64(_msg.m_ed)] = _msg.m_search_path
97 | for _idx, _path_node_it := range _msg.m_search_path {
98 | mgr.m_cache_path[uint64(_path_node_it)<<32|uint64(_msg.m_ed)] = _msg.m_search_path[_idx:]
99 | }
100 | */
101 | delete(mgr.m_call_back, _msg.m_uid)
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/engine/YTimer/Timer.go:
--------------------------------------------------------------------------------
1 | package YTimer
2 |
3 | var time_uid_count uint32 = 0
4 |
5 | type Timer struct {
6 | m_perv *Timer
7 | m_next *Timer
8 | m_uid uint32
9 | M_interval int64
10 | M_call_time int64
11 | M_times int
12 | M_slot uint32
13 | M_callback TimerCallBack
14 | }
15 |
16 | func newTimer() *Timer {
17 | time_uid_count++
18 | return &Timer{
19 | m_uid: time_uid_count,
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/engine/YTimer/TimerAPI.go:
--------------------------------------------------------------------------------
1 | package YTimer
2 |
3 | import "time"
4 |
5 | func TimerCall(t_ *Timer) uint32 {
6 | g_add_timer_channel <- t_
7 | return t_.m_uid
8 | }
9 |
10 | func Close() {
11 | g_close <- struct{}{}
12 | }
13 | func CancelTimer(uid_ uint32) {
14 | g_timer_manager.cancelTimer(uid_)
15 | }
16 |
17 | func convertToTickUnit(t_ YSecond) int64 {
18 | return int64((float64(t_)) * float64(int64(time.Second.Nanoseconds())/int64(TickerTime)))
19 | }
20 |
21 | // *秒后执行
22 | func AfterSecondsCall(after_time_ YSecond, cb_ TimerCallBack) uint32 {
23 | _t := newTimer()
24 | _t.M_callback = cb_
25 | _t.M_call_time = convertToTickUnit(after_time_ + YSecond(time.Now().Unix()))
26 | g_add_timer_channel <- _t
27 | return _t.m_uid
28 | }
29 |
30 | // *秒后执行,每隔*秒执行*次
31 | func AfterSecondsWithIntervalAndLoopTimesCall(after_time_ YSecond, inter_val_ YSecond, loop_times int, cb_ TimerCallBack) uint32 {
32 | _t := newTimer()
33 | _t.M_callback = cb_
34 | _t.M_times = loop_times
35 | _t.M_interval = convertToTickUnit(inter_val_)
36 | _t.M_call_time = convertToTickUnit(after_time_ + YSecond(time.Now().Unix()))
37 | g_add_timer_channel <- _t
38 | return _t.m_uid
39 | }
40 |
41 | // *秒后执行,每隔*秒执行
42 | func AfterSecondsWithIntervalCall(after_time_ YSecond, inter_val_ YSecond, cb_ TimerCallBack) uint32 {
43 | _t := newTimer()
44 | _t.M_callback = cb_
45 | _t.M_times = -1
46 | _t.M_interval = convertToTickUnit(inter_val_)
47 | _t.M_call_time = convertToTickUnit(after_time_ + YSecond(time.Now().Unix()))
48 | g_add_timer_channel <- _t
49 | return _t.m_uid
50 | }
51 |
52 | // 在 * 时执行
53 | func WhenTimeCall(timestamp_ YSecond, cb_ TimerCallBack) uint32 {
54 | _t := newTimer()
55 | _t.M_callback = cb_
56 | _t.M_times = -1
57 | _t.M_call_time = convertToTickUnit(timestamp_)
58 | g_add_timer_channel <- _t
59 | return _t.m_uid
60 | }
61 |
62 | // 在 * 时执行,每隔*秒执行
63 | func WhenTimeWithIntervalCall(timestamp_ YSecond, inter_val_ YSecond, cb_ TimerCallBack) uint32 {
64 | _t := newTimer()
65 | _t.M_callback = cb_
66 | _t.M_times = -1
67 | _t.M_interval = convertToTickUnit(inter_val_)
68 | _t.M_call_time = convertToTickUnit(timestamp_)
69 | g_add_timer_channel <- _t
70 | return _t.m_uid
71 | }
72 |
73 | // 在 * 时执行,每隔*秒执行 *次
74 | func WhenTimeWithIntervalAndLoopTimesCall(timestamp_ YSecond, inter_val_ YSecond, loop_times int, cb_ TimerCallBack) uint32 {
75 | _t := newTimer()
76 | _t.M_callback = cb_
77 | _t.M_times = loop_times
78 | _t.M_interval = convertToTickUnit(inter_val_)
79 | _t.M_call_time = convertToTickUnit(timestamp_)
80 | g_add_timer_channel <- _t
81 | return _t.m_uid
82 | }
83 |
84 | // 每天 * 点执行
85 | func EveryDayCall(timestamp_ YSecond, cb_ TimerCallBack) uint32 {
86 | _t := newTimer()
87 | _t.M_callback = cb_
88 | _t.M_call_time = convertToTickUnit(timestamp_)
89 | g_add_timer_channel <- _t
90 | return _t.m_uid
91 | }
92 |
93 | // 每天 * 点到 *点 间隔*秒执行
94 | func TimeToTimeWithIntervalCall(start_timestamp_ YSecond, end_timestamp_ YSecond, inter_val_ YSecond, cb_ TimerCallBack) uint32 {
95 | _t := newTimer()
96 | _t.M_callback = cb_
97 | _t.M_call_time = convertToTickUnit(start_timestamp_)
98 | _t.M_times = int((end_timestamp_-start_timestamp_) / inter_val_)
99 | _t.M_interval = convertToTickUnit(inter_val_)
100 | g_add_timer_channel <- _t
101 | return _t.m_uid
102 | }
103 | func Loop(_timer_list *ChanTimer) {
104 | g_timer_manager.loop(_timer_list)
105 | }
106 |
107 | func GetTimerSize() uint32 {
108 | return g_timer_manager.getTimerSize()
109 | }
110 |
--------------------------------------------------------------------------------
/engine/YTimer/WheelTimer.go:
--------------------------------------------------------------------------------
1 | package YTimer
2 |
3 | import (
4 | "fmt"
5 | "sync"
6 | "time"
7 | )
8 |
9 | type TimerCallBack func()
10 |
11 | var g_timer_manager timerManagerInter
12 | var g_add_timer_channel = make(chan *Timer, 100)
13 | var g_cancel_timer = make(chan uint32, 100)
14 |
15 | var G_call = make(chan *ChanTimer, 100)
16 |
17 | var g_close = make(chan struct{})
18 |
19 | const (
20 | WheelSlotCount = 3
21 |
22 | TickerTime time.Duration = time.Millisecond*100
23 | )
24 | type YSecond = float64
25 |
26 | type wheelTimer struct {
27 | m_slots []*Timer
28 | m_map map[uint32]*Timer
29 | m_cursor uint32
30 | m_cur_time time.Time
31 | }
32 | type ChanTimer struct {
33 | M_timer_list []*Timer
34 | M_tick_time time.Time
35 | }
36 |
37 | type timerManagerInter interface {
38 | timeCall(t_ *Timer)
39 | getAllCall() *ChanTimer
40 | setTime(t_ time.Time)
41 | getCurTime() *time.Time
42 | cancelTimer(uint32)
43 | close()
44 | getNextCursor() uint32
45 | getSlotSize() uint32
46 | getTimerSize() uint32
47 | loop(*ChanTimer)
48 | }
49 |
50 | func NewWheelTimer(slot_count_ int) {
51 | _wheel_timer := &wheelTimer{
52 | m_slots: make([]*Timer, slot_count_),
53 | m_map: make(map[uint32]*Timer),
54 | }
55 | for _idx := range _wheel_timer.m_slots {
56 | _wheel_timer.m_slots[_idx] = newTimer()
57 | }
58 | g_timer_manager = _wheel_timer
59 | _wg := &sync.WaitGroup{}
60 | _wg.Add(1)
61 | go func() {
62 | g_timer_manager.setTime(time.Now())
63 | ticker := time.Tick(TickerTime)
64 | _wg.Done()
65 | for {
66 | select {
67 | case _time := <-ticker:
68 | g_timer_manager.setTime(_time)
69 |
70 | G_call <- g_timer_manager.getAllCall()
71 | case _timer := <-g_add_timer_channel:
72 | g_timer_manager.timeCall(_timer)
73 | case _cancel_uid := <-g_cancel_timer:
74 | g_timer_manager.cancelTimer(_cancel_uid)
75 | case <-g_close:
76 | return
77 | default:
78 | }
79 | }
80 | }()
81 | _wg.Wait()
82 | }
83 |
84 | func (t *wheelTimer) getSlot(timestamp int64) uint32 {
85 | _diff_tm := timestamp - convertToTickUnit(float64(t.m_cur_time.Unix()))
86 | _future_slot := (int64(_diff_tm) + int64(t.m_cursor)) % int64(t.getSlotSize())
87 | //fmt.Printf("timestamp[%v] t.m_cur_time.Unix() [%v] diff [%v] slot [%v] \n",timestamp,t.m_cur_time.Unix(),_diff_tm,_future_slot)
88 | fmt.Printf("_future_slot [%d] _diff_tm[%v]\n", _future_slot,_diff_tm)
89 | return uint32(_future_slot)
90 | }
91 | func (t *wheelTimer) cancelTimer(t_ uint32) {
92 | _timer, exists := t.m_map[t_]
93 | if !exists {
94 | return
95 | }
96 | if _timer.m_perv != nil {
97 | _timer.m_perv.m_next = _timer.m_next
98 | }
99 | if _timer.m_next != nil {
100 | _timer.m_next.m_perv = _timer.m_perv
101 | }
102 | _timer.m_perv = nil
103 | _timer.m_next = nil
104 | }
105 |
106 | func (t *wheelTimer) setTime(t_ time.Time) {
107 | t.m_cur_time = t_
108 | //fmt.Printf("setTime [%v]\n", t.m_cur_time.Unix())
109 |
110 | }
111 |
112 | func (t *wheelTimer) insertSlot(slot_ uint32, t_ *Timer) {
113 | t.m_map[t_.m_uid] = t_
114 | //fmt.Printf("cur [%v] insertSlot [%v]",t.m_cursor,slot_)
115 | _root := t.m_slots[slot_]
116 | if _root.m_next != nil {
117 | _root.m_next.m_perv = t_
118 | }
119 | t_.m_perv = _root
120 | t_.m_next = _root.m_next
121 | _root.m_next = t_
122 | t_.M_slot = slot_
123 | }
124 |
125 | func (t *wheelTimer) timeCall(t_ *Timer) {
126 | if t_.M_call_time <= convertToTickUnit(float64(t.m_cur_time.Unix())) {
127 | t.insertSlot(t.m_cursor+1, t_)
128 | return
129 | }
130 | t.insertSlot(t.getSlot(t_.M_call_time), t_)
131 | }
132 | func (t *wheelTimer) getSlotSize() uint32 {
133 | return uint32(len(t.m_slots))
134 | }
135 | func (t *wheelTimer) getNextCursor() uint32 {
136 | t.m_cursor++
137 | t.m_cursor %= t.getSlotSize()
138 | //fmt.Printf("t.m_cursor [%v] \n", t.m_cursor)
139 | return t.m_cursor
140 | }
141 |
142 | func (t *wheelTimer) getTimerSize() uint32 {
143 | return uint32(len(t.m_map))
144 | }
145 |
146 | func (t *wheelTimer) close() {
147 | g_close <- struct{}{}
148 | }
149 |
150 | func (t *wheelTimer) getCurTime() *time.Time {
151 | return &t.m_cur_time
152 | }
153 | func (t *wheelTimer) getAllCall() *ChanTimer {
154 | _timer_list := make([]*Timer, 0)
155 | _next_cursor := t.getNextCursor()
156 | _root := t.m_slots[_next_cursor].m_next
157 | _now_time := convertToTickUnit(float64(t.m_cur_time.Unix()))
158 | for _root != nil {
159 | if _root.M_call_time > _now_time {
160 | _root = _root.m_next
161 | continue
162 | }
163 | _append_timer := _root
164 |
165 | _timer_list = append(_timer_list, _append_timer)
166 | delete(t.m_map, _append_timer.m_uid)
167 | if _root.m_perv != nil {
168 | _root.m_perv.m_next = _root.m_next
169 | }
170 | if _root.m_next != nil {
171 | _root.m_next.m_perv = _root.m_perv
172 | }
173 | _append_timer.m_next = nil
174 | _append_timer.m_perv = nil
175 | _root = _root.m_next
176 | }
177 | //t.m_slots[_next_cursor].m_next = _root
178 | return &ChanTimer{
179 | M_timer_list: _timer_list,
180 | M_tick_time: t.m_cur_time,
181 | }
182 | }
183 | func (t *wheelTimer) loop(_timer_list *ChanTimer) {
184 | for _, _it := range _timer_list.M_timer_list {
185 | _it.M_callback()
186 | if _it.M_times == -1 {
187 | _it.M_call_time += _it.M_interval
188 | TimerCall(_it)
189 | continue
190 | } else if _it.M_times > 0 {
191 | _it.M_times--
192 | _it.M_call_time += _it.M_interval
193 | TimerCall(_it)
194 | continue
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/engine/YTimer/timer_test.go:
--------------------------------------------------------------------------------
1 | package YTimer
2 |
3 | import (
4 | "math"
5 | "testing"
6 | "time"
7 | )
8 |
9 | func init() {
10 | NewWheelTimer(WheelSlotCount)
11 | }
12 |
13 | func TestTimerIndexForeach(t_ *testing.T) {
14 | for _idx := 0; _idx < 20; _idx++ {
15 | if g_timer_manager.getNextCursor() != (uint32(_idx+1) % g_timer_manager.getSlotSize()) {
16 | t_.Errorf("[%v]", g_timer_manager.getNextCursor())
17 | }
18 |
19 | }
20 | }
21 | func TimerApiHelp(t_ *testing.T, second_ float64) {
22 | _before_time := time.Now()
23 | _close := make(chan struct{})
24 | AfterSecondsCall(second_, func() {
25 | _diff_time := time.Now().Sub(_before_time)
26 | if math.Abs(_diff_time.Seconds()-second_) > 0.01 {
27 | t_.Errorf("err diff [%v] right diff [%v] _before_time[%v] after_time [%v]", int(_diff_time.Seconds()), second_, _before_time.Unix(), _diff_time.Seconds())
28 | }
29 | t_.Logf("TimerSize [%v]", GetTimerSize())
30 | if GetTimerSize() != 0 {
31 | t_.Errorf("err size [%v]", GetTimerSize())
32 | }
33 |
34 | t_.Logf("diff [%v] right diff [%v] _before_time[%v] after_time [%v]", int(_diff_time.Seconds()), second_, _before_time.Unix(), _diff_time.Seconds())
35 | close(_close)
36 | })
37 | for {
38 | select {
39 | case _t := <-G_call:
40 | Loop(_t)
41 | case <-_close:
42 | return
43 | }
44 | }
45 | }
46 | func TestTimerApi(t_ *testing.T) {
47 | TimerApiHelp(t_, 1)
48 | TimerApiHelp(t_, 1)
49 | TimerApiHelp(t_, 1)
50 | TimerApiHelp(t_, 1)
51 | TimerApiHelp(t_, 1)
52 | TimerApiHelp(t_, 1)
53 | TimerApiHelp(t_, 1)
54 | TimerApiHelp(t_, 1)
55 | TimerApiHelp(t_, 1)
56 | }
57 |
--------------------------------------------------------------------------------
/engine/YTool/DebugPrint.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YJson"
5 | ylog "github.com/yxinyi/YCServer/engine/YLog"
6 | )
7 |
8 | func JsonPrint(args_ ...interface{}) {
9 | for _, _arg_it := range args_ {
10 | ylog.Info("\n%s", YJson.GetPrintStr(_arg_it))
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/engine/YTool/position.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "fmt"
5 | "math"
6 | )
7 |
8 | type PositionXY struct {
9 | M_x float64
10 | M_y float64
11 | }
12 |
13 | func NewPositionXY() *PositionXY {
14 | return &PositionXY{}
15 | }
16 | func ClonePositionXY(src_ *PositionXY) *PositionXY {
17 | return &PositionXY{
18 | M_x: src_.M_x,
19 | M_y: src_.M_y,
20 | }
21 | }
22 |
23 | func (xy PositionXY) DebugString() string {
24 | return fmt.Sprintf("M_x:%02f,M_y:%02f", xy.M_x, xy.M_y)
25 | }
26 |
27 | func (xy *PositionXY) GetOffset(rhs PositionXY) *PositionXY {
28 | offset := NewPositionXY()
29 | offset.M_x = rhs.M_x - xy.M_x
30 | offset.M_y = rhs.M_y - xy.M_y
31 | return offset
32 | }
33 |
34 | func (xy *PositionXY) Distance(rhs *PositionXY) float64 {
35 |
36 | xMinusAbs := math.Abs(xy.M_x - rhs.M_x)
37 | yMinusAbs := math.Abs(xy.M_y - rhs.M_y)
38 |
39 | distance := math.Sqrt(xMinusAbs*xMinusAbs + yMinusAbs*yMinusAbs)
40 |
41 | return distance
42 | }
43 |
44 | const PositionXYMIN = 0.001
45 |
46 | func (xy *PositionXY) IsEqual(rhs *PositionXY) bool {
47 | if xy.M_x > rhs.M_x {
48 | if xy.M_x-rhs.M_x > PositionXYMIN {
49 | return false
50 | }
51 | } else {
52 | if rhs.M_x-xy.M_x > PositionXYMIN {
53 | return false
54 | }
55 | }
56 | if xy.M_y > rhs.M_y {
57 | if xy.M_y-rhs.M_y > PositionXYMIN {
58 | return false
59 | }
60 | } else {
61 | if rhs.M_y-xy.M_y > PositionXYMIN {
62 | return false
63 | }
64 | }
65 | return true
66 | }
67 |
68 | func (p *PositionXY) IsSame(rhs_ PositionXY) bool {
69 | if math.Abs(p.M_x-rhs_.M_x) > 0.0001 {
70 | return false
71 | }
72 | if math.Abs(p.M_y-rhs_.M_y) > 0.0001 {
73 | return false
74 | }
75 | return true
76 | }
77 |
78 | func (xy *PositionXY) Offset(offsetPoint *PositionXY) {
79 | xy.M_x += offsetPoint.M_x
80 | xy.M_y += offsetPoint.M_y
81 | }
82 |
83 | func (xy *PositionXY) Clear() {
84 | xy.M_y = 0
85 | xy.M_x = 0
86 | }
87 | func (xy *PositionXY) Clone() *PositionXY {
88 | pos := NewPositionXY()
89 | pos.M_x = xy.M_x
90 | pos.M_y = xy.M_y
91 | return pos
92 | }
93 | func (xy *PositionXY) CopyOther(rhs *PositionXY) {
94 | xy.M_y = rhs.M_y
95 | xy.M_x = rhs.M_x
96 | }
97 |
--------------------------------------------------------------------------------
/engine/YTool/queue.go:
--------------------------------------------------------------------------------
1 | /*
2 | Package queue provides a fast, ring-buffer queue based on the version suggested by Dariusz Górecki.
3 | Using this instead of other, simpler, queue implementations (slice+append or linked list) provides
4 | substantial memory and time benefits, and fewer GC pauses.
5 |
6 | The queue implemented here is as fast as it is for an additional reason: it is *not* thread-safe.
7 | */
8 | package YTool
9 |
10 | // minQueueLen is smallest capacity that queue may have.
11 | // Must be power of 2 for bitwise modulus: x % n == x & (n - 1).
12 | const minQueueLen = 16
13 |
14 | // Queue represents a single instance of the queue data structure.
15 | type Queue struct {
16 | buf []interface{}
17 | head, tail, count int
18 | }
19 |
20 | // New constructs and returns a new Queue.
21 | func NewQueue() *Queue {
22 | return &Queue{
23 | buf: make([]interface{}, minQueueLen),
24 | }
25 | }
26 |
27 | // Length returns the number of elements currently stored in the queue.
28 | func (q *Queue) Length() int {
29 | return q.count
30 | }
31 |
32 | // resizes the queue to fit exactly twice its current contents
33 | // this can result in shrinking if the queue is less than half-full
34 | func (q *Queue) resize() {
35 | newBuf := make([]interface{}, q.count<<1)
36 |
37 | if q.tail > q.head {
38 | copy(newBuf, q.buf[q.head:q.tail])
39 | } else {
40 | n := copy(newBuf, q.buf[q.head:])
41 | copy(newBuf[n:], q.buf[:q.tail])
42 | }
43 |
44 | q.head = 0
45 | q.tail = q.count
46 | q.buf = newBuf
47 | }
48 |
49 | // Add puts an element on the end of the queue.
50 | func (q *Queue) Add(elem interface{}) {
51 | if q.count == len(q.buf) {
52 | q.resize()
53 | }
54 |
55 | q.buf[q.tail] = elem
56 | // bitwise modulus
57 | q.tail = (q.tail + 1) & (len(q.buf) - 1)
58 | q.count++
59 | }
60 |
61 | // Peek returns the element at the head of the queue. This call panics
62 | // if the queue is empty.
63 | func (q *Queue) Peek() interface{} {
64 | if q.count <= 0 {
65 | return nil
66 | }
67 |
68 | return q.buf[q.head]
69 | }
70 |
71 | // Get returns the element at index i in the queue. If the index is
72 | // invalid, the call will panic. This method accepts both positive and
73 | // negative index values. Index 0 refers to the first element, and
74 | // index -1 refers to the last.
75 | func (q *Queue) Get(i int) interface{} {
76 | // If indexing backwards, convert to positive index.
77 | if i < 0 {
78 | i += q.count
79 | }
80 | if i < 0 || i >= q.count {
81 | return nil
82 | }
83 | // bitwise modulus
84 | return q.buf[(q.head+i)&(len(q.buf)-1)]
85 | }
86 |
87 | // Remove removes and returns the element from the front of the queue. If the
88 | // queue is empty, the call will panic.
89 | func (q *Queue) Pop() interface{} {
90 | if q.count <= 0 {
91 | return nil
92 | }
93 |
94 | ret := q.buf[q.head]
95 | q.buf[q.head] = nil
96 | // bitwise modulus
97 | q.head = (q.head + 1) & (len(q.buf) - 1)
98 | q.count--
99 | // Resize down if buffer 1/4 full.
100 | if len(q.buf) > minQueueLen && (q.count<<2) == len(q.buf) {
101 | q.resize()
102 | }
103 | return ret
104 | }
105 |
--------------------------------------------------------------------------------
/engine/YTool/reactangle.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | )
6 |
7 | type Rectangle struct {
8 | LeftUp *PositionXY
9 | LeftDown *PositionXY
10 | RightUp *PositionXY
11 | RightDown *PositionXY
12 | }
13 |
14 | func NewRectangle() *Rectangle {
15 | return &Rectangle{
16 | LeftUp: NewPositionXY(),
17 | LeftDown: NewPositionXY(),
18 | RightUp: NewPositionXY(),
19 | RightDown: NewPositionXY(),
20 | }
21 | }
22 |
23 | func (rec *Rectangle) InitForLefDownRightUP(leftDown *PositionXY, rightUp *PositionXY) {
24 | rec.LeftUp.M_x = leftDown.M_x
25 | rec.LeftUp.M_y = rightUp.M_y
26 | rec.LeftDown.CopyOther(leftDown)
27 | rec.RightDown.M_y = leftDown.M_y
28 | rec.RightDown.M_x = rightUp.M_x
29 | rec.RightUp.CopyOther(rightUp)
30 | }
31 | func (rec *Rectangle) InitForLefUPRightDown(leftUp *PositionXY, rightDown *PositionXY) {
32 | rec.LeftUp.CopyOther(leftUp)
33 |
34 | rec.LeftDown.M_x = leftUp.M_x
35 | rec.LeftDown.M_y = rightDown.M_y
36 | rec.RightDown.CopyOther(rightDown)
37 |
38 | rec.RightUp.M_y = leftUp.M_y
39 | rec.RightUp.M_x = rightDown.M_x
40 | }
41 |
42 | func (rec *Rectangle) DeBugString() string {
43 | byte, err := jsoniter.Marshal(rec)
44 | if err != nil {
45 | return ""
46 | }
47 | return string(byte)
48 | }
49 |
50 | func (rec *Rectangle) Clone() *Rectangle {
51 | return &Rectangle{
52 | LeftUp: rec.LeftUp.Clone(),
53 | LeftDown: rec.LeftDown.Clone(),
54 | RightUp: rec.RightUp.Clone(),
55 | RightDown: rec.RightDown.Clone(),
56 | }
57 | }
58 |
59 | func (rec *Rectangle) CopyOther(rhs *Rectangle) {
60 | rec.LeftUp.CopyOther(rhs.LeftUp)
61 | rec.LeftDown.CopyOther(rhs.LeftDown)
62 | rec.RightUp.CopyOther(rhs.RightUp)
63 | rec.RightDown.CopyOther(rhs.RightDown)
64 | }
65 |
66 | func (rec *Rectangle) Offset(offsetPoint *PositionXY) {
67 | rec.LeftUp.Offset(offsetPoint)
68 | rec.LeftDown.Offset(offsetPoint)
69 | rec.RightUp.Offset(offsetPoint)
70 | rec.RightDown.Offset(offsetPoint)
71 | }
72 |
73 | //叉乘
74 | func (rec *Rectangle) GetCross(recPoint1 *PositionXY, recPoint2 *PositionXY, checkPoint *PositionXY) float64 {
75 | return ((recPoint2.M_x - recPoint1.M_x) * (checkPoint.M_y - recPoint1.M_y)) - ((checkPoint.M_x - recPoint1.M_x) * (recPoint2.M_y - recPoint1.M_y))
76 | }
77 | func (rec *Rectangle) IsInsidePoint(checkPoint *PositionXY) bool {
78 | //如果是一个点就不检查碰撞
79 | if rec.LeftUp.M_y == rec.LeftDown.M_y {
80 | return false
81 | }
82 | return (rec.GetCross(rec.LeftUp, rec.LeftDown, checkPoint)*rec.GetCross(rec.RightDown, rec.RightUp, checkPoint) >= 0) && (rec.GetCross(rec.LeftDown, rec.RightDown, checkPoint)*rec.GetCross(rec.RightUp, rec.LeftUp, checkPoint) >= 0)
83 | }
84 |
--------------------------------------------------------------------------------
/engine/YTool/syncqueue.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import "sync"
4 |
5 | type SyncQueue struct {
6 | que *Queue
7 | mutex sync.RWMutex
8 | }
9 |
10 | func (q *SyncQueue) Len() int {
11 | q.mutex.RLock()
12 | defer q.mutex.RUnlock()
13 |
14 | return q.que.Length()
15 | }
16 |
17 | func (q *SyncQueue) Add(elem interface{}) {
18 | q.mutex.Lock()
19 | defer q.mutex.Unlock()
20 |
21 | q.que.Add(elem)
22 | }
23 |
24 | func (q *SyncQueue) Peek() interface{} {
25 | q.mutex.RLock()
26 | defer q.mutex.RUnlock()
27 |
28 | return q.que.Peek()
29 | }
30 |
31 | func (q *SyncQueue) Get(i int) interface{} {
32 | q.mutex.RLock()
33 | defer q.mutex.RUnlock()
34 |
35 | return q.que.Get(i)
36 | }
37 |
38 | func (q *SyncQueue) Pop() interface{} {
39 |
40 | q.mutex.Lock()
41 | defer q.mutex.Unlock()
42 |
43 | return q.que.Pop()
44 | }
45 |
46 | func (q *SyncQueue) RLockRange(f func(interface{})) {
47 | q.mutex.RLock()
48 | defer q.mutex.RUnlock()
49 |
50 | for i := 0; i < q.que.Length(); i++ {
51 | f(q.Get(i))
52 | }
53 | }
54 |
55 | func NewSyncQueue() *SyncQueue {
56 | syncQueue := SyncQueue{}
57 | syncQueue.que = NewQueue()
58 |
59 | return &syncQueue
60 | }
61 |
--------------------------------------------------------------------------------
/engine/YTool/timeter.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "time"
5 | )
6 |
7 | type TimerMeterInfo struct {
8 | Name string
9 | Timer int64
10 | }
11 |
12 | type TimerMeter struct {
13 | timerInfoPool map[string]int
14 | timerPool map[int]*TimerMeterInfo
15 | }
16 |
17 | func NewTimerMeter() *TimerMeter {
18 | return &TimerMeter{
19 | timerInfoPool: make(map[string]int),
20 | timerPool: make(map[int]*TimerMeterInfo),
21 | }
22 | }
23 | func (t *TimerMeter) Start(name string) {
24 | timer := &TimerMeterInfo{
25 | Name: name,
26 | Timer: time.Now().UnixNano(),
27 | }
28 | _, exists := t.timerInfoPool[name]
29 | if exists {
30 | t.timerPool[t.timerInfoPool[name]] = timer
31 | } else {
32 | idx := len(t.timerPool)
33 | t.timerInfoPool[name] = idx
34 | t.timerPool[idx] = timer
35 | }
36 | }
37 |
38 | func (t *TimerMeter) End(name string) {
39 | idx, exists := t.timerInfoPool[name]
40 | if !exists {
41 | return
42 | }
43 | delete(t.timerInfoPool, name)
44 | t.timerPool[idx].Timer = time.Now().UnixNano() - t.timerPool[idx].Timer
45 | }
46 |
47 | /*func (t *TimerMeter) Print(name string) {
48 | idx, exists := t.timerInfoPool[name]
49 | if !exists {
50 | return
51 | }
52 |
53 | l4g.Info("[TimerMeter] name [%v] time [%04f]", name, t.timerPool[idx].Timer/int64(time.Millisecond))
54 | }
55 |
56 | func (t *TimerMeter) PrintAll() {
57 | meterList := make([]*TimerMeterInfo, 0)
58 | for idx := 0; idx < len(t.timerPool); idx++ {
59 | meterList = append(meterList, t.timerPool[idx])
60 | //l4g.Info("[TimerMeter] name [%v] time [%04f]", t.timerPool[idx].Name, float64(t.timerPool[idx].Timer/int64(time.Millisecond))/float64(1000))
61 | }
62 | sort.Slice(meterList, func(lhs int, rhs int) bool {
63 | return meterList[lhs].Timer > meterList[rhs].Timer
64 | })
65 |
66 | for _, it := range meterList {
67 | l4g.Info("[TimerMeter] name [%v] time [%04f]", it.Name, float64(it.Timer/int64(time.Millisecond))/float64(1000))
68 | }
69 | }*/
--------------------------------------------------------------------------------
/engine/YTool/tool.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "math"
5 | "reflect"
6 | "sort"
7 | )
8 |
9 | func Uint32SetConvertToSortSlice(set_ map[uint32]struct{}) []uint32 {
10 | _ret_slice := make([]uint32, 0, len(set_))
11 | for _it := range set_ {
12 | _ret_slice = append(_ret_slice, _it)
13 | }
14 | sort.Slice(_ret_slice, func(i_, j_ int) bool {
15 | return _ret_slice[i_] < _ret_slice[j_]
16 | })
17 | return _ret_slice
18 | }
19 |
20 | func Uint64SetClone(set_ map[uint64]struct{}) map[uint64]struct{} {
21 | _ret_set := make(map[uint64]struct{})
22 | for _it := range set_ {
23 | _ret_set[_it] = struct{}{}
24 | }
25 | return _ret_set
26 | }
27 |
28 | func Uint64SetMerge(lhs_ map[uint64]struct{}, rhs_ map[uint64]struct{}) map[uint64]struct{} {
29 | for _it := range rhs_ {
30 | lhs_[_it] = struct{}{}
31 | }
32 | return lhs_
33 | }
34 |
35 | func Uint64MapUint64SetMerge(lhs_ map[uint64]map[uint64]struct{}, rhs_ map[uint64]map[uint64]struct{}) map[uint64]map[uint64]struct{} {
36 | for _key, _set_it := range rhs_ {
37 | _, exists := lhs_[_key]
38 | if !exists {
39 | lhs_[_key] = make(map[uint64]struct{})
40 | }
41 | lhs_[_key] = Uint64SetMerge(lhs_[_key], _set_it)
42 | }
43 | return lhs_
44 | }
45 |
46 | func Float64Equal(check_num_, target_ float64) bool {
47 | if math.Abs(check_num_-target_) < 0.00001 {
48 | return true
49 | }
50 | return false
51 | }
52 |
53 |
54 | func GetFuncInTypeList(func_ reflect.Value)[]reflect.Type{
55 | ret_list := make([]reflect.Type, 0)
56 | for _idx := 0; _idx < func_.Type().NumIn(); _idx++ {
57 | ret_list = append(ret_list, func_.Type().In(_idx))
58 | }
59 | return ret_list
60 | }
61 |
62 | func GetSetUint32Diff(lhs_ map[uint32]struct{}, rhs_ map[uint32]struct{}) map[uint32]struct{} {
63 | _ret_set := make(map[uint32]struct{})
64 | for _it := range lhs_{
65 | _ret_set[_it] = struct{}{}
66 | }
67 | for _it := range rhs_ {
68 | delete(_ret_set, _it)
69 | }
70 | return _ret_set
71 | }
72 | func GetSetUint64Diff(lhs_ map[uint64]struct{}, rhs_ map[uint64]struct{}) map[uint64]struct{} {
73 | _ret_set := make(map[uint64]struct{})
74 | for _it := range lhs_{
75 | _ret_set[_it] = struct{}{}
76 | }
77 | for _it := range rhs_ {
78 | delete(_ret_set, _it)
79 | }
80 | return _ret_set
81 | }
--------------------------------------------------------------------------------
/engine/YTool/tools_test.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "testing"
5 | )
6 |
7 |
8 | func TestUint64SetMerge(t_ *testing.T) {
9 | _lhs := map[uint64]struct{}{0: {},1:{},2:{},3:{}}
10 | _rhs := map[uint64]struct{}{3: {},4:{},5:{},6:{}}
11 |
12 | _final := Uint64SetMerge(_lhs,_rhs)
13 | t_.Logf("_lhs[%v]",_lhs)
14 | t_.Logf("_rhs[%v]",_rhs)
15 | t_.Logf("_final[%v]",_final)
16 | }
17 |
--------------------------------------------------------------------------------
/engine/YTool/uidFactory.go:
--------------------------------------------------------------------------------
1 | package YTool
2 |
3 | import (
4 | "math/rand"
5 | "time"
6 | )
7 |
8 | func init() {
9 | rand.Seed(time.Now().Unix())
10 | }
11 |
12 | func BuildUIDUint64()uint64{
13 | return rand.Uint64()
14 | }
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Client/Client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/hajimehoshi/ebiten/v2"
6 | "github.com/yxinyi/YCServer/engine/YNet"
7 | "github.com/yxinyi/YCServer/engine/YTool"
8 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
9 | "log"
10 | )
11 |
12 | var g_client_cnn = YNet.NewConnect()
13 | var g_sync_queue = YTool.NewSyncQueue()
14 |
15 | func main() {
16 | fmt.Println("Client start")
17 | g_client_cnn.Connect("127.0.0.1:20000")
18 | g_client_cnn.Start()
19 | g_client_cnn.SendJson(Msg.C2S_Login{})
20 | g_client_cnn.SendJson(Msg.C2S_FirstEnterMap{})
21 | game, err := NewMainGame()
22 | if err != nil {
23 | log.Fatal(err.Error())
24 | }
25 | ebiten.SetWindowSize(ScreenWidth, ScreenHeight)
26 | ebiten.SetWindowTitle("mmo aoi test")
27 | if err := ebiten.RunGame(game); err != nil {
28 | log.Fatal(err.Error())
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Client/Game.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/hajimehoshi/ebiten/v2"
5 | "github.com/yxinyi/YCServer/engine/YNet"
6 | "image/color"
7 | "math/rand"
8 | "time"
9 | )
10 |
11 | func init() {
12 | rand.Seed(time.Now().UnixNano())
13 | g_map.Init()
14 | }
15 |
16 | // Game represents a game state.
17 | type Game struct {
18 | }
19 |
20 | // NewGame generates a new Game object.
21 | func NewMainGame() (*Game, error) {
22 | g := &Game{
23 | }
24 | var err error
25 | if err != nil {
26 | return nil, err
27 | }
28 | return g, nil
29 | }
30 |
31 | // Layout implements ebiten.Game's Layout.
32 | func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
33 | return ScreenWidth, ScreenHeight
34 | }
35 |
36 | // Update updates the current game state.
37 | func (g *Game) Update() error {
38 |
39 | for more := true; more; {
40 | select {
41 | case _net_msg := <-YNet.G_net_msg_chan:
42 | YNet.Dispatch(_net_msg.M_session, _net_msg.M_net_msg)
43 | default:
44 | more = false
45 | }
46 | }
47 | g_map.Update()
48 | return nil
49 | }
50 |
51 | // Draw draws the current game to the given screen.
52 | func (g *Game) Draw(screen *ebiten.Image) {
53 | screen.Fill(color.NRGBA{0x00, 0x40, 0x80, 0xff})
54 | g_map.Draw(screen)
55 | }
56 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Client/Map.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/hajimehoshi/ebiten/v2"
6 | "github.com/hajimehoshi/ebiten/v2/ebitenutil"
7 | "github.com/hajimehoshi/ebiten/v2/inpututil"
8 | "github.com/yxinyi/YCServer/engine/YNet"
9 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
10 | "golang.org/x/image/font"
11 | "golang.org/x/image/font/gofont/goregular"
12 | "golang.org/x/image/font/opentype"
13 | "image/color"
14 | "log"
15 | "math"
16 | )
17 |
18 | const (
19 | ScreenWidth = 1280
20 | ScreenHeight = 720
21 | gridSize = 10
22 | userGridSize = 5
23 | )
24 |
25 | var g_center_pos = Msg.PositionXY{float64(ScreenWidth / 2), float64(ScreenHeight / 2)}
26 |
27 | var uiFont font.Face
28 |
29 | type Map struct {
30 | m_user_list map[uint64]Msg.UserData
31 | }
32 |
33 | func NewMap() *Map {
34 | return &Map{
35 | m_user_list: make(map[uint64]Msg.UserData),
36 | }
37 | }
38 |
39 | var g_map = NewMap()
40 | var g_main_uid uint64
41 | var g_main_path_node []Msg.PositionXY
42 | var g_main_check_node []Msg.PositionXY
43 | var g_map_maze_info Msg.S2C_FirstEnterMap
44 |
45 | func (m *Map) Init() {
46 | tt, err := opentype.Parse(goregular.TTF)
47 | if err != nil {
48 | log.Fatal(err.Error())
49 | }
50 | uiFont, _ = opentype.NewFace(tt, &opentype.FaceOptions{
51 | Size: 12,
52 | DPI: 72,
53 | Hinting: font.HintingFull,
54 | })
55 | ebiten.SetMaxTPS(30)
56 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_FirstEnterMap) {
57 | g_map_maze_info = msg_
58 | m.UpdateUser(msg_.M_data)
59 | })
60 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_Login) {
61 | g_main_uid = msg_.M_data.M_uid
62 | m.AddNewUser(msg_.M_data)
63 | })
64 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_MapAStarNodeUpdate) {
65 | g_main_path_node = msg_.M_path
66 | })
67 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2CMapAddUser) {
68 | for _, _it := range msg_.M_user {
69 | m.AddNewUser(_it)
70 | }
71 |
72 | })
73 | /* _msg_count := int32(0)
74 | go func() {
75 | _ticker := time.NewTicker(time.Second)
76 | for {
77 | select {
78 | case <-_ticker.C:
79 | fmt.Printf("msg count [%v]\n", atomic.LoadInt32(&_msg_count))
80 | atomic.StoreInt32(&_msg_count, 0)
81 | }
82 | }
83 |
84 | }()*/
85 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2CMapUpdateUser) {
86 | //atomic.AddInt32(&_msg_count, 1)
87 | for _, _it := range msg_.M_user {
88 | m.UpdateUser(_it)
89 | }
90 | })
91 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2CMapDeleteUser, ) {
92 | for _, _it := range msg_.M_user {
93 | m.DeleteUser(_it.M_uid)
94 | }
95 | })
96 |
97 | /* YNet.Register(Msg.MsgID_S2CUserMove, m.UserMove)
98 | YNet.Register(Msg.MSG_S2C_MAP_FULL_SYNC, func(msg_ Msg.S2CMapFullSync, _ YNet.Session) {
99 | for _, _it := range msg_.M_user {
100 | m.AddNewUser(_it)
101 | }
102 | })
103 | YNet.Register(Msg.MSG_S2C_MAP_ADD_USER, func(msg_ Msg.S2CMapAddUser, _ YNet.Session) {
104 | for _, _it := range msg_.M_user {
105 | m.AddNewUser(_it)
106 | }
107 |
108 | })
109 | YNet.Register(Msg.MSG_S2C_MAP_UPDATE_USER, func(msg_ Msg.S2CMapUpdateUser, _ YNet.Session) {
110 | for _, _it := range msg_.M_user {
111 | m.UpdateUser(_it)
112 | }
113 | })
114 | YNet.Register(Msg.MSG_S2C_MAP_DELETE_USER, func(msg_ Msg.S2CMapDeleteUser, _ YNet.Session) {
115 | for _, _it := range msg_.M_user {
116 | m.DeleteUser(_it.M_module_uid)
117 | }
118 | })
119 | YNet.Register(Msg.MsgID_S2CUserSuccessLogin, func(msg_ Msg.S2CUserSuccessLogin, _ YNet.Session) {
120 | g_main_uid = msg_.M_defalut_value.M_module_uid
121 | m.AddNewUser(msg_.M_defalut_value)
122 | })
123 | YNet.Register(Msg.MSG_S2C_MAP_ASTAR_NODE_UPDATE, func(msg_ Msg.S2C_MapAStarNodeUpdate, _ YNet.Session) {
124 | g_main_path_node = msg_.M_path
125 | })
126 | YNet.Register(Msg.MSG_S2C_MAP_FLUSH_MAP_MAZE, func(msg_ Msg.S2CFlushMapMaze, _ YNet.Session) {
127 | g_map_maze_info = msg_
128 | })*/
129 | }
130 | func (m *Map) DeleteUser(uid_ uint64) {
131 | delete(m.m_user_list, uid_)
132 | }
133 |
134 | func (m *Map) AddNewUser(user_data_ Msg.UserData) {
135 | m.m_user_list[user_data_.M_uid] = user_data_
136 | }
137 |
138 | var g_slope string
139 |
140 | func (m *Map) UpdateUser(user_data_ Msg.UserData) {
141 |
142 | if g_main_uid == user_data_.M_uid {
143 | g_slope = fmt.Sprintf("%.2f", (user_data_.M_pos.M_y-m.m_user_list[user_data_.M_uid].M_pos.M_y)/(user_data_.M_pos.M_x-m.m_user_list[user_data_.M_uid].M_pos.M_x))
144 | }
145 | m.m_user_list[user_data_.M_uid] = user_data_
146 | }
147 |
148 | func (m *Map) UserMove(msg_ Msg.S2C_MOVE, _ YNet.Session) {
149 | m.m_user_list[msg_.M_uid] = msg_.M_data
150 | }
151 |
152 | func (m *Map) MainPos() Msg.PositionXY {
153 | return m.m_user_list[g_main_uid].M_pos
154 | }
155 |
156 | func (m *Map) Update() {
157 | if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
158 | _tar_x, _tar_y := ebiten.CursorPosition()
159 | _x_diff := float64(_tar_x) - g_center_pos.M_x
160 | _y_diff := float64(_tar_y) - g_center_pos.M_y
161 |
162 | //_touch_pos := m.PosConvert(Msg.PositionXY{ float64(_tar_x), float64(_tar_y)})
163 | g_client_cnn.SendJson(Msg.C2S_UserMove{
164 | Msg.PositionXY{
165 | m.MainPos().M_x + _x_diff,
166 | m.MainPos().M_y + _y_diff,
167 | },
168 | })
169 | }
170 |
171 | if inpututil.IsKeyJustPressed(ebiten.KeyT) {
172 | switch ebiten.MaxTPS() {
173 | case 30:
174 | ebiten.SetMaxTPS(60)
175 | case 60:
176 | ebiten.SetMaxTPS(90)
177 | case 90:
178 | ebiten.SetMaxTPS(120)
179 | case 120:
180 | ebiten.SetMaxTPS(150)
181 | case 150:
182 | ebiten.SetMaxTPS(30)
183 | }
184 |
185 | }
186 | }
187 |
188 | func (m *Map) InViewRange(pos Msg.PositionXY) bool {
189 | _distance := pos.DistancePosition(m.MainPos())
190 | if math.Abs( _distance.M_x) > ScreenWidth/2-10 || math.Abs(_distance.M_y) > ScreenHeight/2-10{
191 | return false
192 | }
193 | return true
194 | }
195 | func (m *Map) PosConvert(pos Msg.PositionXY) Msg.PositionXY {
196 |
197 | _main_user_pos := m.MainPos()
198 |
199 | _x_diff := g_center_pos.M_x - _main_user_pos.M_x
200 | _y_diff := g_center_pos.M_y - _main_user_pos.M_y
201 | pos.M_x += _x_diff
202 | pos.M_y += _y_diff
203 | return pos
204 | }
205 |
206 | func (m *Map) Draw(screen *ebiten.Image) {
207 | //text.Draw(screen, g_slope, uiFont, int(100), int(100), color.White)
208 |
209 | _grid_size := g_map_maze_info.M_height / float64(len(g_map_maze_info.M_maze))
210 | for _row_idx_it, _row_it := range g_map_maze_info.M_maze {
211 | _row_idx := _row_idx_it
212 | for _col_idx_it, _block_val := range _row_it {
213 | _col_idx := _col_idx_it
214 | if _block_val != 0 {
215 | _block_pos :=Msg.PositionXY{float64(_col_idx) * _grid_size, float64(_row_idx) * _grid_size}
216 | if !m.InViewRange(_block_pos){
217 | continue
218 | }
219 | _block_pos = m.PosConvert(_block_pos)
220 | ebitenutil.DrawRect(screen, _block_pos.M_x, _block_pos.M_y, _grid_size, _grid_size, color.Black)
221 | } /* else {
222 | ebitenutil.DrawRect(screen, float64(_col_idx)*_grid_size, float64(_row_idx)*_grid_size, _grid_size, _grid_size, color.White)
223 | }*/
224 | /*detailStr := fmt.Sprintf("%d", _row_idx*len(g_map_maze_info.M_maze[0])+_col_idx)
225 | text.Draw(screen, detailStr, uiFont, int (float64(_col_idx)*_grid_size + _grid_size/2), int (float64(_row_idx)*_grid_size+ _grid_size/2), color.White) */
226 | }
227 | }
228 |
229 | for _, it := range m.m_user_list {
230 | for _, path_it := range it.M_path {
231 | if !m.InViewRange(path_it){
232 | continue
233 | }
234 | _path_pos := m.PosConvert(path_it)
235 | ebitenutil.DrawRect(screen, _path_pos.M_x, _path_pos.M_y, gridSize, gridSize, color.RGBA{0xff, 0x00, 0x00, 0xff})
236 | }
237 | }
238 |
239 | for _, path_it := range g_main_path_node {
240 | if !m.InViewRange(path_it){
241 | continue
242 | }
243 | _path_pos := m.PosConvert(path_it)
244 | ebitenutil.DrawRect(screen, _path_pos.M_x, _path_pos.M_y, gridSize, gridSize, color.RGBA{0xff, 0x00, 0x00, 0xff})
245 | }
246 |
247 | for _uid_it, it := range m.m_user_list {
248 | if !m.InViewRange(it.M_pos){
249 | continue
250 | }
251 | if m.m_user_list[_uid_it].M_pos.Distance(it.M_pos) > 100 {
252 | panic("1")
253 | }
254 |
255 | if g_main_uid == _uid_it {
256 | //detailStr := fmt.Sprintf("%.2f,%.2f", it.M_pos.M_x, it.M_pos.M_y)
257 | //text.Draw(screen, detailStr, uiFont, int(it.M_pos.M_x), int(it.M_pos.M_y+20), color.White)
258 | _main_user := m.PosConvert(Msg.PositionXY{it.M_pos.M_x + (gridSize-userGridSize)/2, it.M_pos.M_y + (gridSize-userGridSize)/2})
259 | ebitenutil.DrawRect(screen, _main_user.M_x, _main_user.M_y, userGridSize, userGridSize, color.RGBA{0xff, 0xa0, 0x00, 0xff})
260 | } else {
261 | //detailStr := fmt.Sprintf("%.2f,%.2f", it.M_pos.M_x, it.M_pos.M_y)
262 | //text.Draw(screen, detailStr, uiFont, int(it.M_pos.M_x), int(it.M_pos.M_y+20), color.White)
263 | _main_user := m.PosConvert(Msg.PositionXY{it.M_pos.M_x + (gridSize-userGridSize)/2, it.M_pos.M_y + (gridSize-userGridSize)/2})
264 | ebitenutil.DrawRect(screen, _main_user.M_x, _main_user.M_y, userGridSize, userGridSize, color.RGBA{0x80, 0xa0, 0x00, 0xff})
265 | //ebitenutil.DrawRect(screen, it.M_pos.M_x+(gridSize-userGridSize)/2, it.M_pos.M_y+(gridSize-userGridSize)/2, userGridSize, userGridSize, color.RGBA{0x80, 0xa0, 0xc0, 0xff})
266 | }
267 | }
268 |
269 | ebitenutil.DebugPrint(screen, fmt.Sprintf("MAX: %d\nTPS: %0.2f\nFPS: %0.2f", ebiten.MaxTPS(), ebiten.CurrentTPS(), ebiten.CurrentFPS()))
270 | }
271 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Msg/msg.go:
--------------------------------------------------------------------------------
1 | package Msg
2 |
3 | import (
4 | "fmt"
5 | "math"
6 | )
7 |
8 | type Message struct {
9 | Id int
10 | Number int
11 | }
12 |
13 | type UserData struct {
14 | M_uid uint64
15 | M_pos PositionXY
16 | M_path []PositionXY
17 | }
18 |
19 | type PositionXY struct {
20 | M_x float64
21 | M_y float64
22 | }
23 |
24 | func (p PositionXY) DebugString() string {
25 | return fmt.Sprintf("[x:%v|y:%v]", p.M_x, p.M_y)
26 | }
27 |
28 | func (p *PositionXY) IsSame(rhs_ PositionXY) bool {
29 | if math.Abs(p.M_x-rhs_.M_x) > 0.0001 {
30 | return false
31 | }
32 | if math.Abs(p.M_y-rhs_.M_y) > 0.0001 {
33 | return false
34 | }
35 | return true
36 | }
37 |
38 | func (p *PositionXY) DistancePosition(rhs_ PositionXY) *PositionXY {
39 | _pos := &PositionXY{}
40 | _pos.M_x = rhs_.M_x - p.M_x
41 | _pos.M_y = rhs_.M_y - p.M_y
42 | return _pos
43 | }
44 |
45 | func (p PositionXY) Distance(rhs_ PositionXY) float64 {
46 | _dx := math.Abs(p.M_x - rhs_.M_x)
47 | _dy := math.Abs(p.M_y - rhs_.M_y)
48 | return math.Sqrt(_dx*_dx + _dy*_dy)
49 | }
50 |
51 | type C2SUserMove struct {
52 | M_pos PositionXY
53 | }
54 |
55 | type S2C_MOVE struct {
56 | M_uid uint64
57 | M_data UserData
58 | }
59 |
60 | type S2CMapFullSync struct {
61 | M_user []UserData
62 | }
63 |
64 | type S2CMapAddUser struct {
65 | M_user []UserData
66 | }
67 | type S2CMapUpdateUser struct {
68 | M_user []UserData
69 | }
70 | type S2CMapDeleteUser struct {
71 | M_user []UserData
72 | }
73 | type S2C_MapAStarNodeUpdate struct {
74 | M_uid uint64
75 | M_path []PositionXY
76 | }
77 |
78 | type C2S_Login struct {
79 |
80 | }
81 |
82 | type S2C_Login struct {
83 | M_data UserData
84 | }
85 |
86 | type C2S_FirstEnterMap struct {
87 |
88 | }
89 |
90 | type S2C_FirstEnterMap struct {
91 | M_map_uid uint64
92 | M_maze [][]float64
93 | M_height float64
94 | M_width float64
95 | M_data UserData
96 | }
97 |
98 |
99 | type C2S_UserMove struct {
100 | M_pos PositionXY
101 | }
102 |
103 |
104 | type MapLoad struct {
105 | M_map_uid uint64
106 | M_load uint32
107 | }
108 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Aoi/Aoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | type AoiCell struct {
4 | m_watch_list map[uint64]map[uint64]struct{}
5 | M_enter_callback AoiEnterCallBack
6 | M_quit_callback AoiQuitCallBack
7 | M_move_callback AoiMoveCallBack
8 | M_add_watch_callback AoiAddWatch
9 | }
10 |
11 | func NewAoiCell() *AoiCell {
12 | _cell := &AoiCell{
13 | m_watch_list: make(map[uint64]map[uint64]struct{}),
14 | }
15 |
16 | return _cell
17 | }
18 |
19 | func (cell *AoiCell) enterCell(enter_ uint64) {
20 | cell.m_watch_list[enter_] = make(map[uint64]struct{})
21 | }
22 | func (cell *AoiCell) notifyEnterCell(enter_ uint64) {
23 | for _it := range cell.m_watch_list {
24 | cell.M_enter_callback(_it, enter_)
25 | cell.M_enter_callback(enter_,_it)
26 | }
27 | }
28 |
29 | func (cell *AoiCell) quitCell(quit uint64) {
30 | delete(cell.m_watch_list, quit)
31 | }
32 | func (cell *AoiCell) notifyQuitCell(quit_ uint64) {
33 | for _it := range cell.m_watch_list {
34 | cell.M_quit_callback(_it, quit_)
35 | cell.M_quit_callback(quit_, _it)
36 | }
37 | }
38 |
39 | func (cell *AoiCell) updateCell(enter_ uint64) {
40 | for _it := range cell.m_watch_list {
41 | cell.M_move_callback(_it, enter_)
42 | cell.M_move_callback(enter_,_it)
43 | }
44 | }
45 |
46 | /*func (cell *AoiCell) enterCell(enter_ uint32) {
47 | cell.m_watch_list[enter_] = make(map[uint32]struct{})
48 | for _it := range cell.m_watch_list {
49 | if cell.M_add_watch_callback(enter_, _it) {
50 | cell.m_watch_list[enter_][_it] = struct{}{}
51 | cell.M_enter_callback(enter_, _it)
52 | }
53 | if cell.M_add_watch_callback(_it, enter_) {
54 | cell.m_watch_list[_it][enter_] = struct{}{}
55 | cell.M_enter_callback(_it, enter_)
56 | }
57 | }
58 | }
59 |
60 | func (cell *AoiCell) quitCell(enter_ uint32) {
61 | _watch_list := cell.m_watch_list[enter_]
62 | for _it := range _watch_list {
63 | if enter_== _it {
64 | delete(cell.m_watch_list[_it], enter_)
65 | continue
66 | }
67 | cell.M_quit_callback(enter_, _it)
68 | _, exists := cell.m_watch_list[_it][enter_]
69 | if exists {
70 | cell.M_quit_callback(_it, enter_)
71 | }
72 | delete(cell.m_watch_list[_it], enter_)
73 | }
74 | delete(cell.m_watch_list, enter_)
75 | }
76 |
77 | func (cell *AoiCell) updateCell(enter_ uint32) {
78 | for _it := range cell.m_watch_list {
79 | if cell.M_add_watch_callback(enter_, _it) {
80 | _, exists := cell.m_watch_list[enter_][_it]
81 | if exists {
82 | cell.M_move_callback(enter_, _it)
83 | } else {
84 | cell.m_watch_list[enter_][_it] = struct{}{}
85 | cell.M_enter_callback(enter_, _it)
86 | }
87 |
88 | } else {
89 | _, exists := cell.m_watch_list[enter_][_it]
90 | if exists {
91 | cell.M_quit_callback(enter_, _it)
92 | delete(cell.m_watch_list[enter_], _it)
93 | }
94 | }
95 |
96 | if cell.M_add_watch_callback(_it, enter_) {
97 | _, exists := cell.m_watch_list[_it][enter_]
98 | if exists {
99 | cell.M_move_callback(_it, enter_)
100 | } else {
101 | cell.m_watch_list[_it][enter_] = struct{}{}
102 | cell.M_enter_callback(_it, enter_)
103 | }
104 | } else {
105 | _, exists := cell.m_watch_list[_it][enter_]
106 | if exists {
107 | cell.M_quit_callback(_it, enter_)
108 | delete(cell.m_watch_list[_it], enter_)
109 | }
110 | }
111 |
112 | }
113 | }*/
114 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Aoi/AoiManager.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
5 | )
6 |
7 | type AoiMoveCallBack func(move_, tar_ uint64)
8 | type AoiEnterCallBack func(move_, tar_ uint64)
9 | type AoiQuitCallBack func(move_, tar_ uint64)
10 | type AoiAddWatch func(move_, tar_ uint64) bool
11 |
12 | type AoiManager struct {
13 | M_height float64
14 | M_width float64
15 | m_aoi_list map[uint32]*AoiCell
16 | M_current_index map[uint64]uint32
17 | m_block_height float64
18 | m_block_width float64
19 | m_block_size float64
20 | }
21 |
22 | func NewAoiManager(width_, height_, block_size_ float64) *AoiManager {
23 | _mgr := &AoiManager{
24 | m_aoi_list: make(map[uint32]*AoiCell),
25 | M_current_index: make(map[uint64]uint32),
26 | }
27 | _mgr.M_height = height_
28 | _mgr.M_width = width_
29 | _mgr.m_block_height = height_ / block_size_
30 | _mgr.m_block_width = width_ / block_size_
31 | _mgr.m_block_size = block_size_
32 | return _mgr
33 | }
34 |
35 | func (mgr *AoiManager) Init(add_watch_call_ AoiAddWatch, move_call_ AoiMoveCallBack, enter_call_ AoiEnterCallBack, quit_call_ AoiQuitCallBack) {
36 | for _row_idx := uint32(0); _row_idx < uint32(mgr.m_block_size); _row_idx++ {
37 | for _col_idx := uint32(0); _col_idx < uint32(mgr.m_block_size); _col_idx++ {
38 | _cell := NewAoiCell()
39 | _cell.M_move_callback = move_call_
40 | _cell.M_enter_callback = enter_call_
41 | _cell.M_quit_callback = quit_call_
42 | _cell.M_add_watch_callback = add_watch_call_
43 | mgr.m_aoi_list[mgr.buildIndex(_row_idx, _col_idx)] = _cell
44 | }
45 | }
46 | }
47 |
48 | func getDiff(lhs_ map[uint32]struct{}, rhs_ map[uint32]struct{}) map[uint32]struct{} {
49 | _ret := make(map[uint32]struct{})
50 | for _it := range lhs_ {
51 | _ret[_it] = struct{}{}
52 | }
53 | for _it := range rhs_ {
54 | delete(_ret, _it)
55 | }
56 |
57 | return _ret
58 | }
59 |
60 | func (mgr *AoiManager) Enter(enter_ uint64, pos_ Msg.PositionXY) {
61 | _current_index := mgr.CalcIndex(pos_)
62 | _cell := mgr.m_aoi_list[_current_index]
63 | _cell.enterCell(enter_)
64 | _round_arr := mgr.getRoundBlock(_current_index)
65 | for _it := range _round_arr {
66 | _cell, exists := mgr.m_aoi_list[_it]
67 | if exists {
68 | _cell.notifyEnterCell(enter_)
69 | }
70 | }
71 | mgr.M_current_index[enter_] = _current_index
72 | }
73 |
74 | func (mgr *AoiManager) Quit(quit_ uint64, pos_ Msg.PositionXY) {
75 | _current_index := mgr.CalcIndex(pos_)
76 | _cell := mgr.m_aoi_list[_current_index]
77 | _cell.quitCell(quit_)
78 | _round_arr := mgr.getRoundBlock(_current_index)
79 | for _it := range _round_arr {
80 | _cell, exists := mgr.m_aoi_list[_it]
81 | if exists {
82 | _cell.notifyQuitCell(quit_)
83 | }
84 | }
85 | delete(mgr.M_current_index, quit_)
86 | }
87 |
88 | func (mgr *AoiManager) Move(move_ uint64, pos_ Msg.PositionXY) {
89 |
90 | _old_round_arr := mgr.getOldRoundBlock(move_)
91 |
92 | _current_index := mgr.CalcIndex(pos_)
93 | _new_round_arr := mgr.getRoundBlock(_current_index)
94 |
95 | if _current_index != mgr.M_current_index[move_] {
96 | _enter_cell := mgr.m_aoi_list[_current_index]
97 | _enter_cell.enterCell(move_)
98 |
99 | }
100 | _enter_cell := getDiff(_new_round_arr, _old_round_arr)
101 | for _it := range _enter_cell {
102 | _cell, exists := mgr.m_aoi_list[_it]
103 | if exists {
104 | _cell.notifyEnterCell(move_)
105 | }
106 | }
107 |
108 | _update_cell := getDiff(_new_round_arr, _enter_cell)
109 | for _it := range _update_cell {
110 | _cell, exists := mgr.m_aoi_list[_it]
111 | if exists {
112 | _cell.updateCell(move_)
113 | }
114 | }
115 | if _current_index != mgr.M_current_index[move_] {
116 | _quit_cell := mgr.m_aoi_list[mgr.M_current_index[move_]]
117 | _quit_cell.quitCell(move_)
118 | }
119 | _quit_cell := getDiff(_old_round_arr, _new_round_arr)
120 | for _it := range _quit_cell {
121 | _cell, exists := mgr.m_aoi_list[_it]
122 | if exists {
123 | _cell.notifyQuitCell(move_)
124 | }
125 | }
126 | mgr.M_current_index[move_] = _current_index
127 |
128 | }
129 |
130 | func (mgr *AoiManager) CalcIndex(xy_ Msg.PositionXY) uint32 {
131 | return mgr.buildIndex(uint32(xy_.M_x/mgr.m_block_width), uint32(xy_.M_y/mgr.m_block_height))
132 | }
133 |
134 | func (mgr *AoiManager) buildIndex(row_, col_ uint32) uint32 {
135 | return row_ + col_*uint32(mgr.m_block_size)
136 | }
137 |
138 | func (mgr *AoiManager) getOldRoundBlock(uid_ uint64) map[uint32]struct{} {
139 | _old_index := mgr.M_current_index[uid_]
140 | return mgr.getRoundBlock(_old_index)
141 | }
142 |
143 | func (mgr *AoiManager) getRoundBlock(cent_index_ uint32) map[uint32]struct{} {
144 | _ret_round := make(map[uint32]struct{})
145 | _cent_idex := int(cent_index_)
146 | _block_size := int(mgr.m_block_size)
147 |
148 | _max_idx := int(mgr.m_block_size * mgr.m_block_size)
149 |
150 | _cent_row := int(cent_index_ / uint32(mgr.m_block_size))
151 | _ret_round[cent_index_] = struct{}{}
152 | {
153 | _left_up := _cent_idex - _block_size - 1
154 | if _left_up >= 0 && (_left_up/_block_size+1) == _cent_row {
155 | _ret_round[uint32(_left_up)] = struct{}{}
156 | }
157 | }
158 |
159 | {
160 | _up := _cent_idex - _block_size
161 | if _up >= 0 && (_up/_block_size+1) == _cent_row {
162 | _ret_round[uint32(_up)] = struct{}{}
163 | }
164 | }
165 | {
166 | _up_right := _cent_idex - _block_size + 1
167 | if _up_right >= 0 && (_up_right/_block_size+1) == _cent_row {
168 | _ret_round[uint32(_up_right)] = struct{}{}
169 | }
170 | }
171 |
172 | {
173 | _left := _cent_idex - 1
174 | if _left >= 0 && (_left/_block_size) == _cent_row {
175 | _ret_round[uint32(_left)] = struct{}{}
176 | }
177 | }
178 | {
179 | _right := _cent_idex + 1
180 | if _right >= 0 && (_right/_block_size) == _cent_row {
181 | _ret_round[uint32(_right)] = struct{}{}
182 | }
183 | }
184 |
185 | {
186 | _down_left := _cent_idex + _block_size - 1
187 | if _down_left < _max_idx && (_down_left/_block_size-1) == _cent_row {
188 | _ret_round[uint32(_down_left)] = struct{}{}
189 | }
190 | }
191 |
192 | {
193 | _down := _cent_idex + _block_size
194 | if _down < _max_idx && (_down/_block_size-1) == _cent_row {
195 | _ret_round[uint32(_down)] = struct{}{}
196 | }
197 | }
198 | {
199 | _down_right := _cent_idex + _block_size + 1
200 | if _down_right < _max_idx && (_down_right/_block_size-1) == _cent_row {
201 | _ret_round[uint32(_down_right)] = struct{}{}
202 | }
203 | }
204 |
205 | return _ret_round
206 | }
207 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Aoi/AoiManager_test.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "YMsg"
5 | "testing"
6 | )
7 |
8 | func roundTestHelp(cent_index_, block_ uint32, round_target_ []uint32) map[uint32]struct{} {
9 | _mgr := NewAoiManager(1280, 720, float64(block_))
10 | _sure_arr := make(map[uint32]struct{})
11 | for _, _it := range round_target_ {
12 | _sure_arr[_it] = struct{}{}
13 | }
14 | _round_arr := _mgr.getRoundBlock(cent_index_)
15 | for _it := range _round_arr {
16 | _, exists := _sure_arr[_it]
17 | if !exists {
18 | _sure_arr[_it] = struct{}{}
19 | }
20 | delete(_sure_arr, _it)
21 | }
22 | return _sure_arr
23 | }
24 |
25 | func TestAoiGetRoundIndex(t *testing.T) {
26 |
27 | _err_list := roundTestHelp(16, 5, []uint32{10, 11, 12, 15, 17, 20, 21, 22})
28 | if len(_err_list) > 0 {
29 | t.Fatalf("[%v]", _err_list)
30 | }
31 |
32 | _err_list = roundTestHelp(0, 5, []uint32{1, 5, 6})
33 | if len(_err_list) > 0 {
34 | t.Fatalf("[%v]", _err_list)
35 | }
36 |
37 | _err_list = roundTestHelp(4, 5, []uint32{3, 8, 9})
38 | if len(_err_list) > 0 {
39 | t.Fatalf("[%v]", _err_list)
40 | }
41 |
42 | _err_list = roundTestHelp(2, 5, []uint32{1, 6, 7, 8, 3})
43 | if len(_err_list) > 0 {
44 | t.Fatalf("[%v]", _err_list)
45 | }
46 |
47 | _err_list = roundTestHelp(20, 5, []uint32{15, 16, 21})
48 | if len(_err_list) > 0 {
49 | t.Fatalf("[%v]", _err_list)
50 | }
51 | _err_list = roundTestHelp(22, 5, []uint32{16, 17, 18, 21, 23})
52 | if len(_err_list) > 0 {
53 | t.Fatalf("[%v]", _err_list)
54 | }
55 | _err_list = roundTestHelp(24, 5, []uint32{18, 19, 23})
56 | if len(_err_list) > 0 {
57 | t.Fatalf("[%v]", _err_list)
58 | }
59 | }
60 |
61 | func TestAoiGetRoundIndex10(t *testing.T) {
62 |
63 | _err_list := roundTestHelp(0, 10, []uint32{1, 10, 11})
64 | if len(_err_list) > 0 {
65 | t.Fatalf("[%v]", _err_list)
66 | }
67 |
68 | _err_list = roundTestHelp(11, 10, []uint32{0, 1, 2, 10, 11, 12, 20, 21, 22})
69 | if len(_err_list) > 0 {
70 | t.Fatalf("[%v]", _err_list)
71 | }
72 | }
73 |
74 | func CalcIndexHelp(x_, y_ float64, tar_idx_ uint32) bool {
75 | _mgr := NewAoiManager(1280, 720, float64(10))
76 | _cal_idx := _mgr.CalcIndex(YMsg.PositionXY{x_, y_})
77 | return _cal_idx == tar_idx_
78 | }
79 | func TestCalcIndex(t *testing.T) {
80 | if !CalcIndexHelp(0,0,0){
81 | t.Fatal()
82 | }
83 | if !CalcIndexHelp(128,0,1){
84 | t.Fatal()
85 | }
86 | if !CalcIndexHelp(128,73,11){
87 | t.Fatal()
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Aoi/GoAoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | )
6 |
7 | type GoAoiCellAction struct {
8 | m_action uint32
9 | m_action_obj GoAoiObj
10 | }
11 |
12 | const (
13 | GO_AOI_CELL_ACTION_ENTER = iota
14 | GO_AOI_CELL_ACTION_NOTIFY_ENTER
15 | GO_AOI_CELL_ACTION_UPDATE
16 | GO_AOI_CELL_ACTION_NOTIFY_QUIT
17 | GO_AOI_CELL_ACTION_QUIT
18 | )
19 |
20 | type GoAoiCell struct {
21 | m_obj_list map[uint64]GoAoiObj
22 | m_mgr_chan *YTool.SyncQueue
23 | M_obj_action chan GoAoiCellAction
24 | m_close chan struct{}
25 | }
26 |
27 | func NewGoAoiCell(mgr_chan_ *YTool.SyncQueue) *GoAoiCell {
28 | _cell := &GoAoiCell{
29 | m_obj_list: make(map[uint64]GoAoiObj),
30 | m_mgr_chan: mgr_chan_,
31 | M_obj_action: make(chan GoAoiCellAction, 1000),
32 | m_close: make(chan struct{}),
33 | }
34 | go func() {
35 | for {
36 | select {
37 | case <-_cell.M_obj_action:
38 | for _action := range _cell.M_obj_action {
39 | if len(_cell.M_obj_action) == 0 {
40 | break
41 | }
42 | switch _action.m_action {
43 | case GO_AOI_CELL_ACTION_ENTER:
44 | _cell.enterCell(_action.m_action_obj)
45 | case GO_AOI_CELL_ACTION_NOTIFY_ENTER:
46 | _cell.notifyEnterCell(_action.m_action_obj)
47 | case GO_AOI_CELL_ACTION_UPDATE:
48 | _cell.updateCell(_action.m_action_obj)
49 | case GO_AOI_CELL_ACTION_NOTIFY_QUIT:
50 | _cell.notifyQuitCell(_action.m_action_obj)
51 | case GO_AOI_CELL_ACTION_QUIT:
52 | _cell.quitCell(_action.m_action_obj)
53 | }
54 | }
55 |
56 | case <-_cell.m_close:
57 | return
58 | }
59 | }
60 | }()
61 | return _cell
62 | }
63 |
64 | func (cell *GoAoiCell) EnterCell(enter_ GoAoiObj) {
65 | cell.M_obj_action <- GoAoiCellAction{
66 | GO_AOI_CELL_ACTION_ENTER,
67 | enter_,
68 | }
69 | }
70 | func (cell *GoAoiCell) NotifyEnterCell(enter_ GoAoiObj) {
71 | cell.M_obj_action <- GoAoiCellAction{
72 | GO_AOI_CELL_ACTION_NOTIFY_ENTER,
73 | enter_,
74 | }
75 | }
76 | func (cell *GoAoiCell) QuitCell(quit_ GoAoiObj) {
77 | cell.M_obj_action <- GoAoiCellAction{
78 | GO_AOI_CELL_ACTION_QUIT,
79 | quit_,
80 | }
81 | }
82 | func (cell *GoAoiCell) NotifyQuitCell(enter_ GoAoiObj) {
83 | cell.M_obj_action <- GoAoiCellAction{
84 | GO_AOI_CELL_ACTION_NOTIFY_QUIT,
85 | enter_,
86 | }
87 | }
88 | func (cell *GoAoiCell) UpdateCell(enter_ GoAoiObj) {
89 | cell.M_obj_action <- GoAoiCellAction{
90 | GO_AOI_CELL_ACTION_UPDATE,
91 | enter_,
92 | }
93 | }
94 |
95 | func (cell *GoAoiCell) enterCell(enter_ GoAoiObj) {
96 | cell.m_obj_list[enter_.M_uid] = enter_
97 | /* _, exists := cell.m_watch_list[enter_.M_module_uid]
98 | if !exists {
99 | cell.m_watch_list[enter_.M_module_uid] = make(map[uint64]struct{})
100 | }*/
101 | }
102 |
103 | func (cell *GoAoiCell) notifyEnterCell(enter_ GoAoiObj) {
104 | _func := func(notify_, action_ GoAoiObj) {
105 | if notify_.PositionXY.Distance(action_.PositionXY) < notify_.M_view_range {
106 | //cell.m_watch_list[notify_.M_module_uid][action_.M_module_uid] = struct{}{}
107 | cell.m_mgr_chan.Add(GoAoiAction{
108 | GO_AOI_ACTION_ENTER,
109 | notify_.M_uid,
110 | action_.M_uid,
111 | })
112 | }
113 | }
114 | for _, _it := range cell.m_obj_list {
115 | _func(_it, enter_)
116 | _func(enter_, _it)
117 | }
118 | }
119 |
120 | func (cell *GoAoiCell) quitCell(quit_ GoAoiObj) {
121 |
122 | delete(cell.m_obj_list, quit_.M_uid)
123 | }
124 |
125 | func (cell *GoAoiCell) notifyQuitCell(quit_ GoAoiObj) {
126 | for _, _it := range cell.m_obj_list {
127 | cell.m_mgr_chan.Add(GoAoiAction{
128 | GO_AOI_ACTION_QUIT,
129 | quit_.M_uid,
130 | _it.M_uid,
131 | })
132 | cell.m_mgr_chan.Add(GoAoiAction{
133 | GO_AOI_ACTION_QUIT,
134 | _it.M_uid,
135 | quit_.M_uid,
136 | })
137 | }
138 | }
139 |
140 | func (cell *GoAoiCell) updateCell(enter_ GoAoiObj) {
141 | _func := func(notify_, action_ GoAoiObj) {
142 | _, exists := cell.m_obj_list[enter_.M_uid]
143 | if exists {
144 | cell.m_obj_list[enter_.M_uid] = enter_
145 | }
146 | if action_.PositionXY.Distance(notify_.PositionXY) < action_.M_view_range {
147 |
148 | cell.m_mgr_chan.Add(GoAoiAction{
149 | GO_AOI_ACTION_UPDATE,
150 | action_.M_uid,
151 | notify_.M_uid,
152 | })
153 |
154 | } else {
155 |
156 | cell.m_mgr_chan.Add(GoAoiAction{
157 | GO_AOI_ACTION_QUIT,
158 | action_.M_uid,
159 | notify_.M_uid,
160 | })
161 |
162 | }
163 | }
164 | for _, _it := range cell.m_obj_list {
165 | _func(enter_, _it)
166 | _func(_it, enter_)
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Aoi/GoAoiManager.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
6 | )
7 |
8 | type GoAoiMoveCallBack func(notify_, action_ uint64)
9 | type GoAoiEnterCallBack func(notify_, action_ uint64)
10 | type GoAoiQuitCallBack func(notify_, action_ uint64)
11 |
12 | const (
13 | GO_AOI_ACTION_ENTER = iota
14 | GO_AOI_ACTION_UPDATE
15 | GO_AOI_ACTION_QUIT
16 | )
17 |
18 | type GoAoiObj struct {
19 | M_uid uint64
20 | Msg.PositionXY
21 | M_view_range float64
22 | }
23 |
24 | type GoAoiAction struct {
25 | m_action uint32
26 | m_notify_obj uint64
27 | m_action_obj uint64
28 | }
29 |
30 | type GoAoiManager struct {
31 | M_height float64
32 | M_width float64
33 | m_aoi_list map[uint32]*GoAoiCell
34 | M_current_index map[uint64]uint32
35 | m_block_height float64
36 | m_block_width float64
37 | m_block_size float64
38 |
39 | m_enter_callback GoAoiEnterCallBack
40 | m_update_callback GoAoiMoveCallBack
41 | m_quit_callback GoAoiQuitCallBack
42 | //m_action_list chan GoAoiAction
43 | m_action_list *YTool.SyncQueue
44 | }
45 |
46 | func NewGoAoiManager(width_, height_, block_size_ float64) *GoAoiManager {
47 | _mgr := &GoAoiManager{
48 | m_aoi_list: make(map[uint32]*GoAoiCell),
49 | M_current_index: make(map[uint64]uint32),
50 | m_action_list: YTool.NewSyncQueue(),
51 | }
52 | _mgr.M_height = height_
53 | _mgr.M_width = width_
54 | _mgr.m_block_height = height_ / block_size_
55 | _mgr.m_block_width = width_ / block_size_
56 | _mgr.m_block_size = block_size_
57 | return _mgr
58 | }
59 |
60 | func (mgr *GoAoiManager) Init(move_call_ GoAoiMoveCallBack, enter_call_ GoAoiEnterCallBack, quit_call_ GoAoiQuitCallBack) {
61 |
62 | mgr.m_enter_callback = enter_call_
63 | mgr.m_update_callback = move_call_
64 | mgr.m_quit_callback = quit_call_
65 |
66 | for _row_idx := uint32(0); _row_idx < uint32(mgr.m_block_size); _row_idx++ {
67 | for _col_idx := uint32(0); _col_idx < uint32(mgr.m_block_size); _col_idx++ {
68 | _cell := NewGoAoiCell(mgr.m_action_list)
69 | mgr.m_aoi_list[mgr.buildIndex(_row_idx, _col_idx)] = _cell
70 | }
71 | }
72 | }
73 |
74 | func (mgr *GoAoiManager) Update() {
75 | for {
76 | if mgr.m_action_list.Len() == 0 {
77 | break
78 | }
79 | _act := mgr.m_action_list.Pop().(GoAoiAction)
80 | switch _act.m_action {
81 | case GO_AOI_ACTION_ENTER:
82 | mgr.m_enter_callback(_act.m_notify_obj, _act.m_action_obj)
83 | case GO_AOI_ACTION_UPDATE:
84 | mgr.m_update_callback(_act.m_notify_obj, _act.m_action_obj)
85 | case GO_AOI_ACTION_QUIT:
86 | mgr.m_quit_callback(_act.m_notify_obj, _act.m_action_obj)
87 | }
88 | }
89 |
90 | }
91 |
92 | func (mgr *GoAoiManager) Enter(enter_ GoAoiObj, pos_ Msg.PositionXY) {
93 | _current_index := mgr.CalcIndex(pos_)
94 | _cell := mgr.m_aoi_list[_current_index]
95 | _cell.EnterCell(enter_)
96 | _round_arr := mgr.getRoundBlock(_current_index)
97 | for _it := range _round_arr {
98 | _cell, exists := mgr.m_aoi_list[_it]
99 | if exists {
100 | _cell.NotifyEnterCell(enter_)
101 | }
102 | }
103 | mgr.M_current_index[enter_.M_uid] = _current_index
104 | }
105 |
106 | func (mgr *GoAoiManager) Quit(quit_ GoAoiObj, pos_ Msg.PositionXY) {
107 | _current_index := mgr.CalcIndex(pos_)
108 | _cell := mgr.m_aoi_list[_current_index]
109 | _cell.QuitCell(quit_)
110 | _round_arr := mgr.getRoundBlock(_current_index)
111 | for _it := range _round_arr {
112 | _cell, exists := mgr.m_aoi_list[_it]
113 | if exists {
114 | _cell.NotifyQuitCell(quit_)
115 | }
116 | }
117 | delete(mgr.M_current_index, quit_.M_uid)
118 | }
119 |
120 | func (mgr *GoAoiManager) Move(move_ GoAoiObj, pos_ Msg.PositionXY) {
121 |
122 | _old_round_arr := mgr.getOldRoundBlock(move_.M_uid)
123 |
124 | _current_index := mgr.CalcIndex(pos_)
125 | _new_round_arr := mgr.getRoundBlock(_current_index)
126 |
127 | if _current_index != mgr.M_current_index[move_.M_uid] {
128 | _enter_cell := mgr.m_aoi_list[_current_index]
129 | _enter_cell.EnterCell(move_)
130 |
131 | }
132 | _enter_cell := getDiff(_new_round_arr, _old_round_arr)
133 | for _it := range _enter_cell {
134 | _cell, exists := mgr.m_aoi_list[_it]
135 | if exists {
136 | _cell.NotifyEnterCell(move_)
137 | }
138 | }
139 |
140 | _update_cell := getDiff(_new_round_arr, _enter_cell)
141 | for _it := range _update_cell {
142 | _cell, exists := mgr.m_aoi_list[_it]
143 | if exists {
144 | _cell.UpdateCell(move_)
145 | }
146 | }
147 | if _current_index != mgr.M_current_index[move_.M_uid] {
148 | _quit_cell := mgr.m_aoi_list[mgr.M_current_index[move_.M_uid]]
149 | _quit_cell.QuitCell(move_)
150 | }
151 | _quit_cell := getDiff(_old_round_arr, _new_round_arr)
152 | for _it := range _quit_cell {
153 | _cell, exists := mgr.m_aoi_list[_it]
154 | if exists {
155 | _cell.NotifyQuitCell(move_)
156 | }
157 | }
158 | mgr.M_current_index[move_.M_uid] = _current_index
159 |
160 | }
161 |
162 | func (mgr *GoAoiManager) CalcIndex(xy_ Msg.PositionXY) uint32 {
163 | return mgr.buildIndex(uint32(xy_.M_x/mgr.m_block_width), uint32(xy_.M_y/mgr.m_block_height))
164 | }
165 |
166 | func (mgr *GoAoiManager) buildIndex(row_, col_ uint32) uint32 {
167 | return row_ + col_*uint32(mgr.m_block_size)
168 | }
169 |
170 | func (mgr *GoAoiManager) getOldRoundBlock(uid_ uint64) map[uint32]struct{} {
171 | _old_index := mgr.M_current_index[uid_]
172 | return mgr.getRoundBlock(_old_index)
173 | }
174 |
175 | func (mgr *GoAoiManager) getRoundBlock(cent_index_ uint32) map[uint32]struct{} {
176 | _ret_round := make(map[uint32]struct{})
177 | _cent_idex := int(cent_index_)
178 | _block_size := int(mgr.m_block_size)
179 |
180 | _max_idx := int(mgr.m_block_size * mgr.m_block_size)
181 |
182 | _cent_row := int(cent_index_ / uint32(mgr.m_block_size))
183 | _ret_round[cent_index_] = struct{}{}
184 | {
185 | _left_up := _cent_idex - _block_size - 1
186 | if _left_up >= 0 && (_left_up/_block_size+1) == _cent_row {
187 | _ret_round[uint32(_left_up)] = struct{}{}
188 | }
189 | }
190 |
191 | {
192 | _up := _cent_idex - _block_size
193 | if _up >= 0 && (_up/_block_size+1) == _cent_row {
194 | _ret_round[uint32(_up)] = struct{}{}
195 | }
196 | }
197 | {
198 | _up_right := _cent_idex - _block_size + 1
199 | if _up_right >= 0 && (_up_right/_block_size+1) == _cent_row {
200 | _ret_round[uint32(_up_right)] = struct{}{}
201 | }
202 | }
203 |
204 | {
205 | _left := _cent_idex - 1
206 | if _left >= 0 && (_left/_block_size) == _cent_row {
207 | _ret_round[uint32(_left)] = struct{}{}
208 | }
209 | }
210 | {
211 | _right := _cent_idex + 1
212 | if _right >= 0 && (_right/_block_size) == _cent_row {
213 | _ret_round[uint32(_right)] = struct{}{}
214 | }
215 | }
216 |
217 | {
218 | _down_left := _cent_idex + _block_size - 1
219 | if _down_left < _max_idx && (_down_left/_block_size-1) == _cent_row {
220 | _ret_round[uint32(_down_left)] = struct{}{}
221 | }
222 | }
223 |
224 | {
225 | _down := _cent_idex + _block_size
226 | if _down < _max_idx && (_down/_block_size-1) == _cent_row {
227 | _ret_round[uint32(_down)] = struct{}{}
228 | }
229 | }
230 | {
231 | _down_right := _cent_idex + _block_size + 1
232 | if _down_right < _max_idx && (_down_right/_block_size-1) == _cent_row {
233 | _ret_round[uint32(_down_right)] = struct{}{}
234 | }
235 | }
236 |
237 | return _ret_round
238 | }
239 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Aoi/GoNineGridAoi.go:
--------------------------------------------------------------------------------
1 | package aoi
2 |
3 | type GoNineGirdAoiCell struct {
4 | m_watch_list map[uint64]struct{}
5 | }
6 |
7 | func NewGoNineGirdAoiCell() *GoNineGirdAoiCell {
8 | _cell := &GoNineGirdAoiCell{
9 | m_watch_list: make(map[uint64]struct{}),
10 | }
11 | return _cell
12 | }
13 | func (cell *GoNineGirdAoiCell)GetWatch()map[uint64]struct{}{
14 | return cell.m_watch_list
15 | }
16 | func (cell *GoNineGirdAoiCell)Watch(uid_ uint64){
17 | cell.m_watch_list[uid_] = struct{}{}
18 | }
19 |
20 | func (cell *GoNineGirdAoiCell)Forget(uid_ uint64){
21 | delete(cell.m_watch_list, uid_)
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Logic/Move/MoveControl.go:
--------------------------------------------------------------------------------
1 | package move
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
6 | "time"
7 | )
8 |
9 | type MoveControl struct {
10 | M_pos Msg.PositionXY
11 | M_tar Msg.PositionXY
12 | M_next_path Msg.PositionXY
13 | m_path_queue *YTool.Queue
14 | m_path_cache []Msg.PositionXY
15 | M_speed float64
16 | m_last_move_time time.Time
17 | M_view_range float64
18 | }
19 |
20 | func (c *MoveControl) CanToNextPath() bool {
21 | if c.m_path_queue == nil {
22 | return false
23 | }
24 | if c.m_path_queue.Length() == 0 {
25 | return false
26 | }
27 |
28 | return true
29 | }
30 |
31 | func (c *MoveControl) DebugString() string {
32 | _str := ""
33 | if c.m_path_queue == nil {
34 | return _str
35 | }
36 | for _idx := 0; _idx < c.m_path_queue.Length(); _idx++ {
37 | _str += c.m_path_queue.Get(_idx).(Msg.PositionXY).DebugString()
38 | }
39 |
40 | return _str
41 | }
42 |
43 | func (c *MoveControl) GetPathNode() []Msg.PositionXY {
44 | return c.m_path_cache
45 | }
46 |
47 | func (c *MoveControl) toNextPath() {
48 | c.M_next_path = c.m_path_queue.Pop().(Msg.PositionXY)
49 | }
50 |
51 | func (c *MoveControl) MoveQueue(path_queue_ *YTool.Queue) {
52 | c.m_path_queue = path_queue_
53 | c.toNextPath()
54 | _path_node := make([]Msg.PositionXY, 0)
55 | for _idx := 0; _idx < c.m_path_queue.Length(); _idx++ {
56 | _path_node = append(_path_node, c.m_path_queue.Get(_idx).(Msg.PositionXY))
57 | }
58 | c.m_path_cache = _path_node
59 |
60 | }
61 | func (c *MoveControl) MoveTarget(tar_ Msg.PositionXY) {
62 | c.M_tar = tar_
63 | }
64 |
65 | func (c *MoveControl) MoveUpdate(time_ time.Time) bool {
66 | defer func() {
67 | c.m_last_move_time = time_
68 | }()
69 |
70 | if c.M_pos.IsSame(c.M_tar) {
71 | return false
72 | }
73 |
74 | if c.M_pos.IsSame(c.M_next_path) {
75 | if !c.CanToNextPath() {
76 | return false
77 | }
78 | c.toNextPath()
79 | }
80 |
81 | _distance := c.M_pos.Distance(c.M_next_path)
82 |
83 | _interval_time := time_.Sub(c.m_last_move_time).Seconds()
84 | _this_move_distance := _interval_time * c.M_speed
85 |
86 | if _distance < _this_move_distance {
87 | c.M_pos = c.M_next_path
88 | return true
89 | }
90 | _precent := _this_move_distance / _distance
91 |
92 | _distance_pos := c.M_pos.DistancePosition(c.M_next_path)
93 |
94 | c.M_pos.M_x += _distance_pos.M_x * _precent
95 | c.M_pos.M_y += _distance_pos.M_y * _precent
96 |
97 | return true
98 | }
99 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "github.com/yxinyi/YCServer/engine/BaseModule/NetModule"
6 | "github.com/yxinyi/YCServer/engine/YModule"
7 | "github.com/yxinyi/YCServer/engine/YMsg"
8 | "github.com/yxinyi/YCServer/engine/YNode"
9 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Server/Module/Map"
10 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Server/Module/MapManager"
11 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Server/Module/UserManager"
12 | "log"
13 | "net/http"
14 | _ "net/http/pprof"
15 | )
16 |
17 |
18 | func main() {
19 | flag.Parse()
20 |
21 | YNode.ModuleCreateFuncRegister("NewMap", Map.NewInfo)
22 | YNode.ModuleCreateFuncRegister("NetModule", NetModule.NewInfo)
23 | YNode.ModuleCreateFuncRegister("MapManager", MapManager.NewInfo)
24 | YNode.ModuleCreateFuncRegister("UserManager", UserManager.NewInfo)
25 | YNode.SetNodeID(0)
26 | YNode.Register(
27 | YNode.NewModuleInfo("NetModule",0),
28 | YNode.NewModuleInfo("NewMap",1),
29 | YNode.NewModuleInfo("MapManager",0),
30 | YNode.NewModuleInfo("UserManager",0),
31 | )
32 | go func(){
33 | log.Fatal(http.ListenAndServe("0.0.0.0:9999", nil))
34 | }()
35 |
36 |
37 | YNode.RPCCall(YModule.NewRPCMsg(YMsg.ToAgent("NetModule"), "Listen", "0.0.0.0:20000"))
38 | YNode.Start()
39 | }
40 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Module/Map/README.md:
--------------------------------------------------------------------------------
1 | # 无缝大地图设计
2 |
3 | ## 无缝大地图服务器与非无缝大地图设计区别
4 |
5 | 对于 普通的MMO 玩法来说, 往往有一个 map 对象来承载地图上数据,在每帧内对这些数据进行处理来完成地图上需要发生的逻辑,玩家其实也就是挂在对象上的一个数据,在地图切换时,往往玩家行走至地图上一个传送点上开始切图,如果发生了`地图A`切换到`地图B`的情况,从内存角度来说,也只不过是将 mapA 上的玩家对象剪切至 mapB 对象上。
6 |
7 | 那么对于无缝地图来说,在地图切换这部分,其实也没有太大区别,可以理解成传送点变成了传送区域,地图A的边界的所有边缘都可以进行地图切换,从mapA到mapB的过程中也是通过剪切内存来处理玩家的数据。
8 |
9 | 但是与非无缝大地图不同的是,当玩家处于 mapA与mapB的边缘时,虽然玩家数据在mapA上,但是mapB上的玩家也必须能看到处于mapA的玩家,且 mapA 地图上的玩家与 mapB地图上的玩家也可以像在一张地图上一样进行交互,战斗。
10 |
11 | 而这个跨进程交互就是无缝大地图的难点了。
12 |
13 | ## 从单进程说起
14 |
15 | 在mmo的地图逻辑中,玩家需要与当前场景的对象进行交互,比如 NPC ,怪物,场景物品,且这些对象往往是对全地图的玩家开放,也就意味着,一个对象的状态发生改变时,也需要对全地图的玩家进行广播,才能让发起主动交互玩家外的玩家获取被交互对象的最新的正确状态,基于此来实现各种效果,如 怪物死亡,NPC移动,场景物品的掉落拾取,技能释放等逻辑。
16 |
17 | 那么在上述需求的前提下,我们要怎么进行同步呢?
18 |
19 | 最简单方法是,当一个对象发生变化时,可以遍历当前地图的所有玩家对他们进行消息同步来实现我们的目的,但是显而易见我们可以想象到这个方案的弊处,如果一个地图大小为1000X1000,玩家屏幕大小为10X10
20 | 那么当玩家处于地图左上角时,右下角其他玩家的对象操作,其实我们是不关心的,但是却依然进行了同步我们在进行游戏行为时更关心的是我们当前屏幕能看到的对象,且一个地图如果有100个玩家,每个玩家1秒钟都要进行一次行为,那么一秒钟的消息数量即为 100 * 100 达到1万条,这也显然是有很大的优化空间的。所以有了AOI的说法。
21 |
22 | AOI 即 arena of interests ,感兴趣的区域,其实现方案不在本文的讨论范围内,主要有 灯塔,九宫格,十字链表 法三种,各有优劣,但说到底,这些都是手段,我们还是要探究为什么能解决上一段提出的优化,简单的了解思路后即使不进行实现,我们也可以知晓其原理,其会将地图进行分割,并只找出自己感兴趣的区域,在一个对象发生变化后,也只同步给周围的对象,虽然从复杂度来说也算是 n^2,但是由于同步的玩家变少了,从原来的 100*100 缩减成 5\*5 * N甚至更低,有一个数量级的优化,也就能提高单地图的逻辑承载上限。
23 |
24 | 不过即使有各种优化,包括多线程级优化,却永远无法突破物理机的限制,即使单进程实现了1000张地图逻辑,那他也会在第1001张地图的时候表现出瓶颈,因为无论是多么高的配置,单机的承载能力是有上限的。在此限制前提下,也就是意味着使用单进程来实现无边界的无缝地图的服务器逻辑是不可行的。
25 |
26 | 那如何完成我们的无缝大地图的服务器框架,我曾在一段时间内反复思考这个问题,有想出一些方案似乎能解决,但没有时间去实现,且也想更深入的思考,直到最近看了kbengine 的设计思路后,才发现自己的方案已经有人实践并证明了其可行性。
27 |
28 | 核心点就2个,一个是分布式AOI,另一个是主从数据
29 |
30 | 由于单进程的物理限制,一个可以无限扩展的无缝大地图一定会发生两张相邻的地图可能被部署在两台物理机上的情况,也就以为着当玩家在两张地图边缘时,要怎么处理其行为,以及如何让边缘的玩家知道他的动作。
31 |
32 |
33 |
34 | ## 需要解决的问题
35 |
36 | 先试想一下玩家在地图边缘时需要做些什么事情
37 |
38 | 一个是玩家的视野,在两张地图边缘处也是要有玩家视野控制的逻辑,也就是我们的AOI逻辑需要独立在地图逻辑之外,也就是一个AOI可以控制多张地图逻辑。
39 |
40 | 一个是玩家间的交互,在边缘时玩家间的战斗处理,如果两个进程的玩家发生交互该如何处理,该哪个进程处理,该如何通知.
41 |
42 |
43 |
44 | ## 分布式AOI
45 |
46 | ## GHOST
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Module/MapManager/MapManager.go:
--------------------------------------------------------------------------------
1 | package MapManager
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YModule"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
8 | _ "github.com/yxinyi/YCServer/examples/AoiAstarExample/Server/Module/Map"
9 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Server/Module/UserManager"
10 | "math"
11 | )
12 |
13 | type Info struct {
14 | YModule.BaseInter
15 | M_map_pool map[uint64]Msg.MapLoad
16 | }
17 |
18 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
19 | _info := &Info{
20 | M_map_pool: make(map[uint64]Msg.MapLoad),
21 | }
22 | _info.Info = YModule.NewInfo(node_)
23 | return _info
24 | }
25 | func (i *Info) Init() {
26 | i.Info.Init(i)
27 | }
28 |
29 | func (i *Info) Close() {
30 | }
31 |
32 | func (i *Info) RPC_MapRegister(load_ Msg.MapLoad) {
33 | i.M_map_pool[load_.M_map_uid] = load_
34 | }
35 |
36 | func (i *Info) RPC_MapLoadChange(load_ Msg.MapLoad) {
37 | i.M_map_pool[load_.M_map_uid] = load_
38 | }
39 |
40 | func (i *Info) GetLeastLoadMap() uint64 {
41 | _max_load := uint32(math.MaxUint32)
42 | _tar_map := uint64(0)
43 | for _, _it := range i.M_map_pool {
44 | if _it.M_load < _max_load {
45 | _max_load = _it.M_load
46 | }
47 | _tar_map = _it.M_map_uid
48 | }
49 | return _tar_map
50 | }
51 |
52 | const (
53 | FirstMapUID = 1
54 | )
55 |
56 |
57 | func (i *Info) RPC_FirstEnterMap(user_ UserManager.User) {
58 | i.Info.RPCCall(YMsg.ToAgent("Map", FirstMapUID), "UserEnterMap", user_)
59 | i.Info.RPCCall(YMsg.ToAgent("UserManager"), "UserChangeCurrentMap", user_.M_uid, FirstMapUID)
60 | }
61 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Module/README.md:
--------------------------------------------------------------------------------
1 | ### 登录及进入地图
2 |
3 | ```sequence
4 | Cli->UserMgr:MSG_C2S_Login
5 | Cli->UserMgr:MSG_C2S_EnterMap
6 | UserMgr->MapMgr:RPC_GetLeastLoadMap
7 | MapMgr->UserMgr:RPC_GetLeastLoadMap
8 | UserMgr->Map:RPC_UserEnterMap
9 | Map->UserMgr:RPC_UserEnterMap
10 | Map->UserMgr:RPC_MapLoadChange
11 | UserMgr->Cli:MSG_S2C_Login
12 | ```
13 |
14 | ### 移动
15 |
16 | ```sequence
17 | Cli->UserMgr:MSG_C2S_UserMove
18 | UserMgr->Map:RPC_UserMove
19 | Map->UserMgr:RPC_UserMove
20 | UserMgr->Cli:MSG_S2C_UserMove
21 | ```
22 |
23 | ### 玩家移动并且通知视野内玩家
24 |
25 | ```sequence
26 | Cli->UserMgr:MSG_C2S_UserMove
27 | UserMgr->Map:RPC_UserMove
28 | Map->OtherClis_1:MSG_S2C_EntityChange
29 | Map->OtherClis_2:MSG_S2C_EntityChange
30 | Map->OtherClis_3:MSG_S2C_EntityChange
31 | Map->UserMgr:RPC_UserMove
32 | UserMgr->Cli:MSG_S2C_UserMove
33 | ```
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Module/UserManager/UserInfo.go:
--------------------------------------------------------------------------------
1 | package UserManager
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YEntity"
5 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
6 | move "github.com/yxinyi/YCServer/examples/AoiAstarExample/Server/Logic/Move"
7 | "time"
8 | )
9 |
10 | type User struct {
11 | YEntity.Info
12 | M_uid uint64
13 | M_current_map uint64
14 | M_session_id uint64
15 | M_is_rotbot bool
16 | move.MoveControl
17 | }
18 |
19 | func NewUser(uid_ uint64, session_id_ uint64) *User {
20 | return &User{
21 | M_uid: uid_,
22 | M_session_id: session_id_,
23 | }
24 | }
25 |
26 |
27 | func (u *User) ToClientJson() Msg.UserData {
28 | _user_msg := Msg.UserData{
29 | M_pos: u.M_pos,
30 | M_uid: u.M_uid,
31 | }
32 | return _user_msg
33 | }
34 |
35 | func (u *User) MoveUpdate(time_ time.Time) bool {
36 | return u.MoveControl.MoveUpdate(time_)
37 | }
38 |
39 | func (u *User) CanToNextPath() bool {
40 | return u.MoveControl.CanToNextPath()
41 | }
42 |
--------------------------------------------------------------------------------
/examples/AoiAstarExample/Server/Module/UserManager/UserManager.go:
--------------------------------------------------------------------------------
1 | package UserManager
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YModule"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "github.com/yxinyi/YCServer/examples/AoiAstarExample/Msg"
8 | )
9 |
10 | type Info struct {
11 | YModule.BaseInter
12 | M_user_pool map[uint64]*User
13 | }
14 |
15 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
16 | _info := &Info{
17 | M_user_pool: make(map[uint64]*User),
18 | }
19 | _info.Info = YModule.NewInfo(node_)
20 | return _info
21 | }
22 | func (i *Info) Init() {
23 | i.Info.Init(i)
24 | }
25 |
26 | func (i *Info) Close() {
27 | }
28 |
29 | func (i *Info) MSG_C2S_Login(s_ uint64, msg_ Msg.C2S_Login) {
30 | _, exists := i.M_user_pool[s_]
31 | if !exists {
32 | i.M_user_pool[s_] = NewUser(s_, s_)
33 | }
34 | i.Info.SendNetMsgJson(s_, Msg.S2C_Login{
35 | i.M_user_pool[s_].ToClientJson(),
36 | })
37 | }
38 |
39 | func (i *Info) RPC_UserChangeCurrentMap(s_, map_uid_ uint64) {
40 | _user := i.M_user_pool[s_]
41 | if _user != nil {
42 | _user.M_current_map = map_uid_
43 | }
44 | }
45 |
46 | func (i *Info) MSG_C2S_FirstEnterMap(s_ uint64, msg_ Msg.C2S_FirstEnterMap) {
47 |
48 | _user := i.M_user_pool[s_]
49 | if _user != nil {
50 | i.Info.RPCCall(YMsg.ToAgent("MapManager"), "FirstEnterMap", *_user)
51 | if len(i.M_user_pool) == 1 {
52 | for idx := uint64(10); idx < 101; idx++ {
53 | _robot_user := NewUser(idx, idx)
54 | _robot_user.M_is_rotbot = true
55 | i.M_user_pool[idx] = _robot_user
56 |
57 | i.Info.RPCCall(YMsg.ToAgent("MapManager"), "FirstEnterMap", *_robot_user)
58 | }
59 | }
60 | }
61 | }
62 |
63 | func (i *Info) MSG_C2S_UserMove(s_ uint64, msg_ Msg.C2S_UserMove) {
64 | _user := i.M_user_pool[s_]
65 | if _user == nil {
66 | return
67 | }
68 |
69 | i.Info.RPCCall(YMsg.ToAgent("Map", _user.M_current_map), "UserMove", _user.M_uid, msg_.M_pos)
70 | }
71 |
--------------------------------------------------------------------------------
/examples/NetExample/Client/Main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "github.com/yxinyi/YCServer/engine/YNet"
6 | "github.com/yxinyi/YCServer/examples/NetExample/Msg"
7 | _ "net/http/pprof"
8 | )
9 |
10 | func main() {
11 | flag.Parse()
12 | _client := YNet.NewConnect()
13 | _client.Connect("127.0.0.1:20000")
14 | _client.Start()
15 | _cnt := 1
16 | for {
17 | _client.SendJson(Msg.C2S_TestMsg{
18 | _cnt,
19 | "测试字符串",
20 | })
21 | _client.SendJson(Msg.C2S_TestMsg_2{
22 | _cnt,
23 | })
24 | _cnt++
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/examples/NetExample/Msg/Msg.go:
--------------------------------------------------------------------------------
1 | package Msg
2 |
3 | type C2S_TestMsg struct {
4 | M_val_int int
5 | M_val_str string
6 | }
7 | type C2S_TestMsg_2 struct {
8 | M_val_int int
9 | }
--------------------------------------------------------------------------------
/examples/NetExample/Server/Logic/TestModule/TestModule.go:
--------------------------------------------------------------------------------
1 | package TestModule
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "github.com/yxinyi/YCServer/examples/NetExample/Msg"
8 | )
9 |
10 | type TestInfo struct {
11 | YModule.BaseInter
12 | }
13 |
14 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
15 | _info := &TestInfo{}
16 | _info.Info = YModule.NewInfo(node_)
17 |
18 | return _info
19 | }
20 |
21 | func (m *TestInfo) GetInfo() *YModule.Info {
22 | return m.Info
23 | }
24 | func (m *TestInfo) Init() {
25 | m.Info.Init(m)
26 | }
27 |
28 | func (m *TestInfo) Close() {
29 |
30 | }
31 |
32 | func (m *TestInfo) MSG_C2S_TestMsg(s_ uint64, msg_ Msg.C2S_TestMsg) {
33 | ylog.Info("TestModule[%v]", msg_)
34 | }
35 |
36 | func (m *TestInfo) MSG_C2S_TestMsg_2(s_ uint64, msg_ Msg.C2S_TestMsg_2) {
37 | ylog.Info("TestModule [%v]", msg_)
38 | }
39 |
--------------------------------------------------------------------------------
/examples/NetExample/Server/Logic/TestModule2/TestModule.go:
--------------------------------------------------------------------------------
1 | package TestModule2
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "github.com/yxinyi/YCServer/examples/NetExample/Msg"
8 | )
9 |
10 | type Info struct {
11 | YModule.BaseInter
12 | }
13 |
14 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
15 | _info := &Info{}
16 | _info.Info = YModule.NewInfo(node_)
17 | return _info
18 | }
19 |
20 | func (m *Info) Init() {
21 | m.Info.Init(m)
22 | }
23 |
24 | func (m *Info) Loop() {
25 | m.Info.Loop_Msg()
26 | }
27 | func (m *Info) Close() {
28 | }
29 |
30 | func (m *Info) MSG_C2S_TestMsg(s_ uint64, msg_ Msg.C2S_TestMsg) {
31 | ylog.Info("TestModule2[%v]", msg_)
32 | }
33 |
34 | func (m *Info) MSG_C2S_TestMsg_2(s_ uint64, msg_ Msg.C2S_TestMsg_2) {
35 | ylog.Info("TestModule2 [%v]", msg_)
36 | }
37 |
--------------------------------------------------------------------------------
/examples/NetExample/Server/Main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/BaseModule/NetModule"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YMsg"
7 | "github.com/yxinyi/YCServer/engine/YNode"
8 | "github.com/yxinyi/YCServer/examples/NetExample/Server/Logic/TestModule"
9 | "github.com/yxinyi/YCServer/examples/NetExample/Server/Logic/TestModule2"
10 | _ "net/http/pprof"
11 | )
12 |
13 |
14 | func main() {
15 | YNode.ModuleCreateFuncRegister("NetModule", NetModule.NewInfo)
16 | YNode.ModuleCreateFuncRegister("TestModule", TestModule.NewInfo)
17 | YNode.ModuleCreateFuncRegister("TestModule2", TestModule2.NewInfo)
18 | YNode.SetNodeID(0)
19 | YNode.Register(
20 | YNode.NewModuleInfo("NetModule",0),
21 | YNode.NewModuleInfo("TestModule",0),
22 | YNode.NewModuleInfo("TestModule2",0),
23 | )
24 | YNode.RPCCall(YModule.NewRPCMsg(YMsg.ToAgent("NetModule"), "Listen", "0.0.0.0:20000"))
25 | YNode.Start()
26 | }
27 |
--------------------------------------------------------------------------------
/examples/RPCCallListExample/Logic/TestModule/TestModule.go:
--------------------------------------------------------------------------------
1 | package TestModule
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YMsg"
7 | "github.com/yxinyi/YCServer/engine/YNode"
8 | )
9 |
10 | type TestInfo struct {
11 | YModule.BaseInter
12 | }
13 |
14 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
15 | _info := &TestInfo{}
16 | _info.Info = YModule.NewInfo(node_)
17 |
18 | return _info
19 | }
20 |
21 | func (m *TestInfo) GetInfo() *YModule.Info {
22 | return m.Info
23 | }
24 | func (m *TestInfo) Init() {
25 | m.Info.Init(m)
26 | }
27 |
28 | func (m *TestInfo) Close() {
29 |
30 | }
31 |
32 | func (m *TestInfo) RPC_Test() {
33 | m.Info.RPCCall(YMsg.ToAgent("TestModule2"), "Test_1", func(val int) {
34 | ylog.Info("Test 回调 返回值 [%v]", val)
35 | }).AfterRPC(YMsg.ToAgent("TestModule2"), "Test_2", "测试值", func(val string) {
36 | ylog.Info("Test_2 回调 返回值 [%v]", val)
37 | }).AfterRPC(YMsg.ToAgent("TestModule2"), "Test_3",
38 | ).AfterRPC(YMsg.ToAgent("TestModule2"), "Test_4", func() {
39 | ylog.Info("Test_4 回调 ")
40 | }).AfterRPC(YMsg.ToAgent("TestModule2"), "Test_5",56)
41 |
42 | m.Info.RPCCall(YMsg.ToAgent("TestModule2"), "Test_1", func(val int) {
43 | ylog.Info("Test_1 取消后续调用链 [%v]", val)
44 | m.Info.CancelCBList()
45 | }).AfterRPC(YMsg.ToAgent("TestModule2"), "Test_5", func() {
46 | ylog.Info("[错误] 没有取消 ")
47 | })
48 |
49 | }
50 |
51 | func (m *TestInfo) RPC_Test_4(param_ int) {
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/examples/RPCCallListExample/Logic/TestModule/module_test.go:
--------------------------------------------------------------------------------
1 | package TestModule
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "testing"
8 | )
9 |
10 | func init() {
11 | YNode.Register(NewInfo(YNode.Obj()))
12 | YNode.Start()
13 | }
14 |
15 | func TestModule(t *testing.T) {
16 | {
17 | msg := &YMsg.S2S_rpc_msg{}
18 | msg.M_func_name = "Test_3"
19 | msg.M_func_parameter = make([][]byte, 0)
20 | {
21 |
22 | _bytes, _ := jsoniter.Marshal(1)
23 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
24 | }
25 | {
26 | _bytes, _ := jsoniter.Marshal("123")
27 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
28 | }
29 | YNode.RPCCall(msg)
30 | }
31 | {
32 | msg := &YMsg.S2S_rpc_msg{}
33 | msg.M_func_name = "Test_4"
34 | msg.M_func_parameter = make([][]byte, 0)
35 | {
36 |
37 | _bytes, _ := jsoniter.Marshal(&YMsg.TestParam{
38 | 123,
39 | "TESTPARAMTER",
40 | []int{
41 | 1, 2, 3, 4, 5, 6, 7,
42 | },
43 | })
44 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
45 | }
46 | YNode.RPCCall(msg)
47 | }
48 | }
49 |
50 | func BenchmarkModule(b_ *testing.B) {
51 | for _idx := 0; _idx < b_.N; _idx++ {
52 | {
53 | msg := &YMsg.S2S_rpc_msg{}
54 | msg.M_func_name = "Test"
55 | msg.M_func_parameter = make([][]byte, 0)
56 |
57 | YNode.RPCCall(msg)
58 | }
59 | {
60 | msg := &YMsg.S2S_rpc_msg{}
61 | msg.M_func_name = "Test_2"
62 | msg.M_func_parameter = make([][]byte, 0)
63 | {
64 |
65 | _bytes, _ := jsoniter.Marshal(1)
66 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
67 | }
68 | YNode.RPCCall(msg)
69 | }
70 | {
71 | msg := &YMsg.S2S_rpc_msg{}
72 | msg.M_func_name = "Test_3"
73 | msg.M_func_parameter = make([][]byte, 0)
74 | {
75 |
76 | _bytes, _ := jsoniter.Marshal(1)
77 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
78 | }
79 | {
80 | _bytes, _ := jsoniter.Marshal("123")
81 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
82 | }
83 | YNode.RPCCall(msg)
84 | }
85 | {
86 | msg := &YMsg.S2S_rpc_msg{}
87 | msg.M_func_name = "Test_4"
88 | msg.M_func_parameter = make([][]byte, 0)
89 | {
90 |
91 | _bytes, _ := jsoniter.Marshal(&YMsg.TestParam{
92 | 123,
93 | "TESTPARAMTER",
94 | []int{
95 | 1, 2, 3, 4, 5, 6, 7,
96 | },
97 | })
98 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
99 | }
100 | YNode.RPCCall(msg)
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/examples/RPCCallListExample/Logic/TestModule2/TestModule.go:
--------------------------------------------------------------------------------
1 | package TestModule2
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | )
8 |
9 | type TestInfo struct {
10 | YModule.BaseInter
11 | }
12 |
13 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
14 | _info := &TestInfo{}
15 | _info.Info = YModule.NewInfo(node_)
16 |
17 | return _info
18 | }
19 | func (m *TestInfo) GetInfo() *YModule.Info {
20 | return m.Info
21 | }
22 | func (m *TestInfo) Init() {
23 | m.Info.Init(m)
24 | }
25 |
26 | func (m *TestInfo) Close() {
27 |
28 | }
29 |
30 | func (m *TestInfo) RPC_Test_1() int {
31 | ylog.Info("[TestModule2:Test_1]")
32 | return 10
33 | }
34 |
35 | func (m *TestInfo) RPC_Test_2(val_ string) string {
36 | ylog.Info("[TestModule2:Test_2]")
37 | return val_
38 | }
39 |
40 | func (m *TestInfo) RPC_Test_3() {
41 | ylog.Info("[TestModule2:Test_3]")
42 | }
43 |
44 | func (m *TestInfo) RPC_Test_4() {
45 | ylog.Info("[TestModule2:Test_4]")
46 | }
47 |
48 | func (m *TestInfo) RPC_Test_5(val_ uint32) {
49 | ylog.Info("[TestModule2:Test_5] [%v]",val_)
50 | }
51 |
--------------------------------------------------------------------------------
/examples/RPCCallListExample/Main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "github.com/yxinyi/YCServer/engine/BaseModule/NetModule"
6 | "github.com/yxinyi/YCServer/engine/YModule"
7 | "github.com/yxinyi/YCServer/engine/YMsg"
8 | "github.com/yxinyi/YCServer/engine/YNode"
9 | "github.com/yxinyi/YCServer/examples/RPCCallListExample/Logic/TestModule"
10 | "github.com/yxinyi/YCServer/examples/RPCCallListExample/Logic/TestModule2"
11 | _ "net/http/pprof"
12 | )
13 |
14 | func main() {
15 | flag.Parse()
16 | YNode.ModuleCreateFuncRegister("NetModule", NetModule.NewInfo)
17 | YNode.ModuleCreateFuncRegister("TestModule", TestModule.NewInfo)
18 | YNode.ModuleCreateFuncRegister("TestModule2", TestModule2.NewInfo)
19 | YNode.SetNodeID(0)
20 | YNode.Register(
21 | YNode.NewModuleInfo("NetModule",0),
22 | YNode.NewModuleInfo("TestModule", 0),
23 | YNode.NewModuleInfo("TestModule2", 0),
24 | )
25 | YNode.RPCCall(YModule.NewRPCMsg(YMsg.ToAgent("TestModule"), "Test"))
26 | YNode.Start()
27 | }
28 |
--------------------------------------------------------------------------------
/examples/RPCExample/Logic/TestModule/TestModule.go:
--------------------------------------------------------------------------------
1 | package TestModule
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YMsg"
7 | "github.com/yxinyi/YCServer/engine/YNode"
8 | )
9 |
10 | type TestInfo struct {
11 | YModule.BaseInter
12 | }
13 |
14 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
15 | _info := &TestInfo{}
16 | _info.Info = YModule.NewInfo(node_)
17 |
18 | return _info
19 | }
20 |
21 | func (m *TestInfo) GetInfo() *YModule.Info {
22 | return m.Info
23 | }
24 | func (m *TestInfo) Init() {
25 | m.Info.Init(m)
26 | }
27 |
28 | func (m *TestInfo) Close() {
29 |
30 | }
31 |
32 | func (m *TestInfo) RPC_Test() {
33 | ylog.Info("TestModule RPC_Test")
34 |
35 | }
36 |
37 | func (m *TestInfo) RPC_Test_2(val_ uint32) {
38 | ylog.Info("TestModule RPC_Test_2 [%v]", val_)
39 | }
40 |
41 | func (m *TestInfo) RPC_Test_3(val_ uint32, str_ string) {
42 | ylog.Info("TestModule RPC_Test_3 [%v] [%v]", val_, str_)
43 | var _func func()
44 | _func = func() {
45 | m.Info.RPCCall(YMsg.ToAgent("TestModule2"), "Test", func() {
46 | ylog.Info("Test 回调")
47 | _func()
48 | })
49 | }
50 | _func()
51 | }
52 |
53 | func (m *TestInfo) RPC_Test_4(param_ int) {
54 |
55 | }
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/examples/RPCExample/Logic/TestModule/module_test.go:
--------------------------------------------------------------------------------
1 | package TestModule
2 |
3 | import (
4 | "github.com/json-iterator/go"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "testing"
8 | )
9 |
10 | func init() {
11 | YNode.Register(NewInfo(YNode.Obj()))
12 | YNode.Start()
13 | }
14 |
15 | func TestModule(t *testing.T) {
16 | {
17 | msg := &YMsg.S2S_rpc_msg{}
18 | msg.M_func_name = "Test_3"
19 | msg.M_func_parameter = make([][]byte, 0)
20 | {
21 |
22 | _bytes, _ := jsoniter.Marshal(1)
23 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
24 | }
25 | {
26 | _bytes, _ := jsoniter.Marshal("123")
27 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
28 | }
29 | YNode.RPCCall(msg)
30 | }
31 | {
32 | msg := &YMsg.S2S_rpc_msg{}
33 | msg.M_func_name = "Test_4"
34 | msg.M_func_parameter = make([][]byte, 0)
35 | {
36 |
37 | _bytes, _ := jsoniter.Marshal(&YMsg.TestParam{
38 | 123,
39 | "TESTPARAMTER",
40 | []int{
41 | 1, 2, 3, 4, 5, 6, 7,
42 | },
43 | })
44 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
45 | }
46 | YNode.RPCCall(msg)
47 | }
48 | }
49 |
50 | func BenchmarkModule(b_ *testing.B) {
51 | for _idx := 0; _idx < b_.N; _idx++ {
52 | {
53 | msg := &YMsg.S2S_rpc_msg{}
54 | msg.M_func_name = "Test"
55 | msg.M_func_parameter = make([][]byte, 0)
56 |
57 | YNode.RPCCall(msg)
58 | }
59 | {
60 | msg := &YMsg.S2S_rpc_msg{}
61 | msg.M_func_name = "Test_2"
62 | msg.M_func_parameter = make([][]byte, 0)
63 | {
64 |
65 | _bytes, _ := jsoniter.Marshal(1)
66 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
67 | }
68 | YNode.RPCCall(msg)
69 | }
70 | {
71 | msg := &YMsg.S2S_rpc_msg{}
72 | msg.M_func_name = "Test_3"
73 | msg.M_func_parameter = make([][]byte, 0)
74 | {
75 |
76 | _bytes, _ := jsoniter.Marshal(1)
77 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
78 | }
79 | {
80 | _bytes, _ := jsoniter.Marshal("123")
81 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
82 | }
83 | YNode.RPCCall(msg)
84 | }
85 | {
86 | msg := &YMsg.S2S_rpc_msg{}
87 | msg.M_func_name = "Test_4"
88 | msg.M_func_parameter = make([][]byte, 0)
89 | {
90 |
91 | _bytes, _ := jsoniter.Marshal(&YMsg.TestParam{
92 | 123,
93 | "TESTPARAMTER",
94 | []int{
95 | 1, 2, 3, 4, 5, 6, 7,
96 | },
97 | })
98 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
99 | }
100 | YNode.RPCCall(msg)
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/examples/RPCExample/Logic/TestModule2/TestModule.go:
--------------------------------------------------------------------------------
1 | package TestModule2
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YModule"
6 | "github.com/yxinyi/YCServer/engine/YMsg"
7 | "github.com/yxinyi/YCServer/engine/YNode"
8 | )
9 |
10 | type TestInfo struct {
11 | YModule.BaseInter
12 | }
13 |
14 | func NewInfo(node_ *YNode.Info, uid_ uint64) YModule.Inter {
15 | _info := &TestInfo{}
16 | _info.Info = YModule.NewInfo(node_)
17 |
18 | return _info
19 | }
20 | func (m *TestInfo) GetInfo() *YModule.Info {
21 | return m.Info
22 | }
23 | func (m *TestInfo) Init() {
24 | m.Info.Init(m)
25 | }
26 |
27 | func (m *TestInfo) Close() {
28 |
29 | }
30 |
31 | func (m *TestInfo) RPC_Test() {
32 | ylog.Info("TestModule2 RPC_Test")
33 | }
34 |
35 | func (m *TestInfo) RPC_Test_2(val_ uint32) {
36 | ylog.Info("TestModule2 RPC_Test_2 [%v]", val_)
37 | }
38 |
39 | func (m *TestInfo) RPC_Test_3(val_ uint32, str_ string) float64 {
40 | ylog.Info("TestModule2 RPC_Test_3 [%v] [%v]", val_, str_)
41 | m.Info.RPCCall(YMsg.ToAgent("TestModule"), "Test_3", val_+1, "从 Module2 发出")
42 | return 0.1241423523452342
43 | }
44 |
--------------------------------------------------------------------------------
/examples/RPCExample/Main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "flag"
5 | "github.com/json-iterator/go"
6 | "github.com/yxinyi/YCServer/engine/BaseModule/NetModule"
7 | "github.com/yxinyi/YCServer/engine/YMsg"
8 | "github.com/yxinyi/YCServer/engine/YNode"
9 | "github.com/yxinyi/YCServer/examples/RPCExample/Logic/TestModule"
10 | "github.com/yxinyi/YCServer/examples/RPCExample/Logic/TestModule2"
11 | _ "net/http/pprof"
12 | )
13 |
14 | func main() {
15 | flag.Parse()
16 | YNode.ModuleCreateFuncRegister("NetModule", NetModule.NewInfo)
17 | YNode.ModuleCreateFuncRegister("TestModule", TestModule.NewInfo)
18 | YNode.ModuleCreateFuncRegister("TestModule2", TestModule2.NewInfo)
19 | YNode.SetNodeID(0)
20 | YNode.Register(
21 | YNode.NewModuleInfo("NetModule",0),
22 | YNode.NewModuleInfo("TestModule", 0),
23 | YNode.NewModuleInfo("TestModule2", 0),
24 | )
25 | {
26 | msg := &YMsg.S2S_rpc_msg{}
27 | msg.M_func_name = "Test_3"
28 | msg.M_tar.M_module_name = "TestModule"
29 | msg.M_func_parameter = make([][]byte, 0)
30 | {
31 | _bytes, _ := jsoniter.Marshal(1)
32 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
33 | }
34 | {
35 | _bytes, _ := jsoniter.Marshal("测试")
36 | msg.M_func_parameter = append(msg.M_func_parameter, _bytes)
37 | }
38 | YNode.RPCCall(msg)
39 | }
40 | YNode.Start()
41 | }
42 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Client/Client.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/hajimehoshi/ebiten/v2"
6 | "github.com/yxinyi/YCServer/engine/YNet"
7 | "github.com/yxinyi/YCServer/engine/YTool"
8 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
9 | "log"
10 | )
11 |
12 | var g_client_cnn = YNet.NewConnect()
13 | var g_sync_queue = YTool.NewSyncQueue()
14 |
15 | func main() {
16 | fmt.Println("Client start")
17 | g_client_cnn.Connect("127.0.0.1:20000")
18 | g_client_cnn.Start()
19 | g_client_cnn.SendJson(Msg.C2S_Login{})
20 | g_client_cnn.SendJson(Msg.C2S_FirstEnterMap{})
21 | game, err := NewMainGame()
22 | if err != nil {
23 | log.Fatal(err.Error())
24 | }
25 | ebiten.SetWindowSize(ScreenWidth, ScreenHeight)
26 | ebiten.SetWindowTitle("mmo aoi test")
27 | if err := ebiten.RunGame(game); err != nil {
28 | log.Fatal(err.Error())
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Client/Game.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/hajimehoshi/ebiten/v2"
5 | "github.com/yxinyi/YCServer/engine/YNet"
6 | "image/color"
7 | "math/rand"
8 | "time"
9 | )
10 |
11 | func init() {
12 | rand.Seed(time.Now().UnixNano())
13 | g_map.Init()
14 | }
15 |
16 | // Game represents a game state.
17 | type Game struct {
18 | }
19 |
20 | // NewGame generates a new Game object.
21 | func NewMainGame() (*Game, error) {
22 | g := &Game{
23 | }
24 | var err error
25 | if err != nil {
26 | return nil, err
27 | }
28 | return g, nil
29 | }
30 |
31 | // Layout implements ebiten.Game's Layout.
32 | func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
33 | return ScreenWidth, ScreenHeight
34 | }
35 |
36 | // Update updates the current game state.
37 | func (g *Game) Update() error {
38 |
39 | for more := true; more; {
40 | select {
41 | case _net_msg := <-YNet.G_net_msg_chan:
42 | YNet.Dispatch(_net_msg.M_session, _net_msg.M_net_msg)
43 | default:
44 | more = false
45 | }
46 | }
47 | g_map.Update()
48 | return nil
49 | }
50 |
51 | // Draw draws the current game to the given screen.
52 | func (g *Game) Draw(screen *ebiten.Image) {
53 | screen.Fill(color.NRGBA{0x00, 0x40, 0x80, 0xff})
54 | g_map.Draw(screen)
55 | }
56 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Client/Map.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/hajimehoshi/ebiten/v2"
6 | "github.com/hajimehoshi/ebiten/v2/ebitenutil"
7 | "github.com/hajimehoshi/ebiten/v2/inpututil"
8 | "github.com/hajimehoshi/ebiten/v2/text"
9 | "github.com/yxinyi/YCServer/engine/YNet"
10 | "github.com/yxinyi/YCServer/engine/YTool"
11 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
12 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Util"
13 | "golang.org/x/image/font"
14 | "golang.org/x/image/font/gofont/goregular"
15 | "golang.org/x/image/font/opentype"
16 | "image/color"
17 | "log"
18 | "math"
19 | )
20 |
21 | const (
22 | ScreenWidth = 1280
23 | ScreenHeight = 720
24 | userGridSize = 5
25 | )
26 |
27 | var g_center_pos = YTool.PositionXY{float64(ScreenWidth / 2), float64(ScreenHeight / 2)}
28 |
29 | var uiFont font.Face
30 |
31 | type Map struct {
32 | m_user_list map[uint64]Msg.UserData
33 | }
34 |
35 | func NewMap() *Map {
36 | return &Map{
37 | m_user_list: make(map[uint64]Msg.UserData),
38 | }
39 | }
40 |
41 | var g_map = NewMap()
42 | var g_main_uid uint64
43 | var g_main_path_node []YTool.PositionXY
44 | var g_main_check_node []YTool.PositionXY
45 |
46 | type MapMazeInfo struct {
47 | M_msg *Msg.S2C_AllSyncMapInfo
48 | *YTool.Rectangle
49 | M_grid_size float64
50 | }
51 |
52 | func NewMapMazeInfo(msg_ *Msg.S2C_AllSyncMapInfo) *MapMazeInfo {
53 | _info := &MapMazeInfo{}
54 | _info.M_msg = msg_
55 | _info.Rectangle = YTool.NewRectangle()
56 | _up_down_offset, _left_right_offset := Util.MapOffDiff(0x7FFFFFFF<<32|0x7FFFFFFF, msg_.M_map_uid)
57 |
58 | _left_up := &YTool.PositionXY{
59 | M_x: float64(_left_right_offset) * msg_.M_width,
60 | M_y: float64(_up_down_offset) * msg_.M_height,
61 | }
62 | _right_down := &YTool.PositionXY{
63 | M_x: _left_up.M_x + msg_.M_width,
64 | M_y: _left_up.M_y + msg_.M_height,
65 | }
66 | _info.Rectangle.InitForLefUPRightDown(_left_up, _right_down)
67 | _info.M_grid_size = msg_.M_height / float64(len(msg_.M_maze))
68 | return _info
69 | }
70 |
71 | var g_map_maze_info = make(map[uint64]*MapMazeInfo)
72 |
73 | func (m *Map) Init() {
74 | tt, err := opentype.Parse(goregular.TTF)
75 | if err != nil {
76 | log.Fatal(err.Error())
77 | }
78 | uiFont, _ = opentype.NewFace(tt, &opentype.FaceOptions{
79 | Size: 12,
80 | DPI: 72,
81 | Hinting: font.HintingFull,
82 | })
83 | ebiten.SetMaxTPS(150)
84 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_FirstEnterMap) {
85 | m.UpdateUser(msg_.M_data)
86 | })
87 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_AllSyncMapInfo) {
88 | g_map_maze_info[msg_.M_map_uid] = NewMapMazeInfo(&msg_)
89 | })
90 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_Login) {
91 | g_main_uid = msg_.M_main_uid
92 | //m.AddNewUser(msg_.M_defalut_value)
93 | })
94 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2C_MapAStarNodeUpdate) {
95 | g_main_path_node = msg_.M_path
96 | })
97 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2CMapAddUser) {
98 | for _, _it := range msg_.M_user {
99 | m.AddNewUser(_it)
100 | }
101 | })
102 |
103 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2CMapUpdateUser) {
104 | //atomic.AddInt32(&_msg_count, 1)
105 | for _, _it := range msg_.M_user {
106 | if _it.M_current_map_id != m.MainMapID() {
107 | fmt.Printf("b[%v]a[%v]\n", m.MainMapID(), _it.M_current_map_id)
108 | }
109 | fmt.Printf("pos[%v]\n", _it.M_pos.DebugString())
110 |
111 | m.UpdateUser(_it)
112 | }
113 | })
114 | YNet.Register(func(_ YNet.Session, msg_ Msg.S2CMapDeleteUser, ) {
115 | for _, _it := range msg_.M_user {
116 | m.DeleteUser(_it.M_uid)
117 | }
118 | })
119 |
120 | }
121 | func (m *Map) DeleteUser(uid_ uint64) {
122 | delete(m.m_user_list, uid_)
123 | }
124 |
125 | func (m *Map) AddNewUser(user_data_ Msg.UserData) {
126 | m.m_user_list[user_data_.M_uid] = user_data_
127 | }
128 |
129 | var g_slope string
130 |
131 | func (m *Map) UpdateUser(user_data_ Msg.UserData) {
132 |
133 | if g_main_uid == user_data_.M_uid {
134 | g_slope = fmt.Sprintf("%.2f", (user_data_.M_pos.M_y-m.m_user_list[user_data_.M_uid].M_pos.M_y)/(user_data_.M_pos.M_x-m.m_user_list[user_data_.M_uid].M_pos.M_x))
135 | }
136 | m.m_user_list[user_data_.M_uid] = user_data_
137 | }
138 |
139 | func (m *Map) UserMove(msg_ Msg.S2C_MOVE, _ YNet.Session) {
140 | m.m_user_list[msg_.M_uid] = msg_.M_data
141 | }
142 |
143 | func (m *Map) MainMapID() uint64 {
144 | return m.m_user_list[g_main_uid].M_current_map_id
145 | }
146 |
147 | func (m *Map) MainMapInfo() *MapMazeInfo {
148 | return g_map_maze_info[m.MainMapID()]
149 | }
150 |
151 | func (m *Map) MainPos() YTool.PositionXY {
152 | return m.m_user_list[g_main_uid].M_pos
153 | }
154 |
155 | func (m *Map) Update() {
156 | if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
157 | _tar_x, _tar_y := ebiten.CursorPosition()
158 | _x_diff := float64(_tar_x) - g_center_pos.M_x
159 | _y_diff := float64(_tar_y) - g_center_pos.M_y
160 |
161 | _fix_tar_pos := &YTool.PositionXY{
162 | m.MainPos().M_x + _x_diff,
163 | m.MainPos().M_y + _y_diff,
164 | }
165 |
166 | _tar_map := uint64(0)
167 |
168 | _msg := Msg.C2S_UserMove{
169 | _tar_map,
170 | *_fix_tar_pos,
171 | }
172 | //fmt.Printf("[%v]", _msg.M_tar_map_uid)
173 | g_client_cnn.SendJson(_msg)
174 | }
175 |
176 | if inpututil.IsKeyJustPressed(ebiten.KeyT) {
177 | switch ebiten.MaxTPS() {
178 | case 30:
179 | ebiten.SetMaxTPS(60)
180 | case 60:
181 | ebiten.SetMaxTPS(90)
182 | case 90:
183 | ebiten.SetMaxTPS(120)
184 | case 120:
185 | ebiten.SetMaxTPS(150)
186 | case 150:
187 | ebiten.SetMaxTPS(30)
188 | }
189 |
190 | }
191 | }
192 |
193 | func (m *Map) InViewRange(pos YTool.PositionXY) bool {
194 | _distance := pos.GetOffset(m.MainPos())
195 | if math.Abs(_distance.M_x) > ScreenWidth/2-10 || math.Abs(_distance.M_y) > ScreenHeight/2-10 {
196 | return false
197 | }
198 | return true
199 | }
200 |
201 | func (m *Map) PosConvert(pos YTool.PositionXY) YTool.PositionXY {
202 |
203 | _main_user_pos := m.MainPos()
204 |
205 | _x_diff := g_center_pos.M_x - _main_user_pos.M_x
206 | _y_diff := g_center_pos.M_y - _main_user_pos.M_y
207 | pos.M_x += _x_diff
208 | pos.M_y += _y_diff
209 | return pos
210 | }
211 |
212 | func (m *Map) Draw(screen *ebiten.Image) {
213 | //fmt.Printf("[%v] [%v]\n", m.MainMapID(), m.MainPos().DebugString())
214 | _is_show := 0
215 | _show_pos := YTool.PositionXY{}
216 |
217 | _round_map := make(map[uint64]struct{})
218 | _round_map[m.MainMapID()] = struct{}{}
219 | _round_map[m.MainMapID()-1] = struct{}{}
220 | _round_map[m.MainMapID()+1] = struct{}{}
221 | _round_map[m.MainMapID()+(1<<32)] = struct{}{}
222 | _round_map[m.MainMapID()-(1<<32)] = struct{}{}
223 | _round_map[m.MainMapID()+(1<<32)+1] = struct{}{}
224 | _round_map[m.MainMapID()+(1<<32)-1] = struct{}{}
225 | _round_map[m.MainMapID()-(1<<32)+1] = struct{}{}
226 | _round_map[m.MainMapID()-(1<<32)-1] = struct{}{}
227 |
228 | for _map_uid_it := range _round_map {
229 | _map_it := g_map_maze_info[_map_uid_it]
230 | if _map_it == nil{
231 | continue
232 | }
233 | for _row_idx_it, _row_it := range _map_it.M_msg.M_maze {
234 | _row_idx := _row_idx_it
235 | for _col_idx_it, _block_val := range _row_it {
236 | _col_idx := _col_idx_it
237 | if _block_val != 0 {
238 | _block_pos := YTool.PositionXY{float64(_col_idx)*_map_it.M_grid_size + _map_it.LeftUp.M_x, float64(_row_idx)*_map_it.M_grid_size + _map_it.LeftUp.M_y}
239 | if !m.InViewRange(_block_pos) {
240 | continue
241 | }
242 | _block_pos = m.PosConvert(_block_pos)
243 | if _map_it.M_msg.M_map_uid == 9223372034707292159 && _is_show == 0 {
244 | _is_show = 1
245 | _show_pos = _block_pos
246 | }
247 | _rgb := color.RGBA{
248 | uint8(((_map_it.M_msg.M_map_uid>>32)+100-0x7fffffff)*77) & 0xff,
249 | uint8(((_map_it.M_msg.M_map_uid)+133-0x7fffffff)*155) & 0xff,
250 | uint8(((_map_it.M_msg.M_map_uid>>32)+211-0x7fffffff)*211) & 0xff,
251 | 0xff,
252 | }
253 | /* if _row_idx == 0 && _col_idx == 0 {
254 | fmt.Printf("first block [%v]\n", _block_pos.DebugString())
255 | }*/
256 | ebitenutil.DrawRect(screen, _block_pos.M_x, _block_pos.M_y, _map_it.M_grid_size, _map_it.M_grid_size, _rgb)
257 | }
258 | }
259 | }
260 | }
261 | gridSize := float64(10)
262 | for _, it := range m.m_user_list {
263 | for _, path_it := range it.M_path {
264 | if !m.InViewRange(path_it) {
265 | continue
266 | }
267 | _path_pos := m.PosConvert(path_it)
268 | ebitenutil.DrawRect(screen, _path_pos.M_x, _path_pos.M_y, gridSize, gridSize, color.RGBA{0xff, 0x00, 0x00, 0xff})
269 | }
270 | }
271 |
272 | for _, path_it := range g_main_path_node {
273 | if !m.InViewRange(path_it) {
274 | continue
275 | }
276 | _path_pos := m.PosConvert(path_it)
277 | ebitenutil.DrawRect(screen, _path_pos.M_x, _path_pos.M_y, gridSize, gridSize, color.RGBA{0xff, 0x00, 0x00, 0xff})
278 | }
279 |
280 | for _uid_it, it := range m.m_user_list {
281 | if !m.InViewRange(it.M_pos) {
282 | continue
283 | }
284 | /* if m.m_user_list[_uid_it].M_pos.Distance(it.M_pos) > 100 {
285 | panic("1")
286 | }*/
287 |
288 | if g_main_uid == _uid_it {
289 | //detailStr := fmt.Sprintf("%.2f,%.2f", it.M_pos.M_x, it.M_pos.M_y)
290 | //text.Draw(screen, detailStr, uiFont, int(it.M_pos.M_x), int(it.M_pos.M_y+20), color.White)
291 | _main_user := m.PosConvert(YTool.PositionXY{it.M_pos.M_x + (gridSize-userGridSize)/2, it.M_pos.M_y + (gridSize-userGridSize)/2})
292 | ebitenutil.DrawRect(screen, _main_user.M_x, _main_user.M_y, userGridSize, userGridSize, color.RGBA{0xff, 0xa0, 0x00, 0xff})
293 | } else {
294 | //detailStr := fmt.Sprintf("%.2f,%.2f", it.M_pos.M_x, it.M_pos.M_y)
295 | //text.Draw(screen, detailStr, uiFont, int(it.M_pos.M_x), int(it.M_pos.M_y+20), color.White)
296 | _main_user := m.PosConvert(YTool.PositionXY{it.M_pos.M_x + (gridSize-userGridSize)/2, it.M_pos.M_y + (gridSize-userGridSize)/2})
297 | ebitenutil.DrawRect(screen, _main_user.M_x, _main_user.M_y, userGridSize, userGridSize, color.RGBA{0x80, 0xa0, 0x00, 0xff})
298 | //ebitenutil.DrawRect(screen, it.M_pos.M_x+(gridSize-userGridSize)/2, it.M_pos.M_y+(gridSize-userGridSize)/2, userGridSize, userGridSize, color.RGBA{0x80, 0xa0, 0xc0, 0xff})
299 | }
300 | }
301 |
302 | ebitenutil.DebugPrint(screen, fmt.Sprintf("MAX: %d\nTPS: %0.2f\nFPS: %0.2f \nCM[%v]\nPOS[%v] \nFP[%v]", ebiten.MaxTPS(), ebiten.CurrentTPS(), ebiten.CurrentFPS(), m.MainMapID(), m.MainPos().DebugString(), _show_pos.DebugString()))
303 |
304 | {
305 | detailStr := fmt.Sprintf("%d,%d", 100, 100)
306 | text.Draw(screen, detailStr, uiFont, int(100), int(100), color.White)
307 | }
308 | {
309 | detailStr := fmt.Sprintf("%d,%d", 400, 100)
310 | text.Draw(screen, detailStr, uiFont, int(400), int(100), color.White)
311 | }
312 | {
313 | detailStr := fmt.Sprintf("%d,%d", 100, 400)
314 | text.Draw(screen, detailStr, uiFont, int(100), int(400), color.White)
315 | }
316 |
317 | }
318 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Msg/msg.go:
--------------------------------------------------------------------------------
1 | package Msg
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | )
6 |
7 | type Message struct {
8 | Id int
9 | Number int
10 | }
11 |
12 | type UserData struct {
13 | M_uid uint64
14 | M_current_map_id uint64
15 | M_pos YTool.PositionXY
16 | M_path []YTool.PositionXY
17 | }
18 |
19 | type C2SUserMove struct {
20 | M_pos YTool.PositionXY
21 | }
22 |
23 | type S2C_MOVE struct {
24 | M_uid uint64
25 | M_data UserData
26 | }
27 |
28 | type S2CMapFullSync struct {
29 | M_user []UserData
30 | }
31 |
32 | type S2CMapAddUser struct {
33 | M_user []UserData
34 | }
35 | type S2CMapUpdateUser struct {
36 | M_user []UserData
37 | }
38 | type S2CMapDeleteUser struct {
39 | M_user []UserData
40 | }
41 | type S2C_MapAStarNodeUpdate struct {
42 | M_uid uint64
43 | M_path []YTool.PositionXY
44 | }
45 |
46 | type C2S_Login struct {
47 | }
48 |
49 | type S2C_Login struct {
50 | M_main_uid uint64
51 | //M_defalut_value UserData
52 | }
53 |
54 | type C2S_FirstEnterMap struct {
55 | }
56 |
57 | type S2C_FirstEnterMap struct {
58 | M_data UserData
59 | }
60 |
61 | type S2C_AllSyncMapInfo struct {
62 | M_map_uid uint64
63 | M_maze [][]float64
64 | M_height float64
65 | M_width float64
66 | M_overlap float64
67 | M_gird_size float64
68 | }
69 |
70 | type C2S_UserMove struct {
71 | M_tar_map_uid uint64
72 | M_pos YTool.PositionXY
73 | }
74 |
75 | type MapLoad struct {
76 | M_map_uid uint64
77 | M_load uint32
78 | }
79 |
80 | type S2S_SyncOtherNodeRPC struct {
81 | M_net_msg []string
82 | M_node_id uint32
83 | }
84 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Logic/Move/MoveControl.go:
--------------------------------------------------------------------------------
1 | package move
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YTool"
5 | "time"
6 | )
7 |
8 | type MoveControl struct {
9 | M_pos YTool.PositionXY
10 | M_tar YTool.PositionXY
11 | M_next_path YTool.PositionXY
12 | M_speed float64
13 | M_last_move_time time.Time
14 | M_view_range float64
15 | M_path_cur_idx int
16 | M_path []YTool.PositionXY
17 | }
18 |
19 | func (c *MoveControl) CanToNextPath() bool {
20 | if c.M_path_cur_idx == len(c.M_path) {
21 | return false
22 | }
23 |
24 | return true
25 | }
26 |
27 | func (c *MoveControl) DebugString() string {
28 | _str := ""
29 | /* for _idx := 0; _idx < c.M_path_queue.Length(); _idx++ {
30 | _str += c.M_path_queue.Get(_idx).(YTool.PositionXY).DebugString()
31 | }*/
32 |
33 | return _str
34 | }
35 |
36 | func (c *MoveControl) ClearPathNode() {
37 | c.M_path = c.M_path[:0]
38 | }
39 |
40 | func (c *MoveControl) GetPathNode() []YTool.PositionXY {
41 | return c.M_path
42 | }
43 |
44 | func (c *MoveControl) toNextPath() {
45 | c.M_next_path = c.M_path[c.M_path_cur_idx]
46 | c.M_path_cur_idx++
47 | }
48 |
49 | func (c *MoveControl) MoveQueue(path_queue_ *YTool.Queue) {
50 | c.M_path_cur_idx = 0
51 | _path_node := make([]YTool.PositionXY, 0)
52 | for _idx := 0; _idx < path_queue_.Length(); _idx++ {
53 | _path_node = append(_path_node, path_queue_.Get(_idx).(YTool.PositionXY))
54 | }
55 | c.M_path = _path_node
56 | c.toNextPath()
57 | }
58 | func (c *MoveControl) MoveTarget(tar_ YTool.PositionXY) {
59 | c.M_tar = tar_
60 | }
61 |
62 | func (c *MoveControl) MoveUpdate(time_ time.Time) bool {
63 | defer func() {
64 | c.M_last_move_time = time_
65 | }()
66 |
67 | if c.M_pos.IsSame(c.M_tar) {
68 | return false
69 | }
70 |
71 | if c.M_pos.IsSame(c.M_next_path) {
72 | if !c.CanToNextPath() {
73 | return false
74 | }
75 | c.toNextPath()
76 | }
77 |
78 | _distance := c.M_pos.Distance(&c.M_next_path)
79 |
80 | _interval_time := time_.Sub(c.M_last_move_time).Seconds()
81 | _this_move_distance := _interval_time * c.M_speed
82 |
83 | if _distance < _this_move_distance {
84 | c.M_pos = c.M_next_path
85 | return true
86 | }
87 | _precent := _this_move_distance / _distance
88 |
89 | _distance_pos := c.M_pos.GetOffset(c.M_next_path)
90 |
91 | c.M_pos.M_x += _distance_pos.M_x * _precent
92 | c.M_pos.M_y += _distance_pos.M_y * _precent
93 |
94 | return true
95 | }
96 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/spf13/pflag"
6 | "github.com/spf13/viper"
7 | "github.com/yxinyi/YCServer/engine/YConfig"
8 | "github.com/yxinyi/YCServer/engine/YModule"
9 | "github.com/yxinyi/YCServer/engine/YMsg"
10 | "github.com/yxinyi/YCServer/engine/YNode"
11 | "github.com/yxinyi/YCServer/engine/YTool"
12 | "log"
13 | "net/http"
14 | _ "net/http/pprof"
15 | )
16 |
17 | type NodeCfg struct {
18 | NodeID uint32
19 | Port uint32
20 | PprofPort uint32
21 | Modules []string
22 | }
23 | type NodeCfgList struct {
24 | CfgList []NodeCfg
25 | }
26 |
27 | func init() {
28 | pflag.Uint("NodeID", 0, "服务器ID")
29 | }
30 | func main() {
31 | pflag.Parse()
32 | ModuleCreateFuncLoad()
33 | viper.BindPFlags(pflag.CommandLine)
34 |
35 | YNode.SetNodeID(viper.GetUint32("NodeID"))
36 |
37 | var _node_cfg_list NodeCfgList
38 | YConfig.Load("node_cfg.json", &_node_cfg_list)
39 | YTool.JsonPrint(_node_cfg_list)
40 |
41 | YNode.Register(
42 | YNode.NewModuleInfo("NetModule",0),
43 | )
44 | for _, _node_it := range _node_cfg_list.CfgList {
45 | if _node_it.NodeID == viper.GetUint32("NodeID") {
46 | _listen_addr := fmt.Sprintf("0.0.0.0:%d", _node_it.Port)
47 | YNode.RPCCall(YModule.NewRPCMsg(YMsg.ToAgent("NetModule"), "Listen", _listen_addr))
48 | go func() {
49 | log.Fatal(http.ListenAndServe(fmt.Sprintf("0.0.0.0:%d", _node_it.PprofPort), nil))
50 | }()
51 | for _, _module_it := range _node_it.Modules {
52 | YNode.RPCCall(YModule.NewRPCMsg(YMsg.ToAgent("YNode", uint64(_node_it.NodeID)), "NewModule", _module_it, 0))
53 | }
54 | } else {
55 | _connect_port := fmt.Sprintf("127.0.0.1:%d", _node_it.Port)
56 | YNode.RPCCall(YModule.NewRPCMsg(YMsg.ToAgent("NetModule"), "Connect", _connect_port))
57 | YNode.RegisterNodeIpStr2NodeId(_connect_port, _node_it.NodeID)
58 | }
59 | }
60 | YNode.Start()
61 | }
62 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Module/Map/API.go:
--------------------------------------------------------------------------------
1 | package Map
2 |
3 | import (
4 | ylog "github.com/yxinyi/YCServer/engine/YLog"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YTool"
7 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
8 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Module/UserManager"
9 | "time"
10 | )
11 |
12 | func (m *Info) RPC_UserEnterMap(user_ UserManager.User) {
13 | _user := &User{
14 | M_uid: user_.M_uid,
15 | M_current_map: user_.M_current_map,
16 | M_session_id: user_.M_session_id,
17 | }
18 | m.M_user_pool[_user.M_uid] = _user
19 | _user.M_current_map = m.m_map_uid
20 | _user.M_speed = 100
21 | _user.M_view_range = 1000
22 |
23 | m.randPos(_user)
24 | m.Info.SendNetMsgJson(_user.GetSessionID(), Msg.S2C_FirstEnterMap{
25 | _user.ToClientJson(),
26 | })
27 |
28 | m.RPC_SyncMapInfoToClient(_user.GetSessionID())
29 |
30 | m.m_aoi.Enter(_user.M_uid, _user.GetMoveControl().M_view_range, _user.GetMoveControl().M_pos)
31 | //负载均衡同步
32 | m.NotifyMapLoad()
33 | }
34 |
35 | func (m *Info) RPC_SyncMapInfoToClient(s_ uint64) {
36 | _msg := Msg.S2C_AllSyncMapInfo{
37 | m.m_map_uid,
38 | make([][]float64, int(m.m_vaild_col_grid)),
39 | m.m_vaild_height,
40 | m.m_vaild_width,
41 | float64(m.m_overlap_count),
42 | m.m_gird_size,
43 | }
44 |
45 | _col_loop := 0
46 | for _col_idx := int(m.m_overlap_count); _col_idx < int(m.m_overlap_count+m.m_vaild_col_grid); _col_idx++ {
47 | _msg.M_maze[_col_loop] = make([]float64, int(m.m_vaild_row_grid))
48 | _row_loop := 0
49 | for _row_idx := int(m.m_overlap_count); _row_idx < int(m.m_overlap_count+m.m_vaild_row_grid); _row_idx++ {
50 | _msg.M_maze[_col_loop][_row_loop] = m.m_go_astar.GetMaze()[_col_idx][_row_idx]
51 | _row_loop++
52 | }
53 | _col_loop++
54 | }
55 |
56 | m.Info.SendNetMsgJson(s_, _msg)
57 | }
58 |
59 | func (m *Info) RPC_UserQuitMap(user_ UserManager.User) {
60 | delete(m.M_user_pool, user_.M_uid)
61 | user_.M_current_map = 0
62 | //负载均衡同步
63 | m.NotifyMapLoad()
64 | }
65 |
66 | func (m *Info) RPC_UserMove(user_uid_ uint64, move_msg_ Msg.C2S_UserMove) {
67 |
68 | //_map_pos := m.ClientPosConvertMapPos(move_msg_.M_pos)
69 | _map_pos := move_msg_.M_pos
70 | _map_pos.M_x = float64(int(_map_pos.M_x))
71 | _map_pos.M_y = float64(int(_map_pos.M_y))
72 | if m.m_go_astar.IsBlock(m.MapPosConvertMapIdx(_map_pos)) {
73 | return
74 | }
75 | if m.isGhostUser(user_uid_) {
76 | return
77 | }
78 |
79 | _user, exists := m.M_user_pool[user_uid_]
80 | if !exists {
81 | return
82 | }
83 | if _user.M_map_swtich_state == UserManager.CONST_MAP_SWITCHING {
84 | return
85 | }
86 | ylog.Info("[RPC_UserMove] tar [%v]", _map_pos.DebugString())
87 | _user.MoveTarget(_map_pos)
88 |
89 | m.m_go_astar.Search(m.MapPosConvertMapIdx(_user.M_pos), m.MapPosConvertMapIdx(_user.M_tar), func(path_ []int) {
90 | _user, exists := m.M_user_pool[_user.M_uid]
91 | if !exists {
92 | return
93 | }
94 | if len(path_) == 0 {
95 | return
96 | }
97 | _target_indx := m.MapPosConvertMapIdx(_user.M_tar)
98 | if path_[len(path_)-1] != _target_indx {
99 | return
100 | }
101 | _path_idx := m.IdxListConvertPosList(path_)
102 |
103 | _path_pos := make([]YTool.PositionXY, 0, len(path_))
104 | for _, _it := range path_ {
105 | _path_pos = append(_path_pos, m.MapIdxConvertMapPos(_it))
106 | }
107 |
108 | _user.GetMoveControl().MoveQueue(_path_idx)
109 | m.Info.SendNetMsgJson(_user.GetSessionID(), Msg.S2C_MapAStarNodeUpdate{
110 | _user.M_uid,
111 | _path_pos,
112 | })
113 | })
114 | }
115 |
116 | func (m *Info) RPC_RegisterNeighborMap(neighbor_map_list_ []uint64) {
117 | for _, _map_id := range neighbor_map_list_ {
118 | _, _exists := m.m_neighbor_uid[_map_id]
119 | if !_exists {
120 | m.m_neighbor_uid[_map_id] = struct{}{}
121 | //判断邻居位于本地图的哪个位置,发送边缘N行或N列地图作为缓冲切换边缘
122 | //暂时固定发送10行
123 | var _sync_map_info [][]float64
124 | _sync_line_count := 10
125 | _col_start_index, _col_end_index, _row_start_index, _row_end_index := m.MapSyncOverlapColRowRange(_map_id)
126 | _sync_map_info = make([][]float64, _col_end_index-_col_start_index+1)
127 | _col_set_idx := 0
128 | for _col_idx := _col_start_index; _col_idx < _col_end_index; _col_idx++ {
129 | _row_line_info := make([]float64, _row_end_index-_row_start_index+1)
130 | _row_set_idx := 0
131 | for _row_idx := _row_start_index; _row_idx < _row_end_index; _row_idx++ {
132 | _row_line_info[_row_set_idx] = m.m_go_astar.GetMaze()[_col_idx][_row_idx]
133 | _row_set_idx++
134 | }
135 | _sync_map_info[_col_set_idx] = _row_line_info
136 | _col_set_idx++
137 | }
138 | m.Info.RPCCall(YMsg.ToAgent("Map", _map_id), "SyncOverlapBlock", _sync_map_info, m.m_map_uid, _sync_line_count)
139 | }
140 | }
141 | }
142 |
143 | func (m *Info) RPC_SyncOverlapBlock(overlap_map_info_ [][]float64, over_map_uid_ uint64, over_map_line_ int) {
144 | _col_start_index, _col_end_index, _row_start_index, _row_end_index := m.MapSetOverlapColRowRange(over_map_uid_)
145 | _col_get_idx := 0
146 | for _col_idx := _col_start_index; _col_idx < _col_end_index; _col_idx++ {
147 | _row_get_idx := 0
148 | for _row_idx := _row_start_index; _row_idx < _row_end_index; _row_idx++ {
149 | m.m_go_astar.GetMaze()[_col_idx][_row_idx] = overlap_map_info_[_col_get_idx][_row_get_idx]
150 | _row_get_idx++
151 | }
152 | _col_get_idx++
153 | }
154 |
155 | for _, _it := range m.M_user_pool {
156 | m.RPC_SyncMapInfoToClient(_it.M_session_id)
157 | }
158 | }
159 | func (m *Info) RPC_UserConvertToThisMap(user_uid_ uint64) {
160 | _user := m.M_user_pool[user_uid_]
161 | _user.M_current_map = m.m_map_uid
162 | _user.M_last_move_time = time.Now()
163 | _user.M_map_swtich_state = UserManager.CONST_MAP_SWITCH_NONE
164 | {
165 | _update_msg := Msg.S2CMapUpdateUser{
166 | M_user: make([]Msg.UserData, 0),
167 | }
168 | _update_msg.M_user = append(_update_msg.M_user, _user.ToClientJson())
169 | m.SendNetMsgJson(_user.M_session_id, _update_msg)
170 | }
171 | m.m_aoi.Move(_user.M_uid, _user.M_pos)
172 | m.Info.RPCCall(YMsg.ToAgent("UserManager"), "UserChangeCurrentMap", user_uid_, _user.M_current_map)
173 | m.Info.RPCCall(YMsg.ToAgent("UserManager"), "UserFinishSwitchMap", user_uid_)
174 |
175 | }
176 | func (m *Info) RPC_SyncGhostUser(user_ User) {
177 | _, exists := m.M_user_pool[user_.M_uid]
178 | if !exists {
179 | m.RPC_SyncMapInfoToClient(user_.M_session_id)
180 | m.m_aoi.Enter(user_.M_uid, user_.M_view_range, user_.M_pos)
181 | m.M_user_pool[user_.M_uid] = &user_
182 | } else {
183 | m.m_aoi.Move(user_.M_uid, user_.M_pos)
184 | m.M_user_pool[user_.M_uid] = &user_
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Module/Map/Info.go:
--------------------------------------------------------------------------------
1 | package Map
2 |
3 | import (
4 | aoi "github.com/yxinyi/YCServer/engine/YAoi"
5 | "github.com/yxinyi/YCServer/engine/YAttr"
6 | "github.com/yxinyi/YCServer/engine/YEntity"
7 | "github.com/yxinyi/YCServer/engine/YJson"
8 | ylog "github.com/yxinyi/YCServer/engine/YLog"
9 | "github.com/yxinyi/YCServer/engine/YModule"
10 | "github.com/yxinyi/YCServer/engine/YPathFinding"
11 | "github.com/yxinyi/YCServer/engine/YTool"
12 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
13 | move "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Logic/Move"
14 | "time"
15 | )
16 |
17 | func init() {
18 | YEntity.RegisterEntityAttr("User",
19 | YAttr.Define("MapInfo",
20 | YAttr.Tmpl("CurrentMap", uint64(0), true, true, true, true),
21 | YAttr.Tmpl("SessionID", uint64(0), true, true, true, true),
22 | YAttr.Tmpl("MapSwitchState", uint64(0), true, true, true, true),
23 | YAttr.Tmpl("MoveControl", move.MoveControl{}, true, true, true, true),
24 | ),
25 | )
26 | }
27 |
28 | type User struct {
29 | //*YEntity.Info
30 | M_uid uint64 `SA:""SG:""SC:"-"C:""`
31 | M_current_map uint64 `SA:""SG:""SC:""C:"-"`
32 | M_session_id uint64 `SA:""SC:""C:"-"`
33 | M_map_swtich_state uint32 `SA:""SG:""SC:"-"C:""`
34 | move.MoveControl `SG:"move"`
35 | }
36 |
37 | func (u *User) GetMoveControl() *move.MoveControl {
38 | return &u.MoveControl
39 | }
40 | func (u *User) GetCurrentMap() uint64 {
41 | return u.M_current_map
42 | }
43 | func (u *User) GetSessionID() uint64 {
44 | return u.M_session_id
45 | }
46 | func (u *User) GetMapSwitchState() uint64 {
47 | return u.GetMapSwitchState()
48 | }
49 |
50 | func (u *User) ToGhost() User {
51 | _ghost_u := User{}
52 | _ghost_user_str, _err := YJson.GhostMarshal(*u)
53 | if _err!= nil {
54 | ylog.Erro("[%v]",_err.Error())
55 | }
56 | YJson.UnMarshal(_ghost_user_str, &_ghost_u)
57 | return _ghost_u
58 | }
59 |
60 | /*func (u *User) GetMoveControl() *move.MoveControl {
61 | return u.GetAttr("MapInfo.MoveControl").(*move.MoveControl)
62 | }
63 |
64 | func (u *User) GetCurrentMap() uint64 {
65 | return *u.GetAttr("MapInfo.CurrentMap").(*uint64)
66 | }
67 | func (u *User) GetSessionID() uint64 {
68 | return *u.GetAttr("MapInfo.SessionID").(*uint64)
69 | }
70 | func (u *User) GetMapSwitchState() uint64 {
71 | return *u.GetAttr("MapInfo.MapSwitchState").(*uint64)
72 | }*/
73 |
74 | func (u *User) MoveUpdate(time_ time.Time) bool {
75 |
76 | return u.GetMoveControl().MoveUpdate(time_)
77 | }
78 |
79 | func (u *User) ToClientJson() Msg.UserData {
80 | _user_msg := Msg.UserData{
81 | M_uid: u.M_uid,
82 | M_current_map_id: u.GetCurrentMap(),
83 | M_pos: u.GetMoveControl().M_pos,
84 | }
85 | return _user_msg
86 | }
87 |
88 | type Info struct {
89 | YModule.BaseInter
90 | m_aoi *aoi.GoTowerAoiCellManager
91 | M_user_pool map[uint64]*User
92 | m_map_uid uint64
93 | m_go_astar *YPathFinding.AStarManager
94 | m_neighbor_uid map[uint64]struct{}
95 |
96 | m_gird_size float64
97 |
98 | m_vaild_up_left_pos YTool.PositionXY
99 | m_vaild_up_right_pos YTool.PositionXY
100 | m_vaild_down_left_pos YTool.PositionXY
101 | m_vaild_down_right_pos YTool.PositionXY
102 | m_origin_up_left_pos YTool.PositionXY
103 | m_origin_up_right_pos YTool.PositionXY
104 | m_origin_down_left_pos YTool.PositionXY
105 | m_origin_down_right_pos YTool.PositionXY
106 | m_vaild_width float64
107 | m_vaild_height float64
108 | m_total_width float64
109 | m_total_height float64
110 | m_vaild_row_grid float64
111 | m_vaild_col_grid float64
112 | m_total_row_grid float64
113 | m_total_col_grid float64
114 | m_overlap_count float64
115 | m_overlap_length float64
116 |
117 | m_up_down_offset int
118 | m_left_right_offset int
119 | }
120 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Module/MapManager/MapManager.go:
--------------------------------------------------------------------------------
1 | package MapManager
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YModule"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
8 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Module/UserManager"
9 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Util"
10 | "math"
11 | )
12 |
13 | type Info struct {
14 | YModule.BaseInter
15 | M_map_pool map[uint64]Msg.MapLoad
16 | }
17 |
18 | func NewInfo(node_ *YNode.Info, uid uint64) YModule.Inter {
19 | _info := &Info{
20 | M_map_pool: make(map[uint64]Msg.MapLoad),
21 | }
22 | _info.Info = YModule.NewInfo(node_)
23 | return _info
24 | }
25 | func (i *Info) Init() {
26 | i.Info.Init(i)
27 | }
28 |
29 | func (i *Info) Close() {
30 | }
31 |
32 | func (i *Info) RPC_MapRegister(load_ Msg.MapLoad) {
33 | i.M_map_pool[load_.M_map_uid] = load_
34 | }
35 |
36 | func (i *Info) RPC_MapLoadChange(load_ Msg.MapLoad) {
37 | i.M_map_pool[load_.M_map_uid] = load_
38 | }
39 |
40 | func (i *Info) GetLeastLoadMap() uint64 {
41 | _max_load := uint32(math.MaxUint32)
42 | _tar_map := uint64(0)
43 | for _, _it := range i.M_map_pool {
44 | if _it.M_load < _max_load {
45 | _max_load = _it.M_load
46 | }
47 | _tar_map = _it.M_map_uid
48 | }
49 | return _tar_map
50 | }
51 |
52 | const (
53 | FirstMapUID = 0x7FFFFFFF<<32 | 0x7FFFFFFF
54 | )
55 |
56 | func (i *Info) RPC_FirstEnterMap(user_ UserManager.User) {
57 | if len(i.M_map_pool) == 0 {
58 | i.RegisterModule("NewMap", FirstMapUID)
59 | }
60 |
61 | i.Info.RPCCall(YMsg.ToAgent("Map", FirstMapUID), "UserEnterMap", user_)
62 | i.Info.RPCCall(YMsg.ToAgent("UserManager"), "UserChangeCurrentMap", user_.M_uid, FirstMapUID)
63 | }
64 |
65 | func (i *Info) RPC_CreateMap(map_uid_ uint64) {
66 | _, exists := i.M_map_pool[map_uid_]
67 | if exists {
68 | return
69 | }
70 | i.M_map_pool[map_uid_] = Msg.MapLoad{}
71 |
72 | i.RegisterModule("NewMap", map_uid_)
73 | {
74 | _round_list := Util.GetRoundNeighborMapIDList(map_uid_)
75 | _exists_round := make([]uint64, 0)
76 | for _, _round_it := range _round_list {
77 | _, exists := i.M_map_pool[_round_it]
78 | if exists {
79 | _exists_round = append(_exists_round, _round_it)
80 | i.Info.RPCCall(YMsg.ToAgent("Map", _round_it), "RegisterNeighborMap", []uint64{map_uid_})
81 | }
82 | }
83 | i.Info.RPCCall(YMsg.ToAgent("Map", map_uid_), "RegisterNeighborMap", _exists_round)
84 | }
85 |
86 | //RegisterNeighborMap
87 | }
88 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Module/README.md:
--------------------------------------------------------------------------------
1 | ### 登录及进入地图
2 |
3 | ```sequence
4 | Cli->UserMgr:MSG_C2S_Login
5 | Cli->UserMgr:MSG_C2S_EnterMap
6 | UserMgr->MapMgr:RPC_GetLeastLoadMap
7 | MapMgr->UserMgr:RPC_GetLeastLoadMap
8 | UserMgr->Map:RPC_UserEnterMap
9 | Map->UserMgr:RPC_UserEnterMap
10 | Map->UserMgr:RPC_MapLoadChange
11 | UserMgr->Cli:MSG_S2C_Login
12 | ```
13 |
14 | ### 移动
15 |
16 | ```sequence
17 | Cli->UserMgr:MSG_C2S_UserMove
18 | UserMgr->Map:RPC_UserMove
19 | Map->UserMgr:RPC_UserMove
20 | UserMgr->Cli:MSG_S2C_UserMove
21 | ```
22 |
23 | ### 玩家移动并且通知视野内玩家
24 |
25 | ```sequence
26 | Cli->UserMgr:MSG_C2S_UserMove
27 | UserMgr->Map:RPC_UserMove
28 | Map->OtherClis_1:MSG_S2C_EntityChange
29 | Map->OtherClis_2:MSG_S2C_EntityChange
30 | Map->OtherClis_3:MSG_S2C_EntityChange
31 | Map->UserMgr:RPC_UserMove
32 | UserMgr->Cli:MSG_S2C_UserMove
33 | ```
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Module/UserManager/UserInfo.go:
--------------------------------------------------------------------------------
1 | package UserManager
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YEntity"
5 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
6 | )
7 |
8 | const (
9 | CONST_MAP_SWITCH_NONE = iota
10 | CONST_MAP_SWITCHING
11 | )
12 |
13 | type User struct {
14 | YEntity.Info
15 | M_uid uint64
16 | M_current_map uint64
17 | M_session_id uint64
18 | M_map_swtich_state uint32
19 | }
20 |
21 | func NewUser(uid_ uint64, session_id_ uint64) *User {
22 | return &User{
23 | M_uid: uid_,
24 | M_session_id: session_id_,
25 | }
26 | }
27 |
28 | func (u *User) ToClientJson() Msg.UserData {
29 | _user_msg := Msg.UserData{
30 | M_uid: u.M_uid,
31 | M_current_map_id: u.M_current_map,
32 | }
33 | return _user_msg
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Module/UserManager/UserManager.go:
--------------------------------------------------------------------------------
1 | package UserManager
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/YModule"
5 | "github.com/yxinyi/YCServer/engine/YMsg"
6 | "github.com/yxinyi/YCServer/engine/YNode"
7 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Msg"
8 | )
9 |
10 | type Info struct {
11 | YModule.BaseInter
12 | M_user_pool map[uint64]*User
13 | }
14 |
15 | func NewInfo(node_ *YNode.Info, uid uint64) YModule.Inter {
16 | _info := &Info{
17 | M_user_pool: make(map[uint64]*User),
18 | }
19 | _info.Info = YModule.NewInfo(node_)
20 | return _info
21 | }
22 | func (i *Info) Init() {
23 | i.Info.Init(i)
24 | }
25 |
26 | func (i *Info) Close() {
27 | }
28 |
29 | func (i *Info) MSG_C2S_Login(s_ uint64, msg_ Msg.C2S_Login) {
30 | _, exists := i.M_user_pool[s_]
31 | if !exists {
32 | i.M_user_pool[s_] = NewUser(s_, s_)
33 | }
34 | i.Info.SendNetMsgJson(s_, Msg.S2C_Login{
35 | //i.M_user_pool[s_].ToClientJson(nil),
36 | M_main_uid: s_,
37 | })
38 | }
39 |
40 | func (i *Info) RPC_UserChangeCurrentMap(s_, map_uid_ uint64) {
41 | _user := i.M_user_pool[s_]
42 | if _user != nil {
43 | _user.M_current_map = map_uid_
44 | }
45 | }
46 |
47 | func (i *Info) RPC_UserStartSwitchMap(user_uid_ uint64) {
48 | _user := i.M_user_pool[user_uid_]
49 | if _user != nil {
50 | _user.M_map_swtich_state = CONST_MAP_SWITCHING
51 | }
52 | }
53 | func (i *Info) RPC_UserFinishSwitchMap(user_uid_ uint64) {
54 | _user := i.M_user_pool[user_uid_]
55 | if _user != nil {
56 | _user.M_map_swtich_state = CONST_MAP_SWITCH_NONE
57 | }
58 | }
59 |
60 | func (i *Info) MSG_C2S_FirstEnterMap(s_ uint64, msg_ Msg.C2S_FirstEnterMap) {
61 | _user := i.M_user_pool[s_]
62 | if _user != nil {
63 | i.Info.RPCCall(YMsg.ToAgent("MapManager"), "FirstEnterMap", *_user)
64 | }
65 | }
66 |
67 | func (i *Info) MSG_C2S_UserMove(s_ uint64, msg_ Msg.C2S_UserMove) {
68 | _user := i.M_user_pool[s_]
69 | if _user == nil {
70 | return
71 | }
72 |
73 | i.Info.RPCCall(YMsg.ToAgent("Map", _user.M_current_map), "UserMove", _user.M_uid, msg_)
74 | }
75 |
76 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/ModuleRegister.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/yxinyi/YCServer/engine/BaseModule/NetModule"
5 | "github.com/yxinyi/YCServer/engine/YNode"
6 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Module/Map"
7 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Module/MapManager"
8 | "github.com/yxinyi/YCServer/examples/SeamlessExample/Server/Module/UserManager"
9 | _ "net/http/pprof"
10 | )
11 |
12 | func ModuleCreateFuncLoad() {
13 | YNode.ModuleCreateFuncRegister("NewMap", Map.NewInfo)
14 | YNode.ModuleCreateFuncRegister("NetModule", NetModule.NewInfo)
15 | YNode.ModuleCreateFuncRegister("MapManager", MapManager.NewInfo)
16 | YNode.ModuleCreateFuncRegister("UserManager", UserManager.NewInfo)
17 | }
18 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/Util/Map.go:
--------------------------------------------------------------------------------
1 | package Util
2 |
3 | func GetTarSideNeighborMapIDList(side_ []bool, map_uid_ uint64) []uint64 {
4 | _neighbor_map_list := make([]uint64, 0)
5 |
6 | if side_[0] == true {
7 | _neighbor_map_list = append(_neighbor_map_list, map_uid_-(1<<32))
8 | }
9 | if side_[1] == true {
10 | _neighbor_map_list = append(_neighbor_map_list, map_uid_+(1<<32))
11 | }
12 |
13 | if side_[2] == true {
14 | _neighbor_map_list = append(_neighbor_map_list, map_uid_-1)
15 | }
16 | if side_[3] == true {
17 | _neighbor_map_list = append(_neighbor_map_list, map_uid_+1)
18 | }
19 |
20 | if side_[0] && side_[2] {
21 | _neighbor_map_list = append(_neighbor_map_list, map_uid_-1-(1<<32))
22 | }
23 |
24 | if side_[0] && side_[3] {
25 | _neighbor_map_list = append(_neighbor_map_list, map_uid_+1-(1<<32))
26 | }
27 | if side_[1] && side_[2] {
28 | _neighbor_map_list = append(_neighbor_map_list, map_uid_-1+(1<<32))
29 | }
30 | if side_[1] && side_[3] {
31 | _neighbor_map_list = append(_neighbor_map_list, map_uid_+1+(1<<32))
32 | }
33 |
34 | return _neighbor_map_list
35 | }
36 |
37 | func GetRoundNeighborMapIDList(map_uid_ uint64) []uint64 {
38 | return GetTarSideNeighborMapIDList([]bool{true, true, true, true}, map_uid_)
39 | }
40 |
41 | func MapOffDiff(cent_map_, offset_map_ uint64) (int, int) {
42 | _offset_up_down := int(offset_map_>>32)&0xFFFFFFFF
43 | _cent_up_down := int(cent_map_>>32)&0xFFFFFFFF
44 | _up_down_offset := _offset_up_down - _cent_up_down
45 | _left_right_offset := int(offset_map_&0xFFFFFFFF) - int(cent_map_&0xFFFFFFFF)
46 | return _up_down_offset, _left_right_offset
47 | }
48 |
49 | const (
50 | CONST_MAP_OFFSET_ERROR = iota
51 | CONST_MAP_OFFSET_LEFT_UP
52 | CONST_MAP_OFFSET_UP
53 | CONST_MAP_OFFSET_RIGHT_UP
54 | CONST_MAP_OFFSET_LEFT
55 | CONST_MAP_OFFSET_RIGHT
56 | CONST_MAP_OFFSET_LEFT_DOWN
57 | CONST_MAP_OFFSET_DOWN
58 | CONST_MAP_OFFSET_RIGHT_DOWN
59 | )
60 |
61 | func MapOffsetMask(main_map_uid_, offset_map_uid_ uint64) uint32 {
62 | _up_down_offset, _left_right_offset := MapOffDiff(main_map_uid_, offset_map_uid_)
63 | if _up_down_offset < 0 {
64 | if _left_right_offset < 0 {
65 | //左上角
66 | return CONST_MAP_OFFSET_LEFT_UP
67 | }
68 | if _left_right_offset == 0 {
69 | //正上方
70 | return CONST_MAP_OFFSET_UP
71 | }
72 | if _left_right_offset > 0 {
73 | //右上角
74 | return CONST_MAP_OFFSET_RIGHT_UP
75 | }
76 | } else if _up_down_offset > 0 {
77 | if _left_right_offset < 0 {
78 | //左下角
79 | return CONST_MAP_OFFSET_LEFT_DOWN
80 | }
81 |
82 | if _left_right_offset == 0 {
83 | //正下方
84 | return CONST_MAP_OFFSET_DOWN
85 | }
86 |
87 | if _left_right_offset > 0 {
88 | //右下角
89 | return CONST_MAP_OFFSET_RIGHT_DOWN
90 | }
91 | } else {
92 | if _left_right_offset < 0 {
93 | //正左角
94 | return CONST_MAP_OFFSET_LEFT
95 | }
96 |
97 | if _left_right_offset > 0 {
98 | //正右角
99 | return CONST_MAP_OFFSET_RIGHT
100 | }
101 | }
102 | return CONST_MAP_OFFSET_ERROR
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/无缝地图切换方案.md:
--------------------------------------------------------------------------------
1 | ### 对象在无缝地图上切换
2 |
3 | ```sequence
4 | Client->UserManager:MSG_C2S_UserMove
5 | UserManager->Map:RPC_UserMove
6 | Map->Map:Moving:在边缘发生切换
7 | Map->UserManager:RPC_Map2UMStarSwitch
8 | UserManager->Map:RPC_UM2MapStarSwitch
9 | Client->UserManager: CacheAllMsg
10 | Map->NeighborMap:RPC_BetweenMapSwitch
11 | NeighborMap->UserManager:RPC_OverSwitch
12 | UserManager->NeighborMap:PushAllMsg
13 | Client->UserManager:MSG_C2S_UserMove
14 | UserManager->NeighborMap:RPC_UserMove
15 | ```
16 |
17 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/无缝地图动态创建方案.md:
--------------------------------------------------------------------------------
1 | ### 玩家登录新服务器
2 |
3 | ```sequence
4 | Client->UserManager:MSG_C2S_Login
5 | UserMgr->Client:MSG_C2S_Login
6 | Client->UserManager:C2S_FirstEnterMap
7 | UserMgr->MapManager:RPC_FirstEnterMap
8 | MapManager->YNode:RPC_NewModule:创建地图
9 | MapManager->Map:RPC_UserEnterMap
10 | MapManager->UserManager:RPC_UserChangeCurrentMap:用于后续路由
11 | Map->Client:S2C_FirstEnterMap
12 | ```
13 |
14 | ### 单地图移动
15 |
16 | ```sequence
17 | Client->UserManager:MSG_C2S_UserMove
18 | UserManager->Map:RPC_UserMove:\n user上有当前MapId可以进行路由
19 | Map->Map: AStar寻路
20 | Map->Map: UserUpdate
21 | Map->Client:S2C_MapAStarNodeUpdate:定时同步
22 | Map->Client:S2C_MapAStarNodeUpdate:定时同步
23 | Map->Client:S2C_MapAStarNodeUpdate:定时同步
24 | ```
25 |
26 | ### 移动至近边缘,创建未创建的邻近地图
27 |
28 | ```sequence
29 | Client->UserManager:MSG_C2S_UserMove
30 | UserManager->Map:RPC_UserMove:\n user上有当前MapId可以进行路由
31 | Map->Map:检测有玩家位于近边缘
32 | Map->Map:GetNeighborMap == nil
33 | Map->Map:CreateNeighborMapID
34 | Map->YNode:RPC_NewModule:创建地图
35 | Map->NeighborMap:RPC_CreateGhostEntity
36 | Client->Map: Msg_C2S_UserMove
37 | Map->Client:S2C_MapAStarNodeUpdate:定时同步
38 | Map->NeighborMap: RPC_DiffSyncEntity
39 | NeighborMap->NeighborUser:Msg_S2C_DiffSyncEntity
40 | Map->Client:S2C_MapAStarNodeUpdate:定时同步
41 | Map->NeighborMap: RPC_DiffSyncEntity
42 | NeighborMap->NeighborUser:Msg_S2C_DiffSyncEntity
43 | ```
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/examples/SeamlessExample/Server/无缝地图边缘处理方案.md:
--------------------------------------------------------------------------------
1 | ### 边缘增加重叠区域
2 |
3 | ```
4 | ┌───┬───────────────────┬───┐
5 | │ │ │ │
6 | ├───┼───────────────────┼───┤
7 | │ │0 1 2 3 4 5 6 7 8 9│ │
8 | │ │ │ │
9 | │ │ │ │
10 | │ │ │ │
11 | │ │ │ │
12 | │ │ │ │
13 | │ │ │ │
14 | ├───┼───────────────────┼───┤
15 | │ │ │ │
16 | └───┴───────────────────┴───┘
17 | ```
18 |
19 | 创建地图时四周留出一定的空白区域,动态创建地图时候,将地图的边缘信息拷贝到空白区域,如下
20 |
21 | ```
22 | ┌───┬───────────────┬───┬───┬───────────────┬───┐
23 | │ │ │ │ │ │ │
24 | ├───┼───────────────┼───┼───┼───────────────┼───┤
25 | │ │0 1 2 3 4 5 6 7│8 9│0 1│2 3 4 5 6 7 8 9│ │
26 | │ │ │ │ │ │ │
27 | │ │ │ │ │ │ │
28 | │ │ 1 │ A │ B │ 2 │ │
29 | │ │ │ │ │ │ │
30 | │ │ │ │ │ │ │
31 | │ │ │ │ │ │ │
32 | ├───┼───────────────┼───┼───┼───────────────┼───┤
33 | │ │ │ │ │ │ │
34 | └───┴───────────────┴───┴───┴───────────────┴───┘
35 | ```
36 |
37 | 如果空白区域为5,则重叠区域为10,玩家在重叠区域可以根据需求灵活在两张地图间切换
38 |
39 | `寻路至邻居地图流程`
40 |
41 | ```sequence
42 | Client->UserManager:MSG_C2S_UserMove
43 | UserManager->Map:RPC_UserMove
44 | Map->Map:MovingUpdate
45 | Map->NeighborMap:SyncUser \n移动至邻近地图的重叠区域A就开始同步
46 | Map->NeighborMap:检测到移动至B重叠区域,就开始根据切换方案进行切换
47 |
48 |
49 |
50 | ```
51 |
52 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/yxinyi/YCServer
2 |
3 | go 1.16
4 |
5 | require (
6 | github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect
7 | github.com/hajimehoshi/ebiten/v2 v2.1.6
8 | github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect
9 | github.com/jonboulle/clockwork v0.2.2 // indirect
10 | github.com/json-iterator/go v1.1.12
11 | github.com/lestrrat/go-envload v0.0.0-20180220120943-6ed08b54a570 // indirect
12 | github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
13 | github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
14 | github.com/spf13/pflag v1.0.5
15 | github.com/spf13/viper v1.9.0
16 | github.com/tebeka/strftime v0.1.5 // indirect
17 | github.com/yxinyi/YEventBus v0.1.2
18 | go.uber.org/zap v1.19.0
19 | golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
20 | )
21 |
--------------------------------------------------------------------------------