123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- 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("<Usercenter>")
- skynet.dispatch("lua", function(session, _, cmd, ...)
- local f = assert(CMD[cmd])
- if session == 0 then
- f(...)
- else
- skynet_retpack(f(...))
- end
- end)
- end)
|