diff --git a/lib/init.lua b/lib/init.lua index c9ede57..ee62f82 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -35,8 +35,19 @@ type EntityIndex = { [i24]: Record } type ComponentIndex = { [i24]: ArchetypeMap} type ArchetypeRecord = number -type ArchetypeMap = { map: { [ArchetypeId]: ArchetypeRecord } , size: number } +type ArchetypeMap = { sparse: { [ArchetypeId]: ArchetypeRecord } , size: number } type Archetypes = { [ArchetypeId]: Archetype } + +type ArchetypeDiff = { + added: Ty, + removed: Ty, +} + +local HI_COMPONENT_ID = 256 +local ON_ADD = HI_COMPONENT_ID + 1 +local ON_REMOVE = HI_COMPONENT_ID + 2 +local ON_SET = HI_COMPONENT_ID + 3 +local REST = HI_COMPONENT_ID + 4 local function transitionArchetype( entityIndex: EntityIndex, @@ -89,14 +100,7 @@ local function moveEntity(entityIndex, entityId: i53, record: Record, to: Archet end local function hash(arr): string | number - if true then - return table.concat(arr, "_") - end - local hashed = 5381 - for i = 1, #arr do - hashed = ((bit32.lshift(hashed, 5)) + hashed) + arr[i] - end - return hashed + return table.concat(arr, "_") end local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archetype, from: Archetype?) @@ -107,11 +111,11 @@ local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archet local destinationId = destinationIds[i] if not componentIndex[destinationId] then - componentIndex[destinationId] = { size = 0, map = {} } + componentIndex[destinationId] = { size = 0, sparse = {} } end local archetypesMap = componentIndex[destinationId] - archetypesMap.map[to.id] = i + archetypesMap.sparse[to.id] = i to.records[destinationId] = i end end @@ -152,22 +156,47 @@ function World.new() componentIndex = {}, archetypes = {}, archetypeIndex = {}, - ROOT_ARCHETYPE = nil :: Archetype?, + ROOT_ARCHETYPE = (nil :: any) :: Archetype, nextId = 0, - nextArchetypeId = 0 + nextArchetypeId = 0, + hooks = { + [ON_ADD] = {} + } }, World) return self end +local function emit(world, eventDescription) + local event = eventDescription.event + + table.insert(world.hooks[event], { + ids = eventDescription.ids, + archetype = eventDescription.archetype, + otherArchetype = eventDescription.otherArchetype, + offset = eventDescription.offset + }) +end + + + +local function onNotifyAdd(world, archetype, otherArchetype, row: number, added: Ty) + if #added > 0 then + emit(world, { + event = ON_ADD, + ids = added, + archetype = archetype, + otherArchetype = otherArchetype, + offset = row, + }) + end +end + + type World = typeof(World.new()) local function ensureArchetype(world: World, types, prev) if #types < 1 then - if not world.ROOT_ARCHETYPE then - local ROOT_ARCHETYPE = archetypeOf(world, {}, nil) - world.ROOT_ARCHETYPE = ROOT_ARCHETYPE - return ROOT_ARCHETYPE - end + end local ty = hash(types) local archetype = world.archetypeIndex[ty] @@ -211,8 +240,14 @@ local function ensureEdge(archetype: Archetype, componentId: i53) return archetype.edges[componentId] end -local function archetypeTraverseAdd(world: World, componentId: i53, archetype: Archetype?): Archetype - local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype +local function archetypeTraverseAdd(world: World, componentId: i53, from: Archetype): Archetype + if not from then + if not world.ROOT_ARCHETYPE then + local ROOT_ARCHETYPE = archetypeOf(world, {}, nil) + world.ROOT_ARCHETYPE = ROOT_ARCHETYPE + end + from = world.ROOT_ARCHETYPE + end local edge = ensureEdge(from, componentId) if not edge.add then @@ -222,17 +257,16 @@ local function archetypeTraverseAdd(world: World, componentId: i53, archetype: A return edge.add end -function World.ensureRecord(world: World, entityId: i53) - local entityIndex = world.entityIndex +local function ensureRecord(entityIndex, entityId: i53): Record local id = entityId if not entityIndex[id] then - entityIndex[id] = {} :: Record + entityIndex[id] = {} end - return entityIndex[id] + return entityIndex[id] :: Record end function World.set(world: World, entityId: i53, componentId: i53, data: unknown) - local record = world:ensureRecord(entityId) + local record = ensureRecord(world.entityIndex, entityId) local sourceArchetype = record.archetype local destinationArchetype = archetypeTraverseAdd(world, componentId, sourceArchetype) @@ -242,6 +276,7 @@ function World.set(world: World, entityId: i53, componentId: i53, data: unknown) -- if it has any components, then it wont be the root archetype if #destinationArchetype.types > 0 then newEntity(entityId, record, destinationArchetype) + onNotifyAdd(world, destinationArchetype, sourceArchetype, record.row, { componentId }) end end local archetypeRecord = destinationArchetype.records[componentId] @@ -263,7 +298,7 @@ local function archetypeTraverseRemove(world: World, componentId: i53, archetype end function World.remove(world: World, entityId: i53, componentId: i53) - local record = world:ensureRecord(entityId) + local record = ensureRecord(world.entityIndex, entityId) local sourceArchetype = record.archetype local destinationArchetype = archetypeTraverseRemove(world, componentId, sourceArchetype) @@ -274,7 +309,7 @@ end local function get(componentIndex: { [i24]: ArchetypeMap }, record: Record, componentId: i24) local archetype = record.archetype - local archetypeRecord = componentIndex[componentId].map[archetype.id] + local archetypeRecord = componentIndex[componentId].sparse[archetype.id] if not archetypeRecord then return nil @@ -306,10 +341,7 @@ function World.get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53 end end -function World.entity(world: World) - world.nextId += 1 - return world.nextId -end + local function noop(): any return function() @@ -326,10 +358,11 @@ local function getSmallestMap(componentIndex, components) end end - return s.map + return s.sparse end function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> () + local compatibleArchetypes = {} local components = { ... } local archetypes = world.archetypes @@ -449,6 +482,71 @@ function World.query(world: World, ...: i53): (() -> (number, ...any)) | () -> ( end end +function World.component(world: World) + local id = world.nextId + 1 + if id > HI_COMPONENT_ID then + error("Too many components") + end + return id +end + +function World.entity(world: World) + world.nextId += 1 + return world.nextId + REST +end + +function World.observer(world: World, ...) + local componentIds = { ... } + + return { + event = function(event) + local hook = world.hooks[event] + world.hooks[event] = nil + + local last, change + return function() + last, change = next(hook, last) + if not last then + return + end + + local matched = false + + while not matched do + local skip = false + for _, id in change.ids do + if not table.find(componentIds, id) then + skip = true + break + end + end + + if skip then + last, change = next(hook, last) + continue + end + + matched = true + end + + local queryOutput = {} + local row = change.offset + local archetype = change.archetype + local columns = archetype.columns + local archetypeRecords = archetype.records + for _, id in componentIds do + table.insert(queryOutput, columns[archetypeRecords[id]][row]) + end + + return archetype.entities[row], unpack(queryOutput, 1, #queryOutput) + end + end + } +end + return table.freeze({ - World = World + World = World, + ON_ADD = ON_ADD, + ON_REMOVE = ON_REMOVE, + ON_SET = ON_SET }) \ No newline at end of file diff --git a/lib/init.spec.lua b/lib/init.spec.lua index de2ff9f..a0e4aa7 100644 --- a/lib/init.spec.lua +++ b/lib/init.spec.lua @@ -1,7 +1,8 @@ -local ecs = require(script.Parent).World.new() +local jecs = require(script.Parent) +local world = jecs.World.new() -local A, B, C, D = ecs:entity(), ecs:entity(), ecs:entity(), ecs:entity() -local E, F, G, H = ecs:entity(), ecs:entity(), ecs:entity(), ecs:entity() +local A, B, C, D = world:entity(), world:entity(), world:entity(), world:entity() +local E, F, G, H = world:entity(), world:entity(), world:entity(), world:entity() print("A", A) print("B", B) print("C", C) @@ -20,42 +21,42 @@ end local hm = 0 for i = 1, N do - local entity = ecs:entity() + local entity = world:entity() local combination = "" if flip() then combination ..= "2_" - ecs:set(entity, B, { value = true}) + world:set(entity, B, { value = true}) end if flip() then combination ..= "3_" - ecs:set(entity, C, { value = true}) + world:set(entity, C, { value = true}) end if flip() then combination ..= "4_" - ecs:set(entity, D, { value = true}) + world:set(entity, D, { value = true}) end if flip() then combination ..= "5_" - ecs:set(entity, E, { value = true}) + world:set(entity, E, { value = true}) end if flip() then combination ..= "6_" - ecs:set(entity, F, { value = true}) + world:set(entity, F, { value = true}) end if flip() then combination ..= "7_" - ecs:set(entity, G, { value = true}) + world:set(entity, G, { value = true}) end if flip() then combination ..= "8" - ecs:set(entity, H, { value = true}) + world:set(entity, H, { value = true}) end if #combination == 7 then combination = "1_" .. combination common += 1 - ecs:set(entity, A, { value = true}) + world:set(entity, A, { value = true}) end if combination:find("2") @@ -82,42 +83,57 @@ end return function() describe("World", function() it("should add component", function() - local id = ecs:entity() - ecs:set(id, A, true) - ecs:set(id, B, 1) + local id = world:entity() + world:set(id, A, true) + world:set(id, B, 1) - local id1 = ecs:entity() - ecs:set(id1, A, "hello") - expect(ecs:get(id, A)).to.equal(true) - expect(ecs:get(id, B)).to.equal(1) - expect(ecs:get(id1, A)).to.equal("hello") + local id1 = world:entity() + world:set(id1, A, "hello") + expect(world:get(id, A)).to.equal(true) + expect(world:get(id, B)).to.equal(1) + expect(world:get(id1, A)).to.equal("hello") end) it("should remove component", function() - local id = ecs:entity() - ecs:set(id, A, true) - ecs:set(id, B, 1000) - ecs:remove(id, A, false) + local id = world:entity() + world:set(id, A, true) + world:set(id, B, 1000) + world:remove(id, A, false) - expect(ecs:get(id, A)).to.equal(nil) + expect(world:get(id, A)).to.equal(nil) end) it("should override component data", function() - local id = ecs:entity() - ecs:set(id, A, true) - expect(ecs:get(id, A)).to.equal(true) + local id = world:entity() + world:set(id, A, true) + expect(world:get(id, A)).to.equal(true) - ecs:set(id, A, false) - expect(ecs:get(id, A)).to.equal(false) + world:set(id, A, false) + expect(world:get(id, A)).to.equal(false) end) it("query", function() local added = 0 - for _ in ecs:query(B, C, D, F) do + for _ in world:query(B, C, D, F) do added += 1 end expect(added).to.equal(hm) print(added, hm) end) - + + it("track changes", function() + local Position = world:entity() + + local moving = world:entity() + world:set(moving, Position, Vector3.new(1, 2, 3)) + + local count = 0 + + for e, position in world:observer(Position).event(jecs.ON_ADD) do + count += 1 + expect(e).to.equal(moving) + expect(position).to.equal(Vector3.new(1, 2, 3)) + end + expect(count).to.equal(1) + end) end) end \ No newline at end of file diff --git a/matterRewrite/init.lua b/matterRewrite/init.lua deleted file mode 100644 index 643cdee..0000000 --- a/matterRewrite/init.lua +++ /dev/null @@ -1,541 +0,0 @@ ---!optimize 2 ---!native ---!strict ---draft 4 - -type i53 = number -type i24 = number - -type Ty = { i53 } -type ArchetypeId = number - -type Column = { any } - -type Archetype = { - id: number, - edges: { - [i24]: { - add: Archetype, - remove: Archetype, - }, - }, - types: Ty, - type: string | number, - entities: { number }, - columns: { Column }, - records: {}, -} - -type Record = { - archetype: Archetype, - row: number, -} - -type EntityIndex = { [i24]: Record } -type ComponentIndex = { [i24]: ArchetypeMap} - -type ArchetypeRecord = number -type ArchetypeMap = { [ArchetypeId]: ArchetypeRecord } -type Archetypes = { [ArchetypeId]: Archetype } - -local function transitionArchetype( - entityIndex: EntityIndex, - destinationArchetype: Archetype, - destinationRow: i24, - sourceArchetype: Archetype, - sourceRow: i24 -) - local columns = sourceArchetype.columns - local sourceEntities = sourceArchetype.entities - local destinationEntities = destinationArchetype.entities - local destinationColumns = destinationArchetype.columns - - for componentId, column in columns do - local targetColumn = destinationColumns[componentId] - if targetColumn then - targetColumn[destinationRow] = column[sourceRow] - end - column[sourceRow] = column[#column] - column[#column] = nil - end - - destinationEntities[destinationRow] = sourceEntities[sourceRow] - local moveAway = #sourceEntities - sourceEntities[sourceRow] = sourceEntities[moveAway] - sourceEntities[moveAway] = nil - entityIndex[destinationEntities[destinationRow]].row = sourceRow -end - -local function archetypeAppend(entity: i53, archetype: Archetype): i24 - local entities = archetype.entities - table.insert(entities, entity) - return #entities -end - -local function newEntity(entityId: i53, record: Record, archetype: Archetype) - local row = archetypeAppend(entityId, archetype) - record.archetype = archetype - record.row = row - return record -end - -local function moveEntity(entityIndex, entityId: i53, record: Record, to: Archetype) - local sourceRow = record.row - local from = record.archetype - local destinationRow = archetypeAppend(entityId, to) - transitionArchetype(entityIndex, to, destinationRow, from, sourceRow) - record.archetype = to - record.row = destinationRow -end - -local function hash(arr): string | number - if true then - return table.concat(arr, "_") - end - local hashed = 5381 - for i = 1, #arr do - hashed = ((bit32.lshift(hashed, 5)) + hashed) + arr[i] - end - return hashed -end - -local function createArchetypeRecords(componentIndex: ComponentIndex, to: Archetype, from: Archetype?) - local destinationCount = #to.types - local destinationIds = to.types - - for i = 1, destinationCount do - local destinationId = destinationIds[i] - - if not componentIndex[destinationId] then - componentIndex[destinationId] = {} - end - componentIndex[destinationId][to.id] = i - to.records[destinationId] = i - end -end - -local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Archetype - local ty = hash(types) - - world.nextArchetypeId = (world.nextArchetypeId::number)+ 1 - local id = world.nextArchetypeId - - local columns = {} :: { any } - - for _ in types do - table.insert(columns, {}) - end - - local archetype = { - id = id, - types = types, - type = ty, - columns = columns, - entities = {}, - edges = {}, - records = {}, - } - world.archetypeIndex[ty] = archetype - world.archetypes[id] = archetype - createArchetypeRecords(world.componentIndex, archetype, prev) - - return archetype -end - -local World = {} -World.__index = World -function World.new() - local self = setmetatable({ - entityIndex = {}, - componentIndex = {}, - archetypes = {}, - archetypeIndex = {}, - ROOT_ARCHETYPE = nil :: Archetype?, - nextId = 2^8, - nextArchetypeId = 0 - }, World) - self.ROOT_ARCHETYPE = archetypeOf(self, {}, nil) - return self -end - -type World = typeof(World.new()) - -local function ensureArchetype(world: World, types, prev) - if #types < 1 then - - if not world.ROOT_ARCHETYPE then - local ROOT_ARCHETYPE = archetypeOf(world, {}, nil) - world.ROOT_ARCHETYPE = ROOT_ARCHETYPE - return ROOT_ARCHETYPE - end - end - local ty = hash(types) - local archetype = world.archetypeIndex[ty] - if archetype then - return archetype - end - - return archetypeOf(world, types, prev) -end - -local function findInsert(types: { i53 }, toAdd: i53) - local count = #types - for i = 1, count do - local id = types[i] - if id == toAdd then - return -1 - end - if id > toAdd then - return i - end - end - return count + 1 -end - -local function findArchetypeWith(world: World, node: Archetype, componentId: i53) - local types = node.types - local at = findInsert(types, componentId) - if at == -1 then - return node - end - - local destinationType = table.clone(node.types) - table.insert(destinationType, at, componentId) - return ensureArchetype(world, destinationType, node) -end - -local function ensureEdge(archetype: Archetype, componentId: i53) - if not archetype.edges[componentId] then - archetype.edges[componentId] = {} :: any - end - return archetype.edges[componentId] -end - -local function archetypeTraverseAdd(world: World, componentId: i53, archetype: Archetype?): Archetype - local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype - local edge = ensureEdge(from, componentId) - - if not edge.add then - edge.add = findArchetypeWith(world, from, componentId) - end - - return edge.add -end - -function World.ensureRecord(world: World, entityId: i53) - local entityIndex = world.entityIndex - local id = entityId - if not entityIndex[id] then - entityIndex[id] = {} :: Record - end - return entityIndex[id] -end - -function World.add(world: World, entityId: i53, componentId: i53, data: unknown) - local record = world:ensureRecord(entityId) - local sourceArchetype = record.archetype - local destinationArchetype = archetypeTraverseAdd(world, componentId, sourceArchetype) - - if sourceArchetype and not (sourceArchetype == destinationArchetype) then - moveEntity(world.entityIndex, entityId, record, destinationArchetype) - else - -- if it has any components, then it wont be the root archetype - if #destinationArchetype.types > 0 then - newEntity(entityId, record, destinationArchetype) - end - end - - local archetypeRecord = destinationArchetype.records[componentId] - destinationArchetype.columns[archetypeRecord][record.row] = data -end - -local function archetypeTraverseRemove(world: World, componentId: i53, archetype: Archetype?): Archetype - local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype - local edge = ensureEdge(from, componentId) - - - if not edge.remove then - local to = table.clone(from.types) - table.remove(to, table.find(to, componentId)) - edge.remove = ensureArchetype(world, to, from) - end - - return edge.remove -end - -function World.remove(world: World, entityId: i53, component: () -> () -> i53) - local componentId = component()() - local record = world:ensureRecord(entityId) - local sourceArchetype = record.archetype - local destinationArchetype = archetypeTraverseRemove(world, componentId, sourceArchetype) - - if sourceArchetype and not (sourceArchetype == destinationArchetype) then - moveEntity(world.entityIndex, entityId, record, destinationArchetype) - end -end - -local function get(componentIndex: { [i24]: ArchetypeMap }, record: Record, componentId: i24) - local archetype = record.archetype - local archetypeRecord = componentIndex[componentId][archetype.id] - - if not archetypeRecord then - return nil - end - - return archetype.columns[archetypeRecord][record.row] -end - -function World.get( - world: World, - entityId: i53, - a: () -> () -> i53, - b: () -> i53, - c: () -> i53, - d: () -> i53, - e: () -> i53 -) - - local id = entityId - local componentIndex = world.componentIndex - local record = world.entityIndex[id] - if not record then - return nil - end - - local va = get(componentIndex, record, a()()) - - if b == nil then - return va - elseif c == nil then - return va, get(componentIndex, record, b()) - elseif d == nil then - return va, get(componentIndex, record, b()), get(componentIndex, record, c()) - elseif e == nil then - return va, - get(componentIndex, record, b()), - get(componentIndex, record, c()), - get(componentIndex, record, d()) - else - error("args exceeded") - end -end - -function World.entity(world: World) - world.nextId += 1 - return world.nextId -end - -local nextId = 0 -local function component(): (data: T) -> () -> (number, T) - nextId += 1 - local id = nextId - return function(data) - return function() - return id, data - end - end -end - -function World.archetypesWith(world: World, componentId: i53) - local archetypes = world.archetypes - local archetypeMap = world.componentIndex[componentId] - local compatibleArchetypes = {} - for id, archetypeRecord in archetypeMap do - compatibleArchetypes[archetypes[id]] = true - end - return compatibleArchetypes -end - -function World.spawn(world: World, ...: () -> () -> (number, T)) - local entity = world:entity() - for i = 1, select("#", ...) do - local component = select(i, ...) - local componentId, data = component() - world:add(entity, componentId, data) - end - return entity -end - -function World.insert(world: World, entity: i53, ...: () -> (data: T) -> (number, T)) - for i = 1, select("#", ...) do - local component = select(i, ...) - local componentId, data = component() - world:add(entity, componentId, data) - end -end - - - - -function World.query(world: World, ...: () -> () -> i53): () -> (number, ...any) - local compatibleArchetypes = {} - local components = { ... } - local archetypes = world.archetypes - local queryLength = select("#", ...) - local a: any, b: any, c: any, d: any, e: any = ... - - if queryLength == 1 then - a = a()() - local archetypesMap = world.componentIndex[a] - components = { a } - local function single() - local id = next(archetypesMap) - local archetype = archetypes[id :: number] - local lastRow - - return function(): any - local row, entity = next(archetype.entities, lastRow) - while row == nil do - id = next(archetypesMap, id) - if id == nil then - return - end - archetype = archetypes[id] - row = next(archetype.entities, row) - end - lastRow = row - - return entity, archetype.columns[archetype.records[a]] - end - end - return single() - elseif queryLength == 2 then - a = a()() - b = b()() - components = { a, b } - local archetypesMap = world.componentIndex[a] - for id in archetypesMap do - local archetype = archetypes[id] - if archetype.records[b] then - table.insert(compatibleArchetypes, archetype) - end - end - - local function double(): any - local lastArchetype, archetype = next(compatibleArchetypes) - local lastRow - - return function(): any - local row = next(archetype.entities, lastRow) - while row == nil do - lastArchetype, archetype = next(compatibleArchetypes, lastArchetype) - if lastArchetype == nil then - return - end - row = next(archetype.entities, row) - end - lastRow = row - - local entity = archetype.entities[row::number] - local columns = archetype.columns - local archetypeRecords = archetype.records - return entity, columns[archetypeRecords[a]], columns[archetypeRecords[b]] - end - end - return double() - - elseif queryLength == 3 then - a = a()() - b = b()() - c = c()() - components = { a, b, c} - - elseif queryLength == 4 then - a = a()() - b = b()() - c = c()() - d = d()() - - components = { a, b, c, d } - - elseif queryLength == 5 then - a = a()() - b = b()() - c = c()() - d = d()() - e = e()() - components = {a,b,c,d,e} - else - for i, comp in components do - components[i] = comp()() :: any - end - end - - local firstArchetypeMap = world.componentIndex[components[1] :: any] - - for id in firstArchetypeMap do - local archetype = archetypes[id] - local archetypeRecords = archetype.records - local matched = true - for i, componentId in components do - if not archetypeRecords[componentId] then - matched = false - break - end - end - if matched then - table.insert(compatibleArchetypes, archetype) - end - end - - local lastArchetype, archetype = next(compatibleArchetypes) - - local lastRow - - local function queryNext(): (...any) - local row = next(archetype.entities, lastRow) - while row == nil do - lastArchetype, archetype = next(compatibleArchetypes, lastArchetype) - if lastArchetype == nil then - return - end - row = next(archetype.entities, row) - end - lastRow = row - - local columns = archetype.columns - local entityId = archetype.entities[row :: number] - local archetypeRecords = archetype.records - - if queryLength == 1 then - return entityId, columns[archetypeRecords[a]] - elseif queryLength == 2 then - return entityId, columns[archetypeRecords[a]], columns[archetypeRecords[b]] - elseif queryLength == 3 then - return entityId, - columns[archetypeRecords[a]], - columns[archetypeRecords[b]], - columns[archetypeRecords[c]] - elseif queryLength == 4 then - return entityId, - columns[archetypeRecords[a]], - columns[archetypeRecords[b]], - columns[archetypeRecords[c]], - columns[archetypeRecords[d]] - elseif queryLength == 5 then - return entityId, - columns[archetypeRecords[a]], - columns[archetypeRecords[b]], - columns[archetypeRecords[c]], - columns[archetypeRecords[d]], - columns[archetypeRecords[e]] - end - - local queryOutput = {} - for i, componentId in (components :: any) :: { number } do - queryOutput[i] = columns[archetypeRecords[componentId]] - end - - return entityId, unpack(queryOutput, 1, queryLength) - end - - return function() - -- consider this to be the iterator that gets invoked each iteration step - return queryNext() - end -end - -return { - World = World, - component = component -} \ No newline at end of file diff --git a/matterRewrite/init.spec.lua b/matterRewrite/init.spec.lua deleted file mode 100644 index 33f1447..0000000 --- a/matterRewrite/init.spec.lua +++ /dev/null @@ -1,62 +0,0 @@ -local Jecs = require(script.Parent) -local component = Jecs.component -local world = Jecs.World.new() - -local A, B, C, D = component(), component(), component(), component() -local E, F, G, H = component(), component(), component(), component() -print("A", A) -print("B", B) -print("C", C) -print("D", D) -print("E", E) -print("F", F) -print("G", G) -print("H", H) - -for i = 1, 256 do - world:spawn(A(true), B(true), C(true), D(true)) - - --[[ - ecs:set(entity, E, true) - ecs:set(entity, F, true) - ecs:set(entity, G, true) - ecs:set(entity, H, true) - print("end") - ]] -end - -return function() - describe("World", function() - it("should add component", function() - local id = world:spawn(A(true), B(1)) - - local id1 = world:spawn(A("hello")) - expect(world:get(id, A)).to.equal(true) - expect(world:get(id, B)).to.equal(1) - expect(world:get(id1, A)).to.equal("hello") - end) - it("should remove component", function() - local id = world:spawn(A(true), B(1000)) - world:remove(id, A) - - expect(world:get(id, A)).to.equal(nil) - end) - it("should override component data", function() - - local id = world:spawn(A(true)) - expect(world:get(id, A)).to.equal(true) - - world:insert(id, A(false)) - expect(world:get(id, A)).to.equal(false) - - end) - it("query", function() - local added = 0 - for e, a, b, c, d in world:query(A, B, C, D) do - added += 1 - end - expect(added).to.equal(256) - end) - - end) -end \ No newline at end of file