ef2c81e2d6
added sm_forceinputplayer to ForceInputs added ZE_FFVII_Mako_Reactor_V6_B08 savelevel config fixed runtime error in voiceannounce_ex and ExtraCommands
254 lines
6.1 KiB
SourcePawn
254 lines
6.1 KiB
SourcePawn
#pragma semicolon 1
|
|
|
|
#include <sourcemod>
|
|
#include <sdktools>
|
|
#include <dhooks>
|
|
#include <voiceannounce_ex>
|
|
|
|
#define PLUGIN_VERSION "2.0.0"
|
|
|
|
new Handle:g_hProcessVoice = INVALID_HANDLE;
|
|
new Handle:g_hOnClientTalking = INVALID_HANDLE;
|
|
new Handle:g_hOnClientTalkingEnd = INVALID_HANDLE;
|
|
new bool:g_bLateLoad = false;
|
|
|
|
new g_iHookID[MAXPLAYERS+1] = { -1, ... };
|
|
new Handle:g_hClientMicTimers[MAXPLAYERS + 1] = {INVALID_HANDLE, ...};
|
|
|
|
new bool:g_bIsCSGO;
|
|
new Handle:g_hCSGOVoice;
|
|
|
|
public Plugin:myinfo =
|
|
{
|
|
name = "VoiceAnnounceEx",
|
|
author = "Franc1sco franug, Mini and GoD-Tony",
|
|
description = "Feature for developers to check/control client mic usage.",
|
|
version = PLUGIN_VERSION,
|
|
url = "https://forums.alliedmods.net"
|
|
}
|
|
|
|
public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max)
|
|
{
|
|
if(GetEngineVersion() == Engine_CSGO)
|
|
g_bIsCSGO = true;
|
|
else
|
|
g_bIsCSGO = false;
|
|
|
|
CreateNative("IsClientSpeaking", Native_IsClientTalking);
|
|
|
|
RegPluginLibrary("voiceannounce_ex");
|
|
|
|
g_bLateLoad = late;
|
|
return APLRes_Success;
|
|
}
|
|
|
|
public Native_IsClientTalking(Handle:plugin, numParams)
|
|
{
|
|
new client = GetNativeCell(1);
|
|
|
|
if (client > MaxClients || client <= 0)
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid.");
|
|
return false;
|
|
}
|
|
|
|
if (!IsClientInGame(client))
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game.");
|
|
return false;
|
|
}
|
|
|
|
if (IsFakeClient(client))
|
|
{
|
|
ThrowNativeError(SP_ERROR_NATIVE, "Cannot do mic checks on fake clients.");
|
|
return false;
|
|
}
|
|
|
|
return (g_hClientMicTimers[client] == INVALID_HANDLE) ? false : true;
|
|
}
|
|
|
|
public OnPluginStart()
|
|
{
|
|
//CreateConVar("voiceannounce_ex_version", PLUGIN_VERSION, "plugin", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_DONTRECORD);
|
|
new Offset;
|
|
if(g_bIsCSGO)
|
|
{
|
|
Offset = GameConfGetOffset(GetConfig(), "OnVoiceTransmit");
|
|
|
|
if(Offset == -1)
|
|
SetFailState("Failed to get offset");
|
|
|
|
g_hCSGOVoice = DHookCreate(Offset, HookType_Entity, ReturnType_Int, ThisPointer_CBaseEntity, CSGOVoicePost);
|
|
}
|
|
else
|
|
{
|
|
Offset = GameConfGetOffset(GetConfig(), "CGameClient::ProcessVoiceData");
|
|
|
|
g_hProcessVoice = DHookCreate(Offset, HookType_Raw, ReturnType_Void, ThisPointer_Address, Hook_ProcessVoiceData);
|
|
DHookAddParam(g_hProcessVoice, HookParamType_ObjectPtr);
|
|
}
|
|
|
|
g_hOnClientTalking = CreateGlobalForward("OnClientSpeakingEx", ET_Single, Param_Cell);
|
|
g_hOnClientTalkingEnd = CreateGlobalForward("OnClientSpeakingEnd", ET_Ignore, Param_Cell);
|
|
|
|
if(g_bLateLoad)
|
|
{
|
|
for(new i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsClientInGame(i) && !IsFakeClient(i))
|
|
OnClientPutInServer(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
public OnClientPutInServer(client)
|
|
{
|
|
if (!IsFakeClient(client))
|
|
{
|
|
if(g_bIsCSGO)
|
|
DHookEntity(g_hCSGOVoice, true, client);
|
|
else
|
|
g_iHookID[client] = DHookRaw(g_hProcessVoice, true, GetIMsgHandler(client));
|
|
|
|
if(g_hClientMicTimers[client] != INVALID_HANDLE)
|
|
KillTimer(g_hClientMicTimers[client]);
|
|
|
|
g_hClientMicTimers[client] = INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
public OnClientDisconnect(client)
|
|
{
|
|
if(g_bIsCSGO)
|
|
{
|
|
if(g_iHookID[client] != -1)
|
|
{
|
|
DHookRemoveHookID(g_iHookID[client]);
|
|
g_iHookID[client] = -1;
|
|
}
|
|
}
|
|
|
|
if(g_hClientMicTimers[client] != INVALID_HANDLE)
|
|
KillTimer(g_hClientMicTimers[client]);
|
|
|
|
g_hClientMicTimers[client] = INVALID_HANDLE;
|
|
}
|
|
|
|
public MRESReturn:Hook_ProcessVoiceData(Address:pThis, Handle:hParams)
|
|
{
|
|
new Address:pIClient = pThis - Address:4;
|
|
new client = GetPlayerSlot(pIClient) + 1;
|
|
|
|
if(g_hClientMicTimers[client] != INVALID_HANDLE)
|
|
{
|
|
KillTimer(g_hClientMicTimers[client]);
|
|
g_hClientMicTimers[client] = CreateTimer(0.3, Timer_ClientMicUsage, GetClientUserId(client));
|
|
}
|
|
|
|
if(g_hClientMicTimers[client] == INVALID_HANDLE && IsClientInGame(client))
|
|
g_hClientMicTimers[client] = CreateTimer(0.3, Timer_ClientMicUsage, GetClientUserId(client));
|
|
|
|
new bool:returnBool = true;
|
|
Call_StartForward(g_hOnClientTalking);
|
|
Call_PushCell(client);
|
|
Call_Finish(_:returnBool);
|
|
|
|
if(!returnBool)
|
|
return MRES_Supercede;
|
|
|
|
return MRES_Ignored;
|
|
}
|
|
|
|
public MRESReturn:CSGOVoicePost(client, Handle:hReturn)
|
|
{
|
|
if(g_hClientMicTimers[client] != INVALID_HANDLE)
|
|
{
|
|
KillTimer(g_hClientMicTimers[client]);
|
|
g_hClientMicTimers[client] = CreateTimer(0.3, Timer_ClientMicUsage, GetClientUserId(client));
|
|
}
|
|
|
|
if(g_hClientMicTimers[client] == INVALID_HANDLE && IsClientInGame(client))
|
|
g_hClientMicTimers[client] = CreateTimer(0.3, Timer_ClientMicUsage, GetClientUserId(client));
|
|
|
|
|
|
new bool:returnBool = true;
|
|
Call_StartForward(g_hOnClientTalking);
|
|
Call_PushCell(client);
|
|
Call_Finish(_:returnBool);
|
|
|
|
if(!returnBool)
|
|
return MRES_Supercede;
|
|
|
|
return MRES_Ignored;
|
|
}
|
|
|
|
public Action:Timer_ClientMicUsage(Handle:timer, any:userid)
|
|
{
|
|
new client = GetClientOfUserId(userid);
|
|
g_hClientMicTimers[client] = INVALID_HANDLE;
|
|
|
|
Call_StartForward(g_hOnClientTalkingEnd);
|
|
Call_PushCell(client);
|
|
Call_Finish();
|
|
}
|
|
|
|
/*
|
|
* Internal Functions
|
|
* Credits go to GoD-Tony
|
|
*/
|
|
stock Handle:GetConfig()
|
|
{
|
|
static Handle:hGameConf = INVALID_HANDLE;
|
|
|
|
if(hGameConf == INVALID_HANDLE)
|
|
hGameConf = LoadGameConfigFile("voiceannounce_ex.games");
|
|
|
|
return hGameConf;
|
|
}
|
|
|
|
stock Address:GetBaseServer()
|
|
{
|
|
static Address:pBaseServer = Address_Null;
|
|
|
|
if(pBaseServer == Address_Null)
|
|
pBaseServer = GameConfGetAddress(GetConfig(), "CBaseServer");
|
|
|
|
return pBaseServer;
|
|
}
|
|
|
|
stock Address:GetIClient(slot)
|
|
{
|
|
static Handle:hGetClient = INVALID_HANDLE;
|
|
|
|
if(hGetClient == INVALID_HANDLE)
|
|
{
|
|
StartPrepSDKCall(SDKCall_Raw);
|
|
PrepSDKCall_SetFromConf(GetConfig(), SDKConf_Virtual, "CBaseServer::GetClient");
|
|
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
|
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
|
|
hGetClient = EndPrepSDKCall();
|
|
}
|
|
|
|
return Address:SDKCall(hGetClient, GetBaseServer(), slot);
|
|
}
|
|
|
|
stock GetPlayerSlot(Address:pIClient)
|
|
{
|
|
static Handle:hPlayerSlot = INVALID_HANDLE;
|
|
|
|
if(hPlayerSlot == INVALID_HANDLE)
|
|
{
|
|
StartPrepSDKCall(SDKCall_Raw);
|
|
PrepSDKCall_SetFromConf(GetConfig(), SDKConf_Virtual, "CBaseClient::GetPlayerSlot");
|
|
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
|
hPlayerSlot = EndPrepSDKCall();
|
|
}
|
|
|
|
return SDKCall(hPlayerSlot, pIClient);
|
|
}
|
|
|
|
stock Address:GetIMsgHandler(client)
|
|
{
|
|
return GetIClient(client - 1) + Address:4;
|
|
}
|