Commit graph

19 commits

Author SHA1 Message Date
Stephen Gutekanst
0645429df9 all: move standalone libraries to libs/ subdirectory
The root dir of our repository has grown quite a lot the past few months.

I'd like to make it more clear where the bulk of the engine lives (`src/`) and
also make it more clear which Mach libraries are consumable as standalone projects.

As for the name of this directory, `libs` was my first choice but there's a bit of
a convention of that being external libraries in Zig projects _today_, while these
are libraries maintained as part of Mach in this repository - not external ones.

We will name this directory `libs`, and if we have a need for external libraries
we will use `external` or `deps` for that directory name. I considered other names
such as `components`, `systems`, `modules` (which are bad as they overlap with
major ECS / engine concepts), and it seems likely the official Zig package manager
will break the convention of using a `libs` dir anyway.

Performed via:

```sh
mkdir libs/
git mv freetype libs/
git mv basisu libs/
git mv gamemode libs/
git mv glfw libs/
git mv gpu libs/
git mv gpu-dawn libs/
git mv sysaudio libs/
git mv sysjs libs/
git mv ecs libs/
```

git-subtree-dir: glfw
git-subtree-mainline: 0d5b853443
git-subtree-split: 572d1144f11b353abdb64fff828b25a4f0fbb7ca

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>

git mv ecs libs/

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-08-26 15:12:04 -07:00
dweiller
ebc09ee55e ecs: generic iterator type
This change makes the the Iterator generic over the components being
queried. This restores the api to the previous style with components
given to the query() function and next() having no parameters (other
that the iterator itself).
2022-07-14 21:49:20 -07:00
dweiller
b9fc04de6a ecs: make Entities.query take a typed query 2022-07-14 21:49:20 -07:00
dweiller
05b0df052d ecs: fix pointer invalidation in get/setComponent
The reference to the old archetype is invalidated by getOrPut() calls of
std.ArrayHashMap. The implementation of std.ArrayHashMap means that
pointers can be invalidated on getOrPut() calls even if the key exists
in the map. This means that the reference to the old archetype needs to
be refreshed unconditionally (i.e. not only if the new archetype didn't
exist previously).
2022-07-12 06:56:49 -07:00
Stephen Gutekanst
5c4c2d3850 ecs: add namespaced components
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-07-04 09:12:19 -07:00
Stephen Gutekanst
25afe5ccf4 ecs: make [set/remove/get]Component globally type safe
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-07-04 09:12:19 -07:00
Stephen Gutekanst
1f7ea529f4 ecs: pass an all_components parameter to everything
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-07-04 09:12:19 -07:00
dweiller
f406f42005 ecs: fix memory leak in ArchetypeStorage 2022-07-01 16:48:35 -07:00
dweiller
2d923ea9b7 ecs: fix memory corruption in set/removeComponent 2022-07-01 16:48:35 -07:00
dweiller
fa5afee5bc ecs: allow components to have type void 2022-06-18 20:56:36 -07:00
dweiller
dd4d741aed ecs: use std.mem.alignForward to calculate padding 2022-06-12 08:02:53 -07:00
dweiller
f6d29e7669 ecs: fix padding and data copy in setCapacity() 2022-06-12 08:02:53 -07:00
dweiller
390b8bd922 ecs: fix appendUndefined() off-by-one error 2022-06-12 08:02:53 -07:00
Stephen Gutekanst
70283bfcb4 ecs: zig fmt
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-06-10 16:56:12 -07:00
Stephen Gutekanst
334ed5c25f ecs: switch from ArrayList per-table-per-component-set -> single-[]u8-per-table
This switches our ECS over to manually managed memory (1 `[]u8` per archetype table,
with multiple column arrays packed into it - dealing with padding/alignment ourselves)
rather than the prior 1 `ArrayList(Component)` per component in an archetype table.

This idea was discussed in depth in [#ecs:matrix.org](https://matrix.to/#/#ecs:matrix.org)
(thanks Levy!) Notable advantages from my POV:

1. This means we don't need an `ErasedComponentStorage` interface, which is nice.
2. It means component storage does not have to have a Zig type. It could e.g. in theory enable
   the ECS to be usable from other languages (C, WebAssembly plugins, etc.) with component types
   defined in those languages in the future.
3. It reduces some overhead `ArrayList` has: slice ptr+len+capacity integers per component
   array per table
4. It guarantees component arrays are contiguous memory, rather than relying on the allocator
   to hopefully provide that (may not hold true in multi-threaded large-allocation situations.)
5. It means we could easily optimize for tables that have very few components by allocating exact
   memory for them (could've done this with `ArrayList` too, but now it's more likely the
   allocation are larger and thus more reusable by future archetype tables.) This could be quite
   important because one can imagine ending up with many small archetype tables.

Overall seems like the right thing to do, so we're doing it.

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-06-10 13:24:27 -07:00
Stephen Gutekanst
14ec786c62 ecs: remove incomplete sparse storage implementation
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-06-10 13:24:27 -07:00
dweiller
3234b6c0dd ecs: fix pointer invalidation in set/removeComponent 2022-06-07 19:26:40 -07:00
dweiller
997cf7d446 ecs: fix argument order in copy() calls 2022-06-07 19:26:40 -07:00
Stephen Gutekanst
0ef13eb1cc ecs: third major redesign/rethink of implementation
In the past:

* hexops/mach#156 was the initial ECS implementation detailed in https://devlog.hexops.com/2022/lets-build-ecs-part-1
* hexops/mach#157 was the second major redesign in which we:
    * Eliminated major limitations (e.g. inability to add/remove components at runtime)
    * Investigated sparse sets
    * Began thinking in terms of databases
    * Enabled runtime introspection

Our second revision of the ECS, however, still had _archetypes_ exposed as a public-facing
user concern. When a new component was added to an entity, say a weapon, the table storing
entities of that archetype changed to effectively have a new column `?Weapon` with a null
value for _all existing entities of that archetype_. We can say that our ECS had archetypes
as a user-facing concern AND this made performance worse: when iterating all entities with
a weapon, we needed to check if the component value was `null` or not because every column
was `?Weapon` instead of a guaranteed non-null value like `Weapon`. This was a key learning
that I got from [discussing ECS tradeoffs with the Bevy team](https://github.com/hexops/mach/pull/157#issuecomment-1022916117).

This third revision of our ECS has some big benefits:

* Entities are now just IDs proper, you can add/remove arbitrary components at runtime.
    * You don't have an "entity which always belongs to one archetype table which changes"
    * Rather, you have an "entity of one archetype" and adding a component means that entity _moves_ from one archetype table to another.
    * Archetypes are now an implementation detail, not something you worry about as a consumer of the API.
* Performance
    * We benefit from the fact that we no longer need check if a component on an entity is `null` or not.
* Introspection
    * Previously iterating the component names/values an entity had was not possible, now it is.
* Querying & multi-threading
    * Very very early stages into this, but we now have a general plan for how querying will work and multi-threading.
    * Effectively, it will look much like interfacing with a database: you have a connection (we call it an adapter)
      and you can ask for information through that. More work to be done here.
* Systems, we now have a (very) basic starting point for how systems will work.

Some examples of how the API looks today:

* 979240135b/ecs/src/main.zig (L49)
* 979240135b/ecs/src/entities.zig (L625-L656)

Much more work to do, I will do a blog post detailing this step-by-step first though.

Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
2022-03-19 10:59:26 -07:00