Dev Diary - Data interfaces, Reliability an Expandability

A Long Long time ago, in a game company not so far away... Quake 3 was born. With it came a dedicated server and a log file for administrative purposes. The ingenious citizens of the galaxy took that log and mined it for all it was worth, bringing a variety of riches for all to share. The peoples hunger for more data was unbounded and the clever citizens dug deeper and deeper into that mine with ever more diminishing returns. Until today. The days of data mining from logs is over, instead data shall grow freely from the ground for all to enjoy....

Using the games log to see what's going on inside JKA and MB2 specifically has been going on for as long as the mod itself, but it is not without it's problems. Namely it is difficult to programmatically read, if you are not careful it is unsafe to read programmatically, and the performance can degrade as more data, and more types of data that are added unless care is taken about how the log is accessed, and lastly it is without extra steps both permanent and local. All these factors combine to make a replacement which avoids these problems desirable.

Today the games log is used to provide the data source for functionality such as RTV/RTM, integrations to discord, and other custom functionality. This presents us with a unique problem - any time we make any change to the log output there is a real chance we could be ruining someone's day by breaking their script. Maybe that person isn't around to support the script anymore and it will be broken forever.

Movie Battles II will introduce a new feature in the next patch, where all the current data that is currently written to the log file will optionally be sent out as UDP packets to the endpoint(s) of servers choice. The UDP packets are designed to be safe and easy to process, and fast to send. There are a few advantages here, people who run more than one server will no longer have to have multiple instances of multiple tools running against multiple log files. Game Server owners who's providers won't let external scripts run against the games.log will now be able to take advantage of scripting capabilities, and importantly, as multiple endpoints are supported, community wide efforts will be possible with server owners simply adding a destination for their data to contribute to. A few examples might be community wide efforts to share ban information, or even stats being shared across the whole community. The possibilities available by having this data freely and widely accessible are endless.

Furthermore, as the cost of sending UDP packets is much lower than writing to the disk, and then reading the same data again, we will be able to easily expand the new system to export much more granular data, and we will be open to requests for what people would like to see added - and unlike the current system, adding more data types won't break everyone's existing scripts.

To make adoption even easier, today we have made open source under the LGPL license, a crossplatform Library for receiving and processing the UDP packets into programmatically actionable data. At the moment, this is a barebones library which provides only the functionality to receive, parse packets and raise events. It is our hope that this Library can be a community wide effort to do much more than that and share the burden of such tools wildly across the community. The github for this library is here GitHub - MBII/MB2EventReceiver: Library for recieving and processing MB2 Event Notifications

Technical Details

The service must be enabled by setting the cvar sv_notificationservice to 1. A json document should then be created at GameData/MBII/rensConfig.json with the following format:
Code:
{
   "Endpoints":[{
         "Server":"127.0.0.1",
         "Port":8080
      }]
}

Optionally, the types of packet that are sent to an endpoint can be filtered by setting a TypeFlags field in the rensConfig.json file. If this value is omitted all packet types will be sent. A value of 0 will effectively disable an endpoint by not sending any packet types. Changes to the rensConfig.json file will take effect the next time the game module is loaded - for example, at map change.

Code:
{
   "Endpoints":[{
         "Server":"127.0.0.1",
         "Port":8080,
          "TypeFlags":1
      }]
}

Up to 16 different servers may be added as endpoints, IPv4, IPv6 and DNS may be used for the host.

Packet types are broken up into the categories in the table below. For clarity the exact packet types and their Bit Mask Value are provided later.

GroupingBit Mask Value
Server Infrastructure Events1
Game Events2
Speech Events4
SMOD Events8



RENS Packet Types

Enum ValueNameMeaningBit Mask Value
0MBII_RENS_CLIENTCONNECTA client has connected to the server2
1MBII_RENS_CLIENTDISCONNECTA client has disconnected from the server2
2MBII_RENS_CLIENTBEGINA client has fully entered the game (spawned/loaded)2
3MBII_RENS_TEAMCHANGEA client has switched teams2
4MBII_RENS_SPEECHA client has sent a chat message4
5MBII_RENS_KILLA kill event occurred (death + killer + assist + MOD)2
6MBII_RENS_SERVERSTARTThe server has started a new map/mode1
7MBII_RENS_SERVERSHUTDOWNThe server is shutting down1
8MBII_RENS_PRIVATEDUELEVENTA private duel has started or ended2
9MBII_RENS_MAPCHANGEThe server has changed to a new map2
10MBII_RENS_MODECHANGEThe server has changed game mode2
11MBII_RENS_SMODCMDAn admin has executed an SMOD command8
12MBII_RENS_SMODLOGINAn admin has logged in (success/fail)8
13MBII_RENS_NAMECHANGEA client has changed their name2
14MBII_RENS_BANA client has been banned1
15MBII_RENS_INTERMISSIONIntermission has begun (round end)2
16MBII_RENS_OBJCOMPLETEA client has completed an objective2




MBII Packet Header (always 16 bytes)

BytesFieldMeaningSize
0–3MBIIIdentifierLiteral "MBII" ASCII identifier4
4–7PacketBodyTypeMBIINotificationType_t enum4
8–11LevelTimeServer time (ms) when event occurred4
12–13PortServer port2
14VersionProtocol version1
15FlagsProtocol flags1



ClientConnect (69 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdConnecting client's ID1
17–20IPAddressClient IPv4 address4
21–36Guid[4]Client GUID (4× uint32)16
37–68PlayerNamePlayer name (MAX_NAME_LENGTH = 32)32



ClientDisconnect (17 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdDisconnecting client's ID1



ClientBegin (17 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdClient who began playing1



SwitchTeams (18 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdClient switching teams1
17NewTeamNew team ID1



PlayerDeath (23 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientKilledIdVictim client ID1
17ClientKilledByIdKiller client ID1
18ClientAssistIdAssist client ID1
19–22MeansOfDeathDamage type (enum as int)4



ServerStart (89 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16MBModeGame mode1
17–20rulesetRuleset (int)4
21–24respawnModeRespawn mode (qboolean)4
25–88MapMap name (MAX_QPATH = 64)64



ServerShutdown (16 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16



Speech (169 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdSpeaker client ID1
17MessageModeChat mode (team/global/etc.)1
18TargetClientIdTarget client (if whisper)1
19–168TextChat text (MAX_SAY_TEXT = 150)150



SmodLogin (26 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdAdmin client ID1
17adminNumAdmin level1
18–21LoginSuccessqboolean (int)4
22–25IPAddressAdmin IP address4



SmodCommand (19 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientIdAdmin issuing command1
17SmodCommandIdCommand ID1
18ClientTargetIdTarget client1



PrivateDuelEvent (19 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16ClientId1First dueling client1
17ClientId2Second dueling client1
18endDuel1 = duel ended1



MapChange (80 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16–79NewMapMap name (MAX_QPATH = 64)64



ModeChange (17 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16NewModeNew game mode1



NameChange (49 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16clientIdClient changing name1
17–48NewNameNew name (MAX_NAME_LENGTH = 32)32



Ban (21 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16clientIdClient being banned1
17–20IPAddressClient IP address4



Intermission (16 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16



ObjectiveComplete (17 bytes)

BytesFieldMeaningSize
0–15HeaderMBII packet header16
16clientIdClient completing objective1
 
Top