local current_scene = nil local comp_inits = {} local comp_deinits = {} global_on_update = new_event() global_on_draw = new_event() global_on_ui = new_event() function TAGCOMP(_) end function new_scene() local newscene = { compmask = {}, entities = {}, entities_size = 0, free_entids = {}, free_entids_size = 0, killset = {}, killq = {}, killq_size = 0, -- Events on_draw = new_event(), on_update = new_event(), on_ui = new_event(), comp_removeq = {}, comp_entq = {}, comp_removeq_size = 0, } for comp, _ in pairs(comp_inits) do newscene.compmask[comp] = { sparse = {}, dense = {}, size = 0, } end return newscene end function set_scene(newscene) current_scene = newscene end function get_current_scene() return current_scene end function register_comp(name, init, deinit) assert(comp_inits[name] == nil, "Component '"..name.."' is already registered.") comp_inits[name] = init comp_deinits[name] = deinit end function add_comp(ent, comp, ...) assert(current_scene, "No scene up.") assert(comp_inits[comp], "Unknown component '"..tostring(comp).."'") assert(current_scene.entities[ent.id], "Entity "..tostring(ent.id).." doesn't exist.") local mask = current_scene.compmask[comp] assert(not mask.sparse[ent.id], "Entity "..tostring(ent.id).." already has component of type '"..comp.."'.") mask.size = mask.size + 1 mask.sparse[ent.id] = mask.size mask.dense[mask.size] = ent.id comp_inits[comp](current_scene.entities[ent.id], ...) end local function remove_comp(ent, comp) assert(current_scene, "No scene up.") assert(comp_inits[comp], "Unknown component '"..tostring(comp).."'") assert(current_scene.entities[ent.id], "Entity "..tostring(ent.id).." doesn't exist.") local deinit = comp_deinits[comp] if deinit then deinit(ent) end local mask = current_scene.compmask[comp] assert(mask.sparse[ent.id], "Entity "..tostring(ent.id).." does not have component of type '"..comp.."'.") local index = mask.sparse[ent.id] local lastid = mask.dense[mask.size] mask.sparse[ent.id] = nil if ent.id ~= lastid then mask.sparse[lastid] = index mask.dense[index] = mask.dense[mask.size] end mask.dense[mask.size] = nil mask.size = mask.size - 1 end function run_system(comp, func, ...) assert(current_scene, "No scene up.") assert(comp_inits[comp], "Unknown component '"..tostring(comp).."'") for _, entid in ipairs(current_scene.compmask[comp].dense) do func(current_scene.entities[entid], ...) end end function queue_entity_kill(ent) assert(current_scene, "No scene up.") assert(current_scene.entities[ent.id], "Entity "..tostring(ent.id).." doesn't exist.") if current_scene.killset[ent.id] then return end current_scene.killset[ent.id] = true current_scene.killq_size = current_scene.killq_size + 1 current_scene.killq[current_scene.killq_size] = ent.id end function has_comp(ent, comp) assert(current_scene, "No scene up.") assert(comp_inits[comp], "Unknown component '"..tostring(comp).."'") assert(current_scene.entities[ent.id], "Entity "..tostring(ent.id).." doesn't exist.") return current_scene.compmask[comp].sparse[ent.id] ~= nil end function queue_remove_comp(ent, comp) assert(current_scene, "No scene up.") assert(comp_inits[comp], "Unknown component '"..tostring(comp).."'") if not has_comp(ent, comp) then return end current_scene.comp_removeq_size = current_scene.comp_removeq_size + 1 current_scene.comp_removeq[current_scene.comp_removeq_size] = comp current_scene.comp_entq[current_scene.comp_removeq_size] = ent end function flush_scene() assert(current_scene, "No scene up.") for i=1, current_scene.comp_removeq_size do remove_comp(current_scene.comp_entq[i], current_scene.comp_removeq[i]) end current_scene.comp_removeq_size = 0 for i=current_scene.killq_size, 1, -1 do local ent = current_scene.entities[current_scene.killq[i]] for comp, _ in pairs(current_scene.compmask) do if has_comp(ent, comp) then remove_comp(ent, comp) end end current_scene.killset[ent.id] = nil current_scene.free_entids_size = current_scene.free_entids_size + 1 current_scene.free_entids[current_scene.free_entids_size] = ent.id end current_scene.killq_size = 0 end function new_entity() assert(current_scene, "No scene up.") if current_scene.free_entids_size > 0 then local entid = current_scene.free_entids[current_scene.free_entids_size] current_scene.free_entids_size = current_scene.free_entids_size - 1 local ent = current_scene.entities[entid] for key in pairs(ent) do ent[key] = nil end ent.id = entid return ent end local newid = current_scene.entities_size + 1 current_scene.entities[newid] = {id = newid} current_scene.entities_size = newid return current_scene.entities[newid] end