mirror of
https://github.com/Ukendio/jecs.git
synced 2025-06-20 08:19:18 +00:00
Fix line endings
This commit is contained in:
parent
bb03e88d3d
commit
b73bb0daee
21 changed files with 2102 additions and 2011 deletions
|
@ -4,66 +4,81 @@ local remotes = require("../remotes")
|
||||||
local collect = require("../collect")
|
local collect = require("../collect")
|
||||||
local client_ids = {}
|
local client_ids = {}
|
||||||
|
|
||||||
local function ecs_map_get(world: types.World, id: types.Entity)
|
|
||||||
|
local function ecs_map_get(world, id)
|
||||||
local deserialised_id = client_ids[id]
|
local deserialised_id = client_ids[id]
|
||||||
|
|
||||||
if not deserialised_id then
|
if not deserialised_id then
|
||||||
if world:has(id, jecs.Name) then
|
if world:has(id, jecs.Name) then
|
||||||
deserialised_id = world:entity(id)
|
deserialised_id = world:entity(id)
|
||||||
else
|
else
|
||||||
if world:exists(id) then
|
deserialised_id = world:entity()
|
||||||
deserialised_id = world:entity()
|
|
||||||
else
|
|
||||||
deserialised_id = world:entity(id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
client_ids[id] = deserialised_id
|
client_ids[id] = deserialised_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- local deserialised_id = client_ids[id]
|
||||||
|
-- if not deserialised_id then
|
||||||
|
-- if world:has(id, jecs.Name) then
|
||||||
|
-- deserialised_id = world:entity(id)
|
||||||
|
-- else
|
||||||
|
-- if world:exists(id) then
|
||||||
|
-- deserialised_id = world:entity()
|
||||||
|
-- else
|
||||||
|
-- deserialised_id = world:entity(id)
|
||||||
|
-- end
|
||||||
|
-- end
|
||||||
|
-- client_ids[id] = deserialised_id
|
||||||
|
-- end
|
||||||
|
|
||||||
return deserialised_id
|
return deserialised_id
|
||||||
end
|
end
|
||||||
|
|
||||||
local function ecs_make_alive_id(world: types.World, id: jecs.Id)
|
local function ecs_make_alive_id(world, id)
|
||||||
local rel = jecs.ECS_PAIR_FIRST(id)
|
local rel = jecs.ECS_PAIR_FIRST(id)
|
||||||
local tgt = jecs.ECS_PAIR_SECOND(id)
|
local tgt = jecs.ECS_PAIR_SECOND(id)
|
||||||
|
|
||||||
ecs_map_get(world, rel)
|
rel = ecs_map_get(world, rel)
|
||||||
ecs_map_get(world, tgt)
|
tgt = ecs_map_get(world, tgt)
|
||||||
|
|
||||||
|
return jecs.pair(rel, tgt)
|
||||||
end
|
end
|
||||||
|
|
||||||
local snapshots = collect(remotes.replication.OnClientEvent)
|
local snapshots = collect(remotes.replication.OnClientEvent)
|
||||||
|
|
||||||
return function(world: types.World)
|
return function(world: types.World)
|
||||||
return function()
|
for snapshot in snapshots do
|
||||||
for snapshot in snapshots do
|
for id, map in snapshot do
|
||||||
for key, map in snapshot do
|
id = tonumber(id)
|
||||||
local id = (tonumber(key) :: any) :: jecs.Id
|
if jecs.IS_PAIR(id) then
|
||||||
if jecs.IS_PAIR(id) then
|
id = ecs_make_alive_id(world, id)
|
||||||
ecs_make_alive_id(world, id)
|
end
|
||||||
end
|
|
||||||
|
|
||||||
local set = map.set
|
local set = map.set
|
||||||
if set then
|
if set then
|
||||||
if jecs.is_tag(world, id) then
|
if jecs.is_tag(world, id) then
|
||||||
for _, entity in set do
|
for _, entity in set do
|
||||||
entity = ecs_map_get(world, entity)
|
entity = ecs_map_get(world, entity)
|
||||||
world:add(entity, id)
|
world:add(entity, id)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local values = map.values :: { any }
|
local values = map.values
|
||||||
for i, entity in set do
|
for i, entity in set do
|
||||||
entity = ecs_map_get(world, entity)
|
entity = ecs_map_get(world, entity)
|
||||||
world:set(entity, id, values[i])
|
world:set(entity, id, values[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local removed = map.removed
|
local removed = map.removed
|
||||||
if removed then
|
|
||||||
for i, e in removed do
|
if removed then
|
||||||
if not world:contains(e) then
|
for i, e in removed do
|
||||||
continue
|
if not world:contains(e) then
|
||||||
end
|
continue
|
||||||
world:remove(e, id)
|
|
||||||
end
|
end
|
||||||
|
world:remove(e, id)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,5 +4,12 @@ local observers_add = require("../ReplicatedStorage/observers_add")
|
||||||
export type World = typeof(observers_add(jecs.world()))
|
export type World = typeof(observers_add(jecs.world()))
|
||||||
export type Entity = jecs.Entity
|
export type Entity = jecs.Entity
|
||||||
export type Id<T> = jecs.Id<T>
|
export type Id<T> = jecs.Id<T>
|
||||||
|
export type Snapshot = {
|
||||||
|
[string]: {
|
||||||
|
set: { jecs.Entity }?,
|
||||||
|
values: { any }?,
|
||||||
|
removed: { jecs.Entity }?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -3,102 +3,169 @@ local types = require("../../ReplicatedStorage/types")
|
||||||
local ct = require("../../ReplicatedStorage/components")
|
local ct = require("../../ReplicatedStorage/components")
|
||||||
local jecs = require(ReplicatedStorage.ecs)
|
local jecs = require(ReplicatedStorage.ecs)
|
||||||
local remotes = require("../../ReplicatedStorage/remotes")
|
local remotes = require("../../ReplicatedStorage/remotes")
|
||||||
|
local components = ct :: {[string]: jecs.Entity }
|
||||||
|
|
||||||
return function(world: types.World)
|
return function(world: ty.World)
|
||||||
local storages = {}
|
|
||||||
|
|
||||||
for component in world:query(ct.Networked) do
|
--- integration test
|
||||||
local is_tag = jecs.is_tag(world, component)
|
|
||||||
local storage = {} :: { [types.Entity]: any }
|
|
||||||
storages[component] = storage
|
|
||||||
|
|
||||||
if is_tag then
|
-- for _ = 1, 10 do
|
||||||
world:added(component, function(entity)
|
-- local e = world:entity()
|
||||||
storage[entity] = true
|
-- world:set(e, ct.TestA, true)
|
||||||
end)
|
-- end
|
||||||
else
|
|
||||||
world:added(component, function(entity, _, value)
|
local storages = {} :: { [jecs.Entity]: {[jecs.Entity]: any }}
|
||||||
storage[entity] = value
|
local networked_components = {}
|
||||||
end)
|
local networked_pairs = {}
|
||||||
world:changed(component, function(entity, _, value)
|
|
||||||
storage[entity] = value
|
for component in world:each(ct.Networked) do
|
||||||
end)
|
local name = world:get(component, jecs.Name) :: string
|
||||||
end
|
if components[name] == nil then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
storages[component] = {}
|
||||||
|
|
||||||
|
table.insert(networked_components, component)
|
||||||
|
end
|
||||||
|
|
||||||
|
for relation in world:each(ct.NetworkedPair) do
|
||||||
|
local name = world:get(relation, jecs.Name) :: string
|
||||||
|
if not components[name] then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
table.insert(networked_pairs, relation)
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, component in networked_components do
|
||||||
|
local name = world:get(component, jecs.Name) :: string
|
||||||
|
if not components[name] then
|
||||||
|
error(`Networked Component (%id{component}%name{name})`)
|
||||||
|
end
|
||||||
|
local is_tag = jecs.is_tag(world, component)
|
||||||
|
local storage = storages[component]
|
||||||
|
if is_tag then
|
||||||
|
world:added(component, function(entity)
|
||||||
|
storage[entity] = true
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
world:added(component, function(entity, _, value)
|
||||||
|
storage[entity] = value
|
||||||
|
end)
|
||||||
|
world:changed(component, function(entity, _, value)
|
||||||
|
storage[entity] = value
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
world:removed(component, function(entity)
|
world:removed(component, function(entity)
|
||||||
storage[entity] = "jecs.Remove"
|
storage[entity] = "jecs.Remove"
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
for relation in world:query(ct.NetworkedPair) do
|
for _, relation in networked_pairs do
|
||||||
world:added(relation, function(entity, id, value)
|
world:added(relation, function(entity, id, value)
|
||||||
local is_tag = jecs.is_tag(world, id)
|
local is_tag = jecs.is_tag(world, id)
|
||||||
local storage = storages[id]
|
local storage = storages[id]
|
||||||
if not storage then
|
if not storage then
|
||||||
storage = {}
|
storage = {}
|
||||||
storages[id] = storage
|
storages[id] = storage
|
||||||
end
|
end
|
||||||
if is_tag then
|
if is_tag then
|
||||||
storage[entity] = true
|
storage[entity] = true
|
||||||
else
|
else
|
||||||
storage[entity] = value
|
storage[entity] = value
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
world:changed(relation, function(entity, id, value)
|
world:changed(relation, function(entity, id, value)
|
||||||
local is_tag = jecs.is_tag(world, id)
|
local is_tag = jecs.is_tag(world, id)
|
||||||
if is_tag then
|
if is_tag then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local storage = storages[id]
|
local storage = storages[id]
|
||||||
if not storage then
|
if not storage then
|
||||||
storage = {}
|
storage = {}
|
||||||
storages[id] = storage
|
storages[id] = storage
|
||||||
end
|
end
|
||||||
|
|
||||||
storage[entity] = value
|
storage[entity] = value
|
||||||
end :: <T>(types.Entity, types.Id<T>, T) -> ())
|
end)
|
||||||
|
|
||||||
world:removed(relation, function(entity, id)
|
world:removed(relation, function(entity, id)
|
||||||
local storage = storages[id]
|
local storage = storages[id]
|
||||||
if not storage then
|
if not storage then
|
||||||
storage = {}
|
storage = {}
|
||||||
storages[id] = storage
|
storages[id] = storage
|
||||||
end
|
end
|
||||||
|
|
||||||
storage[entity] = "jecs.Remove"
|
storage[entity] = "jecs.Remove"
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local players_added = collect(Players.PlayerAdded)
|
||||||
|
|
||||||
return function()
|
return function()
|
||||||
local snapshot = {} :: {
|
local snapshot_lazy: ty.Snapshot
|
||||||
[string]: {
|
local set_ids_lazy: { jecs.Entity }
|
||||||
set: { types.Entity }?,
|
|
||||||
values: { any }?,
|
|
||||||
removed: { types.Entity }?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
local set_ids = {} :: { types.Entity }
|
for player in players_added do
|
||||||
local removed_ids = {} :: { types.Entity }
|
if not snapshot_lazy then
|
||||||
|
snapshot_lazy, set_ids_lazy = {}, {}
|
||||||
|
|
||||||
for component, storage in storages do
|
for component, storage in storages do
|
||||||
local set_values = {}
|
local set_values = {}
|
||||||
local set_n = 0
|
local set_n = 0
|
||||||
local removed_n = 0
|
|
||||||
for e, v in storage do
|
|
||||||
if v ~= "jecs.Remove" then
|
|
||||||
set_n += 1
|
|
||||||
set_ids[set_n] = e
|
|
||||||
set_values[set_n] = v or true
|
|
||||||
elseif world:contains(e) then
|
|
||||||
removed_n += 1
|
|
||||||
removed_ids[removed_n] = e
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
table.clear(storage)
|
local q = world:query(component)
|
||||||
|
local is_tag = jecs.is_tag(world, component)
|
||||||
|
for _, archetype in q:archetypes() do
|
||||||
|
local entities = archetype.entities
|
||||||
|
local entities_len = #entities
|
||||||
|
table.move(entities, 1, entities_len, set_n + 1, set_ids_lazy)
|
||||||
|
if is_tag then
|
||||||
|
set_values = table.create(entities_len, true)
|
||||||
|
else
|
||||||
|
local column = archetype.columns[archetype.records[component]]
|
||||||
|
table.move(column, 1, entities_len, set_n + 1, set_values)
|
||||||
|
end
|
||||||
|
|
||||||
|
set_n += entities_len
|
||||||
|
end
|
||||||
|
|
||||||
|
local set = table.move(set_ids_lazy, 1, set_n, 1, {})
|
||||||
|
|
||||||
|
snapshot_lazy[tostring(component)] = {
|
||||||
|
set = if set_n > 0 then set else nil,
|
||||||
|
values = if set_n > 0 then set_values else nil,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
remotes.replication:FireClient(player, snapshot_lazy)
|
||||||
|
end
|
||||||
|
|
||||||
|
local snapshot = {} :: ty.Snapshot
|
||||||
|
|
||||||
|
local set_ids = {}
|
||||||
|
local removed_ids = {}
|
||||||
|
|
||||||
|
for component, storage in storages do
|
||||||
|
local set_values = {} :: { any }
|
||||||
|
local set_n = 0
|
||||||
|
local removed_n = 0
|
||||||
|
for e, v in storage do
|
||||||
|
if v ~= "jecs.Remove" then
|
||||||
|
set_n += 1
|
||||||
|
set_ids[set_n] = e
|
||||||
|
set_values[set_n] = v or true
|
||||||
|
elseif not world:contains(e) then
|
||||||
|
removed_n += 1
|
||||||
|
removed_ids[removed_n] = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.clear(storage)
|
||||||
|
|
||||||
local dirty = false
|
local dirty = false
|
||||||
|
|
||||||
|
@ -107,14 +174,15 @@ return function(world: types.World)
|
||||||
end
|
end
|
||||||
|
|
||||||
if dirty then
|
if dirty then
|
||||||
|
local removed = table.move(removed_ids, 1, removed_n, 1, {}) :: { jecs.Entity }
|
||||||
|
local set = table.move(set_ids, 1, set_n, 1, {}) :: { jecs.Entity }
|
||||||
snapshot[tostring(component)] = {
|
snapshot[tostring(component)] = {
|
||||||
set = if set_n > 0 then table.move(set_ids, 1, set_n, 1, {}) else nil,
|
set = if set_n > 0 then set else nil,
|
||||||
values = if set_n > 0 then set_values else nil,
|
values = if set_n > 0 then set_values else nil,
|
||||||
removed = if removed_n > 0 then table.move(removed_ids, 1, removed_n, 1, {} :: { types.Entity }) else nil
|
removed = if removed_n > 0 then removed else nil
|
||||||
} :: any
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if next(snapshot) ~= nil then
|
if next(snapshot) ~= nil then
|
||||||
remotes.replication:FireAllClients(snapshot)
|
remotes.replication:FireAllClients(snapshot)
|
||||||
end
|
end
|
||||||
|
|
37
jecs.luau
37
jecs.luau
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
--!native
|
--!native
|
||||||
--!strict
|
--!strict
|
||||||
|
@ -117,6 +118,7 @@ local ECS_ID_MASK = 0b00
|
||||||
|
|
||||||
local ECS_ENTITY_MASK = bit32.lshift(1, 24)
|
local ECS_ENTITY_MASK = bit32.lshift(1, 24)
|
||||||
local ECS_GENERATION_MASK = bit32.lshift(1, 16)
|
local ECS_GENERATION_MASK = bit32.lshift(1, 16)
|
||||||
|
local ECS_PAIR_OFFSET = 2^48
|
||||||
|
|
||||||
local NULL_ARRAY = table.freeze({}) :: Column
|
local NULL_ARRAY = table.freeze({}) :: Column
|
||||||
local NULL = newproxy(false)
|
local NULL = newproxy(false)
|
||||||
|
@ -168,7 +170,6 @@ end
|
||||||
local function ECS_COMBINE(id: number, generation: number): i53
|
local function ECS_COMBINE(id: number, generation: number): i53
|
||||||
return id + (generation * ECS_ENTITY_MASK)
|
return id + (generation * ECS_ENTITY_MASK)
|
||||||
end
|
end
|
||||||
local ECS_PAIR_OFFSET = 2^48
|
|
||||||
|
|
||||||
local function ECS_IS_PAIR(e: number): boolean
|
local function ECS_IS_PAIR(e: number): boolean
|
||||||
return e > ECS_PAIR_OFFSET
|
return e > ECS_PAIR_OFFSET
|
||||||
|
@ -2576,40 +2577,40 @@ export type World = {
|
||||||
component: <T>(self: World) -> Entity<T>,
|
component: <T>(self: World) -> Entity<T>,
|
||||||
--- Gets the target of an relationship. For example, when a user calls
|
--- Gets the target of an relationship. For example, when a user calls
|
||||||
--- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity.
|
--- `world:target(id, ChildOf(parent), 0)`, you will obtain the parent entity.
|
||||||
target: <T>(self: World, id: Entity, relation: Id<T>, index: number?) -> Entity?,
|
target: <T, a>(self: World, id: Entity<T>, relation: Id<a>, index: number?) -> Entity?,
|
||||||
--- Deletes an entity and all it's related components and relationships.
|
--- Deletes an entity and all it's related components and relationships.
|
||||||
delete: (self: World, id: Entity) -> (),
|
delete: <T>(self: World, id: Entity<T>) -> (),
|
||||||
|
|
||||||
--- Adds a component to the entity with no value
|
--- Adds a component to the entity with no value
|
||||||
add: <T>(self: World, id: Entity, component: Id<T>) -> (),
|
add: <T, a>(self: World, id: Entity<T>, component: Id<a>) -> (),
|
||||||
--- Assigns a value to a component on the given entity
|
--- Assigns a value to a component on the given entity
|
||||||
set: <T>(self: World, id: Entity, component: Id<T>, data: T) -> (),
|
set: <T, a>(self: World, id: Entity<T>, component: Id<a>, data: a) -> (),
|
||||||
|
|
||||||
cleanup: (self: World) -> (),
|
cleanup: (self: World) -> (),
|
||||||
-- Clears an entity from the world
|
-- Clears an entity from the world
|
||||||
clear: <T>(self: World, id: Id<T>) -> (),
|
clear: <a>(self: World, id: Id<a>) -> (),
|
||||||
--- Removes a component from the given entity
|
--- Removes a component from the given entity
|
||||||
remove: <T>(self: World, id: Entity, component: Id<T>) -> (),
|
remove: <T, a>(self: World, id: Entity<T>, component: Id<a>) -> (),
|
||||||
--- Retrieves the value of up to 4 components. These values may be nil.
|
--- Retrieves the value of up to 4 components. These values may be nil.
|
||||||
get: (<A>(self: World, id: Entity, Id<A>) -> A?)
|
get: & (<T, a>(World, Entity<T>, Id<a>) -> a?)
|
||||||
& (<A, B>(self: World, id: Entity, Id<A>, Id<B>) -> (A?, B?))
|
& (<T, a, b>(World, Entity<T>, Id<a>, Id<b>) -> (a?, b?))
|
||||||
& (<A, B, C>(self: World, id: Entity, Id<A>, Id<B>, Id<C>) -> (A?, B?, C?))
|
& (<T, a, b, c>(World, Entity<T>, Id<a>, Id<b>, Id<c>) -> (a?, b?, c?))
|
||||||
& <A, B, C, D>(self: World, id: Entity, Id<A>, Id<B>, Id<C>, Id<D>) -> (A?, B?, C?, D?),
|
& (<T, a, b, c, d>(World, Entity<T>, Id<a>, Id<b>, Id<c>, Id<d>) -> (a?, b?, c?, d?)),
|
||||||
|
|
||||||
--- Returns whether the entity has the ID.
|
--- Returns whether the entity has the ID.
|
||||||
has: (<A>(World, Entity, A) -> boolean)
|
has: (<T>(World, Entity<T>, Id) -> boolean)
|
||||||
& (<A, B>(World, Entity, A, B) -> boolean)
|
& (<T>(World, Entity<T>, Id, Id) -> boolean)
|
||||||
& (<A, B, C>(World, Entity, A, B, C) -> boolean)
|
& (<T>(World, Entity<T>, Id, Id, Id) -> boolean)
|
||||||
& <A, B, C, D>(World, Entity, A, B, C, D) -> boolean,
|
& <T>(World, Entity<T>, Id, Id, Id, Id) -> boolean,
|
||||||
|
|
||||||
--- Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil.
|
--- Get parent (target of ChildOf relationship) for entity. If there is no ChildOf relationship pair, it will return nil.
|
||||||
parent:(self: World, entity: Entity) -> Entity,
|
parent: <T>(self: World, entity: Entity<T>) -> Entity,
|
||||||
|
|
||||||
--- Checks if the world contains the given entity
|
--- Checks if the world contains the given entity
|
||||||
contains:(self: World, entity: Entity) -> boolean,
|
contains: <T>(self: World, entity: Entity<T>) -> boolean,
|
||||||
|
|
||||||
--- Checks if the entity exists
|
--- Checks if the entity exists
|
||||||
exists: (self: World, entity: Entity) -> boolean,
|
exists: <T>(self: World, entity: Entity<T>) -> boolean,
|
||||||
|
|
||||||
each: <T>(self: World, id: Id<T>) -> () -> Entity,
|
each: <T>(self: World, id: Id<T>) -> () -> Entity,
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue