cross-posted from: https://programming.dev/post/1086370

This time on my arbitrary blog: Entity component systems.

Also, highlight.js should degrade more gracefully without JS activated than last time. Note that I can’t process syntax highlighting in my build step, because I don’t have a build step.

EDIT: improved phrasing

  •  TehPers   ( @TehPers@beehaw.org ) 
    link
    fedilink
    3
    edit-2
    11 months ago

    I do not consider programming in Rust scripting.

    I don’t think most people do to be honest, I was providing it as reference because it’s a strongly typed ECS. One of the other challenges with scripts is they often don’t have static type checkers since they’re intended to be executed right away. mypy and TypeScript have helped tremendously with Python and JavaScript, but they’re still extra steps that need to be executed before you can run your code.

    an embedded interpreter seems kind of off the table.

    An embedded interpreter can still be highly performant, assuming it has a decent JIT compiler. Sending data between the host and the interpreter would be a concern, but it might be possible to allow the script to share memory with the host and directly access the components (while holding locks on those components’ storages). I tried experimenting with this a while back using WASI, but unfortunately the runtimes I played with (wasmer + wasmtime) weren’t yet mature enough from my experience to be realistically useful, and I couldn’t figure out how to get the modules to share memory with each other.

    I know there are people playing around with scripting capabilities in bevy though, so I’m sure this will be possible at some point. The other challenge, of course, is having a scheduler that’s flexible enough to handle dynamically added/removed systems, and systems which execute runtime-specified queries.

    Edit: I should add that a large part of the performance of an ECS comes from the ability of an ECS runtime to parallelize the systems. If your interpreter can execute the systems in parallel, then you still get to keep that benefit as long as your scheduler knows which systems are safe to run in parallel.

    • If your interpreter can execute the systems in parallel,

      Well, the way I thought of it was that the interpreter gets called in the systems in the first place, so that might become a problem.

      • I would definitely be concerned about the performance in this case, unless you can do some kind of AoT compilation of the scripts being executed (at least in production builds, development builds probably can’t do that if you need hot reloading). Unfortunately the execution time budget is really tight if you want to get frequent updates and decent frame times (although if the system in question runs parallel to the rest of your systems, for example, then it might have more time to operate with).

        That being said, with the interpreter pre-compiling those scripts, performance could still be really good. Sharing memory would become less relevant since your scripts would now operate on more than whatever’s in your component storages and could now, in theory, work with variables local to the system, assuming you’re meaning that the interpreter is called ad-hoc basically and isn’t the entirety of the system.

        This is all in theory of course, in practice you’d need to find an interpreter that supports pre-compiling (or at least pre-optimizing in some form) all the scripts you’ll want to run if you want to maximize performance.

        • assuming you’re meaning that the interpreter is called ad-hoc basically and isn’t the entirety of the system.

          That was my assumption. Basically, that interpreter would have to run small snippets here and there typically on an irregular base. Thanks for reminding, I should probably clarify that as well.