Add voice manager (ability to override voice chat / mute players) (#179)

Co-authored-by: Michael Wilson <roflmuffin@users.noreply.github.com>
Co-authored-by: roflmuffin <shortguy014@gmail.com>
This commit is contained in:
Poggu
2023-12-12 08:46:45 +01:00
committed by GitHub
parent d495ac6230
commit bff04e7795
20 changed files with 579 additions and 6 deletions

View File

@@ -75,6 +75,7 @@ SET(SOURCE_FILES
src/scripting/natives/natives_memory.cpp
src/scripting/natives/natives_schema.cpp
src/scripting/natives/natives_entities.cpp
src/scripting/natives/natives_voice.cpp
src/core/managers/entity_manager.cpp
src/core/managers/entity_manager.h
src/core/managers/chat_manager.cpp
@@ -83,6 +84,8 @@ SET(SOURCE_FILES
src/core/managers/server_manager.h
src/scripting/natives/natives_server.cpp
libraries/nlohmann/json.hpp
src/core/managers/voice_manager.cpp
src/core/managers/voice_manager.h
src/scripting/natives/natives_dynamichooks.cpp
)

View File

@@ -0,0 +1,5 @@
[!INCLUDE [WithVoiceOverrides](../../examples/WithVoiceOverrides/README.md)]
<a href="https://github.com/roflmuffin/CounterStrikeSharp/tree/main/examples/WithVoiceOverrides" class="btn btn-secondary">View project on Github <i class="bi bi-github"></i></a>
[!code-csharp[](../../examples/WithVoiceOverrides/WithVoiceOverridesPlugin.cs)]

View File

@@ -15,5 +15,7 @@ items:
href: WithDatabase.md
- name: Translations
href: WithTranslations.md
- name: Voice Overrides
href: WithVoiceOverrides.md
- name: Warcraft Plugin
href: WarcraftPlugin.md

View File

@@ -0,0 +1,2 @@
# With Voice Overrides
Provides examples how to manipulate player voice flags & listening overrides to prevent certain players from hearing others.

View File

@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<CopyLocalLockFileAssemblies>false</CopyLocalLockFileAssemblies>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\managed\CounterStrikeSharp.API\CounterStrikeSharp.API.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,79 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Attributes;
using CounterStrikeSharp.API.Core.Attributes.Registration;
using CounterStrikeSharp.API.Modules.Commands;
using Microsoft.Extensions.Logging;
namespace WithVoiceOverrides;
[MinimumApiVersion(80)]
public class WithVoiceOverridesPlugin : BasePlugin
{
public override string ModuleName => "Example: With Voice Overrides";
public override string ModuleVersion => "1.0.0";
public override string ModuleAuthor => "CounterStrikeSharp & Contributors";
public override string ModuleDescription => "A plugin that manipulates voice flags";
[ConsoleCommand("css_hearall")]
public void OnHearAllCommand(CCSPlayerController? caller, CommandInfo command)
{
if (caller is null) return;
if (caller.VoiceFlags.HasFlag(VoiceFlags.ListenAll))
{
caller.VoiceFlags = VoiceFlags.Normal;
command.ReplyToCommand("Voice set back to default");
}
else
{
caller.VoiceFlags = VoiceFlags.ListenAll;
command.ReplyToCommand("Can hear both teams");
}
}
[ConsoleCommand("css_muteself")]
public void OnMuteSelfCommand(CCSPlayerController? caller, CommandInfo command)
{
if (caller is null) return;
if (caller.VoiceFlags.HasFlag(VoiceFlags.Muted))
{
caller.VoiceFlags = VoiceFlags.Normal;
command.ReplyToCommand("Unmuted yourself");
}
else
{
caller.VoiceFlags = VoiceFlags.Muted;
command.ReplyToCommand("Muted yourself");
}
}
[ConsoleCommand("css_muteothers")]
[CommandHelper(minArgs: 1, usage: "[target]")]
public void OnMuteOthersCommand(CCSPlayerController? caller, CommandInfo command)
{
if (caller is null) return;
var targetResult = command.GetArgTargetResult(1);
foreach (var player in targetResult.Players)
{
if (player == caller) continue;
var existingOverride = caller.GetListenOverride(player);
if (existingOverride == ListenOverride.Mute)
{
caller.SetListenOverride(player, ListenOverride.Default);
command.ReplyToCommand($"Now hearing {player.PlayerName}");
}
else
{
caller.SetListenOverride(player, ListenOverride.Mute);
command.ReplyToCommand($"Muted {player.PlayerName}");
}
}
}
}

View File

@@ -1311,5 +1311,51 @@ namespace CounterStrikeSharp.API.Core
return (bool)ScriptContext.GlobalScriptContext.GetResult(typeof(bool));
}
}
public static void SetClientListening(IntPtr receiver, IntPtr sender, uint listen){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(receiver);
ScriptContext.GlobalScriptContext.Push(sender);
ScriptContext.GlobalScriptContext.Push(listen);
ScriptContext.GlobalScriptContext.SetIdentifier(0xD38BEE77);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static ListenOverride GetClientListening(IntPtr receiver, IntPtr sender){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(receiver);
ScriptContext.GlobalScriptContext.Push(sender);
ScriptContext.GlobalScriptContext.SetIdentifier(0xE95644E3);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (ListenOverride)ScriptContext.GlobalScriptContext.GetResult(typeof(ListenOverride));
}
}
public static void SetClientVoiceFlags(IntPtr client, uint flags){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(client);
ScriptContext.GlobalScriptContext.Push(flags);
ScriptContext.GlobalScriptContext.SetIdentifier(0x48EB2FC8);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}
public static uint GetClientVoiceFlags(IntPtr client){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(client);
ScriptContext.GlobalScriptContext.SetIdentifier(0x9685205C);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
return (uint)ScriptContext.GlobalScriptContext.GetResult(typeof(uint));
}
}
}
}

View File

@@ -202,6 +202,21 @@ public partial class CCSPlayerController
public void ExecuteClientCommand(string command) => NativeAPI.IssueClientCommand(Slot, command);
/// <summary>
/// Overrides who a player can hear in voice chat.
/// </summary>
/// <param name="sender">Player talking in the voice chat</param>
/// <param name="override">Whether the talker should be heard</param>
public void SetListenOverride(CCSPlayerController sender, ListenOverride @override)
{
NativeAPI.SetClientListening(Handle, sender.Handle, (Byte)@override);
}
public ListenOverride GetListenOverride(CCSPlayerController sender)
{
return NativeAPI.GetClientListening(Handle, sender.Handle);
}
public int Slot => (int)Index - 1;
/// <summary>
@@ -234,4 +249,16 @@ public partial class CCSPlayerController
return ipAddress;
}
}
/// <summary>
/// Determines how the player interacts with voice chat.
/// </summary>
public VoiceFlags VoiceFlags
{
get => (VoiceFlags)NativeAPI.GetClientVoiceFlags(Handle);
set
{
NativeAPI.SetClientVoiceFlags(Handle, (Byte)value);
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
namespace CounterStrikeSharp.API
{
[Flags]
public enum VoiceFlags : Byte
{
Normal = 0,
Muted = (1 << 0),
All = (1 << 1),
ListenAll = (1 << 2),
Team = (1 << 3),
ListenTeam = (1 << 4),
}
public enum ListenOverride
{
Default = 0,
Mute,
Hear
}
}

View File

@@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CounterStrikeSharp.API.Test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithTranslations", "..\examples\WithTranslations\WithTranslations.csproj", "{BB44E08E-CCA8-4E22-A132-11B2F69D1890}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WithVoiceOverrides", "..\examples\WithVoiceOverrides\WithVoiceOverrides.csproj", "{6FA3107D-42AF-42A0-BF51-2230D13268B5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -92,6 +94,10 @@ Global
{BB44E08E-CCA8-4E22-A132-11B2F69D1890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BB44E08E-CCA8-4E22-A132-11B2F69D1890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BB44E08E-CCA8-4E22-A132-11B2F69D1890}.Release|Any CPU.Build.0 = Release|Any CPU
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FA3107D-42AF-42A0-BF51-2230D13268B5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{57E64289-5D69-4AA1-BEF0-D0D96A55EE8F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
@@ -104,5 +110,6 @@ Global
{A641D8D7-35F1-48AB-AABA-EDFB6B7FC49B} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{31EABE0B-871F-497B-BF36-37FFC6FAD15F} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{BB44E08E-CCA8-4E22-A132-11B2F69D1890} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
{6FA3107D-42AF-42A0-BF51-2230D13268B5} = {7DF99C35-881D-4FF2-B1C9-246BD3DECB9A}
EndGlobalSection
EndGlobal

View File

@@ -20,6 +20,7 @@
#include "interfaces/cs2_interfaces.h"
#include "core/managers/entity_manager.h"
#include "core/managers/server_manager.h"
#include "core/managers/voice_manager.h"
#include <public/game/server/iplayerinfo.h>
#include <public/entity2/entitysystem.h>
@@ -77,6 +78,7 @@ ConCommandManager conCommandManager;
EntityManager entityManager;
ChatManager chatManager;
ServerManager serverManager;
VoiceManager voiceManager;
bool gameLoopInitialized = false;
GetLegacyGameEventListener_t* GetLegacyGameEventListener = nullptr;

View File

@@ -53,6 +53,7 @@ class HookManager;
class EntityManager;
class ChatManager;
class ServerManager;
class VoiceManager;
class CCoreConfig;
class CGameConfig;
@@ -98,6 +99,7 @@ extern TimerSystem timerSystem;
extern ChatCommands chatCommands;
extern ChatManager chatManager;
extern ServerManager serverManager;
extern VoiceManager voiceManager;
extern HookManager hookManager;
extern SourceHook::ISourceHook *source_hook;

View File

@@ -31,6 +31,7 @@
#include "core/managers/player_manager.h"
#include "core/managers/con_command_manager.h"
#include "core/managers/voice_manager.h"
#include <public/eiface.h>
#include <public/inetchannelinfo.h>
@@ -273,7 +274,7 @@ void PlayerManager::OnLevelEnd()
{
CSSHARP_CORE_TRACE("[PlayerManager][OnLevelEnd]");
for (int i = 0; i <= m_max_clients; i++) {
for (int i = 0; i <= MaxClients(); i++) {
if (m_players[i].IsConnected()) {
OnClientDisconnect(m_players[i].m_slot, ENetworkDisconnectionReason::NETWORK_DISCONNECT_INVALID, m_players[i].GetName(), 0,
m_players[i].GetIpAddress());
@@ -290,6 +291,8 @@ void PlayerManager::OnClientCommand(CPlayerSlot slot, const CCommand& args) cons
const char* cmd = args.Arg(0);
globals::voiceManager.OnClientCommand(slot, args);
auto result = globals::conCommandManager.ExecuteCommandCallbacks(
cmd, CCommandContext(CommandTarget_t::CT_NO_TARGET, slot), args, HookMode::Pre);
@@ -302,11 +305,11 @@ int PlayerManager::ListenClient() const { return m_listen_client; }
int PlayerManager::NumPlayers() const { return m_player_count; }
int PlayerManager::MaxClients() const { return m_max_clients; }
int PlayerManager::MaxClients() const { return globals::getGlobalVars()->maxClients; }
CPlayer* PlayerManager::GetPlayerBySlot(int client) const
{
if (client > m_max_clients || client < 0) {
if (client > MaxClients() || client < 0) {
return nullptr;
}
@@ -426,7 +429,6 @@ INetChannelInfo* CPlayer::GetNetInfo() const { return globals::engine->GetPlayer
PlayerManager::PlayerManager()
{
m_max_clients = 64;
m_players = new CPlayer[66];
m_player_count = 0;
m_user_id_lookup = new int[USHRT_MAX + 1];
@@ -441,7 +443,7 @@ void PlayerManager::RunAuthChecks()
m_last_auth_check_time = globals::timerSystem.GetTickedTime();
for (int i = 0; i <= m_max_clients; i++) {
for (int i = 0; i <= MaxClients(); i++) {
if (m_players[i].IsConnected()) {
if (m_players[i].IsAuthorized() || m_players[i].IsFakeClient())
continue;
@@ -532,6 +534,23 @@ float CPlayer::GetLatency() const
return GetNetInfo()->GetLatency(FLOW_INCOMING) + GetNetInfo()->GetLatency(FLOW_OUTGOING);
}
void CPlayer::SetListen(CPlayerSlot slot, ListenOverride listen)
{
m_listenMap[slot.Get()] = listen;
}
void CPlayer::SetVoiceFlags(VoiceFlag_t flags)
{
m_voiceFlag = flags;
}
VoiceFlag_t CPlayer::GetVoiceFlags() { return m_voiceFlag; }
ListenOverride CPlayer::GetListen(CPlayerSlot slot) const
{
return m_listenMap[slot.Get()];
}
void CPlayer::Connect()
{
if (m_is_in_game) {
@@ -551,6 +570,9 @@ void CPlayer::Disconnect()
m_user_id = -1;
m_is_authorized = false;
m_ip_address.clear();
m_selfMutes->ClearAll();
memset(m_listenMap, 0, sizeof m_listenMap);
m_voiceFlag = 0;
}
QAngle CPlayer::GetAbsAngles() const { return m_info->GetAbsAngles(); }

View File

@@ -45,6 +45,25 @@ namespace counterstrikesharp {
class ScriptCallback;
class CBaseEntityWrapper;
enum ListenOverride
{
Listen_Default = 0,
Listen_Mute,
Listen_Hear
};
enum VoiceFlagValue
{
Speak_Normal = 0,
Speak_Muted = 1 << 0,
Speak_All = 1 << 1,
Speak_ListenAll = 1 << 2,
Speak_Team = 1 << 3,
Speak_ListenTeam = 1 << 4,
};
typedef uint8_t VoiceFlag_t;
class CPlayer {
friend class PlayerManager;
@@ -92,6 +111,10 @@ public:
int GetUserId() const;
float GetTimeConnected() const;
float GetLatency() const;
void SetListen(CPlayerSlot slot, ListenOverride listen);
void SetVoiceFlags(VoiceFlag_t flags);
VoiceFlag_t GetVoiceFlags();
ListenOverride GetListen(CPlayerSlot slot) const;
public:
std::string m_name;
@@ -105,6 +128,9 @@ public:
CPlayerSlot m_slot = CPlayerSlot(-1);
const CSteamID* m_steamId;
std::string m_ip_address;
ListenOverride m_listenMap[66] = {};
VoiceFlag_t m_voiceFlag = 0;
CPlayerBitVec m_selfMutes[64] = {};
void SetName(const char *name);
INetChannelInfo *GetNetInfo() const;
};

View File

@@ -0,0 +1,129 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
#include "core/managers/voice_manager.h"
#include "core/managers/player_manager.h"
#include <public/eiface.h>
#include "scripting/callback_manager.h"
#include <schema.h>
#include <entity2/entitysystem.h>
SH_DECL_HOOK3(IVEngineServer2, SetClientListening, SH_NOATTRIB, 0, bool, CPlayerSlot, CPlayerSlot,
bool);
namespace counterstrikesharp {
VoiceManager::VoiceManager() {}
VoiceManager::~VoiceManager() {}
void VoiceManager::OnAllInitialized()
{
SH_ADD_HOOK(IVEngineServer2, SetClientListening, globals::engine,
SH_MEMBER(this, &VoiceManager::SetClientListening), false);
}
void VoiceManager::OnShutdown()
{
SH_REMOVE_HOOK(IVEngineServer2, SetClientListening, globals::engine,
SH_MEMBER(this, &VoiceManager::SetClientListening), false);
}
bool VoiceManager::SetClientListening(CPlayerSlot iReceiver, CPlayerSlot iSender, bool bListen)
{
auto pReceiver = globals::playerManager.GetPlayerBySlot(iReceiver.Get());
auto pSender = globals::playerManager.GetPlayerBySlot(iSender.Get());
if (pReceiver && pSender)
{
auto listenOverride = pReceiver->GetListen(iSender);
auto senderFlags = pSender->GetVoiceFlags();
auto receiverFlags = pReceiver->GetVoiceFlags();
if (pReceiver->m_selfMutes->Get(iSender.Get()))
{
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
(iReceiver, iSender, false));
}
if (senderFlags & Speak_Muted)
{
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
(iReceiver, iSender, false));
}
if (listenOverride == Listen_Mute)
{
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
(iReceiver, iSender, false));
} else if (listenOverride == Listen_Hear) {
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
(iReceiver, iSender, true));
}
if ((senderFlags & Speak_All) || (receiverFlags & Speak_ListenAll)) {
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen, &IVEngineServer2::SetClientListening,
(iReceiver, iSender, true));
}
if ((senderFlags & Speak_Team) || (receiverFlags & Speak_ListenTeam))
{
static auto classKey = hash_32_fnv1a_const("CBaseEntity");
static auto memberKey = hash_32_fnv1a_const("m_iTeamNum");
const static auto m_key = schema::GetOffset("CBaseEntity", classKey, "m_iTeamNum", memberKey);
auto receiverController = globals::entitySystem->GetBaseEntity(CEntityIndex(iReceiver.Get() + 1));
auto senderController = globals::entitySystem->GetBaseEntity(CEntityIndex(iSender.Get() + 1));
if (receiverController && senderController)
{
auto receiverTeam = *reinterpret_cast<std::add_pointer_t<unsigned int>>(
(uintptr_t)(receiverController) + m_key.offset);
auto senderTeam = *reinterpret_cast<std::add_pointer_t<unsigned int>>(
(uintptr_t)(senderController) + m_key.offset);
RETURN_META_VALUE_NEWPARAMS(MRES_IGNORED, bListen,
&IVEngineServer2::SetClientListening,
(iReceiver, iSender, receiverTeam == senderTeam));
}
}
}
RETURN_META_VALUE(MRES_IGNORED, bListen);
}
void VoiceManager::OnClientCommand(CPlayerSlot slot, const CCommand& args)
{
auto pPlayer = globals::playerManager.GetPlayerBySlot(slot.Get());
if (!pPlayer)
return;
if (args.ArgC() > 1 && stricmp(args.Arg(0), "vban") == 0)
{
// clients just refuse to send vban for indexes over 32 and all 4 fields are just the same number, so we only get the first one
//for (int i = 1; (i < args.ArgC()) && (i < 3); i++) {
unsigned int mask = 0;
sscanf(args.Arg(1), "%x", &mask);
pPlayer->m_selfMutes->SetDWord(0, mask);
//}
}
}
} // namespace counterstrikesharp

View File

@@ -0,0 +1,38 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
#pragma once
#include "core/globals.h"
#include "core/global_listener.h"
#include "scripting/script_engine.h"
namespace counterstrikesharp {
class ScriptCallback;
class VoiceManager : public GlobalClass
{
public:
VoiceManager();
~VoiceManager();
void OnAllInitialized() override;
void OnShutdown() override;
bool SetClientListening(CPlayerSlot iReceiver, CPlayerSlot iSender, bool bListen);
void OnClientCommand(CPlayerSlot slot, const CCommand& args);
private:
};
} // namespace counterstrikesharp

View File

@@ -0,0 +1,129 @@
/*
* This file is part of CounterStrikeSharp.
* CounterStrikeSharp is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CounterStrikeSharp is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with CounterStrikeSharp. If not, see <https://www.gnu.org/licenses/>. *
*/
#include "scripting/autonative.h"
#include "scripting/script_engine.h"
#include "core/managers/player_manager.h"
#include <public/entity2/entitysystem.h>
namespace counterstrikesharp {
void SetClientListening(ScriptContext& scriptContext)
{
auto receiver = scriptContext.GetArgument<CBaseEntity*>(0);
auto sender = scriptContext.GetArgument<CBaseEntity*>(1);
auto listen = scriptContext.GetArgument<ListenOverride>(2);
if (!receiver) {
scriptContext.ThrowNativeError("Receiver is a null pointer");
return;
}
if (!sender) {
scriptContext.ThrowNativeError("Sender is a null pointer");
return;
}
auto iSenderSlot = sender->GetEntityIndex().Get() - 1;
if (iSenderSlot < 0 || iSenderSlot >= globals::getGlobalVars()->maxClients)
scriptContext.ThrowNativeError("Invalid sender");
auto pPlayer = globals::playerManager.GetPlayerBySlot(receiver->GetEntityIndex().Get() - 1);
if (pPlayer == nullptr) {
scriptContext.ThrowNativeError("Invalid receiver");
return;
}
pPlayer->SetListen(iSenderSlot, listen);
}
ListenOverride GetClientListening(ScriptContext& scriptContext)
{
auto receiver = scriptContext.GetArgument<CBaseEntity*>(0);
auto sender = scriptContext.GetArgument<CBaseEntity*>(1);
if (!receiver) {
scriptContext.ThrowNativeError("Receiver is a null pointer");
return Listen_Default;
}
if (!sender) {
scriptContext.ThrowNativeError("Sender is a null pointer");
return Listen_Default;
}
auto iSenderSlot = sender->GetEntityIndex().Get() - 1;
if (iSenderSlot < 0 || iSenderSlot >= globals::getGlobalVars()->maxClients)
scriptContext.ThrowNativeError("Invalid sender");
auto pPlayer = globals::playerManager.GetPlayerBySlot(receiver->GetEntityIndex().Get() - 1);
if (pPlayer == nullptr) {
scriptContext.ThrowNativeError("Invalid receiver");
return Listen_Default;
}
return pPlayer->GetListen(iSenderSlot);
}
void SetClientVoiceFlags(ScriptContext& scriptContext)
{
auto client = scriptContext.GetArgument<CBaseEntity*>(0);
auto flags = scriptContext.GetArgument<VoiceFlag_t>(1);
if (!client) {
scriptContext.ThrowNativeError("Receiver is a null pointer");
return;
}
auto pPlayer = globals::playerManager.GetPlayerBySlot(client->GetEntityIndex().Get() - 1);
if (pPlayer == nullptr) {
scriptContext.ThrowNativeError("Invalid receiver");
return;
}
pPlayer->SetVoiceFlags(flags);
}
VoiceFlag_t GetClientVoiceFlags(ScriptContext& scriptContext)
{
auto client = scriptContext.GetArgument<CBaseEntity*>(0);
if (!client) {
scriptContext.ThrowNativeError("Receiver is a null pointer");
return VoiceFlag_t{};
}
auto pPlayer = globals::playerManager.GetPlayerBySlot(client->GetEntityIndex().Get() - 1);
if (pPlayer == nullptr) {
scriptContext.ThrowNativeError("Invalid receiver");
}
return pPlayer->GetVoiceFlags();
}
REGISTER_NATIVES(voice, {
ScriptEngine::RegisterNativeHandler("SET_CLIENT_LISTENING", SetClientListening);
ScriptEngine::RegisterNativeHandler("GET_CLIENT_LISTENING", GetClientListening);
ScriptEngine::RegisterNativeHandler("SET_CLIENT_VOICE_FLAGS", SetClientVoiceFlags);
ScriptEngine::RegisterNativeHandler("GET_CLIENT_VOICE_FLAGS", GetClientVoiceFlags);
})
} // namespace counterstrikesharp

View File

@@ -0,0 +1,4 @@
SET_CLIENT_LISTENING: receiver:pointer, sender:pointer, listen:uint -> void
GET_CLIENT_LISTENING: receiver:pointer, sender:pointer -> ListenOverride
SET_CLIENT_VOICE_FLAGS: client:pointer, flags:uint -> void
GET_CLIENT_VOICE_FLAGS: client:pointer -> uint

View File

@@ -63,6 +63,8 @@ public class Mapping
return "[CastFrom(typeof(ulong))]SteamID";
case "HookMode":
return "HookMode";
case "ListenOverride":
return "ListenOverride";
case "DataType_t":
return "DataType";
case "any":