10 Commits
v1.6.0 ... dev

Author SHA1 Message Date
BlackMATov
d9c9b4cf85 v1.7.0 2026-01-11 21:16:36 +07:00
BlackMATov
20c94a0b72 Merge branch 'feature/variants' into dev 2026-01-11 21:11:45 +07:00
BlackMATov
e396c320ee update readme and teal defs (VARIANTS fragment) 2026-01-11 21:08:22 +07:00
BlackMATov
52c898f912 rename eithers to variants 2026-01-11 20:49:09 +07:00
BlackMATov
a5319351c1 first eithers impl 2026-01-11 20:33:17 +07:00
BlackMATov
c9f4a74518 dummy eithers fragment 2026-01-06 20:23:22 +07:00
BlackMATov
c29092c3e1 update embedded xpcall.lua to v1.0.1 2026-01-04 09:32:08 +07:00
BlackMATov
a0a4a20c35 Happy New Year! 🥳 2026-01-03 15:52:01 +07:00
BlackMATov
2f8b0b0ef3 Merge branch 'feature/process_with' into dev
https://github.com/BlackMATov/evolved.lua/issues/34
2026-01-03 15:48:40 +07:00
BlackMATov
5e0170b4e8 new evolved.process_with function impl 2026-01-03 15:42:59 +07:00
9 changed files with 790 additions and 113 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (C) 2024-2025, by Matvey Cherevko (blackmatov@gmail.com)
Copyright (C) 2024-2026, by Matvey Cherevko (blackmatov@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -43,6 +43,7 @@
- [Deferred Operations](#deferred-operations)
- [Batch Operations](#batch-operations)
- [Systems](#systems)
- [Processing Payloads](#processing-payloads)
- [Predefined Traits](#predefined-traits)
- [Fragment Tags](#fragment-tags)
- [Fragment Hooks](#fragment-hooks)
@@ -60,6 +61,7 @@
- [Chunk](#chunk)
- [Builder](#builder)
- [Changelog](#changelog)
- [v1.7.0](#v170)
- [v1.6.0](#v160)
- [v1.5.0](#v150)
- [v1.4.0](#v140)
@@ -586,16 +588,22 @@ evolved.set(entity, fragment, 42)
One of the most important features of any ECS library is the ability to process entities by filters or queries. `evolved.lua` provides a simple and efficient way to do this.
First, you need to create a query that describes which entities you want to process. You can specify fragments you want to include, and fragments you want to exclude. Queries are just identifiers with a special predefined fragments: [`evolved.INCLUDES`](#evolvedincludes) and [`evolved.EXCLUDES`](#evolvedexcludes). These fragments expect a list of fragments as their components.
First, you need to create a query that describes which entities you want to process. You can specify fragments you want to include, and fragments you want to exclude. Queries are just identifiers with a special predefined fragments: [`evolved.INCLUDES`](#evolvedincludes), [`evolved.EXCLUDES`](#evolvedexcludes), and [`evolved.VARIANTS`](#evolvedvariants). These fragments expect a list of fragments as their components.
- [`evolved.INCLUDES`](#evolvedincludes) is used to specify fragments that must be present in the entity;
- [`evolved.EXCLUDES`](#evolvedexcludes) is used to specify fragments that must not be present in the entity;
- [`evolved.VARIANTS`](#evolvedvariants) is used to specify fragments where at least one must be present in the entity.
```lua
local evolved = require 'evolved'
local health, poisoned, resistant = evolved.id(3)
local alive, undead = evolved.id(2)
local query = evolved.id()
evolved.set(query, evolved.INCLUDES, { health, poisoned })
evolved.set(query, evolved.EXCLUDES, { resistant })
evolved.set(query, evolved.VARIANTS, { alive, undead })
```
The builder interface can be used to create queries too. It is more convenient to use, because the builder has special methods for including and excluding fragments. Here is a simple example of this:
@@ -604,10 +612,11 @@ The builder interface can be used to create queries too. It is more convenient t
local query = evolved.builder()
:include(health, poisoned)
:exclude(resistant)
:variant(alive, undead)
:build()
```
We don't have to set both [`evolved.INCLUDES`](#evolvedincludes) and [`evolved.EXCLUDES`](#evolvedexcludes) fragments, we can even do it without filters at all, then the query will match all chunks in the world.
We don't have to set all of [`evolved.INCLUDES`](#evolvedincludes), [`evolved.EXCLUDES`](#evolvedexcludes), and [`evolved.VARIANTS`](#evolvedvariants) fragments, we can even do it without filters at all, then the query will match all chunks in the world.
After the query is created, we are ready to process our filtered by this query entities. You can do this by using the [`evolved.execute`](#evolvedexecute) function. This function takes a query as an argument and returns an iterator that can be used to iterate over all matching with the query chunks.
@@ -786,7 +795,7 @@ The [`evolved.process`](#evolvedprocess) function is used to process systems. It
function evolved.process(...) end
```
If you don't specify a query for the system, the system itself will be treated as a query. This means the system can contain `evolved.INCLUDES` and `evolved.EXCLUDES` fragments, and it will be processed according to them. This is useful for creating systems with unique queries that don't need to be reused in other systems.
If you don't specify a query for the system, the system itself will be treated as a query. This means the system can contain `evolved.INCLUDES`, `evolved.EXCLUDES`, and `evolved.VARIANTS` fragments, and it will be processed according to them. This is useful for creating systems with unique queries that don't need to be reused in other systems.
```lua
local evolved = require 'evolved'
@@ -880,6 +889,43 @@ The prologue and epilogue fragments do not require an explicit query. They will
> [!NOTE]
> And one more thing about systems. Execution callbacks are called in the [deferred scope](#deferred-operations), which means that all modifying operations inside the callback will be queued and applied after the system has processed all chunks. But prologue and epilogue callbacks are not called in the deferred scope, so all modifying operations inside them will be applied immediately. This is done to avoid confusion and to make it clear that prologue and epilogue callbacks are not part of the chunk processing.
#### Processing Payloads
Additionally, systems can have a payload that will be passed to the execution, prologue, and epilogue callbacks. This is useful for passing additional data to the system without using global variables or closures.
```lua
---@param system evolved.system
---@param ... any processing payload
function evolved.process_with(system, ...) end
```
The [`evolved.process_with`](#evolvedprocess_with) function is similar to the [`evolved.process`](#evolvedprocess) function, but it takes a processing payload as additional arguments. These arguments will be passed to the system's callbacks.
```lua
local evolved = require 'evolved'
local position_x, position_y = evolved.id(2)
local velocity_x, velocity_y = evolved.id(2)
local physics_system = evolved.builder()
:include(position_x, position_y)
:include(velocity_x, velocity_y)
:execute(function(chunk, entity_list, entity_count, delta_time)
local px, py = chunk:components(position_x, position_y)
local vx, vy = chunk:components(velocity_x, velocity_y)
for i = 1, entity_count do
px[i] = px[i] + vx[i] * delta_time
py[i] = py[i] + vy[i] * delta_time
end
end):build()
local delta_time = 0.016
evolved.process_with(physics_system, delta_time)
```
`delta_time` in this example is passed as a processing payload to the system's execution callback. Payloads can be of any type and can be multiple values. Also, payloads are passed to prologue and epilogue callbacks if they are defined. Every subsystem in a group will receive the same payload when the group is processed with [`evolved.process_with`](#evolvedprocess_with).
### Predefined Traits
#### Fragment Tags
@@ -1125,9 +1171,9 @@ storage :: component[]
default :: component
duplicate :: {component -> component}
execute :: {chunk, entity[], integer}
prologue :: {}
epilogue :: {}
execute :: {chunk, entity[], integer, any...}
prologue :: {any...}
epilogue :: {any...}
set_hook :: {entity, fragment, component, component}
assign_hook :: {entity, fragment, component, component}
@@ -1159,6 +1205,7 @@ DISABLED :: fragment
INCLUDES :: fragment
EXCLUDES :: fragment
VARIANTS :: fragment
REQUIRES :: fragment
ON_SET :: fragment
@@ -1229,6 +1276,7 @@ execute :: query -> {execute_state? -> chunk?, entity[]?, integer?}, execute_sta
locate :: entity -> chunk?, integer
process :: system... -> ()
process_with :: system, ... -> ()
debug_mode :: boolean -> ()
collect_garbage :: ()
@@ -1292,6 +1340,7 @@ builder_mt:disabled :: builder
builder_mt:include :: fragment... -> builder
builder_mt:exclude :: fragment... -> builder
builder_mt:variant :: fragment... -> builder
builder_mt:require :: fragment... -> builder
builder_mt:on_set :: {entity, fragment, component, component} -> builder
@@ -1302,16 +1351,21 @@ builder_mt:on_remove :: {entity, fragment} -> builder
builder_mt:group :: system -> builder
builder_mt:query :: query -> builder
builder_mt:execute :: {chunk, entity[], integer} -> builder
builder_mt:execute :: {chunk, entity[], integer, any...} -> builder
builder_mt:prologue :: {} -> builder
builder_mt:epilogue :: {} -> builder
builder_mt:prologue :: {any...} -> builder
builder_mt:epilogue :: {any...} -> builder
builder_mt:destruction_policy :: id -> builder
```
## Changelog
### v1.7.0
- Added the new [`evolved.VARIANTS`](#evolvedvariants) query fragment that allows specifying any of multiple fragments in queries
- Added the new [`evolved.process_with`](#evolvedprocess_with) function that allows passing payloads to processing systems
### v1.6.0
- Significant performance improvements of the [`evolved.REQUIRES`](#evolvedrequires) fragment trait
@@ -1384,6 +1438,8 @@ builder_mt:destruction_policy :: id -> builder
### `evolved.EXCLUDES`
### `evolved.VARIANTS`
### `evolved.REQUIRES`
### `evolved.ON_SET`
@@ -1710,6 +1766,14 @@ function evolved.locate(entity) end
function evolved.process(...) end
```
### `evolved.process_with`
```lua
---@param system evolved.system
---@param ... any processing payload
function evolved.process_with(system, ...) end
```
### `evolved.debug_mode`
```lua
@@ -2013,6 +2077,14 @@ function evolved.builder_mt:include(...) end
function evolved.builder_mt:exclude(...) end
```
#### `evolved.builder_mt:variant`
```lua
---@param ... evolved.fragment fragments
---@return evolved.builder builder
function evolved.builder_mt:variant(...) end
```
### `evolved.builder_mt:require`
```lua

View File

@@ -7,6 +7,7 @@ require 'develop.testing.locate_tests'
require 'develop.testing.main_tests'
require 'develop.testing.multi_spawn_tests'
require 'develop.testing.name_tests'
require 'develop.testing.process_with_tests'
require 'develop.testing.requires_fragment_tests'
require 'develop.testing.spawn_tests'
require 'develop.testing.system_as_query_tests'

View File

@@ -56,6 +56,20 @@ local function generate_query(query)
end
end
local variant_set = {}
local variant_list = {}
local variant_count = 0
for _ = 1, math.random(0, #all_fragment_list) do
local variant = all_fragment_list[math.random(1, #all_fragment_list)]
if not variant_set[variant] then
variant_count = variant_count + 1
variant_set[variant] = variant_count
variant_list[variant_count] = variant
end
end
if include_count > 0 then
evo.set(query, evo.INCLUDES, include_list)
end
@@ -63,6 +77,10 @@ local function generate_query(query)
if exclude_count > 0 then
evo.set(query, evo.EXCLUDES, exclude_list)
end
if variant_count > 0 then
evo.set(query, evo.VARIANTS, variant_list)
end
end
---@param query_count integer
@@ -173,12 +191,22 @@ local function execute_query(query)
local query_include_list = evo.get(query, evo.INCLUDES) or {}
local query_exclude_list = evo.get(query, evo.EXCLUDES) or {}
local query_variant_list = evo.get(query, evo.VARIANTS) or {}
local query_include_count = #query_include_list
local query_exclude_count = #query_exclude_list
local query_variant_count = #query_variant_list
local query_include_set = {}
for _, include in ipairs(query_include_list) do
query_include_set[include] = true
end
local query_variant_set = {}
for _, variant in ipairs(query_variant_list) do
query_variant_set[variant] = true
end
for chunk, entity_list, entity_count in evo.execute(query) do
assert(not query_chunk_set[chunk])
query_chunk_set[chunk] = true
@@ -189,19 +217,29 @@ local function execute_query(query)
query_entity_set[entity] = true
end
assert(chunk:has_all(__table_unpack(query_include_list)))
assert(not chunk:has_any(__table_unpack(query_exclude_list)))
if query_include_count > 0 then
assert(chunk:has_all(__table_unpack(query_include_list)))
end
if query_exclude_count > 0 then
assert(not chunk:has_any(__table_unpack(query_exclude_list)))
end
if query_variant_count > 0 then
assert(chunk:has_any(__table_unpack(query_variant_list)))
end
end
for i = 1, all_entity_count do
local entity = all_entity_list[i]
local is_entity_matched =
evo.has_all(entity, __table_unpack(query_include_list))
and not evo.has_any(entity, __table_unpack(query_exclude_list))
(query_variant_count == 0 or evo.has_any(entity, __table_unpack(query_variant_list))) and
(query_include_count == 0 or evo.has_all(entity, __table_unpack(query_include_list))) and
(query_exclude_count == 0 or not evo.has_any(entity, __table_unpack(query_exclude_list)))
for fragment in evo.each(entity) do
if evo.has(fragment, evo.EXPLICIT) and not query_include_set[fragment] then
if evo.has(fragment, evo.EXPLICIT) and not query_variant_set[fragment] and not query_include_set[fragment] then
is_entity_matched = false
end
end
@@ -236,10 +274,13 @@ for _ = 1, math.random(1, 5) do
if math.random(1, 2) == 1 then
generate_query(query)
else
if math.random(1, 2) == 1 then
local r = math.random(1, 3)
if r == 1 then
evo.remove(query, evo.INCLUDES)
else
elseif r == 2 then
evo.remove(query, evo.EXCLUDES)
else
evo.remove(query, evo.VARIANTS)
end
end
end

View File

@@ -0,0 +1,107 @@
local evo = require 'evolved'
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local s = evo.builder()
:include(f)
:prologue(function(payload1, payload2, payload3)
assert(payload1 == 11 and payload2 == 22 and payload3 == 33)
end)
:execute(function(chunk, entity_list, entity_count, payload1, payload2, payload3)
assert(payload1 == 11 and payload2 == 22 and payload3 == 33)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(payload1, payload2, payload3)
assert(payload1 == 11 and payload2 == 22 and payload3 == 33)
end)
:spawn()
evo.process_with(s, 11, 22, 33)
end
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local s = evo.builder()
:include(f)
:prologue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == 42 and payload3 == nil)
end)
:execute(function(chunk, entity_list, entity_count, payload1, payload2, payload3)
assert(payload1 == nil and payload2 == 42 and payload3 == nil)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == 42 and payload3 == nil)
end)
:spawn()
evo.process_with(s, nil, 42)
end
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local s = evo.builder()
:include(f)
:prologue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == nil and payload3 == nil)
end)
:execute(function(chunk, entity_list, entity_count, payload1, payload2, payload3)
assert(payload1 == nil and payload2 == nil and payload3 == nil)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(payload1, payload2, payload3)
assert(payload1 == nil and payload2 == nil and payload3 == nil)
end)
:spawn()
evo.process_with(s)
end
do
local f = evo.id()
local e = evo.builder():set(f, 42):spawn()
local prologue_sum, execute_sum, epilogue_sum = 0, 0, 0
local function sum(...)
local s = 0
for i = 1, select('#', ...) do
s = s + select(i, ...)
end
return s
end
local function iota(n)
if n == 0 then return end
return n, iota(n - 1)
end
local s = evo.builder()
:include(f)
:prologue(function(...)
prologue_sum = prologue_sum + sum(...)
end)
:execute(function(chunk, entity_list, entity_count, ...)
execute_sum = execute_sum + sum(...)
assert(chunk == evo.chunk(f) and entity_count == 1 and entity_list[1] == e)
end)
:epilogue(function(...)
epilogue_sum = epilogue_sum + sum(...)
end)
:spawn()
for n = 0, 50 do
prologue_sum, execute_sum, epilogue_sum = 0, 0, 0
evo.process_with(s, iota(n))
local expect_sum = (n * (n + 1)) / 2
assert(prologue_sum == expect_sum)
assert(execute_sum == expect_sum)
assert(epilogue_sum == expect_sum)
end
end

View File

@@ -69,6 +69,7 @@
include: function(self: Builder, ...: Fragment): Builder
exclude: function(self: Builder, ...: Fragment): Builder
variant: function(self: Builder, ...: Fragment): Builder
require: function(self: Builder, ...: Fragment): Builder
on_set: function<Component>(self: Builder, on_set: function(Entity, Fragment, ? Component, ? Component)): Builder
@@ -79,10 +80,10 @@
group: function(self: Builder, group: System): Builder
query: function(self: Builder, query: Query): Builder
execute: function(self: Builder, execute: function(Chunk, {Entity}, integer)): Builder
execute: function(self: Builder, execute: function(Chunk, {Entity}, integer, ...: any)): Builder
prologue: function(self: Builder, prologue: function()): Builder
epilogue: function(self: Builder, epilogue: function()): Builder
prologue: function(self: Builder, prologue: function(...: any)): Builder
epilogue: function(self: Builder, epilogue: function(...: any)): Builder
destruction_policy: function(self: Builder, destruction_policy: Id): Builder
end
@@ -102,6 +103,7 @@
INCLUDES: Fragment
EXCLUDES: Fragment
VARIANTS: Fragment
REQUIRES: Fragment
ON_SET: Fragment
@@ -171,6 +173,7 @@
locate: function(entity: Entity): Chunk | nil, integer
process: function(...: System)
process_with: function(system: System, ...: any)
debug_mode: function(yesno: boolean)
collect_garbage: function()

View File

@@ -1,11 +1,11 @@
local evolved = {
__HOMEPAGE = 'https://github.com/BlackMATov/evolved.lua',
__DESCRIPTION = 'Evolved ECS (Entity-Component-System) for Lua',
__VERSION = '1.6.0',
__VERSION = '1.7.0',
__LICENSE = [[
MIT License
Copyright (C) 2024-2025, by Matvey Cherevko (blackmatov@gmail.com)
Copyright (C) 2024-2026, by Matvey Cherevko (blackmatov@gmail.com)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -43,10 +43,11 @@ local evolved = {
---@alias evolved.execute fun(
--- chunk: evolved.chunk,
--- entity_list: evolved.entity[],
--- entity_count: integer)
--- entity_count: integer,
--- ...: any)
---@alias evolved.prologue fun()
---@alias evolved.epilogue fun()
---@alias evolved.prologue fun(...: any)
---@alias evolved.epilogue fun(...: any)
---@alias evolved.set_hook fun(
--- entity: evolved.entity,
@@ -80,7 +81,9 @@ local evolved = {
---@field package [1] integer structural_changes
---@field package [2] evolved.chunk[] chunk_stack
---@field package [3] integer chunk_stack_size
---@field package [4] table<evolved.fragment, integer>? exclude_set
---@field package [4] table<evolved.fragment, integer>? include_set
---@field package [5] table<evolved.fragment, integer>? exclude_set
---@field package [6] table<evolved.fragment, integer>? variant_set
---@alias evolved.each_iterator fun(
--- state: evolved.each_state?):
@@ -134,6 +137,7 @@ local __entity_places = {} ---@type table<integer, integer>
local __sorted_includes = {} ---@type table<evolved.query, evolved.assoc_list<evolved.fragment>>
local __sorted_excludes = {} ---@type table<evolved.query, evolved.assoc_list<evolved.fragment>>
local __sorted_variants = {} ---@type table<evolved.query, evolved.assoc_list<evolved.fragment>>
local __sorted_requires = {} ---@type table<evolved.fragment, evolved.assoc_list<evolved.fragment>>
local __subsystem_groups = {} ---@type table<evolved.system, evolved.system>
@@ -207,7 +211,6 @@ local __lua_string_format = string.format
local __lua_table_concat = table.concat
local __lua_table_sort = table.sort
local __lua_tostring = tostring
local __lua_xpcall = xpcall
---@type fun(nseq?: integer): table
local __lua_table_new = (function()
@@ -338,6 +341,244 @@ local __lua_debug_traceback = (function()
end
end)()
---@type fun(f: function, e: function, ...): boolean, ...
local __lua_xpcall = (function()
-- https://github.com/BlackMATov/xpcall.lua/tree/v1.0.1
local __lua_xpcall = xpcall
---@diagnostic disable-next-line: redundant-parameter
if __lua_select(2, __lua_xpcall(function(a) return a end, function() end, 42)) == 42 then
-- use built-in xpcall if it works correctly with extra arguments
return __lua_xpcall
end
local __xpcall_function
local __xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4
local __xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7, __xpcall_argument_8
local __xpcall_argument_tail_list = __lua_setmetatable({}, { __mode = 'v' })
local __xpcall_argument_tail_count = 0
local function ret_xpcall_function_1(...)
__xpcall_function = nil
__xpcall_argument_1 = nil
return ...
end
local function ret_xpcall_function_2(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2 = nil, nil
return ...
end
local function ret_xpcall_function_3(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3 = nil, nil, nil
return ...
end
local function ret_xpcall_function_4(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4 = nil, nil, nil, nil
return ...
end
local function ret_xpcall_function_5(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4 = nil, nil, nil, nil
__xpcall_argument_5 = nil
return ...
end
local function ret_xpcall_function_6(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4 = nil, nil, nil, nil
__xpcall_argument_5, __xpcall_argument_6 = nil, nil
return ...
end
local function ret_xpcall_function_7(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4 = nil, nil, nil, nil
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7 = nil, nil, nil
return ...
end
local function ret_xpcall_function_8(...)
__xpcall_function = nil
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4 = nil, nil, nil, nil
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7, __xpcall_argument_8 = nil, nil, nil, nil
return ...
end
local function call_xpcall_function_1()
return ret_xpcall_function_1(__xpcall_function(
__xpcall_argument_1))
end
local function call_xpcall_function_2()
return ret_xpcall_function_2(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2))
end
local function call_xpcall_function_3()
return ret_xpcall_function_3(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3))
end
local function call_xpcall_function_4()
return ret_xpcall_function_4(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4))
end
local function call_xpcall_function_5()
return ret_xpcall_function_5(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5))
end
local function call_xpcall_function_6()
return ret_xpcall_function_6(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6))
end
local function call_xpcall_function_7()
return ret_xpcall_function_7(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7))
end
local function call_xpcall_function_8()
return ret_xpcall_function_8(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7, __xpcall_argument_8))
end
local function call_xpcall_function_N()
return ret_xpcall_function_8(__xpcall_function(
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7, __xpcall_argument_8,
__lua_table_unpack(__xpcall_argument_tail_list, 1, __xpcall_argument_tail_count)))
end
---@param f function
---@param e function
---@param ... any
---@return boolean success
---@return any ... results
return function(f, e, ...)
local argument_count = __lua_select('#', ...)
if argument_count == 0 then
-- no extra arguments, just use built-in xpcall
return __lua_xpcall(f, e)
end
__xpcall_function = f
if argument_count <= 8 then
if argument_count <= 4 then
if argument_count <= 2 then
if argument_count <= 1 then
__xpcall_argument_1 = ...
return __lua_xpcall(call_xpcall_function_1, e)
else
__xpcall_argument_1, __xpcall_argument_2 = ...
return __lua_xpcall(call_xpcall_function_2, e)
end
else
if argument_count <= 3 then
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3 = ...
return __lua_xpcall(call_xpcall_function_3, e)
else
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4 = ...
return __lua_xpcall(call_xpcall_function_4, e)
end
end
else
if argument_count <= 6 then
if argument_count <= 5 then
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5 = ...
return __lua_xpcall(call_xpcall_function_5, e)
else
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6 = ...
return __lua_xpcall(call_xpcall_function_6, e)
end
else
if argument_count <= 7 then
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7 = ...
return __lua_xpcall(call_xpcall_function_7, e)
else
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7, __xpcall_argument_8 = ...
return __lua_xpcall(call_xpcall_function_8, e)
end
end
end
else
__xpcall_argument_1, __xpcall_argument_2, __xpcall_argument_3, __xpcall_argument_4,
__xpcall_argument_5, __xpcall_argument_6, __xpcall_argument_7, __xpcall_argument_8 = ...
end
local argument_tail_list = __xpcall_argument_tail_list
__xpcall_argument_tail_count = argument_count - 8
for i = 1, argument_count - 8, 8 do
local argument_remaining = argument_count - 8 - i + 1
if argument_remaining <= 4 then
if argument_remaining <= 2 then
if argument_remaining <= 1 then
argument_tail_list[i] = __lua_select(i + 8, ...)
else
argument_tail_list[i], argument_tail_list[i + 1] = __lua_select(i + 8, ...)
end
else
if argument_remaining <= 3 then
argument_tail_list[i], argument_tail_list[i + 1],
argument_tail_list[i + 2] = __lua_select(i + 8, ...)
else
argument_tail_list[i], argument_tail_list[i + 1],
argument_tail_list[i + 2], argument_tail_list[i + 3] = __lua_select(i + 8, ...)
end
end
else
if argument_remaining <= 6 then
if argument_remaining <= 5 then
argument_tail_list[i], argument_tail_list[i + 1],
argument_tail_list[i + 2], argument_tail_list[i + 3],
argument_tail_list[i + 4] = __lua_select(i + 8, ...)
else
argument_tail_list[i], argument_tail_list[i + 1],
argument_tail_list[i + 2], argument_tail_list[i + 3],
argument_tail_list[i + 4], argument_tail_list[i + 5] = __lua_select(i + 8, ...)
end
else
if argument_remaining <= 7 then
argument_tail_list[i], argument_tail_list[i + 1],
argument_tail_list[i + 2], argument_tail_list[i + 3],
argument_tail_list[i + 4], argument_tail_list[i + 5],
argument_tail_list[i + 6] = __lua_select(i + 8, ...)
else
argument_tail_list[i], argument_tail_list[i + 1],
argument_tail_list[i + 2], argument_tail_list[i + 3],
argument_tail_list[i + 4], argument_tail_list[i + 5],
argument_tail_list[i + 6], argument_tail_list[i + 7] = __lua_select(i + 8, ...)
end
end
end
end
return __lua_xpcall(call_xpcall_function_N, e)
end
end)()
---
---
---
@@ -735,6 +976,7 @@ local __DISABLED = __acquire_id()
local __INCLUDES = __acquire_id()
local __EXCLUDES = __acquire_id()
local __VARIANTS = __acquire_id()
local __REQUIRES = __acquire_id()
local __ON_SET = __acquire_id()
@@ -840,6 +1082,7 @@ local __evolved_execute
local __evolved_locate
local __evolved_process
local __evolved_process_with
local __evolved_debug_mode
local __evolved_collect_garbage
@@ -867,6 +1110,9 @@ local __trace_minor_chunks
local __cache_query_chunks
local __reset_query_chunks
local __query_major_matches
local __query_minor_matches
local __update_major_chunks
local __update_major_chunks_trace
@@ -876,7 +1122,6 @@ local __chunk_without_fragment
local __chunk_without_fragments
local __chunk_without_unique_fragments
local __chunk_matches
local __chunk_requires
local __chunk_fragments
local __chunk_components
@@ -1158,7 +1403,7 @@ function __update_chunk_queries(chunk)
local major_query_chunks = __query_chunks[major_query]
if major_query_chunks then
if __chunk_matches(chunk, major_query) then
if __query_major_matches(chunk, major_query) then
__assoc_list_insert(major_query_chunks, chunk)
else
__assoc_list_remove(major_query_chunks, chunk)
@@ -1335,16 +1580,15 @@ function __cache_query_chunks(query)
local query_include_list = query_includes and query_includes.__item_list
local query_include_count = query_includes and query_includes.__item_count or 0
if query_include_count == 0 then
__error_fmt('the query (%s) has no include fragments and cannot be cached',
__id_name(query))
end
local query_variants = __sorted_variants[query]
local query_variant_list = query_variants and query_variants.__item_list
local query_variant_count = query_variants and query_variants.__item_count or 0
---@type evolved.assoc_list<evolved.chunk>
local query_chunks = __assoc_list_new(4)
__query_chunks[query] = query_chunks
do
if query_include_count > 0 then
local query_major = query_include_list[query_include_count]
local major_chunks = __major_chunks[query_major]
@@ -1354,12 +1598,30 @@ function __cache_query_chunks(query)
for major_chunk_index = 1, major_chunk_count do
local major_chunk = major_chunk_list[major_chunk_index]
if __chunk_matches(major_chunk, query) then
if __query_major_matches(major_chunk, query) then
__assoc_list_insert(query_chunks, major_chunk)
end
end
end
for query_variant_index = 1, query_variant_count do
local query_variant = query_variant_list[query_variant_index]
if query_include_count == 0 or query_variant > query_include_list[query_include_count] then
local major_chunks = __major_chunks[query_variant]
local major_chunk_list = major_chunks and major_chunks.__item_list
local major_chunk_count = major_chunks and major_chunks.__item_count or 0
for major_chunk_index = 1, major_chunk_count do
local major_chunk = major_chunk_list[major_chunk_index]
if __query_major_matches(major_chunk, query) then
__assoc_list_insert(query_chunks, major_chunk)
end
end
end
end
return query_chunks
end
@@ -1368,6 +1630,87 @@ function __reset_query_chunks(query)
__query_chunks[query] = nil
end
---@param chunk evolved.chunk
---@param query evolved.query
---@return boolean
---@nodiscard
function __query_major_matches(chunk, query)
local query_includes = __sorted_includes[query]
local query_include_set = query_includes and query_includes.__item_set
local query_include_count = query_includes and query_includes.__item_count or 0
local query_variants = __sorted_variants[query]
local query_variant_set = query_variants and query_variants.__item_set
local query_variant_list = query_variants and query_variants.__item_list
local query_variant_count = query_variants and query_variants.__item_count or 0
local query_include_index = query_include_count > 0 and query_include_set[chunk.__fragment] or nil
local query_variant_index = query_variant_count > 0 and query_variant_set[chunk.__fragment] or nil
return (
(query_include_index ~= nil and query_include_index == query_include_count) or
(query_variant_index ~= nil and not __chunk_has_any_fragment_list(chunk, query_variant_list, query_variant_index - 1))
) and __query_minor_matches(chunk, query)
end
---@param chunk evolved.chunk
---@param query evolved.query
---@return boolean
---@nodiscard
function __query_minor_matches(chunk, query)
local query_includes = __sorted_includes[query]
local query_include_set = query_includes and query_includes.__item_set
local query_include_list = query_includes and query_includes.__item_list
local query_include_count = query_includes and query_includes.__item_count or 0
if query_include_count > 0 then
if not __chunk_has_all_fragment_list(chunk, query_include_list, query_include_count) then
return false
end
end
local query_excludes = __sorted_excludes[query]
local query_exclude_list = query_excludes and query_excludes.__item_list
local query_exclude_count = query_excludes and query_excludes.__item_count or 0
if query_exclude_count > 0 then
if __chunk_has_any_fragment_list(chunk, query_exclude_list, query_exclude_count) then
return false
end
end
local query_variants = __sorted_variants[query]
local query_variant_set = query_variants and query_variants.__item_set
local query_variant_list = query_variants and query_variants.__item_list
local query_variant_count = query_variants and query_variants.__item_count or 0
if query_variant_count > 0 then
if not __chunk_has_any_fragment_list(chunk, query_variant_list, query_variant_count) then
return false
end
end
if chunk.__has_explicit_fragments then
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do
local chunk_fragment = chunk_fragment_list[chunk_fragment_index]
local is_chunk_fragment_matched =
(not __evolved_has(chunk_fragment, __EXPLICIT)) or
(query_variant_count > 0 and query_variant_set[chunk_fragment]) or
(query_include_count > 0 and query_include_set[chunk_fragment])
if not is_chunk_fragment_matched then
return false
end
end
end
return true
end
---@param major evolved.fragment
function __update_major_chunks(major)
if __defer_depth > 0 then
@@ -1548,50 +1891,6 @@ function __chunk_without_unique_fragments(chunk)
return sib_chunk
end
---@param chunk evolved.chunk
---@param query evolved.query
---@return boolean
---@nodiscard
function __chunk_matches(chunk, query)
local query_includes = __sorted_includes[query]
local query_include_set = query_includes and query_includes.__item_set
local query_include_list = query_includes and query_includes.__item_list
local query_include_count = query_includes and query_includes.__item_count or 0
if query_include_count > 0 then
if not __chunk_has_all_fragment_list(chunk, query_include_list, query_include_count) then
return false
end
elseif chunk.__has_explicit_fragments then
return false
end
local query_excludes = __sorted_excludes[query]
local query_exclude_list = query_excludes and query_excludes.__item_list
local query_exclude_count = query_excludes and query_excludes.__item_count or 0
if query_exclude_count > 0 then
if __chunk_has_any_fragment_list(chunk, query_exclude_list, query_exclude_count) then
return false
end
end
if chunk.__has_explicit_fragments then
local chunk_fragment_list = chunk.__fragment_list
local chunk_fragment_count = chunk.__fragment_count
for chunk_fragment_index = 1, chunk_fragment_count do
local chunk_fragment = chunk_fragment_list[chunk_fragment_index]
if not query_include_set[chunk_fragment] and __evolved_has(chunk_fragment, __EXPLICIT) then
return false
end
end
end
return true
end
---@param chunk evolved.chunk
---@return evolved.chunk
---@nodiscard
@@ -3623,7 +3922,9 @@ function __iterator_fns.__execute_iterator(execute_state)
local structural_changes = execute_state[1]
local chunk_stack = execute_state[2]
local chunk_stack_size = execute_state[3]
local exclude_set = execute_state[4]
local include_set = execute_state[4]
local exclude_set = execute_state[5]
local variant_set = execute_state[6]
if structural_changes ~= __structural_changes then
__error_fmt('structural changes are prohibited during iteration')
@@ -3643,7 +3944,9 @@ function __iterator_fns.__execute_iterator(execute_state)
local chunk_child_fragment = chunk_child.__fragment
local is_chunk_child_matched =
(not chunk_child.__has_explicit_major) and
(not chunk_child.__has_explicit_major or (
(include_set and include_set[chunk_child_fragment]) or
(variant_set and variant_set[chunk_child_fragment]))) and
(not exclude_set or not exclude_set[chunk_child_fragment])
if is_chunk_child_matched then
@@ -3665,32 +3968,24 @@ function __iterator_fns.__execute_iterator(execute_state)
__release_table(__table_pool_tag.execute_state, execute_state, true)
end
---@type { [1]: evolved.query, [2]: evolved.execute }
local __query_execute_external_arguments = {}
---@param query? evolved.query
---@param execute? evolved.execute
local function __query_execute(query, execute)
-- we use the external arguments here to support lua 5.1 xpcall (which does not support argument passing)
-- also, we can not use upvalues directly, because the function may be called recursively in that case
-- storing the arguments in local variables makes them invulnerable to changes during recursive calls
query = query or __query_execute_external_arguments[1]
execute = execute or __query_execute_external_arguments[2]
---@param query evolved.query
---@param execute evolved.execute
---@param ... any processing payload
local function __query_execute(query, execute, ...)
for chunk, entity_list, entity_count in __evolved_execute(query) do
execute(chunk, entity_list, entity_count)
execute(chunk, entity_list, entity_count, ...)
end
end
---@param system evolved.system
local function __system_process(system)
---@param ... any processing payload
local function __system_process(system, ...)
---@type evolved.query?, evolved.execute?, evolved.prologue?, evolved.epilogue?
local query, execute, prologue, epilogue = __evolved_get(system,
__QUERY, __EXECUTE, __PROLOGUE, __EPILOGUE)
if prologue then
local success, result = __lua_xpcall(prologue, __lua_debug_traceback)
local success, result = __lua_xpcall(prologue, __lua_debug_traceback, ...)
if not success then
__error_fmt('system prologue failed: %s', result)
@@ -3700,8 +3995,7 @@ local function __system_process(system)
if execute then
__evolved_defer()
do
__query_execute_external_arguments[1], __query_execute_external_arguments[2] = query or system, execute
local success, result = __lua_xpcall(__query_execute, __lua_debug_traceback, query or system, execute)
local success, result = __lua_xpcall(__query_execute, __lua_debug_traceback, query or system, execute, ...)
if not success then
__evolved_cancel()
@@ -3727,7 +4021,7 @@ local function __system_process(system)
for subsystem_index = 1, group_subsystem_count do
local subsystem = subsystem_list[subsystem_index]
if not __evolved_has(subsystem, __DISABLED) then
__system_process(subsystem)
__system_process(subsystem, ...)
end
end
@@ -3736,7 +4030,7 @@ local function __system_process(system)
end
if epilogue then
local success, result = __lua_xpcall(epilogue, __lua_debug_traceback)
local success, result = __lua_xpcall(epilogue, __lua_debug_traceback, ...)
if not success then
__error_fmt('system epilogue failed: %s', result)
@@ -5002,13 +5296,18 @@ function __evolved_execute(query)
local chunk_stack_size = 0
local query_includes = __sorted_includes[query]
local query_include_set = query_includes and query_includes.__item_set
local query_include_count = query_includes and query_includes.__item_count or 0
local query_excludes = __sorted_excludes[query]
local query_exclude_set = query_excludes and query_excludes.__item_set
local query_exclude_count = query_excludes and query_excludes.__item_count or 0
if query_include_count > 0 then
local query_variants = __sorted_variants[query]
local query_variant_set = query_variants and query_variants.__item_set
local query_variant_count = query_variants and query_variants.__item_count or 0
if query_include_count > 0 or query_variant_count > 0 then
local query_chunks = __query_chunks[query] or __cache_query_chunks(query)
local query_chunk_list = query_chunks and query_chunks.__item_list
local query_chunk_count = query_chunks and query_chunks.__item_count or 0
@@ -5049,7 +5348,9 @@ function __evolved_execute(query)
execute_state[1] = __structural_changes
execute_state[2] = chunk_stack
execute_state[3] = chunk_stack_size
execute_state[4] = query_exclude_set
execute_state[4] = query_include_set
execute_state[5] = query_exclude_set
execute_state[6] = query_variant_set
return __iterator_fns.__execute_iterator, execute_state
end
@@ -5092,14 +5393,25 @@ function __evolved_process(...)
if __freelist_ids[system_primary] ~= system then
__warning_fmt('the system (%s) is not alive and cannot be processed',
__id_name(system))
elseif __evolved_has(system, __DISABLED) then
-- the system is disabled, nothing to process
else
__system_process(system)
end
end
end
---@param system evolved.system
---@param ... any processing payload
function __evolved_process_with(system, ...)
local system_primary = system % 2 ^ 20
if __freelist_ids[system_primary] ~= system then
__error_fmt('the system (%s) is not alive and cannot be processed',
__id_name(system))
end
__system_process(system, ...)
end
---@param yesno boolean
function __evolved_debug_mode(yesno)
__debug_mode = yesno
@@ -5799,6 +6111,31 @@ function __builder_mt:exclude(...)
return self:set(__EXCLUDES, exclude_list)
end
---@param ... evolved.fragment fragments
---@return evolved.builder builder
function __builder_mt:variant(...)
local argument_count = __lua_select('#', ...)
if argument_count == 0 then
return self
end
local variant_list = self:get(__VARIANTS)
local variant_count = variant_list and #variant_list or 0
if variant_count == 0 then
variant_list = __list_new(argument_count)
end
for argument_index = 1, argument_count do
---@type evolved.fragment
local fragment = __lua_select(argument_index, ...)
variant_list[variant_count + argument_index] = fragment
end
return self:set(__VARIANTS, variant_list)
end
---@param ... evolved.fragment fragments
---@return evolved.builder builder
function __builder_mt:require(...)
@@ -5947,6 +6284,7 @@ __evolved_set(__DISABLED, __NAME, 'DISABLED')
__evolved_set(__INCLUDES, __NAME, 'INCLUDES')
__evolved_set(__EXCLUDES, __NAME, 'EXCLUDES')
__evolved_set(__VARIANTS, __NAME, 'VARIANTS')
__evolved_set(__REQUIRES, __NAME, 'REQUIRES')
__evolved_set(__ON_SET, __NAME, 'ON_SET')
@@ -5987,6 +6325,7 @@ __evolved_set(__DISABLED, __INTERNAL)
__evolved_set(__INCLUDES, __INTERNAL)
__evolved_set(__EXCLUDES, __INTERNAL)
__evolved_set(__VARIANTS, __INTERNAL)
__evolved_set(__REQUIRES, __INTERNAL)
__evolved_set(__ON_SET, __INTERNAL)
@@ -6036,6 +6375,9 @@ __evolved_set(__INCLUDES, __DUPLICATE, __list_dup)
__evolved_set(__EXCLUDES, __DEFAULT, __list_new())
__evolved_set(__EXCLUDES, __DUPLICATE, __list_dup)
__evolved_set(__VARIANTS, __DEFAULT, __list_new())
__evolved_set(__VARIANTS, __DUPLICATE, __list_dup)
__evolved_set(__REQUIRES, __DEFAULT, __list_new())
__evolved_set(__REQUIRES, __DUPLICATE, __list_dup)
@@ -6056,17 +6398,38 @@ local function __insert_query(query)
local query_include_list = query_includes and query_includes.__item_list
local query_include_count = query_includes and query_includes.__item_count or 0
local query_variants = __sorted_variants[query]
local query_variant_list = query_variants and query_variants.__item_list
local query_variant_count = query_variants and query_variants.__item_count or 0
if query_include_count > 0 then
local query_major = query_include_list[query_include_count]
local major_queries = __major_queries[query_major]
if not major_queries then
---@type evolved.assoc_list<evolved.query>
major_queries = __assoc_list_new(4)
__major_queries[query_major] = major_queries
end
__assoc_list_insert(major_queries, query)
end
for query_variant_index = 1, query_variant_count do
local query_variant = query_variant_list[query_variant_index]
if query_include_count == 0 or query_variant > query_include_list[query_include_count] then
local major_queries = __major_queries[query_variant]
if not major_queries then
---@type evolved.assoc_list<evolved.query>
major_queries = __assoc_list_new(4)
__major_queries[query_variant] = major_queries
end
__assoc_list_insert(major_queries, query)
end
end
end
---@param query evolved.query
@@ -6075,6 +6438,10 @@ local function __remove_query(query)
local query_include_list = query_includes and query_includes.__item_list
local query_include_count = query_includes and query_includes.__item_count or 0
local query_variants = __sorted_variants[query]
local query_variant_list = query_variants and query_variants.__item_list
local query_variant_count = query_variants and query_variants.__item_count or 0
if query_include_count > 0 then
local query_major = query_include_list[query_include_count]
local major_queries = __major_queries[query_major]
@@ -6084,9 +6451,27 @@ local function __remove_query(query)
end
end
for query_variant_index = 1, query_variant_count do
local query_variant = query_variant_list[query_variant_index]
if query_include_count == 0 or query_variant > query_include_list[query_include_count] then
local major_queries = __major_queries[query_variant]
if major_queries and __assoc_list_remove(major_queries, query) == 0 then
__major_queries[query_variant] = nil
end
end
end
__reset_query_chunks(query)
end
---
---
---
---
---
---@param query evolved.query
---@param include_list evolved.fragment[]
__evolved_set(__INCLUDES, __ON_SET, function(query, _, include_list)
@@ -6163,6 +6548,44 @@ end)
---
---
---@param query evolved.query
---@param variant_list evolved.fragment[]
__evolved_set(__VARIANTS, __ON_SET, function(query, _, variant_list)
__remove_query(query)
local variant_count = #variant_list
if variant_count > 0 then
---@type evolved.assoc_list<evolved.fragment>
local sorted_variants = __assoc_list_new(variant_count)
__assoc_list_move(variant_list, 1, variant_count, sorted_variants)
__assoc_list_sort(sorted_variants)
__sorted_variants[query] = sorted_variants
else
__sorted_variants[query] = nil
end
__insert_query(query)
__update_major_chunks(query)
end)
__evolved_set(__VARIANTS, __ON_REMOVE, function(query)
__remove_query(query)
__sorted_variants[query] = nil
__insert_query(query)
__update_major_chunks(query)
end)
---
---
---
---
---
---@param fragment evolved.fragment
---@param require_list evolved.fragment[]
__evolved_set(__REQUIRES, __ON_SET, function(fragment, _, require_list)
@@ -6265,6 +6688,7 @@ evolved.DISABLED = __DISABLED
evolved.INCLUDES = __INCLUDES
evolved.EXCLUDES = __EXCLUDES
evolved.VARIANTS = __VARIANTS
evolved.REQUIRES = __REQUIRES
evolved.ON_SET = __ON_SET
@@ -6337,6 +6761,7 @@ evolved.execute = __evolved_execute
evolved.locate = __evolved_locate
evolved.process = __evolved_process
evolved.process_with = __evolved_process_with
evolved.debug_mode = __evolved_debug_mode
evolved.collect_garbage = __evolved_collect_garbage

View File

@@ -12,10 +12,6 @@ local STAGES = {
:build(),
}
local UNIFORMS = {
DELTA_TIME = 1.0 / 60.0,
}
local FRAGMENTS = {
POSITION_X = evolved.builder()
:name('FRAGMENTS.POSITION_X')
@@ -82,8 +78,7 @@ evolved.builder()
:group(STAGES.ON_UPDATE)
:include(FRAGMENTS.POSITION_X, FRAGMENTS.POSITION_Y)
:include(FRAGMENTS.VELOCITY_X, FRAGMENTS.VELOCITY_Y)
:execute(function(chunk, _, entity_count)
local delta_time = UNIFORMS.DELTA_TIME
:execute(function(chunk, _, entity_count, delta_time)
local screen_width, screen_height = love.graphics.getDimensions()
---@type number[], number[]
@@ -156,8 +151,7 @@ end
---@type love.update
function love.update(dt)
UNIFORMS.DELTA_TIME = dt
evolved.process(STAGES.ON_UPDATE)
evolved.process_with(STAGES.ON_UPDATE, dt)
end
---@type love.draw

View File

@@ -0,0 +1,34 @@
rockspec_format = "3.0"
package = "evolved.lua"
version = "1.7.0-0"
source = {
url = "git://github.com/BlackMATov/evolved.lua",
tag = "v1.7.0",
}
description = {
homepage = "https://github.com/BlackMATov/evolved.lua",
summary = "Evolved ECS (Entity-Component-System) for Lua",
detailed = [[
`evolved.lua` is a fast and flexible ECS (Entity-Component-System) library for Lua.
It is designed to be simple and easy to use, while providing all the features needed to create complex systems with blazing performance.
]],
license = "MIT",
labels = {
"ecs",
"entity",
"entities",
"component",
"components",
"entity-component",
"entity-component-system",
},
}
dependencies = {
"lua >= 5.1",
}
build = {
type = "builtin",
modules = {
evolved = "evolved.lua",
}
}