Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add replicate convar #563

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions configs/addons/counterstrikesharp/gamedata/gamedata.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,5 +239,11 @@
"windows": 2,
"linux": 0
}
},
"CNetworkGameServer_ClientList": {
"offsets": {
"windows": 78,
"linux": 80
}
}
}
12 changes: 12 additions & 0 deletions managed/CounterStrikeSharp.API/Core/API.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,18 @@ public static void SetFakeClientConvarValue(int clientindex, string convarname,
}
}

public static void ReplicateConvar(int clientslot, string convarname, string convarvalue){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
ScriptContext.GlobalScriptContext.Push(clientslot);
ScriptContext.GlobalScriptContext.Push(convarname);
ScriptContext.GlobalScriptContext.Push(convarvalue);
ScriptContext.GlobalScriptContext.SetIdentifier(0xC8728BEC);
ScriptContext.GlobalScriptContext.Invoke();
ScriptContext.GlobalScriptContext.CheckErrors();
}
}

public static T DynamicHookGetReturn<T>(IntPtr hook, int datatype){
lock (ScriptContext.GlobalScriptContext.Lock) {
ScriptContext.GlobalScriptContext.Reset();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,4 +340,9 @@ public VoiceFlags VoiceFlags
NativeAPI.SetClientVoiceFlags(Handle, (Byte)value);
}
}

public void ReplicateConVar(string conVar, string value)
{
NativeAPI.ReplicateConvar(Slot, conVar, value);
}
}
58 changes: 58 additions & 0 deletions src/core/cs2_sdk/serversideclient.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#pragma once

#include "inetchannel.h"
#include "networkbasetypes.pb.h"
#include "playerslot.h"
#include "steam/steamclientpublic.h"
#include "utlstring.h"

class CServerSideClient : public INetworkMessageProcessingPreFilter
{
public:
virtual ~CServerSideClient() = 0;

INetChannel* GetNetChannel() const { return m_NetChannel; };
CPlayerSlot GetPlayerSlot() const { return m_nClientSlot; };
CEntityIndex GetEntityIndex() const { return m_nEntityIndex; };
CPlayerUserId GetUserID() const { return m_UserID; };
int GetSignonState() const { return m_nSignonState; }
CSteamID GetClientSteamID() const { return m_SteamID; }
const char* GetClientName() const { return m_Name; };
bool IsConnected() const { return m_nSignonState >= SIGNONSTATE_CONNECTED; };
bool IsSpawned() const { return m_nSignonState >= SIGNONSTATE_NEW; };
bool IsActive() const { return m_nSignonState == SIGNONSTATE_FULL; };
bool IsFakeClient() const { return m_bFakePlayer; };
bool IsHLTV() const { return m_bIsHLTV; }
bool IsFullyAuthenticated() { return m_bFullyAuthenticated; }
const netadr_t* GetRemoteAddress() const { return &m_NetAdr0; }

private:
[[maybe_unused]] void* m_pVT1; // INetworkMessageProcessingPreFilter
[[maybe_unused]] char pad1[0x30];
#ifdef __linux__
[[maybe_unused]] char pad2[0x10];
#endif
CUtlString m_Name; // 64 | 80
CPlayerSlot m_nClientSlot; // 72 | 88
CEntityIndex m_nEntityIndex; // 76 | 92
[[maybe_unused]] char pad3[0x8];
INetChannel* m_NetChannel; // 88 | 104
[[maybe_unused]] char pad4[0x4];
int32 m_nSignonState; // 100 | 116
[[maybe_unused]] char pad5[0x38];
bool m_bFakePlayer; // 160 | 176
[[maybe_unused]] char pad6[0x7];
CPlayerUserId m_UserID; // 168 | 184
[[maybe_unused]] char pad7[0x1];
CSteamID m_SteamID; // 171 | 187
[[maybe_unused]] char pad8[0x19];
netadr_t m_NetAdr0; // 204 | 220
[[maybe_unused]] char pad9[0x14];
netadr_t m_NetAdr1; // 236 | 252
[[maybe_unused]] char pad10[0x22];
bool m_bIsHLTV; // 282 | 298
[[maybe_unused]] char pad11[0x19];
int m_nDeltaTick; // 308 | 324
[[maybe_unused]] char pad12[0x882];
bool m_bFullyAuthenticated; // 2490 | 2506
};
11 changes: 11 additions & 0 deletions src/core/globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "core/managers/server_manager.h"
#include "core/managers/voice_manager.h"
#include "core/managers/usermessage_manager.h"
#include "serversideclient.h"
#include "utlvector.h"
#include <public/game/server/iplayerinfo.h>
#include <public/entity2/entitysystem.h>

Expand All @@ -32,6 +34,14 @@

namespace counterstrikesharp {

CUtlVector<CServerSideClient*>* GetClientList()
{
if (!globals::networkGameServer) return nullptr;

static int offset = globals::gameConfig->GetOffset("CNetworkGameServer_ClientList");
return (CUtlVector<CServerSideClient*>*)(&globals::networkGameServer[offset]);
}

namespace modules {
std::vector<std::unique_ptr<CModule>> moduleList{};
CModule* engine = nullptr;
Expand All @@ -53,6 +63,7 @@ IUniformRandomStream* randomStream = nullptr;
IEngineTrace* engineTrace = nullptr;
IEngineSound* engineSound = nullptr;
IEngineServiceMgr* engineServiceManager = nullptr;
INetworkGameServer* networkGameServer = nullptr;
INetworkMessages* networkMessages = nullptr;
INetworkStringTableContainer* netStringTables = nullptr;
CGlobalVars* globalVars = nullptr;
Expand Down
2 changes: 2 additions & 0 deletions src/core/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class CounterStrikeSharpMMPlugin;
class CGameEntitySystem;
class IGameEventListener2;
class CSchemaSystem;
class INetworkGameServer;

namespace counterstrikesharp {
class EntityListener;
Expand Down Expand Up @@ -81,6 +82,7 @@ extern IFileSystem* fileSystem;
extern IServerGameDLL* serverGameDll;
extern IServerGameClients* serverGameClients;
extern INetworkServerService* networkServerService;
extern INetworkGameServer* networkGameServer;
extern CSchemaSystem* schemaSystem;
extern IServerTools* serverTools;
extern IPhysics* physics;
Expand Down
1 change: 1 addition & 0 deletions src/mm_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ bool CounterStrikeSharpMMPlugin::Load(PluginId id, ISmmAPI* ismm, char* error, s

void CounterStrikeSharpMMPlugin::Hook_StartupServer(const GameSessionConfiguration_t& config, ISource2WorldSession*, const char*)
{
globals::networkGameServer = globals::networkServerService->GetIGameServer();
globals::entitySystem = interfaces::pGameResourceServiceServer->GetGameEntitySystem();
globals::entitySystem->AddListenerEntity(&globals::entityManager.entityListener);
globals::timerSystem.OnStartupServer();
Expand Down
78 changes: 59 additions & 19 deletions src/scripting/natives/natives_commands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@
*/

#include <eiface.h>
#include <inetchannel.h>
#include <networksystem/inetworkmessages.h>
#include <networksystem/inetworkserializer.h>

#include "scripting/autonative.h"
#include "scripting/callback_manager.h"
#include "core/log.h"
#include "core/managers/con_command_manager.h"
#include "core/managers/player_manager.h"
#include "scripting/autonative.h"
#include "scripting/callback_manager.h"
#include "scripting/script_engine.h"
#include "core/log.h"
#include "serversideclient.h"
#include "utlvector.h"
#include <networkbasetypes.pb.h>

namespace counterstrikesharp {

Expand All @@ -33,8 +39,7 @@ static void AddCommand(ScriptContext& script_context)
auto flags = script_context.GetArgument<int>(3);
auto callback = script_context.GetArgument<CallbackT>(4);

CSSHARP_CORE_TRACE("Adding command {}, {}, {}, {}, {}", name, description, server_only, flags,
(void*)callback);
CSSHARP_CORE_TRACE("Adding command {}, {}, {}, {}, {}", name, description, server_only, flags, (void*)callback);

globals::conCommandManager.AddValveCommand(name, description, server_only, flags);
globals::conCommandManager.AddCommandListener(name, callback, HookMode::Pre);
Expand All @@ -55,8 +60,7 @@ static void AddCommandListener(ScriptContext& script_context)
auto callback = script_context.GetArgument<CallbackT>(1);
auto post = script_context.GetArgument<bool>(2);

globals::conCommandManager.AddCommandListener(name, callback,
post ? HookMode::Post : HookMode::Pre);
globals::conCommandManager.AddCommandListener(name, callback, post ? HookMode::Post : HookMode::Pre);
}

static void RemoveCommandListener(ScriptContext& script_context)
Expand All @@ -65,15 +69,15 @@ static void RemoveCommandListener(ScriptContext& script_context)
auto callback = script_context.GetArgument<CallbackT>(1);
auto post = script_context.GetArgument<bool>(2);

globals::conCommandManager.RemoveCommandListener(name, callback,
post ? HookMode::Post : HookMode::Pre);
globals::conCommandManager.RemoveCommandListener(name, callback, post ? HookMode::Post : HookMode::Pre);
}

static int CommandGetArgCount(ScriptContext& script_context)
{
auto command = script_context.GetArgument<CCommand*>(0);

if (!command) {
if (!command)
{
script_context.ThrowNativeError("Invalid command.");
return -1;
}
Expand All @@ -85,7 +89,8 @@ static const char* CommandGetArgString(ScriptContext& script_context)
{
auto command = script_context.GetArgument<CCommand*>(0);

if (!command) {
if (!command)
{
script_context.ThrowNativeError("Invalid command.");
return nullptr;
}
Expand All @@ -97,7 +102,8 @@ static const char* CommandGetCommandString(ScriptContext& script_context)
{
auto* command = script_context.GetArgument<CCommand*>(0);

if (!command) {
if (!command)
{
script_context.ThrowNativeError("Invalid command.");
return nullptr;
}
Expand All @@ -110,7 +116,8 @@ static const char* CommandGetArgByIndex(ScriptContext& script_context)
auto* command = script_context.GetArgument<CCommand*>(0);
auto index = script_context.GetArgument<int>(1);

if (!command) {
if (!command)
{
script_context.ThrowNativeError("Invalid command.");
return nullptr;
}
Expand Down Expand Up @@ -142,8 +149,7 @@ static void IssueClientCommandFromServer(ScriptContext& script_context)
args.Tokenize(pszCommand);

auto handle = globals::cvars->FindCommand(args.Arg(0));
if (!handle.IsValid())
return;
if (!handle.IsValid()) return;

CCommandContext context(CommandTarget_t::CT_NO_TARGET, CPlayerSlot(slot));

Expand Down Expand Up @@ -172,7 +178,8 @@ ConVar* FindConVar(ScriptContext& script_context)
auto name = script_context.GetArgument<const char*>(0);
auto hCvarHandle = globals::cvars->FindConVar(name, true);

if (!hCvarHandle.IsValid()) {
if (!hCvarHandle.IsValid())
{
return nullptr;
}

Expand All @@ -184,13 +191,46 @@ void SetConVarStringValue(ScriptContext& script_context)
auto pCvar = script_context.GetArgument<ConVar*>(0);
auto value = script_context.GetArgument<const char*>(1);

if (!pCvar) {
if (!pCvar)
{
script_context.ThrowNativeError("Invalid cvar.");
}

pCvar->values = reinterpret_cast<CVValue_t**>((char*)value);
}

extern CUtlVector<CServerSideClient*>* GetClientList();

void ReplicateConVar(ScriptContext& script_context)
{
auto slot = script_context.GetArgument<int>(0);
auto name = script_context.GetArgument<const char*>(1);
auto value = script_context.GetArgument<const char*>(2);

INetworkMessageInternal* pNetMsg = globals::networkMessages->FindNetworkMessagePartial("SetConVar");
auto data = pNetMsg->AllocateMessage()->ToPB<CNETMsg_SetConVar>();

CMsg_CVars_CVar* cvarMsg = data->mutable_convars()->add_cvars();
cvarMsg->set_name(name);
cvarMsg->set_value(value);

if (!GetClientList())
{
script_context.ThrowNativeError("Error retrieving client list.");
return;
}

auto client = GetClientList()->Element(slot);
if (!client)
{
script_context.ThrowNativeError("Invalid client.");
return;
}

client->GetNetChannel()->SendNetMessage(data, BUF_RELIABLE);
delete data;
}

REGISTER_NATIVES(commands, {
ScriptEngine::RegisterNativeHandler("ADD_COMMAND", AddCommand);
ScriptEngine::RegisterNativeHandler("REMOVE_COMMAND", RemoveCommand);
Expand All @@ -207,9 +247,9 @@ REGISTER_NATIVES(commands, {
ScriptEngine::RegisterNativeHandler("SET_CONVAR_STRING_VALUE", SetConVarStringValue);

ScriptEngine::RegisterNativeHandler("ISSUE_CLIENT_COMMAND", IssueClientCommand);
ScriptEngine::RegisterNativeHandler("ISSUE_CLIENT_COMMAND_FROM_SERVER",
IssueClientCommandFromServer);
ScriptEngine::RegisterNativeHandler("ISSUE_CLIENT_COMMAND_FROM_SERVER", IssueClientCommandFromServer);
ScriptEngine::RegisterNativeHandler("GET_CLIENT_CONVAR_VALUE", GetClientConVarValue);
ScriptEngine::RegisterNativeHandler("SET_FAKE_CLIENT_CONVAR_VALUE", SetFakeClientConVarValue);
ScriptEngine::RegisterNativeHandler("REPLICATE_CONVAR", ReplicateConVar);
})
} // namespace counterstrikesharp
3 changes: 2 additions & 1 deletion src/scripting/natives/natives_commands.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ ISSUE_CLIENT_COMMAND_FROM_SERVER: slot:int,command:string -> void
FIND_CONVAR: name:string -> pointer
SET_CONVAR_STRING_VALUE: convar:pointer,value:string -> void
GET_CLIENT_CONVAR_VALUE: clientIndex:int,convarName:string -> string
SET_FAKE_CLIENT_CONVAR_VALUE: clientIndex:int,convarName:string,convarValue:string -> void
SET_FAKE_CLIENT_CONVAR_VALUE: clientIndex:int,convarName:string,convarValue:string -> void
REPLICATE_CONVAR: clientSlot:int,convarName:string,convarValue:string -> void
Loading