Skip to content

The data structure problem with active objects #14613

@sfan5

Description

@sfan5

There's a closely related older issue (#6453) but I felt like a fresh start here was better.

Problem

tl;dr: optimizing anything else server-side is basically a waste until this is solved, skip to the next section.

The nice people from the Your Land server sent me several profiling traces of their production server and a common theme is that about 40% of time (on the server thread) is spent just iterating the entity list (average, not peak!).
Now their mods use get_objects_inside_radius a bunch, but this is not a sole cause and I expect any sizeable server will be plagued with this exact issue.

The issue are spatial queries on the entity list, which happen more often than one might think:

  • Lua get_objects_inside_radius, get_objects_in_area
  • Entity collision detection (sometimes)
  • Raycasts (sometimes)
  • ServerEnvironment::getAddedActiveObjects

All of these are O(n) with n being the number of entities. When you consider that every entity does collision detection this becomes O(n²) right in the main thread.

Solution requirements

What we need is a new data structure.

It must:

  • support fast lookup by entity ID
  • be iterable in the order of entity ID
  • support deletion and insertion
  • support fast spatial AABB queries (= getObjectsInArea) on the entity position
  • efficiently handle entity position updates, as these happen often
  • position updates must reflect in lookups instantly

external circumstances:

  • there is almost always opportunity for positions to change between lookups
    • this means any kind of "one-off cache" (that needs to be thrown away once an update happens) is unlikely to produce any hits
  • spatial distance queries (= getObjectsInsideRadius) can be emulated on top of AABB queries and are not an important point
  • being safe from modification during iteration is also important (Use performant and safe data structure for active objects #13880) but I think we can tack that on if the rest is adressed

Finally we will also need to figure out how to reliably propagate position updates up to the container.
There are many ideas in the form of "just add a cache to <thing>" that come to mind, but keeping it in sync is generally the trickier part than designing the structure.

Real-world example data

(thanks to @Bastrabun)
There are 4500 entities. About 1400 move often, 3100 are static.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions