Arceus.jl — A Lightning-Fast Behavior Resolution System

Gesee
Mon, 30 Jun 2025 02:01:08 +0000
Package Announcements

Hi all,

I’m happy to present Arceus.jl, a fork of a high-performance AliceRoselia’s original package Arceus, which introduces a novel way to resolve behaviors for entities based on their component sets—using magic bitboards, an optimization technique originally used in chess engines for O(1) move lookups.

Arceus.jl provides constant-time behavior resolution for ECS-style setups where entities are encoded as UInt64 bitfields. This is especially useful in games, simulations, or other systems where thousands of entities need to be matched to behaviors in real-time.

Explanations

You define a @traitpool, which is a set of traits (characteristics influencing the entity’s behavior) and subpool (subset of traits and other subpool).
Once done, you define a new instance of a traitpool with @make_traitpool and add the relevant traits, only those who describe your object, you can add and remove traits with @addtrait and @removetrait.
Once done, you create a new lookup function with @lookup, you specify in the body how each traits affects the result when present. This may take a while the first time since it compute the magic number which is slow. But for any future run, you won’t have problems (unless you add or remove some test in the lookup function)
Now you are all set to create your lookup table with @make_lookup.
Now for any instance of that trait pool, the resulting behavior for it’s set of traits will be retrieved in less than 10ns, even on a potato hardware.

Features

O(1) Behavior Lookup
Behaviors are precomputed for all possible component combinations, enabling instant retrieval.

Magic Bitboard Caching
Magic numbers are expensive to compute, so they’re deterministically cached to disk (CSV), enabling fast startup on subsequent runs.

ECS Compatibility
Works with any archetype-based ECS that represents components using bitmasks or similar binary encodings.

Fine-Grained Bit Control
You can allocate custom bit ranges for component pools, set precise trait positions, and manage trait dependencies.

Example

Here’s a simplified usage example:

using Arceus

@traitpool "EndingTrait" begin
    @trait start
    @trait meetX
    @trait gotSaber
    @trait lostAlly at 2
    @subpool side begin
        @trait good
        @trait evil
    end
end

@make_traitpool GameEnding from "EndingTrait" begin
    @trait start
end

@addtrait GameEnding begin
    @trait meetX
    @trait lostAlly
    @trait side.good
end

f1 = @lookup END "EndingTrait" begin
    val = UInt(0)
    if @hastrait END.start
        val |= 1
    end
    if @hastrait END.meetX
        val |= 2
    end
    if @hastrait END.gotSaber
        val |= 4
    end
    if @hastrait END.lostAlly
        val |= 8
    end
    if @hastrait END.side.good
        val |= 64
    end
    if @hastrait END.side.evil
        val |= 128
    end
    return val
end

@register_variable f1
ending = @make_lookup f1

println(ending[GameEnding])

This allows sub-10ns behavior lookup on low hardware.

Known Limitations

Heavy Initial Computation: Magic numbers are expensive to generate. It’s best to compute them once during initialization—after that, they are cached to a CSV file.

64-bit Limit: The system operates on UInt64, meaning you’re limited to 64 component flags. Beyond that, the magic bitboard trick doesn’t apply.

Links

GitHub: https://github.com/Gesee-y/Arceus.jl

Original author: AliceRoselia (@Tarny_GG_Channie)

Contribute

Contributions are very welcome—whether it’s suggestions, PRs, or feedback. And please consider supporting the original author of the system!

Summary

If you’re working with ECS architectures and need lightning-fast behavior resolution for complex trait combinations, Arceus.jl might be worth a look. Let me know what you think, and feel free to ask questions or open issues.

25 posts - 4 participants