Commit 23d89d1311fb747bc78ebbad220bc273a64b3262
1 parent
8dce6908
冒险 结构
Showing
7 changed files
with
377 additions
and
10 deletions
Show diff stats
src/GlobalVar.lua
... | ... | @@ -55,4 +55,24 @@ ItemId = { |
55 | 55 | Diamond = 3, -- 钻石 |
56 | 56 | BreakCost = 4, -- 突破材料 |
57 | 57 | HeroFC = {700, 701, 702, 703}, -- 通用角色碎片 |
58 | +} | |
59 | + | |
60 | +--客户端不需要知道这个 | |
61 | +AdvSpecialStage = { | |
62 | + [1]= "In", | |
63 | + [2] = "Out", | |
64 | + [3] = "BOSS" | |
65 | +} | |
66 | +--客户端需要知道这个 | |
67 | +AdvEventType = { | |
68 | + -- 特殊事件(地块决定) | |
69 | + In = -1, --入口 | |
70 | + Out = -2, --出口 | |
71 | + BOSS = -3, -- boss | |
72 | + -- 普通事件(随机) | |
73 | + Choose = 1, --选择点 | |
74 | + Drop = 2, --物品掉落点 | |
75 | + Monster = 3, -- 普通怪 | |
76 | + Trader = 4, --商人 | |
77 | + Build = 5, --建筑物 | |
58 | 78 | } |
59 | 79 | \ No newline at end of file | ... | ... |
src/ProtocolCode.lua
... | ... | @@ -20,6 +20,9 @@ actionCodes = { |
20 | 20 | Role_updateProperties = 106, |
21 | 21 | Role_updateItems = 107, |
22 | 22 | Role_changeUpdate = 108, |
23 | + Role_pipelining = 109, | |
24 | + | |
25 | + Adv_startAdvRpc = 151, | |
23 | 26 | |
24 | 27 | Hero_loadInfos = 201, |
25 | 28 | Hero_updateProperty = 202, |
... | ... | @@ -35,6 +38,7 @@ actionCodes = { |
35 | 38 | Hero_loveItemRpc = 212, |
36 | 39 | Hero_loveTaskRpc = 213, |
37 | 40 | Hero_changeSkinRpc = 214, |
41 | + | |
38 | 42 | } |
39 | 43 | |
40 | 44 | rpcResponseBegin = 10000 | ... | ... |
... | ... | @@ -0,0 +1,35 @@ |
1 | +local ipairs = ipairs | |
2 | +local table = table | |
3 | +local math = math | |
4 | +local next = next | |
5 | +local string = string | |
6 | +local redisproxy = redisproxy | |
7 | +local MsgPack = MsgPack | |
8 | +local getRandomName = getRandomName | |
9 | +local mcast_util = mcast_util | |
10 | +local string_format = string.format | |
11 | +local tonumber = tonumber | |
12 | +local require = require | |
13 | +local table_insert = table.insert | |
14 | +local tconcat = table.concat | |
15 | +local table_unpack = table.unpack | |
16 | + | |
17 | +local _M = {} | |
18 | + | |
19 | +function _M.startAdvRpc( agent, data ) | |
20 | + local role = agent.role | |
21 | + local msg = MsgPack.unpack(data) | |
22 | + | |
23 | + local advInfo = role:getProperty("advInfo") | |
24 | + | |
25 | + role:randomAdvMap(10101, 1) --测试 | |
26 | + | |
27 | + SendPacket(actionCodes.Adv_startAdvRpc, '') | |
28 | + return true | |
29 | +end | |
30 | + | |
31 | + | |
32 | + | |
33 | + | |
34 | + | |
35 | +return _M | |
0 | 36 | \ No newline at end of file | ... | ... |
src/agent.lua
... | ... | @@ -46,17 +46,41 @@ function cancel_agent_timer() |
46 | 46 | end |
47 | 47 | ---- 定时器相关 }}} |
48 | 48 | |
49 | +local _pipelinings = {} --可同时多个序列 栈的形式保证嵌套不出错 | |
49 | 50 | function SendPacket(actionCode, bin, client_fd) |
50 | - if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end | |
51 | - | |
51 | + client_fd = client_fd or agentInfo.client_fd | |
52 | + | |
52 | 53 | local handlerName = actionHandlers[actionCode] |
53 | 54 | if string.sub(handlerName, -3, -1) == "Rpc" then |
54 | 55 | actionCode = actionCode + rpcResponseBegin |
55 | 56 | end |
57 | + -- 查看是否是在 流水线操作中 | |
58 | + if #_pipelinings > 0 then | |
59 | + local _curPipelining = _pipelinings[#_pipelinings] | |
60 | + _curPipelining[client_fd] = _curPipelining[client_fd] or {} --区分不同客户端 | |
61 | + table.insert(_curPipelining[client_fd], {actionCode, bin}) | |
62 | + else | |
63 | + if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end | |
64 | + local head = string.pack("H", actionCode) | |
65 | + return socket.write(client_fd, netpack.pack(head .. bin)) | |
66 | + end | |
67 | +end | |
56 | 68 | |
57 | - local client_fd = client_fd or agentInfo.client_fd | |
58 | - local head = string.pack("H", actionCode) | |
59 | - return socket.write(client_fd, netpack.pack(head .. bin)) | |
69 | +function SendPipelining(callback) | |
70 | + if type(callback) ~= "function" then return end | |
71 | + --push 当前队列 | |
72 | + table.insert(_pipelinings, {}) | |
73 | + -- 执行代码块 输出错误信息 | |
74 | + local ok, err = pcall(callback) | |
75 | + --弹出当前队列 | |
76 | + local curPipelining = table.remove(_pipelinings) | |
77 | + -- 查看是否有消息 | |
78 | + if next(curPipelining) then | |
79 | + for client_fd, msg in pairs(curPipelining) do | |
80 | + SendPacket(actionCodes.Role_pipelining, MsgPack.pack(msg), client_fd) | |
81 | + end | |
82 | + end | |
83 | + if not ok then error(err) end | |
60 | 84 | end |
61 | 85 | |
62 | 86 | function rpcAgent(roleId, funcName, ...) | ... | ... |
src/models/Role.lua
... | ... | @@ -2,10 +2,12 @@ local Role = class("Role", require("shared.ModelBase")) |
2 | 2 | |
3 | 3 | local RolePlugin = import(".RolePlugin") |
4 | 4 | local RoleTask = import(".RoleTask") |
5 | +local RoleAdv = import(".RoleAdv") | |
5 | 6 | local RoleActivity = import(".RoleActivity") |
6 | 7 | local RoleChangeStruct = import(".RoleChangeStruct") |
7 | 8 | RolePlugin.bind(Role) |
8 | 9 | RoleTask.bind(Role) |
10 | +RoleAdv.bind(Role) | |
9 | 11 | RoleActivity.bind(Role) |
10 | 12 | RoleChangeStruct.bind(Role) |
11 | 13 | |
... | ... | @@ -35,8 +37,9 @@ Role.schema = { |
35 | 37 | items = {"string", ""}, |
36 | 38 | loveStatus = {"string", ""}, --统计角色的最高 好感度等级 类型相关 -- type=loveL type=loveL |
37 | 39 | |
38 | - advPass = {"string", ""}, -- 冒险 通关记录 | |
39 | - advInfo = {"table", {}}, -- 冒险 相关信息 | |
40 | + --冒险相关 | |
41 | + advPass = {"string", ""}, -- 通关记录 | |
42 | + advInfo = {"table", {}}, -- 其他信息 | |
40 | 43 | |
41 | 44 | } |
42 | 45 | |
... | ... | @@ -56,7 +59,7 @@ end |
56 | 59 | |
57 | 60 | function Role:updateProperty(params) |
58 | 61 | params = params or {} |
59 | - if not self.fields[params.field] then return end | |
62 | + if not self.schema[params.field] then return end | |
60 | 63 | local oldValue = self:getProperty(params.field) |
61 | 64 | local ret = {key = params.field, oldValue = oldValue} |
62 | 65 | if params.value then |
... | ... | @@ -86,13 +89,36 @@ function Role:notifyUpdateProperties(params) |
86 | 89 | SendPacket(actionCodes.Role_updateProperties, MsgPack.pack(params)) |
87 | 90 | end |
88 | 91 | |
89 | --- 某些字段更新改变量 改变量的定义由字段自身决定 {{type = ""}, } | |
92 | +-- 某些字段 更新改变量 改变量的定义由字段自身决定 {{type = ""}, } | |
90 | 93 | function Role:changeUpdates(params, notNotify) |
91 | 94 | local changeUpdateFunc = { |
92 | 95 | ["loveStatus"] = function(info) |
93 | 96 | self:setProperty("loveStatus", self:getProperty("loveStatus"):setv(info["field"], info["value"])) |
94 | 97 | return {type = "loveStatus", field = info["field"], value = info["value"]} |
95 | 98 | end, |
99 | + --table 类型通用更新 | |
100 | + ["tableCommon"] = function(fieldType, info) | |
101 | + if self.class.schema[fieldType][1] ~= "table" then | |
102 | + error("[ERROR:] need handler for changeUpdate, field : " .. fieldType) | |
103 | + return | |
104 | + end | |
105 | + --支持多深度单字段 | |
106 | + local curValue = self:getProperty(fieldType) | |
107 | + if type(info["field"]) == "table" then | |
108 | + for _idx, _field in ipairs(info["field"]) do | |
109 | + if _idx < #info["field"] then | |
110 | + curValue[_field] = curValue[_field] or {} | |
111 | + curValue = curValue[_field] | |
112 | + else | |
113 | + curValue[_field] = info["value"] | |
114 | + end | |
115 | + end | |
116 | + else | |
117 | + curValue[info["field"]] = info["value"] | |
118 | + end | |
119 | + self:setProperty(fieldType) | |
120 | + return {type = fieldType, field = info["field"], value = info["value"]} | |
121 | + end, | |
96 | 122 | } |
97 | 123 | |
98 | 124 | local updates = {} |
... | ... | @@ -100,7 +126,7 @@ function Role:changeUpdates(params, notNotify) |
100 | 126 | if changeUpdateFunc[one["type"]] then |
101 | 127 | table.insert(updates, changeUpdateFunc[one["type"]](one)) |
102 | 128 | else |
103 | - print("need handler for changeUpdate type : " .. params["type"]) | |
129 | + table.insert(updates, changeUpdateFunc["tableCommon"](one["type"], one)) | |
104 | 130 | end |
105 | 131 | end |
106 | 132 | if not notNotify and next(updates) then |
... | ... | @@ -117,6 +143,8 @@ function Role:data() |
117 | 143 | reDiamond = self:getProperty("reDiamond"), |
118 | 144 | items = self:getProperty("items"):toNumMap(), |
119 | 145 | loveStatus = self:getProperty("loveStatus"):toNumMap(), |
146 | + advPass = self:getProperty("advPass"), | |
147 | + advInfo = self:getProperty("advInfo"), | |
120 | 148 | } |
121 | 149 | end |
122 | 150 | ... | ... |
... | ... | @@ -0,0 +1,250 @@ |
1 | + | |
2 | +local RoleAdv = {} | |
3 | + | |
4 | +function RoleAdv.bind(Role) | |
5 | + | |
6 | + | |
7 | + local function getIdByCr(c, r) | |
8 | + local crId = math.abs(r) + math.abs(c) * 100 | |
9 | + if c < 0 then | |
10 | + crId = crId + 10000 | |
11 | + end | |
12 | + if r < 0 then | |
13 | + crId = crId + 20000 | |
14 | + end | |
15 | + return crId | |
16 | + end | |
17 | + local function getCrById(crId) | |
18 | + local c = math.floor(crId % 10000 / 100) | |
19 | + local r = crId % 100 | |
20 | + local last = math.floor(crId / 10000) | |
21 | + if last == 3 then | |
22 | + c, r = -c, -r | |
23 | + elseif last == 1 then | |
24 | + c = -c | |
25 | + elseif last == 2 then | |
26 | + r = -r | |
27 | + end | |
28 | + return c, r | |
29 | + end | |
30 | + | |
31 | + --检查 是否满足层数限制条件 | |
32 | + local function checkIsIn(checkValue, checkType, checkRange) | |
33 | + if not checkValue then return end | |
34 | + if checkType == 1 then | |
35 | + local limits = checkRange:toNumMap() | |
36 | + for min, max in pairs(limits) do | |
37 | + if checkValue >= min and checkValue <= max then | |
38 | + return true | |
39 | + end | |
40 | + end | |
41 | + else | |
42 | + local limit = checkRange:toArray(true, "=") | |
43 | + for _, _l in ipairs(limit) do | |
44 | + if _l == checkValue then | |
45 | + return true | |
46 | + end | |
47 | + end | |
48 | + end | |
49 | + end | |
50 | + | |
51 | + --关卡事件库 | |
52 | + local function getEventLib(chapterId, level) | |
53 | + local chapter = math.floor(chapterId / 100) % 100 | |
54 | + | |
55 | + local libsToType = { | |
56 | + ["event_monsterCsv"] = {AdvEventType.Monster, AdvEventType.BOSS}, | |
57 | + ["event_chooseCsv"] = AdvEventType.Choose, | |
58 | + ["event_dropCsv"] = AdvEventType.Drop, | |
59 | + ["event_buildingCsv"] = AdvEventType.Build, | |
60 | + ["event_traderCsv"] = AdvEventType.Trader, | |
61 | + | |
62 | + } | |
63 | + local eventLib = {} | |
64 | + for lib, eventType in pairs(libsToType) do | |
65 | + if type(eventType) == "table" then | |
66 | + for _, temp in ipairs(eventType) do | |
67 | + eventLib[temp] = {} | |
68 | + end | |
69 | + else | |
70 | + eventLib[eventType] = {} | |
71 | + end | |
72 | + for id, data in pairs(csvdb[lib]) do | |
73 | + if data.levelchapter == chapter then | |
74 | + if checkIsIn(level, data.leveltype, data.levellimit) then | |
75 | + if type(eventType) == "table" then | |
76 | + eventLib[eventType[data.type]][id] = data | |
77 | + else | |
78 | + eventLib[eventType][id] = data | |
79 | + end | |
80 | + end | |
81 | + end | |
82 | + end | |
83 | + end | |
84 | + return eventLib | |
85 | + end | |
86 | + | |
87 | + -- 生成地图 是否可以生成地图上层判断 | |
88 | + function Role:randomAdvMap(chapterId, level) | |
89 | + local chapterData = csvdb["adv_chapterCsv"][chapterId] | |
90 | + if not chapterData then return end | |
91 | + if level > chapterData.limitlevel then return end | |
92 | + --随出地图 | |
93 | + local raw_pool = chapterData.mapid:toArray(true, "=") | |
94 | + local advInfo = self:getProperty("advInfo") | |
95 | + local lastMapId = advInfo.mapId --非同一层不连续随出同一张类似的地图 | |
96 | + local lastChapterId = advInfo.chapter | |
97 | + local pool = {} | |
98 | + for _, mapId in ipairs(raw_pool) do | |
99 | + local temp = csvdb["mapCsv"][mapId] | |
100 | + if temp and (lastChapterId == chapterId or lastMapId ~= mapId) then --非同一层不连续随出同一张类似的地图 | |
101 | + if checkIsIn(level, temp.leveltype, temp.levellimit) then | |
102 | + table.insert(pool, mapId) | |
103 | + end | |
104 | + end | |
105 | + end | |
106 | + if not next(pool) then return end | |
107 | + local mapId = pool[math.randomInt(1, #pool)] | |
108 | + --随出事件 | |
109 | + local mapData = csvdb["map_" .. csvdb["mapCsv"][mapId]["path"] .. "Csv"] | |
110 | + if not mapData then return end | |
111 | + | |
112 | + table.clear(advInfo) | |
113 | + advInfo.chapter = chapterId | |
114 | + advInfo.level = level | |
115 | + advInfo.mapId = mapId | |
116 | + advInfo.rooms = {} -- {[roomId] = {event = {}, open = {}, isPath = nil},} -- event 事件信息(具体信息查看randomEvent), open 是否解锁 isPath 是否是路径 | |
117 | + | |
118 | + --事件随机 | |
119 | + local eventLib = getEventLib(chapterId, level) | |
120 | + local monsterEvents = {} --处理钥匙掉落 | |
121 | + local haveBoss = false | |
122 | + local function randomEvent(roomId, blockId, eventType) | |
123 | + if advInfo.rooms[roomId]["event"][blockId] then return end --已经有事件了 不覆盖 | |
124 | + local event = {etype = eventType} | |
125 | + local randomFunc = { | |
126 | + [AdvEventType.In] = function() | |
127 | + advInfo.rooms[roomId]["open"][blockId] = 1 | |
128 | + end, | |
129 | + [AdvEventType.Out] = function() | |
130 | + end, | |
131 | + [AdvEventType.BOSS] = function() | |
132 | + if not next(eventLib[eventType]) or haveBoss then return false end | |
133 | + haveBoss = true | |
134 | + event.id = math.randWeight(eventLib[eventType], "showup") | |
135 | + end, | |
136 | + [AdvEventType.Choose] = function() | |
137 | + if not next(eventLib[eventType]) then return false end | |
138 | + event.id = math.randWeight(eventLib[eventType], "showup") | |
139 | + end, | |
140 | + [AdvEventType.Drop] = function() | |
141 | + if not next(eventLib[eventType]) then return false end | |
142 | + event.item = eventLib[eventType][math.randWeight(eventLib[eventType], "showup")]["range"]:randWeight(true) | |
143 | + end, | |
144 | + [AdvEventType.Monster] = function() | |
145 | + if not next(eventLib[eventType]) then return false end | |
146 | + event.id = math.randWeight(eventLib[eventType], "showup") | |
147 | + table.insert(monsterEvents, event) | |
148 | + end, | |
149 | + [AdvEventType.Trader] = function() | |
150 | + if not next(eventLib[eventType]) then return false end | |
151 | + event.id = math.randWeight(eventLib[eventType], "showup") | |
152 | + end, | |
153 | + [AdvEventType.Build] = function() | |
154 | + if not next(eventLib[eventType]) then return false end | |
155 | + event.id = math.randWeight(eventLib[eventType], "showup") | |
156 | + end, | |
157 | + } | |
158 | + | |
159 | + if randomFunc[eventType] then | |
160 | + if randomFunc[eventType]() ~= false then | |
161 | + advInfo.rooms[roomId]["event"][blockId] = event | |
162 | + end | |
163 | + end | |
164 | + end | |
165 | + | |
166 | + stagePool = {["global"] = {}} | |
167 | + for roomId, roomName in pairs(mapData["rooms"]) do | |
168 | + stagePool[roomId] = {} | |
169 | + advInfo.rooms[roomId] = {event = {}, open = {}} -- 事件, open | |
170 | + local roomData | |
171 | + if roomName == "path" then | |
172 | + advInfo.rooms[roomId].isPath = true | |
173 | + roomData = mapData["path"] | |
174 | + else | |
175 | + roomName = roomName:gsub("/", "_") | |
176 | + roomData = csvdb["room_" .. roomName .. "Csv"] | |
177 | + end | |
178 | + for blockId, stageType in pairs(roomData["blocks"]) do | |
179 | + if AdvSpecialStage[stageType] then | |
180 | + eventType = AdvEventType[AdvSpecialStage[stageType]] | |
181 | + randomEvent(roomId, blockId, eventType) | |
182 | + else | |
183 | + stagePool["global"][stageType] = stagePool["global"][stageType] or {} | |
184 | + stagePool[roomId][stageType] = stagePool[roomId][stageType] or {} | |
185 | + table.insert(stagePool["global"][stageType], {room = roomId, block = blockId}) | |
186 | + stagePool[roomId][stageType][blockId] = 1 | |
187 | + end | |
188 | + end | |
189 | + end | |
190 | + -- 全地图事件 优先级高 | |
191 | + for stageType, events in pairs(mapData["events"]) do | |
192 | + for _, event in ipairs(events) do | |
193 | + local lastCount = #stagePool["global"][stageType] | |
194 | + if lastCount <= 0 then break end | |
195 | + if math.randomFloat(0, 1) <= (event["rate"] or 1) then | |
196 | + local count = math.randomInt(math.min(lastCount, event["minc"]), math.min(lastCount, event["maxc"])) | |
197 | + for i = 1, count do | |
198 | + local idx = math.randomInt(1, lastCount) | |
199 | + local cur = stagePool["global"][stageType][idx] | |
200 | + randomEvent(cur["room"], cur["block"], event["event"]) | |
201 | + table.remove(stagePool["global"][stageType], idx) | |
202 | + lastCount = lastCount - 1 | |
203 | + stagePool[cur["room"]][stageType][cur["block"]] = nil | |
204 | + end | |
205 | + end | |
206 | + end | |
207 | + end | |
208 | + -- 随机单个房间的事件 | |
209 | + for roomId, roomName in pairs(mapData["rooms"]) do | |
210 | + local roomData | |
211 | + if roomName == "path" then | |
212 | + roomData = mapData["path"] | |
213 | + else | |
214 | + roomName = roomName:gsub("/", "_") | |
215 | + roomData = csvdb["room_" .. roomName .. "Csv"] | |
216 | + end | |
217 | + for stageType, events in pairs(roomData["events"]) do | |
218 | + local bpool = {} | |
219 | + if stagePool[roomId][stageType] then | |
220 | + for block, _ in pairs(stagePool[roomId][stageType]) do | |
221 | + table.insert(bpool, block) | |
222 | + end | |
223 | + end | |
224 | + for _, event in ipairs(events) do | |
225 | + if #bpool <= 0 then break end | |
226 | + if math.randomFloat(0, 1) <= (event["rate"] or 1) then | |
227 | + local count = math.randomInt(math.min(#bpool, event["minc"]), math.min(#bpool, event["maxc"])) | |
228 | + for i = 1, count do | |
229 | + local idx = math.randomInt(1, #bpool) | |
230 | + randomEvent(roomId, bpool[idx], event["event"]) | |
231 | + table.remove(bpool, idx) | |
232 | + end | |
233 | + end | |
234 | + end | |
235 | + end | |
236 | + end | |
237 | + if not haveBoss then | |
238 | + if not next(monsterEvents) then | |
239 | + print("这个地图没有钥匙!!! mapId : " .. mapId) | |
240 | + else | |
241 | + local event = monsterEvents[math.randomInt(1, #monsterEvents)] | |
242 | + event.item = {1, 1} --掉落钥匙 | |
243 | + end | |
244 | + end | |
245 | + self:updateProperty({field = "advInfo", value = advInfo}) | |
246 | + end | |
247 | + | |
248 | +end | |
249 | + | |
250 | +return RoleAdv | |
0 | 251 | \ No newline at end of file | ... | ... |
src/utils/TableUtil.lua