From 131d2feb2a318fb37181a206f95952e5c14542f7 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Tue, 11 Aug 2020 10:51:38 +0200 Subject: [PATCH] Refactoring --- .gitmodules | 9 ++ README | 2 +- deps/moonassimp | 1 + deps/moonglmath | 1 + deps/moonimage | 1 + init.lua | 16 ++- modules/BlockSystem/src/init.lua | 18 ++++ modules/Client/dependencies.txt | 3 + modules/Client/src/graphics.lua | 44 +++++++++ modules/Client/src/init.lua | 7 ++ modules/Game/dependencies.txt | 1 + modules/Game/ressources/dirt.png | Bin 0 -> 676 bytes modules/Game/ressources/stone.png | Bin 0 -> 528 bytes modules/Game/ressources/texture.xcf | Bin 0 -> 1462 bytes modules/Game/src/init.lua | 11 +++ modules/MainMenu/dependencies.txt | 1 - modules/MainMenu/src/init.lua | 6 -- modules/MapGen/dependencies.txt | 1 + modules/MapGen/src/init.lua | 19 ++++ modules/PlayerSystem/src/init.lua | 9 ++ modules/PlayerSystem/src/localplayer.lua | 23 +++++ modules/PlayerSystem/src/player.lua | 28 ++++++ modules/PlayerSystem/src/remoteplayer.lua | 8 ++ modules/RenderEngine/shaders/fragment.glsl | 12 +++ modules/RenderEngine/shaders/vertex.glsl | 16 +++ modules/RenderEngine/src/camera.lua | 1 + modules/RenderEngine/src/cube.lua | 43 ++++++++ modules/RenderEngine/src/init.lua | 85 ++++++++++++---- modules/RenderEngine/src/mesh.lua | 110 +++++++++++++++++++++ modules/RenderEngine/src/shaders.lua | 9 ++ modules/RenderEngine/src/textures.lua | 32 ++++++ modules/RenderEngine/src/window.lua | 34 +++++++ modules/WorldSystem/dependencies.txt | 1 + modules/WorldSystem/src/block.lua | 7 ++ modules/WorldSystem/src/chunk.lua | 31 ++++++ modules/WorldSystem/src/init.lua | 4 + modules/WorldSystem/src/map.lua | 7 ++ modules/WorldSystem/src/world.lua | 7 ++ src/class.lua | 33 +++---- src/{event_interface.lua => events.lua} | 37 ++++--- src/init.lua | 20 ++-- src/module_manager.lua | 76 -------------- src/modulemgr.lua | 64 ++++++++++++ src/{serializer.lua => serialisation.lua} | 19 ++-- src/task_manager.lua | 34 ------- src/taskmgr.lua | 24 +++++ util/hex2rgb.lua | 8 ++ util/objectmgr.lua | 39 -------- util/{split.lua => string_split.lua} | 2 +- util/table_assign.lua | 5 + util/{indexof.lua => table_indexof.lua} | 2 +- 51 files changed, 722 insertions(+), 249 deletions(-) create mode 160000 deps/moonassimp create mode 160000 deps/moonglmath create mode 160000 deps/moonimage create mode 100644 modules/BlockSystem/src/init.lua create mode 100644 modules/Client/dependencies.txt create mode 100644 modules/Client/src/graphics.lua create mode 100644 modules/Client/src/init.lua create mode 100644 modules/Game/dependencies.txt create mode 100644 modules/Game/ressources/dirt.png create mode 100644 modules/Game/ressources/stone.png create mode 100644 modules/Game/ressources/texture.xcf create mode 100644 modules/Game/src/init.lua delete mode 100644 modules/MainMenu/dependencies.txt delete mode 100644 modules/MainMenu/src/init.lua create mode 100644 modules/MapGen/dependencies.txt create mode 100644 modules/MapGen/src/init.lua create mode 100644 modules/PlayerSystem/src/init.lua create mode 100644 modules/PlayerSystem/src/localplayer.lua create mode 100644 modules/PlayerSystem/src/player.lua create mode 100644 modules/PlayerSystem/src/remoteplayer.lua create mode 100755 modules/RenderEngine/shaders/fragment.glsl create mode 100755 modules/RenderEngine/shaders/vertex.glsl create mode 100644 modules/RenderEngine/src/camera.lua create mode 100644 modules/RenderEngine/src/cube.lua create mode 100644 modules/RenderEngine/src/mesh.lua create mode 100644 modules/RenderEngine/src/shaders.lua create mode 100644 modules/RenderEngine/src/textures.lua create mode 100644 modules/RenderEngine/src/window.lua create mode 100644 modules/WorldSystem/dependencies.txt create mode 100644 modules/WorldSystem/src/block.lua create mode 100644 modules/WorldSystem/src/chunk.lua create mode 100644 modules/WorldSystem/src/init.lua create mode 100644 modules/WorldSystem/src/map.lua create mode 100644 modules/WorldSystem/src/world.lua rename src/{event_interface.lua => events.lua} (51%) delete mode 100644 src/module_manager.lua create mode 100644 src/modulemgr.lua rename src/{serializer.lua => serialisation.lua} (81%) delete mode 100644 src/task_manager.lua create mode 100644 src/taskmgr.lua create mode 100644 util/hex2rgb.lua delete mode 100644 util/objectmgr.lua rename util/{split.lua => string_split.lua} (87%) create mode 100644 util/table_assign.lua rename util/{indexof.lua => table_indexof.lua} (71%) diff --git a/.gitmodules b/.gitmodules index 713f6c8..a6c4f67 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,12 @@ [submodule "moonglfw"] path = deps/moonglfw url = https://github.com/stetre/moonglfw +[submodule "moonglmath"] + path = deps/moonglmath + url = https://github.com/stetre/moonglmath +[submodule "moonassimp"] + path = deps/moonassimp + url = https://github.com/stetre/moonassimp +[submodule "moonimage"] + path = deps/moonimage + url = https://github.com/stetre/moonimage diff --git a/README b/README index 7792d15..1115293 100644 --- a/README +++ b/README @@ -4,4 +4,4 @@ $ luarocks install lsqlite3 $ luarocks install luasocket $ luarocks install luafilesystem -Build moongl and moonglfw: See build README.md in deps/moongl and deps/moonglfw +Build moongl, moonglfw, moonglmath, moonimage and moonassimp: Only needed for running the client, see build instructions in deps/*/README.md diff --git a/deps/moonassimp b/deps/moonassimp new file mode 160000 index 0000000..9168e06 --- /dev/null +++ b/deps/moonassimp @@ -0,0 +1 @@ +Subproject commit 9168e065e17d164d2c7ddcb691fec23b47362fc1 diff --git a/deps/moonglmath b/deps/moonglmath new file mode 160000 index 0000000..088ad95 --- /dev/null +++ b/deps/moonglmath @@ -0,0 +1 @@ +Subproject commit 088ad95710be4325dd368df19b5323e2837c4059 diff --git a/deps/moonimage b/deps/moonimage new file mode 160000 index 0000000..1879986 --- /dev/null +++ b/deps/moonimage @@ -0,0 +1 @@ +Subproject commit 18799868803a424bff4b95b79123f1d9c28c9483 diff --git a/init.lua b/init.lua index 5edef9f..da40c8a 100755 --- a/init.lua +++ b/init.lua @@ -4,16 +4,12 @@ socket = require("socket") lsqlite3 = require("lsqlite3") gl = require("moongl") glfw = require("moonglfw") -require("util/objectmgr") -require("util/split") -require("util/indexof") - -Dragonblocks = ObjectMgr.create() +image = require("moonimage") +glm = require("moonglmath") +string.split = require("util/string_split") +table.indexof = require("util/table_indexof") +table.assign = require("util/table_assign") +hex2rgb = require("util/hex2rgb") require("src/init") -Dragonblocks:init() - -Dragonblocks:start_module(arg[1]) - -Dragonblocks:start_tasks() diff --git a/modules/BlockSystem/src/init.lua b/modules/BlockSystem/src/init.lua new file mode 100644 index 0000000..0dcd48d --- /dev/null +++ b/modules/BlockSystem/src/init.lua @@ -0,0 +1,18 @@ +BlockSystem.blocks = {} + +function BlockSystem:register_block(def) + local id = table.insert(self.blocks, def) + def.id = id + self.blocks[def.name] = def +end + +function BlockSystem:get_def(key) + return self.blocks[key] +end + +function BlockSystem:init_textures() + RenderEngine:init_texture_args() + for _, def in ipairs(self.blocks) do + def.texture = RenderEngine:create_texture(def.texture_path) + end +end diff --git a/modules/Client/dependencies.txt b/modules/Client/dependencies.txt new file mode 100644 index 0000000..30cb2e1 --- /dev/null +++ b/modules/Client/dependencies.txt @@ -0,0 +1,3 @@ +RenderEngine +WorldSystem +PlayerSystem diff --git a/modules/Client/src/graphics.lua b/modules/Client/src/graphics.lua new file mode 100644 index 0000000..1dc1e42 --- /dev/null +++ b/modules/Client/src/graphics.lua @@ -0,0 +1,44 @@ +local graphics = {} + +function graphics:init() + RenderEngine:init() + + RenderEngine.bininear_filter = false + RenderEngine.mipmap = false + RenderEngine.camera_pos = glm.vec3(-8, -18, -40) + RenderEngine.fov = 45 + RenderEngine.mesh_effect_grow_time = 0.25 + RenderEngine.mesh_effect_flyin_time = 1 + RenderEngine.mesh_effect_flyin_offset = 20 + --RenderEngine.mesh_effect_rotate_speed = + + RenderEngine:set_wireframe(false) + + RenderEngine:set_window_title("Dragonblocks 3D") + RenderEngine:set_window_size(1250, 750) + RenderEngine:set_window_pos(50, 50) + + RenderEngine:set_sky("#87CEEB") + + BlockSystem:init_textures() +end + +function graphics:create_chunk_meshes(chunk) + for _, block in pairs(chunk.blocks) do + self:create_block_mesh(block, true) + end +end + +function graphics:create_block_mesh(block, grow) + local mesh = RenderEngine.Mesh() + mesh:set_pos(block.pos) + mesh:set_size(glm.vec3(1, 1, 1)) + mesh:set_texture(block.def.texture) + mesh:make_cube() + if grow then + mesh:set_effect(RenderEngine.Mesh.EFFECT_GROW) + end + mesh:add_to_scene() +end + +return graphics diff --git a/modules/Client/src/init.lua b/modules/Client/src/init.lua new file mode 100644 index 0000000..0dbaa46 --- /dev/null +++ b/modules/Client/src/init.lua @@ -0,0 +1,7 @@ +Client.graphics = Client:run("graphics") + +Client.graphics:init() + +Client.map = WorldSystem.Map() + +RenderEngine:render_loop() diff --git a/modules/Game/dependencies.txt b/modules/Game/dependencies.txt new file mode 100644 index 0000000..bbea3c7 --- /dev/null +++ b/modules/Game/dependencies.txt @@ -0,0 +1 @@ +BlockSystem diff --git a/modules/Game/ressources/dirt.png b/modules/Game/ressources/dirt.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc6e8639556cfa826aa5e5079ff318de48de4ff GIT binary patch literal 676 zcmV;V0$crwP)e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00In2L_t(I%Po>yj@(!bLysQ! z+STbK8<=&>Rxr!y0Ph{RPHLy0H=RE05&|DPxC zRs8&%D1xeh82;b$KoLZsX(F3H$AyY8hv7h7#lAU6Qc=8CF{kp_2U@_DiJOq!0Aw~R znye-ZqTsj!1kNg+=f%1T0n`+R3$G){Y@X+Z2o%Np462*%Mpal*P_Vf(r*f^p-3+?u zEM5^rHBkWwuEzUJ)RfBP`^Uzg_oDOm=gPu|8LwCH<8xBaMn#Ay-Vr=D~u9)5PUV(}t(!9>Vvx+$e?#k%qN?4iD zjXQ`anMGF7S5YPGyYu@M2;hRS@5Wk1H*CYW7E~2<15E+boIn^;8Dp|}QZ2Xu(n3|^ zaufHVG=cyk0QX)H$R;#6j^g9PP&46-xSOSdni5~v5q7Uf(?iGT^+O?C5_lbKE2 zKI3MJ&>S?X%F1F6MZ_3WaaFFBe zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00DSOL_t(I%Vm>Mk{mGzL!V?% zZnmk){V$W+HYgu<_e^E|<1z*WNa)Y+uYiE?+!CbE`~4fhpMHobo9@uvaJwrz58Gx7 zdvKpS1rn14Sqw}P(8hou>8W9@0zzkpTf5NN+2|dxjcwA6#~|G&L9j&vzvdu_bkiMX z!$$2zRj4W?QC0jr;p$Ug_B~TY5YxMb&ixsL-W5pCPysv!vYD0$!V;0OV6BC?0O zC+N%tfNr{*Ip*ZL7OOUD*htl(YGHeqY5_jzrmA@jGrzBkac7OdA{{&j)}A&JLr{1B zT?`vZ%po6UIRXlm=K4OvBuHl6KETVSx>;4sImc<~t+k10Tbb@8XUV$lrJq`h3UDpo*TiQvqcVML+PW}O9j|S#d S1&MJ00000{$nE8U4uByze>c$cN1)33)Sqx|7;b}yIo%dcv= zzPUO)?GF08gURqnb+~O>JJZ>tlYTxOpA3&~U)ebx^u{OSNxrk$b|-_o-F)xoz0EoY z>~BrC;d=KR*V>-{KTy}R>HThRI2z>pbuK6$ou}ODb{~v}vwS$}-Rn=)e|&sA?aw|J zsNVloebW5fRe5ME^Q>{GVLdNp_p0mmej7~24@MgbbuzjxKy*@T$ajhlp5TjVLR7D= zm$w*O>-z@&wt=rSaNfXI8~BR`zSh8B0&Bi{T?EkF8vmy)#@6~#@fr*J4-MS>+n}zO zeNiLqH5D2c%f9-wZ@#rn^~+j+DJ{zsvvM6XHnL8(dR10cnNo}*F(nZqiID?Gj$+e1 z!YItvufs)e++P%ggZF``E$>n(49~#gHY%agk_iic=)9Fh;xe@5PmUx~YWOOXg)f|I z`;U>Ss%%;cNhhtOvho@ggj7bMK#WSFcqB$S>5i?;oh7uEtgQ6-Hc3iVg 0 then + for _, listener in ipairs(listeners) do + listener(event) + end + end + if callback then + callback(event) end end -function event_interface:add_event_listener(eventtype, eventlistener) +function events:add_event_listener(eventtype, eventlistener) self._event_listeners[eventtype] = self._event_listeners[eventtype] or {} table.insert(self._event_listeners[eventtype], eventlistener) end -function event_interface:remove_event_listener(eventtype, eventlistener) +function events:remove_event_listener(eventtype, eventlistener) local listeners = self._event_listeners[eventtype] if listeners then for k, listener in ipairs(listeners) do @@ -37,8 +31,13 @@ function event_interface:remove_event_listener(eventtype, eventlistener) end end -function event_interface:clear_event_listeners() +function events:clear_event_listeners() self._event_listeners = {} end -return event_interface +function Dragonblocks:create_event_interface() + self = self or {} + table.assign(self, events) + self:clear_event_listeners() + return self +end diff --git a/src/init.lua b/src/init.lua index a036f98..b94e151 100644 --- a/src/init.lua +++ b/src/init.lua @@ -1,13 +1,13 @@ -Dragonblocks.event_interface = require("src/event_interface") -Dragonblocks.class = require("src/class") -Dragonblocks.task_manager = require("src/task_manager") -Dragonblocks.module_manager = require("src/module_manager") -Dragonblocks.serializer = require("src/serializer") +Dragonblocks = {} -Dragonblocks:add_proto(Dragonblocks.module_manager) -Dragonblocks:add_proto(Dragonblocks.task_manager) -Dragonblocks:add_proto(Dragonblocks.serializer) - -Dragonblocks:register_event_interface(Dragonblocks) +require("src/class") +require("src/events") +require("src/taskmgr") +require("src/modulemgr") +require("src/serialisation") print("Started Dragonblocks core") + +Dragonblocks:read_modules() +Dragonblocks:start_module(arg[1]) +Dragonblocks:start_tasks() diff --git a/src/module_manager.lua b/src/module_manager.lua deleted file mode 100644 index dee4720..0000000 --- a/src/module_manager.lua +++ /dev/null @@ -1,76 +0,0 @@ -local module_ref = {} - -function module_ref:preinit() - self._dependencies = {} - self._started = false - local depfile = io.open(self._path .. "/dependencies.txt") - if depfile then - local data = depfile:read() - depfile:close() - self._dependencies = data:split("\n") - end - -end - -function module_ref:init() - self._started = true -end - -function module_ref:run_script(s) - return require(self._path .. "src/" .. s) -end - -function module_ref:start() - _G[self._name] = self - self:run_script("init") - print("Started module " .. self._name) -end - -function module_ref:get_path() - return self._path -end - -function module_ref:get_data_path() - local p = self._data_path - if not lfs.attributes(p, "mode") then - lfs.mkdir(p) - end -end - -local module_manager = {} - -module_manager.module_path = "modules/" -module_manager.data_path = "data/" - -function module_manager:init() - if not lfs.attributes(self.data_path, "mode") then - lfs.mkdir(self.data_path) - end - self._modules = {} - for modulename in lfs.dir(self.module_path) do - if modulename:sub(1, 1) ~= "." then - local m = ObjectMgr.create() - m._name = modulename - m._path = self.module_path .. modulename .. "/" - m._data_path = self.data_path .. modulename .. "/" - m:add_proto(module_ref) - m:preinit() - self._modules[modulename] = m - end - end -end - -function module_manager:start_module(name) - local m = self._modules[name] - if not m then - error("Module '" .. name .. "' not found.") - elseif m._started then - return - end - for _, dep in ipairs(m._dependencies) do - self:start_module(dep) - end - m:start() -end - -return module_manager diff --git a/src/modulemgr.lua b/src/modulemgr.lua new file mode 100644 index 0000000..7aaa1cf --- /dev/null +++ b/src/modulemgr.lua @@ -0,0 +1,64 @@ +local Module = Dragonblocks.create_class() + +function Module:constructor(name) + self._name = name + self._dependencies = {} + self._started = false + local depfile = io.open(self:get_path() .. "/dependencies.txt") + if depfile then + local data = depfile:read("*a") + depfile:close() + self._dependencies = data:split("\n") + end +end + +function Module:run(s) + return require(self:get_path() .. "/src/" .. s) +end + +function Module:start() + _G[self._name] = self + self:run("init") + self._started = true + print("Started module " .. self._name) +end + +function Module:get_path() + return "modules/" .. self._name +end + +function Module:get_data_path() + local p = "data/" .. self._name + if not lfs.attributes(p, "mode") then + lfs.mkdir(p) + end + return p +end + +function Dragonblocks:read_modules() + if not lfs.attributes("data", "mode") then + lfs.mkdir(self.data_path) + end + self.modules = {} + for modulename in lfs.dir("modules") do + if modulename:sub(1, 1) ~= "." then + local m = Module(modulename) + self.modules[modulename] = m + end + end +end + +function Dragonblocks:start_module(name) + local m = self.modules[name] + if not m then + error("Module '" .. name .. "' not found.") + elseif m._started then + return + end + for _, dep in ipairs(m._dependencies) do + self:start_module(dep) + end + m:start() +end + +return module_manager diff --git a/src/serializer.lua b/src/serialisation.lua similarity index 81% rename from src/serializer.lua rename to src/serialisation.lua index 582e927..a1877ed 100644 --- a/src/serializer.lua +++ b/src/serialisation.lua @@ -1,6 +1,4 @@ -local serializer = {} - -function serializer:serialize() +function Dragonblocks:serialize() local data = "{" for k, v in pairs(self) do local kdata, vdata @@ -35,15 +33,16 @@ function serializer:serialize() return data .. "}" end -function serializer:deserialize(raw) - raw = "return" .. (raw or "") +function Dragonblocks:deserialize(raw) + if not raw then + raw = self + self = {} + end + raw = "return" .. raw local f = loadstring(raw) local data = f and f() if type(data) == "table" then - for k, v in pairs(data) do - self[k] = v - end + table.assign(self, raw) end + return self end - -return serializer diff --git a/src/task_manager.lua b/src/task_manager.lua deleted file mode 100644 index 23a4ead..0000000 --- a/src/task_manager.lua +++ /dev/null @@ -1,34 +0,0 @@ -local task_manager = {} - -function task_manager:init() - self._tasks = {} -end - -function task_manager:add_task(f) - local t = coroutine.create(f) - table.insert(self._tasks, t) - return t -end - -function task_manager:step() - local t_start = socket.gettime() - local tasks = self._tasks - self._tasks = {} - for _, t in ipairs(tasks) do - if coroutine.resume(t) then - table.insert(self._tasks, t) - end - end - self.tps = 1 / (socket.gettime() - t_start) -end - -function task_manager:start_tasks() - repeat self:step() - until #self._tasks == 0 -end - -function task_manager:register_event_interface(e) - e._task_manager = self -end - -return task_manager diff --git a/src/taskmgr.lua b/src/taskmgr.lua new file mode 100644 index 0000000..7792718 --- /dev/null +++ b/src/taskmgr.lua @@ -0,0 +1,24 @@ +Dragonblocks.tasks = {} + +function Dragonblocks:add_task(f) + local t = coroutine.create(f) + table.insert(self.tasks, t) + return t +end + +function Dragonblocks:step() + local t_start = socket.gettime() + local tasks = self.tasks + self.tasks = {} + for _, t in ipairs(tasks) do + if coroutine.resume(t) then + table.insert(self.tasks, t) + end + end + self.tps = 1 / (socket.gettime() - t_start) +end + +function Dragonblocks:start_tasks() + repeat self:step() + until #self.tasks == 0 +end diff --git a/util/hex2rgb.lua b/util/hex2rgb.lua new file mode 100644 index 0000000..15072fb --- /dev/null +++ b/util/hex2rgb.lua @@ -0,0 +1,8 @@ +return function(hex) + local hex = hex:gsub("#","") + if hex:len() == 3 then + return (tonumber("0x"..hex:sub(1,1))*17)/255, (tonumber("0x"..hex:sub(2,2))*17)/255, (tonumber("0x"..hex:sub(3,3))*17)/255 + else + return tonumber("0x"..hex:sub(1,2))/255, tonumber("0x"..hex:sub(3,4))/255, tonumber("0x"..hex:sub(5,6))/255 + end +end diff --git a/util/objectmgr.lua b/util/objectmgr.lua deleted file mode 100644 index 3140915..0000000 --- a/util/objectmgr.lua +++ /dev/null @@ -1,39 +0,0 @@ -local ObjectRef = {} - -function ObjectRef:init() - for _, p in ipairs(self._proto) do - if p ~= ObjectRef and p.init then - p.init(self) - end - end -end - -function ObjectRef:add_proto(p) - table.insert(self._proto, p) -end - -ObjectMgr = {} - -ObjectMgr.metatable = { - __index = function(t, k) - for _, p in ipairs(t._proto) do - local v = p[k] - if v then - return v - end - end - end, - __call = function(t, ...) - return t:_call() - end, - __tostring = function(t) - return t.serialize and t:serialize() or "" - end, -} - -function ObjectMgr.create() - local o = {} - o._proto = {ObjectRef} - setmetatable(o, ObjectMgr.metatable) - return o -end diff --git a/util/split.lua b/util/string_split.lua similarity index 87% rename from util/split.lua rename to util/string_split.lua index f0bc8af..fb6dd7d 100644 --- a/util/split.lua +++ b/util/string_split.lua @@ -1,4 +1,4 @@ -function string.split(str, delim, include_empty, max_splits, sep_is_pattern) +return function(str, delim, include_empty, max_splits, sep_is_pattern) delim = delim or "," max_splits = max_splits or -2 local items = {} diff --git a/util/table_assign.lua b/util/table_assign.lua new file mode 100644 index 0000000..f14a8f5 --- /dev/null +++ b/util/table_assign.lua @@ -0,0 +1,5 @@ +return function(t, o) + for k, v in pairs(o) do + t[k] = v + end +end diff --git a/util/indexof.lua b/util/table_indexof.lua similarity index 71% rename from util/indexof.lua rename to util/table_indexof.lua index 24fbead..ee9410a 100644 --- a/util/indexof.lua +++ b/util/table_indexof.lua @@ -1,4 +1,4 @@ -function table.indexof(list, val) +return function(list, val) for i, v in ipairs(list) do if v == val then return i -- 2.44.0