From: Elias Fleckenstein Date: Tue, 11 Aug 2020 08:51:38 +0000 (+0200) Subject: Refactoring X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=131d2feb2a318fb37181a206f95952e5c14542f7;p=dragonblocks3d-lua.git Refactoring --- 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 0000000..5cc6e86 Binary files /dev/null and b/modules/Game/ressources/dirt.png differ diff --git a/modules/Game/ressources/stone.png b/modules/Game/ressources/stone.png new file mode 100644 index 0000000..a641ceb Binary files /dev/null and b/modules/Game/ressources/stone.png differ diff --git a/modules/Game/ressources/texture.xcf b/modules/Game/ressources/texture.xcf new file mode 100644 index 0000000..0c09065 Binary files /dev/null and b/modules/Game/ressources/texture.xcf differ diff --git a/modules/Game/src/init.lua b/modules/Game/src/init.lua new file mode 100644 index 0000000..707ce0d --- /dev/null +++ b/modules/Game/src/init.lua @@ -0,0 +1,11 @@ +local ressource_path = Game:get_path() .. "/ressources/" + +BlockSystem:register_block({ + name = "game:stone", + texture_path = ressource_path .. "stone.png", +}) + +BlockSystem:register_block({ + name = "game:dirt", + texture_path = ressource_path .. "dirt.png", +}) diff --git a/modules/MainMenu/dependencies.txt b/modules/MainMenu/dependencies.txt deleted file mode 100644 index 0055b8e..0000000 --- a/modules/MainMenu/dependencies.txt +++ /dev/null @@ -1 +0,0 @@ -RenderEngine diff --git a/modules/MainMenu/src/init.lua b/modules/MainMenu/src/init.lua deleted file mode 100644 index 503e73e..0000000 --- a/modules/MainMenu/src/init.lua +++ /dev/null @@ -1,6 +0,0 @@ -RenderEngine:open_window() -RenderEngine:set_window_title("Dragonblocks 3D - Main Menu") - -RenderEngine:add_render_task() - -MainMenu:init() diff --git a/modules/MapGen/dependencies.txt b/modules/MapGen/dependencies.txt new file mode 100644 index 0000000..93ba72e --- /dev/null +++ b/modules/MapGen/dependencies.txt @@ -0,0 +1 @@ +Game diff --git a/modules/MapGen/src/init.lua b/modules/MapGen/src/init.lua new file mode 100644 index 0000000..86f4087 --- /dev/null +++ b/modules/MapGen/src/init.lua @@ -0,0 +1,19 @@ +local stone = BlockSystem:get_def("game:stone") +local dirt = BlockSystem:get_def("game:dirt") + +local air_probability = 2 +local random_blocks = {stone, dirt} +local random_blocks_num = #random_blocks + air_probability + +function MapGen:generate(chunk) + for x = 0, 15 do + for y = 0, 15 do + for z = 0, 15 do + local block = random_blocks[math.random(random_blocks_num)] + if block then + chunk:add_block(glm.vec3(x, y, z), block) + end + end + end + end +end diff --git a/modules/PlayerSystem/src/init.lua b/modules/PlayerSystem/src/init.lua new file mode 100644 index 0000000..8c7cf17 --- /dev/null +++ b/modules/PlayerSystem/src/init.lua @@ -0,0 +1,9 @@ +PlayerSystem.Player = PlayerSystem:run("player") + +function PlayerSystem:init(gametype) + if gametype == "client" then + PlayerSystem.LocalPlayer = PlayerSystem:run("localplayer") + elseif gametype == "server" then + PlayerSystem.RemotePlayer = PlayerSystem:run("remoteplayer") + end +end diff --git a/modules/PlayerSystem/src/localplayer.lua b/modules/PlayerSystem/src/localplayer.lua new file mode 100644 index 0000000..18465e1 --- /dev/null +++ b/modules/PlayerSystem/src/localplayer.lua @@ -0,0 +1,23 @@ +local LocalPlayer = Dragonblocks.create_class() +table.assign(LocalPlayer, PlayerSystem.Player) + +function LocalPlayer:constructor() + self:init() + self:set_fov(45) + self:add_event_listener("after_set_position", function(event) self:set_position_callback(event) end) +end + +function LocalPlayer:set_position_callback(event) + -- Move Camera & Report to Server +end + +function LocalPlayer:move(vec) + self:set_position(self.pos + vec) +end + +function LocalPlayer:set_fov(fov) + self.fov = fov + RenderEngine.fov = fov +end + +return LocalPlayer diff --git a/modules/PlayerSystem/src/player.lua b/modules/PlayerSystem/src/player.lua new file mode 100644 index 0000000..4bf03b9 --- /dev/null +++ b/modules/PlayerSystem/src/player.lua @@ -0,0 +1,28 @@ +local Player = {} + +function Player:init() + Dragonblocks.create_event_interface(self) + self.pos = glm.vec3(0, 0, 0) +end + +function Player:set_position(pos) + self:fire_event({ + type = "on_set_position", + new_position = pos, + cancel = false + }, function(evt) self:raw_set_position(evt) end) +end + +function Player:raw_set_position(event) + local self = event.origin + if not event.cancel then + self.pos = event.new_position + end + self:fire_event({ + type = "after_set_position", + }) +end + + + +return Player diff --git a/modules/PlayerSystem/src/remoteplayer.lua b/modules/PlayerSystem/src/remoteplayer.lua new file mode 100644 index 0000000..96a81b0 --- /dev/null +++ b/modules/PlayerSystem/src/remoteplayer.lua @@ -0,0 +1,8 @@ +local RemotePlayer = Dragonblocks.create_class() +table.assign(RemotePlayer, PlayerSystem.Player) + +function RemotePlayer:constructor() + self:init() +end + +return RemotePlayer diff --git a/modules/RenderEngine/shaders/fragment.glsl b/modules/RenderEngine/shaders/fragment.glsl new file mode 100755 index 0000000..8169c5d --- /dev/null +++ b/modules/RenderEngine/shaders/fragment.glsl @@ -0,0 +1,12 @@ +#version 330 core + +in vec2 ourTexCoord; + +out vec4 finalColor; + +uniform sampler2D ourTexture; + +void main() +{ + finalColor = texture(ourTexture, ourTexCoord); +} diff --git a/modules/RenderEngine/shaders/vertex.glsl b/modules/RenderEngine/shaders/vertex.glsl new file mode 100755 index 0000000..9c08313 --- /dev/null +++ b/modules/RenderEngine/shaders/vertex.glsl @@ -0,0 +1,16 @@ +#version 330 core + +layout(location = 0) in vec3 aPos; +layout(location = 1) in vec2 aTexCoord; + +out vec2 ourTexCoord; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + gl_Position = projection * view * model * vec4(aPos, 1.0); + ourTexCoord = aTexCoord; +} diff --git a/modules/RenderEngine/src/camera.lua b/modules/RenderEngine/src/camera.lua new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/modules/RenderEngine/src/camera.lua @@ -0,0 +1 @@ + diff --git a/modules/RenderEngine/src/cube.lua b/modules/RenderEngine/src/cube.lua new file mode 100644 index 0000000..ba4e6c9 --- /dev/null +++ b/modules/RenderEngine/src/cube.lua @@ -0,0 +1,43 @@ +return { + -0.5, -0.5, -0.5, 0.0, 0.0, + 0.5, -0.5, -0.5, 1.0, 0.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 0.0, + + -0.5, -0.5, 0.5, 0.0, 0.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + + -0.5, 0.5, 0.5, 1.0, 0.0, + -0.5, 0.5, -0.5, 1.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, 0.5, 1.0, 0.0, + + 0.5, 0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, 0.5, 0.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + + -0.5, -0.5, -0.5, 0.0, 1.0, + 0.5, -0.5, -0.5, 1.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + 0.5, -0.5, 0.5, 1.0, 0.0, + -0.5, -0.5, 0.5, 0.0, 0.0, + -0.5, -0.5, -0.5, 0.0, 1.0, + + -0.5, 0.5, -0.5, 0.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + 0.5, 0.5, 0.5, 1.0, 0.0, + -0.5, 0.5, 0.5, 0.0, 0.0, + -0.5, 0.5, -0.5, 0.0, 1.0 +} diff --git a/modules/RenderEngine/src/init.lua b/modules/RenderEngine/src/init.lua index 0da1656..1d6d888 100644 --- a/modules/RenderEngine/src/init.lua +++ b/modules/RenderEngine/src/init.lua @@ -1,37 +1,80 @@ -glfw.window_hint("context version major", 3) -glfw.window_hint("context version minor", 3) -glfw.window_hint("opengl profile", "core") +RenderEngine:run("camera") +RenderEngine:run("shaders") +RenderEngine:run("textures") +RenderEngine:run("window") -function RenderEngine.reshape(_, width, height) - gl.viewport(0, 0, width, height) +RenderEngine.Mesh = RenderEngine:run("mesh") + +function RenderEngine:init() + self:init_glfw() + self:create_window() + self:init_glew() + self:load_shaders() + self:set_sky("#FFFFFF") + self:add_render_task() end -function RenderEngine:open_window() - self.window = glfw.create_window(50, 50, "Unnamed Window") - glfw.make_context_current(self.window) +function RenderEngine:init_glew() gl.init() - glfw.set_framebuffer_size_callback(self.window, RenderEngine.reshape) end -function RenderEngine:set_window_title(title) - glfw.set_window_title(self.window, title) +function RenderEngine:add_render_task() + Dragonblocks:add_task(function() + + end) +end + +function RenderEngine:render_loop() + self.last_time = glfw.get_time() + repeat + self:render() + --coroutine.yield() + until glfw.window_should_close(self.window) end function RenderEngine:render() - glfw.poll_events() - gl.clear_color(1.0, 0.5, 0.2, 1.0) + local dtime = glfw.get_time() - self.last_time + self.last_time = glfw.get_time() + + gl.clear_color(self.sky) + gl.enable("depth test") gl.clear("color", "depth") + + gl.use_program(self.shaders) + + local view_matrix = glm.translate(self.camera_pos) + local projection_matrix = glm.perspective(math.rad(self.fov), self.window_width / self.window_height, 0.1, 100) + + gl.uniform_matrix4f(self.projection_matix_location, true, projection_matrix) + gl.uniform_matrix4f(self.view_matix_location, true, view_matrix) + + for _, mesh in ipairs(self.Mesh.list) do + mesh:render(dtime) + end + glfw.swap_buffers(self.window) - coroutine.yield() + glfw.poll_events() end -function RenderEngine:render_loop() - repeat RenderEngine:render() - until glfw.window_should_close(self.window) -end -function RenderEngine:add_render_task() - Dragonblocks:add_task(function() RenderEngine:render_loop() end) +--[[ +function RenderEngine:clear_removed_meshes() + local remove_indices = {} + for index, mesh in pairs(self.meshes) do + if mesh.removed then + table.insert(remove_indices, index) + end + end + for i, index in pairs(remove_indices) + table.remove(self.meshes, index - i + 1) + end +end +]]-- +function RenderEngine:set_sky(htmlcolor) + local r, g, b = hex2rgb(htmlcolor) + self.sky = {r, g, b, 1.0} end -RenderEngine:init() +function RenderEngine:set_wireframe(v) + gl.polygon_mode("front and back", (v and "line" or "fill")) +end diff --git a/modules/RenderEngine/src/mesh.lua b/modules/RenderEngine/src/mesh.lua new file mode 100644 index 0000000..446e2b4 --- /dev/null +++ b/modules/RenderEngine/src/mesh.lua @@ -0,0 +1,110 @@ +local Mesh = Dragonblocks.create_class() + +Mesh.EFFECT_GROW = 1 +Mesh.EFFECT_FLYIN = 2 +Mesh.EFFECT_ROTATE = 3 +Mesh.CUBE = RenderEngine:run("cube") +Mesh.list = {} + +function Mesh:set_size(size) + self.size = size +end + +function Mesh:set_pos(pos) + self.pos = pos +end + +function Mesh:set_texture(texture) + self.texture = texture +end + +function Mesh:set_effect(effect, after) + self.effect = effect + self.effect_lasts = + (effect == Mesh.EFFECT_GROW) and RenderEngine.mesh_effect_grow_time + or + (effect == Mesh.EFFECT_FLYIN) and RenderEngine.mesh_effect_flyin_time + self.after_effect = after +end + +function Mesh:add_to_scene() + if self.effect then + self.created = glfw.get_time() + end + table.insert(Mesh.list, self) +end + +function Mesh:remove_from_scene() + local i = table.indexof(Mesh.list, self) + if i then + table.remove(Mesh.list, i) + end +end + +function Mesh:make_cube() + self:apply_vertices(Mesh.CUBE) +end + +function Mesh:apply_vertices(vertices) + self.vao = gl.gen_vertex_arrays(1) + self.vbo = gl.gen_buffers(1) + + gl.bind_vertex_array(self.vao) + + gl.bind_buffer("array", self.vbo) + gl.buffer_data("array", gl.pack("float", vertices), "static draw") + + local fsize = gl.sizeof("float") + + local stride = 5 * fsize + + gl.vertex_attrib_pointer(0, 3, "float", false, stride, 0) + gl.enable_vertex_attrib_array(0) + gl.vertex_attrib_pointer(1, 2, "float", false, stride, 3 * fsize) + gl.enable_vertex_attrib_array(1) + + gl.unbind_buffer("array") + gl.unbind_vertex_array() + + return vao +end + +function Mesh:render(dtime) + local pos, size = self.pos, self.size + + if self.effect then + if self.effect_lasts then + self.effect_lasts = self.effect_lasts - dtime + if self.effect_lasts < 0 then + if self.after_effect then + self:after_effect() + end + self.effect = nil + self.effect_lasts = nil + self.after_effect = nil + goto draw + end + end + if self.effect == Mesh.EFFECT_GROW then + size = size * math.pow(1 - self.effect_lasts / RenderEngine.mesh_effect_grow_time, 1) + elseif self.effect == Mesh.EFFECT_FLYIN then + pos = pos - glm.vec3(0, RenderEngine.mesh_effect_flyin_offset * self.effect_lasts / RenderEngine.mesh_effect_flyin_time, 0) + end + end + + ::draw:: + + local model_matrix = 1 + * glm.translate(pos) + * glm.scale(size) + + gl.uniform_matrix4f(gl.get_uniform_location(RenderEngine.shaders, "model"), true, model_matrix) + gl.active_texture(0) + gl.bind_texture("2d", self.texture) + gl.bind_vertex_array(self.vao) + gl.draw_arrays("triangles", 0, 36) + gl.unbind_vertex_array() + gl.unbind_texture("2d") +end + +return Mesh diff --git a/modules/RenderEngine/src/shaders.lua b/modules/RenderEngine/src/shaders.lua new file mode 100644 index 0000000..f9cb691 --- /dev/null +++ b/modules/RenderEngine/src/shaders.lua @@ -0,0 +1,9 @@ +function RenderEngine:load_shaders() + local path = self:get_path() .. "/shaders/" + local program, vsh, fsh = gl.make_program({vertex = path .. "vertex.glsl", fragment = path .. "fragment.glsl"}) + gl.delete_shaders(vsh, fs) + self.shaders = program + + self.view_matix_location = gl.get_uniform_location(self.shaders, "view") + self.projection_matix_location = gl.get_uniform_location(self.shaders, "projection") +end diff --git a/modules/RenderEngine/src/textures.lua b/modules/RenderEngine/src/textures.lua new file mode 100644 index 0000000..847c9d2 --- /dev/null +++ b/modules/RenderEngine/src/textures.lua @@ -0,0 +1,32 @@ +function RenderEngine:init_texture_args() + local base_filter = (self.bilinear_filter and "linear" or "nearest") + local mipmap = (self.mipmap and " mipmap nearest" or "") + self.texture_min_filter = base_filter .. mipmap + self.texture_mag_filter = base_filter +end + +function RenderEngine:create_texture(path) + local texture = gl.gen_textures(1) + + gl.bind_texture("2d", texture) + gl.texture_parameter("2d", "min filter", self.texture_min_filter) + gl.texture_parameter("2d", "mag filter", self.texture_mag_filter) + gl.texture_parameter("2d", "wrap s", "repeat") + gl.texture_parameter("2d", "wrap t", "repeat") + + local data, width, height, channels = image.load(path) + + if not data then + error("Failed to load texture '" .. path .. "'") + end + + gl.texture_image("2d", 0, "rgb", "rgba", "ubyte", data, width, height) + if self.mipmap then + gl.generate_mipmap("2d") + end + + gl.unbind_texture("2d") + data, width, height, channels = nil + + return texture +end diff --git a/modules/RenderEngine/src/window.lua b/modules/RenderEngine/src/window.lua new file mode 100644 index 0000000..88bfc9c --- /dev/null +++ b/modules/RenderEngine/src/window.lua @@ -0,0 +1,34 @@ +function RenderEngine:framebuffer_size_callback(_, width, height) + gl.viewport(0, 0, width, height) + self:update_window_size(width, height) +end + +function RenderEngine:init_glfw() + glfw.window_hint("context version major", 3) + glfw.window_hint("context version minor", 3) + glfw.window_hint("opengl profile", "core") +end + +function RenderEngine:create_window() + self.window = glfw.create_window(500, 500, "Unnamed Window") + glfw.make_context_current(self.window) + self:update_window_size() + glfw.set_framebuffer_size_callback(self.window, function (...) self:framebuffer_size_callback(...) end) +end + +function RenderEngine:set_window_title(title) + glfw.set_window_title(self.window, title) +end + +function RenderEngine:set_window_pos(x, y) + glfw.set_window_pos(self.window, x, y) +end + +function RenderEngine:set_window_size(width, height) + glfw.set_window_size(self.window, width, height) + self:update_window_size(width, height) +end + +function RenderEngine:update_window_size(width, height) + self.window_width, self.window_height = width, height +end diff --git a/modules/WorldSystem/dependencies.txt b/modules/WorldSystem/dependencies.txt new file mode 100644 index 0000000..06776e7 --- /dev/null +++ b/modules/WorldSystem/dependencies.txt @@ -0,0 +1 @@ +MapGen diff --git a/modules/WorldSystem/src/block.lua b/modules/WorldSystem/src/block.lua new file mode 100644 index 0000000..2c67a27 --- /dev/null +++ b/modules/WorldSystem/src/block.lua @@ -0,0 +1,7 @@ +local Block = Dragonblocks.create_class() + +function Block:constructor(def, pos) + self.def, self.pos = def, pos +end + +return Block diff --git a/modules/WorldSystem/src/chunk.lua b/modules/WorldSystem/src/chunk.lua new file mode 100644 index 0000000..1d68249 --- /dev/null +++ b/modules/WorldSystem/src/chunk.lua @@ -0,0 +1,31 @@ +local Chunk = Dragonblocks.create_class() + +local size = 16 +local size_squared = math.pow(size, 2) + +function Chunk:constructor() + self.blocks = {} + MapGen:generate(self) + if Client then + Client.graphics:create_chunk_meshes(self) + end +end + +function Chunk:get_pos_hash(pos) + return pos.x + size * pos.y + size_squared * pos.z +end + +function Chunk:add_block(pos, def) + local block = WorldSystem.Block(def, pos) + self.blocks[self:get_pos_hash(pos)] = block +end + +function Chunk:remove_block(pos) + self.blocks[self:get_pos_hash(pos)] = nil +end + +function Chunk:get_block(pos) + return self.blocks[self:get_pos_hash(pos)] +end + +return Chunk diff --git a/modules/WorldSystem/src/init.lua b/modules/WorldSystem/src/init.lua new file mode 100644 index 0000000..d3ffdcc --- /dev/null +++ b/modules/WorldSystem/src/init.lua @@ -0,0 +1,4 @@ +WorldSystem.World = WorldSystem:run("world") +WorldSystem.Map = WorldSystem:run("map") +WorldSystem.Chunk = WorldSystem:run("chunk") +WorldSystem.Block = WorldSystem:run("block") diff --git a/modules/WorldSystem/src/map.lua b/modules/WorldSystem/src/map.lua new file mode 100644 index 0000000..44d7490 --- /dev/null +++ b/modules/WorldSystem/src/map.lua @@ -0,0 +1,7 @@ +local Map = Dragonblocks.create_class() + +function Map:constructor() + self.chunk = WorldSystem.Chunk() +end + +return Map diff --git a/modules/WorldSystem/src/world.lua b/modules/WorldSystem/src/world.lua new file mode 100644 index 0000000..6bad913 --- /dev/null +++ b/modules/WorldSystem/src/world.lua @@ -0,0 +1,7 @@ +local World = Dragonblocks.create_class() + +function World:constructor() + self.map = WorldSystem.Map() +end + +return World diff --git a/src/class.lua b/src/class.lua index f424d73..5b2c20f 100644 --- a/src/class.lua +++ b/src/class.lua @@ -1,21 +1,14 @@ -local class = {} - -local instance_metatable = { - __index = function(t, k) - if k == "_call" then return end - local f = rawget(t._class, k) - if type(f) == "function" then - return f +function Dragonblocks.create_class() + local class = self or {} + setmetatable(class, { + __call = function(_, ...) + local o = {} + setmetatable(o, {__index = class}) + if o.constructor then + o:constructor(...) + end + return o end - end -} - -function class:_call(...) - local o = {class = self} - setmetatable(o, instance_metatable) - if o.constructor then - o:constructor(table.unpack(...)) - end -end - -return class + }) + return class +end diff --git a/src/event_interface.lua b/src/event_interface.lua deleted file mode 100644 index cb23a2d..0000000 --- a/src/event_interface.lua +++ /dev/null @@ -1,44 +0,0 @@ -local event_interface = {} - -function event_interface:init() - assert(self._task_manager) - self:clear_event_listeners() -end - -function event_interface:fire_event(event, callback) - event = event or {} - event.origin = self - local listeners = self._event_listeners[eventtype] - if listeners then - self._task_manager:add_task(function() - for _, listener in ipairs(listeners) do - listener(event) - coroutine.yield() - end - callback(event) - end) - end -end - -function event_interface: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) - local listeners = self._event_listeners[eventtype] - if listeners then - for k, listener in ipairs(listeners) do - if listener == eventlistener then - table.remove(k) - return self:removeEventListener(eventtype, eventlistener) - end - end - end -end - -function event_interface:clear_event_listeners() - self._event_listeners = {} -end - -return event_interface diff --git a/src/events.lua b/src/events.lua new file mode 100644 index 0000000..312a9b3 --- /dev/null +++ b/src/events.lua @@ -0,0 +1,43 @@ +local events = {} + +function events:fire_event(event, callback) + event = event or {} + event.origin = self + local listeners = self._event_listeners[eventtype] + if listeners and #listeners > 0 then + for _, listener in ipairs(listeners) do + listener(event) + end + end + if callback then + callback(event) + end +end + +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 events:remove_event_listener(eventtype, eventlistener) + local listeners = self._event_listeners[eventtype] + if listeners then + for k, listener in ipairs(listeners) do + if listener == eventlistener then + table.remove(k) + return self:removeEventListener(eventtype, eventlistener) + end + end + end +end + +function events:clear_event_listeners() + self._event_listeners = {} +end + +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/serialisation.lua b/src/serialisation.lua new file mode 100644 index 0000000..a1877ed --- /dev/null +++ b/src/serialisation.lua @@ -0,0 +1,48 @@ +function Dragonblocks:serialize() + local data = "{" + for k, v in pairs(self) do + local kdata, vdata + local ktype, vtype = type(k), type(v) + local serialize_pair = true + if ktype == "number" then + kdata = "[" .. k .. "]" + elseif ktype == "string" then + if k:sub(1, 1) == "_" then + serialize_pair = false + else + kdata = "[\"" .. k .. "\"]" + end + else + serialize_pair = false + end + if vtype == "table" then + vdata = serializer.serialize(v) + elseif vtype == "string" then + vdata = "\"" .. v .. "\"" + elseif vtype == "number" then + vdata = v + elseif vtype == "boolean" then + vdata = v and "true" or "false" + else + serialize_pair = false + end + if serialize_pair then + data = data .. kdata .. "=" .. vdata .. "," + end + end + return data .. "}" +end + +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 + table.assign(self, raw) + end + return self +end diff --git a/src/serializer.lua b/src/serializer.lua deleted file mode 100644 index 582e927..0000000 --- a/src/serializer.lua +++ /dev/null @@ -1,49 +0,0 @@ -local serializer = {} - -function serializer:serialize() - local data = "{" - for k, v in pairs(self) do - local kdata, vdata - local ktype, vtype = type(k), type(v) - local serialize_pair = true - if ktype == "number" then - kdata = "[" .. k .. "]" - elseif ktype == "string" then - if k:sub(1, 1) == "_" then - serialize_pair = false - else - kdata = "[\"" .. k .. "\"]" - end - else - serialize_pair = false - end - if vtype == "table" then - vdata = serializer.serialize(v) - elseif vtype == "string" then - vdata = "\"" .. v .. "\"" - elseif vtype == "number" then - vdata = v - elseif vtype == "boolean" then - vdata = v and "true" or "false" - else - serialize_pair = false - end - if serialize_pair then - data = data .. kdata .. "=" .. vdata .. "," - end - end - return data .. "}" -end - -function serializer:deserialize(raw) - raw = "return" .. (raw or "") - 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 - end -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/indexof.lua b/util/indexof.lua deleted file mode 100644 index 24fbead..0000000 --- a/util/indexof.lua +++ /dev/null @@ -1,8 +0,0 @@ -function table.indexof(list, val) - for i, v in ipairs(list) do - if v == val then - return i - end - end - return -1 -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/split.lua deleted file mode 100644 index f0bc8af..0000000 --- a/util/split.lua +++ /dev/null @@ -1,23 +0,0 @@ -function string.split(str, delim, include_empty, max_splits, sep_is_pattern) - delim = delim or "," - max_splits = max_splits or -2 - local items = {} - local pos, len = 1, #str - local plain = not sep_is_pattern - max_splits = max_splits + 1 - repeat - local np, npe = string.find(str, delim, pos, plain) - np, npe = (np or (len+1)), (npe or (len+1)) - if (not np) or (max_splits == 1) then - np = len + 1 - npe = np - end - local s = string.sub(str, pos, np - 1) - if include_empty or (s ~= "") then - max_splits = max_splits - 1 - items[#items + 1] = s - end - pos = npe + 1 - until (max_splits == 0) or (pos > (len + 1)) - return items -end diff --git a/util/string_split.lua b/util/string_split.lua new file mode 100644 index 0000000..fb6dd7d --- /dev/null +++ b/util/string_split.lua @@ -0,0 +1,23 @@ +return function(str, delim, include_empty, max_splits, sep_is_pattern) + delim = delim or "," + max_splits = max_splits or -2 + local items = {} + local pos, len = 1, #str + local plain = not sep_is_pattern + max_splits = max_splits + 1 + repeat + local np, npe = string.find(str, delim, pos, plain) + np, npe = (np or (len+1)), (npe or (len+1)) + if (not np) or (max_splits == 1) then + np = len + 1 + npe = np + end + local s = string.sub(str, pos, np - 1) + if include_empty or (s ~= "") then + max_splits = max_splits - 1 + items[#items + 1] = s + end + pos = npe + 1 + until (max_splits == 0) or (pos > (len + 1)) + return items +end 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/table_indexof.lua b/util/table_indexof.lua new file mode 100644 index 0000000..ee9410a --- /dev/null +++ b/util/table_indexof.lua @@ -0,0 +1,8 @@ +return function(list, val) + for i, v in ipairs(list) do + if v == val then + return i + end + end + return -1 +end