This commit is contained in:
HowManySmall 2024-05-04 14:10:59 -06:00
parent cda04ce5a9
commit b3f8e2504e
8 changed files with 19491 additions and 178 deletions

2
.gitignore vendored
View file

@ -50,3 +50,5 @@ WallyPatches
roblox.toml roblox.toml
sourcemap.json sourcemap.json
drafts/*.lua drafts/*.lua
*.code-workspace

73
lib/Types.luau Normal file
View file

@ -0,0 +1,73 @@
--!native
--!optimize 2
--!strict
export type i53 = number
export type i24 = number
export type Ty = {i53}
export type ArchetypeId = number
export type Column = {any}
export type Archetype = {
id: number,
edges: {
[i24]: {
add: Archetype,
remove: Archetype,
},
},
types: Ty,
type: string | number,
entities: {number},
columns: {Column},
records: {},
}
export type Record = {
archetype: Archetype,
row: number,
}
export type EntityIndex = {[i24]: Record}
export type ComponentIndex = {[i24]: ArchetypeMap}
export type ArchetypeRecord = number
export type ArchetypeMap = {sparse: {[ArchetypeId]: ArchetypeRecord}, size: number}
export type Archetypes = {[ArchetypeId]: Archetype}
export type ArchetypeDiff = {
added: Ty,
removed: Ty,
}
export type Hook = {
ids: Ty,
archetype: Archetype,
otherArchetype: Archetype,
offset: number,
}
export type EventDescription = Hook & {
event: number,
}
export type World = {
archetypeIndex: {[number | string]: Archetype},
archetypes: {[number]: Archetype},
componentIndex: {[i24]: ArchetypeMap},
entityIndex: {[i53]: Record},
hooks: {[number]: {Hook}},
nextComponentId: number,
nextEntityId: number,
ROOT_ARCHETYPE: Archetype,
get: (self: World) -> (),
}
export type WorldStatic = {
new: () -> World,
}
return false

View file

@ -3,45 +3,29 @@
--!strict --!strict
--draft 4 --draft 4
type i53 = number local Types = require(script.Types)
type i24 = number
type Ty = { i53 } type i53 = Types.i53
type ArchetypeId = number type i24 = Types.i24
type Column = { any } type Ty = Types.Ty
type ArchetypeId = Types.ArchetypeId
type Archetype = { type Column = Types.Column
id: number,
edges: {
[i24]: {
add: Archetype,
remove: Archetype,
},
},
types: Ty,
type: string | number,
entities: { number },
columns: { Column },
records: {},
}
type Record = { type Archetype = Types.Archetype
archetype: Archetype, type Record = Types.Record
row: number,
}
type EntityIndex = { [i24]: Record } type EntityIndex = Types.EntityIndex
type ComponentIndex = { [i24]: ArchetypeMap} type ComponentIndex = Types.ComponentIndex
type ArchetypeRecord = number type ArchetypeRecord = Types.ArchetypeRecord
type ArchetypeMap = { sparse: { [ArchetypeId]: ArchetypeRecord } , size: number } type ArchetypeMap = Types.ArchetypeMap
type Archetypes = { [ArchetypeId]: Archetype } type Archetypes = Types.Archetypes
type ArchetypeDiff = { type ArchetypeDiff = Types.ArchetypeDiff
added: Ty,
removed: Ty, -- type World = Types.World
}
local HI_COMPONENT_ID = 256 local HI_COMPONENT_ID = 256
local ON_ADD = HI_COMPONENT_ID + 1 local ON_ADD = HI_COMPONENT_ID + 1
@ -152,13 +136,13 @@ local function archetypeOf(world: World, types: { i24 }, prev: Archetype?): Arch
end end
local archetype = { local archetype = {
id = id, id = id;
types = types, types = types;
type = ty, type = ty;
columns = columns, columns = columns;
entities = {}, entities = {};
edges = {}, edges = {};
records = {}, records = {};
} }
world.archetypeIndex[ty] = archetype world.archetypeIndex[ty] = archetype
world.archetypes[id] = archetype world.archetypes[id] = archetype
@ -173,17 +157,17 @@ local World = {}
World.__index = World World.__index = World
function World.new() function World.new()
local self = setmetatable({ local self = setmetatable({
entityIndex = {}, entityIndex = {};
componentIndex = {}, componentIndex = {};
archetypes = {}, archetypes = {};
archetypeIndex = {}, archetypeIndex = {};
ROOT_ARCHETYPE = (nil :: any) :: Archetype, ROOT_ARCHETYPE = (nil :: any) :: Archetype;
nextEntityId = 0, nextEntityId = 0;
nextComponentId = 0, nextComponentId = 0;
nextArchetypeId = 0, nextArchetypeId = 0;
hooks = { hooks = {
[ON_ADD] = {} [ON_ADD] = {};
} };
}, World) }, World)
return self return self
end end
@ -192,21 +176,21 @@ local function emit(world, eventDescription)
local event = eventDescription.event local event = eventDescription.event
table.insert(world.hooks[event], { table.insert(world.hooks[event], {
ids = eventDescription.ids, ids = eventDescription.ids;
archetype = eventDescription.archetype, archetype = eventDescription.archetype;
otherArchetype = eventDescription.otherArchetype, otherArchetype = eventDescription.otherArchetype;
offset = eventDescription.offset offset = eventDescription.offset;
}) })
end end
local function onNotifyAdd(world, archetype, otherArchetype, row: number, added: Ty) local function onNotifyAdd(world, archetype, otherArchetype, row: number, added: Ty)
if #added > 0 then if #added > 0 then
emit(world, { emit(world, {
event = ON_ADD, event = ON_ADD;
ids = added, ids = added;
archetype = archetype, archetype = archetype;
otherArchetype = otherArchetype, otherArchetype = otherArchetype;
offset = row, offset = row;
}) })
end end
end end
@ -326,7 +310,6 @@ local function archetypeTraverseRemove(world: World, componentId: i53, archetype
local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype local from = (archetype or world.ROOT_ARCHETYPE) :: Archetype
local edge = ensureEdge(from, componentId) local edge = ensureEdge(from, componentId)
if not edge.remove then if not edge.remove then
local to = table.clone(from.types) local to = table.clone(from.types)
table.remove(to, table.find(to, componentId)) table.remove(to, table.find(to, componentId))
@ -347,7 +330,7 @@ function World.remove(world: World, entityId: i53, componentId: i53)
end end
-- Keeping the function as small as possible to enable inlining -- Keeping the function as small as possible to enable inlining
local function get(componentIndex: { [i24]: ArchetypeMap }, record: Record, componentId: i24) local function get(componentIndex: {[i24]: ArchetypeMap}, record: Record, componentId: i24): number?
local archetype = record.archetype local archetype = record.archetype
local archetypeRecord = archetype.records[componentId] local archetypeRecord = archetype.records[componentId]
@ -382,13 +365,12 @@ function World.get(world: World, entityId: i53, a: i53, b: i53?, c: i53?, d: i53
end end
local function noop(self: Query, ...: i53): () -> (number, ...any) local function noop(self: Query, ...: i53): () -> (number, ...any)
return function() return function() end :: any
end :: any
end end
local EmptyQuery = { local EmptyQuery = {
__iter = noop, __iter = noop;
without = noop without = noop;
} }
EmptyQuery.__index = EmptyQuery EmptyQuery.__index = EmptyQuery
setmetatable(EmptyQuery, EmptyQuery) setmetatable(EmptyQuery, EmptyQuery)
@ -475,7 +457,6 @@ function World.query(world: World, ...: i53): Query
local lastRow local lastRow
local queryOutput = {} local queryOutput = {}
function preparedQuery:__iter() function preparedQuery:__iter()
return function() return function()
local archetype = compatibleArchetype[1] local archetype = compatibleArchetype[1]
@ -499,16 +480,9 @@ function World.query(world: World, ...: i53): Query
elseif queryLength == 2 then elseif queryLength == 2 then
return entityId, columns[tr[1]][row], columns[tr[2]][row] return entityId, columns[tr[1]][row], columns[tr[2]][row]
elseif queryLength == 3 then elseif queryLength == 3 then
return entityId, return entityId, columns[tr[1]][row], columns[tr[2]][row], columns[tr[3]][row]
columns[tr[1]][row],
columns[tr[2]][row],
columns[tr[3]][row]
elseif queryLength == 4 then elseif queryLength == 4 then
return entityId, return entityId, columns[tr[1]][row], columns[tr[2]][row], columns[tr[3]][row], columns[tr[4]][row]
columns[tr[1]][row],
columns[tr[2]][row],
columns[tr[3]][row],
columns[tr[4]][row]
elseif queryLength == 5 then elseif queryLength == 5 then
return entityId, return entityId,
columns[tr[1]][row], columns[tr[1]][row],
@ -628,13 +602,13 @@ function World.observer(world: World, ...)
return archetype.entities[row], unpack(queryOutput, 1, #queryOutput) return archetype.entities[row], unpack(queryOutput, 1, #queryOutput)
end end
end end;
} }
end end
return table.freeze({ return table.freeze({
World = World, World = World;
ON_ADD = ON_ADD, ON_ADD = ON_ADD;
ON_REMOVE = ON_REMOVE, ON_REMOVE = ON_REMOVE;
ON_SET = ON_SET ON_SET = ON_SET;
}) })

19255
roblox.yml Normal file

File diff suppressed because it is too large Load diff

4
selene.toml Normal file
View file

@ -0,0 +1,4 @@
std = "roblox"
[lints]
global_usage = "allow"

5
stylua.toml Normal file
View file

@ -0,0 +1,5 @@
column_width = 120
quote_style = "ForceDouble"
[sort_requires]
enabled = true

3
testez-companion.toml Normal file
View file

@ -0,0 +1,3 @@
roots = ["ServerStorage"]
[extraOptions]

View file

@ -10,6 +10,3 @@ include = ["default.project.json", "lib", "wally.toml", "README.md"]
TestEZ = "roblox/testez@0.4.1" TestEZ = "roblox/testez@0.4.1"
Matter = "matter-ecs/matter@0.8.0" Matter = "matter-ecs/matter@0.8.0"
ecr = "centau/ecr@0.8.0" ecr = "centau/ecr@0.8.0"