--排行榜服务 local skynet = require "skynet" require "skynet.manager" local util = require "util" local logger = require "logger" local common_fun = require "model.common_fun" local stringify = require "stringify" local pipeline = require "pipeline" local redisdriver = require "skynet.db.redis" local redis local KEY_STR = "ranking:%d:list" local cjson = require "cjson" local cjson_decode = cjson.decode -- 解码 local cjson_encode = cjson.encode -- 编码 local MAX_RANK = 300 local compare = function(a, b) if a.num > b.num then return true end if a.num == b.num and a.num2 and b.num2 then return a.num2 > b.num2 end return false end local function inserting(t, n, f) assert(type(t) == "table") local f = f or compare local size = #t local n = n or size + 1 for i = 2, size do local num = math.min(i, n) if i > n and f(t[i], t[num]) then t[i], t[num] = t[num], t[i] end local temp = t[num] local j = num -1 while j >= 1 and f(temp, t[j]) do t[j+1] = t[j] j = j - 1 end t[j+1] = temp end -- if n < size then -- t[n+1] = nil -- end for i = n + 1, size do t[i] = nil end return t end local CMD = {} local ranklist = { } local showlist = { } local function update() for rank_type, list in pairs(ranklist) do inserting(list, MAX_RANK) showlist[rank_type] = {} local key = string.format(KEY_STR, rank_type) redis:del(key) local batch = pipeline(100) for rank, data in ipairs(list) do batch.add("hset", key, data.role.uid, cjson_encode(data)) showlist[rank_type][rank] = common_fun.scopy(data) end batch.execute(redis,{}) end end local function init() local conf = assert(option.redis) redis = redisdriver.connect(conf) redis:select(12) for rank_type= RANKING_ADV, RANKING_POWER do ranklist[rank_type] = {} local key = string.format(KEY_STR, rank_type) local retnuma = redis:hgetall(key) for k = 1, #retnuma, 2 do local data = cjson_decode(retnuma[k+1]) ranklist[rank_type][#ranklist[rank_type]+1] = data end end end local function watchtime() skynet.fork(function() local interval = 60*2 -- 更新间隔为2分钟 local up_time = os.time() while(true) do local now = os.time() if now > up_time then up_time = now + interval update() end skynet.sleep(300) end end) end local function find_uid(list, uid) for k, info in ipairs(list or {})do if info.role.uid == uid then return k, info end end end function CMD.player_rename(uid, name) for _, list in pairs(ranklist) do local _, info = find_uid(list, uid) if info then info.role.nickname = name end end end function CMD.update(rank_type, data) local key = string.format(KEY_STR, rank_type) ranklist[rank_type] = ranklist[rank_type] or {} local list = ranklist[rank_type] local k = find_uid(list, data.role.uid) if k then list[k] = data redis:hset(key, data.role.uid, cjson_encode(data)) return end local show = showlist[rank_type] or {} if show[MAX_RANK] and show[MAX_RANK].num > data.num then return end list[#list+1] = data redis:hset(key, data.role.uid, cjson_encode(data)) end function CMD.get_ranking(rank_type) return showlist[rank_type] or {} end -- 从排行榜中删除玩家 function CMD.del(uid) for _, list in pairs(showlist) do local k = find_uid(list, uid) if k then table.remove(list, k) end end for rank_type, list in pairs(ranklist) do local key = string.format(KEY_STR, rank_type) local k = find_uid(list, uid) if k then table.remove(list, k) redis:hdel(key, uid) end end end function CMD.start() init() watchtime() end skynet.init(function() skynet.register(".rankinglist") end) skynet.start(function() skynet.dispatch("lua", function(session, _, cmd, ...) local f = assert(CMD[cmd]) if 0==session then f(...) else skynet.retpack(f(...)) end end) end)