local skynet = require "skynet" require "skynet.manager" local redisdriver = require "skynet.db.redis" local logger = require "logger" -- local keygen = require "model.keygen" local stringify = require "stringify" local util = require "util" local os_time = os.time local string_format = string.format local skynet_retpack = skynet.retpack local skynet_call = skynet.call local skynet_send = skynet.send local table_insert = table.insert local table_remove = table.remove local table_length = util.length local trace = logger.trace local login_user = {} local online_user = {} local allowed_server_id = {} local redis local uid_num local function keygen() local rand_list = {1,2,1,1,2,1} assert(uid_num and uid_num < 999999, uid_num) uid_num = uid_num + rand_list[(uid_num%(#rand_list))+1] redis:set("uidnum", uid_num) return string.format("%02d-%06d", option.sid, 100000+uid_num) end local CMD = {} function CMD.start() logger.info("start") local conf = assert(option.redis) redis = redisdriver.connect(conf) redis:select(0) uid_num = tonumber(redis:get("uidnum") or 0) local res = redis:smembers("sharepoint") for _, sid in ipairs(res) do allowed_server_id[math.tointeger(sid)] = true end local sid = assert(option.sid) allowed_server_id[sid] = true logger.info("%s:%s\n%s", conf.host, conf.port, stringify(allowed_server_id)) end function CMD.service_list() return allowed_server_id end function CMD.batch_save(pkg) assert(#pkg > 1) pkg[1] = string_format("character:%s", pkg[1]) return redis:hmset(pkg) end function CMD.load(uid) local k = string_format("character:%s", uid) local rets = redis:hgetall(k) if next(rets) then return rets end end local facebook = nil -- 云账号登陆废弃 local function retrieve_facebook_account(account, sid, channel) facebook = facebook or skynet.localname(".facebook") local errno, fb = skynet.call(facebook, "lua", "retrieve", account, channel) local uid = nil if errno == 200 then uid = redis:get(string_format("account:%s:%s:%s", channel, sid, fb)) end return errno, uid end function CMD.bingding(channel, sid, account, cuid) -- CDPK3-005 海外SDK -- 检查账号是否已经存在 local key = string_format("account:%s:%s:%s", channel, sid, account) local uid = redis:get(key) if uid then return STD_ERR.PLYAER_BING_ACCOUNT_EXIST -- 绑定账号已经存在 end logger.trace( "##### key %s uid %s", key, cuid) local ok = redis:set(key, cuid) if ok ~= "OK" then return STD_ERR.PLYAER_BING_SERVER_ERROR end return 0 end function CMD.login(args, agent) local sid = assert(args.sid) -- 服务器唯一标识 local account = assert(args.account) -- 帐号唯一标识(渠道分配) -- local appid = assert(args.appid) -- App唯一标识 local channel = assert(args.channel) -- 渠道唯一标识 -- local platform = assert(args.platform) -- 操作系统(pc,ios,android等) -- local version = assert(args.version) -- 客户端版本号 if not allowed_server_id[sid] then return 1 end -- 防止非法的服务器标识 if login_user[account] then return 2 end -- 防止多设备登录 login_user[account] = true -- 查找帐号在指定 sid 上创建的角色id local k = string_format("account:%s:%s:%s", channel, sid, account) local uid = redis:get(k) -- 云账号登陆废弃 -- if uid == nil then -- local errno, val = retrieve_facebook_account(account, sid, channel) -- if errno == 200 then -- uid = val -- elseif errno ~= 404 then -- login_user[account] = nil -- return 3 -- 暂时不能放用户进来 -- end -- end if uid then -- 通知当前在线设备下线 local old = online_user[uid] online_user[uid] = agent if old then pcall(skynet_call, old, "lua", "multilogin") end -- 载入角色数据 k = string_format("character:%s", uid) local rets = redis:hgetall(k) if next(rets) then login_user[account] = nil return 0, rets end else -- 为尚未创建角色的帐号关联一个新的角色id uid = keygen() local key = string_format("character:%s", uid) assert(not redis:exists(key)) online_user[uid] = agent redis:set(k, uid) k = string_format("character:%s", uid) end -- 创建并保存角色的基础信息 local rets = { k, 'uid', uid, 'account', account, -- 'appid', appid, 'channel', channel, -- 'platform', platform, 'sid', sid, 'createtime', os_time(), 'tourist', args.tourist or 1 -- nil/1:非游客账号 2: 游客账号 CDPK3-005 海外SDK } redis:hmset(rets) table_remove(rets, 1) login_user[account] = nil return 0, rets end function CMD.exsits(args) local sid = assert(args.sid) local account = assert(args.account) -- 帐号唯一标识(渠道分配) local channel = assert(args.channel) -- 渠道唯一标识 local k = string_format("account:%s:%s:%s", channel, sid, account) return redis:exists(k) end function CMD.logout(uid, agent) if online_user[uid] == agent then online_user[uid] = nil trace("User '%s' logout", uid) end end --向全服在线玩家广播网络消息 function CMD.broadcast(pname, args) for _, agent in pairs(online_user) do pcall(skynet_send, agent, "lua", "broad_cast_msg", pname, args) end end -- 向全服在线玩家的 agent 发送命令 function CMD.command(cmd, ...) for _, agent in pairs(online_user) do pcall(skynet_send, agent, "lua", cmd, ...) end end -- 向指定玩家的 agent 发送命令 function CMD.agent_command(uid, cmd, ...) trace("User '%s' agent_command", uid) local agent = online_user[uid] if agent then trace("User '%s' agent_command", uid) local ok, err = pcall(skynet_send, agent, "lua", cmd, ...) if ok then return err end end end -- 向部分玩家的 agent 发送命令 uids = {[uid] = true} function CMD.batch_agent_command(uids, cmd, ...) for uid in pairs(uids) do local agent = online_user[uid] if agent then pcall(skynet_send, agent, "lua", cmd, ...) end end end function CMD.maintain(timeout, ...) -- 向全服在线玩发送维护指令 for _, agent in pairs(online_user) do pcall(skynet_send, agent, "lua", "maintain", ...) end -- 等待在线玩家执行标准退出流程,超时强制退出 timeout = math.max(5, timeout or 15) for i=1, timeout do local number = table_length(online_user) + table_length(login_user) if number == 0 then return true end logger.warn("正在等待 %s 个用户下线", number) skynet.sleep(100) end end -- 批量查询玩家是否在线 function CMD.batch_ping(uids) local ret = {} for _, uid in ipairs(uids) do table_insert(ret, online_user[uid] and true or false) end return ret end -- 向指定的玩家发送gm命令 function CMD.gm_command(uid, cmd, ...) local agent = online_user[uid] if agent then local ok, errno, msg = pcall(skynet_call, agent, "lua", cmd, ...) if ok then return errno, msg else return 5, "系统异常" end end return 1, "玩家不在线/不存在" end skynet.init(function() skynet.register(".usercenter") end) skynet.info_func(function() return stringify({ agent = table_length(online_user), login = table_length(login_user) }) end) skynet.start(function() logger.label("") skynet.dispatch("lua", function(session, _, cmd, ...) local f = assert(CMD[cmd]) if session == 0 then f(...) else skynet_retpack(f(...)) end end) end)