Compare commits

..

No commits in common. "0064f249247cbf5f80cf3e33ff1dcc16df1a6357" and "1d1b7b099aa0bd798ca0d6f6cb7d8c6354c12cf7" have entirely different histories.

6 changed files with 49 additions and 220 deletions

View file

@ -1,67 +0,0 @@
--!optimize 2
--!native
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local jecs = require(ReplicatedStorage.ecs)
local __ = jecs.Wildcard
local std = ReplicatedStorage.std
local world = require(std.world)
local Position = world:component() :: jecs.Entity<vector>
local Previous = jecs.Rest
local pre = jecs.pair(Position, Previous)
local added = world
:query(Position)
:without(pre)
:cached()
local changed = world
:query(Position, pre)
:cached()
local removed = world
:query(pre)
:without(Position)
:cached()
local children = {}
for i = 1, 10 do
local e = world:entity()
world:set(e, Position, vector.create(i, i, i))
table.insert(children, e)
end
local function flip()
return math.random() > 0.5
end
local function system()
for i, child in children do
world:set(child, Position, vector.create(i,i,i))
end
for e, p in added:iter() do
world:set(e, pre, p)
end
for i, child in children do
if flip() then
world:set(child, Position, vector.create(i + 1, i + 1, i + 1))
end
end
for e, new, old in changed:iter() do
if new ~= old then
world:set(e, pre, new)
end
end
for i, child in children do
world:remove(child, Position)
end
for e in removed:iter() do
world:remove(e, pre)
end
end
local scheduler = require(std.scheduler)
scheduler.SYSTEM(system)
return 0

View file

@ -1,90 +0,0 @@
--!optimize 2
--!native
--!strict
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local jecs = require(ReplicatedStorage.ecs)
local __ = jecs.Wildcard
local std = ReplicatedStorage.std
local world = require(std.world)
local Position = world:component() :: jecs.Entity<vector>
local Previous = jecs.Rest
local pre = jecs.pair(Position, Previous)
local added = world
:query(Position)
:without(pre)
:cached()
local changed = world
:query(Position, pre)
:cached()
local removed = world
:query(pre)
:without(Position)
:cached()
local children = {}
for i = 1, 10 do
local e = world:entity()
world:set(e, Position, vector.create(i, i, i))
table.insert(children, e)
end
local function flip()
return math.random() > 0.5
end
local entity_index = world.entity_index
local function copy(archetypes, id)
for _, archetype in archetypes do
local to = jecs.archetype_traverse_add(world, pre, archetype)
local columns = to.columns
local records = to.records
local old = columns[records[pre].column]
local new = columns[records[id].column]
if to ~= archetype then
for _, entity in archetype.entities do
local r = jecs.entity_index_try_get_fast(entity_index, entity)
jecs.entity_move(entity_index, entity, r, to)
end
end
table.move(new, 1, #new, 1, old)
end
end
local function system2()
for i, child in children do
world:set(child, Position, vector.create(i,i,i))
end
for e, p in added:iter() do
end
copy(added:archetypes(), Position)
for i, child in children do
if flip() then
world:set(child, Position, vector.create(i + 1, i + 1, i + 1))
end
end
for e, new, old in changed:iter() do
if new ~= old then
end
end
copy(changed:archetypes(), Position)
for i, child in children do
world:remove(child, Position)
end
for e in removed:iter() do
world:remove(e, pre)
end
end
local scheduler = require(std.scheduler)
scheduler.SYSTEM(system2)
return 0

View file

@ -9,23 +9,15 @@ local cts = require(std.components)
local Model = cts.Model local Model = cts.Model
local Transform = cts.Transform local Transform = cts.Transform
local moved_models = world:query(Model, Transform):cached() local moving_models = world:query(Transform, Model):cached()
local updated_models = {}
local i = 0
local function processed(n)
i += 1
if i > n then
i = 0
return true
end
return false
end
local function move(dt: number) local function move(dt: number)
for entity, model in moved_models do for _, transform, model in moving_models do
if updated_models[entity] then local cf = transform.new
updated_models[entity] = nil if cf ~= transform.old then
model.PrimaryPart.CFrame = transform local part = model.PrimaryPart :: BasePart
local origo = part.CFrame
part.CFrame = origo:Lerp(cf, 1)
transform.old = cf
end end
end end
end end
@ -33,8 +25,11 @@ end
local function syncTransforms() local function syncTransforms()
for _, id, cf in blink.UpdateTransform.Iter() do for _, id, cf in blink.UpdateTransform.Iter() do
local e = ref("server-" .. tostring(id)) local e = ref("server-" .. tostring(id))
world:set(e, Transform, cf) local transform = world:get(e, Transform)
moved_models[e] = true if not transform then
continue
end
transform.new = cf
end end
end end
@ -43,4 +38,4 @@ local scheduler = require(std.scheduler)
scheduler.SYSTEM(move) scheduler.SYSTEM(move)
scheduler.SYSTEM(syncTransforms) scheduler.SYSTEM(syncTransforms)
return 0 return 0

View file

@ -1,5 +1,4 @@
local jecs = require("@jecs") local jecs = require("@jecs")
local pair = jecs.pair
local world = jecs.World.new() local world = jecs.World.new()
local Name = world:component() local Name = world:component()
@ -13,37 +12,39 @@ local function name(e)
return world:get(e, Name) return world:get(e, Name)
end end
local Position = named(world.component, "Position") :: jecs.Entity<vector> local Position = named(world.component, "Position") :: jecs.Entity<Vector3>
local Previous = jecs.Rest local Previous = jecs.Rest
local PreviousPosition = jecs.pair(Previous, Position)
local added = world local added = world
:query(Position) :query(Position)
:without(pair(Previous, Position)) :without(PreviousPosition)
:cached() :cached()
local changed = world local changed = world
:query(Position, pair(Previous, Position)) :query(Position, PreviousPosition)
:cached() :cached()
local removed = world local removed = world
:query(pair(Previous, Position)) :query(PreviousPosition)
:without(Position) :without(Position)
:cached() :cached()
local e1 = named(world.entity, "e1") local e1 = named(world.entity, "e1")
world:set(e1, Position, vector.create(10, 20, 30)) world:set(e1, Position, Vector3.new(10, 20, 30))
local e2 = named(world.entity, "e2") local e2 = named(world.entity, "e2")
world:set(e2, Position, vector.create(10, 20, 30)) world:set(e2, Position, Vector3.new(10, 20, 30))
for entity, p in added do
print(`Added {name(entity)}: \{{p.x}, {p.y}, {p.z}}`) for e, p in added:iter() do
world:set(entity, pair(Previous, Position), p) print(`Added {e}: \{{p.X}, {p.Y}, {p.Z}}`)
world:set(e, PreviousPosition, p)
end end
world:set(e1, Position, vector.create(999, 999, 1998)) world:set(e1, Position, "")
for _, archetype in changed:archetypes() do for e, new, old in changed:iter() do
if new ~= old then if new ~= old then
print(`{name(e)}'s Position changed from \{{old.x}, {old.y}, {old.z}\} to \{{new.x}, {new.y}, {new.z}\}`) print(`{name(new)}'s Position changed from \{{old.X}, {old.Y}, {old.Z}\} to \{{new.X}, {new.Y}, {new.Z}\}`)
world:set(e, pair(Previous, Position), new) world:set(e, PreviousPosition, new)
end end
end end
@ -51,7 +52,6 @@ world:remove(e2, Position)
for e in removed:iter() do for e in removed:iter() do
print(`Position was removed from {name(e)}`) print(`Position was removed from {name(e)}`)
world:remove(e, pair(Previous, Position))
end end
-- Output: -- Output:

View file

@ -1144,9 +1144,6 @@ do
end end
end end
local sparse_array = entity_index.sparse_array
local dense_array = entity_index.dense_array
if idr_t then if idr_t then
for archetype_id in idr_t.cache do for archetype_id in idr_t.cache do
local children = {} local children = {}
@ -1177,14 +1174,24 @@ do
else else
local on_remove = id_record.hooks.on_remove local on_remove = id_record.hooks.on_remove
local to = archetype_traverse_remove(world, id, idr_t_archetype) local to = archetype_traverse_remove(world, id, idr_t_archetype)
local empty = #to.types == 0 if on_remove then
for i = n, 1, -1 do if to then
local child = children[i] for i = n, 1, -1 do
if on_remove then local child = children[i]
on_remove(child) on_remove(children[i])
local r = entity_index_try_get_fast(entity_index, child) :: Record
entity_move(entity_index, child, r, to)
end
else
for i = n, 1, -1 do
local child = children[i]
on_remove(child)
end
end end
local r = sparse_array[ECS_ENTITY_T_LO(child)] elseif to then
if not empty then for i = n, 1, -1 do
local child = children[i]
local r = entity_index_try_get_fast(entity_index, child) :: Record
entity_move(entity_index, child, r, to) entity_move(entity_index, child, r, to)
end end
end end
@ -1196,6 +1203,7 @@ do
end end
end end
local dense_array = entity_index.dense_array
local index_of_deleted_entity = record.dense local index_of_deleted_entity = record.dense
local index_of_last_alive_entity = entity_index.alive_count local index_of_last_alive_entity = entity_index.alive_count
entity_index.alive_count = index_of_last_alive_entity - 1 entity_index.alive_count = index_of_last_alive_entity - 1
@ -2188,7 +2196,7 @@ function World.new()
return self return self
end end
export type Entity<T = unknown> = {__T: T} export type Entity<T = nil> = number & { __T: T }
export type Id<T = nil> = export type Id<T = nil> =
| Entity<T> | Entity<T>
@ -2354,8 +2362,6 @@ return {
archetype_traverse_add = archetype_traverse_add, archetype_traverse_add = archetype_traverse_add,
archetype_traverse_remove = archetype_traverse_remove, archetype_traverse_remove = archetype_traverse_remove,
entity_move = entity_move,
entity_index_try_get = entity_index_try_get, entity_index_try_get = entity_index_try_get,
entity_index_try_get_any = entity_index_try_get_any, entity_index_try_get_any = entity_index_try_get_any,
entity_index_try_get_fast = entity_index_try_get_fast, entity_index_try_get_fast = entity_index_try_get_fast,

View file

@ -1045,21 +1045,6 @@ TEST("world:component()", function()
end) end)
TEST("world:delete", function() TEST("world:delete", function()
do CASE "delete recycled entity id used as component"
local world = world_new()
local id = world:entity()
world:add(id, jecs.Component)
local e = world:entity()
world:set(e, id, 1)
CHECK(world:get(e, id) == 1)
world:delete(id)
local recycled = world:entity()
world:add(recycled, jecs.Component)
world:set(e, recycled, 1)
CHECK(world:has(recycled, jecs.Component))
CHECK(world:get(e, recycled) == 1)
end
do do
CASE("bug: Empty entity does not respect cleanup policy") CASE("bug: Empty entity does not respect cleanup policy")
local world = world_new() local world = world_new()