Commit be83d162bc6ca06281a7357740949e6494764081
1 parent
45808b0a
登陆成功。 增加数据结构修正功能
Showing
11 changed files
with
249 additions
and
139 deletions
Show diff stats
src/actions/RoleAction.lua
@@ -55,11 +55,11 @@ function _M.loginRpc( agent, data ) | @@ -55,11 +55,11 @@ function _M.loginRpc( agent, data ) | ||
55 | local msg = MsgPack.unpack(data) | 55 | local msg = MsgPack.unpack(data) |
56 | local response = {} | 56 | local response = {} |
57 | 57 | ||
58 | - if msg.version ~= globalCsv.version then | ||
59 | - response.result = "UPDATE_TIP" | ||
60 | - SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) | ||
61 | - return true | ||
62 | - end | 58 | + -- if msg.version ~= globalCsv.version then |
59 | + -- response.result = "UPDATE_TIP" | ||
60 | + -- SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) | ||
61 | + -- return true | ||
62 | + -- end | ||
63 | 63 | ||
64 | -- 1. | 64 | -- 1. |
65 | local roleId = redisproxy:get(string_format("user:%s", string.upper(msg.name))) | 65 | local roleId = redisproxy:get(string_format("user:%s", string.upper(msg.name))) |
@@ -99,112 +99,42 @@ function _M.loginRpc( agent, data ) | @@ -99,112 +99,42 @@ function _M.loginRpc( agent, data ) | ||
99 | role:reloadWhenLogin() | 99 | role:reloadWhenLogin() |
100 | end | 100 | end |
101 | 101 | ||
102 | - if not msg.isGMlogin then | ||
103 | - local banTime = role:getProperty("banTime") | ||
104 | - if banTime > now then | ||
105 | - response.result = "BAN_TIP" | ||
106 | - response.banTime = banTime | ||
107 | - response.banType = role:getProperty("banType") | ||
108 | - response.roleId = roleId | ||
109 | - SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) | ||
110 | - return true | ||
111 | - end | ||
112 | - if banTime ~= 0 then | ||
113 | - -- 清除封号状态 | ||
114 | - role:setBan(0) | ||
115 | - end | ||
116 | - end | 102 | + -- if not msg.isGMlogin then |
103 | + -- local banTime = role:getProperty("banTime") | ||
104 | + -- if banTime > now then | ||
105 | + -- response.result = "BAN_TIP" | ||
106 | + -- response.banTime = banTime | ||
107 | + -- response.banType = role:getProperty("banType") | ||
108 | + -- response.roleId = roleId | ||
109 | + -- SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) | ||
110 | + -- return true | ||
111 | + -- end | ||
112 | + -- if banTime ~= 0 then | ||
113 | + -- -- 清除封号状态 | ||
114 | + -- role:setBan(0) | ||
115 | + -- end | ||
116 | + -- end | ||
117 | SERV_OPEN = redisproxy:hget("autoincrement_set", "server_start") | 117 | SERV_OPEN = redisproxy:hget("autoincrement_set", "server_start") |
118 | local lastLoginTime = role:getProperty("lastLoginTime") | 118 | local lastLoginTime = role:getProperty("lastLoginTime") |
119 | 119 | ||
120 | - -- 跨天登陆事件 | ||
121 | - if not role:onCrossDay(now) then | ||
122 | - role:checkActivityStatus(lastLoginTime, now) | ||
123 | - if role:getProperty("carbonDouble") == "" then | ||
124 | - role:initCarbonDouble() | ||
125 | - end | ||
126 | - end | ||
127 | - -- 登陆回复 | ||
128 | - role:onRecoverLogin(now) | ||
129 | - -- 引导是否连续 | ||
130 | - role:checkGuide() | 120 | + role:changeStructVersion() -- 数据结构 版本更新 |
131 | 121 | ||
122 | + -- 跨天登陆事件 | ||
123 | + -- role:onCrossDay(now) | ||
132 | 124 | ||
133 | role:setProperty("lastLoginTime", now) | 125 | role:setProperty("lastLoginTime", now) |
134 | - if msg.device and type(msg.device) == "string" then | ||
135 | - role:setProperty("device", msg.device) | ||
136 | - end | 126 | + -- if msg.device and type(msg.device) == "string" then |
127 | + -- role:setProperty("device", msg.device) | ||
128 | + -- end | ||
137 | 129 | ||
138 | response.role = role:data() | 130 | response.role = role:data() |
139 | response.result = "SUCCESS" | 131 | response.result = "SUCCESS" |
140 | response.serverTime = now | 132 | response.serverTime = now |
141 | 133 | ||
142 | - -- 需要加载模块数据 | ||
143 | - local modules = { | ||
144 | - "carbons","maps", | ||
145 | - } | ||
146 | - | ||
147 | - local heroIds = {} | ||
148 | - for heroId, _ in pairs(role.heros) do | ||
149 | - table.insert(heroIds, heroId) | ||
150 | - end | ||
151 | - local heroWave = math.ceil(#heroIds / WAVE_HERO_NUMS) | ||
152 | - | ||
153 | - local equipIds = {} | ||
154 | - for equipId, _ in pairs(role.equips) do | ||
155 | - table.insert(equipIds, equipId) | ||
156 | - end | ||
157 | - local equipWave = math.ceil(#equipIds / WAVE_EQUIP_NUMS) | ||
158 | - | ||
159 | - if #heroIds <= 50 then | ||
160 | - heroWave = 0 | ||
161 | - table_insert(modules, "heros") | ||
162 | - end | ||
163 | - if #equipIds <= 50 then | ||
164 | - equipWave = 0 | ||
165 | - table_insert(modules, "equips") | ||
166 | - end | ||
167 | - | ||
168 | - for _, name in ipairs(modules) do | ||
169 | - response[name] = {} | ||
170 | - for id, unit in pairs(role[name]) do | ||
171 | - response[name][id] = unit:data() | ||
172 | - end | ||
173 | - end | ||
174 | - response.wave = 1 + heroWave + equipWave | 134 | + response.wave = 1 |
175 | 135 | ||
176 | SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) | 136 | SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(response)) |
177 | 137 | ||
178 | - local heroIndex = 1 | ||
179 | - for index = 2, 1 + heroWave do | ||
180 | - local heroResponse = {heros = {}} | ||
181 | - for i = heroIndex, heroIndex + WAVE_HERO_NUMS do | ||
182 | - local heroId = heroIds[i] | ||
183 | - if not heroId then | ||
184 | - break | ||
185 | - end | ||
186 | - local hero = role.heros[heroId] | ||
187 | - table_insert(heroResponse.heros, hero:data()) | ||
188 | - heroIndex = heroIndex + 1 | ||
189 | - end | ||
190 | - heroResponse.heroWave = index | ||
191 | - SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(heroResponse)) | ||
192 | - end | ||
193 | - local equipIndex = 1 | ||
194 | - for index = 2 + heroWave, 1 + heroWave + equipWave do | ||
195 | - local equipResponse = {equips = {}} | ||
196 | - for i = equipIndex, equipIndex + WAVE_EQUIP_NUMS do | ||
197 | - local equipId = equipIds[i] | ||
198 | - if not equipId then | ||
199 | - break | ||
200 | - end | ||
201 | - local equip = role.equips[equipId] | ||
202 | - table_insert(equipResponse.equips, equip:data()) | ||
203 | - equipIndex = equipIndex + 1 | ||
204 | - end | ||
205 | - equipResponse.equipWave = index | ||
206 | - SendPacket(actionCodes.Role_loginRpc, MsgPack.pack(equipResponse)) | ||
207 | - end | ||
208 | 138 | ||
209 | -- role:log("login", { ip = agent.ip, diamond = role:getProperty("diamond"), reDiamond = role:getProperty("reDiamond")}) | 139 | -- role:log("login", { ip = agent.ip, diamond = role:getProperty("diamond"), reDiamond = role:getProperty("reDiamond")}) |
210 | 140 | ||
@@ -214,7 +144,6 @@ function _M.loginRpc( agent, data ) | @@ -214,7 +144,6 @@ function _M.loginRpc( agent, data ) | ||
214 | gate_serv = agent.gate_serv, | 144 | gate_serv = agent.gate_serv, |
215 | }) | 145 | }) |
216 | agent.role = role | 146 | agent.role = role |
217 | - role.lessmsg = false | ||
218 | 147 | ||
219 | start_agent_timer() | 148 | start_agent_timer() |
220 | -- 注册全服广播 | 149 | -- 注册全服广播 |
@@ -247,7 +176,6 @@ function _M.createRpc(agent, data) | @@ -247,7 +176,6 @@ function _M.createRpc(agent, data) | ||
247 | return true | 176 | return true |
248 | end | 177 | end |
249 | local roleName = setRoleName(msg.uid, roleId) | 178 | local roleName = setRoleName(msg.uid, roleId) |
250 | - | ||
251 | local newRole = require("models.Role").new({ | 179 | local newRole = require("models.Role").new({ |
252 | key = string_format("role:%d", roleId), | 180 | key = string_format("role:%d", roleId), |
253 | id = roleId, | 181 | id = roleId, |
@@ -269,38 +197,6 @@ function _M.createRpc(agent, data) | @@ -269,38 +197,6 @@ function _M.createRpc(agent, data) | ||
269 | return true | 197 | return true |
270 | end | 198 | end |
271 | 199 | ||
272 | - -- 给角色自动加载当前副本数据 | ||
273 | - newRole:addCarbon({carbonId = 10101, status = 0, starNum = 0}) | ||
274 | - -- 给角色自动加载农场信息 | ||
275 | - newRole:addFarm() | ||
276 | - -- 给角色自动加载爬塔信息 | ||
277 | - newRole:addTower() | ||
278 | - -- 给角色增加pvpInfo | ||
279 | - newRole:addPvpInfo() | ||
280 | - --给新角色增加diner | ||
281 | - newRole:addDiner() | ||
282 | - -- 关闭 锁定新食灵 | ||
283 | - local autoStatus = newRole:getProperty("autoStatus") | ||
284 | - newRole:setProperty("autoStatus", autoStatus:setv(3,1)) | ||
285 | - | ||
286 | - for index, hero in ipairs(globalCsv["birthHero"]) do | ||
287 | - hero.notNotify = true | ||
288 | - hero.desc = "birth_award" | ||
289 | - local heroId = newRole:awardHero(hero.type, hero) | ||
290 | - if index == 1 then | ||
291 | - local newHero = newRole.heros[heroId] | ||
292 | - newHero:setProperty("lock", 1) | ||
293 | - newHero:setProperty("formation", 1) | ||
294 | - newRole:setProperty("crown", heroId) | ||
295 | - newRole:setProperty("formationJson", json.encode({["1"] = {list = {["1"] = heroId}, pos = {["1"] = heroId}, lock = {}}})) | ||
296 | - end | ||
297 | - end | ||
298 | - -- 出生道具 | ||
299 | - local ucode = getActionCode(newRole) | ||
300 | - for id, num in pairs(globalCsv["birthItem"]:toNumMap()) do | ||
301 | - newRole:awardItemCsv(id, {count = num, desc = "birth_award", notNotify = true, ucode = ucode}) | ||
302 | - end | ||
303 | - | ||
304 | -- 欢迎邮件 | 200 | -- 欢迎邮件 |
305 | -- redisproxy:insertEmail({roleId = roleId, emailId = 1}) | 201 | -- redisproxy:insertEmail({roleId = roleId, emailId = 1}) |
306 | -- redisproxy:insertEmail({roleId = roleId, emailId = 2}) | 202 | -- redisproxy:insertEmail({roleId = roleId, emailId = 2}) |
src/models/Role.lua
1 | local Role = class("Role", require("shared.ModelBase")) | 1 | local Role = class("Role", require("shared.ModelBase")) |
2 | 2 | ||
3 | +local RolePlugin = import(".RolePlugin") | ||
4 | +local RoleTask = import(".RoleTask") | ||
5 | +local RoleActivity = import(".RoleActivity") | ||
6 | +local RoleChangeStruct = import(".RoleChangeStruct") | ||
7 | +RolePlugin.bind(Role) | ||
8 | +RoleTask.bind(Role) | ||
9 | +RoleActivity.bind(Role) | ||
10 | +RoleChangeStruct.bind(Role) | ||
11 | + | ||
3 | function Role:ctor( properties ) | 12 | function Role:ctor( properties ) |
4 | Role.super.ctor(self, properties) | 13 | Role.super.ctor(self, properties) |
5 | - | ||
6 | - self.heros = {} | ||
7 | self.ignoreHeartbeat = false | 14 | self.ignoreHeartbeat = false |
8 | - | ||
9 | end | 15 | end |
10 | 16 | ||
11 | Role.schema = { | 17 | Role.schema = { |
12 | key = {"string"}, | 18 | key = {"string"}, |
13 | id = {"number"}, | 19 | id = {"number"}, |
14 | uid = {"string", ""}, | 20 | uid = {"string", ""}, |
15 | - sid = {"number", 0}, | ||
16 | name = {"string", ""}, | 21 | name = {"string", ""}, |
22 | + sid = {"number", 0}, | ||
23 | + device = {"string", ""}, | ||
24 | + banTime = {"number", 0}, | ||
25 | + banType = {"number", 0}, | ||
26 | + lastLoginTime = {"number", 0}, | ||
27 | + createTime = {"number", skynet.timex()}, | ||
28 | + structVersion = {"number", globalCsv.StructVersion or 0}, -- 重整数据 | ||
29 | + | ||
30 | + -- roleInfo | ||
31 | + level = {"number", 0}, | ||
32 | + diamond = {"number", 0}, | ||
33 | + reDiamond = {"number", 0}, | ||
34 | + items = {"string", ""} | ||
17 | } | 35 | } |
18 | 36 | ||
19 | Role.fields = { | 37 | Role.fields = { |
20 | id = true, | 38 | id = true, |
21 | uid = true, | 39 | uid = true, |
22 | sid = true, | 40 | sid = true, |
41 | + device = true, | ||
23 | name = true, | 42 | name = true, |
43 | + banTime = true, | ||
44 | + banType = true, | ||
45 | + lastLoginTime = true, | ||
46 | + createTime = true, | ||
47 | + level = true, | ||
48 | + diamond = true, | ||
49 | + reDiamond = true, | ||
50 | + items = true, | ||
24 | } | 51 | } |
25 | 52 | ||
53 | + | ||
54 | + | ||
26 | function Role:data() | 55 | function Role:data() |
27 | return { | 56 | return { |
28 | id = self:getProperty("id"), | 57 | id = self:getProperty("id"), |
58 | + name = self:getProperty("name"), | ||
59 | + level = self:getProperty("level"), | ||
60 | + diamond = self:getProperty("diamond"), | ||
61 | + reDiamond = self:getProperty("reDiamond"), | ||
62 | + items = self:getProperty("items"):toNumMap(), | ||
63 | + | ||
29 | } | 64 | } |
30 | end | 65 | end |
31 | 66 |
@@ -0,0 +1,108 @@ | @@ -0,0 +1,108 @@ | ||
1 | + | ||
2 | + | ||
3 | +local VersionType = { | ||
4 | + --不可复用 | ||
5 | + DoOnly = 1, -- 严格执行 数据结构变更等 | ||
6 | + -- 复用类型 | ||
7 | + Add = 2, -- 可叠加执行 活动清除状态等 params需是数组 | ||
8 | + Override = 3, -- 覆盖执行 只执行最后一个同方法变更 取最后一个的 params | ||
9 | +} | ||
10 | + | ||
11 | +---------------------版本方法 start --------------------- | ||
12 | +local function createVersionFunc(vType, func) | ||
13 | + local v = {vType = vType} | ||
14 | + setmetatable(v, {__call = function(cv, ...) | ||
15 | + func( ... ) | ||
16 | + end}) | ||
17 | + return v | ||
18 | +end | ||
19 | + | ||
20 | +-- 例子 | ||
21 | +local clearActivity = createVersionFunc(VersionType.Add ,function(role, params) | ||
22 | + print("clearActivity") | ||
23 | + dump(params) | ||
24 | +end) | ||
25 | + | ||
26 | +local changeStructF = createVersionFunc(VersionType.DoOnly ,function(role, params) | ||
27 | + print("changeStructF" .. " >>> " .. params) | ||
28 | +end) | ||
29 | + | ||
30 | +local awardGift = createVersionFunc(VersionType.Override ,function(role, params) | ||
31 | + print("awardGift" .. " >>> " .. params) | ||
32 | +end) | ||
33 | + | ||
34 | +---------------------版本方法 end ---------------------- | ||
35 | + | ||
36 | +-- version 罗列start | ||
37 | +local versionList = {} -- version 列表 | ||
38 | +versionList[1] = {clearActivity, {1, 2}} | ||
39 | +versionList[2] = {clearActivity, {5, 7}} | ||
40 | +versionList[3] = {changeStructF, "test1"} | ||
41 | +versionList[4] = {changeStructF, "test2"} | ||
42 | +versionList[5] = {awardGift, "test3"} | ||
43 | +versionList[6] = {awardGift, "test4"} | ||
44 | + | ||
45 | +--version 罗列end | ||
46 | + | ||
47 | + | ||
48 | + | ||
49 | +local RoleChangeStruct = {} | ||
50 | +-- 处理历史遗留问题 以及数据不兼容的问题。可用于版本间清除活动状态,发放补偿, 修改数据结构等 | ||
51 | +function RoleChangeStruct.bind(Role) | ||
52 | + | ||
53 | + function Role:changeStructVersion() | ||
54 | + globalCsv.StructVersion = 6 | ||
55 | + local curVersion = self:getProperty("structVersion") | ||
56 | + if not globalCsv.StructVersion or curVersion >= globalCsv.StructVersion then return end | ||
57 | + | ||
58 | + local jumpVersion = {} | ||
59 | + local versionTemp = {} | ||
60 | + for version = curVersion + 1, globalCsv.StructVersion do | ||
61 | + local versionData = versionList[version] | ||
62 | + if versionData then | ||
63 | + if versionData[1].vType == VersionType.DoOnly then | ||
64 | + elseif versionData[1].vType == VersionType.Add then | ||
65 | + if versionTemp[versionData[1]] then | ||
66 | + jumpVersion[versionTemp[versionData[1]].version] = true | ||
67 | + versionTemp[versionData[1]].version = version | ||
68 | + for _, param in ipairs(versionData[2] or {}) do | ||
69 | + table.insert(versionTemp[versionData[1]].params, param) | ||
70 | + end | ||
71 | + else | ||
72 | + local params = {} | ||
73 | + for _, param in ipairs(versionData[2] or {}) do | ||
74 | + table.insert(params, param) | ||
75 | + end | ||
76 | + versionTemp[versionData[1]] = {version = version, params = params} | ||
77 | + end | ||
78 | + elseif versionData[1].vType == VersionType.Override then | ||
79 | + if versionTemp[versionData[1]] then | ||
80 | + jumpVersion[versionTemp[versionData[1]].version] = true | ||
81 | + versionTemp[versionData[1]].version = version | ||
82 | + else | ||
83 | + versionTemp[versionData[1]] = {version = version} | ||
84 | + end | ||
85 | + else | ||
86 | + print(">>>>>>> error changeStruct error version Type >>>>> " .. version) | ||
87 | + end | ||
88 | + else | ||
89 | + jumpVersion[version] = true | ||
90 | + end | ||
91 | + end | ||
92 | + | ||
93 | + for version = curVersion + 1, globalCsv.StructVersion do | ||
94 | + if not jumpVersion[version] then | ||
95 | + local versionData = versionList[version] | ||
96 | + if versionData[1].vType == VersionType.DoOnly or versionData[1].vType == VersionType.Override then | ||
97 | + versionData[1](self, versionData[2]) | ||
98 | + elseif versionData[1].vType == VersionType.Add then | ||
99 | + versionData[1](self, versionTemp[versionData[1]].params) | ||
100 | + end | ||
101 | + end | ||
102 | + end | ||
103 | + -- self:setProperty("structVersion", globalCsv.StructVersion) | ||
104 | + end | ||
105 | + | ||
106 | +end | ||
107 | + | ||
108 | +return RoleChangeStruct | ||
0 | \ No newline at end of file | 109 | \ No newline at end of file |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | + | ||
2 | + | ||
3 | +local RolePlugin = {} | ||
4 | + | ||
5 | +function RolePlugin.bind(Role) | ||
6 | + | ||
7 | + function Role:log() | ||
8 | + | ||
9 | + end | ||
10 | + | ||
11 | + function Role:loadAll() | ||
12 | + | ||
13 | + end | ||
14 | + | ||
15 | + function Role:reloadWhenLogin() | ||
16 | + | ||
17 | + end | ||
18 | + | ||
19 | + | ||
20 | +end | ||
21 | + | ||
22 | +return RolePlugin | ||
0 | \ No newline at end of file | 23 | \ No newline at end of file |
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | + | ||
2 | + | ||
3 | +local TaskType = { | ||
4 | + | ||
5 | +} | ||
6 | + | ||
7 | +local RoleTask = {} | ||
8 | + | ||
9 | +function RoleTask.bind(Role) | ||
10 | + | ||
11 | + Role.TaskType = TaskType | ||
12 | + | ||
13 | + function Role:checkTaskEnter(taskType, ...) | ||
14 | + | ||
15 | + end | ||
16 | + | ||
17 | + | ||
18 | + function Role:checkDailyTask() | ||
19 | + end | ||
20 | + | ||
21 | + function Role:checkWeekTask() | ||
22 | + end | ||
23 | + | ||
24 | + function Role:checkAchievTask() | ||
25 | + end | ||
26 | + | ||
27 | +end | ||
28 | + | ||
29 | +return RoleTask | ||
0 | \ No newline at end of file | 30 | \ No newline at end of file |
src/services/agent_ctrl.lua
@@ -153,8 +153,7 @@ function _M:query_agent(fd, uid) | @@ -153,8 +153,7 @@ function _M:query_agent(fd, uid) | ||
153 | -- self.f2u[f] 肯定存在;self.f2e[f]不存在,则说明在线,则需要踢下线 | 153 | -- self.f2u[f] 肯定存在;self.f2e[f]不存在,则说明在线,则需要踢下线 |
154 | if not self.f2e[f] then | 154 | if not self.f2e[f] then |
155 | local head = string.pack("H", actionCodes.Sys_kickdown) | 155 | local head = string.pack("H", actionCodes.Sys_kickdown) |
156 | - -- local bin = MsgPack.pack({body = "该账号已登上其他机器"}) | ||
157 | - local bin = MsgPack.pack({body = "既にこのアカウントを利用している端末があります。"}) | 156 | + local bin = MsgPack.pack({body = "该账号已登上其他机器"}) |
158 | if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end | 157 | if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end |
159 | socket.write(f, netpack.pack(head .. bin)) | 158 | socket.write(f, netpack.pack(head .. bin)) |
160 | skynet.timeout(10, function () | 159 | skynet.timeout(10, function () |
src/services/dbseed.lua
@@ -38,7 +38,7 @@ skynet.start(function () | @@ -38,7 +38,7 @@ skynet.start(function () | ||
38 | 38 | ||
39 | redisproxy = require("shared.redisproxy") | 39 | redisproxy = require("shared.redisproxy") |
40 | 40 | ||
41 | - local new = redisproxy:hsetnx("autoincrement_set", "server_start", os.date("%Y%m%d", skynet.timex())) | 41 | + local new = redisproxy:hsetnx("autoincrement_set", "server_start", os.date("%Y%m%d", skynet.timex())) == 1 |
42 | if not new then | 42 | if not new then |
43 | print("server has been initialized...") | 43 | print("server has been initialized...") |
44 | skynet.exit() | 44 | skynet.exit() |
src/shared/ModelBase.lua
@@ -53,8 +53,8 @@ function ModelBase:load(properties) | @@ -53,8 +53,8 @@ function ModelBase:load(properties) | ||
53 | 53 | ||
54 | if not properties then | 54 | if not properties then |
55 | properties = redisproxy:hgetall(self:getKey()) | 55 | properties = redisproxy:hgetall(self:getKey()) |
56 | + properties = table.arrayToMap(properties) | ||
56 | end | 57 | end |
57 | - | ||
58 | if not next(properties) then return false end | 58 | if not next(properties) then return false end |
59 | 59 | ||
60 | self:setProperties(properties, true) | 60 | self:setProperties(properties, true) |
src/utils/init.lua