Burnsies HideoutDocsBurnsie.Common

Entities & Blips — EntityBag and Blips

Burnsie.Common.Entities solves the most common plugin bug there is: leaked peds, vehicles and blips. The rule it enforces: everything you create goes in a bag, and the bag is emptied in exactly one place, on every exit path.

EntityBag — lifetime-scoped ownership

One bag per incident/callout/scene. Register everything the scene creates or controls; tear the bag down once, no matter how the scene ends.

var bag = new EntityBag(log);

// Keep() returns its argument, so it chains into creation code:
Ped suspect  = bag.Keep(new Ped(model, position, heading));
Blip marker  = bag.Keep(new Blip(position) { Color = Blips.DangerColor });

// ... scene runs ...

// EXACTLY ONE of these, on every exit path:
bag.ReleaseAll();   // happy path
bag.DeleteAll();    // abort path

ReleaseAll vs DeleteAll

ReleaseAll() (happy path)DeleteAll() (abort path)
Blipsdeleteddeleted
Entitiesdismissed back to the ambient populationhard-deleted
Whenscene ended normally in front of the playerteardown must be instant/total (plugin unload, hard abort)

ReleaseAll never hard-deletes something visible in front of the player. Before dismissing a ped it hands ambient control back (BlockPermanentEvents = false, KeepTasks = false) — a ped left with those flags set stays locked in its scripted task forever instead of resuming ambient life.

Both are idempotent, Exists()-guarded, and must run on a GameFiber. Dispose() is equivalent to ReleaseAll(), so using-style patterns default to the safe path.

Housekeeping

  • Registration is thread-safe (event fibers may Keep while a tracker prunes).
  • Double-Keep of the same entity is a no-op.
  • Prune() drops references to entities the game already cleaned up; Count reports tracked entities + blips (diagnostics).

Blips — standard-color blip factory

Implements the community color standard: LightBlue for police units, white for EMS/medical, orange for fire, red for danger/suspects, yellow for routes/objectives. Scale 1.0 for vehicles, 0.75 for peds.

// Flashing red panic blip (flashes forever) with an optional yellow GPS route:
Blip panic = bag.Keep(Blips.Panic(position, "Officer Down", route: true));

// Standard police blip attached to a unit vehicle (tracks it as it moves):
Blip unit = bag.Keep(Blips.PoliceUnit(vehicle, "Responding Unit"));

// Any standard color on an attached unit blip:
Blip ems = bag.Keep(Blips.Unit(ambulance, "EMS", Blips.EmsColor));

Exposed color constants: Blips.PoliceColor, Blips.EmsColor, Blips.FireColor, Blips.DangerColor, Blips.RouteColor — use them for hand-built blips so your plugin matches the ecosystem.

Fading blips out

Deleting a dozen unit blips at once pops them off the map; fading reads as "units returning to patrol":

// Single blip:
Blips.FadeOutAndDelete(blip, durationMs: 1600);

// A set, faded together:
Blips.FadeOutAndDeleteMany(blipList, durationMs: 1600);

Both run inline on the calling fiber (they sleep between alpha steps) — call them from a cleanup fiber, not from a path that must return immediately. A blip removed by the game mid-fade is handled silently.

Rules

  • One bag per scene; never share a bag between concurrent scenes.
  • Entities handed to you by other systems (e.g. LSPDFR-owned backup vehicles) do not belong in your bag — see the Backup dispatcher, which deliberately leaves units LSPDFR-owned.
  • Re-validate entities with .Exists() after any yield, even ones in your bag — the bag guards its own operations, not yours.