RTech: implement custom events and slight adjustments/improvements

Implemented CustomEvent in code, which supports:
- bool|int|float|string|vector|array|table
- nested arrays and tables, up to a depth of 64

Also improved foundation code for LiveAPI:
- added ability to log liveapi events to a file on the disk (rotates between each match or round, depending on how the abstracted functions are called in scripts)
- when the system is enabled through cvars, code will be invoked on the fly
- when the system is disabled through cvars, the system will be shutdown properly on the fly (properly handling socket closing, log file finishing, etc)
- if the socket system is enabled/disabled on the fly using cvars, related code will be called to initiate or shutdown the connections.

The generated proto.cpp/h file has been moved to the protoc project as it was causing some compiler warnings that we suppress on the thirdparty (vendored) code.
This commit is contained in:
Kawe Mazidjatari 2024-04-03 01:26:53 +02:00
parent 8a3131c550
commit b916e11543
9 changed files with 934 additions and 390 deletions

View File

@ -58,6 +58,7 @@ target_link_libraries( ${PROJECT_NAME} PRIVATE
"vphysics"
"SigCache_Pb"
"LiveAPI_Pb"
"SV_RCon_Pb"
"CL_RCon_Pb"

View File

@ -100,8 +100,6 @@ add_sources( SOURCE_GROUP "Utility"
)
add_sources( SOURCE_GROUP "LiveAPI"
"server/liveapi/events.pb.cc"
"server/liveapi/events.pb.h"
"server/liveapi/liveapi.cpp"
"server/liveapi/liveapi.h"
)

View File

@ -8,7 +8,7 @@
// - Add code callback for player weapon switched ( event WeaponSwitched )
//
//=============================================================================//
#include "tier1/utlsymbol.h"
#include "tier1/depthcounter.h"
#include "vscript/languages/squirrel_re/include/sqtable.h"
#include "vscript/languages/squirrel_re/include/sqarray.h"
#include "game/server/vscript_server.h"
@ -16,8 +16,13 @@
#include "liveapi.h"
#include "engine/sys_utils.h"
#include "events.pb.h"
#include "protobuf/util/json_util.h"
#pragma warning(push)
#pragma warning(disable : 4505)
#include "protoc/events.pb.h"
#pragma warning(pop)
// The total nesting depth cannot exceed this number
#define LIVEAPI_MAX_ITEM_DEPTH 64
/*
@ -50,6 +55,7 @@ static rtech::liveapi::CharacterSelected s_characterSelected;
//static rtech::liveapi::CustomMatch_SetSettings s_customMatch_SetSettings;
//static rtech::liveapi::CustomMatch_SetTeam s_customMatch_SetTeam;
//static rtech::liveapi::CustomMatch_SetTeamName s_customMatch_SetTeamName;
static rtech::liveapi::CustomEvent s_customEvent;
static rtech::liveapi::GameStateChanged s_gameStateChanged;
static rtech::liveapi::GibraltarShieldAbsorbed s_gibraltarShieldAbsorbed;
static rtech::liveapi::GrenadeThrown s_grenadeThrown;
@ -125,7 +131,7 @@ enum class eLiveAPI_EventTypes
//customMatch_SetSettings,
//customMatch_SetTeam,
//customMatch_SetTeamName,
customEvent,
datacenter,
//gameConVar,
gameStateChanged,
@ -221,6 +227,7 @@ static const char* LiveAPI_EventTypeToString(const eLiveAPI_EventTypes eventType
//case eLiveAPI_EventTypes::customMatch_SetSettings: return "customMatch_SetSettings";
//case eLiveAPI_EventTypes::customMatch_SetTeam: return "customMatch_SetTeam";
//case eLiveAPI_EventTypes::customMatch_SetTeamName: return "customMatch_SetTeamName";
case eLiveAPI_EventTypes::customEvent: return "customEvent";
case eLiveAPI_EventTypes::datacenter: return "datacenter";
//case eLiveAPI_EventTypes::gameConVar: return "gameConVar";
case eLiveAPI_EventTypes::gameStateChanged: return "gameStateChanged";
@ -319,9 +326,11 @@ static bool LiveAPI_CheckSwitchType(HSQUIRRELVM const v, const SQObjectPtr& obj)
}
#define LIVEAPI_ENSURE_TYPE(v, obj, expectType, eventMsg, fieldNum) { if (!LiveAPI_EnsureType(v, obj, expectType, eventMsg, fieldNum)) return false; }
#define LIVEAPI_EMPTY_TABLE_ERROR(v, eventMsg) { v_SQVM_RaiseError(v, "Empty table on message \"%s\".", eventMsg->GetTypeName().c_str()); return false; }
#define LIVEAPI_EMPTY_TABLE_ERROR(v, eventMsg) { v_SQVM_RaiseError(v, "Empty iterable on message \"%s\".", eventMsg->GetTypeName().c_str()); return false; }
#define LIVEAPI_FIELD_ERROR(v, fieldNum, eventMsg) { v_SQVM_RaiseError(v, "Field \"%d\" doesn't exist in message \"%s\".", fieldNum, eventMsg->GetTypeName().c_str()); return false; }
#define LIVEAPI_ONEOF_FIELD_ERROR(v, fieldNum, eventMsg) { v_SQVM_RaiseError(v, "Tried to set member \"%d\" of oneof field in message \"%s\" while another has already been set.", fieldNum, eventMsg->GetTypeName().c_str()); return false; }
#define LIVEAPI_UNSUPPORTED_TYPE_ERROR(v, gotType, eventMsg) {v_SQVM_RaiseError(v, "Value type \"%s\" is not supported for message \"%s\".\n", IdType2Name(gotType), eventMsg->GetTypeName().c_str()); return false; }
#define LIVEAPI_CHECK_RECURSION_DEPTH(v, currDepth) { if (currDepth > LIVEAPI_MAX_ITEM_DEPTH) { v_SQVM_RaiseError(v, "Exceeded nesting depth limit of \"%i\".", LIVEAPI_MAX_ITEM_DEPTH); return false; }}
uint64_t GetUnixTimeStamp() // TODO: move elsewhere
{
@ -1743,6 +1752,185 @@ static bool LiveAPI_HandlePlayerStatChanged(HSQUIRRELVM const v, const SQObject&
return true;
}
static void LiveAPI_SetCustomVectorField(google::protobuf::Struct* const structData, const Vector3D* const vecData)
{
google::protobuf::Map<std::string, google::protobuf::Value>* const fieldData = structData->mutable_fields();
(*fieldData)["x"].set_number_value(vecData->x);
(*fieldData)["y"].set_number_value(vecData->y);
(*fieldData)["z"].set_number_value(vecData->z);
}
static bool LiveAPI_SetCustomTableFields(HSQUIRRELVM const v, google::protobuf::Struct* const structData, const SQTable* const tableData);
static bool LiveAPI_SetCustomArrayFields(HSQUIRRELVM const v, google::protobuf::ListValue* const listData, const SQArray* const arrayData);
static int s_currentDepth = 0;
static bool LiveAPI_SetCustomArrayFields(HSQUIRRELVM const v, google::protobuf::ListValue* const listData, const SQArray* const arrayData)
{
CDepthCounter<int> counter(s_currentDepth);
bool ranLoop = false;
for (SQInteger i = 0; i < arrayData->Size(); i++)
{
const SQObject& valueObj = arrayData->_values[i];
if (sq_isnull(valueObj))
continue;
if (!ranLoop)
ranLoop = true;
const SQObjectType valueType = sq_type(valueObj);
switch (valueType)
{
case OT_BOOL:
listData->add_values()->set_bool_value(_bool(valueObj));
break;
case OT_INTEGER:
listData->add_values()->set_number_value(_integer(valueObj));
break;
case OT_FLOAT:
listData->add_values()->set_number_value(_float(valueObj));
break;
case OT_STRING:
listData->add_values()->set_string_value(_string(valueObj)->_val);
break;
case OT_VECTOR:
LiveAPI_SetCustomVectorField(listData->add_values()->mutable_struct_value(), _vector3d(valueObj));
break;
case OT_ARRAY:
LIVEAPI_CHECK_RECURSION_DEPTH(v, counter.Get());
if (arrayData == _array(valueObj))
{
v_SQVM_RaiseError(v, "Attempted to nest array \"%i\" into itself at index \"%i\".", counter.Get(), i);
return false;
}
if (!LiveAPI_SetCustomArrayFields(v, listData->add_values()->mutable_list_value(), _array(valueObj)))
return false;
break;
case OT_TABLE:
LIVEAPI_CHECK_RECURSION_DEPTH(v, counter.Get());
if (!LiveAPI_SetCustomTableFields(v, listData->add_values()->mutable_struct_value(), _table(valueObj)))
return false;
break;
default:
LIVEAPI_UNSUPPORTED_TYPE_ERROR(v, valueType, listData);
}
}
if (!ranLoop)
LIVEAPI_EMPTY_TABLE_ERROR(v, listData);
return true;
}
static bool LiveAPI_SetCustomTableFields(HSQUIRRELVM const v, google::protobuf::Struct* const structData, const SQTable* const tableData)
{
CDepthCounter<int> counter(s_currentDepth);
bool ranLoop = false;
SQ_FOR_EACH_TABLE(tableData, i)
{
const SQTable::_HashNode& node = tableData->_nodes[i];
if (sq_isnull(node.key))
continue;
if (!ranLoop)
ranLoop = true;
const SQObjectType keyType = sq_type(node.key);
if (keyType != OT_STRING)
{
v_SQVM_RaiseError(v, "Key must be a \"%s\", got \"%s\" for message \"%s\" in table \"%i\" at index \"%i\".",
IdType2Name(OT_STRING), IdType2Name(keyType), structData->GetTypeName().c_str(), counter.Get(), i);
return false;
}
const SQObjectType valueType = sq_type(node.val);
switch (valueType)
{
case OT_BOOL:
(*structData->mutable_fields())[_string(node.key)->_val].set_bool_value(_bool(node.val));
break;
case OT_INTEGER:
(*structData->mutable_fields())[_string(node.key)->_val].set_number_value(_integer(node.val));
break;
case OT_FLOAT:
(*structData->mutable_fields())[_string(node.key)->_val].set_number_value(_float(node.val));
break;
case OT_STRING:
(*structData->mutable_fields())[_string(node.key)->_val].set_string_value(_string(node.val)->_val);
break;
case OT_VECTOR:
LiveAPI_SetCustomVectorField((*structData->mutable_fields())[_string(node.key)->_val].mutable_struct_value(), _vector3d(node.val));
break;
case OT_ARRAY:
LIVEAPI_CHECK_RECURSION_DEPTH(v, counter.Get());
if (!LiveAPI_SetCustomArrayFields(v, (*structData->mutable_fields())[_string(node.key)->_val].mutable_list_value(), _array(node.val)))
return false;
break;
case OT_TABLE:
LIVEAPI_CHECK_RECURSION_DEPTH(v, counter.Get());
if (tableData == _table(node.val))
{
v_SQVM_RaiseError(v, "Attempted to nest table \"%i\" into itself at index \"%i\".", counter.Get(), i);
return false;
}
if (!LiveAPI_SetCustomTableFields(v, (*structData->mutable_fields())[_string(node.key)->_val].mutable_struct_value(), _table(node.val)))
return false;
break;
default:
LIVEAPI_UNSUPPORTED_TYPE_ERROR(v, valueType, structData);
}
}
if (!ranLoop)
LIVEAPI_EMPTY_TABLE_ERROR(v, structData);
return true;
}
static bool LiveAPI_HandleCustomEvent(HSQUIRRELVM const v, const SQObject& obj, rtech::liveapi::CustomEvent* const event,
const eLiveAPI_EventTypes eventType, const SQInteger fieldNum)
{
LiveAPI_SetCommonMessageFields(event, eventType);
switch (fieldNum)
{
case rtech::liveapi::CustomEvent::kNameFieldNumber:
LIVEAPI_ENSURE_TYPE(v, obj, OT_STRING, event, fieldNum);
event->set_name(_string(obj)->_val);
break;
case rtech::liveapi::CustomEvent::kDataFieldNumber:
LIVEAPI_ENSURE_TYPE(v, obj, OT_TABLE, event, fieldNum);
if (!LiveAPI_SetCustomTableFields(v, event->mutable_data(), _table(obj)))
return false;
break;
default:
LIVEAPI_FIELD_ERROR(v, fieldNum, event);
}
return true;
}
/*
@ -1757,19 +1945,7 @@ static void LiveAPI_SendEvent(const google::protobuf::Message* const msg)
s_liveAPIEvent.set_event_size(msg->ByteSize());
s_liveAPIEvent.mutable_gamemessage()->PackFrom(*msg);
const string data = s_liveAPIEvent.SerializeAsString();
LiveAPISystem()->LogEvent(data.c_str(), (int)data.size());
std::string jsonStr;
google::protobuf::util::JsonPrintOptions options;
options.add_whitespace = true;
options.always_print_primitive_fields = true;
google::protobuf::util::MessageToJsonString(s_liveAPIEvent, &jsonStr, options);
Msg(eDLL_T::ENGINE, "%s\n", jsonStr.c_str());
LiveAPISystem()->LogEvent(&s_liveAPIEvent, &s_liveAPIEvent.gamemessage());
s_liveAPIEvent.Clear();
}
@ -1818,6 +1994,10 @@ static bool LiveAPI_HandleEventByCategory(HSQUIRRELVM const v, const SQTable* co
msg = &s_bannerCollected;
ret = LiveAPI_HandleBannerCollected(v, obj, &s_bannerCollected, eventType, fieldNum);
break;
case eLiveAPI_EventTypes::customEvent:
msg = &s_customEvent;
ret = LiveAPI_HandleCustomEvent(v, obj, &s_customEvent, eventType, fieldNum);
break;
case eLiveAPI_EventTypes::inventoryPickUp:
msg = &s_inventoryPickUp;
ret = LiveAPI_HandleInventoryChange(v, obj, &s_inventoryPickUp, eventType, fieldNum);
@ -1984,12 +2164,15 @@ namespace VScriptCode
{
SQRESULT LiveAPI_IsValidToRun(HSQUIRRELVM v);
SQRESULT LiveAPI_LogRaw(HSQUIRRELVM v);
SQRESULT LiveAPI_StartLogging(HSQUIRRELVM v);
SQRESULT LiveAPI_StopLogging(HSQUIRRELVM v);
}
}
SQRESULT VScriptCode::Server::LiveAPI_IsValidToRun(HSQUIRRELVM v)
{
sq_pushbool(v, liveapi_enabled.GetBool());
sq_pushbool(v, LiveAPISystem()->IsValidToRun());
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
}
@ -1999,11 +2182,11 @@ SQRESULT VScriptCode::Server::LiveAPI_LogRaw(HSQUIRRELVM v)
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
SQRESULT result = SQ_OK;
SQObjectPtr& object = v->GetUp(-2);
const SQObjectPtr& object = v->GetUp(-2);
if (sq_istable(object))
{
SQTable* const table = object._unVal.pTable;
const SQTable* const table = object._unVal.pTable;
const eLiveAPI_EventTypes eventType = eLiveAPI_EventTypes(sq_getinteger(v, 2));
if (!LiveAPI_HandleEventByCategory(v, table, eventType))
@ -2018,10 +2201,25 @@ SQRESULT VScriptCode::Server::LiveAPI_LogRaw(HSQUIRRELVM v)
SCRIPT_CHECK_AND_RETURN(v, result);
}
SQRESULT VScriptCode::Server::LiveAPI_StartLogging(HSQUIRRELVM v)
{
LiveAPISystem()->CreateLogger();
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
}
SQRESULT VScriptCode::Server::LiveAPI_StopLogging(HSQUIRRELVM v)
{
LiveAPISystem()->DestroyLogger();
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
}
void Script_RegisterLiveAPIFunctions(CSquirrelVM* const s)
{
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, LiveAPI_IsValidToRun, "Whether the LiveAPI system is enabled and able to run", "bool", "");
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, LiveAPI_LogRaw, "VM bridge to the LiveAPI logger from scripts", "void", "table< int, var > data, int eventType");
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, LiveAPI_StartLogging, "Start the LiveAPI session logger", "void", "");
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, LiveAPI_StopLogging, "Stop the LiveAPI session logger", "void", "");
}
void Script_RegisterLiveAPIEnums(CSquirrelVM* const s)
@ -2050,6 +2248,7 @@ void Script_RegisterLiveAPIEnums(CSquirrelVM* const s)
//"customMatch_SetSettings",
//"customMatch_SetTeam",
//"customMatch_SetTeamName",
"customEvent",
"datacenter",
//"gameConVar",
"gameStateChanged",

View File

@ -1,4 +1,16 @@
cmake_minimum_required( VERSION 3.16 )
add_module( "lib" "LiveAPI_Pb" "vpc" ${FOLDER_CONTEXT} FALSE TRUE )
start_sources()
add_sources( SOURCE_GROUP "Runtime"
"events.pb.cc"
"events.pb.h"
)
end_sources()
thirdparty_suppress_warnings()
add_module( "lib" "SigCache_Pb" "vpc" ${FOLDER_CONTEXT} FALSE TRUE )
start_sources()

View File

@ -777,8 +777,9 @@ struct WeaponSwitchedDefaultTypeInternal {
PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 WeaponSwitchedDefaultTypeInternal _WeaponSwitched_default_instance_;
PROTOBUF_CONSTEXPR CustomEvent::CustomEvent(
::_pbi::ConstantInitialized): _impl_{
/*decltype(_impl_.customdata_)*/{}
, /*decltype(_impl_.category_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
/*decltype(_impl_.category_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
, /*decltype(_impl_.name_)*/{&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized{}}
, /*decltype(_impl_.data_)*/nullptr
, /*decltype(_impl_.timestamp_)*/uint64_t{0u}
, /*decltype(_impl_._cached_size_)*/{}} {}
struct CustomEventDefaultTypeInternal {
@ -1531,7 +1532,8 @@ const uint32_t TableStruct_events_2eproto::offsets[] PROTOBUF_SECTION_VARIABLE(p
~0u, // no _inlined_string_donated_
PROTOBUF_FIELD_OFFSET(::rtech::liveapi::CustomEvent, _impl_.timestamp_),
PROTOBUF_FIELD_OFFSET(::rtech::liveapi::CustomEvent, _impl_.category_),
PROTOBUF_FIELD_OFFSET(::rtech::liveapi::CustomEvent, _impl_.customdata_),
PROTOBUF_FIELD_OFFSET(::rtech::liveapi::CustomEvent, _impl_.name_),
PROTOBUF_FIELD_OFFSET(::rtech::liveapi::CustomEvent, _impl_.data_),
~0u, // no _has_bits_
PROTOBUF_FIELD_OFFSET(::rtech::liveapi::ChangeCamera, _internal_metadata_),
~0u, // no _extensions_
@ -1731,24 +1733,24 @@ static const ::_pbi::MigrationSchema schemas[] PROTOBUF_SECTION_VARIABLE(protode
{ 461, -1, -1, sizeof(::rtech::liveapi::AmmoUsed)},
{ 474, -1, -1, sizeof(::rtech::liveapi::WeaponSwitched)},
{ 485, -1, -1, sizeof(::rtech::liveapi::CustomEvent)},
{ 494, -1, -1, sizeof(::rtech::liveapi::ChangeCamera)},
{ 503, -1, -1, sizeof(::rtech::liveapi::PauseToggle)},
{ 510, -1, -1, sizeof(::rtech::liveapi::CustomMatch_CreateLobby)},
{ 516, -1, -1, sizeof(::rtech::liveapi::CustomMatch_JoinLobby)},
{ 523, -1, -1, sizeof(::rtech::liveapi::CustomMatch_LeaveLobby)},
{ 529, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetReady)},
{ 536, -1, -1, sizeof(::rtech::liveapi::CustomMatch_GetLobbyPlayers)},
{ 542, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetMatchmaking)},
{ 549, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetTeam)},
{ 558, -1, -1, sizeof(::rtech::liveapi::CustomMatch_KickPlayer)},
{ 566, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetSettings)},
{ 578, -1, -1, sizeof(::rtech::liveapi::CustomMatch_GetSettings)},
{ 584, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetTeamName)},
{ 592, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SendChat)},
{ 599, -1, -1, sizeof(::rtech::liveapi::Request)},
{ 622, -1, -1, sizeof(::rtech::liveapi::RequestStatus)},
{ 629, -1, -1, sizeof(::rtech::liveapi::Response)},
{ 637, -1, -1, sizeof(::rtech::liveapi::LiveAPIEvent)},
{ 495, -1, -1, sizeof(::rtech::liveapi::ChangeCamera)},
{ 504, -1, -1, sizeof(::rtech::liveapi::PauseToggle)},
{ 511, -1, -1, sizeof(::rtech::liveapi::CustomMatch_CreateLobby)},
{ 517, -1, -1, sizeof(::rtech::liveapi::CustomMatch_JoinLobby)},
{ 524, -1, -1, sizeof(::rtech::liveapi::CustomMatch_LeaveLobby)},
{ 530, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetReady)},
{ 537, -1, -1, sizeof(::rtech::liveapi::CustomMatch_GetLobbyPlayers)},
{ 543, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetMatchmaking)},
{ 550, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetTeam)},
{ 559, -1, -1, sizeof(::rtech::liveapi::CustomMatch_KickPlayer)},
{ 567, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetSettings)},
{ 579, -1, -1, sizeof(::rtech::liveapi::CustomMatch_GetSettings)},
{ 585, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SetTeamName)},
{ 593, -1, -1, sizeof(::rtech::liveapi::CustomMatch_SendChat)},
{ 600, -1, -1, sizeof(::rtech::liveapi::Request)},
{ 623, -1, -1, sizeof(::rtech::liveapi::RequestStatus)},
{ 630, -1, -1, sizeof(::rtech::liveapi::Response)},
{ 638, -1, -1, sizeof(::rtech::liveapi::LiveAPIEvent)},
};
static const ::_pb::Message* const file_default_instances[] = {
@ -1819,224 +1821,227 @@ static const ::_pb::Message* const file_default_instances[] = {
};
const char descriptor_table_protodef_events_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) =
"\n\014events.proto\022\rrtech.liveapi\032\031google/pr"
"otobuf/any.proto\"*\n\007Vector3\022\t\n\001x\030\001 \001(\002\022\t"
"\n\001y\030\002 \001(\002\022\t\n\001z\030\003 \001(\002\"\276\002\n\006Player\022\014\n\004name\030"
"\001 \001(\t\022\016\n\006teamId\030\002 \001(\r\022#\n\003pos\030\003 \001(\0132\026.rte"
"ch.liveapi.Vector3\022&\n\006angles\030\004 \001(\0132\026.rte"
"ch.liveapi.Vector3\022\025\n\rcurrentHealth\030\005 \001("
"\r\022\021\n\tmaxHealth\030\006 \001(\r\022\024\n\014shieldHealth\030\007 \001"
"(\r\022\027\n\017shieldMaxHealth\030\010 \001(\r\022\023\n\013nucleusHa"
"sh\030\t \001(\t\022\024\n\014hardwareName\030\n \001(\t\022\020\n\010teamNa"
"me\030\013 \001(\t\022\022\n\nsquadIndex\030\014 \001(\r\022\021\n\tcharacte"
"r\030\r \001(\t\022\014\n\004skin\030\016 \001(\t\"b\n\027CustomMatch_Lob"
"byPlayer\022\014\n\004name\030\001 \001(\t\022\016\n\006teamId\030\002 \001(\r\022\023"
"\n\013nucleusHash\030\003 \001(\t\022\024\n\014hardwareName\030\004 \001("
"\t\"\?\n\nDatacenter\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010ca"
"tegory\030\002 \001(\t\022\014\n\004name\030\003 \001(\t\"V\n\007Version\022\021\n"
"\tmajor_num\030\001 \001(\r\022\021\n\tminor_num\030\002 \001(\r\022\023\n\013b"
"uild_stamp\030\003 \001(\r\022\020\n\010revision\030\004 \001(\t\"B\n\rIn"
"ventoryItem\022\020\n\010quantity\030\001 \001(\005\022\014\n\004item\030\002 "
"\001(\t\022\021\n\textraData\030\003 \001(\t\"v\n\024LoadoutConfigu"
"ration\022-\n\007weapons\030\001 \003(\0132\034.rtech.liveapi."
"InventoryItem\022/\n\tequipment\030\002 \003(\0132\034.rtech"
".liveapi.InventoryItem\"\214\001\n\004Init\022\021\n\ttimes"
"tamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\023\n\013gameVers"
"ion\030\003 \001(\t\022*\n\napiVersion\030\004 \001(\0132\026.rtech.li"
"veapi.Version\022\020\n\010platform\030\005 \001(\t\022\014\n\004name\030"
"\006 \001(\t\"h\n\030CustomMatch_LobbyPlayers\022\023\n\013pla"
"yerToken\030\001 \001(\t\0227\n\007players\030\002 \003(\0132&.rtech."
"liveapi.CustomMatch_LobbyPlayer\"\262\001\n\020Obse"
"rverSwitched\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010categ"
"ory\030\002 \001(\t\022\'\n\010observer\030\003 \001(\0132\025.rtech.live"
"api.Player\022%\n\006target\030\004 \001(\0132\025.rtech.livea"
"pi.Player\022)\n\ntargetTeam\030\005 \003(\0132\025.rtech.li"
"veapi.Player\"S\n\022ObserverAnnotation\022\021\n\tti"
"mestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\030\n\020annot"
"ationSerial\030\003 \001(\005\"\225\002\n\nMatchSetup\022\021\n\ttime"
"stamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\013\n\003map\030\003 \001"
"(\t\022\024\n\014playlistName\030\004 \001(\t\022\024\n\014playlistDesc"
"\030\005 \001(\t\022-\n\ndatacenter\030\006 \001(\0132\031.rtech.livea"
"pi.Datacenter\022\023\n\013aimAssistOn\030\007 \001(\010\022\025\n\ran"
"onymousMode\030\010 \001(\010\022\020\n\010serverId\030\t \001(\t\022<\n\017s"
"tartingLoadout\030\n \001(\0132#.rtech.liveapi.Loa"
"doutConfiguration\"F\n\020GameStateChanged\022\021\n"
"\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\r\n\005st"
"ate\030\003 \001(\t\"_\n\021CharacterSelected\022\021\n\ttimest"
"amp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 "
"\001(\0132\025.rtech.liveapi.Player\"k\n\rMatchState"
"End\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t"
"\022\r\n\005state\030\003 \001(\t\022&\n\007winners\030\004 \003(\0132\025.rtech"
".liveapi.Player\"\260\001\n\020RingStartClosing\022\021\n\t"
"timestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\r\n\005sta"
"ge\030\003 \001(\r\022&\n\006center\030\004 \001(\0132\026.rtech.liveapi"
".Vector3\022\025\n\rcurrentRadius\030\005 \001(\002\022\021\n\tendRa"
"dius\030\006 \001(\002\022\026\n\016shrinkDuration\030\007 \001(\002\"\240\001\n\023R"
"ingFinishedClosing\022\021\n\ttimestamp\030\001 \001(\004\022\020\n"
"\010category\030\002 \001(\t\022\r\n\005stage\030\003 \001(\r\022&\n\006center"
"\030\004 \001(\0132\026.rtech.liveapi.Vector3\022\025\n\rcurren"
"tRadius\030\005 \001(\002\022\026\n\016shrinkDuration\030\007 \001(\002\"]\n"
"\017PlayerConnected\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010c"
"ategory\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.li"
"veapi.Player\"\207\001\n\022PlayerDisconnected\022\021\n\tt"
"imestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006play"
"er\030\003 \001(\0132\025.rtech.liveapi.Player\022\024\n\014canRe"
"connect\030\004 \001(\010\022\017\n\007isAlive\030\005 \001(\010\"\274\001\n\021Playe"
"rStatChanged\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010categ"
"ory\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveap"
"i.Player\022\020\n\010statName\030\004 \001(\t\022\022\n\010intValue\030\005"
" \001(\rH\000\022\024\n\nfloatValue\030\006 \001(\002H\000\022\023\n\tboolValu"
"e\030\007 \001(\010H\000B\n\n\010newValue\"u\n\030PlayerUpgradeTi"
"erChanged\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category"
"\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.P"
"layer\022\r\n\005level\030\004 \001(\005\"\255\001\n\rPlayerDamaged\022\021"
"\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\'\n\010a"
"ttacker\030\003 \001(\0132\025.rtech.liveapi.Player\022%\n\006"
"victim\030\004 \001(\0132\025.rtech.liveapi.Player\022\016\n\006w"
"eapon\030\005 \001(\t\022\027\n\017damageInflicted\030\006 \001(\r\"\275\001\n"
"\014PlayerKilled\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010cate"
"gory\030\002 \001(\t\022\'\n\010attacker\030\003 \001(\0132\025.rtech.liv"
"eapi.Player\022%\n\006victim\030\004 \001(\0132\025.rtech.live"
"api.Player\022(\n\tawardedTo\030\005 \001(\0132\025.rtech.li"
"veapi.Player\022\016\n\006weapon\030\006 \001(\t\"\223\001\n\014PlayerD"
"owned\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001"
"(\t\022\'\n\010attacker\030\003 \001(\0132\025.rtech.liveapi.Pla"
"yer\022%\n\006victim\030\004 \001(\0132\025.rtech.liveapi.Play"
"er\022\016\n\006weapon\030\005 \001(\t\"\224\001\n\014PlayerAssist\022\021\n\tt"
"imestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022(\n\tassi"
"stant\030\003 \001(\0132\025.rtech.liveapi.Player\022%\n\006vi"
"ctim\030\004 \001(\0132\025.rtech.liveapi.Player\022\016\n\006wea"
"pon\030\005 \001(\t\"^\n\017SquadEliminated\022\021\n\ttimestam"
"p\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022&\n\007players\030\003 \003"
"(\0132\025.rtech.liveapi.Player\"\247\001\n\027GibraltarS"
"hieldAbsorbed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010cate"
"gory\030\002 \001(\t\022\'\n\010attacker\030\003 \001(\0132\025.rtech.liv"
"eapi.Player\022%\n\006victim\030\004 \001(\0132\025.rtech.live"
"api.Player\022\027\n\017damageInflicted\030\006 \001(\r\"\253\001\n\033"
"RevenantForgedShadowDamaged\022\021\n\ttimestamp"
"\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\'\n\010attacker\030\003 \001"
"(\0132\025.rtech.liveapi.Player\022%\n\006victim\030\004 \001("
"\0132\025.rtech.liveapi.Player\022\027\n\017damageInflic"
"ted\030\006 \001(\r\"\211\001\n\021PlayerRespawnTeam\022\021\n\ttimes"
"tamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003"
" \001(\0132\025.rtech.liveapi.Player\022(\n\trespawned"
"\030\004 \003(\0132\025.rtech.liveapi.Player\"\202\001\n\014Player"
"Revive\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 "
"\001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Play"
"er\022&\n\007revived\030\004 \001(\0132\025.rtech.liveapi.Play"
"er\"\200\001\n\022ArenasItemSelected\022\021\n\ttimestamp\030\001"
" \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025"
".rtech.liveapi.Player\022\014\n\004item\030\004 \001(\t\022\020\n\010q"
"uantity\030\005 \001(\005\"\202\001\n\024ArenasItemDeselected\022\021"
"\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006p"
"layer\030\003 \001(\0132\025.rtech.liveapi.Player\022\014\n\004it"
"em\030\004 \001(\t\022\020\n\010quantity\030\005 \001(\005\"}\n\017InventoryP"
"ickUp\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001"
"(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Playe"
"r\022\014\n\004item\030\004 \001(\t\022\020\n\010quantity\030\005 \001(\005\"\216\001\n\rIn"
"ventoryDrop\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010catego"
"ry\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi"
".Player\022\014\n\004item\030\004 \001(\t\022\020\n\010quantity\030\005 \001(\005\022"
"\021\n\textraData\030\006 \003(\t\"z\n\014InventoryUse\022\021\n\tti"
"mestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006playe"
"r\030\003 \001(\0132\025.rtech.liveapi.Player\022\014\n\004item\030\004"
" \001(\t\022\020\n\010quantity\030\005 \001(\005\"\207\001\n\017BannerCollect"
"\n\014events.proto\022\rrtech.liveapi\032\034google/pr"
"otobuf/struct.proto\032\031google/protobuf/any"
".proto\"*\n\007Vector3\022\t\n\001x\030\001 \001(\002\022\t\n\001y\030\002 \001(\002\022"
"\t\n\001z\030\003 \001(\002\"\276\002\n\006Player\022\014\n\004name\030\001 \001(\t\022\016\n\006t"
"eamId\030\002 \001(\r\022#\n\003pos\030\003 \001(\0132\026.rtech.liveapi"
".Vector3\022&\n\006angles\030\004 \001(\0132\026.rtech.liveapi"
".Vector3\022\025\n\rcurrentHealth\030\005 \001(\r\022\021\n\tmaxHe"
"alth\030\006 \001(\r\022\024\n\014shieldHealth\030\007 \001(\r\022\027\n\017shie"
"ldMaxHealth\030\010 \001(\r\022\023\n\013nucleusHash\030\t \001(\t\022\024"
"\n\014hardwareName\030\n \001(\t\022\020\n\010teamName\030\013 \001(\t\022\022"
"\n\nsquadIndex\030\014 \001(\r\022\021\n\tcharacter\030\r \001(\t\022\014\n"
"\004skin\030\016 \001(\t\"b\n\027CustomMatch_LobbyPlayer\022\014"
"\n\004name\030\001 \001(\t\022\016\n\006teamId\030\002 \001(\r\022\023\n\013nucleusH"
"ash\030\003 \001(\t\022\024\n\014hardwareName\030\004 \001(\t\"\?\n\nDatac"
"enter\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001"
"(\t\022\014\n\004name\030\003 \001(\t\"V\n\007Version\022\021\n\tmajor_num"
"\030\001 \001(\r\022\021\n\tminor_num\030\002 \001(\r\022\023\n\013build_stamp"
"\030\003 \001(\r\022\020\n\010revision\030\004 \001(\t\"B\n\rInventoryIte"
"m\022\020\n\010quantity\030\001 \001(\005\022\014\n\004item\030\002 \001(\t\022\021\n\text"
"raData\030\003 \001(\t\"v\n\024LoadoutConfiguration\022-\n\007"
"weapons\030\001 \003(\0132\034.rtech.liveapi.InventoryI"
"tem\022/\n\tequipment\030\002 \003(\0132\034.rtech.liveapi.I"
"nventoryItem\"\214\001\n\004Init\022\021\n\ttimestamp\030\001 \001(\004"
"\022\020\n\010category\030\002 \001(\t\022\023\n\013gameVersion\030\003 \001(\t\022"
"*\n\napiVersion\030\004 \001(\0132\026.rtech.liveapi.Vers"
"ion\022\020\n\010platform\030\005 \001(\t\022\014\n\004name\030\006 \001(\t\"h\n\030C"
"ustomMatch_LobbyPlayers\022\023\n\013playerToken\030\001"
" \001(\t\0227\n\007players\030\002 \003(\0132&.rtech.liveapi.Cu"
"stomMatch_LobbyPlayer\"\262\001\n\020ObserverSwitch"
"ed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022"
"%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Player\022("
"\n\tcollected\030\004 \001(\0132\025.rtech.liveapi.Player"
"\"u\n\021PlayerAbilityUsed\022\021\n\ttimestamp\030\001 \001(\004"
"\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rte"
"ch.liveapi.Player\022\024\n\014linkedEntity\030\004 \001(\t\""
"\234\001\n\025LegendUpgradeSelected\022\021\n\ttimestamp\030\001"
"\'\n\010observer\030\003 \001(\0132\025.rtech.liveapi.Player"
"\022%\n\006target\030\004 \001(\0132\025.rtech.liveapi.Player\022"
")\n\ntargetTeam\030\005 \003(\0132\025.rtech.liveapi.Play"
"er\"S\n\022ObserverAnnotation\022\021\n\ttimestamp\030\001 "
"\001(\004\022\020\n\010category\030\002 \001(\t\022\030\n\020annotationSeria"
"l\030\003 \001(\005\"\225\002\n\nMatchSetup\022\021\n\ttimestamp\030\001 \001("
"\004\022\020\n\010category\030\002 \001(\t\022\013\n\003map\030\003 \001(\t\022\024\n\014play"
"listName\030\004 \001(\t\022\024\n\014playlistDesc\030\005 \001(\t\022-\n\n"
"datacenter\030\006 \001(\0132\031.rtech.liveapi.Datacen"
"ter\022\023\n\013aimAssistOn\030\007 \001(\010\022\025\n\ranonymousMod"
"e\030\010 \001(\010\022\020\n\010serverId\030\t \001(\t\022<\n\017startingLoa"
"dout\030\n \001(\0132#.rtech.liveapi.LoadoutConfig"
"uration\"F\n\020GameStateChanged\022\021\n\ttimestamp"
"\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\r\n\005state\030\003 \001(\t\""
"_\n\021CharacterSelected\022\021\n\ttimestamp\030\001 \001(\004\022"
"\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtec"
"h.liveapi.Player\"k\n\rMatchStateEnd\022\021\n\ttim"
"estamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\r\n\005state\030"
"\003 \001(\t\022&\n\007winners\030\004 \003(\0132\025.rtech.liveapi.P"
"layer\"\260\001\n\020RingStartClosing\022\021\n\ttimestamp\030"
"\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\r\n\005stage\030\003 \001(\r\022&"
"\n\006center\030\004 \001(\0132\026.rtech.liveapi.Vector3\022\025"
"\n\rcurrentRadius\030\005 \001(\002\022\021\n\tendRadius\030\006 \001(\002"
"\022\026\n\016shrinkDuration\030\007 \001(\002\"\240\001\n\023RingFinishe"
"dClosing\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030"
"\002 \001(\t\022\r\n\005stage\030\003 \001(\r\022&\n\006center\030\004 \001(\0132\026.r"
"tech.liveapi.Vector3\022\025\n\rcurrentRadius\030\005 "
"\001(\002\022\026\n\016shrinkDuration\030\007 \001(\002\"]\n\017PlayerCon"
"nected\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 "
"\001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Play"
"er\"\207\001\n\022PlayerDisconnected\022\021\n\ttimestamp\030\001"
" \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025"
".rtech.liveapi.Player\022\023\n\013upgradeName\030\004 \001"
"(\t\022\023\n\013upgradeDesc\030\005 \001(\t\022\r\n\005level\030\006 \001(\005\"o"
"\n\013ZiplineUsed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010cate"
"gory\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.livea"
"pi.Player\022\024\n\014linkedEntity\030\004 \001(\t\"q\n\rGrena"
"deThrown\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030"
"\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Pl"
"ayer\022\024\n\014linkedEntity\030\004 \001(\t\"m\n\021BlackMarke"
"tAction\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002"
" \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Pla"
"yer\022\014\n\004item\030\004 \001(\t\"Z\n\014WraithPortal\022\021\n\ttim"
"estamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player"
"\030\003 \001(\0132\025.rtech.liveapi.Player\"Z\n\014WarpGat"
"eUsed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001"
"(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Playe"
"r\"\250\001\n\010AmmoUsed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010cat"
"egory\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.live"
"api.Player\022\020\n\010ammoType\030\004 \001(\t\022\022\n\namountUs"
"ed\030\005 \001(\r\022\024\n\014oldAmmoCount\030\006 \001(\r\022\024\n\014newAmm"
"oCount\030\007 \001(\r\"\202\001\n\016WeaponSwitched\022\021\n\ttimes"
"tamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003"
" \001(\0132\025.rtech.liveapi.Player\022\021\n\toldWeapon"
"\030\004 \001(\t\022\021\n\tnewWeapon\030\005 \001(\t\"\\\n\013CustomEvent"
"\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022(\n"
"\ncustomData\030\003 \003(\0132\024.google.protobuf.Any\""
"X\n\014ChangeCamera\022.\n\003poi\030\001 \001(\0162\037.rtech.liv"
"eapi.PlayerOfInterestH\000\022\016\n\004name\030\002 \001(\tH\000B"
"\010\n\006target\"\037\n\013PauseToggle\022\020\n\010preTimer\030\001 \001"
"(\002\"\031\n\027CustomMatch_CreateLobby\"*\n\025CustomM"
"atch_JoinLobby\022\021\n\troleToken\030\001 \001(\t\"\030\n\026Cus"
"tomMatch_LeaveLobby\"\'\n\024CustomMatch_SetRe"
"ady\022\017\n\007isReady\030\001 \001(\010\"\035\n\033CustomMatch_GetL"
"obbyPlayers\"-\n\032CustomMatch_SetMatchmakin"
"g\022\017\n\007enabled\030\001 \001(\010\"\\\n\023CustomMatch_SetTea"
"m\022\016\n\006teamId\030\001 \001(\005\022\032\n\022targetHardwareName\030"
"\002 \001(\t\022\031\n\021targetNucleusHash\030\003 \001(\t\"O\n\026Cust"
"omMatch_KickPlayer\022\032\n\022targetHardwareName"
"\030\001 \001(\t\022\031\n\021targetNucleusHash\030\002 \001(\t\"\217\001\n\027Cu"
"stomMatch_SetSettings\022\024\n\014playlistName\030\001 "
"\001(\t\022\021\n\tadminChat\030\002 \001(\010\022\022\n\nteamRename\030\003 \001"
"(\010\022\022\n\nselfAssign\030\004 \001(\010\022\021\n\taimAssist\030\005 \001("
"\010\022\020\n\010anonMode\030\006 \001(\010\"\031\n\027CustomMatch_GetSe"
"ttings\";\n\027CustomMatch_SetTeamName\022\016\n\006tea"
"mId\030\001 \001(\005\022\020\n\010teamName\030\002 \001(\t\"$\n\024CustomMat"
"ch_SendChat\022\014\n\004text\030\001 \001(\t\"\226\010\n\007Request\022\017\n"
"\007withAck\030\001 \001(\010\022\024\n\014preSharedKey\030\002 \001(\t\0220\n\t"
"changeCam\030\004 \001(\0132\033.rtech.liveapi.ChangeCa"
"meraH\000\0221\n\013pauseToggle\030\005 \001(\0132\032.rtech.live"
"api.PauseToggleH\000\022I\n\027customMatch_CreateL"
"obby\030\n \001(\0132&.rtech.liveapi.CustomMatch_C"
"reateLobbyH\000\022E\n\025customMatch_JoinLobby\030\013 "
"\001(\0132$.rtech.liveapi.CustomMatch_JoinLobb"
"yH\000\022G\n\026customMatch_LeaveLobby\030\014 \001(\0132%.rt"
"ech.liveapi.CustomMatch_LeaveLobbyH\000\022C\n\024"
"customMatch_SetReady\030\r \001(\0132#.rtech.livea"
"pi.CustomMatch_SetReadyH\000\022O\n\032customMatch"
"_SetMatchmaking\030\016 \001(\0132).rtech.liveapi.Cu"
"stomMatch_SetMatchmakingH\000\022A\n\023customMatc"
"h_SetTeam\030\017 \001(\0132\".rtech.liveapi.CustomMa"
"tch_SetTeamH\000\022G\n\026customMatch_KickPlayer\030"
"\020 \001(\0132%.rtech.liveapi.CustomMatch_KickPl"
"ayerH\000\022I\n\027customMatch_SetSettings\030\021 \001(\0132"
"&.rtech.liveapi.CustomMatch_SetSettingsH"
"\000\022C\n\024customMatch_SendChat\030\022 \001(\0132#.rtech."
"liveapi.CustomMatch_SendChatH\000\022Q\n\033custom"
"Match_GetLobbyPlayers\030\023 \001(\0132*.rtech.live"
"api.CustomMatch_GetLobbyPlayersH\000\022I\n\027cus"
"tomMatch_SetTeamName\030\024 \001(\0132&.rtech.livea"
"pi.CustomMatch_SetTeamNameH\000\022I\n\027customMa"
"tch_GetSettings\030\025 \001(\0132&.rtech.liveapi.Cu"
"stomMatch_GetSettingsH\000B\t\n\007actions\"\037\n\rRe"
"questStatus\022\016\n\006status\030\001 \001(\t\"A\n\010Response\022"
"\017\n\007success\030\001 \001(\010\022$\n\006result\030\002 \001(\0132\024.googl"
"e.protobuf.Any\"M\n\014LiveAPIEvent\022\022\n\nevent_"
"size\030\001 \001(\007\022)\n\013gameMessage\030\003 \001(\0132\024.google"
".protobuf.Any*\210\001\n\020PlayerOfInterest\022\017\n\013UN"
"SPECIFIED\020\000\022\010\n\004NEXT\020\001\022\014\n\010PREVIOUS\020\002\022\017\n\013K"
"ILL_LEADER\020\003\022\021\n\rCLOSEST_ENEMY\020\004\022\022\n\016CLOSE"
"ST_PLAYER\020\005\022\023\n\017LATEST_ATTACKER\020\006b\006proto3"
".rtech.liveapi.Player\022\024\n\014canReconnect\030\004 "
"\001(\010\022\017\n\007isAlive\030\005 \001(\010\"\274\001\n\021PlayerStatChang"
"ed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022"
"%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Player\022\020"
"\n\010statName\030\004 \001(\t\022\022\n\010intValue\030\005 \001(\rH\000\022\024\n\n"
"floatValue\030\006 \001(\002H\000\022\023\n\tboolValue\030\007 \001(\010H\000B"
"\n\n\010newValue\"u\n\030PlayerUpgradeTierChanged\022"
"\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006"
"player\030\003 \001(\0132\025.rtech.liveapi.Player\022\r\n\005l"
"evel\030\004 \001(\005\"\255\001\n\rPlayerDamaged\022\021\n\ttimestam"
"p\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\'\n\010attacker\030\003 "
"\001(\0132\025.rtech.liveapi.Player\022%\n\006victim\030\004 \001"
"(\0132\025.rtech.liveapi.Player\022\016\n\006weapon\030\005 \001("
"\t\022\027\n\017damageInflicted\030\006 \001(\r\"\275\001\n\014PlayerKil"
"led\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t"
"\022\'\n\010attacker\030\003 \001(\0132\025.rtech.liveapi.Playe"
"r\022%\n\006victim\030\004 \001(\0132\025.rtech.liveapi.Player"
"\022(\n\tawardedTo\030\005 \001(\0132\025.rtech.liveapi.Play"
"er\022\016\n\006weapon\030\006 \001(\t\"\223\001\n\014PlayerDowned\022\021\n\tt"
"imestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\'\n\010atta"
"cker\030\003 \001(\0132\025.rtech.liveapi.Player\022%\n\006vic"
"tim\030\004 \001(\0132\025.rtech.liveapi.Player\022\016\n\006weap"
"on\030\005 \001(\t\"\224\001\n\014PlayerAssist\022\021\n\ttimestamp\030\001"
" \001(\004\022\020\n\010category\030\002 \001(\t\022(\n\tassistant\030\003 \001("
"\0132\025.rtech.liveapi.Player\022%\n\006victim\030\004 \001(\013"
"2\025.rtech.liveapi.Player\022\016\n\006weapon\030\005 \001(\t\""
"^\n\017SquadEliminated\022\021\n\ttimestamp\030\001 \001(\004\022\020\n"
"\010category\030\002 \001(\t\022&\n\007players\030\003 \003(\0132\025.rtech"
".liveapi.Player\"\247\001\n\027GibraltarShieldAbsor"
"bed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t"
"\022\'\n\010attacker\030\003 \001(\0132\025.rtech.liveapi.Playe"
"r\022%\n\006victim\030\004 \001(\0132\025.rtech.liveapi.Player"
"\022\027\n\017damageInflicted\030\006 \001(\r\"\253\001\n\033RevenantFo"
"rgedShadowDamaged\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010"
"category\030\002 \001(\t\022\'\n\010attacker\030\003 \001(\0132\025.rtech"
".liveapi.Player\022%\n\006victim\030\004 \001(\0132\025.rtech."
"liveapi.Player\022\027\n\017damageInflicted\030\006 \001(\r\""
"\211\001\n\021PlayerRespawnTeam\022\021\n\ttimestamp\030\001 \001(\004"
"\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rte"
"ch.liveapi.Player\022(\n\trespawned\030\004 \003(\0132\025.r"
"tech.liveapi.Player\"\202\001\n\014PlayerRevive\022\021\n\t"
"timestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006pla"
"yer\030\003 \001(\0132\025.rtech.liveapi.Player\022&\n\007revi"
"ved\030\004 \001(\0132\025.rtech.liveapi.Player\"\200\001\n\022Are"
"nasItemSelected\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010ca"
"tegory\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liv"
"eapi.Player\022\014\n\004item\030\004 \001(\t\022\020\n\010quantity\030\005 "
"\001(\005\"\202\001\n\024ArenasItemDeselected\022\021\n\ttimestam"
"p\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001("
"\0132\025.rtech.liveapi.Player\022\014\n\004item\030\004 \001(\t\022\020"
"\n\010quantity\030\005 \001(\005\"}\n\017InventoryPickUp\022\021\n\tt"
"imestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006play"
"er\030\003 \001(\0132\025.rtech.liveapi.Player\022\014\n\004item\030"
"\004 \001(\t\022\020\n\010quantity\030\005 \001(\005\"\216\001\n\rInventoryDro"
"p\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%"
"\n\006player\030\003 \001(\0132\025.rtech.liveapi.Player\022\014\n"
"\004item\030\004 \001(\t\022\020\n\010quantity\030\005 \001(\005\022\021\n\textraDa"
"ta\030\006 \003(\t\"z\n\014InventoryUse\022\021\n\ttimestamp\030\001 "
"\001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025."
"rtech.liveapi.Player\022\014\n\004item\030\004 \001(\t\022\020\n\010qu"
"antity\030\005 \001(\005\"\207\001\n\017BannerCollected\022\021\n\ttime"
"stamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030"
"\003 \001(\0132\025.rtech.liveapi.Player\022(\n\tcollecte"
"d\030\004 \001(\0132\025.rtech.liveapi.Player\"u\n\021Player"
"AbilityUsed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010catego"
"ry\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi"
".Player\022\024\n\014linkedEntity\030\004 \001(\t\"\234\001\n\025Legend"
"UpgradeSelected\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010ca"
"tegory\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rtech.liv"
"eapi.Player\022\023\n\013upgradeName\030\004 \001(\t\022\023\n\013upgr"
"adeDesc\030\005 \001(\t\022\r\n\005level\030\006 \001(\005\"o\n\013ZiplineU"
"sed\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t"
"\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Player\022"
"\024\n\014linkedEntity\030\004 \001(\t\"q\n\rGrenadeThrown\022\021"
"\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006p"
"layer\030\003 \001(\0132\025.rtech.liveapi.Player\022\024\n\014li"
"nkedEntity\030\004 \001(\t\"m\n\021BlackMarketAction\022\021\n"
"\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006pl"
"ayer\030\003 \001(\0132\025.rtech.liveapi.Player\022\014\n\004ite"
"m\030\004 \001(\t\"Z\n\014WraithPortal\022\021\n\ttimestamp\030\001 \001"
"(\004\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.r"
"tech.liveapi.Player\"Z\n\014WarpGateUsed\022\021\n\tt"
"imestamp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022%\n\006play"
"er\030\003 \001(\0132\025.rtech.liveapi.Player\"\250\001\n\010Ammo"
"Used\022\021\n\ttimestamp\030\001 \001(\004\022\020\n\010category\030\002 \001("
"\t\022%\n\006player\030\003 \001(\0132\025.rtech.liveapi.Player"
"\022\020\n\010ammoType\030\004 \001(\t\022\022\n\namountUsed\030\005 \001(\r\022\024"
"\n\014oldAmmoCount\030\006 \001(\r\022\024\n\014newAmmoCount\030\007 \001"
"(\r\"\202\001\n\016WeaponSwitched\022\021\n\ttimestamp\030\001 \001(\004"
"\022\020\n\010category\030\002 \001(\t\022%\n\006player\030\003 \001(\0132\025.rte"
"ch.liveapi.Player\022\021\n\toldWeapon\030\004 \001(\t\022\021\n\t"
"newWeapon\030\005 \001(\t\"g\n\013CustomEvent\022\021\n\ttimest"
"amp\030\001 \001(\004\022\020\n\010category\030\002 \001(\t\022\014\n\004name\030\003 \001("
"\t\022%\n\004data\030\004 \001(\0132\027.google.protobuf.Struct"
"\"X\n\014ChangeCamera\022.\n\003poi\030\001 \001(\0162\037.rtech.li"
"veapi.PlayerOfInterestH\000\022\016\n\004name\030\002 \001(\tH\000"
"B\010\n\006target\"\037\n\013PauseToggle\022\020\n\010preTimer\030\001 "
"\001(\002\"\031\n\027CustomMatch_CreateLobby\"*\n\025Custom"
"Match_JoinLobby\022\021\n\troleToken\030\001 \001(\t\"\030\n\026Cu"
"stomMatch_LeaveLobby\"\'\n\024CustomMatch_SetR"
"eady\022\017\n\007isReady\030\001 \001(\010\"\035\n\033CustomMatch_Get"
"LobbyPlayers\"-\n\032CustomMatch_SetMatchmaki"
"ng\022\017\n\007enabled\030\001 \001(\010\"\\\n\023CustomMatch_SetTe"
"am\022\016\n\006teamId\030\001 \001(\005\022\032\n\022targetHardwareName"
"\030\002 \001(\t\022\031\n\021targetNucleusHash\030\003 \001(\t\"O\n\026Cus"
"tomMatch_KickPlayer\022\032\n\022targetHardwareNam"
"e\030\001 \001(\t\022\031\n\021targetNucleusHash\030\002 \001(\t\"\217\001\n\027C"
"ustomMatch_SetSettings\022\024\n\014playlistName\030\001"
" \001(\t\022\021\n\tadminChat\030\002 \001(\010\022\022\n\nteamRename\030\003 "
"\001(\010\022\022\n\nselfAssign\030\004 \001(\010\022\021\n\taimAssist\030\005 \001"
"(\010\022\020\n\010anonMode\030\006 \001(\010\"\031\n\027CustomMatch_GetS"
"ettings\";\n\027CustomMatch_SetTeamName\022\016\n\006te"
"amId\030\001 \001(\005\022\020\n\010teamName\030\002 \001(\t\"$\n\024CustomMa"
"tch_SendChat\022\014\n\004text\030\001 \001(\t\"\226\010\n\007Request\022\017"
"\n\007withAck\030\001 \001(\010\022\024\n\014preSharedKey\030\002 \001(\t\0220\n"
"\tchangeCam\030\004 \001(\0132\033.rtech.liveapi.ChangeC"
"ameraH\000\0221\n\013pauseToggle\030\005 \001(\0132\032.rtech.liv"
"eapi.PauseToggleH\000\022I\n\027customMatch_Create"
"Lobby\030\n \001(\0132&.rtech.liveapi.CustomMatch_"
"CreateLobbyH\000\022E\n\025customMatch_JoinLobby\030\013"
" \001(\0132$.rtech.liveapi.CustomMatch_JoinLob"
"byH\000\022G\n\026customMatch_LeaveLobby\030\014 \001(\0132%.r"
"tech.liveapi.CustomMatch_LeaveLobbyH\000\022C\n"
"\024customMatch_SetReady\030\r \001(\0132#.rtech.live"
"api.CustomMatch_SetReadyH\000\022O\n\032customMatc"
"h_SetMatchmaking\030\016 \001(\0132).rtech.liveapi.C"
"ustomMatch_SetMatchmakingH\000\022A\n\023customMat"
"ch_SetTeam\030\017 \001(\0132\".rtech.liveapi.CustomM"
"atch_SetTeamH\000\022G\n\026customMatch_KickPlayer"
"\030\020 \001(\0132%.rtech.liveapi.CustomMatch_KickP"
"layerH\000\022I\n\027customMatch_SetSettings\030\021 \001(\013"
"2&.rtech.liveapi.CustomMatch_SetSettings"
"H\000\022C\n\024customMatch_SendChat\030\022 \001(\0132#.rtech"
".liveapi.CustomMatch_SendChatH\000\022Q\n\033custo"
"mMatch_GetLobbyPlayers\030\023 \001(\0132*.rtech.liv"
"eapi.CustomMatch_GetLobbyPlayersH\000\022I\n\027cu"
"stomMatch_SetTeamName\030\024 \001(\0132&.rtech.live"
"api.CustomMatch_SetTeamNameH\000\022I\n\027customM"
"atch_GetSettings\030\025 \001(\0132&.rtech.liveapi.C"
"ustomMatch_GetSettingsH\000B\t\n\007actions\"\037\n\rR"
"equestStatus\022\016\n\006status\030\001 \001(\t\"A\n\010Response"
"\022\017\n\007success\030\001 \001(\010\022$\n\006result\030\002 \001(\0132\024.goog"
"le.protobuf.Any\"M\n\014LiveAPIEvent\022\022\n\nevent"
"_size\030\001 \001(\007\022)\n\013gameMessage\030\003 \001(\0132\024.googl"
"e.protobuf.Any*\210\001\n\020PlayerOfInterest\022\017\n\013U"
"NSPECIFIED\020\000\022\010\n\004NEXT\020\001\022\014\n\010PREVIOUS\020\002\022\017\n\013"
"KILL_LEADER\020\003\022\021\n\rCLOSEST_ENEMY\020\004\022\022\n\016CLOS"
"EST_PLAYER\020\005\022\023\n\017LATEST_ATTACKER\020\006b\006proto"
"3"
;
static const ::_pbi::DescriptorTable* const descriptor_table_events_2eproto_deps[1] = {
static const ::_pbi::DescriptorTable* const descriptor_table_events_2eproto_deps[2] = {
&::descriptor_table_google_2fprotobuf_2fany_2eproto,
&::descriptor_table_google_2fprotobuf_2fstruct_2eproto,
};
static ::_pbi::once_flag descriptor_table_events_2eproto_once;
const ::_pbi::DescriptorTable descriptor_table_events_2eproto = {
false, false, 8360, descriptor_table_protodef_events_2eproto,
false, false, 8401, descriptor_table_protodef_events_2eproto,
"events.proto",
&descriptor_table_events_2eproto_once, descriptor_table_events_2eproto_deps, 1, 64,
&descriptor_table_events_2eproto_once, descriptor_table_events_2eproto_deps, 2, 64,
schemas, file_default_instances, TableStruct_events_2eproto::offsets,
file_level_metadata_events_2eproto, file_level_enum_descriptors_events_2eproto,
file_level_service_descriptors_events_2eproto,
@ -17582,10 +17587,18 @@ void WeaponSwitched::InternalSwap(WeaponSwitched* other) {
class CustomEvent::_Internal {
public:
static const ::PROTOBUF_NAMESPACE_ID::Struct& data(const CustomEvent* msg);
};
void CustomEvent::clear_customdata() {
_impl_.customdata_.Clear();
const ::PROTOBUF_NAMESPACE_ID::Struct&
CustomEvent::_Internal::data(const CustomEvent* msg) {
return *msg->_impl_.data_;
}
void CustomEvent::clear_data() {
if (GetArenaForAllocation() == nullptr && _impl_.data_ != nullptr) {
delete _impl_.data_;
}
_impl_.data_ = nullptr;
}
CustomEvent::CustomEvent(::PROTOBUF_NAMESPACE_ID::Arena* arena,
bool is_message_owned)
@ -17597,8 +17610,9 @@ CustomEvent::CustomEvent(const CustomEvent& from)
: ::PROTOBUF_NAMESPACE_ID::Message() {
CustomEvent* const _this = this; (void)_this;
new (&_impl_) Impl_{
decltype(_impl_.customdata_){from._impl_.customdata_}
, decltype(_impl_.category_){}
decltype(_impl_.category_){}
, decltype(_impl_.name_){}
, decltype(_impl_.data_){nullptr}
, decltype(_impl_.timestamp_){}
, /*decltype(_impl_._cached_size_)*/{}};
@ -17611,6 +17625,17 @@ CustomEvent::CustomEvent(const CustomEvent& from)
_this->_impl_.category_.Set(from._internal_category(),
_this->GetArenaForAllocation());
}
_impl_.name_.InitDefault();
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
_impl_.name_.Set("", GetArenaForAllocation());
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
if (!from._internal_name().empty()) {
_this->_impl_.name_.Set(from._internal_name(),
_this->GetArenaForAllocation());
}
if (from._internal_has_data()) {
_this->_impl_.data_ = new ::PROTOBUF_NAMESPACE_ID::Struct(*from._impl_.data_);
}
_this->_impl_.timestamp_ = from._impl_.timestamp_;
// @@protoc_insertion_point(copy_constructor:rtech.liveapi.CustomEvent)
}
@ -17620,8 +17645,9 @@ inline void CustomEvent::SharedCtor(
(void)arena;
(void)is_message_owned;
new (&_impl_) Impl_{
decltype(_impl_.customdata_){arena}
, decltype(_impl_.category_){}
decltype(_impl_.category_){}
, decltype(_impl_.name_){}
, decltype(_impl_.data_){nullptr}
, decltype(_impl_.timestamp_){uint64_t{0u}}
, /*decltype(_impl_._cached_size_)*/{}
};
@ -17629,6 +17655,10 @@ inline void CustomEvent::SharedCtor(
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
_impl_.category_.Set("", GetArenaForAllocation());
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
_impl_.name_.InitDefault();
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
_impl_.name_.Set("", GetArenaForAllocation());
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
}
CustomEvent::~CustomEvent() {
@ -17642,8 +17672,9 @@ CustomEvent::~CustomEvent() {
inline void CustomEvent::SharedDtor() {
GOOGLE_DCHECK(GetArenaForAllocation() == nullptr);
_impl_.customdata_.~RepeatedPtrField();
_impl_.category_.Destroy();
_impl_.name_.Destroy();
if (this != internal_default_instance()) delete _impl_.data_;
}
void CustomEvent::SetCachedSize(int size) const {
@ -17656,8 +17687,12 @@ void CustomEvent::Clear() {
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
_impl_.customdata_.Clear();
_impl_.category_.ClearToEmpty();
_impl_.name_.ClearToEmpty();
if (GetArenaForAllocation() == nullptr && _impl_.data_ != nullptr) {
delete _impl_.data_;
}
_impl_.data_ = nullptr;
_impl_.timestamp_ = uint64_t{0u};
_internal_metadata_.Clear<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
}
@ -17686,16 +17721,21 @@ const char* CustomEvent::_InternalParse(const char* ptr, ::_pbi::ParseContext* c
} else
goto handle_unusual;
continue;
// repeated .google.protobuf.Any customData = 3;
// string name = 3;
case 3:
if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 26)) {
ptr -= 1;
do {
ptr += 1;
ptr = ctx->ParseMessage(_internal_add_customdata(), ptr);
CHK_(ptr);
if (!ctx->DataAvailable(ptr)) break;
} while (::PROTOBUF_NAMESPACE_ID::internal::ExpectTag<26>(ptr));
auto str = _internal_mutable_name();
ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
CHK_(ptr);
CHK_(::_pbi::VerifyUTF8(str, "rtech.liveapi.CustomEvent.name"));
} else
goto handle_unusual;
continue;
// .google.protobuf.Struct data = 4;
case 4:
if (PROTOBUF_PREDICT_TRUE(static_cast<uint8_t>(tag) == 34)) {
ptr = ctx->ParseMessage(_internal_mutable_data(), ptr);
CHK_(ptr);
} else
goto handle_unusual;
continue;
@ -17744,12 +17784,21 @@ uint8_t* CustomEvent::_InternalSerialize(
2, this->_internal_category(), target);
}
// repeated .google.protobuf.Any customData = 3;
for (unsigned i = 0,
n = static_cast<unsigned>(this->_internal_customdata_size()); i < n; i++) {
const auto& repfield = this->_internal_customdata(i);
// string name = 3;
if (!this->_internal_name().empty()) {
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
this->_internal_name().data(), static_cast<int>(this->_internal_name().length()),
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE,
"rtech.liveapi.CustomEvent.name");
target = stream->WriteStringMaybeAliased(
3, this->_internal_name(), target);
}
// .google.protobuf.Struct data = 4;
if (this->_internal_has_data()) {
target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
InternalWriteMessage(3, repfield, repfield.GetCachedSize(), target, stream);
InternalWriteMessage(4, _Internal::data(this),
_Internal::data(this).GetCachedSize(), target, stream);
}
if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
@ -17768,13 +17817,6 @@ size_t CustomEvent::ByteSizeLong() const {
// Prevent compiler warnings about cached_has_bits being unused
(void) cached_has_bits;
// repeated .google.protobuf.Any customData = 3;
total_size += 1UL * this->_internal_customdata_size();
for (const auto& msg : this->_impl_.customdata_) {
total_size +=
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(msg);
}
// string category = 2;
if (!this->_internal_category().empty()) {
total_size += 1 +
@ -17782,6 +17824,20 @@ size_t CustomEvent::ByteSizeLong() const {
this->_internal_category());
}
// string name = 3;
if (!this->_internal_name().empty()) {
total_size += 1 +
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
this->_internal_name());
}
// .google.protobuf.Struct data = 4;
if (this->_internal_has_data()) {
total_size += 1 +
::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::MessageSize(
*_impl_.data_);
}
// uint64 timestamp = 1;
if (this->_internal_timestamp() != 0) {
total_size += ::_pbi::WireFormatLite::UInt64SizePlusOne(this->_internal_timestamp());
@ -17805,10 +17861,16 @@ void CustomEvent::MergeImpl(::PROTOBUF_NAMESPACE_ID::Message& to_msg, const ::PR
uint32_t cached_has_bits = 0;
(void) cached_has_bits;
_this->_impl_.customdata_.MergeFrom(from._impl_.customdata_);
if (!from._internal_category().empty()) {
_this->_internal_set_category(from._internal_category());
}
if (!from._internal_name().empty()) {
_this->_internal_set_name(from._internal_name());
}
if (from._internal_has_data()) {
_this->_internal_mutable_data()->::PROTOBUF_NAMESPACE_ID::Struct::MergeFrom(
from._internal_data());
}
if (from._internal_timestamp() != 0) {
_this->_internal_set_timestamp(from._internal_timestamp());
}
@ -17831,12 +17893,20 @@ void CustomEvent::InternalSwap(CustomEvent* other) {
auto* lhs_arena = GetArenaForAllocation();
auto* rhs_arena = other->GetArenaForAllocation();
_internal_metadata_.InternalSwap(&other->_internal_metadata_);
_impl_.customdata_.InternalSwap(&other->_impl_.customdata_);
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
&_impl_.category_, lhs_arena,
&other->_impl_.category_, rhs_arena
);
swap(_impl_.timestamp_, other->_impl_.timestamp_);
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr::InternalSwap(
&_impl_.name_, lhs_arena,
&other->_impl_.name_, rhs_arena
);
::PROTOBUF_NAMESPACE_ID::internal::memswap<
PROTOBUF_FIELD_OFFSET(CustomEvent, _impl_.timestamp_)
+ sizeof(CustomEvent::_impl_.timestamp_)
- PROTOBUF_FIELD_OFFSET(CustomEvent, _impl_.data_)>(
reinterpret_cast<char*>(&_impl_.data_),
reinterpret_cast<char*>(&other->_impl_.data_));
}
::PROTOBUF_NAMESPACE_ID::Metadata CustomEvent::GetMetadata() const {

View File

@ -32,6 +32,7 @@
#include <thirdparty/protobuf/extension_set.h> // IWYU pragma: export
#include <thirdparty/protobuf/generated_enum_reflection.h>
#include <thirdparty/protobuf/unknown_field_set.h>
#include <thirdparty/protobuf/struct.pb.h>
#include <thirdparty/protobuf/any.pb.h>
// @@protoc_insertion_point(includes)
#include <thirdparty/protobuf/port_def.inc>
@ -9909,28 +9910,11 @@ class CustomEvent final :
// accessors -------------------------------------------------------
enum : int {
kCustomDataFieldNumber = 3,
kCategoryFieldNumber = 2,
kNameFieldNumber = 3,
kDataFieldNumber = 4,
kTimestampFieldNumber = 1,
};
// repeated .google.protobuf.Any customData = 3;
int customdata_size() const;
private:
int _internal_customdata_size() const;
public:
void clear_customdata();
::PROTOBUF_NAMESPACE_ID::Any* mutable_customdata(int index);
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Any >*
mutable_customdata();
private:
const ::PROTOBUF_NAMESPACE_ID::Any& _internal_customdata(int index) const;
::PROTOBUF_NAMESPACE_ID::Any* _internal_add_customdata();
public:
const ::PROTOBUF_NAMESPACE_ID::Any& customdata(int index) const;
::PROTOBUF_NAMESPACE_ID::Any* add_customdata();
const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Any >&
customdata() const;
// string category = 2;
void clear_category();
const std::string& category() const;
@ -9945,6 +9929,38 @@ class CustomEvent final :
std::string* _internal_mutable_category();
public:
// string name = 3;
void clear_name();
const std::string& name() const;
template <typename ArgT0 = const std::string&, typename... ArgT>
void set_name(ArgT0&& arg0, ArgT... args);
std::string* mutable_name();
PROTOBUF_NODISCARD std::string* release_name();
void set_allocated_name(std::string* name);
private:
const std::string& _internal_name() const;
inline PROTOBUF_ALWAYS_INLINE void _internal_set_name(const std::string& value);
std::string* _internal_mutable_name();
public:
// .google.protobuf.Struct data = 4;
bool has_data() const;
private:
bool _internal_has_data() const;
public:
void clear_data();
const ::PROTOBUF_NAMESPACE_ID::Struct& data() const;
PROTOBUF_NODISCARD ::PROTOBUF_NAMESPACE_ID::Struct* release_data();
::PROTOBUF_NAMESPACE_ID::Struct* mutable_data();
void set_allocated_data(::PROTOBUF_NAMESPACE_ID::Struct* data);
private:
const ::PROTOBUF_NAMESPACE_ID::Struct& _internal_data() const;
::PROTOBUF_NAMESPACE_ID::Struct* _internal_mutable_data();
public:
void unsafe_arena_set_allocated_data(
::PROTOBUF_NAMESPACE_ID::Struct* data);
::PROTOBUF_NAMESPACE_ID::Struct* unsafe_arena_release_data();
// uint64 timestamp = 1;
void clear_timestamp();
uint64_t timestamp() const;
@ -9962,8 +9978,9 @@ class CustomEvent final :
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
struct Impl_ {
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Any > customdata_;
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr category_;
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
::PROTOBUF_NAMESPACE_ID::Struct* data_;
uint64_t timestamp_;
mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
};
@ -23499,41 +23516,139 @@ inline void CustomEvent::set_allocated_category(std::string* category) {
// @@protoc_insertion_point(field_set_allocated:rtech.liveapi.CustomEvent.category)
}
// repeated .google.protobuf.Any customData = 3;
inline int CustomEvent::_internal_customdata_size() const {
return _impl_.customdata_.size();
// string name = 3;
inline void CustomEvent::clear_name() {
_impl_.name_.ClearToEmpty();
}
inline int CustomEvent::customdata_size() const {
return _internal_customdata_size();
inline const std::string& CustomEvent::name() const {
// @@protoc_insertion_point(field_get:rtech.liveapi.CustomEvent.name)
return _internal_name();
}
inline ::PROTOBUF_NAMESPACE_ID::Any* CustomEvent::mutable_customdata(int index) {
// @@protoc_insertion_point(field_mutable:rtech.liveapi.CustomEvent.customData)
return _impl_.customdata_.Mutable(index);
template <typename ArgT0, typename... ArgT>
inline PROTOBUF_ALWAYS_INLINE
void CustomEvent::set_name(ArgT0&& arg0, ArgT... args) {
_impl_.name_.Set(static_cast<ArgT0 &&>(arg0), args..., GetArenaForAllocation());
// @@protoc_insertion_point(field_set:rtech.liveapi.CustomEvent.name)
}
inline ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Any >*
CustomEvent::mutable_customdata() {
// @@protoc_insertion_point(field_mutable_list:rtech.liveapi.CustomEvent.customData)
return &_impl_.customdata_;
inline std::string* CustomEvent::mutable_name() {
std::string* _s = _internal_mutable_name();
// @@protoc_insertion_point(field_mutable:rtech.liveapi.CustomEvent.name)
return _s;
}
inline const ::PROTOBUF_NAMESPACE_ID::Any& CustomEvent::_internal_customdata(int index) const {
return _impl_.customdata_.Get(index);
inline const std::string& CustomEvent::_internal_name() const {
return _impl_.name_.Get();
}
inline const ::PROTOBUF_NAMESPACE_ID::Any& CustomEvent::customdata(int index) const {
// @@protoc_insertion_point(field_get:rtech.liveapi.CustomEvent.customData)
return _internal_customdata(index);
inline void CustomEvent::_internal_set_name(const std::string& value) {
_impl_.name_.Set(value, GetArenaForAllocation());
}
inline ::PROTOBUF_NAMESPACE_ID::Any* CustomEvent::_internal_add_customdata() {
return _impl_.customdata_.Add();
inline std::string* CustomEvent::_internal_mutable_name() {
return _impl_.name_.Mutable(GetArenaForAllocation());
}
inline ::PROTOBUF_NAMESPACE_ID::Any* CustomEvent::add_customdata() {
::PROTOBUF_NAMESPACE_ID::Any* _add = _internal_add_customdata();
// @@protoc_insertion_point(field_add:rtech.liveapi.CustomEvent.customData)
return _add;
inline std::string* CustomEvent::release_name() {
// @@protoc_insertion_point(field_release:rtech.liveapi.CustomEvent.name)
return _impl_.name_.Release();
}
inline const ::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Any >&
CustomEvent::customdata() const {
// @@protoc_insertion_point(field_list:rtech.liveapi.CustomEvent.customData)
return _impl_.customdata_;
inline void CustomEvent::set_allocated_name(std::string* name) {
if (name != nullptr) {
} else {
}
_impl_.name_.SetAllocated(name, GetArenaForAllocation());
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
if (_impl_.name_.IsDefault()) {
_impl_.name_.Set("", GetArenaForAllocation());
}
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
// @@protoc_insertion_point(field_set_allocated:rtech.liveapi.CustomEvent.name)
}
// .google.protobuf.Struct data = 4;
inline bool CustomEvent::_internal_has_data() const {
return this != internal_default_instance() && _impl_.data_ != nullptr;
}
inline bool CustomEvent::has_data() const {
return _internal_has_data();
}
inline const ::PROTOBUF_NAMESPACE_ID::Struct& CustomEvent::_internal_data() const {
const ::PROTOBUF_NAMESPACE_ID::Struct* p = _impl_.data_;
return p != nullptr ? *p : reinterpret_cast<const ::PROTOBUF_NAMESPACE_ID::Struct&>(
::PROTOBUF_NAMESPACE_ID::_Struct_default_instance_);
}
inline const ::PROTOBUF_NAMESPACE_ID::Struct& CustomEvent::data() const {
// @@protoc_insertion_point(field_get:rtech.liveapi.CustomEvent.data)
return _internal_data();
}
inline void CustomEvent::unsafe_arena_set_allocated_data(
::PROTOBUF_NAMESPACE_ID::Struct* data) {
if (GetArenaForAllocation() == nullptr) {
delete reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.data_);
}
_impl_.data_ = data;
if (data) {
} else {
}
// @@protoc_insertion_point(field_unsafe_arena_set_allocated:rtech.liveapi.CustomEvent.data)
}
inline ::PROTOBUF_NAMESPACE_ID::Struct* CustomEvent::release_data() {
::PROTOBUF_NAMESPACE_ID::Struct* temp = _impl_.data_;
_impl_.data_ = nullptr;
#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
auto* old = reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(temp);
temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
if (GetArenaForAllocation() == nullptr) { delete old; }
#else // PROTOBUF_FORCE_COPY_IN_RELEASE
if (GetArenaForAllocation() != nullptr) {
temp = ::PROTOBUF_NAMESPACE_ID::internal::DuplicateIfNonNull(temp);
}
#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE
return temp;
}
inline ::PROTOBUF_NAMESPACE_ID::Struct* CustomEvent::unsafe_arena_release_data() {
// @@protoc_insertion_point(field_release:rtech.liveapi.CustomEvent.data)
::PROTOBUF_NAMESPACE_ID::Struct* temp = _impl_.data_;
_impl_.data_ = nullptr;
return temp;
}
inline ::PROTOBUF_NAMESPACE_ID::Struct* CustomEvent::_internal_mutable_data() {
if (_impl_.data_ == nullptr) {
auto* p = CreateMaybeMessage<::PROTOBUF_NAMESPACE_ID::Struct>(GetArenaForAllocation());
_impl_.data_ = p;
}
return _impl_.data_;
}
inline ::PROTOBUF_NAMESPACE_ID::Struct* CustomEvent::mutable_data() {
::PROTOBUF_NAMESPACE_ID::Struct* _msg = _internal_mutable_data();
// @@protoc_insertion_point(field_mutable:rtech.liveapi.CustomEvent.data)
return _msg;
}
inline void CustomEvent::set_allocated_data(::PROTOBUF_NAMESPACE_ID::Struct* data) {
::PROTOBUF_NAMESPACE_ID::Arena* message_arena = GetArenaForAllocation();
if (message_arena == nullptr) {
delete reinterpret_cast< ::PROTOBUF_NAMESPACE_ID::MessageLite*>(_impl_.data_);
}
if (data) {
::PROTOBUF_NAMESPACE_ID::Arena* submessage_arena =
::PROTOBUF_NAMESPACE_ID::Arena::InternalGetOwningArena(
reinterpret_cast<::PROTOBUF_NAMESPACE_ID::MessageLite*>(data));
if (message_arena != submessage_arena) {
data = ::PROTOBUF_NAMESPACE_ID::internal::GetOwnedMessage(
message_arena, data, submessage_arena);
}
} else {
}
_impl_.data_ = data;
// @@protoc_insertion_point(field_set_allocated:rtech.liveapi.CustomEvent.data)
}
// -------------------------------------------------------------------

View File

@ -25,31 +25,31 @@ message Vector3
message Player
{
string name = 1;
uint32 teamId = 2;
Vector3 pos = 3;
Vector3 angles = 4;
string name = 1;
uint32 teamId = 2;
Vector3 pos = 3;
Vector3 angles = 4;
uint32 currentHealth = 5;
uint32 maxHealth = 6;
uint32 shieldHealth = 7;
uint32 shieldMaxHealth = 8;
uint32 currentHealth = 5;
uint32 maxHealth = 6;
uint32 shieldHealth = 7;
uint32 shieldMaxHealth = 8;
string nucleusHash = 9;
string hardwareName = 10;
string nucleusHash = 9;
string hardwareName = 10;
string teamName = 11;
uint32 squadIndex = 12;
string character = 13;
string skin = 14;
string teamName = 11;
uint32 squadIndex = 12;
string character = 13;
string skin = 14;
}
message CustomMatch_LobbyPlayer
{
string name = 1;
uint32 teamId = 2;
string name = 1;
uint32 teamId = 2;
string nucleusHash = 3;
string nucleusHash = 3;
string hardwareName = 4;
}
@ -66,7 +66,7 @@ message Version
uint32 major_num = 1;
uint32 minor_num = 2;
uint32 build_stamp = 3;
string revision = 4;
string revision = 4;
}
message InventoryItem
@ -551,16 +551,18 @@ message WeaponSwitched
// Custom events
/////////////////////////////////////////
import "google/protobuf/struct.proto";
// Event defining custom user data that is otherwise too specific to create dedicated messages for
message CustomEvent
{
uint64 timestamp = 1;
string category = 2;
uint64 timestamp = 1;
string category = 2;
repeated google.protobuf.Any customData = 3;
string name = 3;
google.protobuf.Struct data = 4;
}
//////////////////////////////////////////////////////////////////////
// Input messages:
// Used by observers to programmatically interact with the game

View File

@ -4,6 +4,7 @@
//
//===========================================================================//
#include "liveapi.h"
#include "protobuf/util/json_util.h"
#include "DirtySDK/dirtysock.h"
#include "DirtySDK/dirtysock/netconn.h"
@ -11,29 +12,33 @@
#include "DirtySDK/proto/protowebsocket.h"
//-----------------------------------------------------------------------------
//
// change callbacks
//-----------------------------------------------------------------------------
static void LiveAPI_EnabledChangedCallback(IConVar* var, const char* pOldValue)
{
LiveAPISystem()->ToggleInit();
}
static void LiveAPI_WebSocketEnabledChangedCallback(IConVar* var, const char* pOldValue)
{
LiveAPISystem()->ToggleInitWebSocket();
}
static void LiveAPI_ParamsChangedCallback(IConVar* var, const char* pOldValue)
{
LiveAPISystem()->UpdateParams();
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
static void LiveAPI_AddressChangedCallback(IConVar* var, const char* pOldValue)
{
LiveAPISystem()->InstallAddressList();
LiveAPISystem()->RebootWebSocket();
}
//-----------------------------------------------------------------------------
// console variables
//-----------------------------------------------------------------------------
ConVar liveapi_enabled("liveapi_enabled", "1", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Enable LiveAPI functionality");
ConVar liveapi_enabled("liveapi_enabled", "1", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Enable LiveAPI functionality", &LiveAPI_EnabledChangedCallback);
ConVar liveapi_session_name("liveapi_session_name", "liveapi_session", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "LiveAPI session name to identify this connection");
// WebSocket core
static ConVar liveapi_use_websocket("liveapi_use_websocket", "1", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Use WebSocket to transmit LiveAPI events");
static ConVar liveapi_websocket_enabled("liveapi_websocket_enabled", "1", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Whether to use WebSocket to transmit LiveAPI events", &LiveAPI_WebSocketEnabledChangedCallback);
static ConVar liveapi_servers("liveapi_servers", "ws://127.0.0.1:7777", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Comma separated list of addresses to connect to", &LiveAPI_AddressChangedCallback, "ws://domain.suffix:port");
// WebSocket connection base parameters
@ -45,10 +50,23 @@ static ConVar liveapi_timeout("liveapi_timeout", "300", FCVAR_RELEASE | FCVAR_SE
static ConVar liveapi_keepalive("liveapi_keepalive", "30", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Interval of time to send Pong to any connected server", &LiveAPI_ParamsChangedCallback);
static ConVar liveapi_lax_ssl("liveapi_lax_ssl", "1", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Skip SSL certificate validation for all WSS connections (allows the use of self-signed certificates)", &LiveAPI_ParamsChangedCallback);
// Print core
static ConVar liveapi_print_enabled("liveapi_print_enabled", "0", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Whether to enable the printing of all events to a LiveAPI JSON file");
// Print parameters
static ConVar liveapi_print_pretty("liveapi_print_pretty", "0", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Whether to print events in a formatted manner to the LiveAPI JSON file");
static ConVar liveapi_print_primitive("liveapi_print_primitive", "0", FCVAR_RELEASE | FCVAR_SERVER_FRAME_THREAD, "Whether to print primitive event fields to the LiveAPI JSON file");
//-----------------------------------------------------------------------------
// constructors/destructors
//-----------------------------------------------------------------------------
LiveAPI::LiveAPI()
{
matchLogCount = 0;
initialLog = false;
initialized = false;
}
LiveAPI::~LiveAPI()
{
}
@ -60,16 +78,8 @@ void LiveAPI::Init()
if (!liveapi_enabled.GetBool())
return;
if (liveapi_use_websocket.GetBool())
{
const char* initError = nullptr;
if (!InitWebSocket(initError))
{
Error(eDLL_T::RTECH, 0, "LiveAPI: WebSocket initialization failed! [%s]\n", initError);
return;
}
}
InitWebSocket();
initialized = true;
}
//-----------------------------------------------------------------------------
@ -78,10 +88,26 @@ void LiveAPI::Init()
void LiveAPI::Shutdown()
{
webSocketSystem.Shutdown();
DestroyLogger();
initialized = false;
}
//-----------------------------------------------------------------------------
//
// Toggle between init or deinit depending on current init state and the value
// of the cvar 'liveapi_enabled'
//-----------------------------------------------------------------------------
void LiveAPI::ToggleInit()
{
const bool enabled = liveapi_enabled.GetBool();
if (enabled && !initialized)
Init();
else if (!enabled && initialized)
Shutdown();
}
//-----------------------------------------------------------------------------
// Populate the connection params structure
//-----------------------------------------------------------------------------
void LiveAPI::CreateParams(CWebSocket::ConnParams_s& params)
{
@ -96,7 +122,7 @@ void LiveAPI::CreateParams(CWebSocket::ConnParams_s& params)
}
//-----------------------------------------------------------------------------
//
// Update the websocket parameters and apply them on all connections
//-----------------------------------------------------------------------------
void LiveAPI::UpdateParams()
{
@ -107,23 +133,91 @@ void LiveAPI::UpdateParams()
}
//-----------------------------------------------------------------------------
//
// Initialize the websocket system
//-----------------------------------------------------------------------------
bool LiveAPI::InitWebSocket(const char*& initError)
void LiveAPI::InitWebSocket()
{
if (!liveapi_websocket_enabled.GetBool())
return;
CWebSocket::ConnParams_s connParams;
CreateParams(connParams);
return webSocketSystem.Init(liveapi_servers.GetString(), connParams, initError);
const char* initError = nullptr;
if (!webSocketSystem.Init(liveapi_servers.GetString(), connParams, initError))
{
Error(eDLL_T::RTECH, 0, "LiveAPI: WebSocket initialization failed! [%s]\n", initError);
return;
}
}
//-----------------------------------------------------------------------------
//
// Shutdown the websocket system
//-----------------------------------------------------------------------------
void LiveAPI::InstallAddressList()
void LiveAPI::ShutdownWebSocket()
{
webSocketSystem.ClearAll();
webSocketSystem.UpdateAddressList(liveapi_servers.GetString());
webSocketSystem.Shutdown();
}
//-----------------------------------------------------------------------------
// Toggle between init or deinit depending on current init state and the value
// of the cvar 'liveapi_websocket_enabled'
//-----------------------------------------------------------------------------
void LiveAPI::ToggleInitWebSocket()
{
const bool enabled = liveapi_websocket_enabled.GetBool();
if (enabled && !WebSocketInitialized())
InitWebSocket();
else if (!enabled && WebSocketInitialized())
ShutdownWebSocket();
}
//-----------------------------------------------------------------------------
// Reboot the websocket system and reconnect to addresses specified in cvar
// 'liveapi_servers'
//-----------------------------------------------------------------------------
void LiveAPI::RebootWebSocket()
{
ShutdownWebSocket();
InitWebSocket();
}
//-----------------------------------------------------------------------------
// Create the file logger
//-----------------------------------------------------------------------------
void LiveAPI::CreateLogger()
{
// Its possible that one was already created but never closed, this is
// possible if the game scripts crashed or something along those lines.
DestroyLogger();
if (!liveapi_print_enabled.GetBool())
return; // Logging is disabled
matchLogger = spdlog::basic_logger_mt("match_logger",
Format("platform/liveapi/logs/%s/match_%d.json", g_LogSessionUUID.c_str(), matchLogCount++));
matchLogger.get()->set_pattern("%v");
matchLogger.get()->info("[\n");
}
//-----------------------------------------------------------------------------
// Destroy the file logger
//-----------------------------------------------------------------------------
void LiveAPI::DestroyLogger()
{
if (initialLog)
initialLog = false;
if (!matchLogger)
return; // Nothing to drop
matchLogger.get()->info("\n]\n");
matchLogger.reset();
spdlog::drop("match_logger");
}
//-----------------------------------------------------------------------------
@ -134,30 +228,65 @@ void LiveAPI::RunFrame()
if (!IsEnabled())
return;
if (liveapi_use_websocket.GetBool())
if (WebSocketInitialized())
webSocketSystem.Update();
}
//-----------------------------------------------------------------------------
// Send an event to all sockets
//-----------------------------------------------------------------------------
void LiveAPI::LogEvent(const char* const dataBuf, const int32_t dataSize)
void LiveAPI::LogEvent(const google::protobuf::Message* const toTransmit, const google::protobuf::Message* toPrint)
{
if (!IsEnabled())
return;
if (liveapi_use_websocket.GetBool())
webSocketSystem.SendData(dataBuf, dataSize);
if (WebSocketInitialized())
{
const string data = toTransmit->SerializeAsString();
webSocketSystem.SendData(data.c_str(), (int)data.size());
}
// NOTE: we don't check on the cvar 'liveapi_print_enabled' here because if
// this cvar gets disabled on the fly and we check it here, the output will
// be truncated and thus invalid! Log for as long as the SpdLog instance is
// valid.
if (matchLogger)
{
std::string jsonStr(initialLog ? ",\n" : "");
google::protobuf::util::JsonPrintOptions options;
options.add_whitespace = liveapi_print_pretty.GetBool();
options.always_print_primitive_fields = liveapi_print_primitive.GetBool();
google::protobuf::util::MessageToJsonString(*toPrint, &jsonStr, options);
// Remove the trailing newline character
if (options.add_whitespace && !jsonStr.empty())
jsonStr.pop_back();
matchLogger.get()->info(jsonStr);
if (!initialLog)
initialLog = true;
}
}
//-----------------------------------------------------------------------------
// Returns whether the system is enabled and able to run
// Returns whether the system is enabled
//-----------------------------------------------------------------------------
bool LiveAPI::IsEnabled() const
{
return liveapi_enabled.GetBool();
}
//-----------------------------------------------------------------------------
// Returns whether the system is able to run
//-----------------------------------------------------------------------------
bool LiveAPI::IsValidToRun() const
{
return (IsEnabled() && (WebSocketInitialized() || FileLoggerInitialized()));
}
static LiveAPI s_liveApi;
//-----------------------------------------------------------------------------

View File

@ -1,6 +1,7 @@
#ifndef RTECH_LIVEAPI_H
#define RTECH_LIVEAPI_H
#include "tier2/websocket.h"
#include "thirdparty/protobuf/message.h"
#define LIVE_API_MAX_FRAME_BUFFER_SIZE 0x8000
@ -13,26 +14,43 @@ typedef void (*LiveAPISendCallback_t)(ProtoWebSocketRefT* webSocket);
class LiveAPI
{
public:
LiveAPI();
~LiveAPI();
void Init();
void Shutdown();
void ToggleInit();
void CreateParams(CWebSocket::ConnParams_s& params);
void UpdateParams();
bool InitWebSocket(const char*& initError);
void InstallAddressList();
void InitWebSocket();
void ShutdownWebSocket();
void ToggleInitWebSocket();
void RebootWebSocket();
void CreateLogger();
void DestroyLogger();
void RunFrame();
void LogEvent(const char* const dataBuf, const int32_t dataSize);
void LogEvent(const google::protobuf::Message* const toTransmit, const google::protobuf::Message* toPrint);
bool IsEnabled() const;
bool IsValidToRun() const;
inline bool WebSocketInitialized() const { return webSocketSystem.IsInitialized(); }
inline bool FileLoggerInitialized() const { return matchLogger != nullptr; }
private:
CWebSocket webSocketSystem;
std::shared_ptr<spdlog::logger> matchLogger;
int matchLogCount;
bool initialLog;
bool initialized;
};
LiveAPI* LiveAPISystem();