diff --git a/README.md b/README.md
index 8b73280..86040f0 100644
--- a/README.md
+++ b/README.md
@@ -205,6 +205,13 @@ local world = ECS.CreateWorld(
- Get entity compoment data
- _`world.`_**`Set`** _(`entity`, `component`, `...args`)_
- Defines the value of a component for an entity
+- _`world.`_**`Dirty`** _(`entity`)_
+ - It allows informing that this component has undergone some change outside the common flow of systems
+ ```lua
+ local data = world.Get(entity, Component)
+ data.Value = 2
+ world.Dirty(entity)
+ ```
- _`world.`_**`Call`** _(`entity`, `component`, `method`, `...args`)_
- Invokes a utility method from a component's API
- _`world.`_**`Remove`** _(`entity`, `component`)_
@@ -330,7 +337,7 @@ Represents the logic that transforms component data of an entity from its curren
In **Roblox-ECS**, a system has a strong connection with component types. You must define which components this system works on in the `System` registry.
-If the `update` method is implemented, it will be invoked respecting the order parameter within the configured step. Whenever an entity with the characteristics expected by this system is added on world, the system is informed via the `onEnter` method.
+If the `Update` method is implemented, it will be invoked respecting the order parameter within the configured step. Whenever an entity with the characteristics expected by this system is added on world, the system is informed via the `OnEnter` method. When these characteristics are lost, the `OnExit` method is invoked
```lua
local ECS = require(game.ReplicatedStorage:WaitForChild("ECS"))
@@ -369,6 +376,12 @@ return ECS.RegisterSystem({
return false
end,
+ -- [Optional] Invoked when an entity loses these characteristics
+ OnExit = function(time, world, entity, index, weapons)
+ print('Entity loses these characteristics ', entity)
+ return false
+ end,
+
-- [Optional] Invoked when an entity with these characteristics is removed
OnRemove = function(time, world, entity, index, weapons)
-- on new entity
diff --git a/src/shared/ECS.lua b/src/shared/ECS.lua
index def16e0..ec4ee81 100644
--- a/src/shared/ECS.lua
+++ b/src/shared/ECS.lua
@@ -1,5 +1,5 @@
--[[
- Roblox-ECS v1.2.1 [2020-12-10 02:40]
+ Roblox-ECS v1.2.2 [2021-02-22 15:55]
Roblox-ECS is a tiny and easy to use ECS (Entity Component System) engine for
game development on the Roblox platform
@@ -719,6 +719,17 @@ function Archetype:With(component)
return Archetype.Get(newCoomponents)
end
+--[[
+ Gets the reference to an archetype that has the current components + the informed components
+]]
+function Archetype:WithAll(components)
+ local arch = self
+ for _, component in ipairs(components) do
+ arch = arch:With(component)
+ end
+ return arch
+end
+
--[[
Gets the reference to an archetype that has the current components - the informed component
]]
@@ -742,6 +753,17 @@ function Archetype:Without(component)
return Archetype.Get(newCoomponents)
end
+--[[
+ Gets the reference to an archetype that has the current components - the informed components
+]]
+function Archetype:WithoutAll(components)
+ local arch = self
+ for _, component in ipairs(components) do
+ arch = arch:Without(component)
+ end
+ return arch
+end
+
--[[
Checks whether this archetype has the informed component
]]
@@ -1221,6 +1243,21 @@ function EntityManager:SetValue(entityID, component, value)
chunk:SetValue(entity.ChunkIndex, component, value)
end
+--[[
+ It allows informing that this component has undergone some change outside the common flow of systems
+]]
+function EntityManager:SetDirty(entityID)
+ local entity = self.Entities[entityID]
+ if entity == nil then
+ return
+ end
+
+ local chunk = self.Archetypes[entity.Archetype].Chunks[entity.Chunk]
+
+ self.World.Version = self.World.Version + 1
+ chunk.Version = self.World.Version
+end
+
--[[
Gets all values of the components of an entity
@@ -1344,14 +1381,9 @@ local SYSTEM_STEPS = {
AfterUpdate(time: number, interpolation:number, world, system): void
- OnEnter(entity: Entity): void;
- Invoked when:
- a) An entity with the characteristics (components) expected by this system is
- added in the world;
- b) This system is added in the world and this world has one or more entities with
- the characteristics expected by this system;
- c) An existing entity in the same world receives a new component at runtime
- and all of its new components match the standard expected by this system.
+ OnEnter(time, world, entity, index, [component_N_items...]) -> boolean
+
+ OnExit(time, world, entity, index, [component_N_items...]) -> boolean
OnRemove(time, world, enity, index, [component_N_items...])
}
@@ -1403,6 +1435,10 @@ local function RegisterSystem(config)
error('Task-type systems do not accept the "OnEnter" parameter')
end
+ if config.OnExit ~= nil then
+ error('Task-type systems do not accept the "OnExit" parameter')
+ end
+
if config.Execute == nil then
error('The task "Execute" method is required for registration')
end
@@ -1428,6 +1464,7 @@ local function RegisterSystem(config)
AfterUpdate = config.AfterUpdate,
OnCreate = config.OnCreate,
OnEnter = config.OnEnter,
+ OnExit = config.OnExit,
OnRemove = config.OnRemove,
BeforeExecute = config.BeforeExecute,
Execute = config.Execute,
@@ -1766,7 +1803,7 @@ local function NewExecutionPlan(world, systems)
}
-- systems that process the onEnter event
- local onEnterSystems = {}
+ local onEnterOrExitSystems = {}
-- systems that process the onRemove event
local onRemoveSystems = {}
@@ -1781,8 +1818,8 @@ local function NewExecutionPlan(world, systems)
table.insert(updateSteps[system.Step][system.Order], system)
end
- if system.OnEnter ~= nil then
- table.insert(onEnterSystems, system)
+ if system.OnEnter ~= nil or system.OnExit ~= nil then
+ table.insert(onEnterOrExitSystems, system)
end
if system.OnRemove ~= nil then
@@ -1869,49 +1906,58 @@ local function NewExecutionPlan(world, systems)
end
end
- local onEnter = function(onEnterEntities, entityManager, time)
+ local onEnterOrExit = function(onEnterOrExitEntities, entityManager, time)
+
-- increment Global System Version (GSV), before system update
world.Version = world.Version + 1
- for entityID, newComponents in pairs(onEnterEntities) do
-
- -- temporary filter
- local filterHasAny = Filter({ RequireAny = newComponents })
+ for entityID, newComponents in pairs(onEnterOrExitEntities) do
-- get the chunk and index of this entity
local chunk, index = entityManager:GetEntityChunk(entityID)
if chunk ~= nil then
local buffers = chunk.Buffers
- for j, system in pairs(onEnterSystems) do
+ -- o arquétipo anterior da entidade
+ local newArchetype = chunk.Archetype
+ local oldArchetype = newArchetype:WithAll(newComponents.Lost):WithoutAll(newComponents.Received)
- -- system does not apply to the archetype of that entity
- if system.Filter.Match(chunk.Archetype.Components) then
+ for j, system in pairs(onEnterOrExitSystems) do
+
+ local matchNew = system.Filter.Match(newArchetype.Components)
+ local matchOld = system.Filter.Match(oldArchetype.Components)
+
+ local fn = nil
+ if system.OnEnter ~= nil and matchNew and not matchOld then
+ -- OnEnter
+ fn = system.OnEnter
+ elseif system.OnExit ~= nil and matchOld and not matchNew then
+ -- OnExit
+ fn = system.OnExit
+ end
+ if fn ~= nil then
-- what components the system expects
local whatComponents = system.RequireAllOriginal
if whatComponents == nil then
whatComponents = system.RequireAnyOriginal
end
- -- components received are not in the list of components expected by the system
- if filterHasAny.Match(whatComponents) then
- local componentsData = table.create(table.getn(whatComponents))
+ local componentsData = table.create(table.getn(whatComponents))
- for l, compID in ipairs(whatComponents) do
- if buffers[compID] ~= nil then
- componentsData[l] = buffers[compID]
- else
- componentsData[l] = {}
- end
+ for l, compID in ipairs(whatComponents) do
+ if buffers[compID] ~= nil then
+ componentsData[l] = buffers[compID]
+ else
+ componentsData[l] = {}
end
+ end
- -- onEnter: function(world, entity, index, [component_N_items...]) -> boolean
- if system.OnEnter(time, world, entityID, index, table.unpack(componentsData)) then
- -- If any system execution informs you that it has changed data in
- -- this chunk, it then performs the versioning of the chunk
- chunk.Version = world.Version
- end
+ -- onEnter/onExit: function(time, world, entity, index, [component_N_items...]) -> boolean
+ if fn(time, world, entityID, index, table.unpack(componentsData)) then
+ -- If any system execution informs you that it has changed data in
+ -- this chunk, it then performs the versioning of the chunk
+ chunk.Version = world.Version
end
end
end
@@ -1920,6 +1966,7 @@ local function NewExecutionPlan(world, systems)
end
local onRemove = function(removedEntities, entityManager, time)
+
-- increment Global System Version (GSV), before system update
world.Version = world.Version + 1
@@ -1963,7 +2010,7 @@ local function NewExecutionPlan(world, systems)
end
end
- return onUpdate, onEnter, onRemove
+ return onUpdate, onEnterOrExit, onRemove
end
--[[
@@ -1986,7 +2033,7 @@ local function CreateNewWorld(systems, config)
local scheduler
-- System execution plan
- local updateExecPlan, enterExecPlan, removeExecPlan
+ local updateExecPlan, enterOrExitExecPlan, removeExecPlan
local processDeltaTime
@@ -2092,6 +2139,21 @@ local function CreateNewWorld(systems, config)
end
end
+ --[[
+ It allows informing that this component has undergone some change outside the common flow of systems
+ ]]
+ local function SetDirty(entity)
+ if entitiesNew[entity] == true then
+ entityManagerNew:SetDirty(entity)
+ else
+ if entitiesUpdated[entity] ~= nil then
+ entityManagerUpdated:SetDirty(entity)
+ end
+
+ entityManager:SetDirty(entity)
+ end
+ end
+
--[[
Defines the value of a component for an entity
]]
@@ -2191,6 +2253,8 @@ local function CreateNewWorld(systems, config)
Removing a entity or Removing a component from an entity at runtime
]]
local function RemoveEntityOrComponent(entity, component)
+
+
local archetype = entitiesArchetypes[entity]
if archetype == nil then
return
@@ -2384,6 +2448,7 @@ local function CreateNewWorld(systems, config)
Update = SYSTEM[systemID].Update,
AfterUpdate = SYSTEM[systemID].AfterUpdate,
OnEnter = SYSTEM[systemID].OnEnter,
+ OnExit = SYSTEM[systemID].OnExit,
OnRemove = SYSTEM[systemID].OnRemove,
Step = SYSTEM[systemID].Step,
Order = SYSTEM[systemID].Order,
@@ -2454,7 +2519,7 @@ local function CreateNewWorld(systems, config)
entitiesRemoved = nil
worldSystems = nil
updateExecPlan = nil
- enterExecPlan = nil
+ enterOrExitExecPlan = nil
removeExecPlan = nil
entitiesArchetypes = nil
scheduler = nil
@@ -2462,6 +2527,7 @@ local function CreateNewWorld(systems, config)
-- It also removes all methods in the world, avoids external calls
world.Create = nil
world.Set = nil
+ world.Dirty = nil
world.Get = nil
world.Remove = nil
world.Has = nil
@@ -2485,8 +2551,8 @@ local function CreateNewWorld(systems, config)
dirtyEnvironment = false
- local haveOnEnter = false
- local onEnterEntities = {}
+ local haveOnEnterOrOnExit = false
+ local onEnterOrExitEntities = {}
-- 1: remove entities
-- Event onRemove
@@ -2510,9 +2576,27 @@ local function CreateNewWorld(systems, config)
entityManager:SetData(entityID, entityManagerUpdated:GetData(entityID))
entityManagerUpdated:Remove(entityID)
- if table.getn(updated.received) > 0 then
- onEnterEntities[entityID] = updated.received
- haveOnEnter = true
+ if table.getn(updated.received) > 0 or table.getn(updated.lost) > 0 then
+ if onEnterOrExitEntities[entityID] == nil then
+ onEnterOrExitEntities[entityID] = {
+ Received = {},
+ Lost = {}
+ }
+ end
+
+ if table.getn(updated.received) > 0 then
+ for _, component in ipairs(updated.received) do
+ table.insert(onEnterOrExitEntities[entityID].Received, component)
+ end
+ end
+
+ if table.getn(updated.lost) > 0 then
+ for _, component in ipairs(updated.lost) do
+ table.insert(onEnterOrExitEntities[entityID].Lost, component)
+ end
+ end
+
+ haveOnEnterOrOnExit = true
end
end
entitiesUpdated = {}
@@ -2522,14 +2606,25 @@ local function CreateNewWorld(systems, config)
entityManager:Set(entityID, entitiesArchetypes[entityID])
entityManager:SetData(entityID, entityManagerNew:GetData(entityID))
entityManagerNew:Remove(entityID)
- onEnterEntities[entityID] = entitiesArchetypes[entityID].Components
- haveOnEnter = true
+
+ if onEnterOrExitEntities[entityID] == nil then
+ onEnterOrExitEntities[entityID] = {
+ Received = {},
+ Lost = {}
+ }
+ end
+
+ for _, component in ipairs(entitiesArchetypes[entityID].Components) do
+ table.insert(onEnterOrExitEntities[entityID].Received, component)
+ end
+
+ haveOnEnterOrOnExit = true
end
entitiesNew = {}
- if haveOnEnter then
- enterExecPlan(onEnterEntities, entityManager, time)
- onEnterEntities = nil
+ if haveOnEnterOrOnExit then
+ enterOrExitExecPlan(onEnterOrExitEntities, entityManager, time)
+ onEnterOrExitEntities = nil
end
end
@@ -2578,7 +2673,7 @@ local function CreateNewWorld(systems, config)
-- need to update execution plan?
if lastKnownArchetypeInstant < LAST_ARCHETYPE_INSTANT then
- updateExecPlan, enterExecPlan, removeExecPlan = NewExecutionPlan(world, worldSystems)
+ updateExecPlan, enterOrExitExecPlan, removeExecPlan = NewExecutionPlan(world, worldSystems)
lastKnownArchetypeInstant = LAST_ARCHETYPE_INSTANT
end
@@ -2658,7 +2753,7 @@ local function CreateNewWorld(systems, config)
updated = true
-- need to update execution plan?
if lastKnownArchetypeInstant < LAST_ARCHETYPE_INSTANT then
- updateExecPlan, enterExecPlan = NewExecutionPlan(world, worldSystems)
+ updateExecPlan, enterOrExitExecPlan, removeExecPlan = NewExecutionPlan(world, worldSystems)
lastKnownArchetypeInstant = LAST_ARCHETYPE_INSTANT
end
@@ -2697,6 +2792,7 @@ local function CreateNewWorld(systems, config)
Create = CreateEntity,
Get = GetComponentValue,
Set = SetComponentValue,
+ Dirty = SetDirty,
Call = CallComponentAPI,
Remove = RemoveEntityOrComponent,
Has = CheckComponentHas,
diff --git a/src/shared/ECS.min.lua b/src/shared/ECS.min.lua
index a683d3f..ecd496a 100644
--- a/src/shared/ECS.min.lua
+++ b/src/shared/ECS.min.lua
@@ -1,5 +1,5 @@
--[[
- Roblox-ECS v1.2.1 [2020-12-10 02:40]
+ Roblox-ECS v1.2.2 [2021-02-22 15:55]
Roblox-ECS is a tiny and easy to use ECS (Entity Component System) engine for
game development on the Roblox platform
@@ -33,4 +33,4 @@
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]]
-local a=game:GetService('RunService')local b=0.000000001;local function c(d)if d==nil then d={}end;local e={}local f={}for g,h in pairs(d)do if h~=nil and e[h]==nil then table.insert(f,h)e[h]=true end end;table.sort(f)return f end;local function i(j)j=c(j)return'_'..table.concat(j,'_'),j end;local k={}local function l(m)local n={}if m==nil then m={}end;if m.RequireAll==nil and m.RequireAny==nil then error('It is necessary to define the components using the "RequireAll" or "RequireAny" parameters')end;if m.RequireAll~=nil and m.RequireAny~=nil then error('It is not allowed to use the "RequireAll" and "RequireAny" settings simultaneously')end;if m.RequireAll~=nil then m.RequireAllOriginal=m.RequireAll;m.RequireAll=c(m.RequireAll)if table.getn(m.RequireAll)==0 then error('You must enter at least one component id in the "RequireAll" field')end elseif m.RequireAny~=nil then m.RequireAnyOriginal=m.RequireAny;m.RequireAny=c(m.RequireAny)if table.getn(m.RequireAny)==0 then error('You must enter at least one component id in the "RequireAny" field')end end;if m.RejectAll~=nil and m.RejectAny~=nil then error('It is not allowed to use the "RejectAll" and "RejectAny" settings simultaneously')end;if m.RejectAll~=nil then m.RejectAll=c(m.RejectAll)if table.getn(m.RejectAll)==0 then error('You must enter at least one component id in the "RejectAll" field')end elseif m.RejectAny~=nil then m.RejectAny=c(m.RejectAny)if table.getn(m.RejectAny)==0 then error('You must enter at least one component id in the "RejectAny" field')end end;local o,p=i(m.RequireAll)local q,r=i(m.RequireAny)local s,t=i(m.RejectAll)local u,v=i(m.RejectAny)local w=m.RequireAllOriginal;if w==nil then w=m.RequireAnyOriginal end;return{Components=w,Match=function(w)local x=n[w]if x==false then return false elseif x==true then return true else local y=k[w]if y==nil then y={MatchAny={},MatchAll={},RejectAny={},RejectAll={}}k[w]=y end;if u~='_'then if y.RejectAny[u]or y.RejectAll[u]then n[w]=false;return false end;for g,h in pairs(v)do if table.find(w,h)then n[w]=false;y.MatchAny[u]=true;y.RejectAny[u]=true;return false end end end;if s~='_'then if y.RejectAll[s]then n[w]=false;return false end;local z=true;for g,h in pairs(t)do if not table.find(w,h)then z=false;break end end;if z then n[w]=false;y.MatchAll[s]=true;y.RejectAll[s]=true;return false end end;if q~='_'then if y.MatchAny[q]or y.MatchAll[q]then n[w]=true;return true end;for g,h in pairs(r)do if table.find(w,h)then y.MatchAny[q]=true;n[w]=true;return true end end end;if o~='_'then if y.MatchAll[o]then n[w]=true;return true end;local z=true;for g,h in pairs(p)do if not table.find(w,h)then z=false;break end end;if z then n[w]=true;y.MatchAll[o]=true;y.RejectAll[o]=true;return true end end;n[w]=false;return false end end}end;local A=0;local B=1;local C={key=0,color=A}local function D(E,F)local G=F.right;F.right=G.left;if G.left~=C then G.left.parent=F end;G.parent=F.parent;if F.parent==C then E.root=G elseif F==F.parent.left then F.parent.left=G else F.parent.right=G end;G.left=F;F.parent=G end;local function H(E,F)local I=F.left;F.left=I.right;if I.right~=C then I.right.parent=F end;I.parent=F.parent;if F.parent==C then E.root=I elseif F==F.parent.right then F.parent.right=I else F.parent.left=I end;I.right=F;F.parent=I end;local function J(E,F,K)if F.parent==C then E.root=K elseif F==F.parent.left then F.parent.left=K else F.parent.right=K end;K.parent=F.parent end;local function L(F)while F.left~=C do F=F.left end;return F end;local function M(F)if F==C then return nil end;if F.parent==F then return nil end;if F.right~=C then return L(F.right)end;local N;while true do N=F.parent;if N==C then return nil end;if F==N.right then F=N else break end end;return N end;local function O(E,F)local N=C;local P=E.root;while P~=C do N=P;if F.key
ax then aJ.LastChunk=aJ.LastChunk+1;aJ.NextChunkIndex=1;aJ.Chunks[aJ.LastChunk]=aw.New(self.World,az)self.Version=self.Version+1 end end;function aF:Remove(aG)local aE=self.Entities[aG]if aE==nil then return end;local aJ=self.Archetypes[aE.Archetype]local aK=aJ.Chunks[aE.Chunk]aK:Clear(aE.ChunkIndex)aK.Count=aK.Count-1;self.Entities[aG]=nil;self.CountValue=self.CountValue-1;aJ.Count=aJ.Count-1;if aJ.NextChunkIndex==1 then aJ.Chunks[aJ.LastChunk]=nil;aJ.LastChunk=aJ.LastChunk-1;aJ.NextChunkIndex=ax+1;self.Version=self.Version+1 end;if aJ.Count>0 then if aJ.NextChunkIndex>1 then if not(aJ.LastChunk==aE.Chunk and aJ.NextChunkIndex-1==aE.ChunkIndex)then local aL=aJ.Chunks[aJ.LastChunk]:Get(aJ.NextChunkIndex-1)aJ.Chunks[aE.Chunk]:Set(aE.ChunkIndex,aL)local aM=aL[av]local aN=self.Entities[aM]aN.Chunk=aE.Chunk;aN.ChunkIndex=aE.ChunkIndex end;aJ.NextChunkIndex=aJ.NextChunkIndex-1;aJ.Chunks[aJ.LastChunk]:Clear(aJ.NextChunkIndex)end else aJ.NextChunkIndex=aJ.NextChunkIndex-1 end end;function aF:Count()return self.CountValue end;function aF:Clear(aG)local aE=self.Entities[aG]if aE==nil then return end;local aK=self.Archetypes[aE.Archetype].Chunks[aE.Chunk]aK:Clear(aE.ChunkIndex)end;function aF:GetValue(aG,aa)local aE=self.Entities[aG]if aE==nil then return nil end;return self.Archetypes[aE.Archetype].Chunks[aE.Chunk]:GetValue(aE.ChunkIndex,aa)end;function aF:SetValue(aG,aa,an)local aE=self.Entities[aG]if aE==nil then return end;local aK=self.Archetypes[aE.Archetype].Chunks[aE.Chunk]aK:SetValue(aE.ChunkIndex,aa,an)end;function aF:GetData(aG)local aE=self.Entities[aG]if aE==nil then return nil end;local aK=self.Archetypes[aE.Archetype].Chunks[aE.Chunk]return aK:Get(aE.ChunkIndex)end;function aF:SetData(aG,aa,a5)local aE=self.Entities[aG]if aE==nil then return end;local aK=self.Archetypes[aE.Archetype].Chunks[aE.Chunk]aK:Set(aE.ChunkIndex,aa,a5)end;function aF:GetEntityChunk(aG)local aE=self.Entities[aG]if aE==nil then return end;return self.Archetypes[aE.Archetype].Chunks[aE.Chunk],aE.ChunkIndex end;function aF:FilterChunks(aO)local aP={}for aH,aJ in pairs(self.Archetypes)do if aO(a6[aH].Components)then for af,aK in pairs(aJ.Chunks)do table.insert(aP,aK)end end end;return aP end;local aQ={}local aR={}local aS={'task','render','process','processIn','processOut','transform'}local function aT(m)if m==nil then error('System configuration is required for its creation')end;if m.Name==nil then error('The system "Name" is required for registration')end;if aR[m.Name]~=nil then error('Another System already registered with that name')end;if m.Step==nil then m.Step='transform'end;if not table.find(aS,m.Step)then error('The "step" parameter must one of ',table.concat(aS,', '))end;if m.Step=='task'then if m.Order~=nil then error('Task-type systems do not accept the "Order" parameter')end;if m.ShouldUpdate~=nil then error('Task-type systems do not accept the "ShouldUpdate" parameter')end;if m.BeforeUpdate~=nil then error('Task-type systems do not accept the "BeforeUpdate" parameter')end;if m.Update~=nil then error('Task-type systems do not accept the "Update" parameter')end;if m.AfterUpdate~=nil then error('Task-type systems do not accept the "AfterUpdate" parameter')end;if m.OnEnter~=nil then error('Task-type systems do not accept the "OnEnter" parameter')end;if m.Execute==nil then error('The task "Execute" method is required for registration')end end;if m.Order==nil or m.Order<0 then m.Order=50 end;table.insert(aQ,{Filter=l(m),Name=m.Name,RequireAll=m.RequireAll,RequireAny=m.RequireAny,RequireAllOriginal=m.RequireAllOriginal,RequireAnyOriginal=m.RequireAnyOriginal,RejectAll=m.RejectAll,RejectAny=m.RejectAny,ShouldUpdate=m.ShouldUpdate,BeforeUpdate=m.BeforeUpdate,Update=m.Update,AfterUpdate=m.AfterUpdate,OnCreate=m.OnCreate,OnEnter=m.OnEnter,OnRemove=m.OnRemove,BeforeExecute=m.BeforeExecute,Execute=m.Execute,Step=m.Step,Order=m.Order})local au=table.getn(aQ)aR[m.Name]=au;return au end;local aU={}aU.__index=aU;local aV=0.008;local aW=0.002;function aU.New(ay,aX)return setmetatable({World=ay,EntityManager=aX,min_vruntime=0,rbtree=a3(),LastEntityManagerVersion=-1,Systems={}},aU)end;function aU:AddSystem(aY,m)if self.Systems[aY]~=nil then return end;if m==nil then m={}end;local aZ={Id=aY,name=aQ[aY].Name,RequireAll=aQ[aY].RequireAll,RequireAny=aQ[aY].RequireAny,RequireAllOriginal=aQ[aY].RequireAllOriginal,RequireAnyOriginal=aQ[aY].RequireAnyOriginal,RejectAll=aQ[aY].RejectAll,RejectAny=aQ[aY].RejectAny,Filter=aQ[aY].Filter,BeforeExecute=aQ[aY].BeforeExecute,Execute=aQ[aY].Execute,Config=m}self.Systems[aY]=aZ;self.LastEntityManagerVersion=0 end;function aU:Run(a_)if self.EntityManager.Version~=self.LastEntityManagerVersion then self:Update()self.LastEntityManagerVersion=self.EntityManager.Version end;local E=self.rbtree;local ay=self.World;local b0=math.max(aV,0.01667-(os.clock()-a_.frameReal)-aW)local b1={}local b2=os.clock()local b3,aK,aZ,b4,b5;local b6=X(E)while b6~=nil do Q(E,b6)aK=b6.data[1]aZ=b6.data[2]b4=b6.data[3]b5=b6.data[4]b3=os.clock()if b5==0 then b5=b3 end;local b7=aZ.RequireAllOriginal;if b7==nil then b7=aZ.RequireAnyOriginal end;local b8=table.getn(b7)local b9=aZ.Execute;ay.Version=ay.Version+1;if aZ.BeforeExecute~=nil then aZ.BeforeExecute(a_,ay,aZ)end;local ba=aK.Version==0 or aK.Version>b4;local aA=aK.buffers;local bb=aA[av]local bc=table.create(b8)local bd=false;for be,bf in ipairs(b7)do if aA[bf]~=nil then bc[be]=aA[bf]else bc[be]={}end end;local bg={process=a_.process,frame=a_.frame,frameReal=a_.frameReal,delta=a_.delta,deltaExec=b3-b5}for aC=1,aK.Count do if b9(bg,ay,ba,bb[aC],aC,table.unpack(bc))then bd=true end end;if bd then aK.Version=ay.Version end;b6.data[3]=ay.Version;b6.data[4]=b3;b6.key=b6.key+os.clock()-b3;O(E,b6)if os.clock()-b2>b0 then break end;b6=M(b6)end;local bh=X(E)if bh~=nil then self.min_vruntime=math.max(bh.key-b,0)else self.min_vruntime=0 end end;function aU:Update()local E=self.rbtree;local bi=self.Systems;local aX=self.EntityManager;local bj=self.min_vruntime;local bk=self.World.Version;local bl={}local bm={}local aK,aZ;a0(E,function(b6)aK=b6.data[1]aZ=b6.data[2]if bl[aK]==nil then bl[aK]={}end;if bl[aK][aZ]==nil then bl[aK][aZ]={}end;table.insert(bl[aK][aZ],b6)bm[aK]=true end)for af,bn in pairs(bi)do local aP=aX:FilterChunks(bn.Filter.Match)for bo,bp in pairs(aP)do bm[bp]=nil;if bl[bp]==nil then O(E,a4(bj,{bp,bn,bk,0}))elseif bl[bp][bn]==nil then O(E,a4(bj,{bp,bn,bk,0}))end end end;for bq,g in pairs(bm)do for br,b1 in pairs(bl[bq])do for g,b6 in ipairs(b1)do Q(E,b6)end end end end;local function bs(ay,bi)local bt={processIn={},process={},processOut={},transform={},render={}}local bu={processIn={},process={},processOut={},transform={},render={}}local bv={}local bw={}for aD,aZ in pairs(bi)do if aZ.Update~=nil then if bt[aZ.Step][aZ.Order]==nil then bt[aZ.Step][aZ.Order]={}table.insert(bu[aZ.Step],aZ.Order)end;table.insert(bt[aZ.Step][aZ.Order],aZ)end;if aZ.OnEnter~=nil then table.insert(bv,aZ)end;if aZ.OnRemove~=nil then table.insert(bw,aZ)end end;for g,bx in pairs(bu)do table.sort(bx)end;local by=function(bz,aX,a_,bA)local bB=bt[bz]for af,bx in pairs(bu[bz])do for bo,aZ in pairs(bB[bx])do if aZ.ShouldUpdate==nil or aZ.ShouldUpdate(a_,bA,ay,aZ)then aZ.lastUpdate=a_;local b7=aZ.RequireAllOriginal;if b7==nil then b7=aZ.RequireAnyOriginal end;local b8=table.getn(b7)local bC=aZ.Version;local aP=aX:FilterChunks(aZ.Filter.Match)local bD=aZ.Update;ay.Version=ay.Version+1;if aZ.BeforeUpdate~=nil then aZ.BeforeUpdate(a_,bA,ay,aZ)end;for aD,aK in pairs(aP)do local ba=aK.Version==0 or aK.Version>bC;local aA=aK.Buffers;local bb=aA[av]local bc=table.create(b8)local bd=false;for be,bf in ipairs(b7)do if aA[bf]~=nil then bc[be]=aA[bf]else bc[be]={}end end;for aC=1,aK.Count do if bD(a_,ay,ba,bb[aC],aC,table.unpack(bc))then bd=true end end;if bd then aK.Version=ay.Version end end;if aZ.AfterUpdate~=nil then aZ.AfterUpdate(a_,bA,ay,aZ)end;aZ.Version=ay.Version end end end end;local bE=function(bF,aX,a_)ay.Version=ay.Version+1;for aG,bG in pairs(bF)do local bH=l({RequireAny=bG})local aK,aC=aX:GetEntityChunk(aG)if aK~=nil then local aA=aK.Buffers;for bo,aZ in pairs(bv)do if aZ.Filter.Match(aK.Archetype.Components)then local b7=aZ.RequireAllOriginal;if b7==nil then b7=aZ.RequireAnyOriginal end;if bH.Match(b7)then local bc=table.create(table.getn(b7))for be,bf in ipairs(b7)do if aA[bf]~=nil then bc[be]=aA[bf]else bc[be]={}end end;if aZ.OnEnter(a_,ay,aG,aC,table.unpack(bc))then aK.Version=ay.Version end end end end end end end;local bI=function(bJ,aX,a_)ay.Version=ay.Version+1;for aG,g in pairs(bJ)do local aK,aC=aX:GetEntityChunk(aG)if aK~=nil then local aA=aK.Buffers;for g,aZ in pairs(bw)do if aZ.Filter.Match(aK.Archetype.Components)then local b7=aZ.RequireAllOriginal;if b7==nil then b7=aZ.RequireAnyOriginal end;local bc=table.create(table.getn(b7))for be,bf in ipairs(b7)do if aA[bf]~=nil then bc[be]=aA[bf]else bc[be]={}end end;if aZ.OnRemove(a_,ay,aG,aC,table.unpack(bc))then aK.Version=ay.Version end end end end end end;return by,bE,bI end;local function bK(bi,m)if m==nil then m={}end;local bL=1;local bM={}local bN;local bO,bP,bQ;local bR;local bA=1;local bS=nil;local bT=0;local bU=0;local bV=0;local bW=0;local bX=0;local bY=0;local bZ=10;local b_=0;local aX;local c0;local c1;local c2={}local c3={}local c4={}local c5={}local ay;local c6=false;local function c7()local au=bL;bL=bL+1;c0:Set(au,ag)c2[au]=true;c5[au]=ag;c6=true;return au end;local function c8(aE,aa)if c2[aE]==true then return c0:GetValue(aE,aa)elseif c4[aE]~=nil then return c1:GetValue(aE,aa)else return aX:GetValue(aE,aa)end end;local function c9(aE,aa,...)local az=c5[aE]if az==nil then return end;c6=true;local ca=az:With(aa)local cb=az~=ca;if cb then c5[aE]=ca end;local an;local cc={...}if cc and cc[1]and typeof(cc[1])=='table'and cc[1].__v then an=cc[1].__v[0]else an=ai[aa](table.unpack(cc))end;if c2[aE]==true then if cb then c0:Set(aE,ca)end;c0:SetValue(aE,aa,an)else if cb then if c4[aE]==nil then c4[aE]={received={},lost={}}c1:Set(aE,ca)c1:SetData(aE,aX:GetData(aE))else c1:Set(aE,ca)end end;if c4[aE]~=nil then c1:SetValue(aE,aa,an)local cd=false;for aD,h in pairs(c4[aE].lost)do if h==aa then table.remove(c4[aE].lost,aD)cd=true;break end end;if not cd then table.insert(c4[aE].received,aa)end end;aX:SetValue(aE,aa,an)end end;local function ce(aE,aa,cf,...)local cg=aj[aa][cf]if not cg then return nil end;local ch,an=cg(ay.Get(aE,aa),table.unpack({...}))if ch then ay.Set(aE,aa,{__v={an}})end;return an end;local function ci(aE,aa)local az=c5[aE]if az==nil then return end;if c3[aE]==true then return end;c6=true;if aa==nil then if c2[aE]==true then c0:Remove(aE)c2[aE]=nil;c5[aE]=nil else if c3[aE]==nil then c3[aE]=true end end else local ca=az:Without(aa)local cb=az~=ca;if cb then c5[aE]=ca end;if c2[aE]==true then if cb then c0:Set(aE,ca)end else if cb then if c4[aE]==nil then c4[aE]={received={},lost={}}c1:Set(aE,ca)c1:SetData(aE,aX:GetData(aE))else c1:Set(aE,ca)end end;if c4[aE]~=nil then c1:SetValue(aE,aa,nil)local cd=false;for aD,h in pairs(c4[aE].received)do if h==aa then table.remove(c4[aE].received,aD)cd=true;break end end;if not cd then table.insert(c4[aE].lost,aa)end end;aX:SetValue(aE,aa,nil)end end end;local function cj(aE,aa)if c5[aE]==nil then return false end;return c5[aE]:Has(aa)end;local function ck(cl,a1)local cm=false;local cn=function()cm=true end;local aP=aX:FilterChunks(cl.Match)for aD,aK in pairs(aP)do local aA=aK.Buffers;local bc=table.create(table.getn(cl.Components))for be,bf in ipairs(cl.Components)do if aA[bf]~=nil then bc[be]=aA[bf]else bc[be]={}end end;local bb=aA[av]local bd=false;for aC=1,aK.Count do if a1(cn,bb[aC],aC,table.unpack(bc))then bd=true end;if cm then break end end;if bd then aK.Version=ay.Version end;if cm then break end end end;local function co(aY,bx,m)if aY==nil then return end;if aQ[aY]==nil then error('There is no registered system with the given ID')end;if aQ[aY].Step=='task'then bN:AddSystem(aY)else if bM[aY]~=nil then return end;if aX:Count()>0 or c0:Count()>0 then error('Adding systems is not allowed after adding entities in the world')end;if m==nil then m={}end;local aZ={Id=aY,Name=aQ[aY].Name,RequireAll=aQ[aY].RequireAll,RequireAny=aQ[aY].RequireAny,RequireAllOriginal=aQ[aY].RequireAllOriginal,RequireAnyOriginal=aQ[aY].RequireAnyOriginal,RejectAll=aQ[aY].RejectAll,RejectAny=aQ[aY].RejectAny,Filter=aQ[aY].Filter,OnCreate=aQ[aY].OnCreate,ShouldUpdate=aQ[aY].ShouldUpdate,BeforeUpdate=aQ[aY].BeforeUpdate,Update=aQ[aY].Update,AfterUpdate=aQ[aY].AfterUpdate,OnEnter=aQ[aY].OnEnter,OnRemove=aQ[aY].OnRemove,Step=aQ[aY].Step,Order=aQ[aY].Order,Version=0,LastUpdate=bW,Config=m}if bx~=nil and bx<0 then aZ.Order=50 end;bM[aY]=aZ;b_=0;if aZ.OnCreate~=nil then aZ.OnCreate(ay,aZ)end end end;local function cp(aE)if c5[aE]==nil then return false end;if c2[aE]==true then return false end;if c3[aE]==true then return false end;return true end;local function cq()if ay._steppedConn~=nil then ay._steppedConn:Disconnect()ay._steppedConn=nil end;if ay._heartbeatConn~=nil then ay._heartbeatConn:Disconnect()ay._heartbeatConn=nil end;if ay._renderSteppedConn~=nil then ay._renderSteppedConn:Disconnect()ay._renderSteppedConn=nil end;aX=nil;c0=nil;c1=nil;c4=nil;c3=nil;bM=nil;bO=nil;bP=nil;bQ=nil;c5=nil;bN=nil;ay.Create=nil;ay.Set=nil;ay.Get=nil;ay.Remove=nil;ay.Has=nil;ay.ForEach=nil;ay.AddSystem=nil;ay.Alive=nil;ay.Update=nil;ay.Destroy=nil;ay=nil end;local function cr(a_)if not c6 then return end;c6=false;local cs=false;local bF={}bQ(c3,aX,a_)for aG,ct in pairs(c3)do aX:Remove(aG)c5[aG]=nil;if c4[aG]~=nil then c4[aG]=nil;c1:Remove(aG)end end;c3={}for aG,cu in pairs(c4)do aX:Set(aG,c5[aG])aX:SetData(aG,c1:GetData(aG))c1:Remove(aG)if table.getn(cu.received)>0 then bF[aG]=cu.received;cs=true end end;c4={}for aG,ct in pairs(c2)do aX:Set(aG,c5[aG])aX:SetData(aG,c0:GetData(aG))c0:Remove(aG)bF[aG]=c5[aG].Components;cs=true end;c2={}if cs then bP(bF,aX,a_)bF=nil end end;local function cv(cw)m.Frequency=cw;if m.Frequency==nil then m.Frequency=30 end;local cx=math.round(math.abs(m.Frequency)/2)*2;if cx<2 then cx=2 end;if m.Frequency~=cx then m.Frequency=cx;print(string.format(">>> ATTENTION! The execution frequency of world has been changed to %d <<<",cx))end;bR=1000/m.Frequency/1000;ay.Frequency=m.Frequency end;local function cy(bz,cz)if not a:IsRunning()then return end;if bS==nil then bS=cz end;local cA=cz;cz=cz-bS;if b_ay then aK.LastChunk=aK.LastChunk+1;aK.NextChunkIndex=1;aK.Chunks[aK.LastChunk]=ax.New(self.World,aA)self.Version=self.Version+1 end end;function aG:Remove(aH)local aF=self.Entities[aH]if aF==nil then return end;local aK=self.Archetypes[aF.Archetype]local aL=aK.Chunks[aF.Chunk]aL:Clear(aF.ChunkIndex)aL.Count=aL.Count-1;self.Entities[aH]=nil;self.CountValue=self.CountValue-1;aK.Count=aK.Count-1;if aK.NextChunkIndex==1 then aK.Chunks[aK.LastChunk]=nil;aK.LastChunk=aK.LastChunk-1;aK.NextChunkIndex=ay+1;self.Version=self.Version+1 end;if aK.Count>0 then if aK.NextChunkIndex>1 then if not(aK.LastChunk==aF.Chunk and aK.NextChunkIndex-1==aF.ChunkIndex)then local aM=aK.Chunks[aK.LastChunk]:Get(aK.NextChunkIndex-1)aK.Chunks[aF.Chunk]:Set(aF.ChunkIndex,aM)local aN=aM[aw]local aO=self.Entities[aN]aO.Chunk=aF.Chunk;aO.ChunkIndex=aF.ChunkIndex end;aK.NextChunkIndex=aK.NextChunkIndex-1;aK.Chunks[aK.LastChunk]:Clear(aK.NextChunkIndex)end else aK.NextChunkIndex=aK.NextChunkIndex-1 end end;function aG:Count()return self.CountValue end;function aG:Clear(aH)local aF=self.Entities[aH]if aF==nil then return end;local aL=self.Archetypes[aF.Archetype].Chunks[aF.Chunk]aL:Clear(aF.ChunkIndex)end;function aG:GetValue(aH,aa)local aF=self.Entities[aH]if aF==nil then return nil end;return self.Archetypes[aF.Archetype].Chunks[aF.Chunk]:GetValue(aF.ChunkIndex,aa)end;function aG:SetValue(aH,aa,ao)local aF=self.Entities[aH]if aF==nil then return end;local aL=self.Archetypes[aF.Archetype].Chunks[aF.Chunk]aL:SetValue(aF.ChunkIndex,aa,ao)end;function aG:SetDirty(aH)local aF=self.Entities[aH]if aF==nil then return end;local aL=self.Archetypes[aF.Archetype].Chunks[aF.Chunk]self.World.Version=self.World.Version+1;aL.Version=self.World.Version end;function aG:GetData(aH)local aF=self.Entities[aH]if aF==nil then return nil end;local aL=self.Archetypes[aF.Archetype].Chunks[aF.Chunk]return aL:Get(aF.ChunkIndex)end;function aG:SetData(aH,aa,a5)local aF=self.Entities[aH]if aF==nil then return end;local aL=self.Archetypes[aF.Archetype].Chunks[aF.Chunk]aL:Set(aF.ChunkIndex,aa,a5)end;function aG:GetEntityChunk(aH)local aF=self.Entities[aH]if aF==nil then return end;return self.Archetypes[aF.Archetype].Chunks[aF.Chunk],aF.ChunkIndex end;function aG:FilterChunks(aP)local aQ={}for aI,aK in pairs(self.Archetypes)do if aP(a6[aI].Components)then for ag,aL in pairs(aK.Chunks)do table.insert(aQ,aL)end end end;return aQ end;local aR={}local aS={}local aT={'task','render','process','processIn','processOut','transform'}local function aU(m)if m==nil then error('System configuration is required for its creation')end;if m.Name==nil then error('The system "Name" is required for registration')end;if aS[m.Name]~=nil then error('Another System already registered with that name')end;if m.Step==nil then m.Step='transform'end;if not table.find(aT,m.Step)then error('The "step" parameter must one of ',table.concat(aT,', '))end;if m.Step=='task'then if m.Order~=nil then error('Task-type systems do not accept the "Order" parameter')end;if m.ShouldUpdate~=nil then error('Task-type systems do not accept the "ShouldUpdate" parameter')end;if m.BeforeUpdate~=nil then error('Task-type systems do not accept the "BeforeUpdate" parameter')end;if m.Update~=nil then error('Task-type systems do not accept the "Update" parameter')end;if m.AfterUpdate~=nil then error('Task-type systems do not accept the "AfterUpdate" parameter')end;if m.OnEnter~=nil then error('Task-type systems do not accept the "OnEnter" parameter')end;if m.OnExit~=nil then error('Task-type systems do not accept the "OnExit" parameter')end;if m.Execute==nil then error('The task "Execute" method is required for registration')end end;if m.Order==nil or m.Order<0 then m.Order=50 end;table.insert(aR,{Filter=l(m),Name=m.Name,RequireAll=m.RequireAll,RequireAny=m.RequireAny,RequireAllOriginal=m.RequireAllOriginal,RequireAnyOriginal=m.RequireAnyOriginal,RejectAll=m.RejectAll,RejectAny=m.RejectAny,ShouldUpdate=m.ShouldUpdate,BeforeUpdate=m.BeforeUpdate,Update=m.Update,AfterUpdate=m.AfterUpdate,OnCreate=m.OnCreate,OnEnter=m.OnEnter,OnExit=m.OnExit,OnRemove=m.OnRemove,BeforeExecute=m.BeforeExecute,Execute=m.Execute,Step=m.Step,Order=m.Order})local av=table.getn(aR)aS[m.Name]=av;return av end;local aV={}aV.__index=aV;local aW=0.008;local aX=0.002;function aV.New(az,aY)return setmetatable({World=az,EntityManager=aY,min_vruntime=0,rbtree=a3(),LastEntityManagerVersion=-1,Systems={}},aV)end;function aV:AddSystem(aZ,m)if self.Systems[aZ]~=nil then return end;if m==nil then m={}end;local a_={Id=aZ,name=aR[aZ].Name,RequireAll=aR[aZ].RequireAll,RequireAny=aR[aZ].RequireAny,RequireAllOriginal=aR[aZ].RequireAllOriginal,RequireAnyOriginal=aR[aZ].RequireAnyOriginal,RejectAll=aR[aZ].RejectAll,RejectAny=aR[aZ].RejectAny,Filter=aR[aZ].Filter,BeforeExecute=aR[aZ].BeforeExecute,Execute=aR[aZ].Execute,Config=m}self.Systems[aZ]=a_;self.LastEntityManagerVersion=0 end;function aV:Run(b0)if self.EntityManager.Version~=self.LastEntityManagerVersion then self:Update()self.LastEntityManagerVersion=self.EntityManager.Version end;local E=self.rbtree;local az=self.World;local b1=math.max(aW,0.01667-(os.clock()-b0.frameReal)-aX)local b2={}local b3=os.clock()local b4,aL,a_,b5,b6;local b7=X(E)while b7~=nil do Q(E,b7)aL=b7.data[1]a_=b7.data[2]b5=b7.data[3]b6=b7.data[4]b4=os.clock()if b6==0 then b6=b4 end;local b8=a_.RequireAllOriginal;if b8==nil then b8=a_.RequireAnyOriginal end;local b9=table.getn(b8)local ba=a_.Execute;az.Version=az.Version+1;if a_.BeforeExecute~=nil then a_.BeforeExecute(b0,az,a_)end;local bb=aL.Version==0 or aL.Version>b5;local aB=aL.buffers;local bc=aB[aw]local bd=table.create(b9)local be=false;for bf,bg in ipairs(b8)do if aB[bg]~=nil then bd[bf]=aB[bg]else bd[bf]={}end end;local bh={process=b0.process,frame=b0.frame,frameReal=b0.frameReal,delta=b0.delta,deltaExec=b4-b6}for aD=1,aL.Count do if ba(bh,az,bb,bc[aD],aD,table.unpack(bd))then be=true end end;if be then aL.Version=az.Version end;b7.data[3]=az.Version;b7.data[4]=b4;b7.key=b7.key+os.clock()-b4;O(E,b7)if os.clock()-b3>b1 then break end;b7=M(b7)end;local bi=X(E)if bi~=nil then self.min_vruntime=math.max(bi.key-b,0)else self.min_vruntime=0 end end;function aV:Update()local E=self.rbtree;local bj=self.Systems;local aY=self.EntityManager;local bk=self.min_vruntime;local bl=self.World.Version;local bm={}local bn={}local aL,a_;a0(E,function(b7)aL=b7.data[1]a_=b7.data[2]if bm[aL]==nil then bm[aL]={}end;if bm[aL][a_]==nil then bm[aL][a_]={}end;table.insert(bm[aL][a_],b7)bn[aL]=true end)for ag,bo in pairs(bj)do local aQ=aY:FilterChunks(bo.Filter.Match)for bp,bq in pairs(aQ)do bn[bq]=nil;if bm[bq]==nil then O(E,a4(bk,{bq,bo,bl,0}))elseif bm[bq][bo]==nil then O(E,a4(bk,{bq,bo,bl,0}))end end end;for br,g in pairs(bn)do for bs,b2 in pairs(bm[br])do for g,b7 in ipairs(b2)do Q(E,b7)end end end end;local function bt(az,bj)local bu={processIn={},process={},processOut={},transform={},render={}}local bv={processIn={},process={},processOut={},transform={},render={}}local bw={}local bx={}for aE,a_ in pairs(bj)do if a_.Update~=nil then if bu[a_.Step][a_.Order]==nil then bu[a_.Step][a_.Order]={}table.insert(bv[a_.Step],a_.Order)end;table.insert(bu[a_.Step][a_.Order],a_)end;if a_.OnEnter~=nil or a_.OnExit~=nil then table.insert(bw,a_)end;if a_.OnRemove~=nil then table.insert(bx,a_)end end;for g,by in pairs(bv)do table.sort(by)end;local bz=function(bA,aY,b0,bB)local bC=bu[bA]for ag,by in pairs(bv[bA])do for bp,a_ in pairs(bC[by])do if a_.ShouldUpdate==nil or a_.ShouldUpdate(b0,bB,az,a_)then a_.lastUpdate=b0;local b8=a_.RequireAllOriginal;if b8==nil then b8=a_.RequireAnyOriginal end;local b9=table.getn(b8)local bD=a_.Version;local aQ=aY:FilterChunks(a_.Filter.Match)local bE=a_.Update;az.Version=az.Version+1;if a_.BeforeUpdate~=nil then a_.BeforeUpdate(b0,bB,az,a_)end;for aE,aL in pairs(aQ)do local bb=aL.Version==0 or aL.Version>bD;local aB=aL.Buffers;local bc=aB[aw]local bd=table.create(b9)local be=false;for bf,bg in ipairs(b8)do if aB[bg]~=nil then bd[bf]=aB[bg]else bd[bf]={}end end;for aD=1,aL.Count do if bE(b0,az,bb,bc[aD],aD,table.unpack(bd))then be=true end end;if be then aL.Version=az.Version end end;if a_.AfterUpdate~=nil then a_.AfterUpdate(b0,bB,az,a_)end;a_.Version=az.Version end end end end;local bF=function(bG,aY,b0)az.Version=az.Version+1;for aH,bH in pairs(bG)do local aL,aD=aY:GetEntityChunk(aH)if aL~=nil then local aB=aL.Buffers;local bI=aL.Archetype;local bJ=bI:WithAll(bH.Lost):WithoutAll(bH.Received)for bp,a_ in pairs(bw)do local bK=a_.Filter.Match(bI.Components)local bL=a_.Filter.Match(bJ.Components)local bM=nil;if a_.OnEnter~=nil and bK and not bL then bM=a_.OnEnter elseif a_.OnExit~=nil and bL and not bK then bM=a_.OnExit end;if bM~=nil then local b8=a_.RequireAllOriginal;if b8==nil then b8=a_.RequireAnyOriginal end;local bd=table.create(table.getn(b8))for bf,bg in ipairs(b8)do if aB[bg]~=nil then bd[bf]=aB[bg]else bd[bf]={}end end;if bM(b0,az,aH,aD,table.unpack(bd))then aL.Version=az.Version end end end end end end;local bN=function(bO,aY,b0)az.Version=az.Version+1;for aH,g in pairs(bO)do local aL,aD=aY:GetEntityChunk(aH)if aL~=nil then local aB=aL.Buffers;for g,a_ in pairs(bx)do if a_.Filter.Match(aL.Archetype.Components)then local b8=a_.RequireAllOriginal;if b8==nil then b8=a_.RequireAnyOriginal end;local bd=table.create(table.getn(b8))for bf,bg in ipairs(b8)do if aB[bg]~=nil then bd[bf]=aB[bg]else bd[bf]={}end end;if a_.OnRemove(b0,az,aH,aD,table.unpack(bd))then aL.Version=az.Version end end end end end end;return bz,bF,bN end;local function bP(bj,m)if m==nil then m={}end;local bQ=1;local bR={}local bS;local bT,bU,bV;local bW;local bB=1;local bX=nil;local bY=0;local bZ=0;local b_=0;local c0=0;local c1=0;local c2=0;local c3=10;local c4=0;local aY;local c5;local c6;local c7={}local c8={}local c9={}local ca={}local az;local cb=false;local function cc()local av=bQ;bQ=bQ+1;c5:Set(av,ah)c7[av]=true;ca[av]=ah;cb=true;return av end;local function cd(aF,aa)if c7[aF]==true then return c5:GetValue(aF,aa)elseif c9[aF]~=nil then return c6:GetValue(aF,aa)else return aY:GetValue(aF,aa)end end;local function ce(aF)if c7[aF]==true then c5:SetDirty(aF)else if c9[aF]~=nil then c6:SetDirty(aF)end;aY:SetDirty(aF)end end;local function cf(aF,aa,...)local aA=ca[aF]if aA==nil then return end;cb=true;local cg=aA:With(aa)local ch=aA~=cg;if ch then ca[aF]=cg end;local ao;local ci={...}if ci and ci[1]and typeof(ci[1])=='table'and ci[1].__v then ao=ci[1].__v[0]else ao=aj[aa](table.unpack(ci))end;if c7[aF]==true then if ch then c5:Set(aF,cg)end;c5:SetValue(aF,aa,ao)else if ch then if c9[aF]==nil then c9[aF]={received={},lost={}}c6:Set(aF,cg)c6:SetData(aF,aY:GetData(aF))else c6:Set(aF,cg)end end;if c9[aF]~=nil then c6:SetValue(aF,aa,ao)local cj=false;for aE,h in pairs(c9[aF].lost)do if h==aa then table.remove(c9[aF].lost,aE)cj=true;break end end;if not cj then table.insert(c9[aF].received,aa)end end;aY:SetValue(aF,aa,ao)end end;local function ck(aF,aa,cl,...)local bM=ak[aa][cl]if not bM then return nil end;local cm,ao=bM(az.Get(aF,aa),table.unpack({...}))if cm then az.Set(aF,aa,{__v={ao}})end;return ao end;local function cn(aF,aa)local aA=ca[aF]if aA==nil then return end;if c8[aF]==true then return end;cb=true;if aa==nil then if c7[aF]==true then c5:Remove(aF)c7[aF]=nil;ca[aF]=nil else if c8[aF]==nil then c8[aF]=true end end else local cg=aA:Without(aa)local ch=aA~=cg;if ch then ca[aF]=cg end;if c7[aF]==true then if ch then c5:Set(aF,cg)end else if ch then if c9[aF]==nil then c9[aF]={received={},lost={}}c6:Set(aF,cg)c6:SetData(aF,aY:GetData(aF))else c6:Set(aF,cg)end end;if c9[aF]~=nil then c6:SetValue(aF,aa,nil)local cj=false;for aE,h in pairs(c9[aF].received)do if h==aa then table.remove(c9[aF].received,aE)cj=true;break end end;if not cj then table.insert(c9[aF].lost,aa)end end;aY:SetValue(aF,aa,nil)end end end;local function co(aF,aa)if ca[aF]==nil then return false end;return ca[aF]:Has(aa)end;local function cp(cq,a1)local cr=false;local cs=function()cr=true end;local aQ=aY:FilterChunks(cq.Match)for aE,aL in pairs(aQ)do local aB=aL.Buffers;local bd=table.create(table.getn(cq.Components))for bf,bg in ipairs(cq.Components)do if aB[bg]~=nil then bd[bf]=aB[bg]else bd[bf]={}end end;local bc=aB[aw]local be=false;for aD=1,aL.Count do if a1(cs,bc[aD],aD,table.unpack(bd))then be=true end;if cr then break end end;if be then aL.Version=az.Version end;if cr then break end end end;local function ct(aZ,by,m)if aZ==nil then return end;if aR[aZ]==nil then error('There is no registered system with the given ID')end;if aR[aZ].Step=='task'then bS:AddSystem(aZ)else if bR[aZ]~=nil then return end;if aY:Count()>0 or c5:Count()>0 then error('Adding systems is not allowed after adding entities in the world')end;if m==nil then m={}end;local a_={Id=aZ,Name=aR[aZ].Name,RequireAll=aR[aZ].RequireAll,RequireAny=aR[aZ].RequireAny,RequireAllOriginal=aR[aZ].RequireAllOriginal,RequireAnyOriginal=aR[aZ].RequireAnyOriginal,RejectAll=aR[aZ].RejectAll,RejectAny=aR[aZ].RejectAny,Filter=aR[aZ].Filter,OnCreate=aR[aZ].OnCreate,ShouldUpdate=aR[aZ].ShouldUpdate,BeforeUpdate=aR[aZ].BeforeUpdate,Update=aR[aZ].Update,AfterUpdate=aR[aZ].AfterUpdate,OnEnter=aR[aZ].OnEnter,OnExit=aR[aZ].OnExit,OnRemove=aR[aZ].OnRemove,Step=aR[aZ].Step,Order=aR[aZ].Order,Version=0,LastUpdate=c0,Config=m}if by~=nil and by<0 then a_.Order=50 end;bR[aZ]=a_;c4=0;if a_.OnCreate~=nil then a_.OnCreate(az,a_)end end end;local function cu(aF)if ca[aF]==nil then return false end;if c7[aF]==true then return false end;if c8[aF]==true then return false end;return true end;local function cv()if az._steppedConn~=nil then az._steppedConn:Disconnect()az._steppedConn=nil end;if az._heartbeatConn~=nil then az._heartbeatConn:Disconnect()az._heartbeatConn=nil end;if az._renderSteppedConn~=nil then az._renderSteppedConn:Disconnect()az._renderSteppedConn=nil end;aY=nil;c5=nil;c6=nil;c9=nil;c8=nil;bR=nil;bT=nil;bU=nil;bV=nil;ca=nil;bS=nil;az.Create=nil;az.Set=nil;az.Dirty=nil;az.Get=nil;az.Remove=nil;az.Has=nil;az.ForEach=nil;az.AddSystem=nil;az.Alive=nil;az.Update=nil;az.Destroy=nil;az=nil end;local function cw(b0)if not cb then return end;cb=false;local cx=false;local bG={}bV(c8,aY,b0)for aH,cy in pairs(c8)do aY:Remove(aH)ca[aH]=nil;if c9[aH]~=nil then c9[aH]=nil;c6:Remove(aH)end end;c8={}for aH,cz in pairs(c9)do aY:Set(aH,ca[aH])aY:SetData(aH,c6:GetData(aH))c6:Remove(aH)if table.getn(cz.received)>0 or table.getn(cz.lost)>0 then if bG[aH]==nil then bG[aH]={Received={},Lost={}}end;if table.getn(cz.received)>0 then for g,aa in ipairs(cz.received)do table.insert(bG[aH].Received,aa)end end;if table.getn(cz.lost)>0 then for g,aa in ipairs(cz.lost)do table.insert(bG[aH].Lost,aa)end end;cx=true end end;c9={}for aH,cy in pairs(c7)do aY:Set(aH,ca[aH])aY:SetData(aH,c5:GetData(aH))c5:Remove(aH)if bG[aH]==nil then bG[aH]={Received={},Lost={}}end;for g,aa in ipairs(ca[aH].Components)do table.insert(bG[aH].Received,aa)end;cx=true end;c7={}if cx then bU(bG,aY,b0)bG=nil end end;local function cA(cB)m.Frequency=cB;if m.Frequency==nil then m.Frequency=30 end;local cC=math.round(math.abs(m.Frequency)/2)*2;if cC<2 then cC=2 end;if m.Frequency~=cC then m.Frequency=cC;print(string.format(">>> ATTENTION! The execution frequency of world has been changed to %d <<<",cC))end;bW=1000/m.Frequency/1000;az.Frequency=m.Frequency end;local function cD(bA,cE)if not a:IsRunning()then return end;if bX==nil then bX=cE end;local cF=cE;cE=cE-bX;if c4