Commit 1af7ada5d6f5e31a9725e6d3f8be90c438eec1fd
fix confict
Showing
11 changed files
with
250 additions
and
44 deletions
Show diff stats
config/develop.lua
src/ProtocolCode.lua
src/actions/HangAction.lua
... | ... | @@ -165,16 +165,6 @@ function _M.startRpc( agent, data ) |
165 | 165 | |
166 | 166 | role:updateProperty({field = "hangInfo", value = hangInfo}) |
167 | 167 | |
168 | - -- 指定当前引导的步骤 | |
169 | - if carbonId == 10101 then | |
170 | - role:saveGuide(5,11) | |
171 | - elseif carbonId == 10102 then | |
172 | - role:saveGuide(8,2) | |
173 | - elseif carbonId == 10103 then | |
174 | - role:saveGuide(9,2) | |
175 | - elseif carbonId == 10220 then | |
176 | - role:saveGuide(22,1) | |
177 | - end | |
178 | 168 | role:mylog("hang_action", {desc = "startHang", int1 = carbonId}) |
179 | 169 | SendPacket(actionCodes.Hang_startRpc, '') |
180 | 170 | return true |
... | ... | @@ -265,12 +255,7 @@ function _M.endBattleRpc(agent, data) |
265 | 255 | |
266 | 256 | -- 引导 |
267 | 257 | if carbonId == 10101 then |
268 | - role:finishGuide(5) | |
269 | - elseif carbonId == 10102 then | |
270 | - role:finishGuide(8) | |
271 | - role:saveGuide(9, 2) | |
272 | - elseif carbonId == 10103 then | |
273 | - role:finishGuide(9) | |
258 | + role:finishGuide(6) | |
274 | 259 | elseif carbonId == 20101 then |
275 | 260 | role:finishGuide(22) |
276 | 261 | end |
... | ... | @@ -344,7 +329,7 @@ function _M.roleFormatRpc(agent , data) |
344 | 329 | hangTeam.leader = msg.leader |
345 | 330 | hangTeam.supports = supports |
346 | 331 | role:saveHangTeam(hangTeam) |
347 | - role:saveGuide(5,8) | |
332 | + role:finishGuide(5) | |
348 | 333 | SendPacket(actionCodes.Hang_roleFormatRpc, '') |
349 | 334 | return true |
350 | 335 | end | ... | ... |
src/actions/HeroAction.lua
... | ... | @@ -54,9 +54,6 @@ function _M.levelUpRpc( agent, data ) |
54 | 54 | hero_upgrade_scoreget = hero:getProperty("battleV") - oldBattleV, -- 通过英雄升级提升的评分 |
55 | 55 | }) |
56 | 56 | |
57 | - if hero:getProperty("type") == 103 then | |
58 | - role:finishGuide(7) | |
59 | - end | |
60 | 57 | hero:mylog({desc = "levelUp", int1 = hero:getProperty("level")}) |
61 | 58 | |
62 | 59 | role:checkTaskEnter("HeroLevelUp", {level = hero:getProperty("level")}) |
... | ... | @@ -129,6 +126,10 @@ function _M.wakeRpc(agent, data) |
129 | 126 | hero_rise_result = getChangeAttrJson(oldAttr, hero:getTotalAttrs()), --英雄觉醒效果,可记录效果ID,或json格式记录提升效果,{攻击:20,闪避:20,……..} |
130 | 127 | }) |
131 | 128 | |
129 | + if hero:getProperty("type") == 204 then | |
130 | + role:finishGuide(7) | |
131 | + end | |
132 | + | |
132 | 133 | SendPacket(actionCodes.Hero_wakeRpc, '') |
133 | 134 | |
134 | 135 | role:checkTaskEnter("HeroStarCollect", {}) |
... | ... | @@ -847,8 +848,8 @@ function _M.drawHeroRpc(agent, data) |
847 | 848 | role:costItems(cost, {log = {desc = "drawHero", int1 = btype, int2 = poolId}}) |
848 | 849 | |
849 | 850 | local guideHero = nil |
850 | - if role:getProperty("newerGuide") == "11=1" then | |
851 | - guideHero = globalCsv.newdraw_hero_item_id or 613 | |
851 | + if role:getProperty("newerGuide") == "8=1" then | |
852 | + guideHero = globalCsv.newdraw_hero_item_id or 503 | |
852 | 853 | end |
853 | 854 | |
854 | 855 | local ssrCount = 0 |
... | ... | @@ -907,7 +908,7 @@ function _M.drawHeroRpc(agent, data) |
907 | 908 | if ssrCount > 0 then |
908 | 909 | role:checkTaskEnter("DrawSSR", {count = ssrCount}) |
909 | 910 | end |
910 | - role:finishGuide(11) | |
911 | + role:finishGuide(8) | |
911 | 912 | |
912 | 913 | role:log("gacha", { |
913 | 914 | gacha_id = poolId, -- 卡池ID |
... | ... | @@ -1027,4 +1028,4 @@ function _M.changeCrown(agent, data) |
1027 | 1028 | return true |
1028 | 1029 | end |
1029 | 1030 | |
1030 | -return _M | |
1031 | 1031 | \ No newline at end of file |
1032 | +return _M | ... | ... |
src/agent.lua
... | ... | @@ -29,12 +29,6 @@ _codeSession = {} |
29 | 29 | --- {{{ 定时器相关 |
30 | 30 | local function handle_timeout() |
31 | 31 | if not agentInfo.open_timer then return end |
32 | - | |
33 | - if not agentInfo.role then | |
34 | - skynet.timeout(100, handle_timeout) | |
35 | - return | |
36 | - end | |
37 | - | |
38 | 32 | agent_util:update(agentInfo) |
39 | 33 | skynet.timeout(100, handle_timeout) |
40 | 34 | end |
... | ... | @@ -274,6 +268,8 @@ function CMD.start(session, source, gate, fd, ip, hotfixs) |
274 | 268 | end |
275 | 269 | end |
276 | 270 | |
271 | + start_agent_timer() | |
272 | + | |
277 | 273 | -- 这里将消息伪装成 watchdog 发出,这样就由 A->B->C->B->A 变成 A->B->C->A |
278 | 274 | skynet.redirect(gate, source, "lua", session, skynet.pack("forward", fd, 0, skynet.self())) |
279 | 275 | end | ... | ... |
src/main.lua
1 | 1 | local skynet = require "skynet" |
2 | 2 | |
3 | 3 | local max_client = tonumber(skynet.getenv("max_client")) |
4 | +local max_queue = tonumber(skynet.getenv("max_queue")) | |
4 | 5 | |
5 | 6 | skynet.start(function() |
6 | 7 | print("Server start") |
... | ... | @@ -11,7 +12,7 @@ skynet.start(function() |
11 | 12 | |
12 | 13 | skynet.call(watchdog, "lua", "start", { |
13 | 14 | port = tonumber(skynet.getenv("server_port")), |
14 | - maxclient = max_client, | |
15 | + maxclient = max_client + max_queue + 10, | |
15 | 16 | httpd = httpd, |
16 | 17 | |
17 | 18 | redishost = skynet.getenv("redis_host"), | ... | ... |
src/services/agent_ctrl.lua
... | ... | @@ -58,7 +58,14 @@ function _M:exit_agent(fd) |
58 | 58 | local agent = get_a(pack) |
59 | 59 | |
60 | 60 | pcall(skynet.send, agent, "lua", "exit") |
61 | - pcall(skynet.send, poold, "lua", "feed") | |
61 | + | |
62 | + -- 这里检查是否有排队用户 | |
63 | + local nuid, nfd = skynet.call(queued_serv, "lua", "pop") | |
64 | + if not nuid then | |
65 | + pcall(skynet.send, poold, "lua", "feed") | |
66 | + else | |
67 | + self:query_agent(nfd, nuid, true) | |
68 | + end | |
62 | 69 | |
63 | 70 | self.f2u[fd] = nil |
64 | 71 | self.u2f[uid] = nil |
... | ... | @@ -73,7 +80,11 @@ end |
73 | 80 | function _M:socket_close(fd) |
74 | 81 | self.f2i[fd] = nil |
75 | 82 | local uid = self.f2u[fd] |
76 | - if not uid then return end | |
83 | + if not uid then | |
84 | + -- 排队中? | |
85 | + pcall(skynet.call, queued_serv, "lua", "socket_close", fd) | |
86 | + return | |
87 | + end | |
77 | 88 | self.f2e[fd] = skynet.timex() + AGENT_EXPIRE_TIME |
78 | 89 | |
79 | 90 | if not self.u2f[uid] then |
... | ... | @@ -89,7 +100,11 @@ end |
89 | 100 | function _M:socket_error(fd) |
90 | 101 | self.f2i[fd] = nil |
91 | 102 | local uid = self.f2u[fd] |
92 | - if not uid then return end | |
103 | + if not uid then | |
104 | + -- 排队中? | |
105 | + pcall(skynet.call, queued_serv, "lua", "socket_close", fd) | |
106 | + return | |
107 | + end | |
93 | 108 | |
94 | 109 | if not self.u2f[uid] then |
95 | 110 | self.f2u[fd] = nil |
... | ... | @@ -151,7 +166,7 @@ local function query_agent_response(fd, response) |
151 | 166 | end |
152 | 167 | |
153 | 168 | -- @desc: 玩家登陆第一个包,queryLogin,watchdog为客户端分配一个agent,并告诉gate分配成功,之后的消息直接走agent |
154 | -function _M:query_agent(fd, uid) | |
169 | +function _M:query_agent(fd, uid, isQueue) | |
155 | 170 | local pack = self.u2f[uid] |
156 | 171 | if pack then |
157 | 172 | local f = get_f(pack) |
... | ... | @@ -159,7 +174,6 @@ function _M:query_agent(fd, uid) |
159 | 174 | skynet.error(string.format("%s same fd %d", uid, fd)) |
160 | 175 | return |
161 | 176 | end |
162 | - | |
163 | 177 | -- self.f2u[f] 肯定存在;self.f2e[f]不存在,则说明在线,则需要踢下线 |
164 | 178 | if not self.f2e[f] then |
165 | 179 | local head = string.pack("H", actionCodes.Sys_maintainNotice) |
... | ... | @@ -183,11 +197,18 @@ function _M:query_agent(fd, uid) |
183 | 197 | self.u2f[uid] = set_pack(fd, agent) |
184 | 198 | else |
185 | 199 | -- 该uid未存储,则说明至少超过10分钟未登陆,由agent池服务pop出一个agent |
186 | - local agent = self.factory:pop() | |
187 | - if not agent then | |
188 | - -- 服务器满 | |
189 | - query_agent_response(fd, {ret = "RET_SERVER_FULL"}) | |
190 | - return | |
200 | + local agent | |
201 | + if isQueue then | |
202 | + agent = skynet.newservice("agent") | |
203 | + else | |
204 | + agent = self.factory:pop() | |
205 | + if not agent then | |
206 | + -- 服务器满 | |
207 | + -- 开始排队 | |
208 | + local ok, rank = pcall(skynet.call, queued_serv, "lua", "push", uid, fd) | |
209 | + query_agent_response(fd, {ret = "RET_SERVER_FULL", rank = rank}) | |
210 | + return | |
211 | + end | |
191 | 212 | end |
192 | 213 | |
193 | 214 | local ok = pcall(skynet.call, agent, "lua", "start", gate_serv, fd, self.f2i[fd], hotfixList) | ... | ... |
src/services/agent_util.lua
... | ... | @@ -17,15 +17,32 @@ local HEART_TIMEOUT_COUNT_MAX = 20 |
17 | 17 | local HEART_QUICK_COUNT_MAX = 5 |
18 | 18 | -- 心跳定时间隔 |
19 | 19 | local HEART_TIMER_INTERVAL = 5 |
20 | +-- 忽略心跳的等待时间 | |
21 | +local WAIT_IGNORE_HEART = 300 | |
22 | + | |
23 | +--开始忽略心跳的时间 | |
24 | +local ignoreHeartTime = nil | |
20 | 25 | |
21 | 26 | local function check_heart_beat(agent, now) |
22 | 27 | -- 充值等操作不检查心跳 |
23 | 28 | local role = agent.role |
24 | - if role.ignoreHeartbeat then | |
29 | + if not role or role.ignoreHeartbeat then | |
25 | 30 | lastHeartCheckTime = now - HEART_TIMER_INTERVAL |
26 | 31 | heartTimeoutCount = 0 |
32 | + | |
33 | + if not ignoreHeartTime then | |
34 | + ignoreHeartTime = now | |
35 | + end | |
36 | + | |
37 | + if now - ignoreHeartTime >= WAIT_IGNORE_HEART then -- 等待太久了 踢掉 | |
38 | + skynet.error("timeout! then agent will shut down by self with ignoreHeartbeat or no login", agent.client_fd) | |
39 | + skynet.call(agent.gate_serv, "lua", "kick", agent.client_fd) | |
40 | + ignoreHeartTime = nil | |
41 | + end | |
27 | 42 | return |
28 | 43 | end |
44 | + ignoreHeartTime = nil | |
45 | + | |
29 | 46 | if lastHeartCheckTime - now > HEART_TIMER_INTERVAL or |
30 | 47 | now - lastHeartCheckTime > HEART_TIMER_INTERVAL then |
31 | 48 | heartTimeoutCount = heartTimeoutCount + 1 |
... | ... | @@ -46,6 +63,7 @@ function _M:update(agent) |
46 | 63 | pcall(check_heart_beat, agent, now) |
47 | 64 | nextCheckTime = now + HEART_TIMER_INTERVAL |
48 | 65 | end |
66 | + if not role then return end | |
49 | 67 | pcall(role.onRecoverTimer, role, now) |
50 | 68 | end |
51 | 69 | |
... | ... | @@ -73,6 +91,7 @@ end |
73 | 91 | function _M:reset() |
74 | 92 | heartTimeoutCount = 0 |
75 | 93 | heartQuickCount = 0 |
94 | + ignoreHeartTime = nil | |
76 | 95 | lastHeartCheckTime = skynet.timex() |
77 | 96 | end |
78 | 97 | ... | ... |
src/services/poold.lua
... | ... | @@ -7,14 +7,15 @@ local deque = require "deque" |
7 | 7 | local CMD = {} |
8 | 8 | local factory |
9 | 9 | |
10 | +local PRE_FEED_COUNT = 1 | |
10 | 11 | local dead = 0 |
11 | 12 | -- agent死亡,通知poold补充,当累计到5个agent时,马上生成5个agent放入poold中 |
12 | 13 | -- 当然这里也可以写得更复杂,参考redis落地规则 |
13 | 14 | function CMD.feed() |
14 | 15 | dead = dead + 1 |
15 | - if dead == 5 then | |
16 | + if dead == PRE_FEED_COUNT then | |
16 | 17 | dead = 0 |
17 | - for i=1, 5 do | |
18 | + for i=1, PRE_FEED_COUNT do | |
18 | 19 | factory:push(skynet.newservice("agent")) |
19 | 20 | end |
20 | 21 | end | ... | ... |
... | ... | @@ -0,0 +1,178 @@ |
1 | +-- 排队系统 | |
2 | + | |
3 | +require "ProtocolCode" | |
4 | +require "shared.init" | |
5 | +require "utils.init" | |
6 | +require "GlobalVar" | |
7 | +require "RedisKeys" | |
8 | +require "skynet.manager" | |
9 | + | |
10 | +local queue = require "skynet.queue" | |
11 | +local netpack = require "skynet.netpack" | |
12 | +local socket = require "skynet.socket" | |
13 | +local xxtea = require "xxtea" | |
14 | + | |
15 | +skynet = require "skynet" | |
16 | + | |
17 | +local MAX_COUNT = tonumber(skynet.getenv("max_queue")) | |
18 | +-- 心跳定时间隔 | |
19 | +local HEART_TIMER_INTERVAL = 30 | |
20 | +local HEART_TIMEOUT_COUNT_MAX = 3 | |
21 | +local gate_serv | |
22 | + | |
23 | +local CMD = {} | |
24 | +local f2u = {} | |
25 | +local u2i = {} -- {idx, fd, {lastHeart, timeOutCount, nextCheck}} | |
26 | +local idx2u = {} | |
27 | +local curIdx = 0 -- 下一个即将进入游戏的玩家索引 | |
28 | +local nextIdx = 0 -- 新加的位置 | |
29 | + | |
30 | + | |
31 | + | |
32 | +local function getRank(uid) | |
33 | + local info = u2i[uid] | |
34 | + if not info then return -1 end | |
35 | + return (info[1] + MAX_COUNT - curIdx) % MAX_COUNT + 1 | |
36 | +end | |
37 | + | |
38 | + | |
39 | +function SendPacket(actionCode, bin, client_fd) | |
40 | + if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end | |
41 | + local head = string.pack("H", actionCode) | |
42 | + return socket.write(client_fd, netpack.pack(head .. bin)) | |
43 | +end | |
44 | + | |
45 | +local function checkQueue(fd) | |
46 | + if not f2u[fd] then return end | |
47 | + local info = u2i[f2u[fd]] | |
48 | + if info then | |
49 | + info[3][1] = skynet.timex() | |
50 | + end | |
51 | + local rank = getRank(f2u[fd]) | |
52 | + SendPacket(actionCodes.Sys_checkQueue, MsgPack.pack({rank = rank}), fd) | |
53 | +end | |
54 | + | |
55 | + | |
56 | +skynet.register_protocol { | |
57 | + name = "client", | |
58 | + id = skynet.PTYPE_CLIENT, | |
59 | + unpack = function (msg, sz) | |
60 | + local data = skynet.tostring(msg, sz) | |
61 | + local cmd = string.unpack("H", string.sub(data, 1, 2)) | |
62 | + return cmd, string.sub(data, 3) | |
63 | + end, | |
64 | + dispatch = function(session, address, cmd, data) | |
65 | + skynet.ignoreret() | |
66 | + cs(function() | |
67 | + if cmd == actionCodes.Sys_checkQueue then | |
68 | + checkQueue(session) | |
69 | + end | |
70 | + end) | |
71 | + end | |
72 | +} | |
73 | + | |
74 | +function CMD.open(serv) | |
75 | + gate_serv = serv | |
76 | +end | |
77 | + | |
78 | +function CMD.push(uid, fd) | |
79 | + uid = tostring(uid) | |
80 | + if u2i[uid] then -- 存在] | |
81 | + local oldfd = u2i[uid][2] | |
82 | + if oldfd and oldfd ~= fd then | |
83 | + -- 踢掉老的 | |
84 | + SendPacket(actionCodes.Sys_maintainNotice, MsgPack.pack({body = "server_accountOccupied", iskey = true}), oldfd) | |
85 | + skynet.timeout(10, function () | |
86 | + skynet.call(gate_serv, "lua", "kick", oldfd) | |
87 | + end) | |
88 | + f2u[oldfd] = nil | |
89 | + end | |
90 | + u2i[uid][2] = fd | |
91 | + f2u[fd] = uid | |
92 | + u2i[uid][3] = {skynet.timex(), 0, skynet.timex() + HEART_TIMER_INTERVAL} | |
93 | + else -- 新排队的用户 | |
94 | + if nextIdx == curIdx and next(idx2u) then -- 满了 | |
95 | + return | |
96 | + end | |
97 | + u2i[uid] = {nextIdx, fd, {skynet.timex(), 0, skynet.timex() + HEART_TIMER_INTERVAL}} | |
98 | + f2u[fd] = uid | |
99 | + idx2u[nextIdx] = uid | |
100 | + nextIdx = (nextIdx + 1) % MAX_COUNT | |
101 | + end | |
102 | + skynet.call(gate_serv, "lua", "forward", fd, 0, skynet.self()) | |
103 | + | |
104 | + return getRank(uid) | |
105 | +end | |
106 | + | |
107 | +function CMD.pop() | |
108 | + while true do | |
109 | + local uid = idx2u[curIdx] | |
110 | + if not uid then return end -- 空的 | |
111 | + local info = u2i[uid] | |
112 | + if not info then | |
113 | + idx2u[curIdx] = nil | |
114 | + else | |
115 | + if info[2] then | |
116 | + -- 找到合适的了 | |
117 | + u2i[uid] = nil | |
118 | + idx2u[curIdx] = nil | |
119 | + f2u[info[2]] = nil | |
120 | + | |
121 | + curIdx = (curIdx + 1) % MAX_COUNT | |
122 | + return uid, info[2] | |
123 | + else | |
124 | + idx2u[curIdx] = nil | |
125 | + u2i[uid] = nil | |
126 | + end | |
127 | + end | |
128 | + curIdx = (curIdx + 1) % MAX_COUNT | |
129 | + end | |
130 | +end | |
131 | + | |
132 | +-- 下线了 | |
133 | +function CMD.socket_close(fd) | |
134 | + local uid = f2u[fd] | |
135 | + if not uid then return end | |
136 | + f2u[fd] = nil | |
137 | + local info = u2i[uid] | |
138 | + info[2] = nil | |
139 | +end | |
140 | + | |
141 | + | |
142 | +local function handle_timeout() | |
143 | + local now = skynet.timex() | |
144 | + for uid, info in pairs(u2i) do | |
145 | + if info[2] and info[3] and now >= info[3][3] then --存在fd 检查心跳 | |
146 | + if info[3][1] - now > HEART_TIMER_INTERVAL or now - info[3][1] > HEART_TIMER_INTERVAL then | |
147 | + info[3][2] = info[3][2] + 1 | |
148 | + info[3][3] = now + HEART_TIMER_INTERVAL | |
149 | + if info[3][2] >= HEART_TIMEOUT_COUNT_MAX then | |
150 | + skynet.error("timeout! then queued will closed", info[2], uid) | |
151 | + skynet.call(gate_serv, "lua", "kick", info[2]) | |
152 | + end | |
153 | + end | |
154 | + end | |
155 | + end | |
156 | + skynet.timeout(100, handle_timeout) | |
157 | +end | |
158 | + | |
159 | + | |
160 | +skynet.start(function() | |
161 | + skynet.dispatch("lua", function(session, source, command, ...) | |
162 | + -- skynet.trace() --执行序的跟踪统计 | |
163 | + local f = CMD[command] | |
164 | + if f then | |
165 | + skynet.ret(skynet.pack(f(...))) | |
166 | + end | |
167 | + end) | |
168 | + | |
169 | + skynet.info_func(function() | |
170 | + local info = {} | |
171 | + info.count = (nextIdx + MAX_COUNT - curIdx) % MAX_COUNT | |
172 | + return info | |
173 | + end) | |
174 | + | |
175 | + cs = queue() | |
176 | + | |
177 | + skynet.timeout(100, handle_timeout) | |
178 | +end) | |
0 | 179 | \ No newline at end of file | ... | ... |
src/services/watchdog.lua
... | ... | @@ -66,6 +66,7 @@ end |
66 | 66 | function CMD.start(conf) |
67 | 67 | skynet.call(gate_serv, "lua", "open" , conf) |
68 | 68 | skynet.call(redisd, "lua", "open", conf) |
69 | + skynet.call(queued_serv, "lua", "open", gate_serv) | |
69 | 70 | |
70 | 71 | if use_logd == 1 then |
71 | 72 | skynet.call(logd, "lua", "open") |
... | ... | @@ -137,4 +138,5 @@ skynet.start(function() |
137 | 138 | skynet.newservice("services/chated") |
138 | 139 | -- 网关服务 |
139 | 140 | gate_serv = skynet.newservice("gate") |
141 | + queued_serv = skynet.newservice("services/queued") | |
140 | 142 | end) | ... | ... |
-
mentioned in commit 46a0db220ccf4acdc740ada8ca8e36d26e838883