fix: Bugs + temp push for bugfixing
This commit is contained in:
parent
88ca58df9b
commit
d34edf8d70
21 changed files with 2317 additions and 73 deletions
|
@ -5,7 +5,7 @@
|
||||||
"current": {
|
"current": {
|
||||||
"name": "path",
|
"name": "path",
|
||||||
"sources": {
|
"sources": {
|
||||||
"@pkg": "Packages/"
|
"@jecs": "lib/jecs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
|
|
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
|
@ -66,6 +66,13 @@ jobs:
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run Unit Tests
|
||||||
run: |
|
run: |
|
||||||
lune run test/runner.luau
|
output=$(luau test/tests.luau)
|
||||||
|
echo "$output"
|
||||||
|
if [[ "$output" == *"0 fails"* ]]; then
|
||||||
|
echo "Unit Tests Passed"
|
||||||
|
else
|
||||||
|
echo "Error: One or More Unit Tests Failed."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
3
.luaurc
3
.luaurc
|
@ -2,6 +2,7 @@
|
||||||
"languageMode": "strict",
|
"languageMode": "strict",
|
||||||
"aliases": {
|
"aliases": {
|
||||||
"jecs_utils": "lib",
|
"jecs_utils": "lib",
|
||||||
"testkit": "test/testkit"
|
"testkit": "test/testkit",
|
||||||
|
"jecs": "lib/jecs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ local function start_process(cmd: string)
|
||||||
process.spawn(command, arguments, { stdio = "forward" })
|
process.spawn(command, arguments, { stdio = "forward" })
|
||||||
end
|
end
|
||||||
|
|
||||||
start_process("lune run install-packages.luau")
|
--start_process("lune run install-packages.luau")
|
||||||
--start_process("curl -O https://raw.githubusercontent.com/JohnnyMorganz/luau-lsp/main/scripts/globalTypes.d.luau")
|
--start_process("curl -O https://raw.githubusercontent.com/JohnnyMorganz/luau-lsp/main/scripts/globalTypes.d.luau")
|
||||||
start_process("rojo sourcemap dev.project.json -o sourcemap.json")
|
start_process("rojo sourcemap dev.project.json -o sourcemap.json")
|
||||||
start_process(
|
start_process(
|
||||||
"luau-lsp analyze --base-luaurc=.luaurc --sourcemap=sourcemap.json --settings=luau_lsp_settings.json --no-strict-dm-types --ignore Packages/**/*.lua --ignore Packages/**/*.luau lib/"
|
"luau-lsp analyze --base-luaurc=.luaurc --sourcemap=sourcemap.json --settings=luau_lsp_settings.json --no-strict-dm-types --ignore Packages/**/*.lua --ignore Packages/**/*.luau --ignore lib/jecs.luau lib/"
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,3 +12,4 @@ end
|
||||||
start_process("lune run analyze")
|
start_process("lune run analyze")
|
||||||
start_process("stylua lib/")
|
start_process("stylua lib/")
|
||||||
start_process("selene lib/")
|
start_process("selene lib/")
|
||||||
|
start_process("luau test/tests.luau")
|
||||||
|
|
|
@ -21,10 +21,8 @@
|
||||||
"mode": "relativeToFile",
|
"mode": "relativeToFile",
|
||||||
"fileAliases": {
|
"fileAliases": {
|
||||||
"@jecs_utils": "lib",
|
"@jecs_utils": "lib",
|
||||||
|
"@jecs": "lib/jecs",
|
||||||
"@testkit": "test/testkit"
|
"@testkit": "test/testkit"
|
||||||
},
|
|
||||||
"directoryAliases": {
|
|
||||||
"@pkg": "Packages/"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
"ReplicatedStorage": {
|
"ReplicatedStorage": {
|
||||||
"Packages": {
|
"Packages": {
|
||||||
"$path": "Packages",
|
"$className": "Folder",
|
||||||
"jecs_utils": {
|
"jecs_utils": {
|
||||||
"$path": "lib"
|
"$path": "lib"
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,9 @@ local function collect<D, T...>(event: signal_like<D, T...>): (() -> (number, T.
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local disconnect = event:Connect(function(...)
|
local connect = event.Connect or event.connect
|
||||||
|
assert(connect ~= nil, "Signal is missing a Connect function - is it really a signal?")
|
||||||
|
local disconnect = connect(event, function(...)
|
||||||
table.insert(storage, { ... })
|
table.insert(storage, { ... })
|
||||||
mt.__iter = iter :: any
|
mt.__iter = iter :: any
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
--!strict
|
--!strict
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
local jecs = require("@pkg/jecs")
|
local jecs = require("./jecs")
|
||||||
type entity<T = nil> = jecs.Entity<T>
|
type entity<T = nil> = jecs.Entity<T>
|
||||||
type id<T = nil> = jecs.Id<T>
|
type id<T = nil> = jecs.Id<T>
|
||||||
|
|
||||||
local world = require("./world").get()
|
local WORLD = require("./world").get
|
||||||
|
|
||||||
--- `map<component_id, array<entity_id>>`
|
--- `map<component_id, array<entity_id>>`
|
||||||
local add_commands: { [id]: { entity } } = {}
|
local add_commands: { [id]: { entity } } = {}
|
||||||
|
@ -15,7 +15,7 @@ local remove_commands: { [id]: { entity } } = {}
|
||||||
--- `array<entity_id>`
|
--- `array<entity_id>`
|
||||||
local delete_commands: { entity } = {}
|
local delete_commands: { entity } = {}
|
||||||
|
|
||||||
type command_buffer = {
|
export type command_buffer = {
|
||||||
--- Execute all buffered commands and clear the buffer
|
--- Execute all buffered commands and clear the buffer
|
||||||
flush: () -> (),
|
flush: () -> (),
|
||||||
|
|
||||||
|
@ -30,48 +30,46 @@ type command_buffer = {
|
||||||
}
|
}
|
||||||
|
|
||||||
local function flush()
|
local function flush()
|
||||||
local adds = add_commands
|
local world = WORLD()
|
||||||
local sets = set_commands
|
|
||||||
local removes = remove_commands
|
for _, entity in delete_commands do
|
||||||
local deletes = delete_commands
|
world:delete(entity)
|
||||||
|
end
|
||||||
|
|
||||||
|
for component, entities in add_commands do
|
||||||
|
for _, entity in entities do
|
||||||
|
if delete_commands[entity] then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
world:add(entity, component)
|
||||||
|
end
|
||||||
|
end
|
||||||
table.clear(add_commands)
|
table.clear(add_commands)
|
||||||
|
|
||||||
|
for component, entities in set_commands do
|
||||||
|
for entity, value in entities do
|
||||||
|
if delete_commands[entity] then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
world:set(entity, component, value)
|
||||||
|
end
|
||||||
|
end
|
||||||
table.clear(set_commands)
|
table.clear(set_commands)
|
||||||
|
|
||||||
|
for component, entities in remove_commands do
|
||||||
|
for _, entity in entities do
|
||||||
|
if delete_commands[entity] then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
|
||||||
|
world:remove(entity, component)
|
||||||
|
end
|
||||||
|
end
|
||||||
table.clear(remove_commands)
|
table.clear(remove_commands)
|
||||||
|
|
||||||
table.clear(delete_commands)
|
table.clear(delete_commands)
|
||||||
|
|
||||||
for _, id in deletes do
|
|
||||||
world:delete(id)
|
|
||||||
end
|
|
||||||
|
|
||||||
for component, ids in adds do
|
|
||||||
for _, id in ids do
|
|
||||||
if deletes[id] then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
world:add(id, component)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for component, ids in sets do
|
|
||||||
for id, value in ids do
|
|
||||||
if deletes[id] then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
world:set(id, component, value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for component, ids in removes do
|
|
||||||
for _, id in ids do
|
|
||||||
if deletes[id] then
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
world:remove(id, component)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function add(entity: entity, component: id)
|
local function add(entity: entity, component: id)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
--!strict
|
--!strict
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
local jecs = require("@pkg/jecs")
|
local jecs = require("./jecs")
|
||||||
export type entity<T = nil> = jecs.Entity<T>
|
type entity<T = nil> = jecs.Entity<T>
|
||||||
export type id<T = nil> = entity<T> | jecs.Pair
|
type id<T = nil> = entity<T> | jecs.Pair
|
||||||
|
|
||||||
local world = require("./world").get()
|
local world = require("./world").get
|
||||||
|
|
||||||
type interface = {
|
type interface = {
|
||||||
__index: interface,
|
__index: interface,
|
||||||
|
@ -44,34 +44,34 @@ function handle.new(entity: entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
function handle:has(...: id): boolean
|
function handle:has(...: id): boolean
|
||||||
return world:has(self.entity, ...)
|
return world():has(self.entity, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
handle.get = function(self: handle, a: id, b: id?, c: id?, d: id?)
|
handle.get = function(self: handle, a: id, b: id?, c: id?, d: id?)
|
||||||
return world:get(self.entity, a, b :: any, c :: any, d :: any)
|
return world():get(self.entity, a, b :: any, c :: any, d :: any)
|
||||||
end :: any
|
end :: any
|
||||||
|
|
||||||
function handle:add<T>(id: id<T>): handle
|
function handle:add<T>(id: id<T>): handle
|
||||||
world:add(self.entity, id)
|
world():add(self.entity, id)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function handle:set<T>(id: id<T>, value: T): handle
|
function handle:set<T>(id: id<T>, value: T): handle
|
||||||
world:set(self.entity, id, value)
|
world():set(self.entity, id, value)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function handle:remove(id: id): handle
|
function handle:remove(id: id): handle
|
||||||
world:remove(self.entity, id)
|
world():remove(self.entity, id)
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function handle:delete()
|
function handle:delete()
|
||||||
world:delete(self.entity)
|
world():delete(self.entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
function handle:id(): entity
|
function handle:id(): entity
|
||||||
return self.entity
|
return self.entity
|
||||||
end
|
end
|
||||||
|
|
||||||
return handle
|
return handle.new
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
--!strict
|
--!strict
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
|
local jecs = require("./jecs")
|
||||||
|
|
||||||
local WORLD = require("./world")
|
local WORLD = require("./world")
|
||||||
local collect = require("./collect")
|
local collect = require("./collect")
|
||||||
|
export type collect_signal_like<T...> = collect.signal_like<any, T...>
|
||||||
|
export type collect_verbose_signal_like<D, T...> = collect.signal_like<D, T...>
|
||||||
local command_buffer = require("./command_buffer")
|
local command_buffer = require("./command_buffer")
|
||||||
|
export type command_buffer = command_buffer.command_buffer
|
||||||
local handle = require("./handle")
|
local handle = require("./handle")
|
||||||
local jecs = require("@pkg/jecs")
|
export type handle = handle.handle
|
||||||
local ref = require("./ref")
|
local ref = require("./ref")
|
||||||
local replicator = require("./replicator")
|
local replicator = require("./replicator")
|
||||||
|
export type replicator = replicator.replicator
|
||||||
|
export type changes = replicator.changes
|
||||||
|
|
||||||
--- Set the world for all utilities.
|
--- Set the world for all utilities.
|
||||||
--- Should be called once per context before any utility is used.
|
--- Should be called once per context before any utility is used.
|
||||||
|
|
1895
lib/jecs.luau
Normal file
1895
lib/jecs.luau
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
||||||
--!strict
|
--!strict
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
local handle = require("./handle")
|
local handle = require("./handle")
|
||||||
local world = require("./world").get()
|
local WORLD = require("./world").get
|
||||||
|
|
||||||
local refs = {}
|
local refs = {}
|
||||||
|
|
||||||
|
@ -11,8 +11,9 @@ local refs = {}
|
||||||
--- @param key any
|
--- @param key any
|
||||||
--- @return handle
|
--- @return handle
|
||||||
local function ref(key: any): handle.handle
|
local function ref(key: any): handle.handle
|
||||||
|
local world = WORLD()
|
||||||
if not key then
|
if not key then
|
||||||
return handle.new(world:entity())
|
return handle(world:entity())
|
||||||
end
|
end
|
||||||
|
|
||||||
local entity = refs[key]
|
local entity = refs[key]
|
||||||
|
@ -21,7 +22,7 @@ local function ref(key: any): handle.handle
|
||||||
refs[key] = entity
|
refs[key] = entity
|
||||||
end
|
end
|
||||||
|
|
||||||
return handle.new(entity)
|
return handle(entity)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ref
|
return ref
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
--!strict
|
--!strict
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
local jecs = require("@pkg/jecs")
|
local jecs = require("./jecs")
|
||||||
type entity<T = nil> = jecs.Entity<T>
|
type entity<T = nil> = jecs.Entity<T>
|
||||||
type i53 = number
|
type i53 = number
|
||||||
|
|
||||||
local ref = require("./ref")
|
local ref = require("./ref")
|
||||||
local world = require("./world").get()
|
local WORLD = require("./world").get
|
||||||
|
|
||||||
--- A replicator keeps track of all entities with the passed components and their values -
|
--- A replicator keeps track of all entities with the passed components and their values -
|
||||||
--- whenever a component is changed (add, change, remove) and the replicator listens to it, it's also changed within the contained raw data.\
|
--- whenever a component is changed (add, change, remove) and the replicator listens to it, it's also changed within the contained raw data.\
|
||||||
|
@ -122,6 +122,7 @@ export type changes = {
|
||||||
--- @param ... entity
|
--- @param ... entity
|
||||||
--- @return replicator
|
--- @return replicator
|
||||||
local function replicator(...: entity): replicator
|
local function replicator(...: entity): replicator
|
||||||
|
local world = WORLD()
|
||||||
local components = { ... }
|
local components = { ... }
|
||||||
|
|
||||||
-- don't index a changes table start
|
-- don't index a changes table start
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
--!strict
|
--!strict
|
||||||
--!optimize 2
|
--!optimize 2
|
||||||
local jecs = require("@pkg/jecs")
|
local jecs = require("./jecs")
|
||||||
|
|
||||||
local WORLD: jecs.World
|
local WORLD: jecs.World
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"LuauTinyControlFlowAnalysis": "true"
|
"LuauTinyControlFlowAnalysis": "true"
|
||||||
},
|
},
|
||||||
"luau-lsp.require.mode": "relativeToFile",
|
"luau-lsp.require.mode": "relativeToFile",
|
||||||
"luau-lsp.require.directoryAliases": {
|
"luau-lsp.require.fileAliases": {
|
||||||
"@pkg": "Packages/"
|
"@jecs": "lib/jecs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
std = "selene_definitions"
|
std = "selene_definitions"
|
||||||
|
exclude = ["lib/jecs.luau"]
|
||||||
|
|
96
test/signal.luau
Normal file
96
test/signal.luau
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
-- licensed under MIT
|
||||||
|
-- @author jackdotink
|
||||||
|
-- https://github.com/red-blox/Util/blob/main/libs/Signal/Signal.luau
|
||||||
|
-- adapted to work in pure luau
|
||||||
|
|
||||||
|
type node<T...> = {
|
||||||
|
next: node<T...>?,
|
||||||
|
callback: (T...) -> (),
|
||||||
|
}
|
||||||
|
|
||||||
|
export type signal<T...> = {
|
||||||
|
root: node<T...>?,
|
||||||
|
|
||||||
|
connect: (self: signal<T...>, Callback: (T...) -> ()) -> () -> (),
|
||||||
|
wait: (self: signal<T...>) -> T...,
|
||||||
|
once: (self: signal<T...>, Callback: (T...) -> ()) -> () -> (),
|
||||||
|
fire: (self: signal<T...>, T...) -> (),
|
||||||
|
disconnect_all: (self: signal<T...>) -> (),
|
||||||
|
}
|
||||||
|
|
||||||
|
local Signal = {}
|
||||||
|
Signal.__index = Signal
|
||||||
|
|
||||||
|
-- Extracted this function from Connect as it results in the closure
|
||||||
|
-- made in Connect using less memory because this function can be static
|
||||||
|
local function disconnect<T...>(self: signal<T...>, Node: node<T...>)
|
||||||
|
if self.root == Node then
|
||||||
|
self.root = Node.next
|
||||||
|
else
|
||||||
|
local Current = self.root
|
||||||
|
|
||||||
|
while Current do
|
||||||
|
if Current.next == Node then
|
||||||
|
Current.next = Node.next
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
Current = Current.next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.connect<T...>(self: signal<T...>, Callback: (T...) -> ()): () -> ()
|
||||||
|
local node = {
|
||||||
|
next = self.root,
|
||||||
|
callback = Callback,
|
||||||
|
}
|
||||||
|
|
||||||
|
self.root = node
|
||||||
|
|
||||||
|
return function()
|
||||||
|
disconnect(self, node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.wait<T...>(self: signal<T...>): T...
|
||||||
|
local Thread = coroutine.running()
|
||||||
|
local Disconnect
|
||||||
|
|
||||||
|
Disconnect = self:connect(function(...)
|
||||||
|
Disconnect()
|
||||||
|
coroutine.resume(Thread, ...)
|
||||||
|
end)
|
||||||
|
|
||||||
|
return coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.once<T...>(self: signal<T...>, Callback: (T...) -> ()): () -> ()
|
||||||
|
local Disconnect
|
||||||
|
|
||||||
|
Disconnect = self:connect(function(...)
|
||||||
|
Disconnect()
|
||||||
|
Callback(...)
|
||||||
|
end)
|
||||||
|
|
||||||
|
return Disconnect
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.fire<T...>(self: signal<T...>, ...: T...)
|
||||||
|
local Current = self.root
|
||||||
|
|
||||||
|
while Current do
|
||||||
|
Current.callback(...)
|
||||||
|
Current = Current.next
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Signal.disconnect_all<T...>(self: signal<T...>)
|
||||||
|
self.root = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return function<T...>(): signal<T...>
|
||||||
|
return setmetatable({
|
||||||
|
root = nil,
|
||||||
|
}, Signal) :: any
|
||||||
|
end
|
237
test/tests.luau
Normal file
237
test/tests.luau
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
--!strict
|
||||||
|
-- stylua: ignore start
|
||||||
|
local jecs = require("@jecs")
|
||||||
|
local jecs_utils = require("@jecs_utils")
|
||||||
|
local testkit = require("@testkit")
|
||||||
|
|
||||||
|
local collect = jecs_utils.collect
|
||||||
|
local handle = jecs_utils.handle
|
||||||
|
local replicator = jecs_utils.replicator
|
||||||
|
local ref = jecs_utils.ref
|
||||||
|
local command_buffer = jecs_utils.command_buffer
|
||||||
|
|
||||||
|
local signal = require("./signal")
|
||||||
|
|
||||||
|
local BENCH, START = testkit.benchmark()
|
||||||
|
|
||||||
|
local TEST, CASE, CHECK, FINISH, SKIP, FOCUS = testkit.test()
|
||||||
|
|
||||||
|
TEST("jecs_utils.collect()", function()
|
||||||
|
do CASE "collects"
|
||||||
|
local sig: signal.signal<number> = signal()
|
||||||
|
local flush = collect(sig)
|
||||||
|
local should = {}
|
||||||
|
|
||||||
|
for idx = 100, 1, -1 do
|
||||||
|
local n = math.random()
|
||||||
|
should[idx] = n
|
||||||
|
sig:fire(n)
|
||||||
|
end
|
||||||
|
|
||||||
|
for idx, n in flush do
|
||||||
|
CHECK(should[idx] == n)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
TEST("jecs_utils.handle()", function()
|
||||||
|
do CASE "has"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
local tag = world:entity()
|
||||||
|
|
||||||
|
world:add(entity, tag)
|
||||||
|
CHECK(handle(entity):has(tag))
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "get"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
local component = world:component()
|
||||||
|
|
||||||
|
world:set(entity, component, 50)
|
||||||
|
CHECK(handle(entity):get(component) == 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "add"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
local tag = world:entity()
|
||||||
|
|
||||||
|
handle(entity):add(tag)
|
||||||
|
CHECK(world:has(entity, tag))
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "set"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
local component = world:component()
|
||||||
|
|
||||||
|
handle(entity):set(component, 50)
|
||||||
|
CHECK(world:get(entity, component) == 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "remove"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
local component = world:component()
|
||||||
|
|
||||||
|
handle(entity):set(component, 50)
|
||||||
|
CHECK(world:get(entity, component) == 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "delete"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
handle(entity):delete()
|
||||||
|
CHECK(not world:contains(entity))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
TEST("jecs_utils.ref()", function()
|
||||||
|
do CASE "ref(abc) == ref(abc)"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local a: number = ref(1234):id()
|
||||||
|
local b: number = ref(1234):id()
|
||||||
|
CHECK(a == b)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
TEST("jecs_utils.replicator()", function()
|
||||||
|
do CASE "propagates difference"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
local tag = world:entity()
|
||||||
|
local component: jecs.Entity<number> = world:component()
|
||||||
|
|
||||||
|
local entity1 = world:entity()
|
||||||
|
local entity2 = world:entity()
|
||||||
|
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
local rep = replicator(component, tag)
|
||||||
|
|
||||||
|
world:add(entity1, tag)
|
||||||
|
world:set(entity2, component, 50)
|
||||||
|
|
||||||
|
local difference: jecs_utils.changes = rep.calculate_difference() :: any
|
||||||
|
CHECK(difference ~= nil)
|
||||||
|
|
||||||
|
local world2 = jecs.World.new()
|
||||||
|
local component2: jecs.Entity<number> = world2:component()
|
||||||
|
local tag2 = world2:entity()
|
||||||
|
|
||||||
|
jecs_utils.initialize(world2)
|
||||||
|
local rep2 = replicator(component2, tag2)
|
||||||
|
|
||||||
|
rep2.apply_difference(difference)
|
||||||
|
|
||||||
|
CHECK(ref(`replicated-{entity1}`):has(tag2))
|
||||||
|
CHECK(ref(`replicated-{entity2}`):get(component2) == 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "propagates full data"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
local tag = world:entity()
|
||||||
|
local component: jecs.Entity<number> = world:component()
|
||||||
|
|
||||||
|
local entity1 = world:entity()
|
||||||
|
local entity2 = world:entity()
|
||||||
|
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
local rep = replicator(component, tag)
|
||||||
|
|
||||||
|
world:add(entity1, tag)
|
||||||
|
world:set(entity2, component, 50)
|
||||||
|
|
||||||
|
local full_data = rep.get_full_data()
|
||||||
|
CHECK(full_data ~= nil)
|
||||||
|
|
||||||
|
local world2 = jecs.World.new()
|
||||||
|
local component2: jecs.Entity<number> = world2:component()
|
||||||
|
local tag2 = world2:entity()
|
||||||
|
|
||||||
|
jecs_utils.initialize(world2)
|
||||||
|
local rep2 = replicator(component2, tag2)
|
||||||
|
|
||||||
|
rep2.apply_difference(full_data)
|
||||||
|
|
||||||
|
CHECK(ref(`replicated-{entity1}`):has(tag2))
|
||||||
|
CHECK(ref(`replicated-{entity2}`):get(component2) == 50)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
TEST("jecs_utils.command_buffer", function()
|
||||||
|
do CASE "add"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local tag = world:entity()
|
||||||
|
local entity = world:entity()
|
||||||
|
command_buffer.add(entity, tag)
|
||||||
|
|
||||||
|
CHECK(not world:has(entity, tag))
|
||||||
|
|
||||||
|
command_buffer.flush()
|
||||||
|
|
||||||
|
CHECK(world:has(entity, tag))
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "set"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local component = world:component()
|
||||||
|
local entity = world:entity()
|
||||||
|
command_buffer.set(entity, component, 50)
|
||||||
|
|
||||||
|
CHECK(not world:has(entity, component))
|
||||||
|
|
||||||
|
command_buffer.flush()
|
||||||
|
|
||||||
|
CHECK(world:get(entity, component) == 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "remove"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local component = world:component()
|
||||||
|
local entity = world:entity()
|
||||||
|
world:set(entity, component, 50)
|
||||||
|
command_buffer.remove(entity, component)
|
||||||
|
|
||||||
|
CHECK(world:has(entity, component))
|
||||||
|
|
||||||
|
command_buffer.flush()
|
||||||
|
|
||||||
|
CHECK(not world:has(entity, component))
|
||||||
|
end
|
||||||
|
|
||||||
|
do CASE "delete"
|
||||||
|
local world = jecs.World.new()
|
||||||
|
jecs_utils.initialize(world)
|
||||||
|
|
||||||
|
local entity = world:entity()
|
||||||
|
command_buffer.delete(entity)
|
||||||
|
|
||||||
|
command_buffer.flush()
|
||||||
|
|
||||||
|
CHECK(not world:contains(entity))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
FINISH()
|
||||||
|
-- stylua: ignore end
|
|
@ -15,4 +15,3 @@ include = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
jecs = "ukendio/jecs@0.2.10"
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue