From 11255fd72268036c05b61ba6759ba4f42cebd32b Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Tue, 2 Oct 2018 21:52:23 +0200
Subject: [PATCH 001/113] Optimized Lists. Added pool.added and .removed. Added
entity:ensure
---
TODO | 8 ++++++
examples/simpleDrawing/init.lua | 22 ++++++++--------
lib/entity.lua | 28 +++++++++++++++++---
lib/instance.lua | 4 +++
lib/list.lua | 45 ++++++++++++++++++---------------
lib/pool.lua | 9 +++++++
lib/system.lua | 36 ++++++++++++++++----------
7 files changed, 104 insertions(+), 48 deletions(-)
create mode 100644 TODO
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..4ef844e
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+[x] Modify pools and list to be more efficient
+[x] Rework Entity:give to remove any previous component and re-add it.
+[x] Add Entity:ensure (maybe?)
+[ ] Put pools in the Instance and invert dependency.
+[ ] Share pools between systems
+[ ] Remove System callbacks
+[x] Put .added and .removed in pools so they can be iterated over
+[ ] Implement assemblages
diff --git a/examples/simpleDrawing/init.lua b/examples/simpleDrawing/init.lua
index 9879f94..f9a2d9f 100644
--- a/examples/simpleDrawing/init.lua
+++ b/examples/simpleDrawing/init.lua
@@ -31,10 +31,7 @@ end)
local RectangleRenderer = System({Position, Rectangle})
function RectangleRenderer:draw()
- local e
- for i = 1, self.pool.size do
- e = self.pool:get(i)
-
+ for _, e in ipairs(self.pool) do
local position = e:get(Position)
local rectangle = e:get(Rectangle)
local color = e:get(Color)
@@ -49,11 +46,16 @@ function RectangleRenderer:draw()
end
local CircleRenderer = System({Position, Circle})
-function CircleRenderer:draw()
- local e
- for i = 1, self.pool.size do
- e = self.pool:get(i)
+function CircleRenderer:flush()
+ for _, e in ipairs(self.pool.removed) do
+ print(tostring(e).. " was removed from my pool D:")
+ end
+ self:clear()
+end
+
+function CircleRenderer:draw()
+ for _, e in ipairs(self.pool) do
local position = e:get(Position)
local circle = e:get(Circle)
local color = e:get(Color)
@@ -76,7 +78,7 @@ end
function RandomRemover:update(dt)
self.time = self.time + dt
- if self.time >= 0.25 then
+ if self.time >= 0.5 then
self.time = 0
if self.pool.size > 0 then
@@ -115,4 +117,4 @@ for i = 1, 100 do
end
Game:addEntity(e)
-end
\ No newline at end of file
+end
diff --git a/lib/entity.lua b/lib/entity.lua
index 68fedeb..bfb9a07 100644
--- a/lib/entity.lua
+++ b/lib/entity.lua
@@ -22,6 +22,12 @@ function Entity.new()
return e
end
+local function give(e, component, ...)
+ local comp = component:__initialize(...)
+ e.components[component] = comp
+ e[component] = comp
+end
+
--- Gives an Entity a component with values.
-- @param component The Component to add
-- @param ... The values passed to the Component
@@ -31,9 +37,25 @@ function Entity:give(component, ...)
error("bad argument #1 to 'Entity:give' (Component expected, got "..type(component)..")", 2)
end
- local comp = component:__initialize(...)
- self.components[component] = comp
- self[component] = comp
+ if self[component] then
+ self:remove(component):apply()
+ end
+
+ give(self, component, ...)
+
+ return self
+end
+
+function Entity:ensure(component, ...)
+ if not Type.isComponent(component) then
+ error("bad argument #1 to 'Entity:ensure' (Component expected, got "..type(component)..")", 2)
+ end
+
+ if self[component] then
+ return self
+ end
+
+ give(self, component, ...)
return self
end
diff --git a/lib/instance.lua b/lib/instance.lua
index f2a947e..f4d63a0 100644
--- a/lib/instance.lua
+++ b/lib/instance.lua
@@ -92,6 +92,10 @@ function Instance:flush()
end
end
+ for i = 1, self.systems.size do
+ self.systems:get(i):flush()
+ end
+
return self
end
diff --git a/lib/list.lua b/lib/list.lua
index 33b2c10..a5698c9 100644
--- a/lib/list.lua
+++ b/lib/list.lua
@@ -7,18 +7,21 @@ local mt = {__index = List}
-- @return A new list
function List.new()
return setmetatable({
- objects = {},
- pointers = {},
- size = 0,
+ size = 0,
}, mt)
end
--- Clears the List completely.
-- @return self
function List:clear()
- self.objects = {}
- self.pointers = {}
- self.size = 0
+ for i = 1, self.size do
+ local o = self[i]
+
+ self[o] = nil
+ self[i] = nil
+ end
+
+ self.size = 0
return self
end
@@ -26,12 +29,12 @@ end
--- Adds an object to the List.
-- @param obj The object to add
-- @return self
-function List:add(obj)
+function List:add(obj) -- obj can not be a number and also not the string "size"
local size = self.size + 1
- self.objects[size] = obj
- self.pointers[obj] = size
- self.size = size
+ self[size] = obj
+ self[obj] = size
+ self.size = size
return self
end
@@ -40,22 +43,22 @@ end
-- @param obj The object to remove
-- @return self
function List:remove(obj)
- local index = self.pointers[obj]
- if not index then return end
+ local index = self[obj]
+ if not index then return end
local size = self.size
-
+
if index == size then
- self.objects[size] = nil
+ self[size] = nil
else
- local other = self.objects[size]
+ local other = self[size]
- self.objects[index] = other
- self.pointers[other] = index
+ self[index] = other
+ self[other] = index
- self.objects[size] = nil
+ self[size] = nil
end
- self.pointers[obj] = nil
+ self[obj] = nil
self.size = size - 1
end
@@ -63,14 +66,14 @@ end
-- @param index The index to look at
-- @return The object at the index
function List:get(index)
- return self.objects[index]
+ return self[index]
end
--- Gets if the List has the object.
-- @param obj The object to search for
-- true if the list has the object, false otherwise
function List:has(obj)
- return self.pointers[obj] and true
+ return self[obj] and true
end
return setmetatable(List, {
diff --git a/lib/pool.lua b/lib/pool.lua
index c2d1ab4..5a7f44b 100644
--- a/lib/pool.lua
+++ b/lib/pool.lua
@@ -14,6 +14,9 @@ Pool.__index = Pool
function Pool.new(name, filter)
local pool = setmetatable(List(), Pool)
+ pool.added = {}
+ pool.removed = {}
+
pool.name = name
pool.filter = filter
@@ -22,6 +25,12 @@ function Pool.new(name, filter)
return pool
end
+function Pool:flush()
+ for i = 1, math.max(#self.added, #self.removed) do
+ self.added[i], self.removed[i] = nil, nil
+ end
+end
+
--- Checks if an Entity is eligible for the Pool.
-- @param e The Entity to check
-- @return True if the entity is eligible, false otherwise
diff --git a/lib/system.lua b/lib/system.lua
index ac769ba..7c7b22a 100644
--- a/lib/system.lua
+++ b/lib/system.lua
@@ -66,7 +66,7 @@ end
-- @param e The Entity to check
-- @return True if the Entity was added, false if it was removed. Nil if nothing happend
function System:__check(e)
- local systemHas = self:__has(e)
+ local systemHas = self.__all[e]
for _, pool in ipairs(self.__pools) do
local poolHas = pool:has(e)
@@ -74,23 +74,28 @@ function System:__check(e)
if not poolHas and eligible then
pool:add(e)
+ pool.added[#pool.added + 1] = e
+
self:entityAddedTo(e, pool)
self:__tryAdd(e)
elseif poolHas and not eligible then
pool:remove(e)
+ pool.removed[#pool.removed + 1] = e
+
self:entityRemovedFrom(e, pool)
self:__tryRemove(e)
end
end
end
---- Removed an Entity from the System.
+--- Remove an Entity from the System.
-- @param e The Entity to remove
function System:__remove(e)
- if self:__has(e) then
+ if self.__all[e] then
for _, pool in ipairs(self.__pools) do
if pool:has(e) then
pool:remove(e)
+ pool.removed[#pool.removed + 1] = e
self:entityRemovedFrom(e, pool)
end
end
@@ -103,7 +108,7 @@ end
--- Tries to add an Entity to the System.
-- @param e The Entity to add
function System:__tryAdd(e)
- if not self:__has(e) then
+ if not self.__all[e] then
self.__all[e] = 0
self:entityAdded(e)
end
@@ -114,7 +119,7 @@ end
--- Tries to remove an Entity from the System.
-- @param e The Entity to remove
function System:__tryRemove(e)
- if self:__has(e) then
+ if self.__all[e] then
self.__all[e] = self.__all[e] - 1
if self.__all[e] == 0 then
@@ -124,19 +129,22 @@ function System:__tryRemove(e)
end
end
+function System:flush()
+ self:clear()
+end
+
+function System:clear()
+ for i = 1, #self.__pools do
+ self.__pools[i]:flush()
+ end
+end
+
--- Returns the Instance the System is in.
-- @return The Instance
function System:getInstance()
return self.__instance
end
---- Returns if the System has the Entity.
--- @param e The Entity to check for
--- @return True if the System has the Entity. False otherwise
-function System:__has(e)
- return self.__all[e] and true
-end
-
--- Default callback for system initialization.
-- @param ... Varags
function System:init(...)
@@ -170,12 +178,12 @@ function System:addedTo(instance)
end
-- Default callback for when a System's callback is enabled.
--- @param callbackName The name of the callback that was enabled
+-- @param callbackName The name of the callback that was enabled
function System:enabledCallback(callbackName)
end
-- Default callback for when a System's callback is disabled.
--- @param callbackName The name of the callback that was disabled
+-- @param callbackName The name of the callback that was disabled
function System:disabledCallback(callbackName)
end
From f7a394f057400ee156f17afa402a3e7318e5c4c6 Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Sun, 11 Nov 2018 19:42:44 +0100
Subject: [PATCH 002/113] Added assemblages
---
.luacheckrc | 1 +
TODO | 11 ++++-
examples/assemblageTest/init.lua | 67 +++++++++++++++++++++++++++++
examples/simpleDrawing/init.lua | 6 +--
lib/assemblage.lua | 26 ++++++++++++
lib/entity.lua | 44 ++++++++++++-------
lib/init.lua | 11 ++---
lib/instance.lua | 73 +++++++++++++++++++++-----------
lib/pool.lua | 2 +-
lib/system.lua | 48 ++++-----------------
lib/type.lua | 6 ++-
main.lua | 2 +-
12 files changed, 204 insertions(+), 93 deletions(-)
create mode 100644 .luacheckrc
create mode 100644 examples/assemblageTest/init.lua
create mode 100644 lib/assemblage.lua
diff --git a/.luacheckrc b/.luacheckrc
new file mode 100644
index 0000000..b557738
--- /dev/null
+++ b/.luacheckrc
@@ -0,0 +1 @@
+std="love+luajit"
diff --git a/TODO b/TODO
index 4ef844e..33fc816 100644
--- a/TODO
+++ b/TODO
@@ -3,6 +3,13 @@
[x] Add Entity:ensure (maybe?)
[ ] Put pools in the Instance and invert dependency.
[ ] Share pools between systems
-[ ] Remove System callbacks
+[x] Remove System callbacks
[x] Put .added and .removed in pools so they can be iterated over
-[ ] Implement assemblages
+[x] Implement assemblages
+[x] Do :apply automatically with marked entities
+[x] Remove Entity.components. Use Entity[Component] instead
+
+[ ] Add missing documentation
+[ ] Fix current documentation
+[ ] Write unit tests
+[ ] Write examples
diff --git a/examples/assemblageTest/init.lua b/examples/assemblageTest/init.lua
new file mode 100644
index 0000000..730129b
--- /dev/null
+++ b/examples/assemblageTest/init.lua
@@ -0,0 +1,67 @@
+local Concord = require("lib").init({
+ useEvents = true
+})
+local Entity = Concord.entity
+local Component = Concord.component
+local System = Concord.system
+local Assemblage = Concord.assemblage
+
+local Game = Concord.instance()
+Concord.addInstance(Game)
+
+local Legs = Component(function(e, legCount)
+ e.legCount = legCount or 0
+end)
+
+local Instinct = Component(function(e) -- luacheck: ignore
+end)
+
+local Cool = Component(function(e, coolness)
+ e.coolness = coolness
+end)
+
+local Wings = Component(function(e)
+ e.wingCount = 2
+end)
+
+
+local Animal = Assemblage(function(e, legCount)
+ e
+ :give(Legs, legCount)
+ :give(Instinct)
+
+ print("Animal")
+end)
+
+local Lion = Assemblage(function(e, coolness)
+ e
+ :assemble(Animal, 4)
+ :give(Cool, coolness)
+
+ print("Lion")
+end)
+
+local Eagle = Assemblage(function(e)
+ e
+ :assemble(Animal, 2)
+ :give(Wings)
+
+ print("Eagle")
+end)
+
+local Griffin = Assemblage(function(e, coolness)
+ e
+ :assemble(Animal, 4)
+ :assemble(Lion, coolness * 2)
+ :assemble(Eagle)
+end)
+
+
+local myAnimal = Entity()
+:assemble(Griffin, 5)
+--:apply()
+
+print(myAnimal:has(Legs))
+print(myAnimal:has(Instinct))
+print(myAnimal:has(Cool))
+print(myAnimal:has(Wings))
diff --git a/examples/simpleDrawing/init.lua b/examples/simpleDrawing/init.lua
index f9a2d9f..8cc0426 100644
--- a/examples/simpleDrawing/init.lua
+++ b/examples/simpleDrawing/init.lua
@@ -78,7 +78,7 @@ end
function RandomRemover:update(dt)
self.time = self.time + dt
- if self.time >= 0.5 then
+ if self.time >= 0.05 then
self.time = 0
if self.pool.size > 0 then
@@ -95,7 +95,7 @@ Game:addSystem(RandomRemover(), "update")
Game:addSystem(RectangleRenderer(), "draw")
Game:addSystem(CircleRenderer(), "draw")
-for i = 1, 100 do
+for _ = 1, 100 do
local e = Entity()
e:give(Position, love.math.random(0, 700), love.math.random(0, 700))
e:give(Rectangle, love.math.random(5, 20), love.math.random(5, 20))
@@ -107,7 +107,7 @@ for i = 1, 100 do
Game:addEntity(e)
end
-for i = 1, 100 do
+for _ = 1, 100 do
local e = Entity()
e:give(Position, love.math.random(0, 700), love.math.random(0, 700))
e:give(Circle, love.math.random(5, 20))
diff --git a/lib/assemblage.lua b/lib/assemblage.lua
new file mode 100644
index 0000000..67a1428
--- /dev/null
+++ b/lib/assemblage.lua
@@ -0,0 +1,26 @@
+--- Assemblage
+
+local Assemblage = {}
+Assemblage.__index = Assemblage
+
+function Assemblage.new(assemble)
+ local assemblage = setmetatable({
+ __assemble = assemble,
+
+ __isAssemblage = true,
+ }, Assemblage)
+
+ Assemblage.__mt = {__index = assemblage}
+
+ return assemblage
+end
+
+function Assemblage:assemble(e, ...)
+ self.__assemble(e, ...)
+
+ return self
+end
+
+return setmetatable(Assemblage, {
+ __call = function(_, ...) return Assemblage.new(...) end,
+})
diff --git a/lib/entity.lua b/lib/entity.lua
index bfb9a07..441b9df 100644
--- a/lib/entity.lua
+++ b/lib/entity.lua
@@ -12,9 +12,8 @@ Entity.__index = Entity
-- @return A new Entity
function Entity.new()
local e = setmetatable({
- components = {},
- removed = {},
- instances = List(),
+ removed = {},
+ instances = List(),
__isEntity = true,
}, Entity)
@@ -24,8 +23,9 @@ end
local function give(e, component, ...)
local comp = component:__initialize(...)
- e.components[component] = comp
e[component] = comp
+
+ e:mark()
end
--- Gives an Entity a component with values.
@@ -68,22 +68,36 @@ function Entity:remove(component)
error("bad argument #1 to 'Entity:remove' (Component expected, got "..type(component)..")")
end
- self.removed[component] = true
+ self.removed[#self.removed + 1] = component
+
+ self:mark()
return self
end
---- Checks the Entity against the pools again.
--- @return self
-function Entity:apply()
- for i = 1, self.instances.size do
- self.instances:get(i):checkEntity(self)
+function Entity:assemble(assemblage, ...)
+ if not Type.isAssemblage(assemblage) then
+ error("bad argument #1 to 'Entity:assemble' (Assemblage expected, got "..type(assemblage)..")")
end
- for component, _ in pairs(self.removed) do
- self.components[component] = nil
+ assemblage:assemble(self, ...)
+
+ return self
+end
+
+function Entity:mark()
+ for i = 1, self.instances.size do
+ self.instances:get(i):markEntity(self)
+ end
+end
+
+function Entity:apply()
+ for i = 1, #self.removed do
+ local component = self.removed[i]
+
self[component] = nil
- self.removed[component] = nil
+
+ self.removed[i] = nil
end
return self
@@ -107,7 +121,7 @@ function Entity:get(component)
error("bad argument #1 to 'Entity:get' (Component expected, got "..type(component)..")")
end
- return self.components[component]
+ return self[component]
end
--- Returns true if the Entity has the Component.
@@ -118,7 +132,7 @@ function Entity:has(component)
error("bad argument #1 to 'Entity:has' (Component expected, got "..type(component)..")")
end
- return self.components[component] ~= nil
+ return self[component] ~= nil
end
return setmetatable(Entity, {
diff --git a/lib/init.lua b/lib/init.lua
index 76f2588..81887fb 100644
--- a/lib/init.lua
+++ b/lib/init.lua
@@ -22,7 +22,7 @@ local Concord = {
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
-
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -39,10 +39,11 @@ local Concord = {
-- }
-- @return Concord
function Concord.init(settings)
- Concord.entity = require(PATH..".entity")
- Concord.component = require(PATH..".component")
- Concord.system = require(PATH..".system")
- Concord.instance = require(PATH..".instance")
+ Concord.entity = require(PATH..".entity")
+ Concord.component = require(PATH..".component")
+ Concord.system = require(PATH..".system")
+ Concord.instance = require(PATH..".instance")
+ Concord.assemblage = require(PATH..".assemblage")
if settings and settings.useEvents then
Concord.instances = {}
diff --git a/lib/instance.lua b/lib/instance.lua
index f4d63a0..fa59c35 100644
--- a/lib/instance.lua
+++ b/lib/instance.lua
@@ -2,8 +2,6 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Entity = require(PATH..".entity")
-local System = require(PATH..".system")
local Type = require(PATH..".type")
local List = require(PATH..".list")
@@ -17,8 +15,9 @@ function Instance.new()
entities = List(),
systems = List(),
events = {},
+
+ marked = {},
removed = {},
- toRemove = nil,
__isInstance = true,
}, Instance)
@@ -43,6 +42,29 @@ function Instance:addEntity(e)
return self
end
+--- Marks an Entity as removed from the Instance.
+-- @param e The Entity to mark
+-- @return self
+function Instance:removeEntity(e)
+ if not Type.isEntity(e) then
+ error("bad argument #1 to 'Instance:removeEntity' (Entity expected, got "..type(e)..")", 2)
+ end
+
+ self.removed[#self.removed + 1] = e
+
+ return self
+end
+
+function Instance:markEntity(e)
+ if not Type.isEntity(e) then
+ error("bad argument #1 to 'Instance:markEntity' (Entity expected, got "..type(e)..")", 2)
+ end
+
+ self.marked[#self.marked + 1] = e
+
+ return self
+end
+
--- Checks an Entity against all the systems in the Instance.
-- @param e The Entity to check
-- @return self
@@ -58,34 +80,33 @@ function Instance:checkEntity(e)
return self
end
---- Marks an Entity as removed from the Instance.
--- @param e The Entity to mark
--- @return self
-function Instance:removeEntity(e)
- if not Type.isEntity(e) then
- error("bad argument #1 to 'Instance:removeEntity' (Entity expected, got "..type(e)..")", 2)
- end
-
- self.removed[#self.removed + 1] = e
-
- return self
-end
-
--- Completely removes all marked Entities in the Instance.
-- @return self
function Instance:flush()
- while #self.removed > 0 do
- self.toRemove = self.removed
+ while #self.marked > 0 do
+ local marked = self.removed
self.removed = {}
- for i = 1, #self.toRemove do
- local e = self.toRemove[i]
+ for i = 1, #marked do
+ local e = marked[i]
+
+ e.instances:apply()
+ e.instances:checkEntity(e)
+ end
+ end
+
+ while #self.removed > 0 do
+ local removed = self.removed
+ self.removed = {}
+
+ for i = 1, #removed do
+ local e = removed[i]
e.instances:remove(self)
self.entities:remove(e)
- for i = 1, self.systems.size do
- self.systems:get(i):__remove(e)
+ for j = 1, self.systems.size do
+ self.systems:get(j):__remove(e)
end
self:onEntityRemoved(e)
@@ -93,7 +114,9 @@ function Instance:flush()
end
for i = 1, self.systems.size do
- self.systems:get(i):flush()
+ local system = self.systems:get(i)
+ system:flush()
+ system:clear()
end
return self
@@ -250,12 +273,12 @@ end
--- Default callback for adding an Entity.
-- @param e The Entity that was added
-function Instance:onEntityAdded(e)
+function Instance:onEntityAdded(e) -- luacheck: ignore
end
--- Default callback for removing an Entity.
-- @param e The Entity that was removed
-function Instance:onEntityRemoved(e)
+function Instance:onEntityRemoved(e) -- luacheck: ignore
end
return setmetatable(Instance, {
diff --git a/lib/pool.lua b/lib/pool.lua
index 5a7f44b..e7e949c 100644
--- a/lib/pool.lua
+++ b/lib/pool.lua
@@ -36,7 +36,7 @@ end
-- @return True if the entity is eligible, false otherwise
function Pool:eligible(e)
for _, component in ipairs(self.filter) do
- if not e.components[component] or e.removed[component] then
+ if not e[component] or e.removed[component] then
return false
end
end
diff --git a/lib/system.lua b/lib/system.lua
index 7c7b22a..a42f79b 100644
--- a/lib/system.lua
+++ b/lib/system.lua
@@ -2,8 +2,7 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Component = require(PATH..".component")
-local Pool = require(PATH..".pool")
+local Pool = require(PATH..".pool")
local System = {}
System.mt = {
@@ -47,11 +46,11 @@ end
--- Builds a Pool for the System.
-- @param baseFilter The 'raw' Filter
-- @return A new Pool
-function System:__buildPool(baseFilter)
+function System:__buildPool(baseFilter) -- luacheck: ignore
local name = "pool"
local filter = {}
- for i, v in ipairs(baseFilter) do
+ for _, v in ipairs(baseFilter) do
if type(v) == "table" then
filter[#filter + 1] = v
elseif type(v) == "string" then
@@ -66,8 +65,6 @@ end
-- @param e The Entity to check
-- @return True if the Entity was added, false if it was removed. Nil if nothing happend
function System:__check(e)
- local systemHas = self.__all[e]
-
for _, pool in ipairs(self.__pools) do
local poolHas = pool:has(e)
local eligible = pool:eligible(e)
@@ -76,13 +73,11 @@ function System:__check(e)
pool:add(e)
pool.added[#pool.added + 1] = e
- self:entityAddedTo(e, pool)
self:__tryAdd(e)
elseif poolHas and not eligible then
pool:remove(e)
pool.removed[#pool.removed + 1] = e
- self:entityRemovedFrom(e, pool)
self:__tryRemove(e)
end
end
@@ -96,12 +91,10 @@ function System:__remove(e)
if pool:has(e) then
pool:remove(e)
pool.removed[#pool.removed + 1] = e
- self:entityRemovedFrom(e, pool)
end
end
self.__all[e] = nil
- self:entityRemoved(e)
end
end
@@ -110,7 +103,6 @@ end
function System:__tryAdd(e)
if not self.__all[e] then
self.__all[e] = 0
- self:entityAdded(e)
end
self.__all[e] = self.__all[e] + 1
@@ -124,13 +116,11 @@ function System:__tryRemove(e)
if self.__all[e] == 0 then
self.__all[e] = nil
- self:entityRemoved(e)
end
end
end
-function System:flush()
- self:clear()
+function System:flush() -- luacheck: ignore
end
function System:clear()
@@ -147,44 +137,22 @@ end
--- Default callback for system initialization.
-- @param ... Varags
-function System:init(...)
-end
-
---- Default callback for adding an Entity.
--- @param e The Entity that was added
-function System:entityAdded(e)
-end
-
---- Default callback for adding an Entity to a pool.
--- @param e The Entity that was added
--- @param pool The pool the Entity was added to
-function System:entityAddedTo(e, pool)
-end
-
---- Default callback for removing an Entity.
--- @param e The Entity that was removed
-function System:entityRemoved(e)
-end
-
---- Default callback for removing an Entity from a pool.
--- @param e The Entity that was removed
--- @param pool The pool the Entity was removed from
-function System:entityRemovedFrom(e, pool)
+function System:init(...) -- luacheck: ignore
end
-- Default callback for when the System is added to an Instance.
-- @param instance The Instance the System was added to
-function System:addedTo(instance)
+function System:addedTo(instance) -- luacheck: ignore
end
-- Default callback for when a System's callback is enabled.
-- @param callbackName The name of the callback that was enabled
-function System:enabledCallback(callbackName)
+function System:enabledCallback(callbackName) -- luacheck: ignore
end
-- Default callback for when a System's callback is disabled.
-- @param callbackName The name of the callback that was disabled
-function System:disabledCallback(callbackName)
+function System:disabledCallback(callbackName) -- luacheck: ignore
end
return setmetatable(System, {
diff --git a/lib/type.lua b/lib/type.lua
index 204aa79..80d14b0 100644
--- a/lib/type.lua
+++ b/lib/type.lua
@@ -16,4 +16,8 @@ function Type.isInstance(t)
return type(t) == "table" and t.__isInstance
end
-return Type
\ No newline at end of file
+function Type.isAssemblage(t)
+ return type(t) == "table" and t.__isAssemblage
+end
+
+return Type
diff --git a/main.lua b/main.lua
index c809a1f..ce78707 100644
--- a/main.lua
+++ b/main.lua
@@ -1,4 +1,4 @@
local file = "examples.simpleDrawing"
-- local file = "examples.baseLayout.main"
-require(file)
\ No newline at end of file
+require(file)
From 6ddb28ffbce89f8afe9639fa9d8a3cf03818aa53 Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Mon, 26 Nov 2018 12:37:28 +0100
Subject: [PATCH 003/113] Small fixes
---
LICENSE | 40 ++++++++++++------------
README.md | 78 +++++++++++++++++++++++-----------------------
lib/assemblage.lua | 6 ++--
lib/component.lua | 4 ++-
lib/entity.lua | 4 ++-
lib/init.lua | 8 +++--
lib/instance.lua | 4 ++-
lib/list.lua | 4 ++-
lib/pool.lua | 4 ++-
lib/system.lua | 4 ++-
10 files changed, 85 insertions(+), 71 deletions(-)
diff --git a/LICENSE b/LICENSE
index e3ce12d..8771a88 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,21 @@
-MIT License
-
-Copyright (c) 2018 Justin van der Leij
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+MIT License
+
+Copyright (c) 2018 Justin van der Leij
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index d2187ef..32f0383 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,39 @@
-# Concord
-
-Concord is a feature complete ECS.
-It's main focus is on speed and usage. You should be able to quickly write code that performs well.
-
-Documentation for Concord can be found in the [Wiki tab](https://github.com/Tjakka5/Concord/wiki).
-
-Auto generated docs for Concord can be found in the [Github page](https://tjakka5.github.io/Concord/). These are still work in progress and might be incomplete though.
-
-## Installation
-Download the repository and drop it in your project, then simply require it as:
-```lua
-local Concord = require(PathToConcord).init()
-
-You will only need to call .init once when you first require it.
-```
-
-## Modules
-Below is a list of modules.
-More information about what each done can be found in the Wiki
-
-```lua
-local Concord = require("concord")
-local Entity = require("concord.entity")
-local Component = require("concord.component")
-local System = require("concord.system")
-local Instance = require("concord.instance")
-```
-
-## Contributors
-```
-Positive07: Constant support and a good rubberduck
-Brbl: Early testing and issue reporting
-Josh: Squashed a few bugs and docs
-Erasio: Took inspiration from HooECS. Also introduced me to ECS.
-```
-
-## Licence
-MIT Licensed - Copyright Justin van der Leij (Tjakka5)
+# Concord
+
+Concord is a feature complete ECS.
+It's main focus is on speed and usage. You should be able to quickly write code that performs well.
+
+Documentation for Concord can be found in the [Wiki tab](https://github.com/Tjakka5/Concord/wiki).
+
+Auto generated docs for Concord can be found in the [Github page](https://tjakka5.github.io/Concord/). These are still work in progress and might be incomplete though.
+
+## Installation
+Download the repository and drop it in your project, then simply require it as:
+```lua
+local Concord = require(PathToConcord).init()
+
+You will only need to call .init once when you first require it.
+```
+
+## Modules
+Below is a list of modules.
+More information about what each done can be found in the Wiki
+
+```lua
+local Concord = require("concord")
+local Entity = require("concord.entity")
+local Component = require("concord.component")
+local System = require("concord.system")
+local Instance = require("concord.instance")
+```
+
+## Contributors
+```
+Positive07: Constant support and a good rubberduck
+Brbl: Early testing and issue reporting
+Josh: Squashed a few bugs and docs
+Erasio: Took inspiration from HooECS. Also introduced me to ECS.
+```
+
+## Licence
+MIT Licensed - Copyright Justin van der Leij (Tjakka5)
diff --git a/lib/assemblage.lua b/lib/assemblage.lua
index 67a1428..79b3cbb 100644
--- a/lib/assemblage.lua
+++ b/lib/assemblage.lua
@@ -10,8 +10,6 @@ function Assemblage.new(assemble)
__isAssemblage = true,
}, Assemblage)
- Assemblage.__mt = {__index = assemblage}
-
return assemblage
end
@@ -22,5 +20,7 @@ function Assemblage:assemble(e, ...)
end
return setmetatable(Assemblage, {
- __call = function(_, ...) return Assemblage.new(...) end,
+ __call = function(_, ...)
+ return Assemblage.new(...)
+ end,
})
diff --git a/lib/component.lua b/lib/component.lua
index 5696968..63cb1fb 100644
--- a/lib/component.lua
+++ b/lib/component.lua
@@ -33,5 +33,7 @@ function Component:__initialize(...)
end
return setmetatable(Component, {
- __call = function(_, ...) return Component.new(...) end,
+ __call = function(_, ...)
+ return Component.new(...)
+ end,
})
diff --git a/lib/entity.lua b/lib/entity.lua
index 441b9df..9cabe33 100644
--- a/lib/entity.lua
+++ b/lib/entity.lua
@@ -136,5 +136,7 @@ function Entity:has(component)
end
return setmetatable(Entity, {
- __call = function(_, ...) return Entity.new(...) end,
+ __call = function(_, ...)
+ return Entity.new(...)
+ end,
})
diff --git a/lib/init.lua b/lib/init.lua
index 81887fb..61eb5e8 100644
--- a/lib/init.lua
+++ b/lib/init.lua
@@ -61,9 +61,11 @@ function Concord.init(settings)
error("bad argument #1 to 'Concord.addInstance' (Instance expected, got "..type(instance)..")", 2)
end
- for i, instance in ipairs(Concord.instances) do
- table.remove(Concord.instances, i)
- break
+ for i, _instance in ipairs(Concord.instances) do
+ if (instance == _instance) then
+ table.remove(Concord.instances, i)
+ break
+ end
end
end
diff --git a/lib/instance.lua b/lib/instance.lua
index fa59c35..571bfa4 100644
--- a/lib/instance.lua
+++ b/lib/instance.lua
@@ -282,5 +282,7 @@ function Instance:onEntityRemoved(e) -- luacheck: ignore
end
return setmetatable(Instance, {
- __call = function(_, ...) return Instance.new(...) end,
+ __call = function(_, ...)
+ return Instance.new(...)
+ end,
})
diff --git a/lib/list.lua b/lib/list.lua
index a5698c9..a79d20e 100644
--- a/lib/list.lua
+++ b/lib/list.lua
@@ -77,5 +77,7 @@ function List:has(obj)
end
return setmetatable(List, {
- __call = function() return List.new() end,
+ __call = function()
+ return List.new()
+ end,
})
diff --git a/lib/pool.lua b/lib/pool.lua
index e7e949c..779efd9 100644
--- a/lib/pool.lua
+++ b/lib/pool.lua
@@ -46,5 +46,7 @@ end
return setmetatable(Pool, {
__index = List,
- __call = function(_, ...) return Pool.new(...) end,
+ __call = function(_, ...)
+ return Pool.new(...)
+ end,
})
diff --git a/lib/system.lua b/lib/system.lua
index a42f79b..4572aa6 100644
--- a/lib/system.lua
+++ b/lib/system.lua
@@ -156,5 +156,7 @@ function System:disabledCallback(callbackName) -- luacheck: ignore
end
return setmetatable(System, {
- __call = function(_, ...) return System.new(...) end,
+ __call = function(_, ...)
+ return System.new(...)
+ end,
})
From 39ec2106b7c0ef245885b4a92669ccd3ed9f0b5c Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Mon, 26 Nov 2018 12:43:48 +0100
Subject: [PATCH 004/113] Removed .init
---
examples/assemblageTest/init.lua | 6 ++--
examples/baseLayout/main.lua | 6 ++--
examples/simpleDrawing/init.lua | 15 ++++++---
lib/init.lua | 48 +++-------------------------
lib/run.lua | 55 --------------------------------
lib/type.lua | 2 ++
6 files changed, 22 insertions(+), 110 deletions(-)
delete mode 100644 lib/run.lua
diff --git a/examples/assemblageTest/init.lua b/examples/assemblageTest/init.lua
index 730129b..444d37b 100644
--- a/examples/assemblageTest/init.lua
+++ b/examples/assemblageTest/init.lua
@@ -1,13 +1,11 @@
-local Concord = require("lib").init({
- useEvents = true
-})
+local Concord = require("lib")
+
local Entity = Concord.entity
local Component = Concord.component
local System = Concord.system
local Assemblage = Concord.assemblage
local Game = Concord.instance()
-Concord.addInstance(Game)
local Legs = Component(function(e, legCount)
e.legCount = legCount or 0
diff --git a/examples/baseLayout/main.lua b/examples/baseLayout/main.lua
index ed6e30d..b4785c2 100644
--- a/examples/baseLayout/main.lua
+++ b/examples/baseLayout/main.lua
@@ -1,8 +1,6 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Concord = require("lib").init({
- useEvents = true
-})
+local Concord = require("lib")
local C = require(PATH..".src.components")
-local S = require(PATH..".src.systems")
\ No newline at end of file
+local S = require(PATH..".src.systems")
diff --git a/examples/simpleDrawing/init.lua b/examples/simpleDrawing/init.lua
index 8cc0426..5eca907 100644
--- a/examples/simpleDrawing/init.lua
+++ b/examples/simpleDrawing/init.lua
@@ -1,12 +1,10 @@
-local Concord = require("lib").init({
- useEvents = true
-})
+local Concord = require("lib")
+
local Entity = Concord.entity
local Component = Concord.component
local System = Concord.system
local Game = Concord.instance()
-Concord.addInstance(Game)
local Position = Component(function(e, x, y)
e.x = x
@@ -118,3 +116,12 @@ for _ = 1, 100 do
Game:addEntity(e)
end
+
+
+function love.update(dt)
+ Game:emit("update", dt)
+end
+
+function love.draw()
+ Game:emit("draw")
+end
diff --git a/lib/init.lua b/lib/init.lua
index 61eb5e8..528dd91 100644
--- a/lib/init.lua
+++ b/lib/init.lua
@@ -2,8 +2,6 @@
local PATH = (...):gsub('%.init$', '')
-local Type = require(PATH..".type")
-
local Concord = {
_VERSION = "1.0",
_DESCRIPTION = "A feature-complete ECS library",
@@ -33,46 +31,10 @@ local Concord = {
]]
}
---- Initializes the library with some optional settings
--- @param settings Table of settings: {
--- useEvents Flag to overwrite love.run and use events. Defaults to false
--- }
--- @return Concord
-function Concord.init(settings)
- Concord.entity = require(PATH..".entity")
- Concord.component = require(PATH..".component")
- Concord.system = require(PATH..".system")
- Concord.instance = require(PATH..".instance")
- Concord.assemblage = require(PATH..".assemblage")
-
- if settings and settings.useEvents then
- Concord.instances = {}
-
- Concord.addInstance = function(instance)
- if not Type.isInstance(instance) then
- error("bad argument #1 to 'Concord.addInstance' (Instance expected, got "..type(instance)..")", 2)
- end
-
- table.insert(Concord.instances, instance)
- end
-
- Concord.removeInstance = function(instance)
- if not Type.isInstance(instance) then
- error("bad argument #1 to 'Concord.addInstance' (Instance expected, got "..type(instance)..")", 2)
- end
-
- for i, _instance in ipairs(Concord.instances) do
- if (instance == _instance) then
- table.remove(Concord.instances, i)
- break
- end
- end
- end
-
- love.run = require(PATH..".run")
- end
-
- return Concord
-end
+Concord.entity = require(PATH..".entity")
+Concord.component = require(PATH..".component")
+Concord.system = require(PATH..".system")
+Concord.instance = require(PATH..".instance")
+Concord.assemblage = require(PATH..".assemblage")
return Concord
diff --git a/lib/run.lua b/lib/run.lua
deleted file mode 100644
index 5ad1ce7..0000000
--- a/lib/run.lua
+++ /dev/null
@@ -1,55 +0,0 @@
-local PATH = (...):gsub('%.[^%.]+$', '')
-
-local Concord = require(PATH)
-
-return function()
- if love.math then
- love.math.setRandomSeed(os.time())
- love.timer.step()
- end
-
- for _, instance in ipairs(Concord.instances) do
- instance:emit("load", arg)
- end
-
- if love.timer then love.timer.step() end
-
- local dt = 0
-
- return function()
- if love.event then
- love.event.pump()
- for name, a, b, c, d, e, f in love.event.poll() do
- for _, instance in ipairs(Concord.instances) do
- instance:emit(name, a, b, c, d, e, f)
- end
-
- if name == "quit" then
- return a or 0
- end
- end
- end
-
- if love.timer then
- love.timer.step()
- dt = love.timer.getDelta()
- end
-
- for _, instance in ipairs(Concord.instances) do
- instance:emit("update", dt)
- end
-
- if love.graphics and love.graphics.isActive() then
- love.graphics.clear(love.graphics.getBackgroundColor())
- love.graphics.origin()
-
- for _, instance in ipairs(Concord.instances) do
- instance:emit("draw")
- end
-
- love.graphics.present()
- end
-
- if love.timer then love.timer.sleep(0.001) end
- end
-end
\ No newline at end of file
diff --git a/lib/type.lua b/lib/type.lua
index 80d14b0..ba52b02 100644
--- a/lib/type.lua
+++ b/lib/type.lua
@@ -1,3 +1,5 @@
+-- Type
+
local Type = {}
function Type.isComponent(t)
From 89a3a7fa8a94c603eacfcf1c9ac3189e7f029f86 Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Mon, 26 Nov 2018 12:45:24 +0100
Subject: [PATCH 005/113] Rename 'lib' directory to 'src'
---
{lib => src}/assemblage.lua | 0
{lib => src}/component.lua | 0
{lib => src}/entity.lua | 0
{lib => src}/init.lua | 0
{lib => src}/instance.lua | 0
{lib => src}/list.lua | 0
{lib => src}/pool.lua | 0
{lib => src}/system.lua | 0
{lib => src}/type.lua | 0
9 files changed, 0 insertions(+), 0 deletions(-)
rename {lib => src}/assemblage.lua (100%)
rename {lib => src}/component.lua (100%)
rename {lib => src}/entity.lua (100%)
rename {lib => src}/init.lua (100%)
rename {lib => src}/instance.lua (100%)
rename {lib => src}/list.lua (100%)
rename {lib => src}/pool.lua (100%)
rename {lib => src}/system.lua (100%)
rename {lib => src}/type.lua (100%)
diff --git a/lib/assemblage.lua b/src/assemblage.lua
similarity index 100%
rename from lib/assemblage.lua
rename to src/assemblage.lua
diff --git a/lib/component.lua b/src/component.lua
similarity index 100%
rename from lib/component.lua
rename to src/component.lua
diff --git a/lib/entity.lua b/src/entity.lua
similarity index 100%
rename from lib/entity.lua
rename to src/entity.lua
diff --git a/lib/init.lua b/src/init.lua
similarity index 100%
rename from lib/init.lua
rename to src/init.lua
diff --git a/lib/instance.lua b/src/instance.lua
similarity index 100%
rename from lib/instance.lua
rename to src/instance.lua
diff --git a/lib/list.lua b/src/list.lua
similarity index 100%
rename from lib/list.lua
rename to src/list.lua
diff --git a/lib/pool.lua b/src/pool.lua
similarity index 100%
rename from lib/pool.lua
rename to src/pool.lua
diff --git a/lib/system.lua b/src/system.lua
similarity index 100%
rename from lib/system.lua
rename to src/system.lua
diff --git a/lib/type.lua b/src/type.lua
similarity index 100%
rename from lib/type.lua
rename to src/type.lua
From 26bd0ef93732812f2e760f32e132c501a5725170 Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Mon, 26 Nov 2018 12:58:41 +0100
Subject: [PATCH 006/113] Rename 'instance' to 'context'
---
examples/assemblageTest/init.lua | 4 +-
examples/baseLayout/main.lua | 2 +-
examples/simpleDrawing/init.lua | 4 +-
src/{instance.lua => context.lua} | 102 +++++++++++++++---------------
src/entity.lua | 10 +--
src/init.lua | 2 +-
src/system.lua | 16 ++---
src/type.lua | 4 +-
8 files changed, 72 insertions(+), 72 deletions(-)
rename src/{instance.lua => context.lua} (67%)
diff --git a/examples/assemblageTest/init.lua b/examples/assemblageTest/init.lua
index 444d37b..01adb8b 100644
--- a/examples/assemblageTest/init.lua
+++ b/examples/assemblageTest/init.lua
@@ -1,11 +1,11 @@
-local Concord = require("lib")
+local Concord = require("src")
local Entity = Concord.entity
local Component = Concord.component
local System = Concord.system
local Assemblage = Concord.assemblage
-local Game = Concord.instance()
+local Game = Concord.context()
local Legs = Component(function(e, legCount)
e.legCount = legCount or 0
diff --git a/examples/baseLayout/main.lua b/examples/baseLayout/main.lua
index b4785c2..6d6717f 100644
--- a/examples/baseLayout/main.lua
+++ b/examples/baseLayout/main.lua
@@ -1,6 +1,6 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Concord = require("lib")
+local Concord = require("src")
local C = require(PATH..".src.components")
local S = require(PATH..".src.systems")
diff --git a/examples/simpleDrawing/init.lua b/examples/simpleDrawing/init.lua
index 5eca907..cbf7ac5 100644
--- a/examples/simpleDrawing/init.lua
+++ b/examples/simpleDrawing/init.lua
@@ -1,10 +1,10 @@
-local Concord = require("lib")
+local Concord = require("src")
local Entity = Concord.entity
local Component = Concord.component
local System = Concord.system
-local Game = Concord.instance()
+local Game = Concord.context()
local Position = Component(function(e, x, y)
e.x = x
diff --git a/src/instance.lua b/src/context.lua
similarity index 67%
rename from src/instance.lua
rename to src/context.lua
index 571bfa4..3c9e931 100644
--- a/src/instance.lua
+++ b/src/context.lua
@@ -1,17 +1,17 @@
---- Instance
+--- Context
local PATH = (...):gsub('%.[^%.]+$', '')
local Type = require(PATH..".type")
local List = require(PATH..".list")
-local Instance = {}
-Instance.__index = Instance
+local Context = {}
+Context.__index = Context
---- Creates a new Instance.
--- @return The new instance
-function Instance.new()
- local instance = setmetatable({
+--- Creates a new Context.
+-- @return The new context
+function Context.new()
+ local context = setmetatable({
entities = List(),
systems = List(),
events = {},
@@ -19,35 +19,35 @@ function Instance.new()
marked = {},
removed = {},
- __isInstance = true,
- }, Instance)
+ __isContext = true,
+ }, Context)
- return instance
+ return context
end
---- Adds an Entity to the Instance.
+--- Adds an Entity to the Context.
-- @param e The Entity to add
-- @return self
-function Instance:addEntity(e)
+function Context:addEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Instance:addEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'Context:addEntity' (Entity expected, got "..type(e)..")", 2)
end
self:onEntityAdded(e)
- e.instances:add(self)
+ e.contexts:add(self)
self.entities:add(e)
self:checkEntity(e)
return self
end
---- Marks an Entity as removed from the Instance.
+--- Marks an Entity as removed from the Context.
-- @param e The Entity to mark
-- @return self
-function Instance:removeEntity(e)
+function Context:removeEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Instance:removeEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'Context:removeEntity' (Entity expected, got "..type(e)..")", 2)
end
self.removed[#self.removed + 1] = e
@@ -55,9 +55,9 @@ function Instance:removeEntity(e)
return self
end
-function Instance:markEntity(e)
+function Context:markEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Instance:markEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'Context:markEntity' (Entity expected, got "..type(e)..")", 2)
end
self.marked[#self.marked + 1] = e
@@ -65,12 +65,12 @@ function Instance:markEntity(e)
return self
end
---- Checks an Entity against all the systems in the Instance.
+--- Checks an Entity against all the systems in the Context.
-- @param e The Entity to check
-- @return self
-function Instance:checkEntity(e)
+function Context:checkEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Instance:checkEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'Context:checkEntity' (Entity expected, got "..type(e)..")", 2)
end
for i = 1, self.systems.size do
@@ -80,9 +80,9 @@ function Instance:checkEntity(e)
return self
end
---- Completely removes all marked Entities in the Instance.
+--- Completely removes all marked Entities in the Context.
-- @return self
-function Instance:flush()
+function Context:flush()
while #self.marked > 0 do
local marked = self.removed
self.removed = {}
@@ -90,8 +90,8 @@ function Instance:flush()
for i = 1, #marked do
local e = marked[i]
- e.instances:apply()
- e.instances:checkEntity(e)
+ e.contexts:apply()
+ e.contexts:checkEntity(e)
end
end
@@ -102,7 +102,7 @@ function Instance:flush()
for i = 1, #removed do
local e = removed[i]
- e.instances:remove(self)
+ e.contexts:remove(self)
self.entities:remove(e)
for j = 1, self.systems.size do
@@ -122,24 +122,24 @@ function Instance:flush()
return self
end
---- Adds a System to the Instance.
+--- Adds a System to the Context.
-- @param system The System to add
-- @param eventName The Event to register to
-- @param callback The function name to call. Defaults to eventName
-- @param enabled If the system is enabled. Defaults to true
-- @return self
-function Instance:addSystem(system, eventName, callback, enabled)
+function Context:addSystem(system, eventName, callback, enabled)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Instance:addSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'Context:addSystem' (System expected, got "..type(system)..")", 2)
end
- if system.__instance and system.__instance ~= self then
- error("System already in instance '" ..tostring(system.__instance).."'")
+ if system.__context and system.__context ~= self then
+ error("System already in context '" ..tostring(system.__context).."'")
end
if not self.systems:has(system) then
self.systems:add(system)
- system.__instance = self
+ system.__context = self
system:addedTo(self)
end
@@ -169,41 +169,41 @@ function Instance:addSystem(system, eventName, callback, enabled)
return self
end
---- Enables a System in the Instance.
+--- Enables a System in the Context.
-- @param system The System to enable
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @return self
-function Instance:enableSystem(system, eventName, callback)
+function Context:enableSystem(system, eventName, callback)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Instance:enableSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'Context:enableSystem' (System expected, got "..type(system)..")", 2)
end
return self:setSystem(system, eventName, callback, true)
end
---- Disables a System in the Instance.
+--- Disables a System in the Context.
-- @param system The System to disable
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @return self
-function Instance:disableSystem(system, eventName, callback)
+function Context:disableSystem(system, eventName, callback)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Instance:disableSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'Context:disableSystem' (System expected, got "..type(system)..")", 2)
end
return self:setSystem(system, eventName, callback, false)
end
---- Sets a System 'enable' in the Instance.
+--- Sets a System 'enable' in the Context.
-- @param system The System to set
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @param enable The state to set it to
-- @return self
-function Instance:setSystem(system, eventName, callback, enable)
+function Context:setSystem(system, eventName, callback, enable)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Instance:setSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'Context:setSystem' (System expected, got "..type(system)..")", 2)
end
callback = callback or eventName
@@ -233,13 +233,13 @@ function Instance:setSystem(system, eventName, callback, enable)
return self
end
---- Emits an Event in the Instance.
+--- Emits an Event in the Context.
-- @param eventName The Event that should be emitted
-- @param ... Parameters passed to listeners
-- @return self
-function Instance:emit(eventName, ...)
+function Context:emit(eventName, ...)
if not eventName or type(eventName) ~= "string" then
- error("bad argument #1 to 'Instance:emit' (String expected, got "..type(eventName)..")")
+ error("bad argument #1 to 'Context:emit' (String expected, got "..type(eventName)..")")
end
self:flush()
@@ -259,9 +259,9 @@ function Instance:emit(eventName, ...)
return self
end
---- Removes all entities from the Instance
+--- Removes all entities from the Context
-- @return self
-function Instance:clear()
+function Context:clear()
for i = 1, self.entities.size do
self.entities:get(i):destroy()
end
@@ -273,16 +273,16 @@ end
--- Default callback for adding an Entity.
-- @param e The Entity that was added
-function Instance:onEntityAdded(e) -- luacheck: ignore
+function Context:onEntityAdded(e) -- luacheck: ignore
end
--- Default callback for removing an Entity.
-- @param e The Entity that was removed
-function Instance:onEntityRemoved(e) -- luacheck: ignore
+function Context:onEntityRemoved(e) -- luacheck: ignore
end
-return setmetatable(Instance, {
+return setmetatable(Context, {
__call = function(_, ...)
- return Instance.new(...)
+ return Context.new(...)
end,
})
diff --git a/src/entity.lua b/src/entity.lua
index 9cabe33..0f2da8f 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -13,7 +13,7 @@ Entity.__index = Entity
function Entity.new()
local e = setmetatable({
removed = {},
- instances = List(),
+ contexts = List(),
__isEntity = true,
}, Entity)
@@ -86,8 +86,8 @@ function Entity:assemble(assemblage, ...)
end
function Entity:mark()
- for i = 1, self.instances.size do
- self.instances:get(i):markEntity(self)
+ for i = 1, self.contexts.size do
+ self.contexts:get(i):markEntity(self)
end
end
@@ -106,8 +106,8 @@ end
--- Destroys the Entity.
-- @return self
function Entity:destroy()
- for i = 1, self.instances.size do
- self.instances:get(i):removeEntity(self)
+ for i = 1, self.contexts.size do
+ self.contexts:get(i):removeEntity(self)
end
return self
diff --git a/src/init.lua b/src/init.lua
index 528dd91..ad55f50 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -34,7 +34,7 @@ local Concord = {
Concord.entity = require(PATH..".entity")
Concord.component = require(PATH..".component")
Concord.system = require(PATH..".system")
-Concord.instance = require(PATH..".instance")
+Concord.context = require(PATH..".context")
Concord.assemblage = require(PATH..".assemblage")
return Concord
diff --git a/src/system.lua b/src/system.lua
index 4572aa6..2eebe28 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -11,7 +11,7 @@ System.mt = {
local system = setmetatable({
__all = {},
__pools = {},
- __instance = nil,
+ __context = nil,
__isSystem = true,
}, systemProto)
@@ -129,10 +129,10 @@ function System:clear()
end
end
---- Returns the Instance the System is in.
--- @return The Instance
-function System:getInstance()
- return self.__instance
+--- Returns the Context the System is in.
+-- @return The Context
+function System:getContext()
+ return self.__context
end
--- Default callback for system initialization.
@@ -140,9 +140,9 @@ end
function System:init(...) -- luacheck: ignore
end
--- Default callback for when the System is added to an Instance.
--- @param instance The Instance the System was added to
-function System:addedTo(instance) -- luacheck: ignore
+-- Default callback for when the System is added to an Context.
+-- @param context The Context the System was added to
+function System:addedTo(context) -- luacheck: ignore
end
-- Default callback for when a System's callback is enabled.
diff --git a/src/type.lua b/src/type.lua
index ba52b02..999c42c 100644
--- a/src/type.lua
+++ b/src/type.lua
@@ -14,8 +14,8 @@ function Type.isSystem(t)
return type(t) == "table" and t.__isSystem
end
-function Type.isInstance(t)
- return type(t) == "table" and t.__isInstance
+function Type.isContext(t)
+ return type(t) == "table" and t.__isContext
end
function Type.isAssemblage(t)
From 83162ec02c9ff0ca8eb8211dfa1d612c7f80e603 Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Thu, 29 Nov 2018 22:04:50 +0100
Subject: [PATCH 007/113] Rename 'context' to 'world'
---
examples/simpleDrawing/init.lua | 4 +-
src/entity.lua | 11 ++--
src/init.lua | 4 +-
src/system.lua | 20 +++----
src/{context.lua => world.lua} | 102 ++++++++++++++++----------------
5 files changed, 69 insertions(+), 72 deletions(-)
rename src/{context.lua => world.lua} (66%)
diff --git a/examples/simpleDrawing/init.lua b/examples/simpleDrawing/init.lua
index cbf7ac5..29b31d1 100644
--- a/examples/simpleDrawing/init.lua
+++ b/examples/simpleDrawing/init.lua
@@ -4,7 +4,7 @@ local Entity = Concord.entity
local Component = Concord.component
local System = Concord.system
-local Game = Concord.context()
+local Game = Concord.world()
local Position = Component(function(e, x, y)
e.x = x
@@ -48,8 +48,6 @@ function CircleRenderer:flush()
for _, e in ipairs(self.pool.removed) do
print(tostring(e).. " was removed from my pool D:")
end
-
- self:clear()
end
function CircleRenderer:draw()
diff --git a/src/entity.lua b/src/entity.lua
index 0f2da8f..62d64c4 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -13,7 +13,7 @@ Entity.__index = Entity
function Entity.new()
local e = setmetatable({
removed = {},
- contexts = List(),
+ worlds = List(),
__isEntity = true,
}, Entity)
@@ -86,8 +86,8 @@ function Entity:assemble(assemblage, ...)
end
function Entity:mark()
- for i = 1, self.contexts.size do
- self.contexts:get(i):markEntity(self)
+ for i = 1, self.worlds.size do
+ self.worlds:get(i):markEntity(self)
end
end
@@ -96,7 +96,6 @@ function Entity:apply()
local component = self.removed[i]
self[component] = nil
-
self.removed[i] = nil
end
@@ -106,8 +105,8 @@ end
--- Destroys the Entity.
-- @return self
function Entity:destroy()
- for i = 1, self.contexts.size do
- self.contexts:get(i):removeEntity(self)
+ for i = 1, self.worlds.size do
+ self.worlds:get(i):removeEntity(self)
end
return self
diff --git a/src/init.lua b/src/init.lua
index ad55f50..e13f190 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -3,7 +3,7 @@
local PATH = (...):gsub('%.init$', '')
local Concord = {
- _VERSION = "1.0",
+ _VERSION = "2.0 Beta",
_DESCRIPTION = "A feature-complete ECS library",
_LICENCE = [[
MIT LICENSE
@@ -34,7 +34,7 @@ local Concord = {
Concord.entity = require(PATH..".entity")
Concord.component = require(PATH..".component")
Concord.system = require(PATH..".system")
-Concord.context = require(PATH..".context")
+Concord.world = require(PATH..".world")
Concord.assemblage = require(PATH..".assemblage")
return Concord
diff --git a/src/system.lua b/src/system.lua
index 2eebe28..10729da 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -9,9 +9,9 @@ System.mt = {
__index = System,
__call = function(systemProto, ...)
local system = setmetatable({
- __all = {},
- __pools = {},
- __context = nil,
+ __all = {},
+ __pools = {},
+ __world = nil,
__isSystem = true,
}, systemProto)
@@ -129,10 +129,10 @@ function System:clear()
end
end
---- Returns the Context the System is in.
--- @return The Context
-function System:getContext()
- return self.__context
+--- Returns the World the System is in.
+-- @return The world the system is in
+function System:getWorld()
+ return self.__world
end
--- Default callback for system initialization.
@@ -140,9 +140,9 @@ end
function System:init(...) -- luacheck: ignore
end
--- Default callback for when the System is added to an Context.
--- @param context The Context the System was added to
-function System:addedTo(context) -- luacheck: ignore
+-- Default callback for when the System is added to an World.
+-- @param world The World the System was added to
+function System:addedTo(World) -- luacheck: ignore
end
-- Default callback for when a System's callback is enabled.
diff --git a/src/context.lua b/src/world.lua
similarity index 66%
rename from src/context.lua
rename to src/world.lua
index 3c9e931..59305fa 100644
--- a/src/context.lua
+++ b/src/world.lua
@@ -1,17 +1,17 @@
---- Context
+--- World
local PATH = (...):gsub('%.[^%.]+$', '')
local Type = require(PATH..".type")
local List = require(PATH..".list")
-local Context = {}
-Context.__index = Context
+local World = {}
+World.__index = World
---- Creates a new Context.
--- @return The new context
-function Context.new()
- local context = setmetatable({
+--- Creates a new World.
+-- @return The new World
+function World.new()
+ local world = setmetatable({
entities = List(),
systems = List(),
events = {},
@@ -19,35 +19,35 @@ function Context.new()
marked = {},
removed = {},
- __isContext = true,
- }, Context)
+ __isWorld = true,
+ }, World)
- return context
+ return world
end
---- Adds an Entity to the Context.
+--- Adds an Entity to the World.
-- @param e The Entity to add
-- @return self
-function Context:addEntity(e)
+function World:addEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Context:addEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'World:addEntity' (Entity expected, got "..type(e)..")", 2)
end
self:onEntityAdded(e)
- e.contexts:add(self)
+ e.worlds:add(self)
self.entities:add(e)
self:checkEntity(e)
return self
end
---- Marks an Entity as removed from the Context.
+--- Marks an Entity as removed from the World.
-- @param e The Entity to mark
-- @return self
-function Context:removeEntity(e)
+function World:removeEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Context:removeEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'World:removeEntity' (Entity expected, got "..type(e)..")", 2)
end
self.removed[#self.removed + 1] = e
@@ -55,9 +55,9 @@ function Context:removeEntity(e)
return self
end
-function Context:markEntity(e)
+function World:markEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Context:markEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'World:markEntity' (Entity expected, got "..type(e)..")", 2)
end
self.marked[#self.marked + 1] = e
@@ -65,12 +65,12 @@ function Context:markEntity(e)
return self
end
---- Checks an Entity against all the systems in the Context.
+--- Checks an Entity against all the systems in the World.
-- @param e The Entity to check
-- @return self
-function Context:checkEntity(e)
+function World:checkEntity(e)
if not Type.isEntity(e) then
- error("bad argument #1 to 'Context:checkEntity' (Entity expected, got "..type(e)..")", 2)
+ error("bad argument #1 to 'World:checkEntity' (Entity expected, got "..type(e)..")", 2)
end
for i = 1, self.systems.size do
@@ -80,9 +80,9 @@ function Context:checkEntity(e)
return self
end
---- Completely removes all marked Entities in the Context.
+--- Completely removes all marked Entities in the World.
-- @return self
-function Context:flush()
+function World:flush()
while #self.marked > 0 do
local marked = self.removed
self.removed = {}
@@ -90,8 +90,8 @@ function Context:flush()
for i = 1, #marked do
local e = marked[i]
- e.contexts:apply()
- e.contexts:checkEntity(e)
+ e.Worlds:apply()
+ e.Worlds:checkEntity(e)
end
end
@@ -102,7 +102,7 @@ function Context:flush()
for i = 1, #removed do
local e = removed[i]
- e.contexts:remove(self)
+ e.worlds:remove(self)
self.entities:remove(e)
for j = 1, self.systems.size do
@@ -122,24 +122,24 @@ function Context:flush()
return self
end
---- Adds a System to the Context.
+--- Adds a System to the World.
-- @param system The System to add
-- @param eventName The Event to register to
-- @param callback The function name to call. Defaults to eventName
-- @param enabled If the system is enabled. Defaults to true
-- @return self
-function Context:addSystem(system, eventName, callback, enabled)
+function World:addSystem(system, eventName, callback, enabled)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Context:addSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'World:addSystem' (System expected, got "..type(system)..")", 2)
end
- if system.__context and system.__context ~= self then
- error("System already in context '" ..tostring(system.__context).."'")
+ if system.__World and system.__World ~= self then
+ error("System already in World '" ..tostring(system.__World).."'")
end
if not self.systems:has(system) then
self.systems:add(system)
- system.__context = self
+ system.__World = self
system:addedTo(self)
end
@@ -169,41 +169,41 @@ function Context:addSystem(system, eventName, callback, enabled)
return self
end
---- Enables a System in the Context.
+--- Enables a System in the World.
-- @param system The System to enable
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @return self
-function Context:enableSystem(system, eventName, callback)
+function World:enableSystem(system, eventName, callback)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Context:enableSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'World:enableSystem' (System expected, got "..type(system)..")", 2)
end
return self:setSystem(system, eventName, callback, true)
end
---- Disables a System in the Context.
+--- Disables a System in the World.
-- @param system The System to disable
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @return self
-function Context:disableSystem(system, eventName, callback)
+function World:disableSystem(system, eventName, callback)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Context:disableSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'World:disableSystem' (System expected, got "..type(system)..")", 2)
end
return self:setSystem(system, eventName, callback, false)
end
---- Sets a System 'enable' in the Context.
+--- Sets a System 'enable' in the World.
-- @param system The System to set
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @param enable The state to set it to
-- @return self
-function Context:setSystem(system, eventName, callback, enable)
+function World:setSystem(system, eventName, callback, enable)
if not Type.isSystem(system) then
- error("bad argument #1 to 'Context:setSystem' (System expected, got "..type(system)..")", 2)
+ error("bad argument #1 to 'World:setSystem' (System expected, got "..type(system)..")", 2)
end
callback = callback or eventName
@@ -233,13 +233,13 @@ function Context:setSystem(system, eventName, callback, enable)
return self
end
---- Emits an Event in the Context.
+--- Emits an Event in the World.
-- @param eventName The Event that should be emitted
-- @param ... Parameters passed to listeners
-- @return self
-function Context:emit(eventName, ...)
+function World:emit(eventName, ...)
if not eventName or type(eventName) ~= "string" then
- error("bad argument #1 to 'Context:emit' (String expected, got "..type(eventName)..")")
+ error("bad argument #1 to 'World:emit' (String expected, got "..type(eventName)..")")
end
self:flush()
@@ -259,9 +259,9 @@ function Context:emit(eventName, ...)
return self
end
---- Removes all entities from the Context
+--- Removes all entities from the World
-- @return self
-function Context:clear()
+function World:clear()
for i = 1, self.entities.size do
self.entities:get(i):destroy()
end
@@ -273,16 +273,16 @@ end
--- Default callback for adding an Entity.
-- @param e The Entity that was added
-function Context:onEntityAdded(e) -- luacheck: ignore
+function World:onEntityAdded(e) -- luacheck: ignore
end
--- Default callback for removing an Entity.
-- @param e The Entity that was removed
-function Context:onEntityRemoved(e) -- luacheck: ignore
+function World:onEntityRemoved(e) -- luacheck: ignore
end
-return setmetatable(Context, {
+return setmetatable(World, {
__call = function(_, ...)
- return Context.new(...)
+ return World.new(...)
end,
})
From 052e1cd2ce611be1842e15e890b835efac750b4a Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Wed, 8 May 2019 11:44:15 +0200
Subject: [PATCH 008/113] Add example games
---
README.md | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/README.md b/README.md
index d2187ef..a46947c 100644
--- a/README.md
+++ b/README.md
@@ -27,12 +27,17 @@ local System = require("concord.system")
local Instance = require("concord.instance")
```
+## Example games
+[A Cat Game](https://github.com/flamendless/ECS-A-Cat-Game) by Brbl
+[Tetris](https://github.com/pikashira/tetris-love-ecs) by Pikashira
+
## Contributors
```
Positive07: Constant support and a good rubberduck
Brbl: Early testing and issue reporting
Josh: Squashed a few bugs and docs
Erasio: Took inspiration from HooECS. Also introduced me to ECS.
+Brbl, Pikashria: Example games
```
## Licence
From 93da73ad6ceb93e40c5dfa29ac4f2d2d4c01db16 Mon Sep 17 00:00:00 2001
From: Justin van der Leij
Date: Wed, 8 May 2019 11:44:42 +0200
Subject: [PATCH 009/113] Formatting is hard
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index a46947c..4ef32d5 100644
--- a/README.md
+++ b/README.md
@@ -29,6 +29,7 @@ local Instance = require("concord.instance")
## Example games
[A Cat Game](https://github.com/flamendless/ECS-A-Cat-Game) by Brbl
+
[Tetris](https://github.com/pikashira/tetris-love-ecs) by Pikashira
## Contributors
From cc6783ac31b7d5b6930c7c539d214529879a6ea4 Mon Sep 17 00:00:00 2001
From: Tachytaenius
Date: Tue, 21 May 2019 19:08:43 +0100
Subject: [PATCH 010/113] Fixed a broken luadoc comment
Rewriting this code was haaaard, man...
---
lib/list.lua | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/list.lua b/lib/list.lua
index 33b2c10..be70e4d 100644
--- a/lib/list.lua
+++ b/lib/list.lua
@@ -68,7 +68,7 @@ end
--- Gets if the List has the object.
-- @param obj The object to search for
--- true if the list has the object, false otherwise
+-- @return true if the list has the object, false otherwise
function List:has(obj)
return self.pointers[obj] and true
end
From f7e1be8e1d685b8bfd29835dc2f36229e30c3ad7 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Tue, 10 Dec 2019 12:22:15 +0100
Subject: [PATCH 011/113] Remove todo list
---
TODO | 15 ---------------
1 file changed, 15 deletions(-)
delete mode 100644 TODO
diff --git a/TODO b/TODO
deleted file mode 100644
index 33fc816..0000000
--- a/TODO
+++ /dev/null
@@ -1,15 +0,0 @@
-[x] Modify pools and list to be more efficient
-[x] Rework Entity:give to remove any previous component and re-add it.
-[x] Add Entity:ensure (maybe?)
-[ ] Put pools in the Instance and invert dependency.
-[ ] Share pools between systems
-[x] Remove System callbacks
-[x] Put .added and .removed in pools so they can be iterated over
-[x] Implement assemblages
-[x] Do :apply automatically with marked entities
-[x] Remove Entity.components. Use Entity[Component] instead
-
-[ ] Add missing documentation
-[ ] Fix current documentation
-[ ] Write unit tests
-[ ] Write examples
From bc47eaa651f41c3ca0f91673761efc0ff383a7cb Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Wed, 11 Dec 2019 13:04:09 +0100
Subject: [PATCH 012/113] Allow for named components
---
main.lua | 37 +++++++++++++++++++++++++++++++++++++
src/component.lua | 17 ++++++++++++++++-
2 files changed, 53 insertions(+), 1 deletion(-)
diff --git a/main.lua b/main.lua
index ce78707..cd13075 100644
--- a/main.lua
+++ b/main.lua
@@ -1,4 +1,41 @@
+--[=[
local file = "examples.simpleDrawing"
-- local file = "examples.baseLayout.main"
require(file)
+]=]--
+
+local Concord = require("src")
+local Component = require("src.component")
+
+local test_comp_1 = Concord.component("test_comp_1", function(e, x, y)
+ e.x = x
+ e.y = y
+end)
+
+local test_comp_2 = Concord.component("test_comp_2", function(e, a)
+ e.a = a
+end)
+
+local test_comp_3 = Concord.component("test_comp_3", function(e, b)
+ e.b = b
+end)
+
+local test_system = Concord.system({Component.test_comp_1})
+function test_system:update(dt)
+ print(#self.pool)
+end
+
+local world = Concord.world()
+
+local entity = Concord.entity()
+entity:give(Component.test_comp_2, 100, 100)
+entity:apply()
+
+world:addEntity(entity)
+
+world:addSystem(test_system(), "update")
+
+function love.update(dt)
+ world:emit("update", dt)
+end
\ No newline at end of file
diff --git a/src/component.lua b/src/component.lua
index 63cb1fb..5777743 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -6,8 +6,21 @@ Component.__index = Component
--- Creates a new Component.
-- @param populate A function that populates the Bag with values
-- @return A Component object
-function Component.new(populate)
+function Component.new(name, populate)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Component.new' (string expected, got "..type(name)..")", 2)
+ end
+
+ if not (populate == nil or type(populate) == "function") then
+ error("bad argument #2 to 'Component.new' (function/nil expected, got "..type(populate)..")", 2)
+ end
+
+ if (Component[name] ~= nil) then
+ error("bad argument #2 to 'Component.new' (Component with name '"..name.."' already exists", 2)
+ end
+
local component = setmetatable({
+ __name = name,
__populate = populate,
__isComponent = true,
@@ -15,6 +28,8 @@ function Component.new(populate)
component.__mt = {__index = component}
+ Component[name] = component
+
return component
end
From 038111d55825d7a1347c51cbbf41a3d2ef331926 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Thu, 19 Dec 2019 08:47:38 +0100
Subject: [PATCH 013/113] Streamline entity lifetime
---
main.lua | 37 ++++++++++++++--
src/component.lua | 2 +-
src/entity.lua | 45 +++++++------------
src/list.lua | 2 +-
src/pool.lua | 27 ++++++-----
src/system.lua | 56 ++++-------------------
src/world.lua | 111 +++++++++++++++++-----------------------------
7 files changed, 117 insertions(+), 163 deletions(-)
diff --git a/main.lua b/main.lua
index cd13075..dad60e1 100644
--- a/main.lua
+++ b/main.lua
@@ -22,20 +22,49 @@ local test_comp_3 = Concord.component("test_comp_3", function(e, b)
end)
local test_system = Concord.system({Component.test_comp_1})
-function test_system:update(dt)
- print(#self.pool)
+
+function onEntityAdded(e)
+ print("Added")
end
+function onEntityRemoved(e)
+ print("Removed")
+end
+
+function test_system:init()
+ self.pool.onEntityAdded = onEntityAdded
+ self.pool.onEntityRemoved = onEntityRemoved
+end
+
+function test_system:update(dt)
+ --print(#self.pool)
+end
+
+
+
local world = Concord.world()
local entity = Concord.entity()
-entity:give(Component.test_comp_2, 100, 100)
-entity:apply()
+entity:give(Component.test_comp_1, 100, 100)
world:addEntity(entity)
world:addSystem(test_system(), "update")
function love.update(dt)
+ world:flush()
+
world:emit("update", dt)
+end
+
+function love.keypressed(key)
+ if key == "q" then
+ entity:remove(Component.test_comp_1)
+ end
+ if key == "w" then
+ entity:give(Component.test_comp_1)
+ end
+ if key == "e" then
+ world:removeEntity(entity)
+ end
end
\ No newline at end of file
diff --git a/src/component.lua b/src/component.lua
index 5777743..102e722 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -51,4 +51,4 @@ return setmetatable(Component, {
__call = function(_, ...)
return Component.new(...)
end,
-})
+})
\ No newline at end of file
diff --git a/src/entity.lua b/src/entity.lua
index 62d64c4..a6c6b29 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -3,7 +3,6 @@
local PATH = (...):gsub('%.[^%.]+$', '')
local Type = require(PATH..".type")
-local List = require(PATH..".list")
local Entity = {}
Entity.__index = Entity
@@ -12,8 +11,11 @@ Entity.__index = Entity
-- @return A new Entity
function Entity.new()
local e = setmetatable({
- removed = {},
- worlds = List(),
+ world = nil,
+
+ __isDirty = true,
+ __wasAdded = false,
+ __wasRemoved = false,
__isEntity = true,
}, Entity)
@@ -25,7 +27,13 @@ local function give(e, component, ...)
local comp = component:__initialize(...)
e[component] = comp
- e:mark()
+ e.__isDirty = true
+end
+
+local function remove(e, component)
+ e[component] = nil
+
+ e.__isDirty = true
end
--- Gives an Entity a component with values.
@@ -37,10 +45,6 @@ function Entity:give(component, ...)
error("bad argument #1 to 'Entity:give' (Component expected, got "..type(component)..")", 2)
end
- if self[component] then
- self:remove(component):apply()
- end
-
give(self, component, ...)
return self
@@ -68,9 +72,7 @@ function Entity:remove(component)
error("bad argument #1 to 'Entity:remove' (Component expected, got "..type(component)..")")
end
- self.removed[#self.removed + 1] = component
-
- self:mark()
+ remove(self, component)
return self
end
@@ -85,28 +87,11 @@ function Entity:assemble(assemblage, ...)
return self
end
-function Entity:mark()
- for i = 1, self.worlds.size do
- self.worlds:get(i):markEntity(self)
- end
-end
-
-function Entity:apply()
- for i = 1, #self.removed do
- local component = self.removed[i]
-
- self[component] = nil
- self.removed[i] = nil
- end
-
- return self
-end
-
--- Destroys the Entity.
-- @return self
function Entity:destroy()
- for i = 1, self.worlds.size do
- self.worlds:get(i):removeEntity(self)
+ if self.world then
+ self.world:removeEntity(self)
end
return self
diff --git a/src/list.lua b/src/list.lua
index a79d20e..16819da 100644
--- a/src/list.lua
+++ b/src/list.lua
@@ -73,7 +73,7 @@ end
-- @param obj The object to search for
-- true if the list has the object, false otherwise
function List:has(obj)
- return self[obj] and true
+ return self[obj] and true or false
end
return setmetatable(List, {
diff --git a/src/pool.lua b/src/pool.lua
index 779efd9..e82735a 100644
--- a/src/pool.lua
+++ b/src/pool.lua
@@ -14,9 +14,6 @@ Pool.__index = Pool
function Pool.new(name, filter)
local pool = setmetatable(List(), Pool)
- pool.added = {}
- pool.removed = {}
-
pool.name = name
pool.filter = filter
@@ -25,18 +22,12 @@ function Pool.new(name, filter)
return pool
end
-function Pool:flush()
- for i = 1, math.max(#self.added, #self.removed) do
- self.added[i], self.removed[i] = nil, nil
- end
-end
-
--- Checks if an Entity is eligible for the Pool.
-- @param e The Entity to check
-- @return True if the entity is eligible, false otherwise
function Pool:eligible(e)
for _, component in ipairs(self.filter) do
- if not e[component] or e.removed[component] then
+ if not e[component] then
return false
end
end
@@ -44,6 +35,22 @@ function Pool:eligible(e)
return true
end
+function Pool:add(e)
+ List.add(self, e)
+ self:onEntityAdded(e)
+end
+
+function Pool:remove(e)
+ List.remove(self, e)
+ self:onEntityRemoved(e)
+end
+
+function Pool:onEntityAdded(e)
+end
+
+function Pool:onEntityRemoved(e)
+end
+
return setmetatable(Pool, {
__index = List,
__call = function(_, ...)
diff --git a/src/system.lua b/src/system.lua
index 10729da..b078a50 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -9,7 +9,6 @@ System.mt = {
__index = System,
__call = function(systemProto, ...)
local system = setmetatable({
- __all = {},
__pools = {},
__world = nil,
@@ -63,22 +62,15 @@ end
--- Checks and applies an Entity to the System's pools.
-- @param e The Entity to check
--- @return True if the Entity was added, false if it was removed. Nil if nothing happend
-function System:__check(e)
+function System:__evaluate(e)
for _, pool in ipairs(self.__pools) do
- local poolHas = pool:has(e)
+ local has = pool:has(e)
local eligible = pool:eligible(e)
- if not poolHas and eligible then
+ if not has and eligible then
pool:add(e)
- pool.added[#pool.added + 1] = e
-
- self:__tryAdd(e)
- elseif poolHas and not eligible then
+ elseif has and not eligible then
pool:remove(e)
- pool.removed[#pool.removed + 1] = e
-
- self:__tryRemove(e)
end
end
end
@@ -86,46 +78,16 @@ end
--- Remove an Entity from the System.
-- @param e The Entity to remove
function System:__remove(e)
- if self.__all[e] then
- for _, pool in ipairs(self.__pools) do
- if pool:has(e) then
- pool:remove(e)
- pool.removed[#pool.removed + 1] = e
- end
- end
-
- self.__all[e] = nil
- end
-end
-
---- Tries to add an Entity to the System.
--- @param e The Entity to add
-function System:__tryAdd(e)
- if not self.__all[e] then
- self.__all[e] = 0
- end
-
- self.__all[e] = self.__all[e] + 1
-end
-
---- Tries to remove an Entity from the System.
--- @param e The Entity to remove
-function System:__tryRemove(e)
- if self.__all[e] then
- self.__all[e] = self.__all[e] - 1
-
- if self.__all[e] == 0 then
- self.__all[e] = nil
+ for _, pool in ipairs(self.__pools) do
+ if pool:has(e) then
+ pool:remove(e)
end
end
end
-function System:flush() -- luacheck: ignore
-end
-
function System:clear()
for i = 1, #self.__pools do
- self.__pools[i]:flush()
+ self.__pools[i]:clear()
end
end
@@ -142,7 +104,7 @@ end
-- Default callback for when the System is added to an World.
-- @param world The World the System was added to
-function System:addedTo(World) -- luacheck: ignore
+function System:addedTo(world) -- luacheck: ignore
end
-- Default callback for when a System's callback is enabled.
diff --git a/src/world.lua b/src/world.lua
index 59305fa..2712cb6 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -16,8 +16,8 @@ function World.new()
systems = List(),
events = {},
- marked = {},
- removed = {},
+ __added = {},
+ __removed = {},
__isWorld = true,
}, World)
@@ -33,16 +33,19 @@ function World:addEntity(e)
error("bad argument #1 to 'World:addEntity' (Entity expected, got "..type(e)..")", 2)
end
- self:onEntityAdded(e)
+ if e.world then
+ error("bad argument #1 to 'World:addEntity' (Entity was already added to a world)", 2)
+ end
+
+ e.world = self
+ e.__wasAdded = true
- e.worlds:add(self)
self.entities:add(e)
- self:checkEntity(e)
return self
end
---- Marks an Entity as removed from the World.
+--- Removes an entity from the World.
-- @param e The Entity to mark
-- @return self
function World:removeEntity(e)
@@ -50,73 +53,46 @@ function World:removeEntity(e)
error("bad argument #1 to 'World:removeEntity' (Entity expected, got "..type(e)..")", 2)
end
- self.removed[#self.removed + 1] = e
+ e.__wasRemoved = true
return self
end
-function World:markEntity(e)
- if not Type.isEntity(e) then
- error("bad argument #1 to 'World:markEntity' (Entity expected, got "..type(e)..")", 2)
- end
-
- self.marked[#self.marked + 1] = e
-
- return self
-end
-
---- Checks an Entity against all the systems in the World.
--- @param e The Entity to check
--- @return self
-function World:checkEntity(e)
- if not Type.isEntity(e) then
- error("bad argument #1 to 'World:checkEntity' (Entity expected, got "..type(e)..")", 2)
- end
-
- for i = 1, self.systems.size do
- self.systems:get(i):__check(e)
- end
-
- return self
-end
-
---- Completely removes all marked Entities in the World.
-- @return self
function World:flush()
- while #self.marked > 0 do
- local marked = self.removed
- self.removed = {}
+ local e
+ for i = 1, self.entities.size do
+ e = self.entities:get(i)
- for i = 1, #marked do
- local e = marked[i]
+ if e.__wasAdded then
+ e.__wasAdded = false
+ e.__isDirty = false
- e.Worlds:apply()
- e.Worlds:checkEntity(e)
- end
- end
-
- while #self.removed > 0 do
- local removed = self.removed
- self.removed = {}
-
- for i = 1, #removed do
- local e = removed[i]
-
- e.worlds:remove(self)
- self.entities:remove(e)
-
- for j = 1, self.systems.size do
- self.systems:get(j):__remove(e)
+ for i = 1, self.systems.size do
+ self.systems:get(i):__evaluate(e)
end
- self:onEntityRemoved(e)
+ self:onEntityAdded(e)
end
- end
- for i = 1, self.systems.size do
- local system = self.systems:get(i)
- system:flush()
- system:clear()
+ if e.__wasRemoved then
+ e.world = nil
+ self.entities:remove(e)
+
+ for i = 1, self.systems.size do
+ self.systems:get(i):__remove(e)
+ end
+
+ e.__wasRemoved = false
+ end
+
+ if e.__isDirty then
+ for i = 1, self.systems.size do
+ self.systems:get(i):__evaluate(e)
+ end
+
+ e.__isDirty = false
+ end
end
return self
@@ -142,6 +118,10 @@ function World:addSystem(system, eventName, callback, enabled)
system.__World = self
system:addedTo(self)
+
+ for i = 1, self.entities.size do
+ system:__evaluate(self.entities:get(i))
+ end
end
if eventName then
@@ -159,13 +139,6 @@ function World:addSystem(system, eventName, callback, enabled)
end
end
- local e
- for i = 1, self.entities.size do
- e = self.entities:get(i)
-
- self:checkEntity(e)
- end
-
return self
end
@@ -242,8 +215,6 @@ function World:emit(eventName, ...)
error("bad argument #1 to 'World:emit' (String expected, got "..type(eventName)..")")
end
- self:flush()
-
local listeners = self.events[eventName]
if listeners then
From d4efca976c8669f0ab27b0759e7d73b826249d74 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Thu, 19 Dec 2019 10:34:02 +0100
Subject: [PATCH 014/113] Added named systems
---
main.lua | 45 +++++++++++++++--------
src/component.lua | 12 +++---
src/components.lua | 29 +++++++++++++++
src/init.lua | 2 +
src/list.lua | 2 +
src/pool.lua | 4 +-
src/system.lua | 37 +++++++++++--------
src/systems.lua | 29 +++++++++++++++
src/type.lua | 16 ++++----
src/world.lua | 92 ++++++++++++++++++++++++----------------------
10 files changed, 176 insertions(+), 92 deletions(-)
create mode 100644 src/components.lua
create mode 100644 src/systems.lua
diff --git a/main.lua b/main.lua
index dad60e1..26ef1f8 100644
--- a/main.lua
+++ b/main.lua
@@ -6,50 +6,63 @@ require(file)
]=]--
local Concord = require("src")
-local Component = require("src.component")
-local test_comp_1 = Concord.component("test_comp_1", function(e, x, y)
+local Component = require("src.component")
+local Components = require("src.components")
+
+local System = Concord.system
+local Systems = Concord.systems
+
+local Entity = Concord.entity
+
+local World = Concord.world
+
+Component("test_comp_1", function(e, x, y)
e.x = x
e.y = y
end)
-local test_comp_2 = Concord.component("test_comp_2", function(e, a)
+Component("test_comp_2", function(e, a)
e.a = a
end)
-local test_comp_3 = Concord.component("test_comp_3", function(e, b)
+Component("test_comp_3", function(e, b)
e.b = b
end)
-local test_system = Concord.system({Component.test_comp_1})
+local test_system = System("test_system", {Components.test_comp_1})
-function onEntityAdded(e)
+local function onEntityAdded(e) -- luacheck: ignore
print("Added")
end
-function onEntityRemoved(e)
+local function onEntityRemoved(e) -- luacheck: ignore
print("Removed")
end
function test_system:init()
- self.pool.onEntityAdded = onEntityAdded
+ self.pool.onEntityAdded = onEntityAdded
self.pool.onEntityRemoved = onEntityRemoved
end
-function test_system:update(dt)
+function test_system:update(dt) -- luacheck: ignore
+ --print(#self.pool)
+end
+
+function test_system:update2(dt) -- luacheck: ignore
--print(#self.pool)
end
+local world = World()
-local world = Concord.world()
-
-local entity = Concord.entity()
-entity:give(Component.test_comp_1, 100, 100)
+local entity = Entity()
+entity:give(Components.test_comp_1, 100, 100)
world:addEntity(entity)
-world:addSystem(test_system(), "update")
+world:addSystem(Systems.test_system, "update")
+world:addSystem(Systems.test_system, "update", "update2")
function love.update(dt)
world:flush()
@@ -59,10 +72,10 @@ end
function love.keypressed(key)
if key == "q" then
- entity:remove(Component.test_comp_1)
+ entity:remove(Components.test_comp_1)
end
if key == "w" then
- entity:give(Component.test_comp_1)
+ entity:give(Components.test_comp_1)
end
if key == "e" then
world:removeEntity(entity)
diff --git a/src/component.lua b/src/component.lua
index 102e722..43d4ecc 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -1,5 +1,9 @@
--- Component
+local PATH = (...):gsub('%.[^%.]+$', '')
+
+local Components = require(PATH..".components")
+
local Component = {}
Component.__index = Component
@@ -15,10 +19,6 @@ function Component.new(name, populate)
error("bad argument #2 to 'Component.new' (function/nil expected, got "..type(populate)..")", 2)
end
- if (Component[name] ~= nil) then
- error("bad argument #2 to 'Component.new' (Component with name '"..name.."' already exists", 2)
- end
-
local component = setmetatable({
__name = name,
__populate = populate,
@@ -28,7 +28,7 @@ function Component.new(name, populate)
component.__mt = {__index = component}
- Component[name] = component
+ Components.register(name, component)
return component
end
@@ -51,4 +51,4 @@ return setmetatable(Component, {
__call = function(_, ...)
return Component.new(...)
end,
-})
\ No newline at end of file
+})
\ No newline at end of file
diff --git a/src/components.lua b/src/components.lua
new file mode 100644
index 0000000..63d40e0
--- /dev/null
+++ b/src/components.lua
@@ -0,0 +1,29 @@
+-- Components
+
+local PATH = (...):gsub('%.[^%.]+$', '')
+
+local Type = require(PATH..".type")
+
+local Components = {}
+
+function Components.register(name, component)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Components.register' (string expected, got "..type(name)..")", 3)
+ end
+
+ if (not Type.isComponent(component)) then
+ error("bad argument #2 to 'Components.register' (component expected, got "..type(component)..")", 3)
+ end
+
+ if (rawget(Components, name)) then
+ error("bad argument #2 to 'Components.register' (Component with name '"..name.."' is already registerd)", 3)
+ end
+
+ Components[name] = component
+end
+
+return setmetatable(Components, {
+ __index = function(_, name)
+ error("Attempt to index component '"..tostring(name).."' that does not exist / was not registered", 2)
+ end
+})
\ No newline at end of file
diff --git a/src/init.lua b/src/init.lua
index e13f190..4eb9b99 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -33,7 +33,9 @@ local Concord = {
Concord.entity = require(PATH..".entity")
Concord.component = require(PATH..".component")
+Concord.components = require(PATH..".components")
Concord.system = require(PATH..".system")
+Concord.systems = require(PATH..".systems")
Concord.world = require(PATH..".world")
Concord.assemblage = require(PATH..".assemblage")
diff --git a/src/list.lua b/src/list.lua
index 16819da..b3e8fdf 100644
--- a/src/list.lua
+++ b/src/list.lua
@@ -60,6 +60,8 @@ function List:remove(obj)
self[obj] = nil
self.size = size - 1
+
+ return self
end
--- Gets an object by numerical index.
diff --git a/src/pool.lua b/src/pool.lua
index e82735a..92373e2 100644
--- a/src/pool.lua
+++ b/src/pool.lua
@@ -45,10 +45,10 @@ function Pool:remove(e)
self:onEntityRemoved(e)
end
-function Pool:onEntityAdded(e)
+function Pool:onEntityAdded(e) -- luacheck: ignore
end
-function Pool:onEntityRemoved(e)
+function Pool:onEntityRemoved(e) -- luacheck: ignore
end
return setmetatable(Pool, {
diff --git a/src/system.lua b/src/system.lua
index b078a50..ecafd6b 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -2,20 +2,21 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Pool = require(PATH..".pool")
+local Systems = require(PATH..".systems")
+local Pool = require(PATH..".pool")
local System = {}
System.mt = {
__index = System,
- __call = function(systemProto, ...)
+ __call = function(baseSystem, world)
local system = setmetatable({
__pools = {},
- __world = nil,
+ __world = world,
__isSystem = true,
- }, systemProto)
+ }, baseSystem)
- for _, filter in pairs(systemProto.__filter) do
+ for _, filter in pairs(baseSystem.__filter) do
local pool = system:__buildPool(filter)
if not system[pool.name] then
system[pool.name] = pool
@@ -25,7 +26,8 @@ System.mt = {
end
end
- system:init(...)
+ system:init(world)
+
return system
end,
}
@@ -33,13 +35,21 @@ System.mt = {
--- Creates a new System prototype.
-- @param ... Variable amounts of filters
-- @return A new System prototype
-function System.new(...)
- local systemProto = setmetatable({
+function System.new(name, ...)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'System.new' (string expected, got "..type(name)..")", 2)
+ end
+
+ local baseSystem = setmetatable({
+ __name = name,
+ __isBaseSystem = true,
__filter = {...},
}, System.mt)
- systemProto.__index = systemProto
+ baseSystem.__index = baseSystem
- return systemProto
+ Systems.register(name, baseSystem)
+
+ return baseSystem
end
--- Builds a Pool for the System.
@@ -98,13 +108,8 @@ function System:getWorld()
end
--- Default callback for system initialization.
--- @param ... Varags
-function System:init(...) -- luacheck: ignore
-end
-
--- Default callback for when the System is added to an World.
-- @param world The World the System was added to
-function System:addedTo(world) -- luacheck: ignore
+function System:init(world) -- luacheck: ignore
end
-- Default callback for when a System's callback is enabled.
diff --git a/src/systems.lua b/src/systems.lua
new file mode 100644
index 0000000..4f84472
--- /dev/null
+++ b/src/systems.lua
@@ -0,0 +1,29 @@
+-- Systems
+
+local PATH = (...):gsub('%.[^%.]+$', '')
+
+local Type = require(PATH..".type")
+
+local Systems = {}
+
+function Systems.register(name, system)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Systems.register' (string expected, got "..type(name)..")", 3)
+ end
+
+ if (not Type.isBaseSystem(system)) then
+ error("bad argument #2 to 'Systems.register' (baseSystem expected, got "..type(system)..")", 3)
+ end
+
+ if (rawget(Systems, name)) then
+ error("bad argument #2 to 'Systems.register' (System with name '"..name.."' is already registerd)", 3)
+ end
+
+ Systems[name] = system
+end
+
+return setmetatable(Systems, {
+ __index = function(_, name)
+ error("Attempt to index system '"..tostring(name).."' that does not exist / was not registered", 2)
+ end
+})
\ No newline at end of file
diff --git a/src/type.lua b/src/type.lua
index 999c42c..ae79628 100644
--- a/src/type.lua
+++ b/src/type.lua
@@ -3,23 +3,23 @@
local Type = {}
function Type.isComponent(t)
- return type(t) == "table" and t.__isComponent
+ return type(t) == "table" and t.__isComponent or false
end
function Type.isEntity(t)
- return type(t) == "table" and t.__isEntity
+ return type(t) == "table" and t.__isEntity or false
+end
+
+function Type.isBaseSystem(t)
+ return type(t) == "table" and t.__isBaseSystem or false
end
function Type.isSystem(t)
- return type(t) == "table" and t.__isSystem
-end
-
-function Type.isContext(t)
- return type(t) == "table" and t.__isContext
+ return type(t) == "table" and t.__isSystem or false
end
function Type.isAssemblage(t)
- return type(t) == "table" and t.__isAssemblage
+ return type(t) == "table" and t.__isAssemblage or false
end
return Type
diff --git a/src/world.lua b/src/world.lua
index 2712cb6..2bb13e5 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -14,11 +14,14 @@ function World.new()
local world = setmetatable({
entities = List(),
systems = List(),
+
events = {},
__added = {},
__removed = {},
+ __systemLookup = {},
+
__isWorld = true,
}, World)
@@ -68,8 +71,8 @@ function World:flush()
e.__wasAdded = false
e.__isDirty = false
- for i = 1, self.systems.size do
- self.systems:get(i):__evaluate(e)
+ for j = 1, self.systems.size do
+ self.systems:get(j):__evaluate(e)
end
self:onEntityAdded(e)
@@ -79,16 +82,16 @@ function World:flush()
e.world = nil
self.entities:remove(e)
- for i = 1, self.systems.size do
- self.systems:get(i):__remove(e)
+ for j = 1, self.systems.size do
+ self.systems:get(j):__remove(e)
end
e.__wasRemoved = false
end
if e.__isDirty then
- for i = 1, self.systems.size do
- self.systems:get(i):__evaluate(e)
+ for j = 1, self.systems.size do
+ self.systems:get(j):__evaluate(e)
end
e.__isDirty = false
@@ -99,43 +102,46 @@ function World:flush()
end
--- Adds a System to the World.
--- @param system The System to add
--- @param eventName The Event to register to
--- @param callback The function name to call. Defaults to eventName
+-- @param baseSystem The BaseSystem of the system to add
+-- @param callbackName The callbackName to register to
+-- @param callback The function name to call. Defaults to callbackName
-- @param enabled If the system is enabled. Defaults to true
-- @return self
-function World:addSystem(system, eventName, callback, enabled)
- if not Type.isSystem(system) then
- error("bad argument #1 to 'World:addSystem' (System expected, got "..type(system)..")", 2)
+function World:addSystem(baseSystem, callbackName, callback, enabled)
+ if not Type.isBaseSystem(baseSystem) then
+ error("bad argument #1 to 'World:addSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
end
- if system.__World and system.__World ~= self then
- error("System already in World '" ..tostring(system.__World).."'")
- end
+ local system = self.__systemLookup[baseSystem]
+ if (not system) then
+ -- System was not created for this world yet, so we create it ourselves
+
+ print("Created system")
+
+ system = baseSystem(self)
+
+ self.__systemLookup[baseSystem] = system
- if not self.systems:has(system) then
self.systems:add(system)
- system.__World = self
-
- system:addedTo(self)
-
- for i = 1, self.entities.size do
- system:__evaluate(self.entities:get(i))
- end
end
- if eventName then
- self.events[eventName] = self.events[eventName] or {}
+ -- Retroactively evaluate all entities for this system
+ for i = 1, self.entities.size do
+ system:__evaluate(self.entities:get(i))
+ end
- local i = #self.events[eventName] + 1
- self.events[eventName][i] = {
+ if callbackName then
+ self.events[callbackName] = self.events[callbackName] or {}
+
+ local i = #self.events[callbackName] + 1
+ self.events[callbackName][i] = {
system = system,
- callback = callback or eventName,
+ callback = callback or callbackName,
enabled = enabled == nil or enabled,
}
if enabled == nil or enabled then
- system:enabledCallback(callback or eventName)
+ system:enabledCallback(callback or callbackName)
end
end
@@ -144,15 +150,15 @@ end
--- Enables a System in the World.
-- @param system The System to enable
--- @param eventName The Event it was registered to
+-- @param callbackName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @return self
-function World:enableSystem(system, eventName, callback)
+function World:enableSystem(system, callbackName, callback)
if not Type.isSystem(system) then
error("bad argument #1 to 'World:enableSystem' (System expected, got "..type(system)..")", 2)
end
- return self:setSystem(system, eventName, callback, true)
+ return self:setSystem(system, callbackName, callback, true)
end
--- Disables a System in the World.
@@ -160,12 +166,12 @@ end
-- @param eventName The Event it was registered to
-- @param callback The callback it was registered with. Defaults to eventName
-- @return self
-function World:disableSystem(system, eventName, callback)
+function World:disableSystem(system, callbackName, callback)
if not Type.isSystem(system) then
error("bad argument #1 to 'World:disableSystem' (System expected, got "..type(system)..")", 2)
end
- return self:setSystem(system, eventName, callback, false)
+ return self:setSystem(system, callbackName, callback, false)
end
--- Sets a System 'enable' in the World.
@@ -174,15 +180,15 @@ end
-- @param callback The callback it was registered with. Defaults to eventName
-- @param enable The state to set it to
-- @return self
-function World:setSystem(system, eventName, callback, enable)
+function World:setSystem(system, callbackName, callback, enable)
if not Type.isSystem(system) then
error("bad argument #1 to 'World:setSystem' (System expected, got "..type(system)..")", 2)
end
- callback = callback or eventName
+ callback = callback or callbackName
if callback then
- local listeners = self.events[eventName]
+ local listeners = self.events[callbackName]
if listeners then
for i = 1, #listeners do
@@ -210,12 +216,12 @@ end
-- @param eventName The Event that should be emitted
-- @param ... Parameters passed to listeners
-- @return self
-function World:emit(eventName, ...)
- if not eventName or type(eventName) ~= "string" then
- error("bad argument #1 to 'World:emit' (String expected, got "..type(eventName)..")")
+function World:emit(callbackName, ...)
+ if not callbackName or type(callbackName) ~= "string" then
+ error("bad argument #1 to 'World:emit' (String expected, got "..type(callbackName)..")")
end
- local listeners = self.events[eventName]
+ local listeners = self.events[callbackName]
if listeners then
for i = 1, #listeners do
@@ -234,11 +240,9 @@ end
-- @return self
function World:clear()
for i = 1, self.entities.size do
- self.entities:get(i):destroy()
+ self.removeEntity(self.entities:get(i))
end
- self:flush()
-
return self
end
From d0e227485e181d6ab9948af643828dcd663c5c7a Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Thu, 19 Dec 2019 20:14:21 +0100
Subject: [PATCH 015/113] Allow named worlds
---
main.lua | 6 +++++-
src/component.lua | 2 +-
src/system.lua | 1 +
src/type.lua | 4 ++++
src/world.lua | 15 ++++++++++-----
src/worlds.lua | 29 +++++++++++++++++++++++++++++
6 files changed, 50 insertions(+), 7 deletions(-)
create mode 100644 src/worlds.lua
diff --git a/main.lua b/main.lua
index 26ef1f8..6040302 100644
--- a/main.lua
+++ b/main.lua
@@ -46,7 +46,11 @@ function test_system:init()
end
function test_system:update(dt) -- luacheck: ignore
- --print(#self.pool)
+ --[=[
+ for _, v in ipairs(self.pool) do
+ print(v)
+ end
+ ]=]
end
function test_system:update2(dt) -- luacheck: ignore
diff --git a/src/component.lua b/src/component.lua
index 43d4ecc..e7b3d90 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -38,7 +38,7 @@ end
-- @return A new initialized Bag
function Component:__initialize(...)
if self.__populate then
- local bag = setmetatable({}, self.__mt)
+ local bag = setmetatable({}, self)
self.__populate(bag, ...)
return bag
diff --git a/src/system.lua b/src/system.lua
index ecafd6b..f9b696c 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -14,6 +14,7 @@ System.mt = {
__world = world,
__isSystem = true,
+ __isBaseSystem = false, -- Overwrite value from baseSystem
}, baseSystem)
for _, filter in pairs(baseSystem.__filter) do
diff --git a/src/type.lua b/src/type.lua
index ae79628..3da59d9 100644
--- a/src/type.lua
+++ b/src/type.lua
@@ -18,6 +18,10 @@ function Type.isSystem(t)
return type(t) == "table" and t.__isSystem or false
end
+function Type.isWorld(t)
+ return type(t) == "table" and t.__isWorld or false
+end
+
function Type.isAssemblage(t)
return type(t) == "table" and t.__isAssemblage or false
end
diff --git a/src/world.lua b/src/world.lua
index 2bb13e5..86e76c3 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -2,6 +2,7 @@
local PATH = (...):gsub('%.[^%.]+$', '')
+local Worlds = require(PATH..".world")
local Type = require(PATH..".type")
local List = require(PATH..".list")
@@ -10,7 +11,11 @@ World.__index = World
--- Creates a new World.
-- @return The new World
-function World.new()
+function World.new(name)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Component.new' (string expected, got "..type(name)..")", 2)
+ end
+
local world = setmetatable({
entities = List(),
systems = List(),
@@ -22,9 +27,12 @@ function World.new()
__systemLookup = {},
+ __name = name,
__isWorld = true,
}, World)
+ Worlds.register(world)
+
return world
end
@@ -115,9 +123,6 @@ function World:addSystem(baseSystem, callbackName, callback, enabled)
local system = self.__systemLookup[baseSystem]
if (not system) then
-- System was not created for this world yet, so we create it ourselves
-
- print("Created system")
-
system = baseSystem(self)
self.__systemLookup[baseSystem] = system
@@ -240,7 +245,7 @@ end
-- @return self
function World:clear()
for i = 1, self.entities.size do
- self.removeEntity(self.entities:get(i))
+ self.removeEntity(self.entities[i])
end
return self
diff --git a/src/worlds.lua b/src/worlds.lua
new file mode 100644
index 0000000..0f8ad9c
--- /dev/null
+++ b/src/worlds.lua
@@ -0,0 +1,29 @@
+-- Worlds
+
+local PATH = (...):gsub('%.[^%.]+$', '')
+
+local Type = require(PATH..".type")
+
+local Worlds = {}
+
+function Worlds.register(name, world)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Worlds.register' (string expected, got "..type(name)..")", 3)
+ end
+
+ if (not Type.isWorld(world)) then
+ error("bad argument #2 to 'Worlds.register' (world expected, got "..type(world)..")", 3)
+ end
+
+ if (rawget(Worlds, name)) then
+ error("bad argument #2 to 'Worlds.register' (World with name '"..name.."' is already registerd)", 3)
+ end
+
+ Worlds[name] = component
+end
+
+return setmetatable(Worlds, {
+ __index = function(_, name)
+ error("Attempt to index world '"..tostring(name).."' that does not exist / was not registered", 2)
+ end
+})
\ No newline at end of file
From 276a053b7fbe50662c1408475d91304ae011dffb Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Thu, 19 Dec 2019 20:19:02 +0100
Subject: [PATCH 016/113] Allow named assemblages
---
main.lua | 7 ++++---
src/assemblage.lua | 13 ++++++++++++-
src/assemblages.lua | 29 +++++++++++++++++++++++++++++
src/init.lua | 8 +++++++-
src/world.lua | 6 +++---
src/worlds.lua | 2 +-
6 files changed, 56 insertions(+), 9 deletions(-)
create mode 100644 src/assemblages.lua
diff --git a/main.lua b/main.lua
index 6040302..68bad43 100644
--- a/main.lua
+++ b/main.lua
@@ -15,7 +15,8 @@ local Systems = Concord.systems
local Entity = Concord.entity
-local World = Concord.world
+local World = Concord.world
+local Worlds = Concord.worlds
Component("test_comp_1", function(e, x, y)
e.x = x
@@ -58,12 +59,12 @@ function test_system:update2(dt) -- luacheck: ignore
end
-local world = World()
+local world = World("testWorld")
local entity = Entity()
entity:give(Components.test_comp_1, 100, 100)
-world:addEntity(entity)
+Worlds.testWorld:addEntity(entity)
world:addSystem(Systems.test_system, "update")
world:addSystem(Systems.test_system, "update", "update2")
diff --git a/src/assemblage.lua b/src/assemblage.lua
index 79b3cbb..a6befed 100644
--- a/src/assemblage.lua
+++ b/src/assemblage.lua
@@ -1,14 +1,25 @@
--- Assemblage
+local PATH = (...):gsub('%.[^%.]+$', '')
+
+local Assemblages = require(PATH..".world")
+
local Assemblage = {}
Assemblage.__index = Assemblage
-function Assemblage.new(assemble)
+function Assemblage.new(name, assemble)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Assemblage.new' (string expected, got "..type(name)..")", 2)
+ end
+
local assemblage = setmetatable({
__assemble = assemble,
+ __name = name,
__isAssemblage = true,
}, Assemblage)
+
+ Assemblages.register(name, assemblage)
return assemblage
end
diff --git a/src/assemblages.lua b/src/assemblages.lua
new file mode 100644
index 0000000..f86f629
--- /dev/null
+++ b/src/assemblages.lua
@@ -0,0 +1,29 @@
+-- Assemblages
+
+local PATH = (...):gsub('%.[^%.]+$', '')
+
+local Type = require(PATH..".type")
+
+local Assemblages = {}
+
+function Assemblages.register(name, assemblage)
+ if (type(name) ~= "string") then
+ error("bad argument #1 to 'Assemblages.register' (string expected, got "..type(name)..")", 3)
+ end
+
+ if (not Type.isAssemblage(assemblage)) then
+ error("bad argument #2 to 'Assemblages.register' (assemblage expected, got "..type(world)..")", 3)
+ end
+
+ if (rawget(Assemblages, name)) then
+ error("bad argument #2 to 'Assemblages.register' (Assemblage with name '"..name.."' is already registerd)", 3)
+ end
+
+ Assemblages[name] = assemblage
+end
+
+return setmetatable(Assemblages, {
+ __index = function(_, name)
+ error("Attempt to index assemblage '"..tostring(name).."' that does not exist / was not registered", 2)
+ end
+})
\ No newline at end of file
diff --git a/src/init.lua b/src/init.lua
index 4eb9b99..5f32550 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -32,11 +32,17 @@ local Concord = {
}
Concord.entity = require(PATH..".entity")
+
Concord.component = require(PATH..".component")
Concord.components = require(PATH..".components")
+
Concord.system = require(PATH..".system")
Concord.systems = require(PATH..".systems")
+
Concord.world = require(PATH..".world")
-Concord.assemblage = require(PATH..".assemblage")
+Concord.worlds = require(PATH..".worlds")
+
+Concord.assemblage = require(PATH..".assemblage")
+Concord.assemblages = require(PATH..".assemblages")
return Concord
diff --git a/src/world.lua b/src/world.lua
index 86e76c3..217084e 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -2,7 +2,7 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Worlds = require(PATH..".world")
+local Worlds = require(PATH..".worlds")
local Type = require(PATH..".type")
local List = require(PATH..".list")
@@ -13,7 +13,7 @@ World.__index = World
-- @return The new World
function World.new(name)
if (type(name) ~= "string") then
- error("bad argument #1 to 'Component.new' (string expected, got "..type(name)..")", 2)
+ error("bad argument #1 to 'World.new' (string expected, got "..type(name)..")", 2)
end
local world = setmetatable({
@@ -31,7 +31,7 @@ function World.new(name)
__isWorld = true,
}, World)
- Worlds.register(world)
+ Worlds.register(name, world)
return world
end
diff --git a/src/worlds.lua b/src/worlds.lua
index 0f8ad9c..2f8f5a8 100644
--- a/src/worlds.lua
+++ b/src/worlds.lua
@@ -19,7 +19,7 @@ function Worlds.register(name, world)
error("bad argument #2 to 'Worlds.register' (World with name '"..name.."' is already registerd)", 3)
end
- Worlds[name] = component
+ Worlds[name] = world
end
return setmetatable(Worlds, {
From 2057767e752b7f5d2012244210ae14d8ec2e051c Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 20 Dec 2019 19:00:47 +0100
Subject: [PATCH 017/113] Add world:hasSystem, world:getSystem
---
src/world.lua | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/src/world.lua b/src/world.lua
index 217084e..50377d7 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -109,6 +109,22 @@ function World:flush()
return self
end
+function World:hasSystem(baseSystem)
+ if not Type.isBaseSystem(baseSystem) then
+ error("bad argument #1 to 'World:getSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
+ end
+
+ return self.__systemLookup[baseSystem] and true or false
+end
+
+function World:getSystem(baseSystem)
+ if not Type.isBaseSystem(baseSystem) then
+ error("bad argument #1 to 'World:getSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
+ end
+
+ return self.__systemLookup[baseSystem]
+end
+
--- Adds a System to the World.
-- @param baseSystem The BaseSystem of the system to add
-- @param callbackName The callbackName to register to
From 073aadf74b8a044c59a6914444134b79f220c805 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 20 Dec 2019 19:25:11 +0100
Subject: [PATCH 018/113] Test commit
---
main.lua | 2 ++
1 file changed, 2 insertions(+)
diff --git a/main.lua b/main.lua
index 68bad43..392a4f0 100644
--- a/main.lua
+++ b/main.lua
@@ -5,6 +5,8 @@ local file = "examples.simpleDrawing"
require(file)
]=]--
+--test
+
local Concord = require("src")
local Component = require("src.component")
From bb508ee94762ccad7f2b7260f2e3bc795d83ee7a Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sat, 21 Dec 2019 12:00:48 +0100
Subject: [PATCH 019/113] Add Entity:getComponents
---
src/entity.lua | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/src/entity.lua b/src/entity.lua
index a6c6b29..14619cf 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -13,6 +13,8 @@ function Entity.new()
local e = setmetatable({
world = nil,
+ __components = {},
+
__isDirty = true,
__wasAdded = false,
__wasRemoved = false,
@@ -23,15 +25,18 @@ function Entity.new()
return e
end
-local function give(e, component, ...)
- local comp = component:__initialize(...)
- e[component] = comp
+local function give(e, baseComponent, ...)
+ local component = baseComponent:__initialize(...)
+
+ e[baseComponent] = component
+ e.__components[baseComponent] = component
e.__isDirty = true
end
-local function remove(e, component)
- e[component] = nil
+local function remove(e, baseComponent)
+ e[baseComponent] = nil
+ e.__components[baseComponent] = nil
e.__isDirty = true
end
@@ -119,6 +124,10 @@ function Entity:has(component)
return self[component] ~= nil
end
+function Entity:getComponents()
+ return self.__components
+end
+
return setmetatable(Entity, {
__call = function(_, ...)
return Entity.new(...)
From ecb3c2db7e3f911f16924be26e94ff08ce596381 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 22 Dec 2019 21:00:53 +0100
Subject: [PATCH 020/113] Cache added and removed components
---
main.lua | 13 +++++++++----
src/component.lua | 5 ++++-
src/entity.lua | 46 +++++++++++++++++++++++++++++++++++++++++-----
src/world.lua | 21 +++++++++++++--------
4 files changed, 67 insertions(+), 18 deletions(-)
diff --git a/main.lua b/main.lua
index 392a4f0..6b9f293 100644
--- a/main.lua
+++ b/main.lua
@@ -35,11 +35,12 @@ end)
local test_system = System("test_system", {Components.test_comp_1})
-local function onEntityAdded(e) -- luacheck: ignore
- print("Added")
+local function onEntityAdded(pool, e) -- luacheck: ignore
+ local test_comp = e:get(Components.test_comp_1)
+ print(test_comp.x)
end
-local function onEntityRemoved(e) -- luacheck: ignore
+local function onEntityRemoved(pool, e) -- luacheck: ignore
print("Removed")
end
@@ -64,7 +65,11 @@ end
local world = World("testWorld")
local entity = Entity()
-entity:give(Components.test_comp_1, 100, 100)
+entity
+:give(Components.test_comp_1, 100, 100)
+:remove(Components.test_comp_1)
+:give(Components.test_comp_1, 200, 100)
+
Worlds.testWorld:addEntity(entity)
diff --git a/src/component.lua b/src/component.lua
index e7b3d90..e1ef5aa 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -38,7 +38,10 @@ end
-- @return A new initialized Bag
function Component:__initialize(...)
if self.__populate then
- local bag = setmetatable({}, self)
+ local bag = setmetatable({
+ __baseComponent = self,
+ }, self)
+
self.__populate(bag, ...)
return bag
diff --git a/src/entity.lua b/src/entity.lua
index 14619cf..5bfc88e 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -13,9 +13,13 @@ function Entity.new()
local e = setmetatable({
world = nil,
+ __addedComponents = {},
+ __removedComponents = {},
+ __operations = {},
+
__components = {},
- __isDirty = true,
+ __isDirty = false,
__wasAdded = false,
__wasRemoved = false,
@@ -25,18 +29,30 @@ function Entity.new()
return e
end
-local function give(e, baseComponent, ...)
- local component = baseComponent:__initialize(...)
+local function giveOperation(e, component)
+ local baseComponent = component.__baseComponent
e[baseComponent] = component
e.__components[baseComponent] = component
+end
+
+local function removeOperation(e, baseComponent)
+ e[baseComponent] = nil
+ e.__components[baseComponent] = nil
+end
+
+local function give(e, baseComponent, ...)
+ local component = baseComponent:__initialize(...)
+
+ e.__addedComponents[#e.__addedComponents + 1] = component
+ e.__operations[#e.__operations + 1] = giveOperation
e.__isDirty = true
end
local function remove(e, baseComponent)
- e[baseComponent] = nil
- e.__components[baseComponent] = nil
+ e.__removedComponents[#e.__removedComponents + 1] = baseComponent
+ e.__operations[#e.__operations + 1] = removeOperation
e.__isDirty = true
end
@@ -92,6 +108,26 @@ function Entity:assemble(assemblage, ...)
return self
end
+function Entity:flush()
+ local addi, removei = 1, 1
+
+ for i = 1, #self.__operations do
+ local operation = self.__operations[i]
+
+ if (operation == giveOperation) then
+ operation(self, self.__addedComponents[addi])
+ self.__addedComponents[addi] = nil
+ addi = addi + 1
+ elseif (operation == removeOperation) then
+ operation(self, self.__removedComponents[removei])
+ self.__removedComponents[removei] = nil
+ removei = removei + 1
+ end
+
+ self.__operations[i] = nil
+ end
+end
+
--- Destroys the Entity.
-- @return self
function Entity:destroy()
diff --git a/src/world.lua b/src/world.lua
index 50377d7..8a47aea 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -75,9 +75,20 @@ function World:flush()
for i = 1, self.entities.size do
e = self.entities:get(i)
+ if e.__isDirty then
+ e:flush()
+
+ if (not e.__wasAdded) then -- The __wasAdded check below will handle this instead
+ for j = 1, self.systems.size do
+ self.systems:get(j):__evaluate(e)
+ end
+ end
+
+ e.__isDirty = false
+ end
+
if e.__wasAdded then
e.__wasAdded = false
- e.__isDirty = false
for j = 1, self.systems.size do
self.systems:get(j):__evaluate(e)
@@ -95,14 +106,8 @@ function World:flush()
end
e.__wasRemoved = false
- end
- if e.__isDirty then
- for j = 1, self.systems.size do
- self.systems:get(j):__evaluate(e)
- end
-
- e.__isDirty = false
+ self:onEntityRemoved(e)
end
end
From 89443bd9619faaa9b1b5348161445ed23841624d Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 22 Dec 2019 21:01:47 +0100
Subject: [PATCH 021/113] Make e:flush 'private'
---
src/entity.lua | 2 +-
src/world.lua | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/entity.lua b/src/entity.lua
index 5bfc88e..a3d6483 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -108,7 +108,7 @@ function Entity:assemble(assemblage, ...)
return self
end
-function Entity:flush()
+function Entity:__flush()
local addi, removei = 1, 1
for i = 1, #self.__operations do
diff --git a/src/world.lua b/src/world.lua
index 8a47aea..63ef1a9 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -76,7 +76,7 @@ function World:flush()
e = self.entities:get(i)
if e.__isDirty then
- e:flush()
+ e:__flush()
if (not e.__wasAdded) then -- The __wasAdded check below will handle this instead
for j = 1, self.systems.size do
From f6536d5a0ee42c4b460fc78b1ac1da2f4e7dec4a Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 22 Dec 2019 21:02:25 +0100
Subject: [PATCH 022/113] Add entity:getWorld
---
src/entity.lua | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/entity.lua b/src/entity.lua
index a3d6483..25b063e 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -11,7 +11,7 @@ Entity.__index = Entity
-- @return A new Entity
function Entity.new()
local e = setmetatable({
- world = nil,
+ __world = nil,
__addedComponents = {},
__removedComponents = {},
@@ -164,6 +164,10 @@ function Entity:getComponents()
return self.__components
end
+function Entity:getWorld()
+ return self.__world
+end
+
return setmetatable(Entity, {
__call = function(_, ...)
return Entity.new(...)
From e0f88025bace537ee0d588427c270703849df61b Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 22 Dec 2019 21:08:30 +0100
Subject: [PATCH 023/113] Clean up component vs baseComponent
---
main.lua | 3 +--
src/component.lua | 33 ++++++++++++++++-----------------
src/components.lua | 12 ++++++------
src/entity.lua | 42 +++++++++++++++++++++---------------------
src/type.lua | 12 ++++++++----
5 files changed, 52 insertions(+), 50 deletions(-)
diff --git a/main.lua b/main.lua
index 6b9f293..f155a83 100644
--- a/main.lua
+++ b/main.lua
@@ -36,8 +36,7 @@ end)
local test_system = System("test_system", {Components.test_comp_1})
local function onEntityAdded(pool, e) -- luacheck: ignore
- local test_comp = e:get(Components.test_comp_1)
- print(test_comp.x)
+ print("Added")
end
local function onEntityRemoved(pool, e) -- luacheck: ignore
diff --git a/src/component.lua b/src/component.lua
index e1ef5aa..fd532ea 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -15,39 +15,38 @@ function Component.new(name, populate)
error("bad argument #1 to 'Component.new' (string expected, got "..type(name)..")", 2)
end
- if not (populate == nil or type(populate) == "function") then
- error("bad argument #2 to 'Component.new' (function/nil expected, got "..type(populate)..")", 2)
+ if not (type(populate) == "function") then
+ error("bad argument #2 to 'Component.new' (function expected, got "..type(populate)..")", 2)
end
- local component = setmetatable({
+ local baseComponent = setmetatable({
__name = name,
__populate = populate,
- __isComponent = true,
+ __isBaseComponent = true,
}, Component)
- component.__mt = {__index = component}
+ baseComponent.__mt = {__index = baseComponent}
- Components.register(name, component)
+ Components.register(name, baseComponent)
- return component
+ return baseComponent
end
---- Creates and initializes a new Bag.
+--- Creates and initializes a new Component.
-- @param ... The values passed to the populate function
--- @return A new initialized Bag
+-- @return A new initialized Component
function Component:__initialize(...)
- if self.__populate then
- local bag = setmetatable({
- __baseComponent = self,
- }, self)
+ local component = setmetatable({
+ __baseComponent = self,
- self.__populate(bag, ...)
+ __isComponent = true,
+ __isBaseComponent = false,
+ }, self)
- return bag
- end
+ self.__populate(component, ...)
- return true
+ return component
end
return setmetatable(Component, {
diff --git a/src/components.lua b/src/components.lua
index 63d40e0..2249774 100644
--- a/src/components.lua
+++ b/src/components.lua
@@ -6,24 +6,24 @@ local Type = require(PATH..".type")
local Components = {}
-function Components.register(name, component)
+function Components.register(name, baseComponent)
if (type(name) ~= "string") then
error("bad argument #1 to 'Components.register' (string expected, got "..type(name)..")", 3)
end
- if (not Type.isComponent(component)) then
- error("bad argument #2 to 'Components.register' (component expected, got "..type(component)..")", 3)
+ if (not Type.isBaseComponent(baseComponent)) then
+ error("bad argument #2 to 'Components.register' (BaseComponent expected, got "..type(baseComponent)..")", 3)
end
if (rawget(Components, name)) then
- error("bad argument #2 to 'Components.register' (Component with name '"..name.."' is already registerd)", 3)
+ error("bad argument #2 to 'Components.register' (BaseComponent with name '"..name.."' is already registerd)", 3)
end
- Components[name] = component
+ Components[name] = baseComponent
end
return setmetatable(Components, {
__index = function(_, name)
- error("Attempt to index component '"..tostring(name).."' that does not exist / was not registered", 2)
+ error("Attempt to index BaseComponent '"..tostring(name).."' that does not exist / was not registered", 2)
end
})
\ No newline at end of file
diff --git a/src/entity.lua b/src/entity.lua
index 25b063e..98d1c97 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -61,26 +61,26 @@ end
-- @param component The Component to add
-- @param ... The values passed to the Component
-- @return self
-function Entity:give(component, ...)
- if not Type.isComponent(component) then
- error("bad argument #1 to 'Entity:give' (Component expected, got "..type(component)..")", 2)
+function Entity:give(baseComponent, ...)
+ if not Type.isBaseComponent(baseComponent) then
+ error("bad argument #1 to 'Entity:give' (BaseComponent expected, got "..type(baseComponent)..")", 2)
end
- give(self, component, ...)
+ give(self, baseComponent, ...)
return self
end
-function Entity:ensure(component, ...)
- if not Type.isComponent(component) then
- error("bad argument #1 to 'Entity:ensure' (Component expected, got "..type(component)..")", 2)
+function Entity:ensure(baseComponent, ...)
+ if not Type.isBaseComponent(baseComponent) then
+ error("bad argument #1 to 'Entity:ensure' (BaseComponent expected, got "..type(baseComponent)..")", 2)
end
- if self[component] then
+ if self[baseComponent] then
return self
end
- give(self, component, ...)
+ give(self, baseComponent, ...)
return self
end
@@ -88,12 +88,12 @@ end
--- Removes a component from an Entity.
-- @param component The Component to remove
-- @return self
-function Entity:remove(component)
- if not Type.isComponent(component) then
- error("bad argument #1 to 'Entity:remove' (Component expected, got "..type(component)..")")
+function Entity:remove(baseComponent)
+ if not Type.isBaseComponent(baseComponent) then
+ error("bad argument #1 to 'Entity:remove' (BaseComponent expected, got "..type(baseComponent)..")")
end
- remove(self, component)
+ remove(self, baseComponent)
return self
end
@@ -141,23 +141,23 @@ end
--- Gets a Component from the Entity.
-- @param component The Component to get
-- @return The Bag from the Component
-function Entity:get(component)
- if not Type.isComponent(component) then
- error("bad argument #1 to 'Entity:get' (Component expected, got "..type(component)..")")
+function Entity:get(baseComponent)
+ if not Type.isBaseComponent(baseComponent) then
+ error("bad argument #1 to 'Entity:get' (BaseComponent expected, got "..type(baseComponent)..")")
end
- return self[component]
+ return self[baseComponent]
end
--- Returns true if the Entity has the Component.
-- @param component The Component to check against
-- @return True if the entity has the Bag. False otherwise
-function Entity:has(component)
- if not Type.isComponent(component) then
- error("bad argument #1 to 'Entity:has' (Component expected, got "..type(component)..")")
+function Entity:has(baseComponent)
+ if not Type.isBaseComponent(baseComponent) then
+ error("bad argument #1 to 'Entity:has' (BaseComponent expected, got "..type(baseComponent)..")")
end
- return self[component] ~= nil
+ return self[baseComponent] ~= nil
end
function Entity:getComponents()
diff --git a/src/type.lua b/src/type.lua
index 3da59d9..a7ba264 100644
--- a/src/type.lua
+++ b/src/type.lua
@@ -2,14 +2,18 @@
local Type = {}
-function Type.isComponent(t)
- return type(t) == "table" and t.__isComponent or false
-end
-
function Type.isEntity(t)
return type(t) == "table" and t.__isEntity or false
end
+function Type.isBaseComponent(t)
+ return type(t) == "table" and t.__isBaseComponent or false
+end
+
+function Type.isComponent(t)
+ return type(t) == "table" and t.__isComponent or false
+end
+
function Type.isBaseSystem(t)
return type(t) == "table" and t.__isBaseSystem or false
end
From 144a42dc9ed0f9bb6ea1085bee9d30df3c119df2 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 22 Dec 2019 23:07:42 +0100
Subject: [PATCH 024/113] Automate naming process
---
main.lua | 24 ++++++++-------
src/assemblage.lua | 13 +-------
src/component.lua | 15 ++--------
src/init.lua | 53 +++++++++++++++++++++++++++++++++
src/system.lua | 10 +------
src/world.lua | 10 +------
test/components/test_comp_1.lua | 6 ++++
7 files changed, 78 insertions(+), 53 deletions(-)
create mode 100644 test/components/test_comp_1.lua
diff --git a/main.lua b/main.lua
index f155a83..1a5ed40 100644
--- a/main.lua
+++ b/main.lua
@@ -9,8 +9,8 @@ require(file)
local Concord = require("src")
-local Component = require("src.component")
-local Components = require("src.components")
+local Component = Concord.component
+local Components = Concord.components
local System = Concord.system
local Systems = Concord.systems
@@ -20,20 +20,23 @@ local Entity = Concord.entity
local World = Concord.world
local Worlds = Concord.worlds
-Component("test_comp_1", function(e, x, y)
- e.x = x
- e.y = y
-end)
+Concord.loadComponents("test/components")
-Component("test_comp_2", function(e, a)
+
+local test_comp_2 = Component(function(e, a)
e.a = a
end)
+Components.register("test_comp_2", test_comp_2)
-Component("test_comp_3", function(e, b)
+
+local test_comp_3 = Component(function(e, b)
e.b = b
end)
+Components.register("test_comp_3", test_comp_3)
-local test_system = System("test_system", {Components.test_comp_1})
+
+local test_system = System({Components.test_comp_1})
+Systems.register("test_system", test_system)
local function onEntityAdded(pool, e) -- luacheck: ignore
print("Added")
@@ -61,7 +64,8 @@ function test_system:update2(dt) -- luacheck: ignore
end
-local world = World("testWorld")
+local world = World()
+Worlds.register("testWorld", world)
local entity = Entity()
entity
diff --git a/src/assemblage.lua b/src/assemblage.lua
index a6befed..79b3cbb 100644
--- a/src/assemblage.lua
+++ b/src/assemblage.lua
@@ -1,25 +1,14 @@
--- Assemblage
-local PATH = (...):gsub('%.[^%.]+$', '')
-
-local Assemblages = require(PATH..".world")
-
local Assemblage = {}
Assemblage.__index = Assemblage
-function Assemblage.new(name, assemble)
- if (type(name) ~= "string") then
- error("bad argument #1 to 'Assemblage.new' (string expected, got "..type(name)..")", 2)
- end
-
+function Assemblage.new(assemble)
local assemblage = setmetatable({
__assemble = assemble,
- __name = name,
__isAssemblage = true,
}, Assemblage)
-
- Assemblages.register(name, assemblage)
return assemblage
end
diff --git a/src/component.lua b/src/component.lua
index fd532ea..90dcdc6 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -1,26 +1,17 @@
--- Component
-local PATH = (...):gsub('%.[^%.]+$', '')
-
-local Components = require(PATH..".components")
-
local Component = {}
Component.__index = Component
--- Creates a new Component.
-- @param populate A function that populates the Bag with values
-- @return A Component object
-function Component.new(name, populate)
- if (type(name) ~= "string") then
- error("bad argument #1 to 'Component.new' (string expected, got "..type(name)..")", 2)
- end
-
+function Component.new(populate)
if not (type(populate) == "function") then
- error("bad argument #2 to 'Component.new' (function expected, got "..type(populate)..")", 2)
+ error("bad argument #1 to 'Component.new' (function expected, got "..type(populate)..")", 2)
end
local baseComponent = setmetatable({
- __name = name,
__populate = populate,
__isBaseComponent = true,
@@ -28,8 +19,6 @@ function Component.new(name, populate)
baseComponent.__mt = {__index = baseComponent}
- Components.register(name, baseComponent)
-
return baseComponent
end
diff --git a/src/init.lua b/src/init.lua
index 5f32550..66916db 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -45,4 +45,57 @@ Concord.worlds = require(PATH..".worlds")
Concord.assemblage = require(PATH..".assemblage")
Concord.assemblages = require(PATH..".assemblages")
+local function load(pathOrFiles, namespace)
+ if (type(pathOrFiles) ~= "string" and type(pathOrFiles) ~= "table") then
+ error("bad argument #1 to 'load' (string/table of strings expected, got "..type(pathOrFiles)..")", 3) -- luacheck: ignore
+ end
+
+ if (type(pathOrFiles) == "string") then
+ local info = love.filesystem.getInfo(pathOrFiles) -- luacheck: ignore
+ if (info == nil or info.type ~= "directory") then
+ error("bad argument #1 to 'load' (path '"..pathOrFiles.."' not found)", 3) -- luacheck: ignore
+ end
+
+ local files = love.filesystem.getDirectoryItems(pathOrFiles)
+
+ for _, file in ipairs(files) do
+ local name = file:sub(1, #file - 4)
+ local path = pathOrFiles.."."..name
+
+ namespace.register(name, require(path))
+ end
+ elseif (type(pathOrFiles == "table")) then
+ for _, path in ipairs(pathOrFiles) do
+ if (type(path) ~= "string") then
+ error("bad argument #2 to 'load' (string/table of strings expected, got table containing "..type(path)..")", 3) -- luacheck: ignore
+ end
+
+ local name = path
+
+ local dotIndex, slashIndex = path:match("^.*()%."), path:match("^.*()%/")
+ if (dotIndex or slashIndex) then
+ name = path:sub((dotIndex or slashIndex) + 1)
+ end
+
+ namespace.register(name, require(path))
+ end
+ end
+end
+
+function Concord.loadComponents(pathOrFiles)
+ load(pathOrFiles, Concord.components)
+end
+
+function Concord.loadSystems(pathOrFiles)
+ load(pathOrFiles, Concord.systems)
+end
+
+function Concord.loadWorlds(pathOrFiles)
+ load(pathOrFiles, Concord.worlds)
+end
+
+function Concord.loadAssemblages(pathOrFiles)
+ load(pathOrFiles, Concord.assemblages)
+end
+
return Concord
diff --git a/src/system.lua b/src/system.lua
index f9b696c..871b9a5 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -2,7 +2,6 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Systems = require(PATH..".systems")
local Pool = require(PATH..".pool")
local System = {}
@@ -36,20 +35,13 @@ System.mt = {
--- Creates a new System prototype.
-- @param ... Variable amounts of filters
-- @return A new System prototype
-function System.new(name, ...)
- if (type(name) ~= "string") then
- error("bad argument #1 to 'System.new' (string expected, got "..type(name)..")", 2)
- end
-
+function System.new(...)
local baseSystem = setmetatable({
- __name = name,
__isBaseSystem = true,
__filter = {...},
}, System.mt)
baseSystem.__index = baseSystem
- Systems.register(name, baseSystem)
-
return baseSystem
end
diff --git a/src/world.lua b/src/world.lua
index 63ef1a9..2fe1ca8 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -2,7 +2,6 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Worlds = require(PATH..".worlds")
local Type = require(PATH..".type")
local List = require(PATH..".list")
@@ -11,11 +10,7 @@ World.__index = World
--- Creates a new World.
-- @return The new World
-function World.new(name)
- if (type(name) ~= "string") then
- error("bad argument #1 to 'World.new' (string expected, got "..type(name)..")", 2)
- end
-
+function World.new()
local world = setmetatable({
entities = List(),
systems = List(),
@@ -27,12 +22,9 @@ function World.new(name)
__systemLookup = {},
- __name = name,
__isWorld = true,
}, World)
- Worlds.register(name, world)
-
return world
end
diff --git a/test/components/test_comp_1.lua b/test/components/test_comp_1.lua
new file mode 100644
index 0000000..ef9b98a
--- /dev/null
+++ b/test/components/test_comp_1.lua
@@ -0,0 +1,6 @@
+local Component = require("src").component
+
+return Component(function(e, x, y)
+ e.x = x
+ e.y = y
+end)
\ No newline at end of file
From a8bc92a9516567a063b731f51099e4315fe04fe8 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 22 Dec 2019 23:17:16 +0100
Subject: [PATCH 025/113] Allow for blank components
---
main.lua | 6 ++----
src/component.lua | 7 +++++--
2 files changed, 7 insertions(+), 6 deletions(-)
diff --git a/main.lua b/main.lua
index 1a5ed40..e7614b0 100644
--- a/main.lua
+++ b/main.lua
@@ -29,9 +29,7 @@ end)
Components.register("test_comp_2", test_comp_2)
-local test_comp_3 = Component(function(e, b)
- e.b = b
-end)
+local test_comp_3 = Component()
Components.register("test_comp_3", test_comp_3)
@@ -72,7 +70,7 @@ entity
:give(Components.test_comp_1, 100, 100)
:remove(Components.test_comp_1)
:give(Components.test_comp_1, 200, 100)
-
+:give(Components.test_comp_3, 200, 100)
Worlds.testWorld:addEntity(entity)
diff --git a/src/component.lua b/src/component.lua
index 90dcdc6..a2beddb 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -7,8 +7,8 @@ Component.__index = Component
-- @param populate A function that populates the Bag with values
-- @return A Component object
function Component.new(populate)
- if not (type(populate) == "function") then
- error("bad argument #1 to 'Component.new' (function expected, got "..type(populate)..")", 2)
+ if (type(populate) ~= "function" and type(populate) ~= "nil") then
+ error("bad argument #1 to 'Component.new' (function/nil expected, got "..type(populate)..")", 2)
end
local baseComponent = setmetatable({
@@ -22,6 +22,9 @@ function Component.new(populate)
return baseComponent
end
+function Component:__populate() -- luacheck: ignore
+end
+
--- Creates and initializes a new Component.
-- @param ... The values passed to the populate function
-- @return A new initialized Component
From 38d461f8d6db60604e624a5c3cb8a72271bba73d Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 29 Dec 2019 15:05:19 +0100
Subject: [PATCH 026/113] Fixed entity lifetime problems
---
main.lua | 95 ++++++++++++++++-----------------
src/entity.lua | 56 +++++--------------
src/world.lua | 82 +++++++++++++++++-----------
test/components/test_comp_1.lua | 6 ---
4 files changed, 110 insertions(+), 129 deletions(-)
delete mode 100644 test/components/test_comp_1.lua
diff --git a/main.lua b/main.lua
index e7614b0..f8db366 100644
--- a/main.lua
+++ b/main.lua
@@ -20,77 +20,72 @@ local Entity = Concord.entity
local World = Concord.world
local Worlds = Concord.worlds
-Concord.loadComponents("test/components")
+local test_comp_1 = Component(function(e, a)
+ e.a = a
+end)
local test_comp_2 = Component(function(e, a)
e.a = a
end)
-Components.register("test_comp_2", test_comp_2)
-
local test_comp_3 = Component()
-Components.register("test_comp_3", test_comp_3)
+local test_system_1 = System({test_comp_1})
-local test_system = System({Components.test_comp_1})
-Systems.register("test_system", test_system)
+function test_system_1:init()
+ self.pool.onEntityAdded = function()
+
+
-local function onEntityAdded(pool, e) -- luacheck: ignore
- print("Added")
-end
-
-local function onEntityRemoved(pool, e) -- luacheck: ignore
- print("Removed")
-end
-
-function test_system:init()
- self.pool.onEntityAdded = onEntityAdded
- self.pool.onEntityRemoved = onEntityRemoved
-end
-
-function test_system:update(dt) -- luacheck: ignore
- --[=[
- for _, v in ipairs(self.pool) do
- print(v)
+ print("Added to test_system 1")
end
- ]=]
+ self.pool.onEntityRemoved = function() print("Removed from test_system 1") end
end
-function test_system:update2(dt) -- luacheck: ignore
- --print(#self.pool)
+function test_system_1:test()
+ print("Running test_system_1 with: " ..#self.pool)
+
+ for _, e in ipairs(self.pool) do
+ local newE = Entity()
+ newE:give(test_comp_1)
+ self:getWorld():addEntity(newE)
+
+ e:give(test_comp_2)
+ end
end
+
+local test_system_2 = System({test_comp_2})
+
+function test_system_2:init()
+ self.pool.onEntityAdded = function(pool, e) print("Added to test_system 2") e:remove(test_comp_1) end
+ self.pool.onEntityRemoved = function() print("Removed from test_system 2") end
+end
+
+function test_system_2:test()
+ print("Running test_system_2 with: " ..#self.pool)
+
+ for _, e in ipairs(self.pool) do
+ end
+end
+
local world = World()
-Worlds.register("testWorld", world)
local entity = Entity()
-entity
-:give(Components.test_comp_1, 100, 100)
-:remove(Components.test_comp_1)
-:give(Components.test_comp_1, 200, 100)
-:give(Components.test_comp_3, 200, 100)
+entity:give(test_comp_1, 100, 100)
-Worlds.testWorld:addEntity(entity)
+world:addEntity(entity)
-world:addSystem(Systems.test_system, "update")
-world:addSystem(Systems.test_system, "update", "update2")
+world:addSystem(test_system_1, "test")
+world:addSystem(test_system_2, "test")
-function love.update(dt)
- world:flush()
+print("Iteration: 1")
+world:emit("test")
- world:emit("update", dt)
-end
+print("Iteration: 2")
+world:emit("test")
-function love.keypressed(key)
- if key == "q" then
- entity:remove(Components.test_comp_1)
- end
- if key == "w" then
- entity:give(Components.test_comp_1)
- end
- if key == "e" then
- world:removeEntity(entity)
- end
-end
\ No newline at end of file
+print("Iteration: 3")
+world:emit("test")
\ No newline at end of file
diff --git a/src/entity.lua b/src/entity.lua
index 98d1c97..b1db60c 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -13,10 +13,6 @@ function Entity.new()
local e = setmetatable({
__world = nil,
- __addedComponents = {},
- __removedComponents = {},
- __operations = {},
-
__components = {},
__isDirty = false,
@@ -29,32 +25,22 @@ function Entity.new()
return e
end
-local function giveOperation(e, component)
- local baseComponent = component.__baseComponent
-
- e[baseComponent] = component
- e.__components[baseComponent] = component
-end
-
-local function removeOperation(e, baseComponent)
- e[baseComponent] = nil
- e.__components[baseComponent] = nil
-end
-
local function give(e, baseComponent, ...)
local component = baseComponent:__initialize(...)
- e.__addedComponents[#e.__addedComponents + 1] = component
- e.__operations[#e.__operations + 1] = giveOperation
+ e[baseComponent] = component
+ e.__components[baseComponent] = component
e.__isDirty = true
+ e:__dirty()
end
local function remove(e, baseComponent)
- e.__removedComponents[#e.__removedComponents + 1] = baseComponent
- e.__operations[#e.__operations + 1] = removeOperation
+ e[baseComponent] = nil
+ e.__components[baseComponent] = nil
e.__isDirty = true
+ e:__dirty()
end
--- Gives an Entity a component with values.
@@ -108,36 +94,22 @@ function Entity:assemble(assemblage, ...)
return self
end
-function Entity:__flush()
- local addi, removei = 1, 1
-
- for i = 1, #self.__operations do
- local operation = self.__operations[i]
-
- if (operation == giveOperation) then
- operation(self, self.__addedComponents[addi])
- self.__addedComponents[addi] = nil
- addi = addi + 1
- elseif (operation == removeOperation) then
- operation(self, self.__removedComponents[removei])
- self.__removedComponents[removei] = nil
- removei = removei + 1
- end
-
- self.__operations[i] = nil
- end
-end
-
--- Destroys the Entity.
-- @return self
function Entity:destroy()
- if self.world then
- self.world:removeEntity(self)
+ if self.__world then
+ self.__world:removeEntity(self)
end
return self
end
+function Entity:__dirty()
+ if self.__world then
+ self.__world:__dirtyEntity(self)
+ end
+end
+
--- Gets a Component from the Entity.
-- @param component The Component to get
-- @return The Bag from the Component
diff --git a/src/world.lua b/src/world.lua
index 2fe1ca8..bf0eaf1 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -17,8 +17,9 @@ function World.new()
events = {},
- __added = {},
- __removed = {},
+ __added = List(), __backAdded = List(),
+ __removed = List(), __backRemoved = List(),
+ __dirty = List(), __backDirty = List(),
__systemLookup = {},
@@ -36,14 +37,16 @@ function World:addEntity(e)
error("bad argument #1 to 'World:addEntity' (Entity expected, got "..type(e)..")", 2)
end
- if e.world then
+ if e.__world then
error("bad argument #1 to 'World:addEntity' (Entity was already added to a world)", 2)
end
- e.world = self
+ e.__world = self
e.__wasAdded = true
- self.entities:add(e)
+ self.__added:add(e)
+
+ --self.entities:add(e)
return self
end
@@ -58,50 +61,65 @@ function World:removeEntity(e)
e.__wasRemoved = true
+ self.__removed:add(e)
+
return self
end
+function World:__dirtyEntity(e)
+ if not self.__dirty:has(e) then
+ self.__dirty:add(e)
+ end
+end
+
+
-- @return self
-function World:flush()
+function World:__flush()
+ -- Switch buffers
+ self.__added, self.__backAdded = self.__backAdded, self.__added
+ self.__removed, self.__backRemoved = self.__backRemoved, self.__removed
+ self.__dirty, self.__backDirty = self.__backDirty, self.__dirty
+
local e
- for i = 1, self.entities.size do
- e = self.entities:get(i)
- if e.__isDirty then
- e:__flush()
+ -- Added
+ for i = 1, self.__backAdded.size do
+ e = self.__backAdded:get(i)
- if (not e.__wasAdded) then -- The __wasAdded check below will handle this instead
- for j = 1, self.systems.size do
- self.systems:get(j):__evaluate(e)
- end
- end
+ self.entities:add(e)
- e.__isDirty = false
+ for j = 1, self.systems.size do
+ self.systems:get(j):__evaluate(e)
end
- if e.__wasAdded then
- e.__wasAdded = false
+ self:onEntityAdded(e)
+ end
+ self.__backAdded:clear()
- for j = 1, self.systems.size do
- self.systems:get(j):__evaluate(e)
- end
+ -- Removed
+ for i = 1, self.__backRemoved.size do
+ e = self.__backRemoved:get(i)
- self:onEntityAdded(e)
+ e.__world = nil
+ self.entities:remove(e)
+
+ for j = 1, self.systems.size do
+ self.systems:get(j):__remove(e)
end
- if e.__wasRemoved then
- e.world = nil
- self.entities:remove(e)
+ self:onEntityRemoved(e)
+ end
+ self.__backRemoved:clear()
- for j = 1, self.systems.size do
- self.systems:get(j):__remove(e)
- end
+ -- Dirty
+ for i = 1, self.__backDirty.size do
+ e = self.__backDirty:get(i)
- e.__wasRemoved = false
-
- self:onEntityRemoved(e)
+ for j = 1, self.systems.size do
+ self.systems:get(j):__evaluate(e)
end
end
+ self.__backDirty:clear()
return self
end
@@ -246,6 +264,8 @@ function World:emit(callbackName, ...)
local listener = listeners[i]
if listener.enabled then
+ self:__flush()
+
listener.system[listener.callback](listener.system, ...)
end
end
diff --git a/test/components/test_comp_1.lua b/test/components/test_comp_1.lua
deleted file mode 100644
index ef9b98a..0000000
--- a/test/components/test_comp_1.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local Component = require("src").component
-
-return Component(function(e, x, y)
- e.x = x
- e.y = y
-end)
\ No newline at end of file
From 0183421c47784bb315fc90c6b60a1b047416fae3 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sun, 29 Dec 2019 15:56:20 +0100
Subject: [PATCH 027/113] Clean up entity and world. Remove list:get
---
src/entity.lua | 9 +--------
src/list.lua | 7 -------
src/world.lua | 24 +++++++++---------------
test/components/test_comp_1.lua | 6 ++++++
tests/entityLifetime/init.lua | 0
tests/init.lua | 4 ++++
tests/requireModules/init.lua | 12 ++++++++++++
7 files changed, 32 insertions(+), 30 deletions(-)
create mode 100644 test/components/test_comp_1.lua
create mode 100644 tests/entityLifetime/init.lua
create mode 100644 tests/init.lua
create mode 100644 tests/requireModules/init.lua
diff --git a/src/entity.lua b/src/entity.lua
index b1db60c..755e75e 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -11,14 +11,9 @@ Entity.__index = Entity
-- @return A new Entity
function Entity.new()
local e = setmetatable({
- __world = nil,
-
+ __world = nil,
__components = {},
- __isDirty = false,
- __wasAdded = false,
- __wasRemoved = false,
-
__isEntity = true,
}, Entity)
@@ -31,7 +26,6 @@ local function give(e, baseComponent, ...)
e[baseComponent] = component
e.__components[baseComponent] = component
- e.__isDirty = true
e:__dirty()
end
@@ -39,7 +33,6 @@ local function remove(e, baseComponent)
e[baseComponent] = nil
e.__components[baseComponent] = nil
- e.__isDirty = true
e:__dirty()
end
diff --git a/src/list.lua b/src/list.lua
index b3e8fdf..89c4886 100644
--- a/src/list.lua
+++ b/src/list.lua
@@ -64,13 +64,6 @@ function List:remove(obj)
return self
end
---- Gets an object by numerical index.
--- @param index The index to look at
--- @return The object at the index
-function List:get(index)
- return self[index]
-end
-
--- Gets if the List has the object.
-- @param obj The object to search for
-- true if the list has the object, false otherwise
diff --git a/src/world.lua b/src/world.lua
index bf0eaf1..ca97e1a 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -2,8 +2,8 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Type = require(PATH..".type")
-local List = require(PATH..".list")
+local Type = require(PATH..".type")
+local List = require(PATH..".list")
local World = {}
World.__index = World
@@ -42,12 +42,8 @@ function World:addEntity(e)
end
e.__world = self
- e.__wasAdded = true
-
self.__added:add(e)
- --self.entities:add(e)
-
return self
end
@@ -59,8 +55,6 @@ function World:removeEntity(e)
error("bad argument #1 to 'World:removeEntity' (Entity expected, got "..type(e)..")", 2)
end
- e.__wasRemoved = true
-
self.__removed:add(e)
return self
@@ -84,12 +78,12 @@ function World:__flush()
-- Added
for i = 1, self.__backAdded.size do
- e = self.__backAdded:get(i)
+ e = self.__backAdded[i]
self.entities:add(e)
for j = 1, self.systems.size do
- self.systems:get(j):__evaluate(e)
+ self.systems[j]:__evaluate(e)
end
self:onEntityAdded(e)
@@ -98,13 +92,13 @@ function World:__flush()
-- Removed
for i = 1, self.__backRemoved.size do
- e = self.__backRemoved:get(i)
+ e = self.__backRemoved[i]
e.__world = nil
self.entities:remove(e)
for j = 1, self.systems.size do
- self.systems:get(j):__remove(e)
+ self.systems[j]:__remove(e)
end
self:onEntityRemoved(e)
@@ -113,10 +107,10 @@ function World:__flush()
-- Dirty
for i = 1, self.__backDirty.size do
- e = self.__backDirty:get(i)
+ e = self.__backDirty[i]
for j = 1, self.systems.size do
- self.systems:get(j):__evaluate(e)
+ self.systems[j]:__evaluate(e)
end
end
self.__backDirty:clear()
@@ -163,7 +157,7 @@ function World:addSystem(baseSystem, callbackName, callback, enabled)
-- Retroactively evaluate all entities for this system
for i = 1, self.entities.size do
- system:__evaluate(self.entities:get(i))
+ system:__evaluate(self.entities[i])
end
if callbackName then
diff --git a/test/components/test_comp_1.lua b/test/components/test_comp_1.lua
new file mode 100644
index 0000000..ef9b98a
--- /dev/null
+++ b/test/components/test_comp_1.lua
@@ -0,0 +1,6 @@
+local Component = require("src").component
+
+return Component(function(e, x, y)
+ e.x = x
+ e.y = y
+end)
\ No newline at end of file
diff --git a/tests/entityLifetime/init.lua b/tests/entityLifetime/init.lua
new file mode 100644
index 0000000..e69de29
diff --git a/tests/init.lua b/tests/init.lua
new file mode 100644
index 0000000..5804170
--- /dev/null
+++ b/tests/init.lua
@@ -0,0 +1,4 @@
+local PATH = (...):gsub('%.init$', '')
+
+require(PATH..".requireModules")
+require(PATH..".entityLifetime")
\ No newline at end of file
diff --git a/tests/requireModules/init.lua b/tests/requireModules/init.lua
new file mode 100644
index 0000000..69efe13
--- /dev/null
+++ b/tests/requireModules/init.lua
@@ -0,0 +1,12 @@
+local Concord = require("src")
+
+assert(Concord.component
+local Components = Concord.components
+
+local System = Concord.system
+local Systems = Concord.systems
+
+local Entity = Concord.entity
+
+local World = Concord.world
+local Worlds = Concord.worlds
\ No newline at end of file
From e5d6e1f4b970c5120fc7133a8f3996502ed88eb5 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 18:02:10 +0100
Subject: [PATCH 028/113] Remove temp tests
---
tests/entityLifetime/init.lua | 0
tests/init.lua | 4 ----
tests/requireModules/init.lua | 12 ------------
3 files changed, 16 deletions(-)
delete mode 100644 tests/entityLifetime/init.lua
delete mode 100644 tests/init.lua
delete mode 100644 tests/requireModules/init.lua
diff --git a/tests/entityLifetime/init.lua b/tests/entityLifetime/init.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/init.lua b/tests/init.lua
deleted file mode 100644
index 5804170..0000000
--- a/tests/init.lua
+++ /dev/null
@@ -1,4 +0,0 @@
-local PATH = (...):gsub('%.init$', '')
-
-require(PATH..".requireModules")
-require(PATH..".entityLifetime")
\ No newline at end of file
diff --git a/tests/requireModules/init.lua b/tests/requireModules/init.lua
deleted file mode 100644
index 69efe13..0000000
--- a/tests/requireModules/init.lua
+++ /dev/null
@@ -1,12 +0,0 @@
-local Concord = require("src")
-
-assert(Concord.component
-local Components = Concord.components
-
-local System = Concord.system
-local Systems = Concord.systems
-
-local Entity = Concord.entity
-
-local World = Concord.world
-local Worlds = Concord.worlds
\ No newline at end of file
From fea5fc72230c613bb49710728702cdc269f4d34f Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 18:03:12 +0100
Subject: [PATCH 029/113] Fix World:clear
---
main.lua | 3 ---
src/world.lua | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/main.lua b/main.lua
index f8db366..a671c69 100644
--- a/main.lua
+++ b/main.lua
@@ -35,9 +35,6 @@ local test_system_1 = System({test_comp_1})
function test_system_1:init()
self.pool.onEntityAdded = function()
-
-
-
print("Added to test_system 1")
end
self.pool.onEntityRemoved = function() print("Removed from test_system 1") end
diff --git a/src/world.lua b/src/world.lua
index ca97e1a..59ab04d 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -272,7 +272,7 @@ end
-- @return self
function World:clear()
for i = 1, self.entities.size do
- self.removeEntity(self.entities[i])
+ self:removeEntity(self.entities[i])
end
return self
From ce32d16b8d9637ac5cb5711d139297a02d968e3d Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 21:39:40 +0100
Subject: [PATCH 030/113] Allow Entity.new to take a world
---
main.lua | 4 +---
src/entity.lua | 10 +++++++++-
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/main.lua b/main.lua
index a671c69..c48bd62 100644
--- a/main.lua
+++ b/main.lua
@@ -70,11 +70,9 @@ end
local world = World()
-local entity = Entity()
+local entity = Entity(world)
entity:give(test_comp_1, 100, 100)
-world:addEntity(entity)
-
world:addSystem(test_system_1, "test")
world:addSystem(test_system_2, "test")
diff --git a/src/entity.lua b/src/entity.lua
index 755e75e..ff60a66 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -9,7 +9,11 @@ Entity.__index = Entity
--- Creates and initializes a new Entity.
-- @return A new Entity
-function Entity.new()
+function Entity.new(world)
+ if (world ~= nil and not Type.isWorld(world)) then
+ error("bad argument #1 to 'Entity.new' (world/nil expected, got "..type(world)..")", 2)
+ end
+
local e = setmetatable({
__world = nil,
__components = {},
@@ -17,6 +21,10 @@ function Entity.new()
__isEntity = true,
}, Entity)
+ if (world) then
+ world:addEntity(e)
+ end
+
return e
end
From f6468fbe6ba1d7ad8545f72bb637c24d03e63ae5 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 21:40:09 +0100
Subject: [PATCH 031/113] Add Entity:hasWorld
---
src/entity.lua | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src/entity.lua b/src/entity.lua
index ff60a66..86e42af 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -137,6 +137,10 @@ function Entity:getComponents()
return self.__components
end
+function Entity:hasWorld()
+ return self.__world and true or false
+end
+
function Entity:getWorld()
return self.__world
end
From 6eaf66308d7e7a923fb38d9dae21c913042a231f Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 22:07:13 +0100
Subject: [PATCH 032/113] Revamp how systems are added to worlds
---
main.lua | 3 +-
src/world.lua | 176 +++++++++++++++++---------------------------------
2 files changed, 61 insertions(+), 118 deletions(-)
diff --git a/main.lua b/main.lua
index c48bd62..1773142 100644
--- a/main.lua
+++ b/main.lua
@@ -73,8 +73,7 @@ local world = World()
local entity = Entity(world)
entity:give(test_comp_1, 100, 100)
-world:addSystem(test_system_1, "test")
-world:addSystem(test_system_2, "test")
+world:addSystems(test_system_1, test_system_2)
print("Iteration: 1")
world:emit("test")
diff --git a/src/world.lua b/src/world.lua
index 59ab04d..c9bba3c 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -15,7 +15,7 @@ function World.new()
entities = List(),
systems = List(),
- events = {},
+ events = {},
__added = List(), __backAdded = List(),
__removed = List(), __backRemoved = List(),
@@ -69,6 +69,11 @@ end
-- @return self
function World:__flush()
+ -- Early out
+ if (self.__added.size == 0 and self.__removed.size == 0 and self.__dirty.size == 0) then
+ return self
+ end
+
-- Switch buffers
self.__added, self.__backAdded = self.__backAdded, self.__added
self.__removed, self.__backRemoved = self.__backRemoved, self.__removed
@@ -76,7 +81,7 @@ function World:__flush()
local e
- -- Added
+ -- Process added entities
for i = 1, self.__backAdded.size do
e = self.__backAdded[i]
@@ -90,7 +95,7 @@ function World:__flush()
end
self.__backAdded:clear()
- -- Removed
+ -- Process removed entities
for i = 1, self.__backRemoved.size do
e = self.__backRemoved[i]
@@ -105,7 +110,7 @@ function World:__flush()
end
self.__backRemoved:clear()
- -- Dirty
+ -- Process dirty entities
for i = 1, self.__backDirty.size do
e = self.__backDirty[i]
@@ -118,6 +123,55 @@ function World:__flush()
return self
end
+local blacklistedSystemMethods = {
+ "init",
+}
+
+function World:addSystem(baseSystem)
+ if (not Type.isBaseSystem(baseSystem)) then
+ error("bad argument #"..i.." to 'World:addSystems' (baseSystem expected, got "..type(baseSystem)..")", 2)
+ end
+
+ -- TODO: Check if baseSystem was already added
+
+ -- Create instance of system
+ local system = baseSystem(self)
+
+ self.__systemLookup[baseSystem] = system
+ self.systems:add(system)
+
+ for callbackName, callback in pairs(baseSystem) do
+ -- Skip callback if its blacklisted
+ if (not blacklistedSystemMethods[callbackName]) then
+ -- Make container for all listeners of the callback if it does not exist yet
+ if (not self.events[callbackName]) then
+ self.events[callbackName] = {}
+ end
+
+ -- Add callback to listeners
+ local listeners = self.events[callbackName]
+ listeners[#listeners + 1] = {
+ system = system,
+ callback = callback,
+ }
+ end
+ end
+
+ -- Evaluate all existing entities
+ for j = 1, self.entities.size do
+ system:__evaluate(self.entities[j])
+ end
+end
+
+function World:addSystems(...)
+ for i = 1, select("#", ...) do
+ local baseSystem = select(i, ...)
+
+ self:addSystem(baseSystem)
+ end
+end
+
+
function World:hasSystem(baseSystem)
if not Type.isBaseSystem(baseSystem) then
error("bad argument #1 to 'World:getSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
@@ -134,114 +188,6 @@ function World:getSystem(baseSystem)
return self.__systemLookup[baseSystem]
end
---- Adds a System to the World.
--- @param baseSystem The BaseSystem of the system to add
--- @param callbackName The callbackName to register to
--- @param callback The function name to call. Defaults to callbackName
--- @param enabled If the system is enabled. Defaults to true
--- @return self
-function World:addSystem(baseSystem, callbackName, callback, enabled)
- if not Type.isBaseSystem(baseSystem) then
- error("bad argument #1 to 'World:addSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
- end
-
- local system = self.__systemLookup[baseSystem]
- if (not system) then
- -- System was not created for this world yet, so we create it ourselves
- system = baseSystem(self)
-
- self.__systemLookup[baseSystem] = system
-
- self.systems:add(system)
- end
-
- -- Retroactively evaluate all entities for this system
- for i = 1, self.entities.size do
- system:__evaluate(self.entities[i])
- end
-
- if callbackName then
- self.events[callbackName] = self.events[callbackName] or {}
-
- local i = #self.events[callbackName] + 1
- self.events[callbackName][i] = {
- system = system,
- callback = callback or callbackName,
- enabled = enabled == nil or enabled,
- }
-
- if enabled == nil or enabled then
- system:enabledCallback(callback or callbackName)
- end
- end
-
- return self
-end
-
---- Enables a System in the World.
--- @param system The System to enable
--- @param callbackName The Event it was registered to
--- @param callback The callback it was registered with. Defaults to eventName
--- @return self
-function World:enableSystem(system, callbackName, callback)
- if not Type.isSystem(system) then
- error("bad argument #1 to 'World:enableSystem' (System expected, got "..type(system)..")", 2)
- end
-
- return self:setSystem(system, callbackName, callback, true)
-end
-
---- Disables a System in the World.
--- @param system The System to disable
--- @param eventName The Event it was registered to
--- @param callback The callback it was registered with. Defaults to eventName
--- @return self
-function World:disableSystem(system, callbackName, callback)
- if not Type.isSystem(system) then
- error("bad argument #1 to 'World:disableSystem' (System expected, got "..type(system)..")", 2)
- end
-
- return self:setSystem(system, callbackName, callback, false)
-end
-
---- Sets a System 'enable' in the World.
--- @param system The System to set
--- @param eventName The Event it was registered to
--- @param callback The callback it was registered with. Defaults to eventName
--- @param enable The state to set it to
--- @return self
-function World:setSystem(system, callbackName, callback, enable)
- if not Type.isSystem(system) then
- error("bad argument #1 to 'World:setSystem' (System expected, got "..type(system)..")", 2)
- end
-
- callback = callback or callbackName
-
- if callback then
- local listeners = self.events[callbackName]
-
- if listeners then
- for i = 1, #listeners do
- local listener = listeners[i]
-
- if listener.system == system and listener.callback == callback then
- if enable and not listener.enabled then
- system:enabledCallback(callback)
- elseif not enable and listener.enabled then
- system:disabledCallback(callback)
- end
-
- listener.enabled = enable
-
- break
- end
- end
- end
- end
-
- return self
-end
-
--- Emits an Event in the World.
-- @param eventName The Event that should be emitted
-- @param ... Parameters passed to listeners
@@ -257,11 +203,9 @@ function World:emit(callbackName, ...)
for i = 1, #listeners do
local listener = listeners[i]
- if listener.enabled then
- self:__flush()
+ self:__flush()
- listener.system[listener.callback](listener.system, ...)
- end
+ listener.callback(listener.system, ...)
end
end
From 04a35a117eafba6589001189e2f3b0f0fba7240d Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 22:19:01 +0100
Subject: [PATCH 033/113] Allow systems to be disabled
---
src/system.lua | 34 +++++++++++++++++++++++++++++++---
src/world.lua | 8 +++++---
2 files changed, 36 insertions(+), 6 deletions(-)
diff --git a/src/system.lua b/src/system.lua
index 871b9a5..e77934e 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -9,6 +9,8 @@ System.mt = {
__index = System,
__call = function(baseSystem, world)
local system = setmetatable({
+ __enabled = true,
+
__pools = {},
__world = world,
@@ -94,6 +96,32 @@ function System:clear()
end
end
+function System:enable()
+ self:setEnabled(true)
+end
+
+function System:disable()
+ self:setEnabled(false)
+end
+
+function System:toggleEnable()
+ self:setEnabled(not self.__enabled)
+end
+
+function System:setEnabled(enable)
+ if (not self.__enabled and enable) then
+ self.__enabled = true
+ self:onEnabledCallback()
+ elseif (self.__enabled and not enable) then
+ self.__enabled = false
+ self:onDisabledCallback()
+ end
+end
+
+function System:isEnabled()
+ return self.__enabled
+end
+
--- Returns the World the System is in.
-- @return The world the system is in
function System:getWorld()
@@ -107,16 +135,16 @@ end
-- Default callback for when a System's callback is enabled.
-- @param callbackName The name of the callback that was enabled
-function System:enabledCallback(callbackName) -- luacheck: ignore
+function System:onEnabledCallback(callbackName) -- luacheck: ignore
end
-- Default callback for when a System's callback is disabled.
-- @param callbackName The name of the callback that was disabled
-function System:disabledCallback(callbackName) -- luacheck: ignore
+function System:onDisabledCallback(callbackName) -- luacheck: ignore
end
return setmetatable(System, {
__call = function(_, ...)
return System.new(...)
end,
-})
+})
\ No newline at end of file
diff --git a/src/world.lua b/src/world.lua
index c9bba3c..9ce0215 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -129,7 +129,7 @@ local blacklistedSystemMethods = {
function World:addSystem(baseSystem)
if (not Type.isBaseSystem(baseSystem)) then
- error("bad argument #"..i.." to 'World:addSystems' (baseSystem expected, got "..type(baseSystem)..")", 2)
+ error("bad argument #1 to 'World:addSystems' (baseSystem expected, got "..type(baseSystem)..")", 2)
end
-- TODO: Check if baseSystem was already added
@@ -203,9 +203,11 @@ function World:emit(callbackName, ...)
for i = 1, #listeners do
local listener = listeners[i]
- self:__flush()
+ if (listener.system.__enabled) then
+ self:__flush()
- listener.callback(listener.system, ...)
+ listener.callback(listener.system, ...)
+ end
end
end
From 56b52445418fbb518f79e6335d7a394cdf2ae8b1 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 22:20:31 +0100
Subject: [PATCH 034/113] Let System functions return self
---
src/system.lua | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/src/system.lua b/src/system.lua
index e77934e..28208d2 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -78,6 +78,8 @@ function System:__evaluate(e)
pool:remove(e)
end
end
+
+ return self
end
--- Remove an Entity from the System.
@@ -88,24 +90,34 @@ function System:__remove(e)
pool:remove(e)
end
end
+
+ return self
end
function System:clear()
for i = 1, #self.__pools do
self.__pools[i]:clear()
end
+
+ return self
end
function System:enable()
self:setEnabled(true)
+
+ return self
end
function System:disable()
self:setEnabled(false)
+
+ return self
end
function System:toggleEnable()
self:setEnabled(not self.__enabled)
+
+ return self
end
function System:setEnabled(enable)
@@ -116,6 +128,8 @@ function System:setEnabled(enable)
self.__enabled = false
self:onDisabledCallback()
end
+
+ return self
end
function System:isEnabled()
From 6aeb91d9840c151ccf31f8629ea7c93bdbb4d42e Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 23:01:04 +0100
Subject: [PATCH 035/113] Add optional optimization for worlds and systems
---
main.lua | 75 ++++++++++++++++----------------------------------
src/system.lua | 15 ++++++++--
src/utils.lua | 9 ++++++
src/world.lua | 16 +++++++++--
4 files changed, 58 insertions(+), 57 deletions(-)
create mode 100644 src/utils.lua
diff --git a/main.lua b/main.lua
index 1773142..ff2ec47 100644
--- a/main.lua
+++ b/main.lua
@@ -9,77 +9,48 @@ require(file)
local Concord = require("src")
-local Component = Concord.component
-local Components = Concord.components
-
-local System = Concord.system
-local Systems = Concord.systems
-
-local Entity = Concord.entity
-
-local World = Concord.world
-local Worlds = Concord.worlds
-
+local Component = Concord.component
+local System = Concord.system
+local Entity = Concord.entity
+local World = Concord.world
local test_comp_1 = Component(function(e, a)
e.a = a
end)
-local test_comp_2 = Component(function(e, a)
- e.a = a
-end)
-
-local test_comp_3 = Component()
-
local test_system_1 = System({test_comp_1})
-
-function test_system_1:init()
- self.pool.onEntityAdded = function()
- print("Added to test_system 1")
- end
- self.pool.onEntityRemoved = function() print("Removed from test_system 1") end
-end
+local test_system_2 = System({test_comp_1})
+local test_system_3 = System({test_comp_1})
function test_system_1:test()
- print("Running test_system_1 with: " ..#self.pool)
-
- for _, e in ipairs(self.pool) do
- local newE = Entity()
- newE:give(test_comp_1)
- self:getWorld():addEntity(newE)
-
- e:give(test_comp_2)
+ for _, _ in ipairs(self.pool) do
end
end
-
-
-local test_system_2 = System({test_comp_2})
-
-function test_system_2:init()
- self.pool.onEntityAdded = function(pool, e) print("Added to test_system 2") e:remove(test_comp_1) end
- self.pool.onEntityRemoved = function() print("Removed from test_system 2") end
-end
-
function test_system_2:test()
- print("Running test_system_2 with: " ..#self.pool)
+ for _, _ in ipairs(self.pool) do
+ end
+end
- for _, e in ipairs(self.pool) do
+function test_system_3:test()
+ for _, _ in ipairs(self.pool) do
end
end
local world = World()
-local entity = Entity(world)
-entity:give(test_comp_1, 100, 100)
+world:addSystems(test_system_1, test_system_2, test_system_3)
-world:addSystems(test_system_1, test_system_2)
+for _ = 1, 100 do
+ local entity = Entity(world)
+ entity:give(test_comp_1, 100, 100)
+end
-print("Iteration: 1")
-world:emit("test")
-print("Iteration: 2")
-world:emit("test")
+local start = love.timer.getTime()
+for _ = 1, 1000000 do
+ world:emit("test")
+end
+local stop = love.timer.getTime()
-print("Iteration: 3")
-world:emit("test")
\ No newline at end of file
+print("Time taken: " .. stop - start)
\ No newline at end of file
diff --git a/src/system.lua b/src/system.lua
index 28208d2..4839f70 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -2,9 +2,13 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Pool = require(PATH..".pool")
+local Pool = require(PATH..".pool")
+local Utils = require(PATH..".utils")
+
+local System = {
+ ENABLE_OPTIMIZATION = true,
+}
-local System = {}
System.mt = {
__index = System,
__call = function(baseSystem, world)
@@ -18,6 +22,13 @@ System.mt = {
__isBaseSystem = false, -- Overwrite value from baseSystem
}, baseSystem)
+ -- Optimization: We deep copy the World class into our instance of a world.
+ -- This grants slightly faster access times at the cost of memory.
+ -- Since there (generally) won't be many instances of worlds this is a worthwhile tradeoff
+ if (System.ENABLE_OPTIMIZATION) then
+ Utils.shallowCopy(System, system)
+ end
+
for _, filter in pairs(baseSystem.__filter) do
local pool = system:__buildPool(filter)
if not system[pool.name] then
diff --git a/src/utils.lua b/src/utils.lua
new file mode 100644
index 0000000..43adf6c
--- /dev/null
+++ b/src/utils.lua
@@ -0,0 +1,9 @@
+local Utils = {}
+
+function Utils.shallowCopy(orig, target)
+ for key, value in pairs(orig) do
+ target[key] = value
+ end
+end
+
+return Utils
\ No newline at end of file
diff --git a/src/world.lua b/src/world.lua
index 9ce0215..bd79ebd 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -2,10 +2,13 @@
local PATH = (...):gsub('%.[^%.]+$', '')
-local Type = require(PATH..".type")
-local List = require(PATH..".list")
+local Type = require(PATH..".type")
+local List = require(PATH..".list")
+local Utils = require(PATH..".utils")
-local World = {}
+local World = {
+ ENABLE_OPTIMIZATION = true,
+}
World.__index = World
--- Creates a new World.
@@ -26,6 +29,13 @@ function World.new()
__isWorld = true,
}, World)
+ -- Optimization: We deep copy the World class into our instance of a world.
+ -- This grants slightly faster access times at the cost of memory.
+ -- Since there (generally) won't be many instances of worlds this is a worthwhile tradeoff
+ if (World.ENABLE_OPTIMIZATION) then
+ Utils.shallowCopy(World, world)
+ end
+
return world
end
From f6669b2e6385c33c165625bc0f4b41fdc8b699b4 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Fri, 3 Jan 2020 23:12:56 +0100
Subject: [PATCH 036/113] Improve internal style
---
src/assemblage.lua | 6 ++++--
src/component.lua | 10 ++++++---
src/entity.lua | 6 ++++--
src/list.lua | 52 +++++++++++++++++++++++++++++-----------------
src/pool.lua | 30 +++++++++++++++++---------
src/system.lua | 16 +++++++-------
src/world.lua | 24 +++++++++++----------
7 files changed, 89 insertions(+), 55 deletions(-)
diff --git a/src/assemblage.lua b/src/assemblage.lua
index 79b3cbb..241525d 100644
--- a/src/assemblage.lua
+++ b/src/assemblage.lua
@@ -1,14 +1,16 @@
--- Assemblage
local Assemblage = {}
-Assemblage.__index = Assemblage
+Assemblage.__mt = {
+ __index = Assemblage,
+}
function Assemblage.new(assemble)
local assemblage = setmetatable({
__assemble = assemble,
__isAssemblage = true,
- }, Assemblage)
+ }, Assemblage.__mt)
return assemblage
end
diff --git a/src/component.lua b/src/component.lua
index a2beddb..d288815 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -1,7 +1,9 @@
--- Component
local Component = {}
-Component.__index = Component
+Component.__mt = {
+ __index = Component,
+}
--- Creates a new Component.
-- @param populate A function that populates the Bag with values
@@ -15,9 +17,11 @@ function Component.new(populate)
__populate = populate,
__isBaseComponent = true,
- }, Component)
+ }, Component.__mt)
- baseComponent.__mt = {__index = baseComponent}
+ baseComponent.__mt = {
+ __index = baseComponent
+ }
return baseComponent
end
diff --git a/src/entity.lua b/src/entity.lua
index 86e42af..38cc60d 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -5,7 +5,9 @@ local PATH = (...):gsub('%.[^%.]+$', '')
local Type = require(PATH..".type")
local Entity = {}
-Entity.__index = Entity
+Entity.__mt = {
+ __index = Entity,
+}
--- Creates and initializes a new Entity.
-- @return A new Entity
@@ -19,7 +21,7 @@ function Entity.new(world)
__components = {},
__isEntity = true,
- }, Entity)
+ }, Entity.__mt)
if (world) then
world:addEntity(e)
diff --git a/src/list.lua b/src/list.lua
index 89c4886..94fee52 100644
--- a/src/list.lua
+++ b/src/list.lua
@@ -1,35 +1,22 @@
--- List
local List = {}
-local mt = {__index = List}
+List.__mt = {
+ __index = List
+}
--- Creates a new List.
-- @return A new list
function List.new()
return setmetatable({
size = 0,
- }, mt)
-end
-
---- Clears the List completely.
--- @return self
-function List:clear()
- for i = 1, self.size do
- local o = self[i]
-
- self[o] = nil
- self[i] = nil
- end
-
- self.size = 0
-
- return self
+ }, List.__mt)
end
--- Adds an object to the List.
-- @param obj The object to add
-- @return self
-function List:add(obj) -- obj can not be a number and also not the string "size"
+function List:__add(obj) -- obj can not be a number and also not the string "size"
local size = self.size + 1
self[size] = obj
@@ -42,7 +29,7 @@ end
--- Removes an object from the List.
-- @param obj The object to remove
-- @return self
-function List:remove(obj)
+function List:__remove(obj)
local index = self[obj]
if not index then return end
local size = self.size
@@ -64,6 +51,21 @@ function List:remove(obj)
return self
end
+--- Clears the List completely.
+-- @return self
+function List:__clear()
+ for i = 1, self.size do
+ local o = self[i]
+
+ self[o] = nil
+ self[i] = nil
+ end
+
+ self.size = 0
+
+ return self
+end
+
--- Gets if the List has the object.
-- @param obj The object to search for
-- true if the list has the object, false otherwise
@@ -71,6 +73,18 @@ function List:has(obj)
return self[obj] and true or false
end
+function List:get(i)
+ return self[i]
+end
+
+function List:indexOf(obj)
+ if (not self[obj]) then
+ error("bad argument #1 to 'List:indexOf' (Object was not in List)", 2)
+ end
+
+ return self[obj]
+end
+
return setmetatable(List, {
__call = function()
return List.new()
diff --git a/src/pool.lua b/src/pool.lua
index 92373e2..1b7be39 100644
--- a/src/pool.lua
+++ b/src/pool.lua
@@ -5,17 +5,19 @@ local PATH = (...):gsub('%.[^%.]+$', '')
local List = require(PATH..".list")
local Pool = {}
-Pool.__index = Pool
+Pool.__mt = {
+ __index = Pool,
+}
--- Creates a new Pool
-- @param name Identifier for the Pool.
-- @param filter Table containing the required Components
-- @return The new Pool
function Pool.new(name, filter)
- local pool = setmetatable(List(), Pool)
+ local pool = setmetatable(List(), Pool.__mt)
- pool.name = name
- pool.filter = filter
+ pool.__name = name
+ pool.__filter = filter
pool.__isPool = true
@@ -25,8 +27,8 @@ end
--- Checks if an Entity is eligible for the Pool.
-- @param e The Entity to check
-- @return True if the entity is eligible, false otherwise
-function Pool:eligible(e)
- for _, component in ipairs(self.filter) do
+function Pool:__eligible(e)
+ for _, component in ipairs(self.__filter) do
if not e[component] then
return false
end
@@ -35,16 +37,24 @@ function Pool:eligible(e)
return true
end
-function Pool:add(e)
- List.add(self, e)
+function Pool:__add(e)
+ List.__add(self, e)
self:onEntityAdded(e)
end
-function Pool:remove(e)
- List.remove(self, e)
+function Pool:__remove(e)
+ List.__remove(self, e)
self:onEntityRemoved(e)
end
+function Pool:getName()
+ return self.__name
+end
+
+function Pool:getFilter()
+ return self.__filter
+end
+
function Pool:onEntityAdded(e) -- luacheck: ignore
end
diff --git a/src/system.lua b/src/system.lua
index 4839f70..4e0b778 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -9,7 +9,7 @@ local System = {
ENABLE_OPTIMIZATION = true,
}
-System.mt = {
+System.mt = {
__index = System,
__call = function(baseSystem, world)
local system = setmetatable({
@@ -31,8 +31,8 @@ System.mt = {
for _, filter in pairs(baseSystem.__filter) do
local pool = system:__buildPool(filter)
- if not system[pool.name] then
- system[pool.name] = pool
+ if not system[pool.__name] then
+ system[pool.__name] = pool
system.__pools[#system.__pools + 1] = pool
else
error("Pool with name '"..pool.name.."' already exists.")
@@ -81,12 +81,12 @@ end
function System:__evaluate(e)
for _, pool in ipairs(self.__pools) do
local has = pool:has(e)
- local eligible = pool:eligible(e)
+ local eligible = pool:__eligible(e)
if not has and eligible then
- pool:add(e)
+ pool:__add(e)
elseif has and not eligible then
- pool:remove(e)
+ pool:__remove(e)
end
end
@@ -98,7 +98,7 @@ end
function System:__remove(e)
for _, pool in ipairs(self.__pools) do
if pool:has(e) then
- pool:remove(e)
+ pool:__remove(e)
end
end
@@ -107,7 +107,7 @@ end
function System:clear()
for i = 1, #self.__pools do
- self.__pools[i]:clear()
+ self.__pools[i]:__clear()
end
return self
diff --git a/src/world.lua b/src/world.lua
index bd79ebd..f15a14d 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -9,7 +9,9 @@ local Utils = require(PATH..".utils")
local World = {
ENABLE_OPTIMIZATION = true,
}
-World.__index = World
+World.__mt = {
+ __index = World,
+}
--- Creates a new World.
-- @return The new World
@@ -27,7 +29,7 @@ function World.new()
__systemLookup = {},
__isWorld = true,
- }, World)
+ }, World.__mt)
-- Optimization: We deep copy the World class into our instance of a world.
-- This grants slightly faster access times at the cost of memory.
@@ -52,7 +54,7 @@ function World:addEntity(e)
end
e.__world = self
- self.__added:add(e)
+ self.__added:__add(e)
return self
end
@@ -65,14 +67,14 @@ function World:removeEntity(e)
error("bad argument #1 to 'World:removeEntity' (Entity expected, got "..type(e)..")", 2)
end
- self.__removed:add(e)
+ self.__removed:__add(e)
return self
end
function World:__dirtyEntity(e)
if not self.__dirty:has(e) then
- self.__dirty:add(e)
+ self.__dirty:__add(e)
end
end
@@ -95,7 +97,7 @@ function World:__flush()
for i = 1, self.__backAdded.size do
e = self.__backAdded[i]
- self.entities:add(e)
+ self.entities:__add(e)
for j = 1, self.systems.size do
self.systems[j]:__evaluate(e)
@@ -103,14 +105,14 @@ function World:__flush()
self:onEntityAdded(e)
end
- self.__backAdded:clear()
+ self.__backAdded:__clear()
-- Process removed entities
for i = 1, self.__backRemoved.size do
e = self.__backRemoved[i]
e.__world = nil
- self.entities:remove(e)
+ self.entities:__remove(e)
for j = 1, self.systems.size do
self.systems[j]:__remove(e)
@@ -118,7 +120,7 @@ function World:__flush()
self:onEntityRemoved(e)
end
- self.__backRemoved:clear()
+ self.__backRemoved:__clear()
-- Process dirty entities
for i = 1, self.__backDirty.size do
@@ -128,7 +130,7 @@ function World:__flush()
self.systems[j]:__evaluate(e)
end
end
- self.__backDirty:clear()
+ self.__backDirty:__clear()
return self
end
@@ -148,7 +150,7 @@ function World:addSystem(baseSystem)
local system = baseSystem(self)
self.__systemLookup[baseSystem] = system
- self.systems:add(system)
+ self.systems:__add(system)
for callbackName, callback in pairs(baseSystem) do
-- Skip callback if its blacklisted
From 69a9e83759175247c8f8b6dca0c5ef05f8bc8ea6 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sat, 4 Jan 2020 01:04:18 +0100
Subject: [PATCH 037/113] Document full project. Lots of small fixes
---
src/assemblage.lua | 10 ++++
src/assemblages.lua | 10 ++--
src/component.lua | 29 ++++++-----
src/components.lua | 16 +++---
src/entity.lua | 117 +++++++++++++++++++++++++++-----------------
src/init.lua | 20 +++++++-
src/list.lua | 23 ++++++---
src/pool.lua | 27 ++++++++--
src/system.lua | 76 ++++++++++++++++------------
src/systems.lua | 14 ++++--
src/type.lua | 32 ++++++++++--
src/utils.lua | 6 +++
src/world.lua | 112 ++++++++++++++++++++++++++++--------------
src/worlds.lua | 6 ++-
14 files changed, 342 insertions(+), 156 deletions(-)
diff --git a/src/assemblage.lua b/src/assemblage.lua
index 241525d..c2303f2 100644
--- a/src/assemblage.lua
+++ b/src/assemblage.lua
@@ -1,10 +1,15 @@
--- Assemblage
+-- An Assemblage is a function that 'makes' an entity something.
+-- It does this by :give'ing or :ensure'ing Components, or by :assemble'ing the Entity.
local Assemblage = {}
Assemblage.__mt = {
__index = Assemblage,
}
+--- Creates a new Assemblage.
+-- @param assemble Function that assembles an Entity
+-- @return A new Assemblage
function Assemblage.new(assemble)
local assemblage = setmetatable({
__assemble = assemble,
@@ -15,6 +20,11 @@ function Assemblage.new(assemble)
return assemblage
end
+--- Assembles an Entity.
+-- @see Entity:assemble
+-- @param e Entity to assemble
+-- @param ... Varargs to pass to the assemble function
+-- @ return self
function Assemblage:assemble(e, ...)
self.__assemble(e, ...)
diff --git a/src/assemblages.lua b/src/assemblages.lua
index f86f629..f34e3b9 100644
--- a/src/assemblages.lua
+++ b/src/assemblages.lua
@@ -1,4 +1,5 @@
--- Assemblages
+--- Assemblages
+-- Container for registered Assemblages
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -6,17 +7,20 @@ local Type = require(PATH..".type")
local Assemblages = {}
+--- Registers an Assemblage.
+-- @param name Name to register under
+-- @param assemblage Assemblage to register
function Assemblages.register(name, assemblage)
if (type(name) ~= "string") then
error("bad argument #1 to 'Assemblages.register' (string expected, got "..type(name)..")", 3)
end
if (not Type.isAssemblage(assemblage)) then
- error("bad argument #2 to 'Assemblages.register' (assemblage expected, got "..type(world)..")", 3)
+ error("bad argument #2 to 'Assemblages.register' (assemblage expected, got "..type(assemblage)..")", 3)
end
if (rawget(Assemblages, name)) then
- error("bad argument #2 to 'Assemblages.register' (Assemblage with name '"..name.."' is already registerd)", 3)
+ error("bad argument #2 to 'Assemblages.register' (Assemblage with name '"..name.."' was already registerd)", 3)
end
Assemblages[name] = assemblage
diff --git a/src/component.lua b/src/component.lua
index d288815..bf862a0 100644
--- a/src/component.lua
+++ b/src/component.lua
@@ -1,43 +1,46 @@
--- Component
+-- A Component is a pure data container.
+-- A Component is contained by a single entity.
local Component = {}
Component.__mt = {
__index = Component,
}
---- Creates a new Component.
--- @param populate A function that populates the Bag with values
--- @return A Component object
+--- Creates a new ComponentClass.
+-- @param populate Function that populates a Component with values
+-- @return A new ComponentClass
function Component.new(populate)
if (type(populate) ~= "function" and type(populate) ~= "nil") then
error("bad argument #1 to 'Component.new' (function/nil expected, got "..type(populate)..")", 2)
end
- local baseComponent = setmetatable({
+ local componentClass = setmetatable({
__populate = populate,
- __isBaseComponent = true,
+ __isComponentClass = true,
}, Component.__mt)
- baseComponent.__mt = {
- __index = baseComponent
+ componentClass.__mt = {
+ __index = componentClass
}
- return baseComponent
+ return componentClass
end
+--- Internal: Populates a Component with values
function Component:__populate() -- luacheck: ignore
end
---- Creates and initializes a new Component.
--- @param ... The values passed to the populate function
--- @return A new initialized Component
+--- Internal: Creates and populates a new Component.
+-- @param ... Varargs passed to the populate function
+-- @return A new populated Component
function Component:__initialize(...)
local component = setmetatable({
- __baseComponent = self,
+ __componentClass = self,
__isComponent = true,
- __isBaseComponent = false,
+ __isComponentClass = false,
}, self)
self.__populate(component, ...)
diff --git a/src/components.lua b/src/components.lua
index 2249774..76780de 100644
--- a/src/components.lua
+++ b/src/components.lua
@@ -1,4 +1,5 @@
-- Components
+-- Container for registered ComponentClasss
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -6,24 +7,27 @@ local Type = require(PATH..".type")
local Components = {}
-function Components.register(name, baseComponent)
+--- Registers a ComponentClass.
+-- @param name Name to register under
+-- @param componentClass ComponentClass to register
+function Components.register(name, componentClass)
if (type(name) ~= "string") then
error("bad argument #1 to 'Components.register' (string expected, got "..type(name)..")", 3)
end
- if (not Type.isBaseComponent(baseComponent)) then
- error("bad argument #2 to 'Components.register' (BaseComponent expected, got "..type(baseComponent)..")", 3)
+ if (not Type.isComponentClass(componentClass)) then
+ error("bad argument #2 to 'Components.register' (ComponentClass expected, got "..type(componentClass)..")", 3)
end
if (rawget(Components, name)) then
- error("bad argument #2 to 'Components.register' (BaseComponent with name '"..name.."' is already registerd)", 3)
+ error("bad argument #2 to 'Components.register' (ComponentClass with name '"..name.."' was already registerd)", 3)
end
- Components[name] = baseComponent
+ Components[name] = componentClass
end
return setmetatable(Components, {
__index = function(_, name)
- error("Attempt to index BaseComponent '"..tostring(name).."' that does not exist / was not registered", 2)
+ error("Attempt to index ComponentClass '"..tostring(name).."' that does not exist / was not registered", 2)
end
})
\ No newline at end of file
diff --git a/src/entity.lua b/src/entity.lua
index 38cc60d..c084039 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -1,4 +1,7 @@
--- Entity
+-- Entities are the concrete objects that exist in your project.
+-- An Entity have Components and are processed by Systems.
+-- An Entity is contained by a maximum of 1 World.
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -9,7 +12,8 @@ Entity.__mt = {
__index = Entity,
}
---- Creates and initializes a new Entity.
+--- Creates a new Entity. Optionally adds it to a World.
+-- @param world Optional World to add the entity to
-- @return A new Entity
function Entity.new(world)
if (world ~= nil and not Type.isWorld(world)) then
@@ -30,63 +34,73 @@ function Entity.new(world)
return e
end
-local function give(e, baseComponent, ...)
- local component = baseComponent:__initialize(...)
+local function give(e, componentClass, ...)
+ local component = componentClass:__initialize(...)
- e[baseComponent] = component
- e.__components[baseComponent] = component
+ e[componentClass] = component
+ e.__components[componentClass] = component
e:__dirty()
end
-local function remove(e, baseComponent)
- e[baseComponent] = nil
- e.__components[baseComponent] = nil
+local function remove(e, componentClass)
+ e[componentClass] = nil
+ e.__components[componentClass] = nil
e:__dirty()
end
---- Gives an Entity a component with values.
--- @param component The Component to add
--- @param ... The values passed to the Component
+--- Gives an Entity a Component.
+-- If the Component already exists, it's overridden by this new Component
+-- @param componentClass ComponentClass to add an instance of
+-- @param ... varargs passed to the Component's populate function
-- @return self
-function Entity:give(baseComponent, ...)
- if not Type.isBaseComponent(baseComponent) then
- error("bad argument #1 to 'Entity:give' (BaseComponent expected, got "..type(baseComponent)..")", 2)
+function Entity:give(componentClass, ...)
+ if not Type.isComponentClass(componentClass) then
+ error("bad argument #1 to 'Entity:give' (ComponentClass expected, got "..type(componentClass)..")", 2)
end
- give(self, baseComponent, ...)
+ give(self, componentClass, ...)
return self
end
-function Entity:ensure(baseComponent, ...)
- if not Type.isBaseComponent(baseComponent) then
- error("bad argument #1 to 'Entity:ensure' (BaseComponent expected, got "..type(baseComponent)..")", 2)
+--- Ensures an Entity to have a Component.
+-- If the Component already exists, no action is taken
+-- @param componentClass ComponentClass to add an instance of
+-- @param ... varargs passed to the Component's populate function
+-- @return self
+function Entity:ensure(componentClass, ...)
+ if not Type.isComponentClass(componentClass) then
+ error("bad argument #1 to 'Entity:ensure' (ComponentClass expected, got "..type(componentClass)..")", 2)
end
- if self[baseComponent] then
+ if self[componentClass] then
return self
end
- give(self, baseComponent, ...)
+ give(self, componentClass, ...)
return self
end
---- Removes a component from an Entity.
--- @param component The Component to remove
+--- Removes a Component from an Entity.
+-- @param componentClass ComponentClass of the Component to remove
-- @return self
-function Entity:remove(baseComponent)
- if not Type.isBaseComponent(baseComponent) then
- error("bad argument #1 to 'Entity:remove' (BaseComponent expected, got "..type(baseComponent)..")")
+function Entity:remove(componentClass)
+ if not Type.isComponentClass(componentClass) then
+ error("bad argument #1 to 'Entity:remove' (ComponentClass expected, got "..type(componentClass)..")")
end
- remove(self, baseComponent)
+ remove(self, componentClass)
return self
end
+--- Assembles an Entity.
+-- @see Assemblage:assemble
+-- @param assemblage Assemblage to assemble with
+-- @param ... Varargs to pass to the Assemblage's assemble function.
function Entity:assemble(assemblage, ...)
if not Type.isAssemblage(assemblage) then
error("bad argument #1 to 'Entity:assemble' (Assemblage expected, got "..type(assemblage)..")")
@@ -98,6 +112,7 @@ function Entity:assemble(assemblage, ...)
end
--- Destroys the Entity.
+-- Removes the Entity from it's World if it's in one.
-- @return self
function Entity:destroy()
if self.__world then
@@ -107,42 +122,54 @@ function Entity:destroy()
return self
end
+--- Internal: Tells the World it's in that this Entity is dirty.
+-- @return self
function Entity:__dirty()
if self.__world then
self.__world:__dirtyEntity(self)
end
+
+ return self
+end
+
+--- Returns true if the Entity has a Component.
+-- @param componentClass ComponentClass of the Component to check
+-- @return True if the Entity has the Component, false otherwise
+function Entity:has(componentClass)
+ if not Type.isComponentClass(componentClass) then
+ error("bad argument #1 to 'Entity:has' (ComponentClass expected, got "..type(componentClass)..")")
+ end
+
+ return self[componentClass] ~= nil
end
--- Gets a Component from the Entity.
--- @param component The Component to get
--- @return The Bag from the Component
-function Entity:get(baseComponent)
- if not Type.isBaseComponent(baseComponent) then
- error("bad argument #1 to 'Entity:get' (BaseComponent expected, got "..type(baseComponent)..")")
+-- @param componentClass ComponentClass of the Component to get
+-- @return The Component
+function Entity:get(componentClass)
+ if not Type.isComponentClass(componentClass) then
+ error("bad argument #1 to 'Entity:get' (ComponentClass expected, got "..type(componentClass)..")")
end
- return self[baseComponent]
-end
-
---- Returns true if the Entity has the Component.
--- @param component The Component to check against
--- @return True if the entity has the Bag. False otherwise
-function Entity:has(baseComponent)
- if not Type.isBaseComponent(baseComponent) then
- error("bad argument #1 to 'Entity:has' (BaseComponent expected, got "..type(baseComponent)..")")
- end
-
- return self[baseComponent] ~= nil
+ return self[componentClass]
end
+--- Returns a table of all Components the Entity has.
+-- Warning: Do not modify this table.
+-- Use Entity:give/ensure/remove instead
+-- @return Table of all Components the Entity has
function Entity:getComponents()
return self.__components
end
-function Entity:hasWorld()
+--- Returns true if the Entity is in a World.
+-- @return True if the Entity is in a World, false otherwise
+function Entity:inWorld()
return self.__world and true or false
end
+--- Returns the World the Entity is in.
+-- @return The World the Entity is in.
function Entity:getWorld()
return self.__world
end
@@ -151,4 +178,4 @@ return setmetatable(Entity, {
__call = function(_, ...)
return Entity.new(...)
end,
-})
+})
\ No newline at end of file
diff --git a/src/init.lua b/src/init.lua
index 66916db..b373989 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -47,13 +47,13 @@ Concord.assemblages = require(PATH..".assemblages")
local function load(pathOrFiles, namespace)
if (type(pathOrFiles) ~= "string" and type(pathOrFiles) ~= "table") then
- error("bad argument #1 to 'load' (string/table of strings expected, got "..type(pathOrFiles)..")", 3) -- luacheck: ignore
+ error("bad argument #1 to 'load' (string/table of strings expected, got "..type(pathOrFiles)..")", 3)
end
if (type(pathOrFiles) == "string") then
local info = love.filesystem.getInfo(pathOrFiles) -- luacheck: ignore
if (info == nil or info.type ~= "directory") then
- error("bad argument #1 to 'load' (path '"..pathOrFiles.."' not found)", 3) -- luacheck: ignore
+ error("bad argument #1 to 'load' (path '"..pathOrFiles.."' not found)", 3)
end
local files = love.filesystem.getDirectoryItems(pathOrFiles)
@@ -82,18 +82,34 @@ local function load(pathOrFiles, namespace)
end
end
+--- Loads ComponentClasses and puts them in the Components container.
+-- Accepts a table of paths to files: {"component_1", "component_2", "etc"}
+-- Accepts a path to a directory with ComponentClasses: "components"
+--@see Components
function Concord.loadComponents(pathOrFiles)
load(pathOrFiles, Concord.components)
end
+--- Loads SystemClasses and puts them in the Systems container.
+-- Accepts a table of paths to files: {"system_1", "system_2", "etc"}
+-- Accepts a path to a directory with SystemClasses: "systems"
+--@see Systems
function Concord.loadSystems(pathOrFiles)
load(pathOrFiles, Concord.systems)
end
+--- Loads Worlds and puts them in the Worlds container.
+-- Accepts a table of paths to files: {"world_1", "world_2", "etc"}
+-- Accepts a path to a directory with Worlds: "worlds"
+--@see Worlds
function Concord.loadWorlds(pathOrFiles)
load(pathOrFiles, Concord.worlds)
end
+--- Loads Assemblages and puts them in the Assemblages container.
+-- Accepts a table of paths to files: {"assemblage_1", "assemblage_2", "etc"}
+-- Accepts a path to a directory with Assemblages: "assemblages"
+--@see Assemblages
function Concord.loadAssemblages(pathOrFiles)
load(pathOrFiles, Concord.assemblages)
end
diff --git a/src/list.lua b/src/list.lua
index 94fee52..38ff949 100644
--- a/src/list.lua
+++ b/src/list.lua
@@ -1,4 +1,5 @@
--- List
+-- Data structure that allows for fast removal at the cost of containing order.
local List = {}
List.__mt = {
@@ -6,7 +7,7 @@ List.__mt = {
}
--- Creates a new List.
--- @return A new list
+-- @return A new List
function List.new()
return setmetatable({
size = 0,
@@ -14,9 +15,11 @@ function List.new()
end
--- Adds an object to the List.
--- @param obj The object to add
+-- Object must be of reference type
+-- Object may not be the string 'size'
+-- @param obj Object to add
-- @return self
-function List:__add(obj) -- obj can not be a number and also not the string "size"
+function List:__add(obj)
local size = self.size + 1
self[size] = obj
@@ -27,7 +30,7 @@ function List:__add(obj) -- obj can not be a number and also not the string "siz
end
--- Removes an object from the List.
--- @param obj The object to remove
+-- @param obj Object to remove
-- @return self
function List:__remove(obj)
local index = self[obj]
@@ -66,17 +69,23 @@ function List:__clear()
return self
end
---- Gets if the List has the object.
--- @param obj The object to search for
--- true if the list has the object, false otherwise
+--- Returns true if the List has the object.
+-- @param obj Object to check for
+-- @return True if the List has the object, false otherwise
function List:has(obj)
return self[obj] and true or false
end
+--- Returns the object at an index.
+-- @param i Index to get from
+-- @return Object at the index
function List:get(i)
return self[i]
end
+--- Returns the index of an object in the List.
+-- @param obj Object to get index of
+-- @return index of object in the List.
function List:indexOf(obj)
if (not self[obj]) then
error("bad argument #1 to 'List:indexOf' (Object was not in List)", 2)
diff --git a/src/pool.lua b/src/pool.lua
index 1b7be39..4cde567 100644
--- a/src/pool.lua
+++ b/src/pool.lua
@@ -1,4 +1,6 @@
--- Pool
+-- A Pool is used to iterate over Entities with a specific Components
+-- A Pool contain a any amount of Entities.
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -10,8 +12,8 @@ Pool.__mt = {
}
--- Creates a new Pool
--- @param name Identifier for the Pool.
--- @param filter Table containing the required Components
+-- @param name Name for the Pool.
+-- @param filter Table containing the required BaseComponents
-- @return The new Pool
function Pool.new(name, filter)
local pool = setmetatable(List(), Pool.__mt)
@@ -25,7 +27,7 @@ function Pool.new(name, filter)
end
--- Checks if an Entity is eligible for the Pool.
--- @param e The Entity to check
+-- @param e Entity to check
-- @return True if the entity is eligible, false otherwise
function Pool:__eligible(e)
for _, component in ipairs(self.__filter) do
@@ -37,27 +39,46 @@ function Pool:__eligible(e)
return true
end
+--- Internal: Adds an Entity to the Pool.
+-- @param e Entity to add
+-- @return self
function Pool:__add(e)
List.__add(self, e)
self:onEntityAdded(e)
+
+ return self
end
+--- Internal: Removed an Entity from the Pool.
+-- @param e Entity to remove
+-- @return self
function Pool:__remove(e)
List.__remove(self, e)
self:onEntityRemoved(e)
+
+ return self
end
+--- Gets the name of the Pool
+-- @return Name of the Pool.
function Pool:getName()
return self.__name
end
+--- Gets the filter of the Pool.
+-- Warning: Do not modify this filter.
+-- @return Filter of the Pool.
function Pool:getFilter()
return self.__filter
end
+--- Callback for when an Entity is added to the Pool.
+-- @param e Entity that was added.
function Pool:onEntityAdded(e) -- luacheck: ignore
end
+-- Callback for when an Entity is removed from the Pool.
+-- @param e Entity that was removed.
function Pool:onEntityRemoved(e) -- luacheck: ignore
end
diff --git a/src/system.lua b/src/system.lua
index 4e0b778..5c12d39 100644
--- a/src/system.lua
+++ b/src/system.lua
@@ -1,4 +1,7 @@
--- System
+-- A System iterates over Entities. From these Entities its get Components and modify them.
+-- A System contains 1 or more Pools.
+-- A System is contained by 1 World.
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -11,7 +14,7 @@ local System = {
System.mt = {
__index = System,
- __call = function(baseSystem, world)
+ __call = function(systemClass, world)
local system = setmetatable({
__enabled = true,
@@ -19,8 +22,8 @@ System.mt = {
__world = world,
__isSystem = true,
- __isBaseSystem = false, -- Overwrite value from baseSystem
- }, baseSystem)
+ __isSystemClass = false, -- Overwrite value from systemClass
+ }, systemClass)
-- Optimization: We deep copy the World class into our instance of a world.
-- This grants slightly faster access times at the cost of memory.
@@ -29,8 +32,8 @@ System.mt = {
Utils.shallowCopy(System, system)
end
- for _, filter in pairs(baseSystem.__filter) do
- local pool = system:__buildPool(filter)
+ for _, filter in pairs(systemClass.__filter) do
+ local pool = system.__buildPool(filter)
if not system[pool.__name] then
system[pool.__name] = pool
system.__pools[#system.__pools + 1] = pool
@@ -45,39 +48,40 @@ System.mt = {
end,
}
---- Creates a new System prototype.
+--- Creates a new SystemClass.
-- @param ... Variable amounts of filters
--- @return A new System prototype
+-- @return A new SystemClass
function System.new(...)
- local baseSystem = setmetatable({
- __isBaseSystem = true,
+ local systemClass = setmetatable({
+ __isSystemClass = true,
__filter = {...},
}, System.mt)
- baseSystem.__index = baseSystem
+ systemClass.__index = systemClass
- return baseSystem
+ return systemClass
end
---- Builds a Pool for the System.
+--- Internal: Builds a Pool for the System.
-- @param baseFilter The 'raw' Filter
-- @return A new Pool
-function System:__buildPool(baseFilter) -- luacheck: ignore
+function System.__buildPool(baseFilter)
local name = "pool"
local filter = {}
- for _, v in ipairs(baseFilter) do
- if type(v) == "table" then
- filter[#filter + 1] = v
- elseif type(v) == "string" then
- name = v
+ for _, value in ipairs(baseFilter) do
+ if type(value) == "table" then
+ filter[#filter + 1] = value
+ elseif type(value) == "string" then
+ name = value
end
end
return Pool(name, filter)
end
---- Checks and applies an Entity to the System's pools.
+--- Internal: Evaluates an Entity for all the System's Pools.
-- @param e The Entity to check
+-- @return self
function System:__evaluate(e)
for _, pool in ipairs(self.__pools) do
local has = pool:has(e)
@@ -93,8 +97,9 @@ function System:__evaluate(e)
return self
end
---- Remove an Entity from the System.
+--- Internal: Removes an Entity from the System.
-- @param e The Entity to remove
+-- @return self
function System:__remove(e)
for _, pool in ipairs(self.__pools) do
if pool:has(e) then
@@ -105,6 +110,8 @@ function System:__remove(e)
return self
end
+--- Internal: Clears all Entities from the System.
+-- @return self
function System:clear()
for i = 1, #self.__pools do
self.__pools[i]:__clear()
@@ -113,59 +120,68 @@ function System:clear()
return self
end
+--- Enables the System.
+-- @return self
function System:enable()
self:setEnabled(true)
return self
end
+--- Disables the System.
+-- @return self
function System:disable()
self:setEnabled(false)
return self
end
+--- Toggles if the System is enabled.
+-- @return self
function System:toggleEnable()
self:setEnabled(not self.__enabled)
return self
end
+--- Sets if the System is enabled
+-- @param enable Enable
+-- @return self
function System:setEnabled(enable)
if (not self.__enabled and enable) then
self.__enabled = true
- self:onEnabledCallback()
+ self:onEnabled()
elseif (self.__enabled and not enable) then
self.__enabled = false
- self:onDisabledCallback()
+ self:onDisabled()
end
return self
end
+--- Returns is the System is enabled
+-- @return True if the System is enabled, false otherwise
function System:isEnabled()
return self.__enabled
end
--- Returns the World the System is in.
--- @return The world the system is in
+-- @return The World the System is in
function System:getWorld()
return self.__world
end
---- Default callback for system initialization.
+--- Callback for system initialization.
-- @param world The World the System was added to
function System:init(world) -- luacheck: ignore
end
--- Default callback for when a System's callback is enabled.
--- @param callbackName The name of the callback that was enabled
-function System:onEnabledCallback(callbackName) -- luacheck: ignore
+-- Callback for when a System is enabled.
+function System:onEnabled() -- luacheck: ignore
end
--- Default callback for when a System's callback is disabled.
--- @param callbackName The name of the callback that was disabled
-function System:onDisabledCallback(callbackName) -- luacheck: ignore
+-- Callback for when a System is disabled.
+function System:onDisabled() -- luacheck: ignore
end
return setmetatable(System, {
diff --git a/src/systems.lua b/src/systems.lua
index 4f84472..81e6b2e 100644
--- a/src/systems.lua
+++ b/src/systems.lua
@@ -1,4 +1,5 @@
--- Systems
+--- Systems
+-- Container for registered SystemClasses
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -6,20 +7,23 @@ local Type = require(PATH..".type")
local Systems = {}
-function Systems.register(name, system)
+--- Registers a SystemClass.
+-- @param name Name to register under
+-- @param systemClass SystemClass to register
+function Systems.register(name, systemClass)
if (type(name) ~= "string") then
error("bad argument #1 to 'Systems.register' (string expected, got "..type(name)..")", 3)
end
- if (not Type.isBaseSystem(system)) then
- error("bad argument #2 to 'Systems.register' (baseSystem expected, got "..type(system)..")", 3)
+ if (not Type.isSystemClass(systemClass)) then
+ error("bad argument #2 to 'Systems.register' (systemClass expected, got "..type(systemClass)..")", 3)
end
if (rawget(Systems, name)) then
error("bad argument #2 to 'Systems.register' (System with name '"..name.."' is already registerd)", 3)
end
- Systems[name] = system
+ Systems[name] = systemClass
end
return setmetatable(Systems, {
diff --git a/src/type.lua b/src/type.lua
index a7ba264..9a882a8 100644
--- a/src/type.lua
+++ b/src/type.lua
@@ -1,31 +1,53 @@
--- Type
+--- Type
+-- Helper module to do easy type checking for Concord types
local Type = {}
+--- Returns if object is an Entity.
+-- @param t Object to check
+-- @return True if object is an Entity, false otherwise
function Type.isEntity(t)
return type(t) == "table" and t.__isEntity or false
end
-function Type.isBaseComponent(t)
- return type(t) == "table" and t.__isBaseComponent or false
+--- Returns if object is a ComponentClass.
+-- @param t Object to check
+-- @return True if object is an ComponentClass, false otherwise
+function Type.isComponentClass(t)
+ return type(t) == "table" and t.__isComponentClass or false
end
+--- Returns if object is a Component.
+-- @param t Object to check
+-- @return True if object is an Component, false otherwise
function Type.isComponent(t)
return type(t) == "table" and t.__isComponent or false
end
-function Type.isBaseSystem(t)
- return type(t) == "table" and t.__isBaseSystem or false
+--- Returns if object is a SystemClass.
+-- @param t Object to check
+-- @return True if object is an SystemClass, false otherwise
+function Type.isSystemClass(t)
+ return type(t) == "table" and t.__isSystemClass or false
end
+--- Returns if object is a System.
+-- @param t Object to check
+-- @return True if object is an System, false otherwise
function Type.isSystem(t)
return type(t) == "table" and t.__isSystem or false
end
+--- Returns if object is a World.
+-- @param t Object to check
+-- @return True if object is an World, false otherwise
function Type.isWorld(t)
return type(t) == "table" and t.__isWorld or false
end
+--- Returns if object is an Assemblage.
+-- @param t Object to check
+-- @return True if object is an Assemblage, false otherwise
function Type.isAssemblage(t)
return type(t) == "table" and t.__isAssemblage or false
end
diff --git a/src/utils.lua b/src/utils.lua
index 43adf6c..6372b5b 100644
--- a/src/utils.lua
+++ b/src/utils.lua
@@ -1,5 +1,11 @@
+--- Utils
+-- Helper module for misc operations
+
local Utils = {}
+--- Does a shallow copy of a table and appends it to a target table.
+-- @param orig Table to copy
+-- @param target Table to append to
function Utils.shallowCopy(orig, target)
for key, value in pairs(orig) do
target[key] = value
diff --git a/src/world.lua b/src/world.lua
index f15a14d..a8c7953 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -1,4 +1,8 @@
--- World
+-- A World is a collection of Systems and Entities
+-- A world emits to let Systems iterate
+-- A World contains any amount of Systems
+-- A World contains any amount of Entities
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -42,7 +46,7 @@ function World.new()
end
--- Adds an Entity to the World.
--- @param e The Entity to add
+-- @param e Entity to add
-- @return self
function World:addEntity(e)
if not Type.isEntity(e) then
@@ -59,8 +63,8 @@ function World:addEntity(e)
return self
end
---- Removes an entity from the World.
--- @param e The Entity to mark
+--- Removes an Entity from the World.
+-- @param e Entity to remove
-- @return self
function World:removeEntity(e)
if not Type.isEntity(e) then
@@ -72,13 +76,18 @@ function World:removeEntity(e)
return self
end
+--- Internal: Marks an Entity as dirty.
+-- @see Entity:__dirty
+-- @param e Entity to mark as dirty
function World:__dirtyEntity(e)
if not self.__dirty:has(e) then
self.__dirty:__add(e)
end
end
-
+--- Internal: Flushes all changes to Entities.
+-- This processes all entities. Adding and removing entities, as well as reevaluating dirty entities.
+-- @see System:__evaluate
-- @return self
function World:__flush()
-- Early out
@@ -135,26 +144,37 @@ function World:__flush()
return self
end
-local blacklistedSystemMethods = {
+-- These functions won't be seen as callbacks that will be emitted to.
+local blacklistedSystemFunctions = {
"init",
+ "onEnabled",
+ "onDisabled",
}
-function World:addSystem(baseSystem)
- if (not Type.isBaseSystem(baseSystem)) then
- error("bad argument #1 to 'World:addSystems' (baseSystem expected, got "..type(baseSystem)..")", 2)
+--- Adds a System to the World.
+-- Callbacks are registered automatically
+-- Entities added before are added to the System retroactively
+-- @see World:emit
+-- @param systemClass SystemClass of System to add
+-- @return self
+function World:addSystem(systemClass)
+ if (not Type.isSystemClass(systemClass)) then
+ error("bad argument #1 to 'World:addSystems' (SystemClass expected, got "..type(systemClass)..")", 2)
end
- -- TODO: Check if baseSystem was already added
+ if (self.__systemLookup[systemClass]) then
+ error("bad argument #1 to 'World:addSystems' (SystemClass was already added to World)", 2)
+ end
-- Create instance of system
- local system = baseSystem(self)
+ local system = systemClass(self)
- self.__systemLookup[baseSystem] = system
+ self.__systemLookup[systemClass] = system
self.systems:__add(system)
- for callbackName, callback in pairs(baseSystem) do
+ for callbackName, callback in pairs(systemClass) do
-- Skip callback if its blacklisted
- if (not blacklistedSystemMethods[callbackName]) then
+ if (not blacklistedSystemFunctions[callbackName]) then
-- Make container for all listeners of the callback if it does not exist yet
if (not self.events[callbackName]) then
self.events[callbackName] = {}
@@ -173,43 +193,59 @@ function World:addSystem(baseSystem)
for j = 1, self.entities.size do
system:__evaluate(self.entities[j])
end
+
+ return self
end
+--- Adds multiple Systems to the World.
+-- Callbacks are registered automatically
+-- @see World:addSystem
+-- @see World:emit
+-- @param ... SystemClasses of Systems to add
+-- @return self
function World:addSystems(...)
for i = 1, select("#", ...) do
- local baseSystem = select(i, ...)
+ local systemClass = select(i, ...)
- self:addSystem(baseSystem)
- end
-end
-
-
-function World:hasSystem(baseSystem)
- if not Type.isBaseSystem(baseSystem) then
- error("bad argument #1 to 'World:getSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
+ self:addSystem(systemClass)
end
- return self.__systemLookup[baseSystem] and true or false
+ return self
end
-function World:getSystem(baseSystem)
- if not Type.isBaseSystem(baseSystem) then
- error("bad argument #1 to 'World:getSystem' (baseSystem expected, got "..type(baseSystem)..")", 2)
+--- Returns if the World has a System.
+-- @param systemClass SystemClass of System to check for
+-- @return True if World has System, false otherwise
+function World:hasSystem(systemClass)
+ if not Type.isSystemClass(systemClass) then
+ error("bad argument #1 to 'World:getSystem' (systemClass expected, got "..type(systemClass)..")", 2)
end
- return self.__systemLookup[baseSystem]
+ return self.__systemLookup[systemClass] and true or false
end
---- Emits an Event in the World.
--- @param eventName The Event that should be emitted
--- @param ... Parameters passed to listeners
+--- Gets a System from the World.
+-- @param systemClass SystemClass of System to get
+-- @return System to get
+function World:getSystem(systemClass)
+ if not Type.isSystemClass(systemClass) then
+ error("bad argument #1 to 'World:getSystem' (systemClass expected, got "..type(systemClass)..")", 2)
+ end
+
+ return self.__systemLookup[systemClass]
+end
+
+--- Emits a callback in the World.
+-- Calls all functions with the functionName of added Systems
+-- @param functionName Name of functions to call.
+-- @param ... Parameters passed to System's functions
-- @return self
-function World:emit(callbackName, ...)
- if not callbackName or type(callbackName) ~= "string" then
- error("bad argument #1 to 'World:emit' (String expected, got "..type(callbackName)..")")
+function World:emit(functionName, ...)
+ if not functionName or type(functionName) ~= "string" then
+ error("bad argument #1 to 'World:emit' (String expected, got "..type(functionName)..")")
end
- local listeners = self.events[callbackName]
+ local listeners = self.events[functionName]
if listeners then
for i = 1, #listeners do
@@ -233,15 +269,19 @@ function World:clear()
self:removeEntity(self.entities[i])
end
+ for i = 1, self.systems.size do
+ self.systems[i]:clear()
+ end
+
return self
end
---- Default callback for adding an Entity.
+--- Callback for when an Entity is added to the World.
-- @param e The Entity that was added
function World:onEntityAdded(e) -- luacheck: ignore
end
---- Default callback for removing an Entity.
+--- Callback for when an Entity is removed from the World.
-- @param e The Entity that was removed
function World:onEntityRemoved(e) -- luacheck: ignore
end
diff --git a/src/worlds.lua b/src/worlds.lua
index 2f8f5a8..0ec2574 100644
--- a/src/worlds.lua
+++ b/src/worlds.lua
@@ -1,4 +1,5 @@
--- Worlds
+--- Worlds
+-- Container for registered Worlds
local PATH = (...):gsub('%.[^%.]+$', '')
@@ -6,6 +7,9 @@ local Type = require(PATH..".type")
local Worlds = {}
+--- Registers a World.
+-- @param name Name to register under
+-- @param world World to register
function Worlds.register(name, world)
if (type(name) ~= "string") then
error("bad argument #1 to 'Worlds.register' (string expected, got "..type(name)..")", 3)
From 368766bd27d6c5fefea04ae4a8f64636dfe2af4e Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sat, 4 Jan 2020 01:41:58 +0100
Subject: [PATCH 038/113] Fix broken LDoc tags
---
config.ld | 2 +-
src/assemblage.lua | 1 -
src/components.lua | 2 +-
src/entity.lua | 1 -
src/init.lua | 4 ----
src/world.lua | 2 --
6 files changed, 2 insertions(+), 10 deletions(-)
diff --git a/config.ld b/config.ld
index aada8c2..a04aeaf 100644
--- a/config.ld
+++ b/config.ld
@@ -1,3 +1,3 @@
project = 'Concord'
description = 'A feature-complete ECS library'
-file = {'lib', exclude = {'lib/type.lua', 'lib/run.lua'}}
\ No newline at end of file
+file = {'src', exclude = {}}
\ No newline at end of file
diff --git a/src/assemblage.lua b/src/assemblage.lua
index c2303f2..f989a63 100644
--- a/src/assemblage.lua
+++ b/src/assemblage.lua
@@ -21,7 +21,6 @@ function Assemblage.new(assemble)
end
--- Assembles an Entity.
--- @see Entity:assemble
-- @param e Entity to assemble
-- @param ... Varargs to pass to the assemble function
-- @ return self
diff --git a/src/components.lua b/src/components.lua
index 76780de..ba88c7e 100644
--- a/src/components.lua
+++ b/src/components.lua
@@ -1,4 +1,4 @@
--- Components
+--- Components
-- Container for registered ComponentClasss
local PATH = (...):gsub('%.[^%.]+$', '')
diff --git a/src/entity.lua b/src/entity.lua
index c084039..cce5213 100644
--- a/src/entity.lua
+++ b/src/entity.lua
@@ -98,7 +98,6 @@ function Entity:remove(componentClass)
end
--- Assembles an Entity.
--- @see Assemblage:assemble
-- @param assemblage Assemblage to assemble with
-- @param ... Varargs to pass to the Assemblage's assemble function.
function Entity:assemble(assemblage, ...)
diff --git a/src/init.lua b/src/init.lua
index b373989..1f65695 100644
--- a/src/init.lua
+++ b/src/init.lua
@@ -85,7 +85,6 @@ end
--- Loads ComponentClasses and puts them in the Components container.
-- Accepts a table of paths to files: {"component_1", "component_2", "etc"}
-- Accepts a path to a directory with ComponentClasses: "components"
---@see Components
function Concord.loadComponents(pathOrFiles)
load(pathOrFiles, Concord.components)
end
@@ -93,7 +92,6 @@ end
--- Loads SystemClasses and puts them in the Systems container.
-- Accepts a table of paths to files: {"system_1", "system_2", "etc"}
-- Accepts a path to a directory with SystemClasses: "systems"
---@see Systems
function Concord.loadSystems(pathOrFiles)
load(pathOrFiles, Concord.systems)
end
@@ -101,7 +99,6 @@ end
--- Loads Worlds and puts them in the Worlds container.
-- Accepts a table of paths to files: {"world_1", "world_2", "etc"}
-- Accepts a path to a directory with Worlds: "worlds"
---@see Worlds
function Concord.loadWorlds(pathOrFiles)
load(pathOrFiles, Concord.worlds)
end
@@ -109,7 +106,6 @@ end
--- Loads Assemblages and puts them in the Assemblages container.
-- Accepts a table of paths to files: {"assemblage_1", "assemblage_2", "etc"}
-- Accepts a path to a directory with Assemblages: "assemblages"
---@see Assemblages
function Concord.loadAssemblages(pathOrFiles)
load(pathOrFiles, Concord.assemblages)
end
diff --git a/src/world.lua b/src/world.lua
index a8c7953..fe6107e 100644
--- a/src/world.lua
+++ b/src/world.lua
@@ -77,7 +77,6 @@ function World:removeEntity(e)
end
--- Internal: Marks an Entity as dirty.
--- @see Entity:__dirty
-- @param e Entity to mark as dirty
function World:__dirtyEntity(e)
if not self.__dirty:has(e) then
@@ -87,7 +86,6 @@ end
--- Internal: Flushes all changes to Entities.
-- This processes all entities. Adding and removing entities, as well as reevaluating dirty entities.
--- @see System:__evaluate
-- @return self
function World:__flush()
-- Early out
From 58d9e44bb17ee4291429402ce1991d50e92bcec2 Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sat, 4 Jan 2020 01:52:01 +0100
Subject: [PATCH 039/113] Remove test files
---
conf.lua | 10 ------
main.lua | 56 ---------------------------------
test/components/test_comp_1.lua | 6 ----
3 files changed, 72 deletions(-)
delete mode 100644 conf.lua
delete mode 100644 main.lua
delete mode 100644 test/components/test_comp_1.lua
diff --git a/conf.lua b/conf.lua
deleted file mode 100644
index 4a1ab1c..0000000
--- a/conf.lua
+++ /dev/null
@@ -1,10 +0,0 @@
-function love.conf(t)
- t.identity = "Concord Example"
- t.version = "11.0"
- t.console = true
-
- t.window.vsync = false
- t.window.width = 720
- t.window.height = 720
- end
-
\ No newline at end of file
diff --git a/main.lua b/main.lua
deleted file mode 100644
index ff2ec47..0000000
--- a/main.lua
+++ /dev/null
@@ -1,56 +0,0 @@
---[=[
-local file = "examples.simpleDrawing"
--- local file = "examples.baseLayout.main"
-
-require(file)
-]=]--
-
---test
-
-local Concord = require("src")
-
-local Component = Concord.component
-local System = Concord.system
-local Entity = Concord.entity
-local World = Concord.world
-
-local test_comp_1 = Component(function(e, a)
- e.a = a
-end)
-
-local test_system_1 = System({test_comp_1})
-local test_system_2 = System({test_comp_1})
-local test_system_3 = System({test_comp_1})
-
-function test_system_1:test()
- for _, _ in ipairs(self.pool) do
- end
-end
-
-function test_system_2:test()
- for _, _ in ipairs(self.pool) do
- end
-end
-
-function test_system_3:test()
- for _, _ in ipairs(self.pool) do
- end
-end
-
-local world = World()
-
-world:addSystems(test_system_1, test_system_2, test_system_3)
-
-for _ = 1, 100 do
- local entity = Entity(world)
- entity:give(test_comp_1, 100, 100)
-end
-
-
-local start = love.timer.getTime()
-for _ = 1, 1000000 do
- world:emit("test")
-end
-local stop = love.timer.getTime()
-
-print("Time taken: " .. stop - start)
\ No newline at end of file
diff --git a/test/components/test_comp_1.lua b/test/components/test_comp_1.lua
deleted file mode 100644
index ef9b98a..0000000
--- a/test/components/test_comp_1.lua
+++ /dev/null
@@ -1,6 +0,0 @@
-local Component = require("src").component
-
-return Component(function(e, x, y)
- e.x = x
- e.y = y
-end)
\ No newline at end of file
From 0e1023d2cebb9b9ebeaa56039237fb2c815310ba Mon Sep 17 00:00:00 2001
From: Tjakka5
Date: Sat, 4 Jan 2020 01:54:21 +0100
Subject: [PATCH 040/113] Publish regenerated LDoc pages
---
docs/index.html | 74 +++++-
docs/modules/assemblage.html | 147 +++++++++++
docs/modules/assemblages.html | 116 +++++++++
docs/modules/component.html | 51 +++-
docs/modules/components.html | 116 +++++++++
docs/modules/entity.html | 247 ++++++++++++++----
docs/modules/init.html | 110 ++++++--
docs/modules/instance.html | 463 ----------------------------------
docs/modules/list.html | 153 +++++++----
docs/modules/pool.html | 156 +++++++++++-
docs/modules/system.html | 362 +++++++++++++-------------
docs/modules/systems.html | 116 +++++++++
docs/modules/type.html | 292 +++++++++++++++++++++
docs/modules/utils.html | 116 +++++++++
docs/modules/world.html | 453 +++++++++++++++++++++++++++++++++
docs/modules/worlds.html | 116 +++++++++
16 files changed, 2283 insertions(+), 805 deletions(-)
create mode 100644 docs/modules/assemblage.html
create mode 100644 docs/modules/assemblages.html
create mode 100644 docs/modules/components.html
delete mode 100644 docs/modules/instance.html
create mode 100644 docs/modules/systems.html
create mode 100644 docs/modules/type.html
create mode 100644 docs/modules/utils.html
create mode 100644 docs/modules/world.html
create mode 100644 docs/modules/worlds.html
diff --git a/docs/index.html b/docs/index.html
index 746fc48..c46ade3 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -31,13 +31,20 @@
Modules
@@ -49,33 +56,78 @@
Modules
+
+ assemblage |
+ Assemblage
+ An Assemblage is a function that 'makes' an entity something. |
+
+
+ assemblages |
+ Assemblages
+ Container for registered Assemblages |
+
component |
- Component |
+ Component
+ A Component is a pure data container. |
+
+
+ components |
+ Components
+ Container for registered ComponentClasss |
entity |
- Entity |
+ Entity
+ Entities are the concrete objects that exist in your project. |
init |
init |
-
- instance |
- Instance |
-
list |
- List |
+ List
+ Data structure that allows for fast removal at the cost of containing order. |
pool |
- Pool |
+ Pool
+ A Pool is used to iterate over Entities with a specific Components
+ A Pool contain a any amount of Entities. |
system |
- System |
+ System
+ A System iterates over Entities. |
+
+
+ systems |
+ Systems
+ Container for registered SystemClasses |
+
+
+ type |
+ Type
+ Helper module to do easy type checking for Concord types |
+
+
+ utils |
+ Utils
+ Helper module for misc operations |
+
+
+ world |
+ World
+ A World is a collection of Systems and Entities
+ A world emits to let Systems iterate
+ A World contains any amount of Systems
+ A World contains any amount of Entities |
+
+
+ worlds |
+ Worlds
+ Container for registered Worlds |
@@ -83,7 +135,7 @@
generated by LDoc 1.4.6
-
Last updated 2018-09-25 18:42:43
+
Last updated 2020-01-04 00:43:06
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Concord
+
+
+
+
Contents
+
+
+
+
Modules
+
+
+
+
+
+
+
Module assemblage
+
Assemblage
+ An Assemblage is a function that 'makes' an entity something.
+
+ It does this by :give'ing or :ensure'ing Components, or by :assemble'ing the Entity.
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+ Assemblage.new (assemble)
+
+ -
+ Creates a new Assemblage.
+
+
+
Parameters:
+
+ - assemble
+ Function that assembles an Entity
+
+
+
+ Returns:
+
+
+ A new Assemblage
+
+
+
+
+
+
+ -
+
+ Assemblage:assemble (e, ...)
+
+ -
+ Assembles an Entity.
+
+
+
Parameters:
+
+ - e
+ Entity to assemble
+
+ - ...
+ Varargs to pass to the assemble function
+ @ return self
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
generated by LDoc 1.4.6
+
Last updated 2020-01-04 00:43:06
+
+
+
diff --git a/docs/modules/assemblage.html b/docs/modules/assemblage.html
new file mode 100644
index 0000000..bfb4d07
--- /dev/null
+++ b/docs/modules/assemblage.html
@@ -0,0 +1,147 @@
+
+
+
+