[ANN] A wild apecs-0.10.0 appears!

After 2.5 years of using it from git master, I’m now finally committed enough to publish an update for the venerable ECS package.

The major highlights are:

  • Internals simplified to just being a ReaderT over the generated World record, shedding some dependencies in the process.
  • Storage initialization may use arbitrary constraints/contexts besides MonadIO. They’re collected and fed automatically into the resulting initWorld function.
  • An answer for the most frequent newcomer question: “How do I really, really delete an Entity so that absolutely nothing remains? And no, I can’t be bothered with making archetype aliases.”
    • With the new TH helper: makeWorldDestructible, then destroy ety @WorldDestructible.
    • (It’s a type alias generator that gives you a tuple-of-tuples that just visits every store one by one and asks them to remove the data for that entity.)
  • An entirely new facility that goes against all the core apecs principles :sweat_smile:: component tags and component-tagged values.
    • Another TH helper: makeWorldEnumerable that, when used with the new explMemberSet method, will give you an IntSet of all entities in the world.
    • Now you can make a generic world editor UI or derive one from the components you use.
    • Or run component population and “archetype-like” census to spot optimizations.
    • Or run a diff on what’s changed in the current tick.
    • Or dump the whole dumpable world to console or a file.

apecs-stm is back on track. After many experiments to find its niche, it has been reduced to the 3 STM-capable stm-container-backed stores. Bespoke EntityCounter and makeWorld are gone, and the stores are renamed to avoid clashing with IO-bound originals. That means you can deploy the atomic/transactional stores only where it matters and keep the rest in IO for performance.

21 Likes

Game development isn’t something I’ve ever been particularly interested in, but a lot of the ideas uses in ECSs have turned out to be applicable to other domains; the author of the Zig compiler has a great talk on using similar ideas in the compiler to massively improve its performance and memory usage. I was wondering if you’d looked into uses outside games dev? Reading through the tutorial it feels very much like a relation system missing a few features, which should be pretty relevant to a lot of domains.

2 Likes

Indeed. Anything where you want mutable and/or extensible annotations (AST nodes are entities) or bulk+sparse storage can benefit.
IIRC Anders Hejlsberg argued for something like that for compiler design that’s interactive and incremental instead, predating LSPs for quite a while.
ECS is able to answer both “give me all what you know about entity 345” (kv store for an abstract primary key) and “find me everything that has WIP tag, narrow down by Unblocked”.
Each time I have to reinvent a reverse-index, multimap or stuff like that I go “eh, apecs had this for years”. Recently I’ve hacked together some datomic-ish bitemporal storage in Erlang which is basically a ECS.

2 Likes

This maybe a very beginner question, but is this library aim to be something like Raylib or Ebitengine (Go)?

Can I make games linke Pong/FlappyBird in it?

No, it is only the data storage. There are other packages that provide the integrations with graphics and whatever else.

Here’s how a gloss-based game looks like (and a crash-course in apecs): apecs/examples/Shmup.md at master · jonascarpay/apecs · GitHub

Here’s raylib+apecs: Notakto: A Haskell game with Apecs and Raylib

1 Like