Skip to main content

Entities

Namespace: DeadworksManaged.Api

The entity system provides managed wrappers around Source 2 entities. All entities derive from CBaseEntity.

CBaseEntity

Base managed wrapper for all Source 2 entities. Provides common operations: health, team, lifecycle, modifiers, schema access.

Static Methods (Creation & Lookup)

MethodReturnsDescription
CreateByName(string className)CBaseEntity?Creates a new entity by class name (e.g. "info_particle_system")
FromHandle(uint entityHandle)CBaseEntity?Gets entity by its entity handle
FromIndex(int index)CBaseEntity?Gets entity by its global entity index

Properties

PropertyTypeDescription
DesignerNamestringThe designer/map name (e.g. "npc_boss_tier3", "player")
ClassnamestringThe C++ DLL class name (e.g. "CCitadelPlayerPawn")
EntityHandleuintThe entity handle (CEntityHandle as uint32)
EntityIndexintThe entity index (lower 14 bits of handle)
HealthintCurrent health (get/set)
MaxHealthintMaximum health (get/set)
PositionVector3World position (from BodyComponent)
TeamNumintTeam number (get/set)
LifeStateLifeStateLife state enum (Alive, Dying, Dead, Respawnable, Respawning)
IsAliveboolShorthand for LifeState == Alive
ModifierPropCModifierProperty?Modifier state flags manager
BodyComponentCBodyComponent?Body component with scene node
SubclassVDataCEntitySubclassVDataBase?VData subclass info (.Name for VData key)

Type Checking & Casting

// Check if entity is a specific type
if (entity.Is<CCitadelPlayerPawn>())
{
var pawn = entity.As<CCitadelPlayerPawn>();
// pawn is typed, or null if cast failed
}
MethodReturnsDescription
Is<T>()boolCheck if entity's native type matches T's class name
As<T>()T?Cast to T if native type matches, otherwise null

Lifecycle

MethodDescription
Remove()Marks entity for removal at end of current frame
Spawn()Queues and executes entity spawn
Spawn(void* keyValues)Spawn with CEntityKeyValues
Entity Removal

Calling Remove() immediately after CreateByName() on certain entity types (e.g. info_particle_system) can crash the server with WriteEnterPVS: GetEntServerClass failed. Always delay removal by at least 1 tick:

Timer.Once(1.Ticks(), () => entity.Remove());

Transform

// Teleport entity — pass null to leave component unchanged
entity.Teleport(
position: new Vector3(100, 200, 300),
angles: null, // keep current angles
velocity: null // keep current velocity
);

// Set velocity via Teleport (confirmed working)
entity.Teleport(null, null, new Vector3(0, 0, 1500)); // launch upward

Velocity via Schema

Reading velocity works via schema accessors. Writing via schema does not reliably override the engine — use Teleport instead.

private static readonly SchemaAccessor<Vector3> _vecVelocity =
new("CBaseEntity"u8, "m_vecVelocity"u8);
private static readonly SchemaAccessor<Vector3> _vecAbsVelocity =
new("CBaseEntity"u8, "m_vecAbsVelocity"u8);

// Read current velocity
Vector3 vel = _vecVelocity.Get(entity.Handle);
Vector3 absVel = _vecAbsVelocity.Get(entity.Handle);
caution

m_flSpeed always reads 0 — it appears unused by the engine. Calculate speed from velocity instead: velocity.Length().

caution

RenderFx and RenderMode schema fields (m_nRenderFX, m_nRenderMode) have no visible effect when set on players server-side. These are likely client-only rendering properties.

Model Swapping is Impossible

There is no working method to change a player's model server-side. AcceptInput("SetModel") crashes the server. modifier_citadel_animalcurse applies C++ effects but no model change. modifier_citadel_cheater_curse turns the player into a frog but the model never reverts — use with caution.

Parenting

entity.SetParent(parentEntity);  // Attach to parent
entity.ClearParent(); // Detach

Entity I/O

entity.AcceptInput("Start", activator, caller, "value");

Modifiers

Add modifiers (buffs/debuffs) to entities. See Modifiers for full details.

using var kv = new KeyValues3();
kv.SetFloat("duration", 5.0f);
entity.AddModifier("modifier_citadel_knockdown", kv);

Audio

entity.EmitSound("Mystical.Piano.AOE.Explode");
entity.EmitSound("Damage.Send.Crit", pitch: 100, volume: 0.5f, soundLevel: 75f);

Damage

// Simple damage
entity.Hurt(100f, attacker, inflictor, ability, flags: 0);

// Full control via CTakeDamageInfo — see Damage docs
entity.TakeDamage(damageInfo);

See Damage for full details.

Schema Access

Read/write any networked schema field by class and field name:

// Read a field
int health = entity.GetField<int>("CBaseEntity"u8, "m_iHealth"u8);

// Write a field
entity.SetField<int>("CBaseEntity"u8, "m_iHealth"u8, 500);

For repeated access, use a static SchemaAccessor<T> instead:

private static readonly SchemaAccessor<int> _health =
new("CBaseEntity"u8, "m_iHealth"u8);

// Usage
int hp = _health.Get(entity.Handle);
_health.Set(entity.Handle, 500);

MoveType

The m_MoveType and m_nActualMoveType schema fields control how an entity moves. Set both every tick to override the engine's movement system.

MoveType_t enum:

ValueNameEffect via Schema
0MOVETYPE_NONENo movement
1MOVETYPE_OBSOLETEObsolete
2MOVETYPE_WALKNormal walking (default)
3MOVETYPE_FLYFly, no gravity
4MOVETYPE_FLYGRAVITYFly with gravity
5MOVETYPE_VPHYSICSPhysics-driven
6MOVETYPE_PUSHPush movement
7MOVETYPE_NOCLIPNoclip (free flight, no collision)
8MOVETYPE_OBSERVERObserver/spectator — freezes the player in place
9MOVETYPE_STEPStep movement
10MOVETYPE_SYNCSync movement
11MOVETYPE_CUSTOMCustom movement
private static readonly SchemaAccessor<byte> _moveType = new("CBaseEntity"u8, "m_MoveType"u8);
private static readonly SchemaAccessor<byte> _actualMoveType = new("CBaseEntity"u8, "m_nActualMoveType"u8);

// Freeze a player (MOVETYPE_OBSERVER locks position)
private void FreezePlayer(CCitadelPlayerPawn pawn, float durationSeconds)
{
const byte MOVETYPE_OBSERVER = 8;
const byte MOVETYPE_WALK = 2;

var timer = Timer.Every(1.Ticks(), () =>
{
if (!pawn.IsValid || pawn.Health <= 0) return;
_moveType.Set(pawn.Handle, MOVETYPE_OBSERVER);
_actualMoveType.Set(pawn.Handle, MOVETYPE_OBSERVER);
});

Timer.Once(((int)durationSeconds).Seconds(), () =>
{
timer.Cancel();
if (!pawn.IsValid) return;
_moveType.Set(pawn.Handle, MOVETYPE_WALK);
_actualMoveType.Set(pawn.Handle, MOVETYPE_WALK);
});
}

Note: MOVETYPE_NOCLIP (7) grants true noclip flight with no collision. MOVETYPE_OBSERVER (8) freezes the player in place despite previously being misidentified as noclip.

Entities (Static Class)

Enumerate all server entities.

// All entities
foreach (var entity in Entities.All) { }

// By C++ class type
foreach (var pawn in Entities.ByClass<CCitadelPlayerPawn>()) { }

// By designer name
foreach (var boss in Entities.ByDesignerName("npc_boss_tier3")) { }
MethodReturnsDescription
Entities.AllIEnumerable<CBaseEntity>All valid entities on the server
Entities.ByClass<T>()IEnumerable<T>Entities matching native type T
Entities.ByDesignerName(string)IEnumerable<CBaseEntity>Entities with given designer name

EntityData<T>

Dictionary-like store that associates per-entity data with entities by their handle. Automatically removes entries when an entity is deleted.

private readonly EntityData<IHandle?> _timers = new();

// Store data
_timers[entity] = timerHandle;

// Retrieve safely
if (_timers.TryGet(entity, out var value))
{
// Use value
}

// Remove
_timers.Remove(entity);
MethodDescription
this[entity]Set value for entity
TryGet(entity, out T)Try to get value, returns true if found
Remove(entity)Remove entry for entity

Schema Accessors

For advanced access to entity fields not exposed by the managed API.

SchemaAccessor<T>

Reads and writes a single networked schema field. Resolves offset once on first access and caches it.

// Use UTF-8 string literals for class and field names
private static readonly SchemaAccessor<int> _maxHealth =
new("CBaseEntity"u8, "m_iMaxHealth"u8);

SchemaStringAccessor

Write-only accessor for CUtlSymbolLarge (string) fields:

private static readonly SchemaStringAccessor _name =
new("CBaseEntity"u8, "m_iszPrivateVScripts"u8);

_name.Set(entity.Handle, "my_script");

SchemaArrayAccessor<T>

Reads/writes array-typed fields:

private static readonly SchemaArrayAccessor<float> _dmgTypes =
new("CBaseEntity"u8, "m_flDamageTypes"u8);

float val = _dmgTypes.Get(entity.Handle, index: 0);

Common Entity Types

Entity types found on a typical Deadlock server (from CBaseEntity.FromIndex iteration):

ClassDesignerDescription
CCitadelPlayerPawnplayerPlayer hero entity
CCitadelPlayerController-Player controller
CNPC_Trooper-Lane troopers
CNPC_TrooperNeutral-Neutral camp NPCs
CNPC_TrooperBoss-Trooper boss
CNPC_Boss_Tier2npc_boss_tier2Tier 2 (lane) guardian
CNPC_Boss_Tier3npc_boss_tier3Tier 3 (base) patron
CNPC_BarrackBoss-Barracks walker
CNPC_MidBoss-Mid boss (Rejuvenator)
CNPC_BaseDefenseSentry-Base defense turrets
CNPC_Neutral_Bug-Neutral jungle bugs
CCitadel_BreakableProp-Breakable props (boxes, crates)
CDynamicProp-Dynamic props
CParticleSystem-Particle effect entities
CWorldworldentThe world entity
CCitadelZipLineNode-Zipline nodes
CItemXP-Soul orb pickups

NativeEntity

Base class for all managed wrappers around native C++ entity/object pointers.

PropertyTypeDescription
HandleIntPtrRaw pointer to the native object
IsValidbooltrue if the pointer is non-null

CEntitySubclassVDataBase

Wraps the VData subclass pointer stored on an entity, providing its design-time name.

See Also

  • Players — Player-specific entity types
  • Modifiers — Adding buffs/debuffs via AddModifier
  • Damage — Applying damage to entities
  • Entity I/O — Hooking entity inputs/outputs