Refactoring
parent
5af7069ac5
commit
131d2feb2a
|
@ -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
|
||||
|
|
2
README
2
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
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 9168e065e17d164d2c7ddcb691fec23b47362fc1
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 088ad95710be4325dd368df19b5323e2837c4059
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 18799868803a424bff4b95b79123f1d9c28c9483
|
16
init.lua
16
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()
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,3 @@
|
|||
RenderEngine
|
||||
WorldSystem
|
||||
PlayerSystem
|
|
@ -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
|
|
@ -0,0 +1,7 @@
|
|||
Client.graphics = Client:run("graphics")
|
||||
|
||||
Client.graphics:init()
|
||||
|
||||
Client.map = WorldSystem.Map()
|
||||
|
||||
RenderEngine:render_loop()
|
|
@ -0,0 +1 @@
|
|||
BlockSystem
|
Binary file not shown.
After Width: | Height: | Size: 676 B |
Binary file not shown.
After Width: | Height: | Size: 528 B |
Binary file not shown.
|
@ -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",
|
||||
})
|
|
@ -1 +0,0 @@
|
|||
RenderEngine
|
|
@ -1,6 +0,0 @@
|
|||
RenderEngine:open_window()
|
||||
RenderEngine:set_window_title("Dragonblocks 3D - Main Menu")
|
||||
|
||||
RenderEngine:add_render_task()
|
||||
|
||||
MainMenu:init()
|
|
@ -0,0 +1 @@
|
|||
Game
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,8 @@
|
|||
local RemotePlayer = Dragonblocks.create_class()
|
||||
table.assign(RemotePlayer, PlayerSystem.Player)
|
||||
|
||||
function RemotePlayer:constructor()
|
||||
self:init()
|
||||
end
|
||||
|
||||
return RemotePlayer
|
|
@ -0,0 +1,12 @@
|
|||
#version 330 core
|
||||
|
||||
in vec2 ourTexCoord;
|
||||
|
||||
out vec4 finalColor;
|
||||
|
||||
uniform sampler2D ourTexture;
|
||||
|
||||
void main()
|
||||
{
|
||||
finalColor = texture(ourTexture, ourTexCoord);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
end
|
||||
|
||||
function RenderEngine:render()
|
||||
glfw.poll_events()
|
||||
gl.clear_color(1.0, 0.5, 0.2, 1.0)
|
||||
gl.clear("color", "depth")
|
||||
glfw.swap_buffers(self.window)
|
||||
coroutine.yield()
|
||||
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)
|
||||
Dragonblocks:add_task(function()
|
||||
|
||||
end)
|
||||
end
|
||||
|
||||
RenderEngine:init()
|
||||
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()
|
||||
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)
|
||||
glfw.poll_events()
|
||||
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
|
||||
|
||||
function RenderEngine:set_wireframe(v)
|
||||
gl.polygon_mode("front and back", (v and "line" or "fill"))
|
||||
end
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
MapGen
|
|
@ -0,0 +1,7 @@
|
|||
local Block = Dragonblocks.create_class()
|
||||
|
||||
function Block:constructor(def, pos)
|
||||
self.def, self.pos = def, pos
|
||||
end
|
||||
|
||||
return Block
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
WorldSystem.World = WorldSystem:run("world")
|
||||
WorldSystem.Map = WorldSystem:run("map")
|
||||
WorldSystem.Chunk = WorldSystem:run("chunk")
|
||||
WorldSystem.Block = WorldSystem:run("block")
|
|
@ -0,0 +1,7 @@
|
|||
local Map = Dragonblocks.create_class()
|
||||
|
||||
function Map:constructor()
|
||||
self.chunk = WorldSystem.Chunk()
|
||||
end
|
||||
|
||||
return Map
|
|
@ -0,0 +1,7 @@
|
|||
local World = Dragonblocks.create_class()
|
||||
|
||||
function World:constructor()
|
||||
self.map = WorldSystem.Map()
|
||||
end
|
||||
|
||||
return World
|
|
@ -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
|
||||
|
|
|
@ -1,31 +1,25 @@
|
|||
local event_interface = {}
|
||||
local events = {}
|
||||
|
||||
function event_interface:init()
|
||||
assert(self._task_manager)
|
||||
self:clear_event_listeners()
|
||||
end
|
||||
|
||||
function event_interface:fire_event(event, callback)
|
||||
function events: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)
|
||||
if listeners and #listeners > 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
|
20
src/init.lua
20
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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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 "<not serializable>"
|
||||
end,
|
||||
}
|
||||
|
||||
function ObjectMgr.create()
|
||||
local o = {}
|
||||
o._proto = {ObjectRef}
|
||||
setmetatable(o, ObjectMgr.metatable)
|
||||
return o
|
||||
end
|
|
@ -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 = {}
|
|
@ -0,0 +1,5 @@
|
|||
return function(t, o)
|
||||
for k, v in pairs(o) do
|
||||
t[k] = v
|
||||
end
|
||||
end
|
|
@ -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
|
Loading…
Reference in New Issue