usercenter.lua 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. local skynet = require "skynet"
  2. require "skynet.manager"
  3. local redisdriver = require "skynet.db.redis"
  4. local logger = require "logger"
  5. -- local keygen = require "model.keygen"
  6. local stringify = require "stringify"
  7. local util = require "util"
  8. local os_time = os.time
  9. local string_format = string.format
  10. local skynet_retpack = skynet.retpack
  11. local skynet_call = skynet.call
  12. local skynet_send = skynet.send
  13. local table_insert = table.insert
  14. local table_remove = table.remove
  15. local table_length = util.length
  16. local trace = logger.trace
  17. local login_user = {}
  18. local online_user = {}
  19. local allowed_server_id = {}
  20. local redis
  21. local uid_num
  22. local function keygen()
  23. local rand_list = {1,2,1,1,2,1}
  24. assert(uid_num and uid_num < 999999, uid_num)
  25. uid_num = uid_num + rand_list[(uid_num%(#rand_list))+1]
  26. redis:set("uidnum", uid_num)
  27. return string.format("%02d-%06d", option.sid, 100000+uid_num)
  28. end
  29. local CMD = {}
  30. function CMD.start()
  31. logger.info("start")
  32. local conf = assert(option.redis)
  33. redis = redisdriver.connect(conf)
  34. redis:select(0)
  35. uid_num = tonumber(redis:get("uidnum") or 0)
  36. local res = redis:smembers("sharepoint")
  37. for _, sid in ipairs(res) do
  38. allowed_server_id[math.tointeger(sid)] = true
  39. end
  40. local sid = assert(option.sid)
  41. allowed_server_id[sid] = true
  42. logger.info("%s:%s\n%s", conf.host, conf.port, stringify(allowed_server_id))
  43. end
  44. function CMD.service_list()
  45. return allowed_server_id
  46. end
  47. function CMD.batch_save(pkg)
  48. assert(#pkg > 1)
  49. pkg[1] = string_format("character:%s", pkg[1])
  50. return redis:hmset(pkg)
  51. end
  52. function CMD.load(uid)
  53. local k = string_format("character:%s", uid)
  54. local rets = redis:hgetall(k)
  55. if next(rets) then
  56. return rets
  57. end
  58. end
  59. local facebook = nil -- 云账号登陆废弃
  60. local function retrieve_facebook_account(account, sid, channel)
  61. facebook = facebook or skynet.localname(".facebook")
  62. local errno, fb = skynet.call(facebook, "lua", "retrieve", account, channel)
  63. local uid = nil
  64. if errno == 200 then
  65. uid = redis:get(string_format("account:%s:%s:%s", channel, sid, fb))
  66. end
  67. return errno, uid
  68. end
  69. function CMD.bingding(channel, sid, account, cuid) -- CDPK3-005 海外SDK
  70. -- 检查账号是否已经存在
  71. local key = string_format("account:%s:%s:%s", channel, sid, account)
  72. local uid = redis:get(key)
  73. if uid then
  74. return STD_ERR.PLYAER_BING_ACCOUNT_EXIST -- 绑定账号已经存在
  75. end
  76. logger.trace( "##### key %s uid %s", key, cuid)
  77. local ok = redis:set(key, cuid)
  78. if ok ~= "OK" then
  79. return STD_ERR.PLYAER_BING_SERVER_ERROR
  80. end
  81. return 0
  82. end
  83. function CMD.login(args, agent)
  84. local sid = assert(args.sid) -- 服务器唯一标识
  85. local account = assert(args.account) -- 帐号唯一标识(渠道分配)
  86. -- local appid = assert(args.appid) -- App唯一标识
  87. local channel = assert(args.channel) -- 渠道唯一标识
  88. -- local platform = assert(args.platform) -- 操作系统(pc,ios,android等)
  89. -- local version = assert(args.version) -- 客户端版本号
  90. if not allowed_server_id[sid] then return 1 end -- 防止非法的服务器标识
  91. if login_user[account] then return 2 end -- 防止多设备登录
  92. login_user[account] = true
  93. -- 查找帐号在指定 sid 上创建的角色id
  94. local k = string_format("account:%s:%s:%s", channel, sid, account)
  95. local uid = redis:get(k)
  96. -- 云账号登陆废弃
  97. -- if uid == nil then
  98. -- local errno, val = retrieve_facebook_account(account, sid, channel)
  99. -- if errno == 200 then
  100. -- uid = val
  101. -- elseif errno ~= 404 then
  102. -- login_user[account] = nil
  103. -- return 3 -- 暂时不能放用户进来
  104. -- end
  105. -- end
  106. if uid then
  107. -- 通知当前在线设备下线
  108. local old = online_user[uid]
  109. online_user[uid] = agent
  110. if old then
  111. pcall(skynet_call, old, "lua", "multilogin")
  112. end
  113. -- 载入角色数据
  114. k = string_format("character:%s", uid)
  115. local rets = redis:hgetall(k)
  116. if next(rets) then
  117. login_user[account] = nil
  118. return 0, rets
  119. end
  120. else
  121. -- 为尚未创建角色的帐号关联一个新的角色id
  122. uid = keygen()
  123. local key = string_format("character:%s", uid)
  124. assert(not redis:exists(key))
  125. online_user[uid] = agent
  126. redis:set(k, uid)
  127. k = string_format("character:%s", uid)
  128. end
  129. -- 创建并保存角色的基础信息
  130. local rets = {
  131. k,
  132. 'uid', uid,
  133. 'account', account,
  134. -- 'appid', appid,
  135. 'channel', channel,
  136. -- 'platform', platform,
  137. 'sid', sid,
  138. 'createtime', os_time(),
  139. 'tourist', args.tourist or 1 -- nil/1:非游客账号 2: 游客账号 CDPK3-005 海外SDK
  140. }
  141. redis:hmset(rets)
  142. table_remove(rets, 1)
  143. login_user[account] = nil
  144. return 0, rets
  145. end
  146. function CMD.exsits(args)
  147. local sid = assert(args.sid)
  148. local account = assert(args.account) -- 帐号唯一标识(渠道分配)
  149. local channel = assert(args.channel) -- 渠道唯一标识
  150. local k = string_format("account:%s:%s:%s", channel, sid, account)
  151. return redis:exists(k)
  152. end
  153. function CMD.logout(uid, agent)
  154. if online_user[uid] == agent then
  155. online_user[uid] = nil
  156. trace("User '%s' logout", uid)
  157. end
  158. end
  159. --向全服在线玩家广播网络消息
  160. function CMD.broadcast(pname, args)
  161. for _, agent in pairs(online_user) do
  162. pcall(skynet_send, agent, "lua", "broad_cast_msg", pname, args)
  163. end
  164. end
  165. -- 向全服在线玩家的 agent 发送命令
  166. function CMD.command(cmd, ...)
  167. for _, agent in pairs(online_user) do
  168. pcall(skynet_send, agent, "lua", cmd, ...)
  169. end
  170. end
  171. -- 向指定玩家的 agent 发送命令
  172. function CMD.agent_command(uid, cmd, ...)
  173. trace("User '%s' agent_command", uid)
  174. local agent = online_user[uid]
  175. if agent then
  176. trace("User '%s' agent_command", uid)
  177. local ok, err = pcall(skynet_send, agent, "lua", cmd, ...)
  178. if ok then return err end
  179. end
  180. end
  181. -- 向部分玩家的 agent 发送命令 uids = {[uid] = true}
  182. function CMD.batch_agent_command(uids, cmd, ...)
  183. for uid in pairs(uids) do
  184. local agent = online_user[uid]
  185. if agent then
  186. pcall(skynet_send, agent, "lua", cmd, ...)
  187. end
  188. end
  189. end
  190. function CMD.maintain(timeout, ...)
  191. -- 向全服在线玩发送维护指令
  192. for _, agent in pairs(online_user) do
  193. pcall(skynet_send, agent, "lua", "maintain", ...)
  194. end
  195. -- 等待在线玩家执行标准退出流程,超时强制退出
  196. timeout = math.max(5, timeout or 15)
  197. for i=1, timeout do
  198. local number = table_length(online_user) + table_length(login_user)
  199. if number == 0 then
  200. return true
  201. end
  202. logger.warn("正在等待 %s 个用户下线", number)
  203. skynet.sleep(100)
  204. end
  205. end
  206. -- 批量查询玩家是否在线
  207. function CMD.batch_ping(uids)
  208. local ret = {}
  209. for _, uid in ipairs(uids) do
  210. table_insert(ret, online_user[uid] and true or false)
  211. end
  212. return ret
  213. end
  214. -- 向指定的玩家发送gm命令
  215. function CMD.gm_command(uid, cmd, ...)
  216. local agent = online_user[uid]
  217. if agent then
  218. local ok, errno, msg = pcall(skynet_call, agent, "lua", cmd, ...)
  219. if ok then
  220. return errno, msg
  221. else
  222. return 5, "系统异常"
  223. end
  224. end
  225. return 1, "玩家不在线/不存在"
  226. end
  227. skynet.init(function()
  228. skynet.register(".usercenter")
  229. end)
  230. skynet.info_func(function()
  231. return stringify({
  232. agent = table_length(online_user),
  233. login = table_length(login_user)
  234. })
  235. end)
  236. skynet.start(function()
  237. logger.label("<Usercenter>")
  238. skynet.dispatch("lua", function(session, _, cmd, ...)
  239. local f = assert(CMD[cmd])
  240. if session == 0 then
  241. f(...)
  242. else
  243. skynet_retpack(f(...))
  244. end
  245. end)
  246. end)