Commit 598357652e20e82a14325183b6d22e2c989a896c

Authored by zhouhaihai
1 parent 03a6166a

排行榜

src/GlobalVar.lua
1 1 XXTEA_KEY = "699D448D6D24f7F941E9F6E99F823E18"
2 2 RESET_TIME = 4
  3 +RESET_RANK_TIME = 8
3 4 MAX_ROLE_NUM = 1000000
4 5 -- 属性枚举
5 6 AttsEnum = {
... ...
src/ProtocolCode.lua
... ... @@ -90,12 +90,14 @@ actionCodes = {
90 90 Diner_addWantFoodRpc = 312,
91 91 Diner_initTaskRpc = 313,
92 92 Diner_handleTaskRpc = 314,
  93 + Diner_rankRpc = 315,
93 94  
94 95 Tower_roleFormatRpc = 350,
95 96 Tower_startBattleRpc = 351,
96 97 Tower_endBattleRpc = 352,
97 98 Tower_rankRpc = 353,
98 99 Tower_bugCountRpc = 354,
  100 + Tower_rankInfoRpc = 355,
99 101  
100 102 Car_makePotionRpc = 400,
101 103 Car_equipUpRpc = 401,
... ...
src/RedisKeys.lua
... ... @@ -8,6 +8,13 @@ R_EQUIP_ROOT = "role:%d:equip*" -- 装备根目录
8 8 R_RUNEIDS = "role:%d:runeIds" -- 玩家拥有符文自增id
9 9 R_RUNE = "role:%d:rune:%d" -- 符文详细信息
10 10  
  11 +
  12 +-- rank
  13 +RANK_TOWER = "rank:tower"
  14 +RANK_TOWER_INFO = "rank:tower:info"
  15 +
  16 +RANK_DINER = {"rank:diner1", "rank:diner2"} -- 餐厅排行榜 两个每天互换
  17 +RANK_DINER_INFO = "rank:diner:info"
11 18 -- -- role
12 19 -- R_FARM_KEY = "role:%d:farm"
13 20 -- R_TOWER_KEY = "role:%d:tower"
... ...
src/actions/DinerAction.lua
... ... @@ -67,6 +67,7 @@ function _M.addSellRpc( agent, data )
67 67 if not sells[slot] then
68 68 sells[slot] = {
69 69 reward = "",
  70 + popular = 0,
70 71 }
71 72 end
72 73 sells[slot].dish = dish
... ... @@ -123,7 +124,7 @@ end
123 124 function _M.getSellRewardRpc( agent, data )
124 125 local role = agent.role
125 126 local dirty = false
126   - local reward = ""
  127 + local reward, popular = "", 0
127 128 local sells = json.decode(role.dinerData:getProperty("sells"))
128 129 for slot, _ in pairs(sells) do
129 130 role.dinerData:updateSell(slot)
... ... @@ -134,6 +135,7 @@ function _M.getSellRewardRpc( agent, data )
134 135 for k,v in pairs(rewards) do
135 136 reward = reward:incrv(k, v)
136 137 end
  138 + popular = popular + (sell.popular or 0)
137 139  
138 140 if rewards[ItemId.Gold] and rewards[ItemId.Gold] > 0 then
139 141 if role.dinerData:checkDinerTask(DinerTask.DishWithGold, rewards[ItemId.Gold], sell.dish, nil, true) then
... ... @@ -148,12 +150,15 @@ function _M.getSellRewardRpc( agent, data )
148 150 end
149 151 end
150 152 sells[slot].reward = ""
  153 + sells[slot].popular = 0
151 154 end
152 155 role.dinerData:updateProperty({field = "sells", value = json.encode(sells)})
153 156 for k, v in pairs(reward:toNumMap()) do
154 157 role:addItem({itemId = k,count = v})
155 158 end
156 159  
  160 + role.dinerData:popularAdd(popular)
  161 +
157 162 if dirty then
158 163 role.dinerData:notifyUpdateProperty("order", role.dinerData:getProperty("order"))
159 164 end
... ... @@ -179,7 +184,7 @@ function _M.expediteSellRpc( agent, data )
179 184 end
180 185  
181 186 local dirty = false
182   - local reward,popular = "",0
  187 + local reward,popular = "", 0
183 188 local sells = json.decode(role.dinerData:getProperty("sells"))
184 189 for slot, _ in pairs(sells) do
185 190 role.dinerData:updateSell(slot)
... ... @@ -216,6 +221,8 @@ function _M.expediteSellRpc( agent, data )
216 221 role:addItem({itemId = k,count = v})
217 222 end
218 223  
  224 + role.dinerData:popularAdd(popular)
  225 +
219 226 if dirty then
220 227 role.dinerData:notifyUpdateProperty("order", role.dinerData:getProperty("order"))
221 228 end
... ... @@ -681,4 +688,13 @@ function _M.handleTaskRpc(agent, data)
681 688 return true
682 689 end
683 690  
  691 +function _M.rankRpc(agent , data)
  692 + local role = agent.role
  693 +
  694 + local rankInfo = role.dinerData:getPopularRank()
  695 + SendPacket(actionCodes.Diner_rankRpc, MsgPack.pack(rankInfo))
  696 + return true
  697 +end
  698 +
  699 +
684 700 return _M
685 701 \ No newline at end of file
... ...
src/actions/RoleAction.lua
... ... @@ -120,6 +120,7 @@ function _M.loginRpc( agent, data )
120 120  
121 121 -- 跨天登陆事件
122 122 role:onCrossDay(now)
  123 + role:onResetRank(now)
123 124 role:setProperty("ltime", now)
124 125  
125 126  
... ...
src/actions/TowerAction.lua
... ... @@ -86,6 +86,9 @@ function _M.endBattleRpc(agent, data)
86 86 local reward
87 87 if msg.starNum and msg.starNum > 0 then --win
88 88 curCount = math.min(curCount + 1, globalCsv.tower_count_limit) -- 返还次数
  89 + --排行榜
  90 + role:setTowerRank(towerInfo.l)
  91 +
89 92 towerInfo.l = towerInfo.l + 1
90 93 reward = role:award(curTower.reward)
91 94 end
... ... @@ -122,9 +125,15 @@ end
122 125  
123 126 function _M.rankRpc(agent , data)
124 127 local role = agent.role
  128 + SendPacket(actionCodes.Tower_rankRpc, MsgPack.pack(role:getTowerRank()))
  129 + return true
  130 +end
125 131  
126   - local rankList = {}
127   - SendPacket(actionCodes.Tower_rankRpc, MsgPack.pack({rankList = rankList}))
  132 +function _M.rankInfoRpc(agent , data)
  133 + local role = agent.role
  134 + local msg = MsgPack.unpack(data)
  135 + local roleId = msg.roleId
  136 + SendPacket(actionCodes.Tower_rankInfoRpc, MsgPack.pack({format = role:getTowerRankOneInfo(roleId)}))
128 137 return true
129 138 end
130 139  
... ...
src/models/Diner.lua
... ... @@ -16,11 +16,14 @@ Diner.schema = {
16 16 task = {"table", {}}, -- 任务刷新 {et = 消失时间 id = 任务id, refuse = 0}
17 17 }
18 18  
  19 +function Diner:rankResetData(notify)
  20 + self:updateProperty({field = "popular", value = 0, notNotify = not notify})
  21 +end
  22 +
19 23 function Diner:refreshDailyData(notify)
20 24 -- 每日加速次数
21 25 self:updateProperty({field = "expedite", value = 1, notNotify = not notify})
22 26 self:setProperty("expedite", 1)
23   -
24 27 -- 特殊订单
25 28 local orders = json.decode(self:getProperty("order"))
26 29 local hadTask = {}
... ... @@ -170,8 +173,8 @@ function Diner:updateSell(slot, calOnly)
170 173 sells[slot].count = lastCount
171 174 sells[slot].level = self:getProperty("dishTree"):getv(sell.dish, 1)
172 175 sells[slot].reward = reward
  176 + sells[slot].popular = (sells[slot].popular or 0) + popular
173 177 self:setProperty("sells", json.encode(sells))
174   - self:updateProperty({field = "popular", delta = popular})
175 178 self:checkDinerTask(DinerTask.SellDish, deltaCount, sell.dish)
176 179 self:checkDinerTask(DinerTask.SellDishType, deltaCount, math.ceil(sell.dish / 100))
177 180 self:checkDinerTask(DinerTask.SellDishRare, deltaCount, dishData.rarity)
... ... @@ -181,7 +184,6 @@ function Diner:updateSell(slot, calOnly)
181 184 deltaTime = deltaTime,
182 185 lastCount = lastCount,
183 186 reward = reward,
184   - popular = popular,
185 187 }
186 188 end
187 189  
... ... @@ -204,7 +206,6 @@ function Diner:expediteSell(slot)
204 206 sells[slot].time = sell.time - deltaTime
205 207 sells[slot].count = lastCount
206 208 self:setProperty("sells", json.encode(sells))
207   - self:updateProperty({field = "popular", delta = popular})
208 209 self:checkDinerTask(DinerTask.SellDish, expediteCount, sell.dish)
209 210 self:checkDinerTask(DinerTask.SellDishType, expediteCount, math.ceil(sell.dish / 100))
210 211 self:checkDinerTask(DinerTask.SellDishRare, expediteCount, dishData.rarity)
... ... @@ -233,15 +234,61 @@ end
233 234 function Diner:getMaxDishs()
234 235 local dishCount = globalCsv.diner_sell_dish_init
235 236  
236   - local buildingCsv = csvdb["diner_buildingCsv"]
237   - for id, level in pairs(self:getProperty("buildL"):toNumMap()) do
238   - if buildingCsv[id][level].storage > 0 then
239   - dishCount = dishCount + buildingCsv[id][level].storage
240   - end
241   - end
  237 + -- local buildingCsv = csvdb["diner_buildingCsv"]
  238 + -- for id, level in pairs(self:getProperty("buildL"):toNumMap()) do
  239 + -- if buildingCsv[id][level].storage > 0 then
  240 + -- dishCount = dishCount + buildingCsv[id][level].storage
  241 + -- end
  242 + -- end
242 243 return dishCount
243 244 end
244 245  
  246 +function Diner:popularAdd(popular)
  247 + if popular ~= 0 then
  248 + self:updateProperty({field = "popular", delta = popular})
  249 + local dbKey = self.owner:getCurDinerRankKey()
  250 + local roleId = self.owner:getProperty("id")
  251 + -- 更新排行榜
  252 + local curPopular = self:getProperty("popular")
  253 + redisproxy:pipelining(function (red)
  254 + red:zadd(dbKey, curPopular, roleId) --更新分数
  255 + red:hset(RANK_DINER_INFO, roleId, MsgPack.pack({
  256 + lv = self:getProperty("buildL"):getv(1, 0),
  257 + name = self.owner:getProperty("name"),
  258 + headId = self.owner:getProperty("headId")
  259 + }))
  260 + end)
  261 + end
  262 +end
  263 +
  264 +function Diner:getPopularRank()
  265 + local dbKey = self.owner:getCurDinerRankKey()
  266 + local list = {}
  267 + local ids = redisproxy:zrevrange(dbKey, 0 , 99, "WITHSCORES")
  268 + local redret = {}
  269 + if ids and next(ids) then
  270 + redret = redisproxy:pipelining(function (red)
  271 + for i = 1, #ids, 2 do
  272 + local roleId = ids[i]
  273 + local score = ids[i + 1]
  274 + list[#list + 1] = {score = tonumber(score), roleId = tonumber(roleId)}
  275 + red:hget(RANK_DINER_INFO, roleId)
  276 + end
  277 + end)
  278 + end
  279 + for i = 1, #redret do
  280 + local player = MsgPack.unpack(redret[i])
  281 + list[i].player = player
  282 + end
  283 + local rank = redisproxy:ZREVRANK(dbKey, self.owner:getProperty("id"))
  284 + if not rank then
  285 + rank = -1
  286 + else
  287 + rank = rank + 1
  288 + end
  289 + return {list = list, rank = rank}
  290 +end
  291 +
245 292 function Diner:data()
246 293 local properties = {"buildL", "order", "sells", "dishTree", "skillTree","popular","expedite","gfood", "task"}
247 294 local data = self:getProperties(properties)
... ...
src/models/Role.lua
... ... @@ -22,6 +22,7 @@ Role.schema = {
22 22 id = {"number"},
23 23 uid = {"string", ""},
24 24 name = {"string", ""},
  25 + headId = {"number", 3201},
25 26 sid = {"number", 0},
26 27 device = {"string", ""},
27 28 banTime = {"number", 0},
... ... @@ -178,6 +179,7 @@ function Role:data()
178 179 return {
179 180 id = self:getProperty("id"),
180 181 name = self:getProperty("name"),
  182 + headId = self:getProperty("headId"),
181 183 level = self:getProperty("level"),
182 184 exp = self:getProperty("exp"),
183 185 items = self:getProperty("items"):toNumMap(),
... ...
src/models/RolePlugin.lua
... ... @@ -31,9 +31,37 @@ function RolePlugin.bind(Role)
31 31 if notify then
32 32 self:notifyUpdateProperties(response)
33 33 end
  34 +
  35 + if RESET_TIME == RESET_RANK_TIME then
  36 + self:onResetRank_raw(ltime, now, notify)
  37 + end
  38 + self:setProperty("ltime", now)
34 39 return true
35 40 end
36 41 end
  42 +
  43 + function Role:onResetRank(now, notify)
  44 + local ltime = self:getProperty("ltime")
  45 + if isCrossDay(ltime, now, RESET_RANK_TIME) then
  46 + local response = self:onResetRank_raw(ltime, now, notify)
  47 +
  48 + if notify and next(response) then
  49 + self:notifyUpdateProperties(response)
  50 + end
  51 +
  52 + self:setProperty("ltime", now)
  53 + return true
  54 + end
  55 + end
  56 +
  57 + function Role:onResetRank_raw(ltime, now, notify)
  58 + local response = {}
  59 +
  60 + self.dinerData:rankResetData(notify)
  61 +
  62 + return response
  63 + end
  64 +
37 65 function Role:onOfflineEvent()
38 66  
39 67 end
... ... @@ -613,7 +641,8 @@ function RolePlugin.bind(Role)
613 641 self:changeUpdates({{type = "funcOpen", field = unlockData.type, value = 1}})
614 642 else
615 643 local oldV = self:getFuncLv(unlockData.type)
616   - self:changeUpdates({{type = "funcLv", field = unlockData.type, value = oldV + count}})
  644 + local newLv = math.min(oldV + count, unlockData.value2)
  645 + self:changeUpdates({{type = "funcLv", field = unlockData.type, value = newLv}})
617 646 end
618 647 else
619 648 self:changeUpdates({{type = "funcOpen", field = func, value = 1}})
... ... @@ -661,6 +690,97 @@ function RolePlugin.bind(Role)
661 690 self:setProperty("advElS", globalCsv.adv_endless_season)
662 691 end
663 692 end
  693 +
  694 + function Role:getTeamBattleValue(heros)
  695 + local battleV = 0
  696 + for _, heroId in pairs(heros) do
  697 + local hero = self.heros[heroId]
  698 + battleV = battleV + hero:getProperty("battleV")
  699 + end
  700 + return battleV
  701 + end
  702 +
  703 + function Role:recordRankTeam(heroIds)
  704 + local heros = {}
  705 + for slot, heroId in pairs(heroIds) do
  706 + local hero = self.heros[heroId]
  707 + heros[slot] = {
  708 + htype = hero:getProperty("type"),
  709 + lv = hero:getProperty("level"),
  710 + breakL = hero:getProperty("breakL"),
  711 + }
  712 + end
  713 + return heros
  714 + end
  715 +
  716 + local StdDinerRankTime = toUnixtime("20190101"..string.format("%02x", RESET_RANK_TIME)) --跨天时间
  717 + function Role:getCurDinerRankKey()
  718 + local now = skynet.timex()
  719 + local idx = 1
  720 + if math.floor((now - StdDinerRankTime) / 86400) % 2 == 1 then
  721 + idx = 2
  722 + end
  723 + return RANK_DINER[idx]
  724 + end
  725 +
  726 + local StdTowerRankTime = toUnixtime("2019010100")
  727 + function Role:setTowerRank(level)
  728 + local now = skynet.timex()
  729 + local ct = math.ceil((now - StdTowerRankTime) / 86400) --按天计算 365 * 27 < 10000 可以维持 27 年
  730 + local ct = 10000 - ct -- 越早的排名越靠前
  731 + local towerTeam = self:getProperty("towerF")
  732 + local battleV = self:getTeamBattleValue(towerTeam.heros)
  733 + local score = (level * 10000 + ct) * 10000000 + battleV
  734 +
  735 + local curInfo = {
  736 + name = self:getProperty("name"),
  737 + headId = self:getProperty("headId"),
  738 + lv = self:getProperty("level"),
  739 + batteV = battleV,
  740 + level = level,
  741 + format = self:recordRankTeam(towerTeam.heros),
  742 + }
  743 + local roleId = self:getProperty("id")
  744 + redisproxy:pipelining(function (red)
  745 + red:zadd(RANK_TOWER, score, roleId) --更新分数
  746 + red:hset(RANK_TOWER_INFO, roleId, MsgPack.pack(curInfo))
  747 + end)
  748 + end
  749 +
  750 + function Role:getTowerRank()
  751 + local list = {}
  752 + local ids = redisproxy:zrevrange(RANK_TOWER, 0 , 99)
  753 + local redret = {}
  754 + if ids and next(ids) then
  755 + redret = redisproxy:pipelining(function (red)
  756 + for i = 1, #ids do
  757 + local roleId = ids[i]
  758 + table.insert(list, {roleId = tonumber(roleId)})
  759 + red:hget(RANK_TOWER_INFO, roleId)
  760 + end
  761 + end)
  762 + end
  763 + for i = 1, #redret do
  764 + local player = MsgPack.unpack(redret[i])
  765 + player.format = nil
  766 + list[i].player = player
  767 + end
  768 + local rank = redisproxy:ZREVRANK(RANK_TOWER, self:getProperty("id"))
  769 + if not rank then
  770 + rank = -1
  771 + else
  772 + rank = rank + 1
  773 + end
  774 + return {list = list, rank = rank}
  775 + end
  776 +
  777 + function Role:getTowerRankOneInfo(roleId)
  778 + local data = redisproxy:hget(RANK_TOWER_INFO, roleId)
  779 + if data then
  780 + local player = MsgPack.unpack(data)
  781 + return player.format
  782 + end
  783 + end
664 784 end
665 785  
666 786 return RolePlugin
667 787 \ No newline at end of file
... ...
src/services/agent_util.lua
... ... @@ -41,6 +41,7 @@ end
41 41  
42 42 local PointDataMark = {}
43 43 local resetTimeStr = string.format("%02d00", RESET_TIME)
  44 +local resetRankTimeStr = string.format("%02d00", RESET_RANK_TIME)
44 45  
45 46 local function check_daily_reset(agent, now)
46 47 local date = os.date("*t", now)
... ... @@ -66,6 +67,13 @@ local function check_daily_reset(agent, now)
66 67 role:onCrossDay(now, true)
67 68 end
68 69 end
  70 + if resetTimeStr ~= resetRankTimeStr and timeEffect(resetRankTimeStr) then
  71 + -- 刷新排行榜需要重置的数据
  72 + local role = agent.role
  73 + if role then
  74 + role:onResetRank(now, true)
  75 + end
  76 + end
69 77 end
70 78  
71 79 function _M:update(agent)
... ... @@ -76,7 +84,7 @@ function _M:update(agent)
76 84 nextCheckTime = now + HEART_TIMER_INTERVAL
77 85 end
78 86 pcall(check_daily_reset, agent, now)
79   - pcall(role.onRecoverTimer, role, now)
  87 + -- pcall(role.onRecoverTimer, role, now)
80 88 end
81 89  
82 90 function _M:heart_beat(agent)
... ...
src/utils/CommonFunc.lua
... ... @@ -109,11 +109,12 @@ function isCrossMonth(target, now)
109 109 end
110 110 end
111 111  
112   -function isCrossDay(lastTime, now)
  112 +function isCrossDay(lastTime, now, resetTime)
  113 + resetTime = resetTime or RESET_TIME
113 114 if lastTime == 0 then return true end
114 115 now = now or skynet.timex()
115   - local today4h = specTime({hour = RESET_TIME}, now - RESET_TIME * 3600)
116   - return lastTime < today4h and now >= today4h
  116 + local todayResetH = specTime({hour = resetTime}, now - resetTime * 3600)
  117 + return lastTime < todayResetH and now >= todayResetH
117 118 end
118 119  
119 120 function crossDay(target, now)
... ...