ISource2ModTransmit
Interface for deciding which entities each player receives.
Every tick the server works out, per player, the set of entities to send (CheckTransmit). This interface sits after that decision and takes entities back out of it:
- an entity is hooked once, and from then on has a visibility per viewer -- hidden from some players, shown to others, with up to eight independent "channels" so two features (a !hide command, a spectator mode, a team-only marker) can each hide the same entity without stepping on each other's toes: the entity shows only when no channel hides it;
- a player is hidden through their controller: hiding a controller from a viewer hides the pawn that controller is driving, the observer pawn and a dead player pawn, while the controller itself stays -- the scoreboard keeps working;
- an entity can be tied to an owner entity, and then disappears wherever its owner is hidden (a player's weapons, a beam attached to them);
- BlockAll takes an entity away from everybody, the one-line "server-side only" switch;
- and for anything that does not fit the model, HookCheckTransmit() hands over each viewer's transmit set, wrapped, so a plugin never has to lay out CCheckTransmitInfo itself.
Hiding is done the way the client expects: the entity leaves the transmit set and is put on the "non-transmitted" list at the same time, so the client keeps a record of it while it is hidden and takes it back without the "missing client entity" crash when it comes back. Both of those bits are what ISource2ModTransmitInfo::BlockTransmit() does.
Interface id ISource2ModTransmit002 (SOURCE2MOD_TRANSMIT_INTERFACE) · Global g_pSource2ModTransmit · Header source2mod/ISource2ModTransmit.h
Types
Source2ModTransmitHookId
using Source2ModTransmitHookId = Source2ModHookId;A CheckTransmit hook (HookCheckTransmit).
CheckTransmitHook
using CheckTransmitHook = Source2ModCallback<void(ISource2ModTransmitInfo* const* infos, int infoCount, const uint16_t* entityIndices, int entityCount)>;Hook called once per CheckTransmit, after Source2Mod has applied the hooked entities' visibility.
Runs every tick for every viewer, so do the expensive part (who owns what, who is on which team) once at the top and only the bit work per viewer.
Methods
HookEntity
virtual bool HookEntity(PluginId owner, CEntityInstance* entity, bool defaultVisible = true) = 0;Puts an entity under this interface's control.
Until an entity is hooked, the setters below refuse it and it is sent as the engine decides. The hook goes away with the entity, with the plugin, or with UnhookEntity().
Hook a player's controller, not their pawn: a controller's visibility is applied to whatever pawn it is driving. Pawns are refused.
| Parameter | Type | Default | Description |
|---|---|---|---|
owner | PluginId | Plugin ID that owns the hook | |
entity | CEntityInstance* | Entity to hook | |
defaultVisible | bool | true | Whether viewers see it until told otherwise. false is for "personal" entities: hidden from everybody, then SetVisible(entity, ownerSlot, true). |
Returns bool — false when the entity is a pawn, already hooked, or about to be deleted.
UnhookEntity
virtual void UnhookEntity(CEntityInstance* entity) = 0;Forgets an entity: sent as the engine decides from now on.
| Parameter | Type |
|---|---|
entity | CEntityInstance* |
IsEntityHooked
virtual bool IsEntityHooked(CEntityInstance* entity) = 0;| Parameter | Type |
|---|---|
entity | CEntityInstance* |
SetVisible
virtual bool SetVisible(CEntityInstance* entity, CPlayerSlot viewer, bool visible, int channel = 0) = 0;Shows or hides a hooked entity for one viewer.
| Parameter | Type | Default | Description |
|---|---|---|---|
entity | CEntityInstance* | Hooked entity | |
viewer | CPlayerSlot | The player it is shown to / hidden from | |
visible | bool | false hides it on @p channel; true withdraws that channel's objection, and for an entity hidden by default also marks the viewer as allowed | |
channel | int | 0 | Channel 0..TRANSMIT_MAX_CHANNELS-1, or TRANSMIT_CHANNEL_ALL for every channel at once |
Returns bool — false when the entity is not hooked.
SetVisibleToAll
virtual bool SetVisibleToAll(CEntityInstance* entity, bool visible, int channel = 0) = 0;SetVisible() for every player slot at once.
| Parameter | Type | Default |
|---|---|---|
entity | CEntityInstance* | |
visible | bool | |
channel | int | 0 |
IsVisible
virtual bool IsVisible(CEntityInstance* entity, CPlayerSlot viewer) = 0;Whether a viewer would receive the entity, the channels, the default and BlockAll all taken into account. An unhooked entity is visible. The owner is not consulted -- ask about it directly.
| Parameter | Type |
|---|---|
entity | CEntityInstance* |
viewer | CPlayerSlot |
IsHiddenOnChannel
virtual bool IsHiddenOnChannel(CEntityInstance* entity, CPlayerSlot viewer, int channel) = 0;Whether one channel hides the entity from the viewer.
| Parameter | Type |
|---|---|
entity | CEntityInstance* |
viewer | CPlayerSlot |
channel | int |
SetBlockAll
virtual bool SetBlockAll(CEntityInstance* entity, bool block) = 0;Hides a hooked entity from everybody, whatever the channels say.
| Parameter | Type |
|---|---|
entity | CEntityInstance* |
block | bool |
GetBlockAll
virtual bool GetBlockAll(CEntityInstance* entity) = 0;| Parameter | Type |
|---|---|
entity | CEntityInstance* |
SetOwner
virtual bool SetOwner(CEntityInstance* entity, CEntityInstance* owner) = 0;Ties a hooked entity to an owner: wherever the owner is hidden, so is the entity. The owner has to be hooked for that to apply.
| Parameter | Type | Description |
|---|---|---|
entity | CEntityInstance* | |
owner | CEntityInstance* | Owner entity, nullptr to untie |
GetOwner
virtual CEntityInstance* GetOwner(CEntityInstance* entity) = 0;| Parameter | Type |
|---|---|
entity | CEntityInstance* |
ResetViewer
virtual void ResetViewer(CPlayerSlot viewer) = 0;Puts every hooked entity back to its default for one viewer.
Done by Source2Mod when the player disconnects.
| Parameter | Type |
|---|---|
viewer | CPlayerSlot |
HookCheckTransmit
virtual Source2ModTransmitHookId HookCheckTransmit(CheckTransmitHook handler) = 0;Hooks CheckTransmit itself.
Handlers run after Source2Mod's own pass, in the order they were added; a plugin may add as many as it likes.
Whose it is, the core reads off the handler (see Source2ModCallback); what a plugin still holds at unload the core drops for it.
| Parameter | Type | Description |
|---|---|---|
handler | CheckTransmitHook | A function, an object and a method, or a lambda |
Returns Source2ModTransmitHookId — The id UnhookCheckTransmit(id) takes
UnhookCheckTransmit
virtual bool UnhookCheckTransmit(const CheckTransmitHook& handler) = 0;
virtual bool UnhookCheckTransmit(Source2ModTransmitHookId id) = 0;Drops the hook with this handler -- a function or an object and a method; a lambda goes by its id.
Drops the hook HookCheckTransmit() returned the id for.
| Parameter | Type |
|---|---|
handler | const CheckTransmitHook& |
id | Source2ModTransmitHookId |
Returns bool — true when one was found
ISource2ModTransmitInfo
One viewer's slice of a CheckTransmit call: who it is for, and which entities are on their way to them.
Handed to a CheckTransmitHook, one per viewer, valid for the duration of the callback only.
GetPlayerSlot
virtual CPlayerSlot GetPlayerSlot() const = 0;The player this transmit set belongs to.
IsFullUpdate
virtual bool IsFullUpdate() const = 0;True when the player is being sent everything from scratch (first snapshot, reconnect), false for an ordinary delta.
IsTransmitting
virtual bool IsTransmitting(int entityIndex) const = 0;Whether the entity is currently in the set.
| Parameter | Type |
|---|---|
entityIndex | int |
BlockTransmit
virtual void BlockTransmit(int entityIndex) = 0;
virtual void BlockTransmit(CEntityInstance* entity) = 0;Takes an entity out of the set, and lets the client keep track of it while it is gone, so it can come back later.
This is the right way to hide an entity. Clearing the transmit bit alone makes the client forget the entity, and retransmitting it afterwards crashes the client on "missing client entity".
| Parameter | Type |
|---|---|
entityIndex | int |
entity | CEntityInstance* |
AllowTransmit
virtual void AllowTransmit(int entityIndex) = 0;
virtual void AllowTransmit(CEntityInstance* entity) = 0;Puts an entity (back) into the set.
| Parameter | Type |
|---|---|
entityIndex | int |
entity | CEntityInstance* |
GetTransmitEntity
virtual CBitVec<MAX_EDICTS>* GetTransmitEntity() = 0;The four bit sets of CCheckTransmitInfo, for whatever the methods above do not cover. Entity index = bit index.
TransmitEntity -- entities sent this tick. TransmitNonPlayers -- entities the client keeps a record of without receiving them (what BlockTransmit() sets). TransmitOutOfPVS -- entities that left the PVS but still get a delta. TransmitAlways -- HLTV/replay only, may be nullptr.
GetTransmitNonPlayers
virtual CBitVec<MAX_EDICTS>* GetTransmitNonPlayers() = 0;GetTransmitOutOfPVS
virtual CBitVec<MAX_EDICTS>* GetTransmitOutOfPVS() = 0;GetTransmitAlways
virtual CBitVec<MAX_EDICTS>* GetTransmitAlways() = 0;Macros
TRANSMIT_HOOK_ENTITY
#define TRANSMIT_HOOK_ENTITY(entity, ...) g_pSource2ModTransmit->HookEntity(g_PluginID, entity, ##__VA_ARGS__)Shorthand accessors via g_pSource2ModTransmit.
Other macros
| Macro | Expands to |
|---|---|
TRANSMIT_UNHOOK_ENTITY(entity) | g_pSource2ModTransmit->UnhookEntity(entity) |
TRANSMIT_SET_VISIBLE(entity, ...) | g_pSource2ModTransmit->SetVisible(entity, __VA_ARGS__) |
TRANSMIT_SET_BLOCK_ALL(entity, on) | g_pSource2ModTransmit->SetBlockAll(entity, on) |
HOOK_CHECK_TRANSMIT(handler) | g_pSource2ModTransmit->HookCheckTransmit(handler) |
UNHOOK_CHECK_TRANSMIT(handler) | g_pSource2ModTransmit->UnhookCheckTransmit(handler) |