Difference between revisions of "Protobuf"

From AlliedModders Wiki
Jump to: navigation, search
(Created page with "==Intro== Unlike the serial bitbuffer-backed usermessages in older games, newer games such as CS:GO (and DOTA 2) now use Google's [https://code.google.com/p/protobuf/ Protocol...")
 
m (Multi-game usermessages example: Add newline for readability.)
 
(18 intermediate revisions by 6 users not shown)
Line 7: Line 7:
 
Starting, ending, and hooking usermessages remains unchanged. Reading and writing values to/from them is done using the Pb* set of natives in protobuf.inc instead of the Bf* natives in bitbuffer.inc.
 
Starting, ending, and hooking usermessages remains unchanged. Reading and writing values to/from them is done using the Pb* set of natives in protobuf.inc instead of the Bf* natives in bitbuffer.inc.
  
You can tell which usermessage system is in use for the current game by checking GetUserMessageFormat(). Possible returns are USERMSG_BITBUF and USERMSG_PROTOBUF.
+
You can tell which usermessage system is in use for the current game by checking GetUserMessageType(). Possible returns are UM_BitBuf and UM_Protobuf.
  
  
Line 15: Line 15:
  
  
See the [http://hg.alliedmods.net/hl2sdks/hl2sdk-csgo/file/tip/public/game/shared/csgo/protobuf/cstrike15_usermessages.proto#l130 CS:GO Usermessages] as defined in protobuf's proto format.
+
For message and field names, see the [https://github.com/alliedmodders/hl2sdk/blob/csgo/public/game/shared/csgo/protobuf/cstrike15_usermessages.proto#L68 CS:GO Usermessages] as defined in protobuf's proto format, the [[Counter-Strike: Global Offensive UserMessages]] page, or the [[DOTA 2 UserMessages]] page.
 
 
==Multi-game usermessages example==
 
From funcommands' drug.sp:
 
<pawn>
 
new clients[2];
 
clients[0] = client;
 
 
new duration = 255;
 
new holdtime = 255;
 
new flags = 0x0002;
 
new color[4] = { 0, 0, 0, 128 };
 
color[0] = GetRandomInt(0,255);
 
color[1] = GetRandomInt(0,255);
 
color[2] = GetRandomInt(0,255);
 
 
 
new Handle:message = StartMessageEx(g_FadeUserMsgId, clients, 1);
 
 
if (GetUserMessageFormat() == USERMSG_PROTOBUF)
 
{
 
PbSetInt(message, "duration", duration);
 
PbSetInt(message, "hold_time", holdtime);
 
PbSetInt(message, "flags", flags);
 
PbSetColor(message, "clr", color);
 
}
 
else
 
{
 
BfWriteShort(message, duration);
 
BfWriteShort(message, holdtime);
 
BfWriteShort(message, flags);
 
BfWriteByte(message, color[0]);
 
BfWriteByte(message, color[1]);
 
BfWriteByte(message, color[2]);
 
BfWriteByte(message, color[3]);
 
}
 
 
EndMessage();
 
</pawn>
 
  
 
==Protobuf natives==
 
==Protobuf natives==
TODO: replace this with a link to plugins/include/protobuf.inc once it is pushed to sourcemod-central.
+
See [https://github.com/alliedmodders/sourcemod/blob/master/plugins/include/protobuf.inc protobuf.inc]
<pawn>
 
/**
 
* Reads an int32, uint32, sint32, fixed32, or sfixed32 from a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @return Integer value read.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadInt(Handle:pb, const String:field[]);
 
  
/**
+
==Multi-game usermessages example==
* Reads a float or downcasted double from a protobuf message.
+
From funcommands' drug.sp, using the [http://hg.alliedmods.net/hl2sdks/hl2sdk-csgo/file/9a3c7f5049b6/public/game/shared/csgo/protobuf/cstrike15_usermessages.proto#l204 Fade] usermessage:
*
+
<sourcepawn>
* @param pb protobuf handle.
+
    int clients[2];
* @param field Field name.
+
    clients[0] = client;  
* @return Float value read.
+
   
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
+
    int duration = 255;
*/
+
    int holdtime = 255;
native Float:PbReadFloat(Handle:pb, const String:field[]);
+
    int flags = 0x0002;
 
+
    int color[4] = { 0, 0, 0, 128 };
/**
+
    color[0] = GetRandomInt(0,255);
* Reads a bool from a protobuf message.
+
    color[1] = GetRandomInt(0,255);
*
+
    color[2] = GetRandomInt(0,255);
* @param pb protobuf handle.
 
* @param field Field name.
 
* @return Boolean value read.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native bool:PbReadBool(Handle:pb, const String:field[]);
 
 
 
/**
 
* Reads a string from a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param buffer Destination string buffer.
 
* @param maxlength Maximum length of output string buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadString(Handle:pb, const String:field[], String:buffer[], maxlength);
 
 
 
/**
 
* Reads an RGBA color value from a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param buffer Destination color buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadColor(Handle:pb, const String:field[], buffer[4]);
 
 
 
/**
 
* Reads an XYZ angle value from a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param buffer Destination angle buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadAngle(Handle:pb, const String:field[], Float:buffer[3]);
 
 
 
/**
 
* Reads an XYZ vector value from a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param buffer Destination vector buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadVector(Handle:pb, const String:field[], Float:buffer[3]);
 
 
 
/**
 
* Reads an XY vector value from a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param buffer Destination vector buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadVector2D(Handle:pb, const String:field[], Float:buffer[2]);
 
 
 
/**
 
* Gets the number of elements in a repeated field of a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @return Number of elements in the field.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbGetRepeatedFieldCount(Handle:pb, const String:field[]);
 
 
 
/**
 
* Reads an int32, uint32, sint32, fixed32, or sfixed32 from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @return Integer value read.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadRepeatedInt(Handle:pb, const String:field[], index);
 
 
 
/**
 
* Reads a float or downcasted double from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @return Float value read.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native Float:PbReadRepeatedFloat(Handle:pb, const String:field[], index);
 
 
 
/**
 
* Reads a bool from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @return Boolean value read.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native bool:PbReadRepeatedBool(Handle:pb, const String:field[], index);
 
 
 
/**
 
* Reads a string from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @param buffer Destination string buffer.
 
* @param maxlength Maximum length of output string buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadRepeatedString(Handle:pb, const String:field[], index, String:buffer[], size);
 
 
 
/**
 
* Reads an RGBA color value from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @param buffer Destination color buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadRepeatedColor(Handle:pb, const String:field[], index, buffer[4]);
 
 
 
/**
 
* Reads an XYZ angle value from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @param buffer Destination angle buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadRepeatedAngle(Handle:pb, const String:field[], index, Float:buffer[3]);
 
 
 
/**
 
* Reads an XYZ vector value from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @param buffer Destination vector buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadRepeatedVector(Handle:pb, const String:field[], index, Float:buffer[3]);
 
 
 
/**
 
* Reads an XY vector value from a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @param buffer Destination vector buffer.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbReadRepeatedVector2D(Handle:pb, const String:field[], index, Float:buffer[2]);
 
 
 
/**
 
* Sets an int32, uint32, sint32, fixed32, or sfixed32  on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Integer value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetInt(Handle:pb, const String:field[], value);
 
 
 
/**
 
* Sets a float or double on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Float value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetFloat(Handle:pb, const String:field[], Float:value);
 
 
 
/**
 
* Sets a bool on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Boolean value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetBool(Handle:pb, const String:field[], bool:value);
 
 
 
/**
 
* Sets a string on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value String value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetString(Handle:pb, const String:field[], const String:value[]);
 
 
 
/**
 
* Sets an RGBA color on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Color value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetColor(Handle:pb, const String:field[], const color[4]);
 
 
 
/**
 
* Sets an XYZ angle on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Angle value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetAngle(Handle:pb, const String:field[], const Float:angle[3]);
 
 
 
/**
 
* Sets an XYZ vector on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Vector value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetVector(Handle:pb, const String:field[], const Float:vec[3]);
 
 
 
/**
 
* Sets an XY vector on a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Vector value to set.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbSetVector2D(Handle:pb, const String:field[], const Float:vec[2]);
 
 
 
/**
 
* Add an int32, uint32, sint32, fixed32, or sfixed32 to a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Integer value to add.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbAddInt(Handle:pb, const String:field[], value);
 
 
 
/**
 
* Add a float or double to a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Float value to add.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbAddFloat(Handle:pb, const String:field[], Float:value);
 
 
 
/**
 
* Add a bool to a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Boolean value to add.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbAddBool(Handle:pb, const String:field[], bool:value);
 
 
 
/**
 
* Add a string to a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value String value to add.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbAddString(Handle:pb, const String:field[], const String:value[]);
 
  
/**
+
    Handle msg = StartMessageEx(g_FadeUserMsgId, clients, 1);
* Add an RGBA color to a protobuf message repeated field.
+
   
*
+
    if (GetUserMessageType() == UM_Protobuf)
* @param pb protobuf handle.
+
    {
* @param field Field name.
+
        Protobuf pb = UserMessageToProtobuf(msg);
* @param value Color value to add.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbAddColor(Handle:pb, const String:field[], const color[4]);
 
  
/**
+
        pb.SetInt("duration", duration);
* Add an XYZ angle to a protobuf message repeated field.
+
        pb.SetInt("hold_time", holdtime);
*
+
        pb.SetInt("flags", flags);
* @param pb protobuf handle.
+
        pb.SetColor("clr", color);
* @param field Field name.
+
    }
* @param value Angle value to add.
+
    else
* @noreturn
+
    {
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
+
        BrWrite bf = UserMessageToBfWrite(msg);
*/
 
native PbAddAngle(Handle:pb, const String:field[], const Float:angle[3]);
 
  
/**
+
        bf.WriteShort(duration);
* Add an XYZ vector to a protobuf message repeated field.
+
        bf.WriteShort(holdtime);
*
+
        bf.WriteShort(flags);
* @param pb protobuf handle.
+
        bf.WriteByte(color[0]);
* @param field Field name.
+
        bf.WriteByte(color[1]);
* @param value Vector value to add.
+
        bf.WriteByte(color[2]);
* @noreturn
+
        bf.WriteByte(color[3]);
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
+
    }
*/
+
   
native PbAddVector(Handle:pb, const String:field[], const Float:vec[3]);
+
    EndMessage();
 +
</sourcepawn>
  
/**
+
==Embedded message example==
* Add an XY vector to a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param value Vector value to add.
 
* @noreturn
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native PbAddVector2D(Handle:pb, const String:field[], const Float:vec[2]);
 
  
/**
+
This example sends a VGUIMenu usermessage, adding values to a repeated field "subkeys" that uses the [http://hg.alliedmods.net/hl2sdks/hl2sdk-csgo/file/tip/public/game/shared/csgo/protobuf/cstrike15_usermessages.proto#l137 Subkey message type] defined in the [http://hg.alliedmods.net/hl2sdks/hl2sdk-csgo/file/tip/public/game/shared/csgo/protobuf/cstrike15_usermessages.proto#l132 VGUIMenu message].
* Retrieve a handle to an embedded protobuf message in a protobuf message.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @return protobuf handle to embedded message.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native Handle:PbReadMessage(Handle:pb, const String:field[]);
 
  
/**
+
Once an embedded message handle is retrieved with ReadMessage, you can read or write to its fields with the normal PbRead/Set natives. GetRepeatedMessage or AddMessage will retrieve the handle for reading or writing respectively if it is a repeated field.
* Retrieve a handle to an embedded protobuf message in a protobuf message repeated field.
 
*
 
* @param pb protobuf handle.
 
* @param field Field name.
 
* @param index Index in the repeated field.
 
* @return protobuf handle to embedded message.
 
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
 
*/
 
native Handle:PbReadRepeatedMessage(Handle:pb, const String:field[], index);
 
  
/**
+
<sourcepawn>void SendSourceModMOTD(int client)
* Adds an embedded protobuf message to a protobuf message repeated field.
+
{
*
+
    Protobuf pb = UserMessageToProtobuf(StartMessageOne("VGUIMenu", client));
* @param pb protobuf handle.
+
   
* @param field Field name.
+
    pb.SetString("name", "info");
* @return protobuf handle to added, embedded message.
+
    pb.SetBool("show", true);
* @error Invalid or incorrect Handle, non-existant field, or incorrect field type.
+
   
*/
+
    Protobuf subkey = PbAddMessage(pb, "subkeys");
native Handle:PbAddMessage(Handle:pb, const String:field[]);
+
    subkey.SetString("name", "type");
 +
    subkey.SetString("str", "2"); // MOTDPANEL_TYPE_URL
 +
   
 +
    subkey = pb.AddMessage("subkeys");
 +
    subkey.SetString("name", "title");
 +
    subkey.SetString("str", "TESTING");
 +
   
 +
    subkey = pb.AddMessage("subkeys");
 +
    subkey.SetString("name", "msg");
 +
    subkey.SetString("str", "http://www.sourcemod.net");
 +
   
 +
    EndMessage();
 +
}</sourcepawn>
  
</pawn>
+
[[Category:SourceMod_Scripting]]

Latest revision as of 18:51, 29 March 2020

Intro

Unlike the serial bitbuffer-backed usermessages in older games, newer games such as CS:GO (and DOTA 2) now use Google's Protocol Buffers or "protobuf" to back net messages and usermessages.

Differences

Instead of having to be read or written in order, the protobuf usermessages use defined fields, accessible by name, in any order.

Starting, ending, and hooking usermessages remains unchanged. Reading and writing values to/from them is done using the Pb* set of natives in protobuf.inc instead of the Bf* natives in bitbuffer.inc.

You can tell which usermessage system is in use for the current game by checking GetUserMessageType(). Possible returns are UM_BitBuf and UM_Protobuf.


Basic fields ("optional" or "required") are single values and use the PbRead*/PbSet* natives.

Repeated fields are arrays of values, accessible by their 0-based index with the PbReadRepeated* natives or added with the PbAdd* natives. You can get the count of values in a repeated field with PbGetRepeatedFieldCount.


For message and field names, see the CS:GO Usermessages as defined in protobuf's proto format, the Counter-Strike: Global Offensive UserMessages page, or the DOTA 2 UserMessages page.

Protobuf natives

See protobuf.inc

Multi-game usermessages example

From funcommands' drug.sp, using the Fade usermessage:

    int clients[2];
    clients[0] = client;    
 
    int duration = 255;
    int holdtime = 255;
    int flags = 0x0002;
    int color[4] = { 0, 0, 0, 128 };
    color[0] = GetRandomInt(0,255);
    color[1] = GetRandomInt(0,255);
    color[2] = GetRandomInt(0,255);
 
    Handle msg = StartMessageEx(g_FadeUserMsgId, clients, 1);
 
    if (GetUserMessageType() == UM_Protobuf)
    {
        Protobuf pb = UserMessageToProtobuf(msg);
 
        pb.SetInt("duration", duration);
        pb.SetInt("hold_time", holdtime);
        pb.SetInt("flags", flags);
        pb.SetColor("clr", color);
    }
    else
    {
        BrWrite bf = UserMessageToBfWrite(msg);
 
        bf.WriteShort(duration);
        bf.WriteShort(holdtime);
        bf.WriteShort(flags);
        bf.WriteByte(color[0]);
        bf.WriteByte(color[1]);
        bf.WriteByte(color[2]);
        bf.WriteByte(color[3]);
    }
 
    EndMessage();

Embedded message example

This example sends a VGUIMenu usermessage, adding values to a repeated field "subkeys" that uses the Subkey message type defined in the VGUIMenu message.

Once an embedded message handle is retrieved with ReadMessage, you can read or write to its fields with the normal PbRead/Set natives. GetRepeatedMessage or AddMessage will retrieve the handle for reading or writing respectively if it is a repeated field.

void SendSourceModMOTD(int client)
{
    Protobuf pb = UserMessageToProtobuf(StartMessageOne("VGUIMenu", client));
 
    pb.SetString("name", "info");
    pb.SetBool("show", true);
 
    Protobuf subkey = PbAddMessage(pb, "subkeys");
    subkey.SetString("name", "type");
    subkey.SetString("str", "2"); // MOTDPANEL_TYPE_URL
 
    subkey = pb.AddMessage("subkeys");
    subkey.SetString("name", "title");
    subkey.SetString("str", "TESTING");
 
    subkey = pb.AddMessage("subkeys");
    subkey.SetString("name", "msg");
    subkey.SetString("str", "http://www.sourcemod.net");
 
    EndMessage();
}