agent_queued.lua
3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
-- 排队系统
require "ProtocolCode"
require "shared.init"
require "utils.init"
require "GlobalVar"
require "RedisKeys"
require "skynet.manager"
local queue = require "skynet.queue"
local netpack = require "skynet.netpack"
local socket = require "skynet.socket"
local xxtea = require "xxtea"
skynet = require "skynet"
local MAX_COUNT = tonumber(skynet.getenv("max_queue"))
-- 心跳定时间隔
local HEART_TIMER_INTERVAL = 30
local HEART_TIMEOUT_COUNT_MAX = 3
local CMD = {}
local f2u = {}
local u2i = {} -- {idx, fd, {lastHeart, timeOutCount, nextCheck}}
local idx2u = {}
local curIdx = 0 -- 下一个即将进入游戏的玩家索引
local nextIdx = 0 -- 新加的位置
local function getRank(uid)
local info = u2i[uid]
if not info then return -1 end
return (info[1] + MAX_COUNT - curIdx) % MAX_COUNT + 1
end
function SendPacket(actionCode, bin, client_fd)
if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end
local head = string.pack("H", actionCode)
return socket.write(client_fd, netpack.pack(head .. bin))
end
local function checkQueue(fd)
if not f2u[fd] then return end
local info = u2i[f2u[fd]]
if info then
info[3][1] = skynet.timex()
end
local rank = getRank(f2u[fd])
SendPacket(actionCodes.Sys_checkQueue, MsgPack.pack({rank = rank}), fd)
end
skynet.register_protocol {
name = "client",
id = skynet.PTYPE_CLIENT,
unpack = function (msg, sz)
local data = skynet.tostring(msg, sz)
local cmd = string.unpack("H", string.sub(data, 1, 2))
return cmd, string.sub(data, 3)
end,
dispatch = function(session, address, cmd, data)
skynet.ignoreret()
if cmd == actionCodes.Sys_checkQueue then
checkQueue(session)
end
end
}
function CMD.push(uid, fd)
uid = tostring(uid)
if u2i[uid] then -- 存在]
local oldfd = u2i[uid][2]
if oldfd and oldfd ~= fd then
-- 踢掉老的
SendPacket(actionCodes.Sys_maintainNotice, MsgPack.pack({body = "server_accountOccupied", iskey = true}), oldfd)
skynet.timeout(10, function ()
skynet.call(gate_serv, "lua", "kick", oldfd)
end)
f2u[oldfd] = nil
end
u2i[uid][2] = fd
f2u[fd] = uid
u2i[uid][3] = {skynet.timex(), 0, skynet.timex() + HEART_TIMER_INTERVAL}
else -- 新排队的用户
if nextIdx == curIdx and next(idx2u) then -- 满了
return
end
u2i[uid] = {nextIdx, fd, {skynet.timex(), 0, skynet.timex() + HEART_TIMER_INTERVAL}}
f2u[fd] = uid
idx2u[nextIdx] = uid
nextIdx = (nextIdx + 1) % MAX_COUNT
end
skynet.call(gate_serv, "lua", "forward", fd, 0, skynet.self())
return getRank(uid)
end
function CMD.pop()
while true do
local uid = idx2u[curIdx]
if not uid then return end -- 空的
local info = u2i[uid]
if not info then
idx2u[curIdx] = nil
else
if info[2] then
-- 找到合适的了
u2i[uid] = nil
idx2u[curIdx] = nil
f2u[info[2]] = nil
curIdx = (curIdx + 1) % MAX_COUNT
return uid, info[2]
else
idx2u[curIdx] = nil
u2i[uid] = nil
end
end
curIdx = (curIdx + 1) % MAX_COUNT
end
end
-- 下线了
function CMD.socket_close(fd)
local uid = f2u[fd]
if not uid then return end
f2u[fd] = nil
local info = u2i[uid]
info[2] = nil
end
function CMD.handle_timeout()
local now = skynet.timex()
for uid, info in pairs(u2i) do
if info[2] and info[3] and now >= info[3][3] then --存在fd 检查心跳
if info[3][1] - now > HEART_TIMER_INTERVAL or now - info[3][1] > HEART_TIMER_INTERVAL then
info[3][2] = info[3][2] + 1
info[3][3] = now + HEART_TIMER_INTERVAL
if info[3][2] >= HEART_TIMEOUT_COUNT_MAX then
skynet.error("timeout! then queued will closed", info[2], uid)
skynet.call(gate_serv, "lua", "kick", info[2])
end
end
end
end
end
function CMD.count()
return (nextIdx + MAX_COUNT - curIdx) % MAX_COUNT
end
return CMD