Commit 1af7ada5d6f5e31a9725e6d3f8be90c438eec1fd

Authored by liuzujun
2 parents 00bf6029 a5b98c30

fix confict

config/develop.lua
... ... @@ -6,6 +6,7 @@ codeurl = "192.168.8.223:9090"
6 6 servId = 1
7 7  
8 8 max_client = 64
  9 +max_queue = 64
9 10  
10 11 server_port = 12001
11 12 debug_port = 10001
... ...
src/ProtocolCode.lua
... ... @@ -7,6 +7,7 @@ actionCodes = {
7 7 Sys_commonNotice = 5,
8 8 Sys_maintainNotice = 6,
9 9 Sys_customNotice = 7,
  10 + Sys_checkQueue = 8,
10 11  
11 12 Gm_clientRequest = 20,
12 13 Gm_receiveResponse = 21,
... ...
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
... ...
src/services/queued.lua 0 → 100644
... ... @@ -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)
... ...