Skip to main content

Networking

Namespace: DeadworksManaged.Api

Send and intercept Source 2 network messages between server and clients.

NetMessages

Entry point for sending and hooking protobuf network messages.

Sending Messages

// Create a protobuf message
var msg = new CCitadelUserMsg_HudGameAnnouncement
{
TitleLocstring = "GAME OVER",
DescriptionLocstring = "The match has ended"
};

// Send to all players
NetMessages.Send(msg, RecipientFilter.All);

// Send to one player
NetMessages.Send(msg, RecipientFilter.Single(playerSlot));

Hooking Outgoing Messages (Server → Client)

// Hook before a message is sent to clients
NetMessages.HookOutgoing<CCitadelUserMsg_ChatMsg>(ctx =>
{
// ctx.Message — the protobuf message
// ctx.Recipients — modifiable recipient set
// ctx.MessageId — numeric message ID

// Modify recipients
ctx.Recipients.Remove(someSlot);

return HookResult.Handled;
});

Hooking Incoming Messages (Client → Server)

// Hook when server receives a message from a client
NetMessages.HookIncoming<CCitadelUserMsg_ChatMsg>(ctx =>
{
// ctx.Message — the protobuf message from client
// ctx.SenderSlot — who sent it
// ctx.MessageId — numeric message ID

return HookResult.Handled;
});

Unhooking

NetMessages.UnhookOutgoing<CCitadelUserMsg_ChatMsg>(myHandler);
NetMessages.UnhookIncoming<CCitadelUserMsg_ChatMsg>(myHandler);

Using the Attribute (Alternative)

For chat message hooks, you can also use the [NetMessageHandler] attribute:

[NetMessageHandler]
public HookResult OnChatMsgOutgoing(OutgoingMessageContext<CCitadelUserMsg_ChatMsg> ctx)
{
// Process outgoing chat
return HookResult.Handled;
}

RecipientFilter

Bitmask of player slots that should receive a message.

Static Members

MemberDescription
RecipientFilter.AllA filter targeting all 64 possible player slots
RecipientFilter.Single(int slot)A filter targeting exactly one player

Instance Methods

MethodDescription
Add(int slot)Adds a player slot
Remove(int slot)Removes a player slot
HasRecipient(int slot)Returns true if slot is included

Properties

PropertyTypeDescription
MaskulongRaw bitmask where bit i indicates slot i is included

Example: Custom Recipient List

var filter = new RecipientFilter();
foreach (var controller in Players.GetAll())
{
if (ShouldReceive(controller))
filter.Add(controller.EntityIndex);
}
NetMessages.Send(msg, filter);

Message Contexts

OutgoingMessageContext<T>

Carries a server→client message with destination recipients.

PropertyTypeDescription
MessageTThe protobuf message being sent
RecipientsRecipientFilterTarget players (modifiable)
MessageIdintNumeric network message ID

IncomingMessageContext<T>

Carries a client→server message with sender info.

PropertyTypeDescription
MessageTThe protobuf message from client
SenderSlotintPlayer slot of the sender
MessageIdintNumeric network message ID

NetMessageRegistry

Maps protobuf message types to network message IDs.

MethodReturnsDescription
GetMessageId<T>()intMessage ID for type T, or -1
GetMessageId(Type)intMessage ID for protobuf type, or -1
RegisterManual<T>(int)voidManually register type with specific ID

Common Message Types

Set Client Camera Angles

Forces a player's camera to look in a specific direction. This is the only confirmed working method for server-side camera control — schema writes and Teleport angles only affect the hero model, not the client camera.

NetMessages.Send(new CCitadelUserMsg_SetClientCameraAngles {
PlayerSlot = slot, // target player slot (int)
CameraAngles = new CMsgQAngle {
X = pitch, // vertical angle (negative = look up)
Y = yaw, // horizontal angle
Z = 0 // roll (usually 0)
}
}, RecipientFilter.Single(slot));

HUD Announcement Example

var msg = new CCitadelUserMsg_HudGameAnnouncement
{
TitleLocstring = "ANNOUNCEMENT TITLE",
DescriptionLocstring = "Description text here"
};
NetMessages.Send(msg, RecipientFilter.All);

See Also