From 23d89d1311fb747bc78ebbad220bc273a64b3262 Mon Sep 17 00:00:00 2001 From: zhouahaihai Date: Wed, 2 Jan 2019 11:53:01 +0800 Subject: [PATCH] 冒险 结构 --- src/GlobalVar.lua | 20 ++++++++++++++++++++ src/ProtocolCode.lua | 4 ++++ src/actions/AdvAction.lua | 35 +++++++++++++++++++++++++++++++++++ src/agent.lua | 34 +++++++++++++++++++++++++++++----- src/models/Role.lua | 38 +++++++++++++++++++++++++++++++++----- src/models/RoleAdv.lua | 250 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/utils/TableUtil.lua | 6 ++++++ 7 files changed, 377 insertions(+), 10 deletions(-) create mode 100644 src/actions/AdvAction.lua create mode 100644 src/models/RoleAdv.lua diff --git a/src/GlobalVar.lua b/src/GlobalVar.lua index 55d07cb..1119856 100644 --- a/src/GlobalVar.lua +++ b/src/GlobalVar.lua @@ -55,4 +55,24 @@ ItemId = { Diamond = 3, -- 钻石 BreakCost = 4, -- 突破材料 HeroFC = {700, 701, 702, 703}, -- 通用角色碎片 +} + +--客户端不需要知道这个 +AdvSpecialStage = { + [1]= "In", + [2] = "Out", + [3] = "BOSS" +} +--客户端需要知道这个 +AdvEventType = { + -- 特殊事件(地块决定) + In = -1, --入口 + Out = -2, --出口 + BOSS = -3, -- boss + -- 普通事件(随机) + Choose = 1, --选择点 + Drop = 2, --物品掉落点 + Monster = 3, -- 普通怪 + Trader = 4, --商人 + Build = 5, --建筑物 } \ No newline at end of file diff --git a/src/ProtocolCode.lua b/src/ProtocolCode.lua index b21ed92..3e62861 100644 --- a/src/ProtocolCode.lua +++ b/src/ProtocolCode.lua @@ -20,6 +20,9 @@ actionCodes = { Role_updateProperties = 106, Role_updateItems = 107, Role_changeUpdate = 108, + Role_pipelining = 109, + + Adv_startAdvRpc = 151, Hero_loadInfos = 201, Hero_updateProperty = 202, @@ -35,6 +38,7 @@ actionCodes = { Hero_loveItemRpc = 212, Hero_loveTaskRpc = 213, Hero_changeSkinRpc = 214, + } rpcResponseBegin = 10000 diff --git a/src/actions/AdvAction.lua b/src/actions/AdvAction.lua new file mode 100644 index 0000000..5869b67 --- /dev/null +++ b/src/actions/AdvAction.lua @@ -0,0 +1,35 @@ +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 table_insert = table.insert +local tconcat = table.concat +local table_unpack = table.unpack + +local _M = {} + +function _M.startAdvRpc( agent, data ) + local role = agent.role + local msg = MsgPack.unpack(data) + + local advInfo = role:getProperty("advInfo") + + role:randomAdvMap(10101, 1) --测试 + + SendPacket(actionCodes.Adv_startAdvRpc, '') + return true +end + + + + + +return _M \ No newline at end of file diff --git a/src/agent.lua b/src/agent.lua index eeeec47..9c9d5aa 100644 --- a/src/agent.lua +++ b/src/agent.lua @@ -46,17 +46,41 @@ function cancel_agent_timer() end ---- 定时器相关 }}} +local _pipelinings = {} --可同时多个序列 栈的形式保证嵌套不出错 function SendPacket(actionCode, bin, client_fd) - if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end - + client_fd = client_fd or agentInfo.client_fd + local handlerName = actionHandlers[actionCode] if string.sub(handlerName, -3, -1) == "Rpc" then actionCode = actionCode + rpcResponseBegin end + -- 查看是否是在 流水线操作中 + if #_pipelinings > 0 then + local _curPipelining = _pipelinings[#_pipelinings] + _curPipelining[client_fd] = _curPipelining[client_fd] or {} --区分不同客户端 + table.insert(_curPipelining[client_fd], {actionCode, bin}) + else + if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end + local head = string.pack("H", actionCode) + return socket.write(client_fd, netpack.pack(head .. bin)) + end +end - local client_fd = client_fd or agentInfo.client_fd - local head = string.pack("H", actionCode) - return socket.write(client_fd, netpack.pack(head .. bin)) +function SendPipelining(callback) + if type(callback) ~= "function" then return end + --push 当前队列 + table.insert(_pipelinings, {}) + -- 执行代码块 输出错误信息 + local ok, err = pcall(callback) + --弹出当前队列 + local curPipelining = table.remove(_pipelinings) + -- 查看是否有消息 + if next(curPipelining) then + for client_fd, msg in pairs(curPipelining) do + SendPacket(actionCodes.Role_pipelining, MsgPack.pack(msg), client_fd) + end + end + if not ok then error(err) end end function rpcAgent(roleId, funcName, ...) diff --git a/src/models/Role.lua b/src/models/Role.lua index c7091d7..72a5db8 100644 --- a/src/models/Role.lua +++ b/src/models/Role.lua @@ -2,10 +2,12 @@ local Role = class("Role", require("shared.ModelBase")) local RolePlugin = import(".RolePlugin") local RoleTask = import(".RoleTask") +local RoleAdv = import(".RoleAdv") local RoleActivity = import(".RoleActivity") local RoleChangeStruct = import(".RoleChangeStruct") RolePlugin.bind(Role) RoleTask.bind(Role) +RoleAdv.bind(Role) RoleActivity.bind(Role) RoleChangeStruct.bind(Role) @@ -35,8 +37,9 @@ Role.schema = { items = {"string", ""}, loveStatus = {"string", ""}, --统计角色的最高 好感度等级 类型相关 -- type=loveL type=loveL - advPass = {"string", ""}, -- 冒险 通关记录 - advInfo = {"table", {}}, -- 冒险 相关信息 + --冒险相关 + advPass = {"string", ""}, -- 通关记录 + advInfo = {"table", {}}, -- 其他信息 } @@ -56,7 +59,7 @@ end function Role:updateProperty(params) params = params or {} - if not self.fields[params.field] then return end + if not self.schema[params.field] then return end local oldValue = self:getProperty(params.field) local ret = {key = params.field, oldValue = oldValue} if params.value then @@ -86,13 +89,36 @@ function Role:notifyUpdateProperties(params) SendPacket(actionCodes.Role_updateProperties, MsgPack.pack(params)) end --- 某些字段更新改变量 改变量的定义由字段自身决定 {{type = ""}, } +-- 某些字段 更新改变量 改变量的定义由字段自身决定 {{type = ""}, } function Role:changeUpdates(params, notNotify) local changeUpdateFunc = { ["loveStatus"] = function(info) self:setProperty("loveStatus", self:getProperty("loveStatus"):setv(info["field"], info["value"])) return {type = "loveStatus", field = info["field"], value = info["value"]} end, + --table 类型通用更新 + ["tableCommon"] = function(fieldType, info) + if self.class.schema[fieldType][1] ~= "table" then + error("[ERROR:] need handler for changeUpdate, field : " .. fieldType) + return + end + --支持多深度单字段 + local curValue = self:getProperty(fieldType) + if type(info["field"]) == "table" then + for _idx, _field in ipairs(info["field"]) do + if _idx < #info["field"] then + curValue[_field] = curValue[_field] or {} + curValue = curValue[_field] + else + curValue[_field] = info["value"] + end + end + else + curValue[info["field"]] = info["value"] + end + self:setProperty(fieldType) + return {type = fieldType, field = info["field"], value = info["value"]} + end, } local updates = {} @@ -100,7 +126,7 @@ function Role:changeUpdates(params, notNotify) if changeUpdateFunc[one["type"]] then table.insert(updates, changeUpdateFunc[one["type"]](one)) else - print("need handler for changeUpdate type : " .. params["type"]) + table.insert(updates, changeUpdateFunc["tableCommon"](one["type"], one)) end end if not notNotify and next(updates) then @@ -117,6 +143,8 @@ function Role:data() reDiamond = self:getProperty("reDiamond"), items = self:getProperty("items"):toNumMap(), loveStatus = self:getProperty("loveStatus"):toNumMap(), + advPass = self:getProperty("advPass"), + advInfo = self:getProperty("advInfo"), } end diff --git a/src/models/RoleAdv.lua b/src/models/RoleAdv.lua new file mode 100644 index 0000000..59f0674 --- /dev/null +++ b/src/models/RoleAdv.lua @@ -0,0 +1,250 @@ + +local RoleAdv = {} + +function RoleAdv.bind(Role) + + + local function getIdByCr(c, r) + local crId = math.abs(r) + math.abs(c) * 100 + if c < 0 then + crId = crId + 10000 + end + if r < 0 then + crId = crId + 20000 + end + return crId + end + local function getCrById(crId) + local c = math.floor(crId % 10000 / 100) + local r = crId % 100 + local last = math.floor(crId / 10000) + if last == 3 then + c, r = -c, -r + elseif last == 1 then + c = -c + elseif last == 2 then + r = -r + end + return c, r + end + + --检查 是否满足层数限制条件 + local function checkIsIn(checkValue, checkType, checkRange) + if not checkValue then return end + if checkType == 1 then + local limits = checkRange:toNumMap() + for min, max in pairs(limits) do + if checkValue >= min and checkValue <= max then + return true + end + end + else + local limit = checkRange:toArray(true, "=") + for _, _l in ipairs(limit) do + if _l == checkValue then + return true + end + end + end + end + + --关卡事件库 + local function getEventLib(chapterId, level) + local chapter = math.floor(chapterId / 100) % 100 + + local libsToType = { + ["event_monsterCsv"] = {AdvEventType.Monster, AdvEventType.BOSS}, + ["event_chooseCsv"] = AdvEventType.Choose, + ["event_dropCsv"] = AdvEventType.Drop, + ["event_buildingCsv"] = AdvEventType.Build, + ["event_traderCsv"] = AdvEventType.Trader, + + } + local eventLib = {} + for lib, eventType in pairs(libsToType) do + if type(eventType) == "table" then + for _, temp in ipairs(eventType) do + eventLib[temp] = {} + end + else + eventLib[eventType] = {} + end + for id, data in pairs(csvdb[lib]) do + if data.levelchapter == chapter then + if checkIsIn(level, data.leveltype, data.levellimit) then + if type(eventType) == "table" then + eventLib[eventType[data.type]][id] = data + else + eventLib[eventType][id] = data + end + end + end + end + end + return eventLib + end + + -- 生成地图 是否可以生成地图上层判断 + function Role:randomAdvMap(chapterId, level) + local chapterData = csvdb["adv_chapterCsv"][chapterId] + if not chapterData then return end + if level > chapterData.limitlevel then return end + --随出地图 + local raw_pool = chapterData.mapid:toArray(true, "=") + local advInfo = self:getProperty("advInfo") + local lastMapId = advInfo.mapId --非同一层不连续随出同一张类似的地图 + local lastChapterId = advInfo.chapter + local pool = {} + for _, mapId in ipairs(raw_pool) do + local temp = csvdb["mapCsv"][mapId] + if temp and (lastChapterId == chapterId or lastMapId ~= mapId) then --非同一层不连续随出同一张类似的地图 + if checkIsIn(level, temp.leveltype, temp.levellimit) then + table.insert(pool, mapId) + end + end + end + if not next(pool) then return end + local mapId = pool[math.randomInt(1, #pool)] + --随出事件 + local mapData = csvdb["map_" .. csvdb["mapCsv"][mapId]["path"] .. "Csv"] + if not mapData then return end + + table.clear(advInfo) + advInfo.chapter = chapterId + advInfo.level = level + advInfo.mapId = mapId + advInfo.rooms = {} -- {[roomId] = {event = {}, open = {}, isPath = nil},} -- event 事件信息(具体信息查看randomEvent), open 是否解锁 isPath 是否是路径 + + --事件随机 + local eventLib = getEventLib(chapterId, level) + local monsterEvents = {} --处理钥匙掉落 + local haveBoss = false + local function randomEvent(roomId, blockId, eventType) + if advInfo.rooms[roomId]["event"][blockId] then return end --已经有事件了 不覆盖 + local event = {etype = eventType} + local randomFunc = { + [AdvEventType.In] = function() + advInfo.rooms[roomId]["open"][blockId] = 1 + end, + [AdvEventType.Out] = function() + end, + [AdvEventType.BOSS] = function() + if not next(eventLib[eventType]) or haveBoss then return false end + haveBoss = true + event.id = math.randWeight(eventLib[eventType], "showup") + end, + [AdvEventType.Choose] = function() + if not next(eventLib[eventType]) then return false end + event.id = math.randWeight(eventLib[eventType], "showup") + end, + [AdvEventType.Drop] = function() + if not next(eventLib[eventType]) then return false end + event.item = eventLib[eventType][math.randWeight(eventLib[eventType], "showup")]["range"]:randWeight(true) + end, + [AdvEventType.Monster] = function() + if not next(eventLib[eventType]) then return false end + event.id = math.randWeight(eventLib[eventType], "showup") + table.insert(monsterEvents, event) + end, + [AdvEventType.Trader] = function() + if not next(eventLib[eventType]) then return false end + event.id = math.randWeight(eventLib[eventType], "showup") + end, + [AdvEventType.Build] = function() + if not next(eventLib[eventType]) then return false end + event.id = math.randWeight(eventLib[eventType], "showup") + end, + } + + if randomFunc[eventType] then + if randomFunc[eventType]() ~= false then + advInfo.rooms[roomId]["event"][blockId] = event + end + end + end + + stagePool = {["global"] = {}} + for roomId, roomName in pairs(mapData["rooms"]) do + stagePool[roomId] = {} + advInfo.rooms[roomId] = {event = {}, open = {}} -- 事件, open + local roomData + if roomName == "path" then + advInfo.rooms[roomId].isPath = true + roomData = mapData["path"] + else + roomName = roomName:gsub("/", "_") + roomData = csvdb["room_" .. roomName .. "Csv"] + end + for blockId, stageType in pairs(roomData["blocks"]) do + if AdvSpecialStage[stageType] then + eventType = AdvEventType[AdvSpecialStage[stageType]] + randomEvent(roomId, blockId, eventType) + else + stagePool["global"][stageType] = stagePool["global"][stageType] or {} + stagePool[roomId][stageType] = stagePool[roomId][stageType] or {} + table.insert(stagePool["global"][stageType], {room = roomId, block = blockId}) + stagePool[roomId][stageType][blockId] = 1 + end + end + end + -- 全地图事件 优先级高 + for stageType, events in pairs(mapData["events"]) do + for _, event in ipairs(events) do + local lastCount = #stagePool["global"][stageType] + if lastCount <= 0 then break end + if math.randomFloat(0, 1) <= (event["rate"] or 1) then + local count = math.randomInt(math.min(lastCount, event["minc"]), math.min(lastCount, event["maxc"])) + for i = 1, count do + local idx = math.randomInt(1, lastCount) + local cur = stagePool["global"][stageType][idx] + randomEvent(cur["room"], cur["block"], event["event"]) + table.remove(stagePool["global"][stageType], idx) + lastCount = lastCount - 1 + stagePool[cur["room"]][stageType][cur["block"]] = nil + end + end + end + end + -- 随机单个房间的事件 + for roomId, roomName in pairs(mapData["rooms"]) do + local roomData + if roomName == "path" then + roomData = mapData["path"] + else + roomName = roomName:gsub("/", "_") + roomData = csvdb["room_" .. roomName .. "Csv"] + end + for stageType, events in pairs(roomData["events"]) do + local bpool = {} + if stagePool[roomId][stageType] then + for block, _ in pairs(stagePool[roomId][stageType]) do + table.insert(bpool, block) + end + end + for _, event in ipairs(events) do + if #bpool <= 0 then break end + if math.randomFloat(0, 1) <= (event["rate"] or 1) then + local count = math.randomInt(math.min(#bpool, event["minc"]), math.min(#bpool, event["maxc"])) + for i = 1, count do + local idx = math.randomInt(1, #bpool) + randomEvent(roomId, bpool[idx], event["event"]) + table.remove(bpool, idx) + end + end + end + end + end + if not haveBoss then + if not next(monsterEvents) then + print("这个地图没有钥匙!!! mapId : " .. mapId) + else + local event = monsterEvents[math.randomInt(1, #monsterEvents)] + event.item = {1, 1} --掉落钥匙 + end + end + self:updateProperty({field = "advInfo", value = advInfo}) + end + +end + +return RoleAdv \ No newline at end of file diff --git a/src/utils/TableUtil.lua b/src/utils/TableUtil.lua index b2fa1b6..b858f7a 100644 --- a/src/utils/TableUtil.lua +++ b/src/utils/TableUtil.lua @@ -5,4 +5,10 @@ function table.arrayToMap(tab) result[tab[i]] = tab[i + 1] end return result +end + +function table.clear(tab) + for k, _ in pairs(tab) do + tab[k] = nil + end end \ No newline at end of file -- libgit2 0.21.2