<commit_before>-- Getting folder that contains engine
local folderOfThisFile = (...):match("(.-)[^%/]+$")

-- Requiring class
require(folderOfThisFile .. "class")

-- Requiring all Events
require(folderOfThisFile .. "events/componentAdded")
require(folderOfThisFile .. "events/componentRemoved")
require(folderOfThisFile .. "events/beginContact")

-- Requiring the lovetoys
require(folderOfThisFile .. "entity")
require(folderOfThisFile .. "system")
require(folderOfThisFile .. "eventManager")
require(folderOfThisFile .. "collisionManager")
require(folderOfThisFile .. "component")


Engine = class("Engine")

function Engine:__init() 
    self.entities = {}
    self.requirements = {}
    self.entityLists = {}
    self.eventManager = EventManager()

    self.allSystems = {}
    self.logicSystems = {}
    self.drawSystems = {}

    self.freeIds = {}
    self.eventManager:addListener("ComponentRemoved", {self, self.componentRemoved})
    self.eventManager:addListener("ComponentAdded", {self, self.componentAdded})
end

function Engine:addEntity(entity)
    
    entity.eventManager = self.eventManager

    -- Getting the next free ID or insert into table
    if #self.freeIds == 0 then
        entity.id = #self.entities
        table.insert(self.entities, entity)
    else
        entity.id = table.remove(self.freeIds, #self.freeIds)
        self.entities[entity.id] = entity
    end

    for index, component in pairs(entity.components) do
        -- Adding Entity to specific Entitylist
        if not self.entityLists[component.__name] then self.entityLists[component.__name] = {} end
        self.entityLists[component.__name][entity.id] = entity

        -- Adding Entity to System if all requirements are granted
        if self.requirements[component.__name] then
            for index2, system in pairs(self.requirements[component.__name]) do
                self:checkRequirements(entity, system)
            end
        end
    end
end 

function Engine:removeEntity(entity)
    -- Stashing the id of the removed Entity in self.freeIds
    table.insert(self.freeIds, entity.id)
    -- Removing the Entity from all Systems and engine
    for i, component in pairs(entity.components) do
        if self.requirements[component.__name] then
            for i2, system in pairs(self.requirements[component.__name]) do
                system:removeEntity(entity)
            end
        end
    end
    -- Deleting the Entity from the specific entity lists
    for index, component in pairs(entity.components) do
        self.entityLists[component.__name][entity.id] = nil
    end
    self.entities[entity.id] = nil
end

function Engine:addSystem(system, typ, priority)
    if priority then
        system.priority = priority
    end
    for index, value in pairs(self.allSystems) do
        if value.__name == system.__name then
            print("Lovetoys: System already existing. Aborting")
            return
        end
    end
    -- Adding System to draw or logic table
    if typ == "draw" then
        table.insert(self.drawSystems, system)
        table.sort(self.drawSystems, function(a, b) return a.priority < b.priority end)
    elseif typ == "logic" then
        table.insert(self.logicSystems, system)
        table.sort(self.logicSystems, function(a, b) return a.priority < b.priority end)
    end
    table.insert(self.allSystems, system)

    -- Registering the systems requirements and saving them in a special table for fast access
    for index, value in pairs(system:requires()) do
        if type(value) == "string" then
            self.requirements[value] = self.requirements[value] or {}
            table.insert(self.requirements[value], system)
        elseif type(value) == "table" then
            for index2, string in pairs(value) do
                self.requirements[string] = self.requirements[string] or {}
                table.insert(self.requirements[string], system)
            end
            system.targets[index] = {}
        end
    end
    -- Checks if some of the already entities match the required components.
    for index, entity in pairs(self.entities) do
        self:checkRequirements(entity, system)
    end
    return system
end

function Engine:removeSystem(system)
    
    local requirements
    -- Removes it from the allSystem list
    for k, v in pairs(self.allSystems) do
        if v.__name == system then
            requirements = v:requires()
            table.remove(self.allSystems, k)
        end
    end
    if requirements ~= nil then 
    --  Remove the System from all requirement lists
        for k, v in pairs(requirements) do
            if type(v) == "string" then
                for k2, v2 in pairs(self.requirements[v]) do
                    if v2.__name == system then
                        table.remove(self.requirements, k2)
                    end
                end
            -- Removing if it has subtables
            elseif type(v) == "table" then
                for k2, v2 in pairs(v) do
                    for k3, v3 in pairs(self.requirements[v2]) do
                        if v3.__name == system then
                            table.remove(self.requirements, k3)
                        end
                    end
                end
            end
        end

        -- Remove the system from all systemlists
        for k, v in pairs(self.drawSystems) do
            if v.__name == system then
                table.remove(self.drawSystems, k)
            end
        end
        for k, v in pairs(self.logicSystems) do
            if v.__name == system then
                table.remove(self.logicSystems, k)
            end
        end
    else
        print("Lovetoys: System to be removed couldn't be found")
    end
end

function Engine:update(dt)
    for index, system in ipairs(self.logicSystems) do
        system:update(dt)
    end
end

function Engine:draw()
    for index, system in ipairs(self.drawSystems) do
        system:draw()
    end
end

function Engine.componentRemoved(self, event)
    local entity = event.entity
    local component = event.component
    -- Removing Entity from Entitylists
    self.entityLists[component][entity.id] = nil
    -- Removing Entity from old systems
    if self.requirements[component] then
        for index, system in pairs(self.requirements[component]) do 
            system:removeEntity(entity)
        end
    end<commit_msg>Debugmessages for engine:addSystem, engine:removeSystem and engine:removeEntity added<commit_after>-- Getting folder that contains engine
local folderOfThisFile = (...):match("(.-)[^%/]+$")

-- Requiring class
require(folderOfThisFile .. "class")

-- Requiring all Events
require(folderOfThisFile .. "events/componentAdded")
require(folderOfThisFile .. "events/componentRemoved")
require(folderOfThisFile .. "events/beginContact")

-- Requiring the lovetoys
require(folderOfThisFile .. "entity")
require(folderOfThisFile .. "system")
require(folderOfThisFile .. "eventManager")
require(folderOfThisFile .. "collisionManager")
require(folderOfThisFile .. "component")


Engine = class("Engine")

function Engine:__init() 
    self.entities = {}
    self.requirements = {}
    self.entityLists = {}
    self.eventManager = EventManager()

    self.allSystems = {}
    self.logicSystems = {}
    self.drawSystems = {}

    self.freeIds = {}
    self.eventManager:addListener("ComponentRemoved", {self, self.componentRemoved})
    self.eventManager:addListener("ComponentAdded", {self, self.componentAdded})
end

function Engine:addEntity(entity)
    
    entity.eventManager = self.eventManager

    -- Getting the next free ID or insert into table
    if #self.freeIds == 0 then
        entity.id = #self.entities
        table.insert(self.entities, entity)
    else
        entity.id = table.remove(self.freeIds, #self.freeIds)
        self.entities[entity.id] = entity
    end

    for index, component in pairs(entity.components) do
        -- Adding Entity to specific Entitylist
        if not self.entityLists[component.__name] then self.entityLists[component.__name] = {} end
        self.entityLists[component.__name][entity.id] = entity

        -- Adding Entity to System if all requirements are granted
        if self.requirements[component.__name] then
            for index2, system in pairs(self.requirements[component.__name]) do
                self:checkRequirements(entity, system)
            end
        end
    end
end 

function Engine:removeEntity(entity)
    -- Stashing the id of the removed Entity in self.freeIds
    table.insert(self.freeIds, entity.id)
    -- Removing the Entity from all Systems and engine
    for i, component in pairs(entity.components) do
        if self.requirements[component.__name] then
            for i2, system in pairs(self.requirements[component.__name]) do
                system:removeEntity(entity)
            end
        end
    end
    -- Deleting the Entity from the specific entity lists
    for index, component in pairs(entity.components) do
        self.entityLists[component.__name][entity.id] = nil
    end
    if self.entities[entity.id] then
        self.entities[entity.id] = nil
    else
        print("Trying to remove non existing entity from engine.")
        print("Entity id: " .. entity.id)
        print("Entity's components:")
        for index, component in pairs(entity.components) do
            print(index)
        end
    end
end

function Engine:addSystem(system, typ, priority)
    if priority then
        system.priority = priority
    end
    for index, value in pairs(self.allSystems) do
        if value.__name == system.__name then
            print("Lovetoys: " .. system.__name .. " already existing. Aborting")
            return
        end
    end
    -- Adding System to draw or logic table
    if typ == "draw" then
        table.insert(self.drawSystems, system)
        table.sort(self.drawSystems, function(a, b) return a.priority < b.priority end)
    elseif typ == "logic" then
        table.insert(self.logicSystems, system)
        table.sort(self.logicSystems, function(a, b) return a.priority < b.priority end)
    end
    table.insert(self.allSystems, system)

    -- Registering the systems requirements and saving them in a special table for fast access
    for index, value in pairs(system:requires()) do
        if type(value) == "string" then
            self.requirements[value] = self.requirements[value] or {}
            table.insert(self.requirements[value], system)
        elseif type(value) == "table" then
            for index2, string in pairs(value) do
                self.requirements[string] = self.requirements[string] or {}
                table.insert(self.requirements[string], system)
            end
            system.targets[index] = {}
        end
    end
    -- Checks if some of the already entities match the required components.
    for index, entity in pairs(self.entities) do
        self:checkRequirements(entity, system)
    end
    return system
end

function Engine:removeSystem(system)
    
    local requirements
    -- Removes it from the allSystem list
    for k, v in pairs(self.allSystems) do
        if v.__name == system then
            requirements = v:requires()
            table.remove(self.allSystems, k)
        end
    end
    if requirements ~= nil then 
    --  Remove the System from all requirement lists
        for k, v in pairs(requirements) do
            if type(v) == "string" then
                for k2, v2 in pairs(self.requirements[v]) do
                    if v2.__name == system then
                        table.remove(self.requirements, k2)
                    end
                end
            -- Removing if it has subtables
            elseif type(v) == "table" then
                for k2, v2 in pairs(v) do
                    for k3, v3 in pairs(self.requirements[v2]) do
                        if v3.__name == system then
                            table.remove(self.requirements, k3)
                        end
                    end
                end
            end
        end

        -- Remove the system from all systemlists
        for k, v in pairs(self.drawSystems) do
            if v.__name == system then
                table.remove(self.drawSystems, k)
            end
        end
        for k, v in pairs(self.logicSystems) do
            if v.__name == system then
                table.remove(self.logicSystems, k)
            end
        end
    else
        print("Lovetoys: " .. system .. " isn't existing. System can't be removed from engine.")
    end
end

function Engine:update(dt)
    for index, system in ipairs(self.logicSystems) do
        system:update(dt)
    end
end

function Engine:draw()
    for index, system in ipairs(self.drawSystems) do
        system:draw()
    end
end

function Engine.componentRemoved(self, event)
    local entity = event.entity
    local component = event.component
    -- Removing Entity from Entitylists
    self.entityLists[component][entity.id] = nil
    -- Removing Entity from old systems
    if self.requirements[component] then
        for index, system in pairs(self.requirements[component]) do 
            system:removeEntity(entity)
        end
    end
{'fraction_non_alphanumeric': 0.09073738289513449, 'fraction_numerical': 0.0022665457842248413, 'mean_word_length': 2.27567433803514, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6675924', 'n_tokens_mistral': 3631, 'n_tokens_neox': 3554, 'n_words': 1059}