123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- -- 网关agent
- local skynet = require "skynet"
- local protoUtil = require("utils.protoUtil")
- local nodeUtil = require("utils.nodeUtil")
- local CMD = {}
- local GATE, WATCHDOG
- local mapFd = {} -- MAP, key fd; value {uid=uid, heart=0}
- local mapUid2Session = {} -- MAP, key uid; value session
- -- 断开非活跃链接
- local function l_start_fd_heart_bit()
- skynet.fork(
- function(...)
- while true do
- for fd, v in pairs(mapFd) do
- if skynet_time() - v.heart >= 60 then
- skynet.send(WATCHDOG, "lua", "close", fd, "overTime")
- end
- end
- skynet.sleep(200) -- 20s
- end
- end
- )
- end
- local function l_request(fd, protoname, args, ...)
- local fdInfo = mapFd[fd]
- if fdInfo == nil or fdInfo.uid == nil then
- -- fd未绑定玩家
- return
- end
- local uid = fdInfo.uid
- local session = mapUid2Session[uid]
- if not session then
- return
- end
- -- 修改fd心跳时间
- fdInfo.heart = skynet_time()
- -- 转发给游戏服
- args.uid = args.uid or uid
- nodeUtil:send_to_node(session.gameNode, session.gameAgent, "c2s_forward", uid, protoname, args, ...)
- end
- local function l_dispath_msg(fd, msg)
- local ok, ptype, protoname, args, session, ud = pcall(protoUtil.decode_c2s_req_ex, protoUtil, msg)
- if not ok then
- return log.error("decode sproto faild")
- end
- if ptype ~= "REQUEST" then
- return log.error("This example doesn't support request client")
- end
- l_request(fd, protoname, args, session, ud)
- end
- -- 获取玩家fd
- local function l_get_user_fd(uid)
- if uid == nil then
- return
- end
- local session = mapUid2Session[uid]
- if session then
- return session.fd
- end
- end
- skynet.register_protocol {
- name = "client",
- id = skynet.PTYPE_CLIENT,
- unpack = skynet.tostring,
- dispatch = function(fd, address, msg)
- skynet.ignoreret()
- l_dispath_msg(fd, msg)
- end
- }
- -- from watchdog
- function CMD.login(uid, fd)
- GATE = GATE or skynet.queryservice("srvGate")
- WATCHDOG = WATCHDOG or skynet.queryservice("wsSprotoWatchdog")
- local session = mapUid2Session[uid]
- if session then
- if session.fd then
- mapFd[fd] = nil
- end
- session.fd = fd
- else
- -- 分配游戏服节点/agent
- local gameNode, gameAgent = nodeUtil:user_dispatch_game_node_and_agent(uid)
- log.info("login uid[%s] gameNode[%s] gameAgent[%s]", tostring(uid), tostring(gameNode), tostring(gameAgent))
- session = {
- fd = fd,
- uid = uid,
- gateNode = skynet.getenv("nodeName"),
- gateAgent = skynet.self(),
- gameNode = gameNode,
- gameAgent = gameAgent
- }
- end
- local fdInfo = {uid = uid, heart = skynet_time()}
- mapFd[fd] = fdInfo
- mapUid2Session[uid] = session
- -- 通知gameAgent 玩家登陆
- local ok = nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "login", uid, session)
- if not ok then
- log.error("uid:%s send game to login error", uid)
- return false
- end
- -- 接收客户端协议
- _, ok = pcall(skynet.call, GATE, "lua", "fd_band_agent", fd)
- if not ok then
- log.error("uid:%s send gate to fd_band_agent", tostring(uid))
- return false
- end
- nodeUtil:user_master_band_node(uid)
- return true
- end
- -- from watchdog
- function CMD.logout(uid)
- local session = mapUid2Session[uid]
- if not session then
- return
- end
- local fd = session.fd
- if fd then
- mapFd[fd] = nil
- end
- session.fd = nil
- -- 玩家登出
- nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "logout", uid, session)
- nodeUtil:user_master_unband_node(uid)
- if uid then
- mapUid2Session[uid] = nil
- end
- end
- -- 向玩家发消息
- function CMD.s2c(uid, name, msg)
- local fd = l_get_user_fd(uid)
- if fd == nil then
- return
- end
- -- log.proto("push uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
- local rs = protoUtil:encode_s2c_req(name, msg)
- skynet.send(GATE, "lua", "send_to_client", fd, rs)
- end
- -- 向所有玩家发消息
- function CMD.s2c_broadcast(name, msg)
- local rs = protoUtil:encode_s2c_req(name, msg)
- for fd, _ in pairs(mapFd) do
- skynet.send(GATE, "lua", "send_to_client", fd, rs)
- end
- end
- -- 回应客户端请求
- function CMD.c2s_response(uid, name, msg, session, ud)
- local fd = l_get_user_fd(uid)
- if fd == nil then
- return
- end
- -- log.proto("response uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
- local rs = protoUtil:encode_c2s_rsp_ex(name, msg, session, ud)
- skynet.send(GATE, "lua", "send_to_client", fd, rs)
- end
- -- 踢玩家
- function CMD.kick(uid, msg)
- local fd = l_get_user_fd(uid)
- if fd == nil then
- return
- end
- -- 通知玩家被踢
- local rs = protoUtil:encode_s2c_req("on_server_code", msg)
- skynet.send(GATE, "lua", "send_to_client", fd, rs)
- -- 关闭链接
- skynet.send(WATCHDOG, "lua", "close", fd, "kick")
- end
- function CMD.recycle()
- skynet.exit()
- end
- function CMD.update_proto()
- protoUtil:update()
- end
- skynet.start(
- function()
- skynet.dispatch(
- "lua",
- function(session, address, command, ...)
- local f = CMD[command]
- if f == nil then
- log.error("agent command[%s] not found", tostring(command))
- end
- if session > 0 then
- skynet.ret(skynet.pack(f(...)))
- else
- f(...)
- end
- end
- )
- -- 心跳监听
- l_start_fd_heart_bit()
- end
- )
|