[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
$ 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
--- /dev/null
+Subproject commit 9168e065e17d164d2c7ddcb691fec23b47362fc1
--- /dev/null
+Subproject commit 088ad95710be4325dd368df19b5323e2837c4059
--- /dev/null
+Subproject commit 18799868803a424bff4b95b79123f1d9c28c9483
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()
--- /dev/null
+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
--- /dev/null
+RenderEngine
+WorldSystem
+PlayerSystem
--- /dev/null
+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
--- /dev/null
+Client.graphics = Client:run("graphics")
+
+Client.graphics:init()
+
+Client.map = WorldSystem.Map()
+
+RenderEngine:render_loop()
--- /dev/null
+BlockSystem
--- /dev/null
+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",
+})
+++ /dev/null
-RenderEngine
+++ /dev/null
-RenderEngine:open_window()
-RenderEngine:set_window_title("Dragonblocks 3D - Main Menu")
-
-RenderEngine:add_render_task()
-
-MainMenu:init()
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+local RemotePlayer = Dragonblocks.create_class()
+table.assign(RemotePlayer, PlayerSystem.Player)
+
+function RemotePlayer:constructor()
+ self:init()
+end
+
+return RemotePlayer
--- /dev/null
+#version 330 core\r
+\r
+in vec2 ourTexCoord;\r
+\r
+out vec4 finalColor;\r
+\r
+uniform sampler2D ourTexture;\r
+\r
+void main()\r
+{\r
+ finalColor = texture(ourTexture, ourTexCoord);\r
+}\r
--- /dev/null
+#version 330 core\r
+\r
+layout(location = 0) in vec3 aPos;\r
+layout(location = 1) in vec2 aTexCoord;\r
+\r
+out vec2 ourTexCoord;\r
+\r
+uniform mat4 model;\r
+uniform mat4 view;\r
+uniform mat4 projection;\r
+\r
+void main()\r
+{\r
+ gl_Position = projection * view * model * vec4(aPos, 1.0);\r
+ ourTexCoord = aTexCoord;\r
+}\r
--- /dev/null
+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
+}
-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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+local Block = Dragonblocks.create_class()
+
+function Block:constructor(def, pos)
+ self.def, self.pos = def, pos
+end
+
+return Block
--- /dev/null
+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
--- /dev/null
+WorldSystem.World = WorldSystem:run("world")
+WorldSystem.Map = WorldSystem:run("map")
+WorldSystem.Chunk = WorldSystem:run("chunk")
+WorldSystem.Block = WorldSystem:run("block")
--- /dev/null
+local Map = Dragonblocks.create_class()
+
+function Map:constructor()
+ self.chunk = WorldSystem.Chunk()
+end
+
+return Map
--- /dev/null
+local World = Dragonblocks.create_class()
+
+function World:constructor()
+ self.map = WorldSystem.Map()
+end
+
+return World
-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
+++ /dev/null
-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
--- /dev/null
+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
-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()
+++ /dev/null
-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
--- /dev/null
+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
--- /dev/null
+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
+++ /dev/null
-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
+++ /dev/null
-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
--- /dev/null
+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
--- /dev/null
+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
+++ /dev/null
-function table.indexof(list, val)
- for i, v in ipairs(list) do
- if v == val then
- return i
- end
- end
- return -1
-end
+++ /dev/null
-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
+++ /dev/null
-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
--- /dev/null
+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
--- /dev/null
+return function(t, o)
+ for k, v in pairs(o) do
+ t[k] = v
+ end
+end
--- /dev/null
+return function(list, val)
+ for i, v in ipairs(list) do
+ if v == val then
+ return i
+ end
+ end
+ return -1
+end