Refactoring

master
Elias Fleckenstein 2020-08-11 10:51:38 +02:00
parent 5af7069ac5
commit 131d2feb2a
51 changed files with 729 additions and 256 deletions

9
.gitmodules vendored
View File

@ -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
View File

@ -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

1
deps/moonassimp vendored Submodule

@ -0,0 +1 @@
Subproject commit 9168e065e17d164d2c7ddcb691fec23b47362fc1

1
deps/moonglmath vendored Submodule

@ -0,0 +1 @@
Subproject commit 088ad95710be4325dd368df19b5323e2837c4059

1
deps/moonimage vendored Submodule

@ -0,0 +1 @@
Subproject commit 18799868803a424bff4b95b79123f1d9c28c9483

View File

@ -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()

View File

@ -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

View File

@ -0,0 +1,3 @@
RenderEngine
WorldSystem
PlayerSystem

View File

@ -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

View File

@ -0,0 +1,7 @@
Client.graphics = Client:run("graphics")
Client.graphics:init()
Client.map = WorldSystem.Map()
RenderEngine:render_loop()

View File

@ -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.

11
modules/Game/src/init.lua Normal file
View File

@ -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",
})

View File

@ -1 +0,0 @@
RenderEngine

View File

@ -1,6 +0,0 @@
RenderEngine:open_window()
RenderEngine:set_window_title("Dragonblocks 3D - Main Menu")
RenderEngine:add_render_task()
MainMenu:init()

View File

@ -0,0 +1 @@
Game

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,8 @@
local RemotePlayer = Dragonblocks.create_class()
table.assign(RemotePlayer, PlayerSystem.Player)
function RemotePlayer:constructor()
self:init()
end
return RemotePlayer

View File

@ -0,0 +1,12 @@
#version 330 core
in vec2 ourTexCoord;
out vec4 finalColor;
uniform sampler2D ourTexture;
void main()
{
finalColor = texture(ourTexture, ourTexCoord);
}

View File

@ -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;
}

View File

@ -0,0 +1 @@

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
MapGen

View File

@ -0,0 +1,7 @@
local Block = Dragonblocks.create_class()
function Block:constructor(def, pos)
self.def, self.pos = def, pos
end
return Block

View File

@ -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

View File

@ -0,0 +1,4 @@
WorldSystem.World = WorldSystem:run("world")
WorldSystem.Map = WorldSystem:run("map")
WorldSystem.Chunk = WorldSystem:run("chunk")
WorldSystem.Block = WorldSystem:run("block")

View File

@ -0,0 +1,7 @@
local Map = Dragonblocks.create_class()
function Map:constructor()
self.chunk = WorldSystem.Chunk()
end
return Map

View File

@ -0,0 +1,7 @@
local World = Dragonblocks.create_class()
function World:constructor()
self.map = WorldSystem.Map()
end
return World

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

64
src/modulemgr.lua Normal file
View File

@ -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

View File

@ -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

View File

@ -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

24
src/taskmgr.lua Normal file
View File

@ -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

8
util/hex2rgb.lua Normal file
View File

@ -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

View File

@ -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

View File

@ -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 = {}

5
util/table_assign.lua Normal file
View File

@ -0,0 +1,5 @@
return function(t, o)
for k, v in pairs(o) do
t[k] = v
end
end

View File

@ -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