1
0
mirror of https://github.com/Mauler125/r5sdk.git synced 2025-02-09 19:15:03 +01:00

Server: implement LiveAPI into the game

Full implementation of all LiveAPI events into the game server.

NOTE: The only event left to be implemented in code is CustomEvent.

NOTE: ObserverSwitched and WeaponSwitched events are implemented in code, but they need a proper CodeCallback to hook them up properly in scripts.

The events.proto file is from build "R5pc_r5-200_J33_CL6243000_2024_02_27_14_53" with some slight modifications:

- PlayerStatChanged.newValue is now a oneof field, which can be either int, float or bool as Season 3 Apex still handles stats in one of those 3 types while retail was only int (which is most likely why they kept it just int only int he proto file).

- PlayerRespawnTeam.respawned is now a repeated Player field instead of a string. Initially the respawned field contained a comma separated list of player names that were respawned in the team, it now contains the actual Player data that is respawned as this was much easier to get from scripts, and also makes a bunch more sense than just string names.

- New CustomEvent event: since R5Reloaded is a modding platform, and we can't make new events for literally all gamemodes that modders create, we added another event "CustomEvent" which allows modders to sent their own data to their own tracker or anything while still remaining compatibility with the protocol.
This commit is contained in:
Kawe Mazidjatari 2024-04-05 18:33:33 +02:00
parent 9fd41688e2
commit 44d7a252de
10 changed files with 50938 additions and 13 deletions

@ -250,6 +250,8 @@ void Systems_Init()
ServerScriptRegister_Callback = Script_RegisterServerFunctions;
CoreServerScriptRegister_Callback = Script_RegisterCoreServerFunctions;
AdminPanelScriptRegister_Callback = Script_RegisterAdminPanelFunctions;
ServerScriptRegisterEnum_Callback = Script_RegisterServerEnums;
#endif// !CLIENT_DLL
#ifndef SERVER_DLL

@ -41,7 +41,7 @@ endif()
if( ${PROJECT_NAME} STREQUAL "server_static" )
add_sources( SOURCE_GROUP "Server"
add_sources( SOURCE_GROUP "AI"
"server/ai_network.cpp"
"server/ai_network.h"
"server/ai_networkmanager.cpp"
@ -49,36 +49,61 @@ add_sources( SOURCE_GROUP "Server"
"server/ai_node.h"
"server/ai_utility.cpp"
"server/ai_utility.h"
"server/detour_impl.h"
)
add_sources( SOURCE_GROUP "Entity"
"server/baseanimating.cpp"
"server/baseanimating.h"
"server/baseanimatingoverlay.h"
"server/basecombatcharacter.h"
"server/baseentity.cpp"
"server/baseentity.h"
"server/cbase.cpp"
"server/cbase.h"
"server/detour_impl.h"
"server/entitylist.cpp"
"server/entitylist.h"
"server/entityoutput.cpp"
"server/entityoutput.h"
)
add_sources( SOURCE_GROUP "Network"
"server/networkproperty.cpp"
"server/networkproperty.h"
)
add_sources( SOURCE_GROUP "Player"
"server/player.cpp"
"server/player.h"
"server/playerlocaldata.h"
)
add_sources( SOURCE_GROUP "Script"
"server/vscript_server.cpp"
"server/vscript_server.h"
)
add_sources( SOURCE_GROUP "Physics"
"server/physics_main.cpp"
"server/physics_main.h"
)
add_sources( SOURCE_GROUP "Utility"
"server/cbase.cpp"
"server/cbase.h"
"server/gameinterface.cpp"
"server/gameinterface.h"
"server/movehelper_server.cpp"
"server/movehelper_server.h"
"server/networkproperty.cpp"
"server/networkproperty.h"
"server/physics_main.cpp"
"server/physics_main.h"
"server/player.cpp"
"server/player.h"
"server/playerlocaldata.h"
"server/util_server.cpp"
"server/util_server.h"
"server/variant_t.cpp"
"server/variant_t.h"
"server/vscript_server.cpp"
"server/vscript_server.h"
)
add_sources( SOURCE_GROUP "LiveAPI"
"server/liveapi/events.pb.cc"
"server/liveapi/events.pb.h"
"server/liveapi/liveapi.cpp"
"server/liveapi/liveapi.h"
)
add_sources( SOURCE_GROUP "Public"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,11 @@
#ifndef SERVER_LIVEAPI_H
#define SERVER_LIVEAPI_H
#define LIVEAPI_MAJOR_VERSION 0
#define LIVEAPI_MINOR_VERSION 1
#define LIVEAPI_REVISION "Rev: " MKSTRING(LIVEAPI_MAJOR_VERSION) "." MKSTRING(LIVEAPI_MINOR_VERSION)
extern void Script_RegisterLiveAPIFunctions(CSquirrelVM* const s);
extern void Script_RegisterLiveAPIEnums(CSquirrelVM* const s);
#endif // SERVER_LIVEAPI_H

@ -14,6 +14,7 @@
#include "vscript/vscript.h"
#include "vscript/languages/squirrel_re/include/sqvm.h"
#include "liveapi/liveapi.h"
#include "vscript_server.h"
#include <engine/host_state.h>
#include <networksystem/hostmanager.h>
@ -216,6 +217,13 @@ void Script_RegisterServerFunctions(CSquirrelVM* s)
Script_RegisterCommonAbstractions(s);
Script_RegisterCoreServerFunctions(s);
Script_RegisterAdminPanelFunctions(s);
Script_RegisterLiveAPIFunctions(s);
}
void Script_RegisterServerEnums(CSquirrelVM* const s)
{
Script_RegisterLiveAPIEnums(s);
}
//---------------------------------------------------------------------------------

@ -1,5 +1,6 @@
#ifndef VSCRIPT_SERVER_H
#define VSCRIPT_SERVER_H
#include "vscript/languages/squirrel_re/vsquirrel.h"
namespace VScriptCode
{
@ -26,6 +27,8 @@ void Script_RegisterServerFunctions(CSquirrelVM* s);
void Script_RegisterCoreServerFunctions(CSquirrelVM* s);
void Script_RegisterAdminPanelFunctions(CSquirrelVM* s);
void Script_RegisterServerEnums(CSquirrelVM* const s);
#define DEFINE_SERVER_SCRIPTFUNC_NAMED(s, functionName, helpString, \
returnType, parameters) \
s->RegisterFunction(#functionName, MKSTRING(Script_##functionName), \

@ -0,0 +1,780 @@
//////////////////////////////////////////////////////////////////////
// Apex Legends Live API
// Copyright 2023 Respawn Entertainment
//
// Contains all messages used by LiveAPI with annotations as comments
// See readme.txt for more information on how to consume this file
//////////////////////////////////////////////////////////////////////
syntax = "proto3";
package rtech.liveapi;
//////////////////////////////////////////////////////////////////////
// Intermediary messages:
// Not used directly, but as part of other messages
//////////////////////////////////////////////////////////////////////
message Vector3
{
float x = 1;
float y = 2;
float z = 3;
}
message Player
{
string name = 1;
uint32 teamId = 2;
Vector3 pos = 3;
Vector3 angles = 4;
uint32 currentHealth = 5;
uint32 maxHealth = 6;
uint32 shieldHealth = 7;
uint32 shieldMaxHealth = 8;
string nucleusHash = 9;
string hardwareName = 10;
string teamName = 11;
uint32 squadIndex = 12;
string character = 13;
string skin = 14;
}
message CustomMatch_LobbyPlayer
{
string name = 1;
uint32 teamId = 2;
string nucleusHash = 3;
string hardwareName = 4;
}
message Datacenter
{
uint64 timestamp = 1;
string category = 2;
string name = 3;
}
message Version
{
uint32 major_num = 1;
uint32 minor_num = 2;
uint32 build_stamp = 3;
string revision = 4;
}
message InventoryItem
{
int32 quantity = 1;
string item = 2;
// any mods or additional info on the item
string extraData = 3;
}
message LoadoutConfiguration
{
repeated InventoryItem weapons = 1;
repeated InventoryItem equipment = 2;
}
//////////////////////////////////////////////////////////////////////
// Output messages:
// Game events that describe the ongoing state of the match
// Every message will have a timestamp and category
//////////////////////////////////////////////////////////////////////
// Traffic initialization
// This message is sent upon successfully connecting over WebSockets
message Init
{
uint64 timestamp = 1;
string category = 2;
string gameVersion = 3;
Version apiVersion = 4;
string platform = 5;
// Named specified by `liveapi_session_name`
string name = 6;
}
// Response to the CustomMatch_GetLobbyPlayers
// Contains the list of all players in the lobby
message CustomMatch_LobbyPlayers
{
string playerToken = 1;
repeated CustomMatch_LobbyPlayer players = 2;
}
/////////////////////////////////////////
// Observer Events
/////////////////////////////////////////
// Event when the observer camera switches from viewing one player to another
message ObserverSwitched
{
uint64 timestamp = 1;
string category = 2;
Player observer = 3;
Player target = 4;
repeated Player targetTeam = 5;
}
// Used by observers to annotate events uniquely
message ObserverAnnotation
{
uint64 timestamp = 1;
string category = 2;
int32 annotationSerial = 3;
}
/////////////////////////////////////////
// Match Information
/////////////////////////////////////////
// Sent during the first phase of a match. This event gives a full description of what match is being played
message MatchSetup
{
uint64 timestamp = 1;
string category = 2;
string map = 3;
string playlistName = 4;
string playlistDesc = 5;
Datacenter datacenter = 6;
bool aimAssistOn = 7;
bool anonymousMode = 8;
string serverId = 9;
LoadoutConfiguration startingLoadout = 10;
}
// Sent whenever the match changes phases (e.g. prematch, playing)
message GameStateChanged
{
uint64 timestamp = 1;
string category = 2;
string state = 3;
}
// Occurs when any player has locked in a character during legend select
message CharacterSelected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
}
// Event to summarize the match after it has ended
message MatchStateEnd
{
uint64 timestamp = 1;
string category = 2;
string state = 3;
repeated Player winners = 4;
}
// Fired whenever the ring begins moving in a match
message RingStartClosing
{
uint64 timestamp = 1;
string category = 2;
uint32 stage = 3;
Vector3 center = 4;
float currentRadius = 5;
float endRadius = 6;
float shrinkDuration= 7;
}
// Used when the ring has finished moving and prior to it moving again
message RingFinishedClosing
{
uint64 timestamp = 1;
string category = 2;
uint32 stage = 3;
Vector3 center = 4;
float currentRadius = 5;
float shrinkDuration= 7;
}
// Used when a player has connected to the match
message PlayerConnected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
}
// Used when a player has disconnected, even temporarily
// `canReconnect` will indicate if the player is able to reconnect or has forfeited
message PlayerDisconnected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
bool canReconnect = 4;
bool isAlive = 5;
}
// Generic event for a change in the player stats
// Common stat names that can come with this event include "knockdowns", "revivesGiven", "kills"
message PlayerStatChanged
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string statName = 4;
oneof newValue // R5R: formerly of type `uint32`
{
uint32 intValue = 5;
float floatValue= 6;
bool boolValue = 7;
}
}
// Event used to notify when a player goes above their current tier level
// Tier levels start at 1. Following this event, players may have Upgrades to their legend
// Selection of upgrades will produce a separate `LegendUpgradeSelected` event
message PlayerUpgradeTierChanged
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
int32 level = 4;
}
/////////////////////////////////////////
// Combat events
/////////////////////////////////////////
// Event describing a player taking damage
// Details include the attacker, victim, the weapon used and the amount of damage
message PlayerDamaged
{
uint64 timestamp = 1;
string category = 2;
Player attacker = 3;
Player victim = 4;
string weapon = 5;
uint32 damageInflicted = 6;
}
// Sent when a player is killed. Details are similar to PlayerDamaged event
// The `awardedTo` field has been deprecated for simplicity.
// Listen for the `PlayerStatChanged` message to determine which player the kill was awarded to.
message PlayerKilled
{
uint64 timestamp = 1;
string category = 2;
Player attacker = 3;
Player victim = 4;
reserved 5; // formerly `Player awardedTo`
string weapon = 6;
}
// Event describing a player that has been downed after taking sufficient damage
// Similar to PlayerDamaged, but may not be sent in certain game modes (e.g. Control)
message PlayerDowned
{
uint64 timestamp = 1;
string category = 2;
Player attacker = 3;
Player victim = 4;
string weapon = 5;
}
// Sent when a player is killed if there is an assist awarded
// This event may come in rapid succession to the PlayerKilled event with a corresponding `victim` field
message PlayerAssist
{
uint64 timestamp = 1;
string category = 2;
Player assistant = 3;
Player victim = 4;
string weapon = 5;
}
// Occurs when the entire squad in a game has been eliminated
// The event contains all player in said squad. May not occur in certain game modes
message SquadEliminated
{
uint64 timestamp = 1;
string category = 2;
repeated Player players = 3;
}
// Occurs when Gibraltars shield has taken any enemy damage
// The field `damageInflicted` will indicate how much was absorbed by the shield
message GibraltarShieldAbsorbed
{
uint64 timestamp = 1;
string category = 2;
Player attacker = 3;
Player victim = 4;
uint32 damageInflicted = 6;
}
// Occurs when Revenant, while using his Forged Shadows ultimate, takes any enemy damage
// This event is distinct from `PlayerDamaged` since the player may receive no actual damage if the shadow is able to absorb it
// The field `damageInflicted` will indicate how much damage (in total) was dealt
// If there is any leftover damage that goes affects the player, that amount will be what is registered in a different `PlayerDamaged` event
message RevenantForgedShadowDamaged
{
uint64 timestamp = 1;
string category = 2;
Player attacker = 3;
Player victim = 4;
uint32 damageInflicted = 6;
}
/////////////////////////////////////////
// Interaction events
/////////////////////////////////////////
// Sent when a player is respawned and comes back into game
// For example, when using a respawn beacon
message PlayerRespawnTeam
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
repeated Player respawned = 4; // R5R: formerly of type `string`
}
// Occurs when a player finishes assisting a downed player
// May not be sent in certain game modes (e.g. Control)
message PlayerRevive
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
Player revived = 4;
}
// Specific Arenas-only event that occurs when players select an item
message ArenasItemSelected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string item = 4;
int32 quantity = 5;
}
// Specific Arenas-only event that occurs when players deselect an item
message ArenasItemDeselected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string item = 4;
int32 quantity = 5;
}
// Event that occurs when a player has picked up loot into their inventory
message InventoryPickUp
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string item = 4;
int32 quantity = 5;
}
// Event that occurs when a player has dropped loot from their inventory
// The item itself may have attachments that will be described in the `extraData` field
message InventoryDrop
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string item = 4;
int32 quantity = 5;
repeated string extraData = 6;
}
// Used to indicate the player has used a consumable item (e.g. syringe, shield cell) from their inventory
message InventoryUse
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string item = 4;
int32 quantity = 5;
}
// Event used when a teammate banner has been picked up
message BannerCollected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
Player collected = 4;
}
// Used to indicate that the player has activated one of their legend's abilities
// The ability can be a Tactical or an Ultimate and is decribed in the `linkedEntity` field
// For example: `linkedEntity: "Tactical (Eye of the Allfather)"` for Bloodhound's tactical
message PlayerAbilityUsed
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string linkedEntity = 4;
}
// Signals that a player has selected an upgrade at a particular tier level
// Updates to their tier level will be sent as a PlayerUpgradeTierChanged event
message LegendUpgradeSelected
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string upgradeName = 4;
string upgradeDesc = 5;
int32 level = 6;
}
// Indicates that a player has started using the zipline
message ZiplineUsed
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string linkedEntity = 4;
}
// Used to indicate that a player has tossed a grenade
// The `linkedEntity` will describe the grenade in further detail and it may be a legend's Ability
// For example: `linkedEntity: "Ultimate (Rolling Thunder)"` for Bangalore's Ultimate ability
message GrenadeThrown
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string linkedEntity = 4;
}
// Event specifying that a player has picked up loot from Loba's Black Market
// This event may fire in quick succession to the InventoryPickUp event
message BlackMarketAction
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string item = 4;
}
// Used to indicate a player has traversed a Wraith Portal
message WraithPortal
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
}
// Used to indicate a player has traversed a Warp Gate
message WarpGateUsed
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
}
// Used to indicate that a player has used ammo
// This event may not fire immediately and updates may be batched to save bandwidth
message AmmoUsed
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string ammoType = 4;
uint32 amountUsed = 5;
uint32 oldAmmoCount = 6;
uint32 newAmmoCount = 7;
}
// Used to indicate that a player has switched weapons, either to a weapon in their inventory or swapped with a weapon on the ground
message WeaponSwitched
{
uint64 timestamp = 1;
string category = 2;
Player player = 3;
string oldWeapon = 4;
string newWeapon = 5;
}
/////////////////////////////////////////
// Custom events
/////////////////////////////////////////
// Event defining custom user data that is otherwise too specific to create dedicated messages for
message CustomEvent
{
uint64 timestamp = 1;
string category = 2;
repeated google.protobuf.Any customData = 3;
}
//////////////////////////////////////////////////////////////////////
// Input messages:
// Used by observers to programmatically interact with the game
//////////////////////////////////////////////////////////////////////
// Enum used to quickly described the target of a ChangeCamera operation
enum PlayerOfInterest
{
UNSPECIFIED = 0;
// cycle through known Players in a team
NEXT = 1;
PREVIOUS = 2;
// Go to an interesting player
KILL_LEADER = 3;
CLOSEST_ENEMY = 4;
CLOSEST_PLAYER = 5;
LATEST_ATTACKER = 6;
}
// Request to change the observer camera
// If changing by a target's name, be aware that the
// - server may skip the request if the player is not actively in the game (i.e. waiting for reconnect, downed or killed)
// - If the string is longer than 256 characters, the request will fail
message ChangeCamera
{
oneof target
{
// Set the camera to an interesting player (e.g. the Kill Leader)
PlayerOfInterest poi = 1;
// Change camera to a player by name
string name = 2;
}
}
// Request message to toggle pause in a match type that supports it
message PauseToggle
{
float preTimer = 1;
}
// Request to create a custom match lobby
message CustomMatch_CreateLobby
{
}
// Request to join an existing custom match lobby identified by the `roleToken`
message CustomMatch_JoinLobby
{
string roleToken = 1;
}
// Request to leave a custom match lobby
message CustomMatch_LeaveLobby
{
}
// Request to programatically change your player's ready state in a custom match lobby
message CustomMatch_SetReady
{
bool isReady = 1;
}
// Request to retrieve all connected players in a custom match lobby
message CustomMatch_GetLobbyPlayers
{
}
// Request to change the state of matchmaking in a custom match lobby
// When enabled is True, the lobby will attempt to being a match
message CustomMatch_SetMatchmaking
{
bool enabled = 1;
}
// Request to assign a particular player to a specific team
// Note that the `targetHardwareName` and `targetNucleusHash` can be obtained from a prior request to CustomMatch_GetLobbyPlayers
// If the parameters do not match any lobby player, the request is ignored
// The `teamId` is across the entire lobby. Meaning, observers have a teamId of 0 and match players will be teamId of 1 and upwards
message CustomMatch_SetTeam
{
int32 teamId = 1;
string targetHardwareName = 2;
string targetNucleusHash = 3;
}
// Request to remove a player from the currently connected custom match lobby
message CustomMatch_KickPlayer
{
string targetHardwareName = 1;
string targetNucleusHash = 2;
}
// Request to alter the settings of a custom match lobby
// Your request should specify all fields being set with the new value
// For convinience, call `CustomMatch_GetSettings` to get the full state of settings
message CustomMatch_SetSettings
{
string playlistName = 1;
bool adminChat = 2;
bool teamRename = 3;
bool selfAssign = 4;
bool aimAssist = 5;
bool anonMode = 6;
}
// Review all the current settings. This request will be replied to with
// `CustomMatch_SetSettings` from which you can modify and reply with any new values for your convenience
message CustomMatch_GetSettings
{
}
// Request to set the name of a team in custom match lobby
// Requires special access and is subject to text filtering
message CustomMatch_SetTeamName
{
int32 teamId = 1;
string teamName = 2;
}
// Request to programatically send a chat message to the entire custom match lobby
message CustomMatch_SendChat
{
string text = 1;
}
// Envelope message for any Live API request
// This allows a single uniform data structure for requests to be made and for the game to receive them
// Specifically, there is only one possible action per request. You can request an acknowledgement of your request by setting `withAck` to true
// Acknowledgements will come in the form of a Response message. More information can be found with that event
//
// A single example to create a CustomMatch_JoinLobby request in python is as follows
// ```
// req = Request()
// req.customMatch_JoinLobby.roleToken = "<some token>"
// req.withAck = True
// ```
// For more information, consult the Protobuf documentation for your language of choice and look at details regarding the `oneof` field (https://protobuf.dev/programming-guides/proto3/#oneof)
message Request
{
// Receive an acknowledgement of the request having been received
bool withAck = 1;
// Preshared key to use with the request. Only necessary if the connecting game has a preshared key specified through `cl_liveapi_requests_psk`
string preSharedKey = 2;
oneof actions
{
ChangeCamera changeCam = 4;
PauseToggle pauseToggle = 5;
// Custom Match specific requests (reserved 10 -> 30)
CustomMatch_CreateLobby customMatch_CreateLobby = 10;
CustomMatch_JoinLobby customMatch_JoinLobby = 11;
CustomMatch_LeaveLobby customMatch_LeaveLobby = 12;
CustomMatch_SetReady customMatch_SetReady = 13;
CustomMatch_SetMatchmaking customMatch_SetMatchmaking = 14;
CustomMatch_SetTeam customMatch_SetTeam = 15;
CustomMatch_KickPlayer customMatch_KickPlayer = 16;
CustomMatch_SetSettings customMatch_SetSettings = 17;
CustomMatch_SendChat customMatch_SendChat = 18;
CustomMatch_GetLobbyPlayers customMatch_GetLobbyPlayers = 19;
CustomMatch_SetTeamName customMatch_SetTeamName = 20;
CustomMatch_GetSettings customMatch_GetSettings = 21;
}
}
//////////////////////////////////////////////////////////////////////
// Reply messages:
// Used by the game to send data to any connected clients
//////////////////////////////////////////////////////////////////////
import "google/protobuf/any.proto";
// Message used to indicate the status of a request
// Generally, it is used to provide a plain text, detailed response in case of failures or problems
message RequestStatus
{
string status = 1;
}
// Message used to indicate the response to a request made to the API
// Only the requesting part will receive this message and this message is only sent if the request required an acknowledgement by setting `withAck` to true in the Request object
// This message is always sent within a LiveAPIEvent and never on its own to allow any applications to have a uniform method of reading events over the wire
// If `success` is true, it does not mean that the Request has finished or that it was completed correctly. In this case, it means that it was successfully received and contains no issues (it is a well-formed request)
// The `result` field may sometimes be populated to give more context around the request, especially in the case of error
// Refer to the LiveAPIEvent message on how to the the Any field
message Response
{
bool success = 1;
google.protobuf.Any result = 2;
}
// Envelope for all LiveAPI Events
// Any game events or responses to requests will be sent using this message. The specific event or message is stored in the `gameMessage` field
// Before proceeding, familiarize yourself with the proto3 `Any` field type at: https://protobuf.dev/programming-guides/proto3/#any
// In order to read the message successfully, check the type contained in `gameMessage` and create an instance of that type where you can unpack the data to
// Protobuf has several ways of doing type to instance lookups that will allow you to do this after you've generated bindings
// For example, to read and unpack any LiveAPIEvent in Python, the following can be done (assume `pb_msg` contains the LiveAPIEvent object)
// ```
// from events_pb2 import *
// from google.protobuf import symbol_database
// [ ... ]
// result_type = pb_msg.gameMessage.TypeName()
// msg_result = symbol_database.Default().GetSymbol(result_type)()
// pb_msg.gameMessage.Unpack(msg_result) # msg_result now holds the actual event you want to read
// ```
message LiveAPIEvent
{
fixed32 event_size = 1;
google.protobuf.Any gameMessage = 3;
}

@ -1,3 +1,4 @@
protoc64 --cpp_out=. sig_map.proto
protoc64 --cpp_out=. sv_rcon.proto
protoc64 --cpp_out=. cl_rcon.proto
protoc64 --cpp_out=. events.proto