Add Full CSGO Support

This commit is contained in:
maxime1907 2021-08-27 00:39:45 +02:00
parent 954ff32e1b
commit efe94c402d
14 changed files with 1252 additions and 154 deletions

View File

@ -38,6 +38,7 @@ CSGO = {
PossibleSDKs = {
'css': SDK('HL2SDKCSS', '2.css', '6', 'CSS', WinLinuxMac, 'css'),
'csgo': SDK('HL2SDKCSGO', '2.csgo', '21', 'CSGO', WinLinuxMac, 'csgo'),
}
def ResolveEnvPath(env, folder):
@ -601,6 +602,11 @@ class ExtensionConfig(object):
return binary
def ProtoBufLibrary(self, context, compiler, name, sdk):
binary = self.Library(context, compiler, name)
self.ConfigureForExtension(context, binary.compiler)
return binary
def HL2Library(self, context, compiler, name, sdk):
binary = self.Library(context, compiler, name)
self.ConfigureForExtension(context, binary.compiler)

View File

@ -13,23 +13,34 @@ for cxx in builder.targets:
binary = SM.HL2Library(builder, cxx, projectName + '.ext.' + sdk.ext, sdk)
binary.compiler.defines += [
'SOURCEMOD_BUILD',
'HAVE_STRING_H',
]
if cxx.target.platform == 'linux':
cxx.postlink += ['-lpthread', '-lrt']
binary.compiler.postlink += ['-lpthread', '-lrt']
elif cxx.target.platform == 'mac':
cxx.cflags += ['-Wno-deprecated-declarations']
cxx.postlink += ['-framework', 'CoreServices']
binary.compiler.cflags += ['-Wno-deprecated-declarations']
binary.compiler.postlink += ['-framework', 'CoreServices']
if cxx.family == 'gcc' or cxx.family == 'clang':
cxx.cxxflags += ['-fno-rtti']
elif cxx.family == 'msvc':
cxx.cxxflags += ['/GR-']
# if cxx.family == 'gcc' or cxx.family == 'clang':
# binary.compiler.cxxflags += ['-fno-rtti']
# elif cxx.family == 'msvc':
# binary.compiler.cxxflags += ['/GR-']
binary.compiler.cxxincludes += [
os.path.join(builder.sourcePath, 'pb', 'include'),
]
binary.compiler.postlink += [
'-L' + os.path.join(builder.sourcePath, 'pb', 'lib'),
'-lprotobuf'
]
binary.sources += [
'extension.cpp',
'ringbuffer.cpp',
os.path.join(builder.sourcePath, 'pb', 'csgo', 'netmessages.pb.cc'),
# os.path.join(builder.sourcePath, 'pb', 'google', 'protobuf', 'descriptor.pb.cc'),
os.path.join(SM.sm_root, 'extensions', 'sm-ext-common', 'mathstubs.c'),
os.path.join(SM.sm_root, 'public', 'smsdk_ext.cpp'),
os.path.join(SM.sm_root, 'public', 'CDetour', 'detours.cpp'),

View File

@ -9,6 +9,7 @@ builder.SetBuildFolder('package')
folder_list = [
'addons/sourcemod/extensions',
'addons/sourcemod/scripting/include',
'addons/sourcemod/gamedata',
]
if 'x86_64' in SM.target_archs:
@ -41,6 +42,11 @@ def CopyFiles(src, dest, files):
builder.AddCopy(source_path, dest_entry)
# Include files
CopyFiles('include', 'addons/sourcemod/scripting/include',
CopyFiles('addons/sourcemod/scripting/include', 'addons/sourcemod/scripting/include',
[ 'Voice.inc', ]
)
# Gamedata files
CopyFiles('addons/sourcemod/gamedata', 'addons/sourcemod/gamedata',
[ 'voice.games.txt', ]
)

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# Voice
Inject voice data over existing clients
## Maintaining .proto files
Download from here https://github.com/SteamDatabase/Protobufs

View File

@ -0,0 +1,63 @@
"Games"
{
"#default"
{
"Signatures"
{
"SV_BroadcastVoiceData"
{
"library" "engine"
"windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30"
"linux" "@_Z21SV_BroadcastVoiceDataP7IClientiPcx"
}
}
}
"insurgency"
{
"Signatures"
{
"SV_BroadcastVoiceData"
{
"library" "engine"
"windows" "\x55\x8B\xEC\x83\xEC\x74\x68\x2A\x2A\x2A\x2A\x8D\x4D\xE4\xE8"
"linux" "@_Z21SV_BroadcastVoiceDataP7IClientiPcx"
}
}
}
"nucleardawn"
{
"Signatures"
{
"SV_BroadcastVoiceData"
{
"library" "engine"
"windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x58\x57\x33\xFF"
"linux" "@_Z21SV_BroadcastVoiceDataP7IClientiPcx"
}
}
}
"left4dead2"
{
"Signatures"
{
"SV_BroadcastVoiceData"
{
"library" "engine"
"windows" "\x55\x8B\xEC\x83\xEC\x70\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\xA1\x2A\x2A\x2A\x2A\x53\x56"
"linux" "@_Z21SV_BroadcastVoiceDataP7IClientiPcx"
}
}
}
"csgo"
{
"Signatures"
{
"SV_BroadcastVoiceData"
{
"library" "engine"
"windows" "\x55\x8B\xEC\x83\xE4\xF8\x81\xEC\xE4\x00\x00\x00\x53\x56\x57"
"linux" "\x55\x89\xE5\x57\x56\x8D\x55\xDC"
}
}
}
}

View File

@ -0,0 +1,64 @@
#if defined _Voice_included
#endinput
#endif
#define _Voice_included
/**
*
* Checks whether a client is speaking or not.
*
* @param client The client index to check against.
*
* @error Client is not valid, ingame, or client is a bot.
*
* @return True if client is speaking, false otherwise.
*
*/
native bool IsClientTalking(int client);
/**
*
* Called when a client starts speaking.
*
* @param client Client index.
*
* @noreturn
*
*/
forward void OnClientSpeakingStart(int client);
/**
*
* Called when a client ends speaking.
*
* @param client Client index.
*
* @noreturn
*
*/
forward void OnClientSpeakingEnd(int client);
public Extension __ext_Voice =
{
name = "Voice",
file = "Voice.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public void __ext_Voice_SetNTVOptional()
{
MarkNativeAsOptional("IsClientTalking");
}
#endif

View File

@ -1,5 +1,7 @@
# vim: set ts=2 sw=2 tw=99 noet:
import sys
import os
import subprocess
try:
from ambuild2 import run, util
except:
@ -37,3 +39,8 @@ parser.options.add_argument('--targets', type=str, dest='targets', default=None,
help="Override the target architecture (use commas to separate multiple targets).")
parser.Configure()
# Run protobuf compilation and copy files to corresponding folders
os.chdir("../pb/")
os.chmod('./build_protobuf.sh', 0o755)
subprocess.call("./build_protobuf.sh")

View File

@ -29,6 +29,7 @@
* Version: $Id$
*/
//#define _GNU_SOURCE
#include <stdexcept>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
@ -43,6 +44,8 @@
#include <iserver.h>
#include <ISDKTools.h>
#include <ITimerSystem.h>
#include <ihltvdirector.h>
#include <ihltv.h>
@ -53,14 +56,23 @@
// voice packets are sent over unreliable netchannel
//#define NET_MAX_DATAGRAM_PAYLOAD 4000 // = maximum unreliable payload size
// voice packetsize = 64 | netchannel overflows at >4000 bytes
// with 22050 samplerate and 512 frames per packet -> 23.22ms per packet
// SVC_VoiceData overhead = 5 bytes
// sensible limit of 8 packets per frame = 552 bytes -> 185.76ms of voice data per frame
// 2009 Games with 22050 samplerate and 512 frames per packet -> 23.22ms per packet
// Newer games with 44100 samplerate and 512 frames per packet -> 11.60ms per packet
// 2009 Games SVC_VoiceData overhead = 5 bytes
// 2009 Games sensible limit of 8 packets per frame = 552 bytes -> 185.76ms of voice data per frame
// Newer games sensible limit of 8 packets per frame = 552 bytes -> 82.80ms of voice data per frame
#define NET_MAX_VOICE_BYTES_FRAME (8 * (5 + 64))
ConVar *g_SmVoiceAddr = CreateConVar("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address.");
ConVar *g_SmVoicePort = CreateConVar("sm_voice_port", "27020", FCVAR_PROTECTED, "Voice server listen port.", true, 1025.0, true, 65535.0);
ConVar *g_SvLogging = CreateConVar("sm_voice_logging", "0", FCVAR_NOTIFY, "Log client connections");
ConVar *g_SmVoiceAddr = CreateConVar("sm_voice_addr", "127.0.0.1", FCVAR_PROTECTED, "Voice server listen ip address [0.0.0.0 for docker]");
ConVar *g_SmVoicePort = CreateConVar("sm_voice_port", "27020", FCVAR_PROTECTED, "Voice server listen port [1025 - 65535]", true, 1025.0, true, 65535.0);
ConVar *g_SvSampleRateHz = CreateConVar("sm_voice_sample_rate_hz", "22050", FCVAR_NOTIFY, "Sample rate in Hertz [11050 - 48000]", true, 11050.0, true, 48000.0);
ConVar *g_SvBitRateKbps = CreateConVar("sm_voice_bit_rate_kbps", "64", FCVAR_NOTIFY, "Bit rate in kbps for one channel [24 - 128]", true, 24.0, true, 128.0);
ConVar *g_SvFrameSize = CreateConVar("sm_voice_frame_size", "512", FCVAR_NOTIFY, "Frame size per packet");
ConVar *g_SvPacketSize = CreateConVar("sm_voice_packet_size", "64", FCVAR_NOTIFY, "Packet size for voice data");
ConVar *g_SvComplexity = CreateConVar("sm_voice_complexity", "10", FCVAR_NOTIFY, "Encoder complexity [0 - 10]", true, 0.0, true, 10.0);
ConVar *g_SvCallOriginalBroadcast = CreateConVar("sm_voice_call_original_broadcast", "1", FCVAR_NOTIFY, "Call the original broadcast, set to 0 for debug purposes");
ConVar *g_SvTestDataHex = CreateConVar("sm_voice_debug_celt_data", "", FCVAR_NOTIFY, "Debug only, celt data in HEX to send instead of incoming data");
/**
* @file extension.cpp
@ -72,6 +84,12 @@ template <typename T> inline T min(T a, T b) { return a<b?a:b; }
CVoice g_Interface;
SMEXT_LINK(&g_Interface);
IForward *g_pSpeakingForward = NULL;
IForward *g_pStartSpeakingForward = NULL;
IForward *g_pEndSpeakingForward = NULL;
ITimer *g_pTimerSpeaking[MAX_CLIENTS];
CGlobalVars *gpGlobals = NULL;
ISDKTools *g_pSDKTools = NULL;
IServer *iserver = NULL;
@ -82,6 +100,104 @@ IHLTVServer *hltv = NULL;
int g_aFrameVoiceBytes[SM_MAXPLAYERS + 1];
double g_fLastVoiceData[SM_MAXPLAYERS + 1];
IGameConfig *g_pGameConf = NULL;
std::string string_to_hex(const std::string& input)
{
static const char hex_digits[] = "0123456789ABCDEF";
std::string output;
output.reserve(input.length() * 2);
for (unsigned char c : input)
{
output.push_back(hex_digits[c >> 4]);
output.push_back(hex_digits[c & 15]);
}
return output;
}
int hex_value(unsigned char hex_digit)
{
static const signed char hex_values[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
};
int value = hex_values[hex_digit];
if (value == -1) throw std::invalid_argument("invalid hex digit");
return value;
}
std::string hex_to_string(const std::string& input)
{
const auto len = input.length();
if (len & 1) throw std::invalid_argument("odd length");
std::string output;
output.reserve(len / 2);
for (auto it = input.begin(); it != input.end(); )
{
int hi = hex_value(*it++);
int lo = hex_value(*it++);
output.push_back(hi << 4 | lo);
}
return output;
}
void PrintCCLCMsg_VoiceData(const char *funcName, int client, const CCLCMsg_VoiceData &msg, bool drop)
{
g_pSM->LogMessage(myself, "===START=======%s=============", funcName);
g_pSM->LogMessage(myself, "client %d", client);
g_pSM->LogMessage(myself, "drop %d", drop);
if (msg.xuid())
g_pSM->LogMessage(myself, "Msg XUID: %" PRId64, msg.xuid());
g_pSM->LogMessage(myself, "Msg Format: %d", msg.format());
g_pSM->LogMessage(myself, "Msg sequence_bytes %d", msg.sequence_bytes());
if (msg.has_data())
{
g_pSM->LogMessage(myself, "Msg Data Size: %d", msg.data().size());
g_pSM->LogMessage(myself, "Msg Data Size: %zu", msg.data().size());
g_pSM->LogMessage(myself, "Msg Data Length: %d", msg.data().length());
g_pSM->LogMessage(myself, "Msg Data Length: %zu", msg.data().length());
g_pSM->LogMessage(myself, "Msg Data: %s", msg.data().c_str());
std::string hex_value = string_to_hex(msg.data().c_str());
g_pSM->LogMessage(myself, "Msg Data: %s", hex_value.c_str());
}
g_pSM->LogMessage(myself, "Msg section_number %d", msg.section_number());
g_pSM->LogMessage(myself, "Msg uncompressed_sample_offset %d", msg.uncompressed_sample_offset());
g_pSM->LogMessage(myself, "Msg uncompressed_sample_offset PRId32 %" PRId32, msg.uncompressed_sample_offset());
g_pSM->LogMessage(myself, "===END=======%s================", funcName);
}
DETOUR_DECL_STATIC3(SV_BroadcastVoiceData_CSGO, int, IClient *, pClient, const CCLCMsg_VoiceData &, msg, bool, drop)
{
if (g_SvLogging->GetInt())
PrintCCLCMsg_VoiceData("SV_BroadcastVoiceData_CSGO", pClient->GetPlayerSlot() + 1, msg, drop);
if (g_Interface.OnBroadcastVoiceData(pClient, msg.data().size(), (char*)msg.data().c_str()))
return DETOUR_STATIC_CALL(SV_BroadcastVoiceData_CSGO)(pClient, msg, drop);
// Return CSVCMsg_VoiceData::~CSVCMsg_VoiceData((CSVCMsg_VoiceData *)v48); but return value not used in
// bool CGameClient::CLCMsg_VoiceData( const CCLCMsg_VoiceData& msg ) so wtf ???
return 1;
}
DETOUR_DECL_STATIC4(SV_BroadcastVoiceData, void, IClient *, pClient, int, nBytes, char *, data, int64, xuid)
{
if (g_Interface.OnBroadcastVoiceData(pClient, nBytes, data))
@ -138,104 +254,59 @@ CVoice::CVoice()
m_pCodec = NULL;
m_VoiceDetour = NULL;
m_SV_BroadcastVoiceData = NULL;
}
class SpeakingEndTimer : public ITimedEvent
{
public:
ResultType OnTimer(ITimer *pTimer, void *pData)
{
int client = (int)(intptr_t)pData;
if ((gpGlobals->curtime - g_fLastVoiceData[client]) > 0.1)
{
g_pEndSpeakingForward->PushCell(client);
g_pEndSpeakingForward->Execute();
if (g_SvLogging->GetInt())
g_pSM->LogMessage(myself, "Player Speaking End (client=%d)", client);
return Pl_Stop;
}
return Pl_Continue;
}
void OnTimerEnd(ITimer *pTimer, void *pData)
{
g_pTimerSpeaking[(int)(intptr_t)pData] = NULL;
}
} s_SpeakingEndTimer;
bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
{
// Setup engine-specific data.
Dl_info info;
void *engineFactory = (void *)g_SMAPI->GetEngineFactory(false);
if(dladdr(engineFactory, &info) == 0)
char conf_error[255] = "";
if(!gameconfs->LoadGameConfigFile("voice.games", &g_pGameConf, conf_error, sizeof(conf_error)))
{
g_SMAPI->Format(error, maxlength, "dladdr(engineFactory) failed.");
return false;
if(conf_error[0])
{
snprintf(error, maxlength, "Could not read voice.games.txt: %s\n", conf_error);
}
void *pEngineSo = dlopen(info.dli_fname, RTLD_NOW);
if(pEngineSo == NULL)
{
g_SMAPI->Format(error, maxlength, "dlopen(%s) failed.", info.dli_fname);
return false;
}
int engineVersion = g_SMAPI->GetSourceEngineBuild();
void *adrVoiceData = NULL;
switch (engineVersion)
{
case SOURCE_ENGINE_CSGO:
#ifdef _WIN32
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x81\xEC\xD0\x00\x00\x00\x53\x56\x57", 12);
#else
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
#endif
break;
case SOURCE_ENGINE_LEFT4DEAD2:
#ifdef _WIN32
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x70\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\xA1\x2A\x2A\x2A\x2A\x53\x56", 23);
#else
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
#endif
break;
case SOURCE_ENGINE_NUCLEARDAWN:
#ifdef _WIN32
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x58\x57\x33\xFF", 14);
#else
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
#endif
break;
case SOURCE_ENGINE_INSURGENCY:
#ifdef _WIN32
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\x83\xEC\x74\x68\x2A\x2A\x2A\x2A\x8D\x4D\xE4\xE8", 15);
#else
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
#endif
break;
case SOURCE_ENGINE_TF2:
case SOURCE_ENGINE_CSS:
case SOURCE_ENGINE_HL2DM:
case SOURCE_ENGINE_DODS:
case SOURCE_ENGINE_SDK2013:
#ifdef _WIN32
adrVoiceData = memutils->FindPattern(pEngineSo, "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\xEC\x50\x83\x78\x30", 14);
#else
adrVoiceData = memutils->ResolveSymbol(pEngineSo, "_Z21SV_BroadcastVoiceDataP7IClientiPcx");
#endif
break;
default:
g_SMAPI->Format(error, maxlength, "Unsupported game.");
dlclose(pEngineSo);
return false;
}
dlclose(pEngineSo);
m_SV_BroadcastVoiceData = (t_SV_BroadcastVoiceData)adrVoiceData;
if(!m_SV_BroadcastVoiceData)
{
g_SMAPI->Format(error, maxlength, "SV_BroadcastVoiceData sigscan failed.");
return false;
}
// Setup voice detour.
CDetourManager::Init(g_pSM->GetScriptingEngine(), NULL);
CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_INSURGENCY
#ifdef _WIN32
if (engineVersion == SOURCE_ENGINE_CSGO || engineVersion == SOURCE_ENGINE_INSURGENCY)
{
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData_LTCG, adrVoiceData);
}
else
{
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData, adrVoiceData);
}
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData_LTCG, "SV_BroadcastVoiceData");
#else
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData, adrVoiceData);
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData_CSGO, "SV_BroadcastVoiceData");
#endif
#else
#ifdef _WIN32
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData, "SV_BroadcastVoiceData");
#else
m_VoiceDetour = DETOUR_CREATE_STATIC(SV_BroadcastVoiceData, "SV_BroadcastVoiceData");
#endif
#endif
if (!m_VoiceDetour)
@ -246,12 +317,28 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
m_VoiceDetour->EnableDetour();
g_pSpeakingForward = g_pForwards->CreateForward("OnClientSpeaking", ET_Event, 1, NULL, Param_Cell);
g_pStartSpeakingForward = g_pForwards->CreateForward("OnClientSpeakingStart", ET_Event, 1, NULL, Param_Cell);
g_pEndSpeakingForward = g_pForwards->CreateForward("OnClientSpeakingEnd", ET_Event, 1, NULL, Param_Cell);
AutoExecConfig(g_pCVar, true);
if (g_SvLogging->GetInt())
{
g_pSM->LogMessage(myself, "== Voice Encoder Settings ==");
g_pSM->LogMessage(myself, "SampleRateHertzKbps: %d", g_SvSampleRateHz->GetInt());
g_pSM->LogMessage(myself, "BitRate: %d", g_SvBitRateKbps->GetInt());
g_pSM->LogMessage(myself, "FrameSize: %d", g_SvFrameSize->GetInt());
g_pSM->LogMessage(myself, "PacketSize: %d", g_SvPacketSize->GetInt());
g_pSM->LogMessage(myself, "Complexity: %d", g_SvComplexity->GetInt());
}
// Encoder settings
m_EncoderSettings.SampleRate_Hz = 22050;
m_EncoderSettings.TargetBitRate_Kbps = 64;
m_EncoderSettings.FrameSize = 512; // samples
m_EncoderSettings.PacketSize = 64;
m_EncoderSettings.Complexity = 10; // 0 - 10
m_EncoderSettings.SampleRate_Hz = g_SvSampleRateHz->GetInt();
m_EncoderSettings.TargetBitRate_Kbps = g_SvBitRateKbps->GetInt();
m_EncoderSettings.FrameSize = g_SvFrameSize->GetInt(); // samples
m_EncoderSettings.PacketSize = g_SvPacketSize->GetInt();
m_EncoderSettings.Complexity = g_SvComplexity->GetInt(); // 0 - 10
m_EncoderSettings.FrameTime = (double)m_EncoderSettings.FrameSize / (double)m_EncoderSettings.SampleRate_Hz;
// Init CELT encoder
@ -276,8 +363,6 @@ bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
celt_encoder_ctl(m_pCodec, CELT_SET_BITRATE(m_EncoderSettings.TargetBitRate_Kbps * 1000));
celt_encoder_ctl(m_pCodec, CELT_SET_COMPLEXITY(m_EncoderSettings.Complexity));
AutoExecConfig(g_pCVar, true);
return true;
}
@ -415,6 +500,10 @@ void CVoice::SDK_OnUnload()
m_VoiceDetour = NULL;
}
g_pForwards->ReleaseForward(g_pSpeakingForward);
g_pForwards->ReleaseForward(g_pStartSpeakingForward);
g_pForwards->ReleaseForward(g_pEndSpeakingForward);
if(m_ListenSocket != -1)
{
close(m_ListenSocket);
@ -464,11 +553,24 @@ bool CVoice::OnBroadcastVoiceData(IClient *pClient, int nBytes, char *data)
// 5 = SVC_VoiceData header/overhead
g_aFrameVoiceBytes[client] += 5 + nBytes;
#if SOURCE_ENGINE != SE_CSGO && SOURCE_ENGINE == SE_INSURGENCY
if (g_aFrameVoiceBytes[client] > NET_MAX_VOICE_BYTES_FRAME)
return false;
#endif
g_fLastVoiceData[client] = gpGlobals->curtime;
if (g_pTimerSpeaking[client] == NULL)
{
g_pTimerSpeaking[client] = timersys->CreateTimer(&s_SpeakingEndTimer, 0.3f, (void *)(intptr_t)client, 1);
g_pStartSpeakingForward->PushCell(client);
g_pStartSpeakingForward->Execute();
if (g_SvLogging->GetInt())
g_pSM->LogMessage(myself, "Player Speaking Start (client=%d)", client);
}
return true;
}
@ -681,7 +783,13 @@ void CVoice::HandleVoiceData()
// Get SourceTV Index
if (!hltv)
{
#if SOURCE_ENGINE >= SE_CSGO
hltv = hltvdirector->GetHLTVServer(0);
#else
hltv = hltvdirector->GetHLTVServer();
#endif
}
int iSourceTVIndex = 0;
if (hltv)
@ -711,7 +819,7 @@ void CVoice::HandleVoiceData()
// Encode it!
unsigned char aFinal[PacketSize];
size_t FinalSize = 0;
int FinalSize = 0;
FinalSize = celt_encode(m_pCodec, aBuffer, SamplesPerFrame, aFinal, sizeof(aFinal));
@ -747,8 +855,63 @@ void CVoice::HandleVoiceData()
m_AvailableTime += (double)FramesAvailable * m_EncoderSettings.FrameTime;
}
void CVoice::BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pData)
void CVoice::BroadcastVoiceData(IClient *pClient, size_t nBytes, unsigned char *pData)
{
if (!g_Interface.OnBroadcastVoiceData(pClient, nBytes, (char*)pData))
return;
#if SOURCE_ENGINE == SE_CSGO || SOURCE_ENGINE == SE_INSURGENCY
#ifdef _WIN32
__asm mov ecx, pClient;
__asm mov edx, nBytes;
DETOUR_STATIC_CALL(SV_BroadcastVoiceData_LTCG)((char *)pData, 0);
#else
bool drop = false; // if (!pDestClient->IsSplitScreenUser() && (!drop || !IsReplay/IsHLTV())
static ::google::protobuf::int32 sequence_bytes = 0;
static ::google::protobuf::uint32 section_number = 0;
static ::google::protobuf::uint32 uncompressed_sample_offset = 0;
int client = pClient->GetPlayerSlot() + 1;
if (g_pTimerSpeaking[client] == NULL)
{
section_number++;
sequence_bytes = 0;
uncompressed_sample_offset = 0;
}
CCLCMsg_VoiceData msg;
msg.set_xuid(0); // steamID64 set to 0 because hltv is a BOT
if (strcmp(g_SvTestDataHex->GetString(), "") == 0)
{
sequence_bytes += nBytes;
msg.set_data((char*)pData, nBytes);
}
else
{
::std::string testing = hex_to_string(g_SvTestDataHex->GetString());
sequence_bytes += nBytes;
msg.set_data(testing.c_str(), testing.size());
}
uncompressed_sample_offset += m_EncoderSettings.FrameSize;
msg.set_format(VOICEDATA_FORMAT_ENGINE);
msg.set_sequence_bytes(sequence_bytes);
// These two values set to 0 will make it them ignored
msg.set_section_number(0);
msg.set_uncompressed_sample_offset(0);
if (g_SvLogging->GetInt())
PrintCCLCMsg_VoiceData("BroadcastVoiceData", client, msg, drop);
if (g_SvCallOriginalBroadcast->GetInt())
DETOUR_STATIC_CALL(SV_BroadcastVoiceData_CSGO)(pClient, msg, drop);
#endif
#else
#ifdef _WIN32
__asm mov ecx, pClient;
__asm mov edx, nBytes;
@ -757,4 +920,5 @@ void CVoice::BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pDa
#else
DETOUR_STATIC_CALL(SV_BroadcastVoiceData)(pClient, nBytes, (char *)pData, 0);
#endif
#endif
}

View File

@ -36,6 +36,7 @@
#include "smsdk_ext.h"
#include "celt_header.h"
#include "ringbuffer.h"
#include "pb/csgo/netmessages.pb.h"
/**
* @file extension.h
@ -52,7 +53,6 @@ typedef long long int64;
class CDetour;
class IClient;
typedef void (*t_SV_BroadcastVoiceData)(IClient *, int, unsigned char *, int64);
/**
* @brief Sample implementation of the SDK Extension.
@ -175,13 +175,12 @@ private:
CELTMode *m_pMode;
CELTEncoder *m_pCodec;
t_SV_BroadcastVoiceData m_SV_BroadcastVoiceData;
CDetour *m_VoiceDetour;
void HandleNetwork();
void OnDataReceived(CClient *pClient, int16_t *pData, size_t Samples);
void HandleVoiceData();
void BroadcastVoiceData(IClient *pClient, int nBytes, unsigned char *pData);
void BroadcastVoiceData(IClient *pClient, size_t nBytes, unsigned char *pData);
};
#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_

View File

@ -1,29 +0,0 @@
#if defined _Voice_included
#endinput
#endif
#define _Voice_included
native bool IsClientTalking(int iClient);
public Extension __ext_Voice =
{
name = "Voice",
file = "Voice.ext",
#if defined AUTOLOAD_EXTENSIONS
autoload = 1,
#else
autoload = 0,
#endif
#if defined REQUIRE_EXTENSIONS
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_EXTENSIONS
public void __ext_Voice_SetNTVOptional()
{
MarkNativeAsOptional("IsClientTalking");
}
#endif

28
pb/build_protobuf.sh Normal file
View File

@ -0,0 +1,28 @@
#!/bin/bash
if [[ -d protobuf-master ]]; then
exit 0;
fi;
# Protouf version used by CSGO
PROTOBUF_VERSION=v2.5.0
git clone https://github.com/protocolbuffers/protobuf.git -b $PROTOBUF_VERSION --recursive protobuf-master
cd protobuf-master
#sh autogen.sh
# Fix because autogen in protobuf 2.5.0 doesnt work anymore
autoreconf -f -i -Wall,no-obsolete
rm -rf autom4te.cache config.h.in~
# Make sure to compile for 32bit with old ABI for std::string compatibility
./configure --prefix=/home/alliedmodders/sourcemod/extensions/sm-ext-voice/pb --build=i686-pc-linux-gnu "CFLAGS=-m32 -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++14" "CXXFLAGS=-m32 -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++14" "LDFLAGS=-m32 -D_GLIBCXX_USE_CXX11_ABI=0 -std=c++14" --disable-shared --enable-static
make -j 8
make install
# Compile .proto files to c++
cd ../csgo
../bin/protoc google/protobuf/descriptor.proto --cpp_out=./
../bin/protoc netmessages.proto --cpp_out=./

View File

@ -0,0 +1,281 @@
package google.protobuf;
option optimize_for = SPEED;
option go_package = "google.golang.org/protobuf/types/descriptorpb";
option java_package = "com.google.protobuf";
option java_outer_classname = "DescriptorProtos";
message FileDescriptorSet {
repeated .google.protobuf.FileDescriptorProto file = 1;
}
message FileDescriptorProto {
optional string name = 1;
optional string package = 2;
repeated string dependency = 3;
repeated int32 public_dependency = 10;
repeated int32 weak_dependency = 11;
repeated .google.protobuf.DescriptorProto message_type = 4;
repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
repeated .google.protobuf.ServiceDescriptorProto service = 6;
repeated .google.protobuf.FieldDescriptorProto extension = 7;
optional .google.protobuf.FileOptions options = 8;
optional .google.protobuf.SourceCodeInfo source_code_info = 9;
optional string syntax = 12;
}
message DescriptorProto {
message ExtensionRange {
optional int32 start = 1;
optional int32 end = 2;
optional .google.protobuf.ExtensionRangeOptions options = 3;
}
message ReservedRange {
optional int32 start = 1;
optional int32 end = 2;
}
optional string name = 1;
repeated .google.protobuf.FieldDescriptorProto field = 2;
repeated .google.protobuf.FieldDescriptorProto extension = 6;
repeated .google.protobuf.DescriptorProto nested_type = 3;
repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
optional .google.protobuf.MessageOptions options = 7;
repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
repeated string reserved_name = 10;
}
message ExtensionRangeOptions {
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message FieldDescriptorProto {
enum Type {
TYPE_DOUBLE = 1;
TYPE_FLOAT = 2;
TYPE_INT64 = 3;
TYPE_UINT64 = 4;
TYPE_INT32 = 5;
TYPE_FIXED64 = 6;
TYPE_FIXED32 = 7;
TYPE_BOOL = 8;
TYPE_STRING = 9;
TYPE_GROUP = 10;
TYPE_MESSAGE = 11;
TYPE_BYTES = 12;
TYPE_UINT32 = 13;
TYPE_ENUM = 14;
TYPE_SFIXED32 = 15;
TYPE_SFIXED64 = 16;
TYPE_SINT32 = 17;
TYPE_SINT64 = 18;
}
enum Label {
LABEL_OPTIONAL = 1;
LABEL_REQUIRED = 2;
LABEL_REPEATED = 3;
}
optional string name = 1;
optional int32 number = 3;
optional .google.protobuf.FieldDescriptorProto.Label label = 4 [default = LABEL_OPTIONAL];
optional .google.protobuf.FieldDescriptorProto.Type type = 5 [default = TYPE_DOUBLE];
optional string type_name = 6;
optional string extendee = 2;
optional string default_value = 7;
optional int32 oneof_index = 9;
optional string json_name = 10;
optional .google.protobuf.FieldOptions options = 8;
optional bool proto3_optional = 17;
}
message OneofDescriptorProto {
optional string name = 1;
optional .google.protobuf.OneofOptions options = 2;
}
message EnumDescriptorProto {
message EnumReservedRange {
optional int32 start = 1;
optional int32 end = 2;
}
optional string name = 1;
repeated .google.protobuf.EnumValueDescriptorProto value = 2;
optional .google.protobuf.EnumOptions options = 3;
repeated .google.protobuf.EnumDescriptorProto.EnumReservedRange reserved_range = 4;
repeated string reserved_name = 5;
}
message EnumValueDescriptorProto {
optional string name = 1;
optional int32 number = 2;
optional .google.protobuf.EnumValueOptions options = 3;
}
message ServiceDescriptorProto {
optional string name = 1;
repeated .google.protobuf.MethodDescriptorProto method = 2;
optional .google.protobuf.ServiceOptions options = 3;
}
message MethodDescriptorProto {
optional string name = 1;
optional string input_type = 2;
optional string output_type = 3;
optional .google.protobuf.MethodOptions options = 4;
optional bool client_streaming = 5 [default = false];
optional bool server_streaming = 6 [default = false];
}
message FileOptions {
enum OptimizeMode {
SPEED = 1;
CODE_SIZE = 2;
LITE_RUNTIME = 3;
}
optional string java_package = 1;
optional string java_outer_classname = 8;
optional bool java_multiple_files = 10 [default = false];
optional bool java_generate_equals_and_hash = 20 [deprecated = true];
optional bool java_string_check_utf8 = 27 [default = false];
optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
optional string go_package = 11;
optional bool cc_generic_services = 16 [default = false];
optional bool java_generic_services = 17 [default = false];
optional bool py_generic_services = 18 [default = false];
optional bool php_generic_services = 42 [default = false];
optional bool deprecated = 23 [default = false];
optional bool cc_enable_arenas = 31 [default = true];
optional string objc_class_prefix = 36;
optional string csharp_namespace = 37;
optional string swift_prefix = 39;
optional string php_class_prefix = 40;
optional string php_namespace = 41;
optional string php_metadata_namespace = 44;
optional string ruby_package = 45;
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message MessageOptions {
optional bool message_set_wire_format = 1 [default = false];
optional bool no_standard_descriptor_accessor = 2 [default = false];
optional bool deprecated = 3 [default = false];
optional bool map_entry = 7;
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message FieldOptions {
enum CType {
STRING = 0;
CORD = 1;
STRING_PIECE = 2;
}
enum JSType {
JS_NORMAL = 0;
JS_STRING = 1;
JS_NUMBER = 2;
}
optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
optional bool packed = 2;
optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
optional bool lazy = 5 [default = false];
optional bool deprecated = 3 [default = false];
optional bool weak = 10 [default = false];
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message OneofOptions {
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message EnumOptions {
optional bool allow_alias = 2;
optional bool deprecated = 3 [default = false];
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message EnumValueOptions {
optional bool deprecated = 1 [default = false];
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message ServiceOptions {
optional bool deprecated = 33 [default = false];
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message MethodOptions {
enum IdempotencyLevel {
IDEMPOTENCY_UNKNOWN = 0;
NO_SIDE_EFFECTS = 1;
IDEMPOTENT = 2;
}
optional bool deprecated = 33 [default = false];
optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
extensions 1000 to max;
}
message UninterpretedOption {
message NamePart {
required string name_part = 1;
required bool is_extension = 2;
}
repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
optional string identifier_value = 3;
optional uint64 positive_int_value = 4;
optional int64 negative_int_value = 5;
optional double double_value = 6;
optional bytes string_value = 7;
optional string aggregate_value = 8;
}
message SourceCodeInfo {
message Location {
repeated int32 path = 1 [packed = true];
repeated int32 span = 2 [packed = true];
optional string leading_comments = 3;
optional string trailing_comments = 4;
repeated string leading_detached_comments = 6;
}
repeated .google.protobuf.SourceCodeInfo.Location location = 1;
}
message GeneratedCodeInfo {
message Annotation {
repeated int32 path = 1 [packed = true];
optional string source_file = 2;
optional int32 begin = 3;
optional int32 end = 4;
}
repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
}

491
pb/csgo/netmessages.proto Normal file
View File

@ -0,0 +1,491 @@
import "google/protobuf/descriptor.proto";
option cc_generic_services = false;
enum NET_Messages {
net_NOP = 0;
net_Disconnect = 1;
net_File = 2;
net_SplitScreenUser = 3;
net_Tick = 4;
net_StringCmd = 5;
net_SetConVar = 6;
net_SignonState = 7;
net_PlayerAvatarData = 100;
}
enum CLC_Messages {
clc_ClientInfo = 8;
clc_Move = 9;
clc_VoiceData = 10;
clc_BaselineAck = 11;
clc_ListenEvents = 12;
clc_RespondCvarValue = 13;
clc_FileCRCCheck = 14;
clc_LoadingProgress = 15;
clc_SplitPlayerConnect = 16;
clc_ClientMessage = 17;
clc_CmdKeyValues = 18;
clc_HltvReplay = 20;
}
enum VoiceDataFormat_t {
VOICEDATA_FORMAT_STEAM = 0;
VOICEDATA_FORMAT_ENGINE = 1;
}
enum ESplitScreenMessageType {
option allow_alias = true;
MSG_SPLITSCREEN_ADDUSER = 0;
MSG_SPLITSCREEN_REMOVEUSER = 1;
MSG_SPLITSCREEN_TYPE_BITS = 1;
}
enum SVC_Messages {
svc_ServerInfo = 8;
svc_SendTable = 9;
svc_ClassInfo = 10;
svc_SetPause = 11;
svc_CreateStringTable = 12;
svc_UpdateStringTable = 13;
svc_VoiceInit = 14;
svc_VoiceData = 15;
svc_Print = 16;
svc_Sounds = 17;
svc_SetView = 18;
svc_FixAngle = 19;
svc_CrosshairAngle = 20;
svc_BSPDecal = 21;
svc_SplitScreen = 22;
svc_UserMessage = 23;
svc_EntityMessage = 24;
svc_GameEvent = 25;
svc_PacketEntities = 26;
svc_TempEntities = 27;
svc_Prefetch = 28;
svc_Menu = 29;
svc_GameEventList = 30;
svc_GetCvarValue = 31;
svc_PaintmapData = 33;
svc_CmdKeyValues = 34;
svc_EncryptedData = 35;
svc_HltvReplay = 36;
svc_Broadcast_Command = 38;
}
enum ReplayEventType_t {
REPLAY_EVENT_CANCEL = 0;
REPLAY_EVENT_DEATH = 1;
REPLAY_EVENT_GENERIC = 2;
REPLAY_EVENT_STUCK_NEED_FULL_UPDATE = 3;
}
message CMsgVector {
optional float x = 1;
optional float y = 2;
optional float z = 3;
}
message CMsgVector2D {
optional float x = 1;
optional float y = 2;
}
message CMsgQAngle {
optional float x = 1;
optional float y = 2;
optional float z = 3;
}
message CMsgRGBA {
optional int32 r = 1;
optional int32 g = 2;
optional int32 b = 3;
optional int32 a = 4;
}
message CNETMsg_Tick {
optional uint32 tick = 1;
optional uint32 host_computationtime = 4;
optional uint32 host_computationtime_std_deviation = 5;
optional uint32 host_framestarttime_std_deviation = 6;
optional uint32 hltv_replay_flags = 7;
}
message CNETMsg_StringCmd {
optional string command = 1;
}
message CNETMsg_SignonState {
optional uint32 signon_state = 1;
optional uint32 spawn_count = 2;
optional uint32 num_server_players = 3;
repeated string players_networkids = 4;
optional string map_name = 5;
}
message CMsg_CVars {
message CVar {
optional string name = 1;
optional string value = 2;
optional uint32 dictionary_name = 3;
}
repeated .CMsg_CVars.CVar cvars = 1;
}
message CNETMsg_SetConVar {
optional .CMsg_CVars convars = 1;
}
message CNETMsg_NOP {
}
message CNETMsg_Disconnect {
optional string text = 1;
}
message CNETMsg_File {
optional int32 transfer_id = 1;
optional string file_name = 2;
optional bool is_replay_demo_file = 3;
optional bool deny = 4;
}
message CNETMsg_SplitScreenUser {
optional int32 slot = 1;
}
message CNETMsg_PlayerAvatarData {
optional uint32 accountid = 1;
optional bytes rgb = 2;
}
message CCLCMsg_ClientInfo {
optional fixed32 send_table_crc = 1;
optional uint32 server_count = 2;
optional bool is_hltv = 3;
optional bool is_replay = 4;
optional uint32 friends_id = 5;
optional string friends_name = 6;
repeated fixed32 custom_files = 7;
}
message CCLCMsg_Move {
optional uint32 num_backup_commands = 1;
optional uint32 num_new_commands = 2;
optional bytes data = 3;
}
message CCLCMsg_VoiceData {
optional bytes data = 1;
optional fixed64 xuid = 2;
optional .VoiceDataFormat_t format = 3 [default = VOICEDATA_FORMAT_ENGINE];
optional int32 sequence_bytes = 4;
optional uint32 section_number = 5;
optional uint32 uncompressed_sample_offset = 6;
}
message CCLCMsg_BaselineAck {
optional int32 baseline_tick = 1;
optional int32 baseline_nr = 2;
}
message CCLCMsg_ListenEvents {
repeated fixed32 event_mask = 1;
}
message CCLCMsg_RespondCvarValue {
optional int32 cookie = 1;
optional int32 status_code = 2;
optional string name = 3;
optional string value = 4;
}
message CCLCMsg_FileCRCCheck {
optional int32 code_path = 1;
optional string path = 2;
optional int32 code_filename = 3;
optional string filename = 4;
optional int32 file_fraction = 5;
optional bytes md5 = 6;
optional uint32 crc = 7;
optional int32 file_hash_type = 8;
optional int32 file_len = 9;
optional int32 pack_file_id = 10;
optional int32 pack_file_number = 11;
}
message CCLCMsg_LoadingProgress {
optional int32 progress = 1;
}
message CCLCMsg_SplitPlayerConnect {
optional .CMsg_CVars convars = 1;
}
message CCLCMsg_CmdKeyValues {
optional bytes keyvalues = 1;
}
message CSVCMsg_ServerInfo {
optional int32 protocol = 1;
optional int32 server_count = 2;
optional bool is_dedicated = 3;
optional bool is_official_valve_server = 4;
optional bool is_hltv = 5;
optional bool is_replay = 6;
optional bool is_redirecting_to_proxy_relay = 21;
optional int32 c_os = 7;
optional fixed32 map_crc = 8;
optional fixed32 client_crc = 9;
optional fixed32 string_table_crc = 10;
optional int32 max_clients = 11;
optional int32 max_classes = 12;
optional int32 player_slot = 13;
optional float tick_interval = 14;
optional string game_dir = 15;
optional string map_name = 16;
optional string map_group_name = 17;
optional string sky_name = 18;
optional string host_name = 19;
optional uint32 public_ip = 20;
optional uint64 ugc_map_id = 22;
}
message CSVCMsg_ClassInfo {
message class_t {
optional int32 class_id = 1;
optional string data_table_name = 2;
optional string class_name = 3;
}
optional bool create_on_client = 1;
repeated .CSVCMsg_ClassInfo.class_t classes = 2;
}
message CSVCMsg_SendTable {
message sendprop_t {
optional int32 type = 1;
optional string var_name = 2;
optional int32 flags = 3;
optional int32 priority = 4;
optional string dt_name = 5;
optional int32 num_elements = 6;
optional float low_value = 7;
optional float high_value = 8;
optional int32 num_bits = 9;
}
optional bool is_end = 1;
optional string net_table_name = 2;
optional bool needs_decoder = 3;
repeated .CSVCMsg_SendTable.sendprop_t props = 4;
}
message CSVCMsg_Print {
optional string text = 1;
}
message CSVCMsg_SetPause {
optional bool paused = 1;
}
message CSVCMsg_SetView {
optional int32 entity_index = 1;
}
message CSVCMsg_CreateStringTable {
optional string name = 1;
optional int32 max_entries = 2;
optional int32 num_entries = 3;
optional bool user_data_fixed_size = 4;
optional int32 user_data_size = 5;
optional int32 user_data_size_bits = 6;
optional int32 flags = 7;
optional bytes string_data = 8;
}
message CSVCMsg_UpdateStringTable {
optional int32 table_id = 1;
optional int32 num_changed_entries = 2;
optional bytes string_data = 3;
}
message CSVCMsg_VoiceInit {
optional int32 quality = 1;
optional string codec = 2;
optional int32 version = 3 [default = 0];
}
message CSVCMsg_VoiceData {
optional int32 client = 1;
optional bool proximity = 2;
optional fixed64 xuid = 3;
optional int32 audible_mask = 4;
optional bytes voice_data = 5;
optional bool caster = 6;
optional .VoiceDataFormat_t format = 7 [default = VOICEDATA_FORMAT_ENGINE];
optional int32 sequence_bytes = 8;
optional uint32 section_number = 9;
optional uint32 uncompressed_sample_offset = 10;
}
message CSVCMsg_FixAngle {
optional bool relative = 1;
optional .CMsgQAngle angle = 2;
}
message CSVCMsg_CrosshairAngle {
optional .CMsgQAngle angle = 1;
}
message CSVCMsg_Prefetch {
optional int32 sound_index = 1;
}
message CSVCMsg_BSPDecal {
optional .CMsgVector pos = 1;
optional int32 decal_texture_index = 2;
optional int32 entity_index = 3;
optional int32 model_index = 4;
optional bool low_priority = 5;
}
message CSVCMsg_SplitScreen {
optional .ESplitScreenMessageType type = 1 [default = MSG_SPLITSCREEN_ADDUSER];
optional int32 slot = 2;
optional int32 player_index = 3;
}
message CSVCMsg_GetCvarValue {
optional int32 cookie = 1;
optional string cvar_name = 2;
}
message CSVCMsg_Menu {
optional int32 dialog_type = 1;
optional bytes menu_key_values = 2;
}
message CSVCMsg_UserMessage {
optional int32 msg_type = 1;
optional bytes msg_data = 2;
optional int32 passthrough = 3;
}
message CSVCMsg_PaintmapData {
optional bytes paintmap = 1;
}
message CSVCMsg_GameEvent {
message key_t {
optional int32 type = 1;
optional string val_string = 2;
optional float val_float = 3;
optional int32 val_long = 4;
optional int32 val_short = 5;
optional int32 val_byte = 6;
optional bool val_bool = 7;
optional uint64 val_uint64 = 8;
optional bytes val_wstring = 9;
}
optional string event_name = 1;
optional int32 eventid = 2;
repeated .CSVCMsg_GameEvent.key_t keys = 3;
optional int32 passthrough = 4;
}
message CSVCMsg_GameEventList {
message key_t {
optional int32 type = 1;
optional string name = 2;
}
message descriptor_t {
optional int32 eventid = 1;
optional string name = 2;
repeated .CSVCMsg_GameEventList.key_t keys = 3;
}
repeated .CSVCMsg_GameEventList.descriptor_t descriptors = 1;
}
message CSVCMsg_TempEntities {
optional bool reliable = 1;
optional int32 num_entries = 2;
optional bytes entity_data = 3;
}
message CSVCMsg_PacketEntities {
optional int32 max_entries = 1;
optional int32 updated_entries = 2;
optional bool is_delta = 3;
optional bool update_baseline = 4;
optional int32 baseline = 5;
optional int32 delta_from = 6;
optional bytes entity_data = 7;
}
message CSVCMsg_Sounds {
message sounddata_t {
optional sint32 origin_x = 1;
optional sint32 origin_y = 2;
optional sint32 origin_z = 3;
optional uint32 volume = 4;
optional float delay_value = 5;
optional int32 sequence_number = 6;
optional int32 entity_index = 7;
optional int32 channel = 8;
optional int32 pitch = 9;
optional int32 flags = 10;
optional uint32 sound_num = 11;
optional fixed32 sound_num_handle = 12;
optional int32 speaker_entity = 13;
optional int32 random_seed = 14;
optional int32 sound_level = 15;
optional bool is_sentence = 16;
optional bool is_ambient = 17;
}
optional bool reliable_sound = 1;
repeated .CSVCMsg_Sounds.sounddata_t sounds = 2;
}
message CSVCMsg_EntityMsg {
optional int32 ent_index = 1;
optional int32 class_id = 2;
optional bytes ent_data = 3;
}
message CSVCMsg_CmdKeyValues {
optional bytes keyvalues = 1;
}
message CSVCMsg_EncryptedData {
optional bytes encrypted = 1;
optional int32 key_type = 2;
}
message CSVCMsg_HltvReplay {
optional int32 delay = 1;
optional int32 primary_target = 2;
optional int32 replay_stop_at = 3;
optional int32 replay_start_at = 4;
optional int32 replay_slowdown_begin = 5;
optional int32 replay_slowdown_end = 6;
optional float replay_slowdown_rate = 7;
}
message CCLCMsg_HltvReplay {
optional int32 request = 1;
optional float slowdown_length = 2;
optional float slowdown_rate = 3;
optional int32 primary_target_ent_index = 4;
optional float event_time = 5;
}
message CSVCMsg_Broadcast_Command {
optional string cmd = 1;
}

View File

@ -40,8 +40,8 @@
/* Basic information exposed publicly */
#define SMEXT_CONF_NAME "Voice"
#define SMEXT_CONF_DESCRIPTION "Inject voice data over existing clients"
#define SMEXT_CONF_VERSION "1.2"
#define SMEXT_CONF_AUTHOR "BotoX"
#define SMEXT_CONF_VERSION "2.0"
#define SMEXT_CONF_AUTHOR "BotoX, maxime1907"
#define SMEXT_CONF_URL ""
#define SMEXT_CONF_LOGTAG "VOICE"
#define SMEXT_CONF_LICENSE "GPL"
@ -59,14 +59,14 @@
#define SMEXT_CONF_METAMOD
/** Enable interfaces you want to use here by uncommenting lines */
//#define SMEXT_ENABLE_FORWARDSYS
#define SMEXT_ENABLE_FORWARDSYS
//#define SMEXT_ENABLE_HANDLESYS
#define SMEXT_ENABLE_PLAYERHELPERS
//#define SMEXT_ENABLE_DBMANAGER
#define SMEXT_ENABLE_GAMECONF
#define SMEXT_ENABLE_MEMUTILS
#define SMEXT_ENABLE_GAMEHELPERS
//#define SMEXT_ENABLE_TIMERSYS
#define SMEXT_ENABLE_TIMERSYS
//#define SMEXT_ENABLE_THREADER
//#define SMEXT_ENABLE_LIBSYS
//#define SMEXT_ENABLE_MENUS