From 555f745e7e302cce57f7fb404727bce3d4f0fe1f Mon Sep 17 00:00:00 2001 From: zqj <582132116@qq.com> Date: Mon, 26 Jul 2021 17:59:02 +0800 Subject: [PATCH] feat: 一番赏 --- src/ProtocolCode.lua | 9 +++++++++ src/RedisKeys.lua | 9 +++++++++ src/actions/CapsuleAction.lua | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/agent.lua | 3 ++- src/models/Capsule.lua | 797 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/models/Role.lua | 1 + src/models/RoleCross.lua | 11 +++++++++++ src/models/RoleLog.lua | 3 +++ src/models/RolePlugin.lua | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/services/agent_ctrl.lua | 4 ++-- src/services/capsuled.lua | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/services/watchdog.lua | 3 +++ 12 files changed, 1190 insertions(+), 3 deletions(-) create mode 100644 src/actions/CapsuleAction.lua create mode 100644 src/models/Capsule.lua create mode 100644 src/services/capsuled.lua diff --git a/src/ProtocolCode.lua b/src/ProtocolCode.lua index 7e93ef2..59683ef 100644 --- a/src/ProtocolCode.lua +++ b/src/ProtocolCode.lua @@ -274,6 +274,15 @@ actionCodes = { Seaport_taskRpc = 753, Seaport_shopRpc = 754, Seaport_resetRpc = 755, + + Capsule_listRpc = 850, --扭蛋机列表 + Capsule_joinRpc = 851, --扭蛋机详情 + Capsule_registerRpc = 853, --报名扭蛋机 "报名"后,抽取按钮才会开放,未报名的玩家分在围观玩家中 + Capsule_drawRpc = 854, --抽扭蛋机 + Capsule_switchRoomRpc = 855, --切换扭蛋机房间 + Capsule_notifyChange = 856, -- 通知信息变动 + Capsule_payReward = 857, -- 特殊赏 奖励通知 + Capsule_exitRpc = 858, -- 退出 } rpcResponseBegin = 10000 diff --git a/src/RedisKeys.lua b/src/RedisKeys.lua index 0b7711a..9a57702 100644 --- a/src/RedisKeys.lua +++ b/src/RedisKeys.lua @@ -63,6 +63,15 @@ FRIEND_RECOMMEND = "friend:recommend" -- sort set 登录排序 获取推荐好 CHAT_OFFLINE = "chat:offline:%d" --消息离线缓存 WORK_BATTLE_COUNT = "global:workbattle" -- 世界次数统计 + +--Capsule 扭蛋机 +CAPSULE_INFO= "capsule:info" --set +CAPSULE_PUBLIC = "capsule:%d:info" --hash + +CAPSULE_ID_ROLE = "role:%s:capsule:id" -- set +CAPSULE_ROLE = "role:%s:capsule:%d" --hash 独享 + + -- FRIEND_DINER_LIKE_KEY = "role:%d:diner:like" -- list -- UNION_SET = "global:union" diff --git a/src/actions/CapsuleAction.lua b/src/actions/CapsuleAction.lua new file mode 100644 index 0000000..7a24dd9 --- /dev/null +++ b/src/actions/CapsuleAction.lua @@ -0,0 +1,123 @@ +local ipairs = ipairs +local table = table +local math = math +local next = next +local string = string +local redisproxy = redisproxy +local MsgPack = MsgPack +local getRandomName = getRandomName +local mcast_util = mcast_util +local string_format = string.format +local tonumber = tonumber +local require = require + +local _M = {} + +function _M.listRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local typ = msg.typ + local coin = msg.coin + + local capsules = {} + if typ == 1 then + local ret = skynet.call(agent.capsule_serv, "lua", "list", coin) + if next(ret) then + for k, v in pairs(ret) do + capsules[k] = v + end + end + elseif typ == 0 then + local ret = role:getCapsuleList(coin) + if next(ret) then + for k, v in pairs(ret) do + capsules[k] = v + end + end + end + + SendPacket(actionCodes.Capsule_listRpc, MsgPack.pack(capsules)) + return true +end + +function _M.joinRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local roleId = role:getProperty("id") + local capsuleId = msg.capsule_id --如果刷新则需要传递当前扭蛋机id + local typ = msg.typ or 1 + + local ret = {} + if typ == 1 then + ret = skynet.call(agent.capsule_serv, "lua", "join", roleId, capsuleId) + elseif typ == 0 then + ret = role:joinCapsule() + end + SendPacket(actionCodes.Capsule_joinRpc, MsgPack.pack(ret)) + return true +end + +function _M.exitRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local roleId = role:getProperty("id") + local capsuleId = msg.capsule_id --如果刷新则需要传递当前扭蛋机id + local typ = msg.typ or 1 + + local ret = {} + if typ == 1 then + ret = skynet.call(agent.capsule_serv, "lua", "exit", roleId, capsuleId) + elseif typ == 0 then + ret = role:exitCapsule() + end + + SendPacket(actionCodes.Capsule_exitRpc, MsgPack.pack(ret)) + return true +end + +function _M.registerRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local roleId = role:getProperty("id") + local capsuleId = msg.capsule_id + + local ret = skynet.call(agent.capsule_serv, "lua", "register", roleId, capsuleId) + SendPacket(actionCodes.Capsule_registerRpc, MsgPack.pack(ret)) + return true +end + +function _M.drawRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local roleId = role:getProperty("id") + local capsuleId = msg.capsule_id + local typ = msg.typ --0=独享,1= 公开 + local full = msg.full -- 0=单次,1=十连抽 2=全收 + local continue = msg.continue--确认次数。 + local cares = msg.cares + + local ret, reward, change + if typ == 1 then + ret, reward = skynet.call(agent.capsule_serv, "lua", "draw_capsule", roleId, capsuleId, full, continue, cares) + else + ret, reward = role:drawCapsule(capsuleId, full, cares) + end + if ret <= 4 then return ret end + + reward, change = role:award(reward, {log = {desc = "CapsuleReward", int1 = capsuleId, int2 = roleId}}) + dump(reward) + SendPacket(actionCodes.Capsule_drawRpc, MsgPack.pack(role:packReward(reward, change))) + return true +end + +function _M.switchRoomRpc(agent, data) + local role = agent.role + local msg = MsgPack.unpack(data) + local roleId = role:getProperty("id") + + local ret = skynet.call(agent.capsule_serv, "lua", "switch_room", roleId) + SendPacket(actionCodes.Capsule_switchRoomRpc, MsgPack.pack(ret)) + return true +end + +return _M \ No newline at end of file diff --git a/src/agent.lua b/src/agent.lua index 1d7229e..fdf53b6 100644 --- a/src/agent.lua +++ b/src/agent.lua @@ -254,11 +254,12 @@ skynet.register_protocol { } -- function CMD.start(gate, fd, ip) -function CMD.start(session, source, gate, fd, ip, hotfixs) +function CMD.start(session, source, gate, capsuled, fd, ip, hotfixs) ignoreHeartbeat = false agentInfo.client_fd = fd agentInfo.gate_serv = gate + agentInfo.capsule_serv = capsuled agentInfo.ip = ip agent_util:reset() diff --git a/src/models/Capsule.lua b/src/models/Capsule.lua new file mode 100644 index 0000000..3099bb1 --- /dev/null +++ b/src/models/Capsule.lua @@ -0,0 +1,797 @@ +--扭蛋机 +local MsgPack = MsgPack +local Capsule = class("Capsule", require("shared.ModelBase")) + +function Capsule:ctor(properties) + Capsule.super.ctor(self, properties) +end + +RewardTYpe = { + GOODS = 0, + TOP = 1, + CORE = 2, + LAST = 3, + JOKER = 4, + KING = 5, + GOOD = 6, + INCENTIVE = 7, +} + +CapsuleType = { + PRIVATE = 0, + PUBLIC = 1, +} + +Capsule.schema = { + id = {"number", 0}, --扭蛋机key,配置读取 + room = {"number", 0}, --房间号, 配置读取 + name = {"string", 0}, + typ = {"number", 1}, -- 1=共享,2=独享 + coin = {"number", 0}, --货币代号 + register = {"table", {}}, --人数 {["id"]=0}, 0 围观, 1 已报名 + record = {"table", {}}, --抽取记录 列表 + recordByRole = {"table", {}}, -- 抽取记录,hash, {roleid=record} + rank = {"table", {}}, --排行 + goods = {"table", {}}, --奖励池 + specials = {"table", {}}, --特殊赏 + incentive = {"table", {}}, --激励奖 + specialsFlag= {"table", {}}, --特殊赏是否已经领取 + resetInfo = {"table", {}}, + resetTimes = {"number", 0}, --每日一次手动重置的机会 + hideTime = {"number", 0} , --隐藏时间 + drawEndTime = {"number", 0}, --抽完时间 +} + +function Capsule:isShow() + if skynet.timex() >= self:getProperty("hideTime") then + return false + end + return true +end + +function Capsule:refreshing(now) + local id = self:getProperty("id") + local room = self:getProperty("room") + local ichibankuji = csvdb["ichibankuji_mainCsv"][id][room] + local reset = tostring(ichibankuji.reset) + + if reset == "0" then + return false + elseif reset == "1" then + if self:getProperty("resetTimes") == 1 then + return true + end + return false + else + local resetArr = reset:toArray(true, "=") + if not next(resetArr) then return false end + + if resetArr[1] == "2" then + if self:getGoodsAmount() > 0 then return false end + + local drawEndTime = self:getProperty("drawEndTime") or 0 + if drawEndTime == 0 then return false end + + if now - drawEndTime >= resetArr[2] then + return true + end + return false + + elseif resetArr[1] == "3" then + + elseif resetArr[1] == "4" then + if now >= resetArr[2] then return true end + end + end + + return false +end + +function Capsule:getResetFields() + return { + id = self:getProperty("id"), + room = self:getProperty("room"), + typ = self:getProperty("typ"), + coin = 0, + register = {}, + record = {}, + recordByRole = {}, + rank = {}, + goods = {}, + specials = {}, + incentive = {}, + specialsFlag= {}, + resetInfo = {}, + resetTimes = 0, + } +end + +function Capsule:init() + local id = self:getProperty("id") + local room = self:getProperty("room") + self:setProperties(self:getResetFields()) + + local ichibankuji = csvdb["ichibankuji_mainCsv"][id][room] + + --奖励池 + local goods_id = ichibankuji["goods_id"] + local goods, specials, incentive = {}, {}, {} + for _, data in pairs(csvdb["ichibankuji_goodsCsv"]) do + for _, val in pairs(data) do + if val.key == goods_id then + goods[goods_id..val.id] = clone(val) + end + end + end + for _, v in ipairs(goods) do + v.weight = (v.weight or 0) * v.amount + end + + --特殊赏 + local special_ids = ichibankuji["special_id"] + if special_ids ~= "" then + for _, special_id in ipairs(special_ids:toArray(true, "=")) do + local val = csvdb["ichibankuji_specialCsv"][special_id] + if type(val.type) == "number" then + specials[special_id] = {np= 1, amount = val.amount, award = val.award, quality = tonumber(val.type), showIndex = val.showIndex} + elseif type(val.type) == "string" then + local pos = val.type:find("=") + if pos then + for k, v in pairs(val.type:toNumMap()) do + specials[special_id] = {np= v, amount = val.amount, award = val.award, quality = k, showIndex = val.showIndex} + end + else + specials[special_id] = {np= 1, amount = val.amount, award = val.award, quality = tonumber(val.type), showIndex = val.showIndex} + end + end + end + end + + --激励奖 + local incentive_ids = ichibankuji["incentive_id"] + if incentive_ids ~= "" then + for _, incentive_id in ipairs(incentive_ids:toArray(true, "=")) do + local val = csvdb["ichibankuji_incentiveCsv"][incentive_id] + if type(val.type) == "number" then + incentive["last"] = {np=val.type, award = val.award} + elseif type(val.type) == "string" then + for k, v in pairs(val.type:toNumMap()) do + if k == 2 then + incentive["amount"] = {np= v, award = val.award} + elseif k==3 then + incentive["probabilities"] = {np= v, award = val.award} + end + end + end + end + end + --货币类型 + local coin = ichibankuji["token"]:toArray(true, "=") + self:setProperties({coin = coin[1] or 0, hideTime = ichibankuji.hide_time, goods = goods, specials = specials, incentive = incentive}) +end + +function Capsule:getOnlineCount() + local register = self:getProperty("register") or {} + local reg, onlookers = 0, 0 + for _, v in pairs(register) do + if v == 1 then + reg = reg + 1 + else + onlookers = onlookers + 1 + end + end + return {[0]=onlookers, [1]=reg, [2] = reg+onlookers} +end + +function Capsule:join(roleId) + --一个房间最多人数 TODO + local register = self:getProperty("register") or {} + register[roleId] = 0 + self:setProperty("register", register) + return true +end + +function Capsule:isRegister(roleId) + local register = self:getProperty("register") or {} + return register[roleId] == 1 +end + +function Capsule:register(roleId) + local register = self:getProperty("register") or {} + if next(register) then + register[roleId] = 1 + return true + end + return false +end + +function Capsule:exit(roleId) + local register = self:getProperty("register") or {} + if next(register) then + register[roleId] = nil + return true + end + return false +end + +function Capsule:confirmed(cares) + local goods = self:getProperty("goods") or {} + local specials = self:getProperty("specials") or {} + local change = {} + for k, v in pairs(cares) do + if v.typ == 1 then + if goods[k] and goods[k].amount ~= v.count then + change[k] = goods[k].amount + end + else + if specials[k] and specials[k].amount ~= v.count then + change[k] = specials[k].amount + end + end + end + return change +end + +function Capsule:getGoodsAmount() + local goods = self:getProperty("goods") or {} + local amount = 0 + for _, v in ipairs(goods) do + amount = amount + v.amount + end + return amount +end + +function Capsule:getSpecialByType(typ) + local specials = self:getProperty("specials") or {} + for k, v in pairs(specials) do + if v.quality == typ then + return k, v + end + end + return nil +end + +function Capsule:getTop(record) + local specialsFlag = self:getProperty("specialsFlag") or {} + if specialsFlag[RewardTYpe.TOP] then return nil end + + local specials = self:getProperty("specials") or {} + local spKey, special = self:getSpecialByType(RewardTYpe.TOP) + if not special then return nil end + + local np = special["np"] + if #record >= special["np"] then + local topRecord = {} + local count = np + for _, v in ipairs(record) do + if count <= 0 then break end + + local tmpCount = 0 + if count >= v.amount then + count = count - v.amount + tmpCount = v.amount + else + tmpCount = count + count = 0 + end + + if not topRecord[v.role_id]then + topRecord[v.role_id] = {amount = v.amount } + else + topRecord[v.role_id] = {amount = (topRecord[v.rol_id]["amount"] or 0) + tmpCount} + end + end + + count = special["amount"] + local topRoleIds = {} + while(count > 0 and next(topRecord)) do + local roleId = math.randWeight(topRecord, "amount") + if roleId then + table.insert(topRoleIds, roleId) + local tmpTopRecord = topRecord[roleId] + tmpTopRecord["amount"] = tmpTopRecord["amount"] - 1 + + if tmpTopRecord["amount"] <= 0 then topRecord[roleId] = nil end + + count = count - 1 + end + + end + + special["amount"] = count + specials[spKey] = special + specialsFlag[RewardTYpe.TOP] = topRoleIds + self:setProperty("specialsFlag", specialsFlag) + self:setProperty("specials", specials) + return {role_ids = topRoleIds, award = sspecial["award"]} + end + + return nil +end + +--TODO +function Capsule:getCore(record) + if self:getGoodsAmount() > 0 then return nil end + + local specialsFlag = self:getProperty("specialsFlag") or {} + if specialsFlag[RewardTYpe.CORE] then return nil end + + local specials = self:getProperty("specials") or {} + local spKey, special = self:getSpecialByType(RewardTYpe.CORE) + if not special then return nil end + + local np = special["np"] + if np > #record then return nil end + + + local left = math.ceil((np - #record)/2) or 0 + local count = np + local roleRecord = {} + for i, v in ipairs(record) do + if count <= 0 then break end + if i > left then + local tmpCount = 0 + if count >= v.amount then + count = count - v.amount + tmpCount = v.amount + else + tmpCount = count + count = 0 + end + + if not roleRecord[v.role_id]then + roleRecord[v.role_id] = {amount = v.amount } + else + roleRecord[v.role_id] = {amount = (roleRecord[v.rol_id]["amount"] or 0) + tmpCount} + end + end + + end + + count = special["amount"] + local roleIds = {} + while(count > 0 and next(roleRecord)) do + local roleId = math.randWeight(roleRecord, "amount") + if roleId then + table.insert(roleIds, roleId) + local tmpLastRecord = roleRecord[roleId] + tmpLastRecord["amount"] = tmpLastRecord["amount"] - 1 + + if tmpLastRecord["amount"] <= 0 then roleRecord[roleId] = nil end + + count = count - 1 + end + end + special["amount"] = count + specials[spKey] = special + specialsFlag[RewardTYpe.CORE] = roleIds + self:setProperty("specialsFlag", specialsFlag) + self:setProperty("specials", specials) + return {role_ids = roleIds, award = special["award"]} +end + +function Capsule:getLast(record) + if self:getGoodsAmount() > 0 then return nil end + + local specialsFlag = self:getProperty("specialsFlag") or {} + if specialsFlag[RewardTYpe.LAST] then return nil end + + local specials = self:getProperty("specials") or {} + local spKey, special = self:getSpecialByType(RewardTYpe.LAST) + if not special then return nil end + + if not next(record) then return nil end + table.sort(record, function(a, b) return a.create_time > b.create_time end) + + + local np = special["np"] + local count = np + local lastRecord = {} + for _, v in ipairs(record) do + if count <= 0 then break end + + local tmpCount = 0 + if count >= v.amount then + count = count - v.amount + tmpCount = v.amount + else + tmpCount = count + count = 0 + end + + if not lastRecord[v.role_id]then + lastRecord[v.role_id] = {amount = v.amount } + else + lastRecord[v.role_id] = {amount = (lastRecord[v.rol_id]["amount"] or 0) + tmpCount} + end + end + + count = special["amount"] + local lastRoleIds = {} + while(count > 0 and next(lastRecord)) do + local roleId = math.randWeight(lastRecord, "amount") + if roleId then + table.insert(lastRoleIds, roleId) + local tmpLastRecord = lastRecord[roleId] + tmpLastRecord["amount"] = tmpLastRecord["amount"] - 1 + + if tmpLastRecord["amount"] <= 0 then lastRecord[roleId] = nil end + + count = count - 1 + end + end + special["amount"] = count + specials[spKey] = special + specialsFlag[RewardTYpe.LAST] = lastRoleIds + self:setProperty("specialsFlag", specialsFlag) + self:setProperty("specials", specials) + return {role_ids = lastRoleIds, award = special["award"]} +end + +function Capsule:getJoker(record) + if self:getGoodsAmount() > 0 then return nil end + local specialsFlag = self:getProperty("specialsFlag") or {} + if specialsFlag[RewardTYpe.JOKER] then return nil end + + local specials = self:getProperty("specials") or {} + local spKey, special = self:getSpecialByType(RewardTYpe.JOKER) + if not special then return nil end + + local roleRecord = {} + for _, v in ipairs(record) do + if not roleRecord[v.role_id]then + roleRecord[v.role_id] = {amount = v.amount } + else + roleRecord[v.role_id] = {amount = (roleRecord[v.rol_id]["amount"] or 0) + v.amount} + end + end + + local count = special["amount"] + local roleIds = {} + while(count > 0 and next(roleRecord)) do + local roleId = math.randWeight(roleRecord, "amount") + if roleId then + table.insert(roleIds, roleId) + local tmpRoleRecord = roleRecord[roleId] + tmpRoleRecord["amount"] = tmpRoleRecord["amount"] - 1 + + if tmpRoleRecord["amount"] <= 0 then roleRecord[roleId] = nil end + + count = count - 1 + end + end + special["amount"] = count + specials[spKey] = special + specialsFlag[RewardTYpe.JOKER] = roleIds + self:setProperty("specialsFlag", specialsFlag) + self:setProperty("specials", specials) + return {role_ids = roleIds, award = special["award"]} +end + +function Capsule:getKing(record) + if self:getGoodsAmount() > 0 then return nil end + local specialsFlag = self:getProperty("specialsFlag") or {} + if specialsFlag[RewardTYpe.JOKER] then return nil end + + local specials = self:getProperty("specials") or {} + local spKey, special = self:getSpecialByType(RewardTYpe.KING) + if not special then return nil end + + + local roleRecord = {} + for _, v in ipairs(record) do + if not roleRecord[v.role_id]then + roleRecord[v.role_id] = {amount = v.amount } + else + roleRecord[v.role_id] = {amount = (roleRecord[v.rol_id]["amount"] or 0) + v.amount} + end + end + + local count = special["amount"] + local roleIds = {} + while(count > 0 and next(roleRecord)) do + local roleId = math.randWeight(roleRecord, "amount") + if roleId then + table.insert(roleIds, roleId) + local tmpRoleRecord = roleRecord[roleId] + tmpRoleRecord["amount"] = tmpRoleRecord["amount"] - 1 + + if tmpRoleRecord["amount"] <= 0 then roleRecord[roleId] = nil end + + count = count - 1 + end + end + special["amount"] = count + specials[spKey] = special + specialsFlag[RewardTYpe.KING] = roleIds + self:setProperty("specialsFlag", specialsFlag) + self:setProperty("specials", specials) + return {role_ids = roleIds, award = special["award"]} +end + + +function Capsule:checkSpecialReward() + local specials = self:getProperty("specials") or {} + if not next(specials) then return nil end + local record = self:getProperty("record") or {} + if not next(record) then return nil end + table.sort(record, function(a, b) return a.create_time < b.create_time end ) + local notify = {} + + local topReward = self:getTop(record) + if topReward then + for _, roleId in ipairs(topReward.role_ids) do + rpcRole(roleId, "paySpecialReward", RewardTYpe.TOP, topReward.award) + table.insert(notify, {role_id = roleId, typ = RewardTYpe.TOP, award = topReward.award, amount = 1, create_time= skynet.timex()}) + end + end + + local coreReward = self:getCore(record) + if coreReward then + for _, roleId in ipairs(topReward.role_ids) do + rpcRole(roleId, "paySpecialReward", RewardTYpe.CORE, coreReward.award) + table.insert(notify, {role_id = roleId, typ = RewardTYpe.CORE, award = topReward.award, amount = 1, create_time= skynet.timex()}) + end + end + local lastReward = self:getLast(record) + if lastReward then + for _, roleId in ipairs(lastReward.role_ids) do + rpcRole(roleId, "paySpecialReward", RewardTYpe.LAST, lastReward.award) + table.insert(notify, {role_id = roleId, typ = RewardTYpe.LAST, award = topReward.award, amount = 1, create_time= skynet.timex()}) + end + end + local jokerReward = self:getJoker(record) + if jokerReward then + for _, roleId in ipairs(jokerReward.role_ids) do + rpcRole(roleId, "paySpecialReward", RewardTYpe.JOKER, jokerReward.award) + table.insert(notify, {role_id = roleId, typ = RewardTYpe.JOKER, award = topReward.award, amount = 1, create_time= skynet.timex()}) + end + end + local kingReward = self:getKing(record) + if kingReward then + for _, roleId in ipairs(kingReward.role_ids) do + rpcRole(roleId, "paySpecialReward", RewardTYpe.KING, kingReward.award) + table.insert(notify, {role_id = roleId, typ = RewardTYpe.KING, award = topReward.award, amount = 1, create_time= skynet.timex()}) + end + end + + return notify +end + +function Capsule:checkIncentive(roleId) + local goods = self:getProperty("goods") or {} + local record = self:getProperty("record") or {} + local recordByRole = self:getProperty("recordByRole") or {} + local roleRecord = recordByRole[roleId] or {} + local incentive = self:getProperty("incentive") + + + local reward + -- 最后一抽 TODO + if incentive["last"] then + local last = true + for k, v in pairs(goods) do + if v and v.amount then + last = false + break + end + end + reward = incentive["last"]["award"] + end + + --次数 + if incentive["amount"] then + local amount = 0 + for _, v in pairs(roleRecord) do + if (v.calculated or 0) == 0 then + amount = amount + v.amount + end + end + + local count = math.floor(amount / incentive["amount"]["np"]) + local tmpCount = count * incentive["amount"]["np"] + for i=1, count do + reward = reward.. " " .. incentive["amount"]["award"] + end + + --填充v.calculated 字段,标识已经用于每x抽的计算中。 + for _, v in pairs(roleRecord) do + if tmpCount <= 0 then break end + + v.calculated = v.calculated or 0 + if v.calculated ~= v.amount then + if tmpCount <= v.amount then + v.calculated = tmpCount + tmpCount = 0 + else + v.calculated = v.amount + tmpCount = tmpCount - v.amount + end + end + + end + end + + --概率 + if incentive["probabilities"] then + local probabilities = math.randomInt(1, 100) + if probabilities <= incentive["probabilities"]["np"] then + reward = reward .. " " .. incentive["probabilities"]["award"] + end + end + if reward and reward ~= "" then + local tmpReward, notify = {}, {} + for k, v in pairs(reward:toNumMap()) do + tmpReward[k] = (tmpReward[k] or 0) + v + end + + notify = {role_id = roleId, typ = RewardTYpe.incentive, award = reward, amount = 1, create_time= skynet.timex()} + table.insert(record, notify) + self:setProperty("record", record) + return tmpReward,notify + end + return nil, nil +end + +function Capsule:drawByCount(roleId, count) + if count <= 0 then return nil end + + local goods = self:getProperty("goods") or {} + local record = self:getProperty("record") or {} + local recordByRole = self:getProperty("recordByRole") or {} + + local id = self:getProperty("id") + local room = self:getProperty("room") + local ichibankuji = csvdb["ichibankuji_mainCsv"][id][room] + local goods_id = ichibankuji["goods_id"] + + --奖励, 通知信息 + local reward, notify= {}, {} + while (goods and next(goods) and count > 0) do + local good_id = math.randWeight(goods, "weight") + if good_id then + local good = goods[good_id] or {} + if good.amount > 0 then + good.amount = good.amount - 1 + for k, v in pairs(good.award:toNumMap()) do + reward[k] = (reward[k] or 0) + v + end + + --插入记录 + local tmpNotify = {role_id = roleId, good_id = good_id, typ = RewardTYpe.GOODS, award = good.award, amount = 1, quality = good.quality, create_time= skynet.timex()} + + table.insert(record, tmpNotify) + table.insert(notify, tmpNotify) + + --记录角色的抽奖记录 + local tmp = recordByRole[roleId] + if not tmp then + recordByRole[roleId] = {good_id=notify} + else + if not tmp[good_id] then + tmp[good_id] = notify + else + tmp[good_id].amount = tmp[good_id].amount + 1 + end + end + + good.weight = good.weight - csvdb["ichibankuji_goodsCsv"][goods_id].weight + count = count - 1 + end + end + + end + + self:setProperty("recordByRole", recordByRole) + self:setProperty("record", record) + self:setProperty("goods", goods) + local incentiveReward, tmpNotify = self:checkIncentive(roleId) + for k, v in pairs(incentiveReward or {}) do + reward[k] = (reward[k] or 0) + v + end + if tmpNotify then table.insert(notify, tmpNotify) end + + local speciNotify = self:checkSpecialReward(roleId) + if speciNotify and next(speciNotify) then table.insert(notify, speciNotify) end + + return reward, notify +end + +function Capsule:drawAll(roleId) + local goods = self:getProperty("goods") or {} + local record = self:getProperty("record") or {} + local recordByRole = self:getProperty("recordByRole") or {} + + local reward, notify = {}, {} + for good_id, good in pairs(goods) do + + if good.amount > 0 then + notify = {role_id = roleId, good_id = good_id, typ = RewardTYpe.GOODS, award = good.award, amount = good.amount, quality = good.quality, create_time = skynet.timex()} + table.insert(record, notify) + + --记录角色的抽奖记录 + local tmp = recordByRole[roleId] + if not tmp then + recordByRole[roleId] = {good_id=notify} + else + if not tmp[good_id] then + tmp[good_id] = notify + else + tmp[good_id].amount = tmp[good_id].amount + good.amount + end + end + end + + while(good.amount > 0) do + for k, v in pairs(good.award:toNumMap()) do + reward[k] = (reward[k] or 0) + v + end + good.amount = good.amount - 1 + end + + end + + local incentiveReward, tmpNotify = self:checkIncentive(roleId) + for k, v in pairs(incentiveReward or {}) do + reward[k] = (reward[k] or 0) + v + end + if tmpNotify then table.insert(notify, tmpNotify) end + + local speciNotify = self:checkSpecialReward(roleId) + if speciNotify and next(speciNotify) then table.insert(notify, speciNotify) end + + self:setProperty("recordByRole", recordByRole) + self:setProperty("record", record) + self:setProperty("goods", goods) + return reward, notify +end + +--@param +--[[ +@roleId +@typ 1=全收 0=单次 +@cares 关注{k=v} +]]-- + +function Capsule:draw(roleId, full, cares) + if self:getGoodsAmount() == 0 then return 2 end + if self:getProperty("typ") == 1 then + --是否报名 + if self:isRegister(roleId) == false then return 3 end + + --关注的奖品的数量发生了变化 + if cares then + local change = self:confirmed(cares) + if next(change) then return 4, change end + end + end + + if full == 0 then + return 5, self:drawByCount(roleId, 1) + elseif full == 1 then + return 5, self:drawByCount(roleId, 10) + elseif full == 2 then + return 5, self:drawAll(roleId) + end +end + + +function Capsule:data() + return { + id = self:getProperty("id"), + room = self:getProperty("room"), + typ = self:getProperty("typ"), + name = self:getProperty("name"), + coin = self:getProperty("coin"), + onlineCount = self:getOnlineCount(), + record = self:getProperty("record"), + --recordByRole = self:getProperty("recordByRole"), + rank = self:getProperty("rank"), + goods = self:getProperty("goods"), + specials = self:getProperty("specials"), + incentive = self:getProperty("incentive"), + specialsFlag= self:getProperty("specialsFlag"), + } +end + +return Capsule \ No newline at end of file diff --git a/src/models/Role.lua b/src/models/Role.lua index 242fb79..65e4fb8 100644 --- a/src/models/Role.lua +++ b/src/models/Role.lua @@ -28,6 +28,7 @@ function Role:ctor( properties ) self.runeBag = {} self.friends = {} self.sparkBag = {} + self.capsules = {} self.advData = nil self.activity = nil self._pushToken = nil diff --git a/src/models/RoleCross.lua b/src/models/RoleCross.lua index ba3dd60..5639619 100644 --- a/src/models/RoleCross.lua +++ b/src/models/RoleCross.lua @@ -210,6 +210,12 @@ RoleCross.bind = function (Role) return "成功" end + function Role:paySpecialReward(typ, reward) + local tmpReward, _= self:award(reward, {log = {desc = "specialsReward", int1=self:getKey(), int2 = typ}}) + SendPacket(actionCodes.Capsule_payReward, MsgPack.pack({reward=tmpReward})) + return "reward" + end + end @@ -370,6 +376,11 @@ function CMD.redPTag(roleId, tag, pms) end end +function CMD.paySpecialReward(roleId, typ, reward) + local role = require("models.Role").new({key = string.format("%s",roleId), id = roleId}) + role:award(reward, {log = {desc = "specialsReward", int1=self:getKey(), int2 = typ}}) +end + RoleCross.handle = function(cmd, roleId, ...) SRole = SRole or require("models.Role") if CMD[cmd] then diff --git a/src/models/RoleLog.lua b/src/models/RoleLog.lua index e44ceb2..ccea51b 100644 --- a/src/models/RoleLog.lua +++ b/src/models/RoleLog.lua @@ -159,6 +159,9 @@ local ItemReason = { seaportTask = 1403, -- 贸易港任务奖励 returner = 1410, -- 回归者奖励 + + CapsuleReward = 1411, --扭蛋机奖励 + specialsReward = 1412, --特殊赏 } diff --git a/src/models/RolePlugin.lua b/src/models/RolePlugin.lua index 2643f1d..afe1be0 100644 --- a/src/models/RolePlugin.lua +++ b/src/models/RolePlugin.lua @@ -19,6 +19,7 @@ function RolePlugin.bind(Role) --self:loadRoleIncre() self:loadFriends() self:loadSparks() + self:loadCapsules() end function Role:reloadWhenLogin() @@ -821,6 +822,36 @@ function RolePlugin.bind(Role) end end + function Role:loadCapsules() + local now = skynet.timex() + local roleId = self:getProperty("id") + local res = redisproxy:smembers(CAPSULE_ID_ROLE:format(roleId)) or {} + for _, key in pairs(res) do + local capsule = require("models.Capsule").new({ key = CAPSULE_ROLE:format(roleId,tonumber(key))}) + capsule:load() + if capsule:refreshing(now) then + capsule:init() + capsule:create() + end + self.capsules[key] = capsule + end + + for _, data in pairs(csvdb["ichibankuji_mainCsv"]) do + for _, val in pairs(data) do + if val.typ == 0 then + local key = val.id..val.room + if not self.capsules[key] then + local capsule = require("models.Capsule").new({ key = CAPSULE_ROLE:format(roleId, tonumber(key)), id= val.id, room = val.room, typ = 0, name=val.name}) + capsule:init() + capsule:create() + self.capsules[key] = capsule + redisproxy.sadd(CAPSULE_ID_ROLE:format(roleId), key) + end + end + end + end + end + -- 0 为操作成功 function Role:addRune(params) if params.type and params.id then @@ -1995,6 +2026,7 @@ function RolePlugin.bind(Role) function Role:onRecoverTimer(now) self:updateTimeReset(now, true) self:checkNewEvent(now) + self:checkCapsule(now) self:saveRoleData(now) end @@ -3116,7 +3148,38 @@ function RolePlugin.bind(Role) return itemRandomOccupy end + function Role:getCapsuleList(coin) + local capsules = {} + for k, v in pairs(self.capsules) do + if v:getProperty("coin") == coin then + local onlineCount= v:getOnlineCount() + capsules[k] = {id=v:getProperty("id"), room=v:getProperty("room"), typ=v:getProperty("typ"), people=onlineCount[2], coin= v:getProperty("coin")} + end + end + return capsules + end + function Role:drawCapsule(capsuleId, full, cares) + local capsule = self.capsules[capsuleId] or {} + if next(capsule) then + local roleId = self:getProperty("id") + return capsule:draw(roleId, full, cares) + end + end + + function Role:joinCapsule(capsuleId) + local capsule = self.capsules[capsuleId] or {} + return capsule:data() + end + + function Role:checkCapsule(now) + for _, v in pairs(self.capsules) do + if v:refreshing(now) then + v:init() + v:create() + end + end + end end return RolePlugin \ No newline at end of file diff --git a/src/services/agent_ctrl.lua b/src/services/agent_ctrl.lua index 22480c9..48c54af 100644 --- a/src/services/agent_ctrl.lua +++ b/src/services/agent_ctrl.lua @@ -188,7 +188,7 @@ function _M:query_agent(fd, uid, isQueue) end local agent = get_a(pack) - local ok = pcall(skynet.call, agent, "lua", "start", gate_serv, fd, self.f2i[fd]) + local ok = pcall(skynet.call, agent, "lua", "start", gate_serv, capsuled, fd, self.f2i[fd]) if not ok then query_agent_response(fd, {ret = "INNER_ERROR"}) return @@ -223,7 +223,7 @@ function _M:query_agent(fd, uid, isQueue) end end - local ok = pcall(skynet.call, agent, "lua", "start", gate_serv, fd, self.f2i[fd], hotfixList) + local ok = pcall(skynet.call, agent, "lua", "start", gate_serv, capsuled, fd, self.f2i[fd], hotfixList) if not ok then self.factory:push(agent) query_agent_response(fd, {ret = "INNER_ERROR"}) diff --git a/src/services/capsuled.lua b/src/services/capsuled.lua new file mode 100644 index 0000000..3067646 --- /dev/null +++ b/src/services/capsuled.lua @@ -0,0 +1,167 @@ +require "ProtocolCode" +require "shared.init" +require "GlobalVar" +require "RedisKeys" +require "skynet.manager" +local skynet = require "skynet" +csvdb = require "shared.csvdata" +redisproxy = require "shared.redisproxy" +datacenter = require "skynet.datacenter" + +local capsules = {} +local CMD = {} + +NotifyChangeType = { + JOIN = 1, + EXIT = 2, + DRAW = 3, + SPECIAL = 4, + INCENTIVE = 5, +} + +function rpcRole(roleId, funcName, ...) + local fields = ... + local agent = datacenter.get("agent", roleId) + if agent and agent.serv then + if funcName == "getProperties" then + return true, skynet.call(agent.serv, "role", funcName, fields) + else + return true, skynet.call(agent.serv, "role", funcName, ...) + end + else + local roleCross = require("models.RoleCross") + if funcName == "getProperties" then + return false, roleCross.handle(funcName, roleId, fields) + else + return false, roleCross.handle(funcName, roleId, ...) + end + end +end + +function broadCastCapsule(roleId, capsuleId, broadInfo) + local capsule = capsules[capsuleId] or {} + local register = capsule:getProperty("register") or {} + if next(capsule) then + for id, _ in pairs(register) do + if id ~= roleId then + rpcRole(id, "SendPacket", actionCodes.Capsule_notifyChange, MsgPack.pack(broadInfo)) -- 通知对方 + end + end + end +end + +local function getCapsuleId(id, room) + return string.format("%d%d", id, room) +end + + +local function add(roleId, capsuleId) + print(type(capsuleId)) + local capsule = capsules[capsuleId] or {} + if next(capsule) then + capsule:join(roleId) + broadCastCapsule(roleId, capsuleId, {changeType = NotifyChangeType.JOIN, roleId = roleId}) + return capsule:data() + end + print("id 不存在: ".. capsuleId) + return nil +end + +local function capsuleRefreshing() + for _, v in pairs(capsules) do + if v:refreshing() then + v:init() + v:create() + end + end +end + +--扭蛋机刷新 +local function check_capsules() + pcall(capsuleRefreshing) + skynet.timeout(60, check_capsules) +end + +function CMD.start() + local now = skynet.timex() + local res = redisproxy:smembers(CAPSULE_INFO) or {} + for _, key in pairs(res) do + local capsule = require("models.Capsule").new({ key = CAPSULE_PUBLIC:format(tonumber(key))}) + capsule:load() + if capsule:isShow() then + if capsule:refreshing(now) then + capsule:init() + capsule:create() + end + capsules[key] = capsule + else + redisproxy.del(CAPSULE_PUBLIC:format(tonumber(key))) + redisproxy.srem(CAPSULE_INFO, key) + end + end + + for _, data in pairs(csvdb["ichibankuji_mainCsv"]) do + for _, val in ipairs(data) do + if val.type == 1 then + local key = string.format("%d%d", val.id, val.room) + if not capsules[key] then + local capsule = require("models.Capsule").new({ key = CAPSULE_PUBLIC:format(tonumber(key)), id= val.id, room = val.room, typ = 1, name=val.name}) + capsule:init() + capsule:create() + capsules[key] = capsule + redisproxy.sadd(CAPSULE_INFO, key) + end + end + end + end + + check_capsules() +end + +function CMD.list(coin) + local tmpCapsules = {} + for k, v in pairs(capsules) do + if v:getProperty("coin") == coin then + local onlineCount= v:getOnlineCount() + tmpCapsules[k] = {id=v:getProperty("id"), room=v:getProperty("room"), typ=v:getProperty("typ"), people=onlineCount[2], coin= v:getProperty("coin")} + end + end + return tmpCapsules +end + +function CMD.join(roleId, capsuleId) + if capsuleId then + return add(roleId, capsuleId) + end + return nil +end + + +function CMD.exit(roleId, capsuleId) + local capsule = capsules[capsuleId] or {} + if next(capsule) then + capsule:exit(roleId) + broadCastCapsule(roleId, capsuleId, {changeType = NotifyChangeType.EXIT, roleId = roleId}) + end +end + +function CMD.draw_capsule(roleId, capsuleId, typ, cares) + local capsule = capsules[capsuleId] or {} + if next(capsule) then + local ret, reward, notify = capsule:draw(roleId, typ, cares) + --if ret > 4 then + -- broadCastCapsule(roleId, capsuleId, {changeType = NotifyChangeType.DRAW, roleId = roleId, notify = notify}) + --end + return ret, reward + end + return nil +end + +skynet.start(function() + skynet.dispatch("lua", function(session, address, cmd, ...) + local f = CMD[string.lower(cmd)] + skynet.ret(skynet.pack(f(...))) + end) + + skynet.register("capsuled") +end) \ No newline at end of file diff --git a/src/services/watchdog.lua b/src/services/watchdog.lua index d9cd59a..5c29637 100644 --- a/src/services/watchdog.lua +++ b/src/services/watchdog.lua @@ -66,6 +66,8 @@ function CMD.start(conf) skynet.call(gate_serv, "lua", "open" , conf) skynet.call(pvpd, "lua", "start") + + skynet.call(capsuled, "lua", "start") -- 开启agent状态检测定时器 check_agent_status() -- 创建广播服务 @@ -126,4 +128,5 @@ skynet.start(function() skynet.newservice("services/chated") -- 网关服务 gate_serv = skynet.newservice("gate") + capsuled = skynet.newservice("services/capsuled") end) -- libgit2 0.21.2