diff --git a/src/GlobalVar.lua b/src/GlobalVar.lua index 22b437e..07534bd 100644 --- a/src/GlobalVar.lua +++ b/src/GlobalVar.lua @@ -1,5 +1,6 @@ XXTEA_KEY = "699D448D6D24f7F941E9F6E99F823E18" RESET_TIME = 4 +RESET_RANK_TIME = 8 MAX_ROLE_NUM = 1000000 -- 属性枚举 AttsEnum = { diff --git a/src/ProtocolCode.lua b/src/ProtocolCode.lua index ddb4c45..618cd62 100644 --- a/src/ProtocolCode.lua +++ b/src/ProtocolCode.lua @@ -90,12 +90,14 @@ actionCodes = { Diner_addWantFoodRpc = 312, Diner_initTaskRpc = 313, Diner_handleTaskRpc = 314, + Diner_rankRpc = 315, Tower_roleFormatRpc = 350, Tower_startBattleRpc = 351, Tower_endBattleRpc = 352, Tower_rankRpc = 353, Tower_bugCountRpc = 354, + Tower_rankInfoRpc = 355, Car_makePotionRpc = 400, Car_equipUpRpc = 401, diff --git a/src/RedisKeys.lua b/src/RedisKeys.lua index 7e3cc2b..4e2c933 100644 --- a/src/RedisKeys.lua +++ b/src/RedisKeys.lua @@ -8,6 +8,13 @@ R_EQUIP_ROOT = "role:%d:equip*" -- 装备根目录 R_RUNEIDS = "role:%d:runeIds" -- 玩家拥有符文自增id R_RUNE = "role:%d:rune:%d" -- 符文详细信息 + +-- rank +RANK_TOWER = "rank:tower" +RANK_TOWER_INFO = "rank:tower:info" + +RANK_DINER = {"rank:diner1", "rank:diner2"} -- 餐厅排行榜 两个每天互换 +RANK_DINER_INFO = "rank:diner:info" -- -- role -- R_FARM_KEY = "role:%d:farm" -- R_TOWER_KEY = "role:%d:tower" diff --git a/src/actions/DinerAction.lua b/src/actions/DinerAction.lua index 3030d12..d7c69ee 100644 --- a/src/actions/DinerAction.lua +++ b/src/actions/DinerAction.lua @@ -67,6 +67,7 @@ function _M.addSellRpc( agent, data ) if not sells[slot] then sells[slot] = { reward = "", + popular = 0, } end sells[slot].dish = dish @@ -123,7 +124,7 @@ end function _M.getSellRewardRpc( agent, data ) local role = agent.role local dirty = false - local reward = "" + local reward, popular = "", 0 local sells = json.decode(role.dinerData:getProperty("sells")) for slot, _ in pairs(sells) do role.dinerData:updateSell(slot) @@ -134,6 +135,7 @@ function _M.getSellRewardRpc( agent, data ) for k,v in pairs(rewards) do reward = reward:incrv(k, v) end + popular = popular + (sell.popular or 0) if rewards[ItemId.Gold] and rewards[ItemId.Gold] > 0 then if role.dinerData:checkDinerTask(DinerTask.DishWithGold, rewards[ItemId.Gold], sell.dish, nil, true) then @@ -148,12 +150,15 @@ function _M.getSellRewardRpc( agent, data ) end end sells[slot].reward = "" + sells[slot].popular = 0 end role.dinerData:updateProperty({field = "sells", value = json.encode(sells)}) for k, v in pairs(reward:toNumMap()) do role:addItem({itemId = k,count = v}) end + role.dinerData:popularAdd(popular) + if dirty then role.dinerData:notifyUpdateProperty("order", role.dinerData:getProperty("order")) end @@ -179,7 +184,7 @@ function _M.expediteSellRpc( agent, data ) end local dirty = false - local reward,popular = "",0 + local reward,popular = "", 0 local sells = json.decode(role.dinerData:getProperty("sells")) for slot, _ in pairs(sells) do role.dinerData:updateSell(slot) @@ -216,6 +221,8 @@ function _M.expediteSellRpc( agent, data ) role:addItem({itemId = k,count = v}) end + role.dinerData:popularAdd(popular) + if dirty then role.dinerData:notifyUpdateProperty("order", role.dinerData:getProperty("order")) end @@ -681,4 +688,13 @@ function _M.handleTaskRpc(agent, data) return true end +function _M.rankRpc(agent , data) + local role = agent.role + + local rankInfo = role.dinerData:getPopularRank() + SendPacket(actionCodes.Diner_rankRpc, MsgPack.pack(rankInfo)) + return true +end + + return _M \ No newline at end of file diff --git a/src/actions/RoleAction.lua b/src/actions/RoleAction.lua index 08ed35f..4ff528f 100644 --- a/src/actions/RoleAction.lua +++ b/src/actions/RoleAction.lua @@ -120,6 +120,7 @@ function _M.loginRpc( agent, data ) -- 跨天登陆事件 role:onCrossDay(now) + role:onResetRank(now) role:setProperty("ltime", now) diff --git a/src/actions/TowerAction.lua b/src/actions/TowerAction.lua index 8f3270a..bf72622 100644 --- a/src/actions/TowerAction.lua +++ b/src/actions/TowerAction.lua @@ -86,6 +86,9 @@ function _M.endBattleRpc(agent, data) local reward if msg.starNum and msg.starNum > 0 then --win curCount = math.min(curCount + 1, globalCsv.tower_count_limit) -- 返还次数 + --排行榜 + role:setTowerRank(towerInfo.l) + towerInfo.l = towerInfo.l + 1 reward = role:award(curTower.reward) end @@ -122,9 +125,15 @@ end function _M.rankRpc(agent , data) local role = agent.role + SendPacket(actionCodes.Tower_rankRpc, MsgPack.pack(role:getTowerRank())) + return true +end - local rankList = {} - SendPacket(actionCodes.Tower_rankRpc, MsgPack.pack({rankList = rankList})) +function _M.rankInfoRpc(agent , data) + local role = agent.role + local msg = MsgPack.unpack(data) + local roleId = msg.roleId + SendPacket(actionCodes.Tower_rankInfoRpc, MsgPack.pack({format = role:getTowerRankOneInfo(roleId)})) return true end diff --git a/src/models/Diner.lua b/src/models/Diner.lua index 5d475b3..646956d 100644 --- a/src/models/Diner.lua +++ b/src/models/Diner.lua @@ -16,11 +16,14 @@ Diner.schema = { task = {"table", {}}, -- 任务刷新 {et = 消失时间 id = 任务id, refuse = 0} } +function Diner:rankResetData(notify) + self:updateProperty({field = "popular", value = 0, notNotify = not notify}) +end + function Diner:refreshDailyData(notify) -- 每日加速次数 self:updateProperty({field = "expedite", value = 1, notNotify = not notify}) self:setProperty("expedite", 1) - -- 特殊订单 local orders = json.decode(self:getProperty("order")) local hadTask = {} @@ -170,8 +173,8 @@ function Diner:updateSell(slot, calOnly) sells[slot].count = lastCount sells[slot].level = self:getProperty("dishTree"):getv(sell.dish, 1) sells[slot].reward = reward + sells[slot].popular = (sells[slot].popular or 0) + popular self:setProperty("sells", json.encode(sells)) - self:updateProperty({field = "popular", delta = popular}) self:checkDinerTask(DinerTask.SellDish, deltaCount, sell.dish) self:checkDinerTask(DinerTask.SellDishType, deltaCount, math.ceil(sell.dish / 100)) self:checkDinerTask(DinerTask.SellDishRare, deltaCount, dishData.rarity) @@ -181,7 +184,6 @@ function Diner:updateSell(slot, calOnly) deltaTime = deltaTime, lastCount = lastCount, reward = reward, - popular = popular, } end @@ -204,7 +206,6 @@ function Diner:expediteSell(slot) sells[slot].time = sell.time - deltaTime sells[slot].count = lastCount self:setProperty("sells", json.encode(sells)) - self:updateProperty({field = "popular", delta = popular}) self:checkDinerTask(DinerTask.SellDish, expediteCount, sell.dish) self:checkDinerTask(DinerTask.SellDishType, expediteCount, math.ceil(sell.dish / 100)) self:checkDinerTask(DinerTask.SellDishRare, expediteCount, dishData.rarity) @@ -233,15 +234,61 @@ end function Diner:getMaxDishs() local dishCount = globalCsv.diner_sell_dish_init - local buildingCsv = csvdb["diner_buildingCsv"] - for id, level in pairs(self:getProperty("buildL"):toNumMap()) do - if buildingCsv[id][level].storage > 0 then - dishCount = dishCount + buildingCsv[id][level].storage - end - end + -- local buildingCsv = csvdb["diner_buildingCsv"] + -- for id, level in pairs(self:getProperty("buildL"):toNumMap()) do + -- if buildingCsv[id][level].storage > 0 then + -- dishCount = dishCount + buildingCsv[id][level].storage + -- end + -- end return dishCount end +function Diner:popularAdd(popular) + if popular ~= 0 then + self:updateProperty({field = "popular", delta = popular}) + local dbKey = self.owner:getCurDinerRankKey() + local roleId = self.owner:getProperty("id") + -- 更新排行榜 + local curPopular = self:getProperty("popular") + redisproxy:pipelining(function (red) + red:zadd(dbKey, curPopular, roleId) --更新分数 + red:hset(RANK_DINER_INFO, roleId, MsgPack.pack({ + lv = self:getProperty("buildL"):getv(1, 0), + name = self.owner:getProperty("name"), + headId = self.owner:getProperty("headId") + })) + end) + end +end + +function Diner:getPopularRank() + local dbKey = self.owner:getCurDinerRankKey() + local list = {} + local ids = redisproxy:zrevrange(dbKey, 0 , 99, "WITHSCORES") + local redret = {} + if ids and next(ids) then + redret = redisproxy:pipelining(function (red) + for i = 1, #ids, 2 do + local roleId = ids[i] + local score = ids[i + 1] + list[#list + 1] = {score = tonumber(score), roleId = tonumber(roleId)} + red:hget(RANK_DINER_INFO, roleId) + end + end) + end + for i = 1, #redret do + local player = MsgPack.unpack(redret[i]) + list[i].player = player + end + local rank = redisproxy:ZREVRANK(dbKey, self.owner:getProperty("id")) + if not rank then + rank = -1 + else + rank = rank + 1 + end + return {list = list, rank = rank} +end + function Diner:data() local properties = {"buildL", "order", "sells", "dishTree", "skillTree","popular","expedite","gfood", "task"} local data = self:getProperties(properties) diff --git a/src/models/Role.lua b/src/models/Role.lua index 0a09cb8..e0fbe0f 100644 --- a/src/models/Role.lua +++ b/src/models/Role.lua @@ -22,6 +22,7 @@ Role.schema = { id = {"number"}, uid = {"string", ""}, name = {"string", ""}, + headId = {"number", 3201}, sid = {"number", 0}, device = {"string", ""}, banTime = {"number", 0}, @@ -178,6 +179,7 @@ function Role:data() return { id = self:getProperty("id"), name = self:getProperty("name"), + headId = self:getProperty("headId"), level = self:getProperty("level"), exp = self:getProperty("exp"), items = self:getProperty("items"):toNumMap(), diff --git a/src/models/RolePlugin.lua b/src/models/RolePlugin.lua index e9e8fe1..aae409e 100644 --- a/src/models/RolePlugin.lua +++ b/src/models/RolePlugin.lua @@ -31,9 +31,37 @@ function RolePlugin.bind(Role) if notify then self:notifyUpdateProperties(response) end + + if RESET_TIME == RESET_RANK_TIME then + self:onResetRank_raw(ltime, now, notify) + end + self:setProperty("ltime", now) return true end end + + function Role:onResetRank(now, notify) + local ltime = self:getProperty("ltime") + if isCrossDay(ltime, now, RESET_RANK_TIME) then + local response = self:onResetRank_raw(ltime, now, notify) + + if notify and next(response) then + self:notifyUpdateProperties(response) + end + + self:setProperty("ltime", now) + return true + end + end + + function Role:onResetRank_raw(ltime, now, notify) + local response = {} + + self.dinerData:rankResetData(notify) + + return response + end + function Role:onOfflineEvent() end @@ -613,7 +641,8 @@ function RolePlugin.bind(Role) self:changeUpdates({{type = "funcOpen", field = unlockData.type, value = 1}}) else local oldV = self:getFuncLv(unlockData.type) - self:changeUpdates({{type = "funcLv", field = unlockData.type, value = oldV + count}}) + local newLv = math.min(oldV + count, unlockData.value2) + self:changeUpdates({{type = "funcLv", field = unlockData.type, value = newLv}}) end else self:changeUpdates({{type = "funcOpen", field = func, value = 1}}) @@ -661,6 +690,97 @@ function RolePlugin.bind(Role) self:setProperty("advElS", globalCsv.adv_endless_season) end end + + function Role:getTeamBattleValue(heros) + local battleV = 0 + for _, heroId in pairs(heros) do + local hero = self.heros[heroId] + battleV = battleV + hero:getProperty("battleV") + end + return battleV + end + + function Role:recordRankTeam(heroIds) + local heros = {} + for slot, heroId in pairs(heroIds) do + local hero = self.heros[heroId] + heros[slot] = { + htype = hero:getProperty("type"), + lv = hero:getProperty("level"), + breakL = hero:getProperty("breakL"), + } + end + return heros + end + + local StdDinerRankTime = toUnixtime("20190101"..string.format("%02x", RESET_RANK_TIME)) --跨天时间 + function Role:getCurDinerRankKey() + local now = skynet.timex() + local idx = 1 + if math.floor((now - StdDinerRankTime) / 86400) % 2 == 1 then + idx = 2 + end + return RANK_DINER[idx] + end + + local StdTowerRankTime = toUnixtime("2019010100") + function Role:setTowerRank(level) + local now = skynet.timex() + local ct = math.ceil((now - StdTowerRankTime) / 86400) --按天计算 365 * 27 < 10000 可以维持 27 年 + local ct = 10000 - ct -- 越早的排名越靠前 + local towerTeam = self:getProperty("towerF") + local battleV = self:getTeamBattleValue(towerTeam.heros) + local score = (level * 10000 + ct) * 10000000 + battleV + + local curInfo = { + name = self:getProperty("name"), + headId = self:getProperty("headId"), + lv = self:getProperty("level"), + batteV = battleV, + level = level, + format = self:recordRankTeam(towerTeam.heros), + } + local roleId = self:getProperty("id") + redisproxy:pipelining(function (red) + red:zadd(RANK_TOWER, score, roleId) --更新分数 + red:hset(RANK_TOWER_INFO, roleId, MsgPack.pack(curInfo)) + end) + end + + function Role:getTowerRank() + local list = {} + local ids = redisproxy:zrevrange(RANK_TOWER, 0 , 99) + local redret = {} + if ids and next(ids) then + redret = redisproxy:pipelining(function (red) + for i = 1, #ids do + local roleId = ids[i] + table.insert(list, {roleId = tonumber(roleId)}) + red:hget(RANK_TOWER_INFO, roleId) + end + end) + end + for i = 1, #redret do + local player = MsgPack.unpack(redret[i]) + player.format = nil + list[i].player = player + end + local rank = redisproxy:ZREVRANK(RANK_TOWER, self:getProperty("id")) + if not rank then + rank = -1 + else + rank = rank + 1 + end + return {list = list, rank = rank} + end + + function Role:getTowerRankOneInfo(roleId) + local data = redisproxy:hget(RANK_TOWER_INFO, roleId) + if data then + local player = MsgPack.unpack(data) + return player.format + end + end end return RolePlugin \ No newline at end of file diff --git a/src/services/agent_util.lua b/src/services/agent_util.lua index 593ef6e..d6a45a3 100644 --- a/src/services/agent_util.lua +++ b/src/services/agent_util.lua @@ -41,6 +41,7 @@ end local PointDataMark = {} local resetTimeStr = string.format("%02d00", RESET_TIME) +local resetRankTimeStr = string.format("%02d00", RESET_RANK_TIME) local function check_daily_reset(agent, now) local date = os.date("*t", now) @@ -66,6 +67,13 @@ local function check_daily_reset(agent, now) role:onCrossDay(now, true) end end + if resetTimeStr ~= resetRankTimeStr and timeEffect(resetRankTimeStr) then + -- 刷新排行榜需要重置的数据 + local role = agent.role + if role then + role:onResetRank(now, true) + end + end end function _M:update(agent) @@ -76,7 +84,7 @@ function _M:update(agent) nextCheckTime = now + HEART_TIMER_INTERVAL end pcall(check_daily_reset, agent, now) - pcall(role.onRecoverTimer, role, now) + -- pcall(role.onRecoverTimer, role, now) end function _M:heart_beat(agent) diff --git a/src/utils/CommonFunc.lua b/src/utils/CommonFunc.lua index ded3560..9817c1e 100644 --- a/src/utils/CommonFunc.lua +++ b/src/utils/CommonFunc.lua @@ -109,11 +109,12 @@ function isCrossMonth(target, now) end end -function isCrossDay(lastTime, now) +function isCrossDay(lastTime, now, resetTime) + resetTime = resetTime or RESET_TIME if lastTime == 0 then return true end now = now or skynet.timex() - local today4h = specTime({hour = RESET_TIME}, now - RESET_TIME * 3600) - return lastTime < today4h and now >= today4h + local todayResetH = specTime({hour = resetTime}, now - resetTime * 3600) + return lastTime < todayResetH and now >= todayResetH end function crossDay(target, now) -- libgit2 0.21.2