Difference between revisions of "Protobuf"

From AlliedModders Wiki
Jump to: navigation, search
m
m (Update syntax, methodmap, highlighting)
Line 22: Line 22:
 
==Multi-game usermessages example==
 
==Multi-game usermessages example==
 
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:
 
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:
<pawn>
+
<sourcepawn>
new clients[2];
+
    int clients[2];
clients[0] = client;
+
    clients[0] = client;  
+
   
new duration = 255;
+
    int duration = 255;
new holdtime = 255;
+
    int holdtime = 255;
new flags = 0x0002;
+
    int flags = 0x0002;
new color[4] = { 0, 0, 0, 128 };
+
    int color[4] = { 0, 0, 0, 128 };
color[0] = GetRandomInt(0,255);
+
    color[0] = GetRandomInt(0,255);
color[1] = GetRandomInt(0,255);
+
    color[1] = GetRandomInt(0,255);
color[2] = GetRandomInt(0,255);
+
    color[2] = GetRandomInt(0,255);
  
new Handle:message = StartMessageEx(g_FadeUserMsgId, clients, 1);
+
    Handle msg = StartMessageEx(g_FadeUserMsgId, clients, 1);
+
   
if (GetUserMessageType() == UM_Protobuf)
+
    if (GetUserMessageType() == UM_Protobuf)
{
+
    {
PbSetInt(message, "duration", duration);
+
        Protobuf pb = UserMessageToProtobuf(msg);
PbSetInt(message, "hold_time", holdtime);
+
        pb.SetInt("duration", duration);
PbSetInt(message, "flags", flags);
+
        pb.SetInt("hold_time", holdtime);
PbSetColor(message, "clr", color);
+
        pb.SetInt("flags", flags);
}
+
        pb.SetColor("clr", color);
else
+
    }
{
+
    else
BfWriteShort(message, duration);
+
    {
BfWriteShort(message, holdtime);
+
        BrWrite bf = UserMessageToBfWrite(msg);
BfWriteShort(message, flags);
+
        bf.WriteShort(duration);
BfWriteByte(message, color[0]);
+
        bf.WriteShort(holdtime);
BfWriteByte(message, color[1]);
+
        bf.WriteShort(flags);
BfWriteByte(message, color[2]);
+
        bf.WriteByte(color[0]);
BfWriteByte(message, color[3]);
+
        bf.WriteByte(color[1]);
}
+
        bf.WriteByte(color[2]);
+
        bf.WriteByte(color[3]);
EndMessage();
+
    }
</pawn>
+
   
 +
    EndMessage();
 +
</sourcepawn>
  
 
==Embedded message example==
 
==Embedded message example==
Line 63: Line 65:
 
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.
 
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.
  
<pawn>SendSourceModMOTD(client)
+
<sourcepawn>SendSourceModMOTD(client)
{
+
{
new Handle:pb = StartMessageOne("VGUIMenu", client);
+
    Protobuf pb = UserMessageToProtobuf(StartMessageOne("VGUIMenu", client));
+
   
PbSetString(pb, "name", "info");
+
    pb.SetString("name", "info");
PbSetBool(pb, "show", true);
+
    pb.SetBool("show", true);
+
   
new Handle:subkey;
+
    Protobuf subkey = PbAddMessage(pb, "subkeys");
+
    subkey.SetString("name", "type");
subkey = PbAddMessage(pb, "subkeys");
+
    subkey.SetString("str", "2"); // MOTDPANEL_TYPE_URL
PbSetString(subkey, "name", "type");
+
   
PbSetString(subkey, "str", "2"); // MOTDPANEL_TYPE_URL
+
    subkey = pb.AddMessage("subkeys");
+
    subkey.SetString("name", "title");
subkey = PbAddMessage(pb, "subkeys");
+
    subkey.SetString("str", "TESTING");
PbSetString(subkey, "name", "title");
+
   
PbSetString(subkey, "str", "TESTING");
+
    subkey = pb.AddMessage("subkeys");
+
    subkey.SetString("name", "msg");
subkey = PbAddMessage(pb, "subkeys");
+
    subkey.SetString("str", "http://www.sourcemod.net");
PbSetString(subkey, "name", "msg");
+
   
PbSetString(subkey, "str", "http://www.sourcemod.net");
+
    EndMessage();
+
}</sourcepawn>
EndMessage();
 
}</pawn>
 
  
 
[[Category:SourceMod_Scripting]]
 
[[Category:SourceMod_Scripting]]

Revision as of 18:27, 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.

SendSourceModMOTD(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();
}