Opened 15 years ago

Closed 14 years ago

Last modified 14 years ago

#222 closed task (wontfix)

Better reference-counting of entities

Reported by: Jan Wassenberg Owned by: Jan Wassenberg
Priority: Should Have Milestone:
Component: Core engine Keywords:
Cc: philip, matei Patch:

Description (last modified by Jan Wassenberg)

We currently have a fairly complicated and unsafe means of managing entities. CHandle is basically a reference-counted pointer. HEntity is an index into a table of CHandle; the class simulates smart pointer semantics by accessing this table.

A fixed table of CHandle is both inefficient (what if we really only need 10% of the limit at a time?) and unsafe (we can't validate HEntity indices sent via network, and risk dangling entity pointers).

To delete entities, they must be inserted into a reaper queue, the contents of which are deleted at the beginning of each update. However, the entities are still accessible and can be referenced.

Finally, there are a bunch of complicated and seemingly redundant flags/access mechanisms for entity aliveness - the refd bitset, its reference count (trumped however by the reaper queue), a destroyed flag and the destroy notifier flag.

This complexity is causing real problems - we've had several access violations at 0x400..0x460, which are most likely caused by NULL entity pointers. At the meeting yesterday, we discussed banning raw CEntity* pointers and replacing them all with smart pointers. Also, separating network ID from entity storage seems prudent (allows stringent error checks and removes an artificial limit on the number of handles).

The proposed solution we arrived at is based on weak pointers - this allows code (e.g. AI) to hold on to entity references and be able to determine in a controlled way whether the entity is dead. The implementation is such that every entity holds a reference-counted pointer to itself and hands it out in form of a smart pointer class. When the entity is `killed', it marks the shared pointer value as invalid and frees itself immediately. Only when the last weak reference is freed would the reference-counted-pointer class instance that they use be released.

The requirement for the reaper is based on the assumption that entities are killed fairly high on the call stack, and the calling functions may still be wanting to do something with the entity. To detect when an entity is dead, we are already using an isDead flag. I figure this could be replaced with the standard weak_ptr isValid mechanism.

Finally, the network ID. For practically limitless numbers of entities, we need a 32-bit counter that resets to zero each game. Entities store their number (which is what is serialized), and EntityManager needs a sparse mapping of ID -> HEntity (the new/old entity reference system).

This sounds like it would simplify things; a partial implementation is underway, but a few design questions remain to be hashed out (Philip and I will be discussing this shortly; any other input is welcome).

TODO:

  • ~update HEntity~
  • ~adapt EntityManager~
  • proper construction of CEntity, including !JS_AddRoot
  • update all code to use HEntity instead of CEntity*

Change History (5)

comment:1 by Jan Wassenberg, 15 years ago

Description: modified (diff)

comment:2 by Jan Wassenberg, 15 years ago

Description: modified (diff)
Owner: set to Jan Wassenberg
Status: newassigned

Matei had a good idea: to further defend against yanking the rug out from under JS code (GUI, AI) holding a reference to an entity, we could simply have the CEntity managed by JS. CEntity inherits from CJSComplex; it looks like we'd only need to set m_EngineOwned to false to get the desired AddRoot behavior.

comment:3 by Jan Wassenberg, 15 years ago

Cc: matei added
Description: modified (diff)

comment:4 by Philip Taylor, 14 years ago

Resolution: wontfix
Status: assignedclosed

Obsoleted by new simulation system.

comment:5 by (none), 14 years ago

Milestone: Open Source Release

Milestone Open Source Release deleted

Note: See TracTickets for help on using tickets.