diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 3c79d501..e9a2bf5e 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -207,6 +207,28 @@ static cell_t IsSoundPrecached(IPluginContext *pContext, const cell_t *params) return enginesound->IsSoundPrecached(sample) ? 1 : 0; } +static cell_t FakeClientCommand(IPluginContext *pContext, const cell_t *params) +{ + CPlayer *pPlayer = g_Players.GetPlayerByIndex(params[1]); + + if (!pPlayer) + { + return pContext->ThrowNativeError("Player %d is not a valid player", params[1]); + } + + if (!pPlayer->IsConnected()) + { + return pContext->ThrowNativeError("Player %d is not connected", params[1]); + } + + char buffer[256]; + g_SourceMod.FormatString(buffer, sizeof(buffer)-1, pContext, params, 2); + + serverpluginhelpers->ClientCommand(pPlayer->GetEdict(), buffer); + + return 1; +} + REGISTER_NATIVES(halflifeNatives) { {"CreateFakeClient", CreateFakeClient}, @@ -229,5 +251,6 @@ REGISTER_NATIVES(halflifeNatives) {"IsGenericPrecached", IsGenericPrecached}, {"PrecacheSound", PrecacheSound}, {"IsSoundPrecached", IsSoundPrecached}, + {"FakeClientCommand", FakeClientCommand}, {NULL, NULL}, }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index c2461049..387c7a1f 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -31,6 +31,7 @@ CallClass *gamedllPatch = NULL; IPlayerInfoManager *playerinfo = NULL; IBaseFileSystem *basefilesystem = NULL; IEngineSound *enginesound = NULL; +IServerPluginHelpers *serverpluginhelpers = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); @@ -46,6 +47,7 @@ bool SourceMod_Core::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen GET_V_IFACE_CURRENT(engineFactory, engrandom, IUniformRandomStream, VENGINE_SERVER_RANDOM_INTERFACE_VERSION); GET_V_IFACE_CURRENT(fileSystemFactory, basefilesystem, IBaseFileSystem, BASEFILESYSTEM_INTERFACE_VERSION); GET_V_IFACE_CURRENT(engineFactory, enginesound, IEngineSound, IENGINESOUND_SERVER_INTERFACE_VERSION); + GET_V_IFACE_CURRENT(engineFactory, serverpluginhelpers, IServerPluginHelpers, INTERFACEVERSION_ISERVERPLUGINHELPERS); /* :TODO: Make this optional and... make it find earlier versions [?] */ GET_V_IFACE_CURRENT(serverFactory, playerinfo, IPlayerInfoManager, INTERFACEVERSION_PLAYERINFOMANAGER); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index a35c327e..8e3b7612 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -61,6 +61,7 @@ extern IUniformRandomStream *engrandom; extern IPlayerInfoManager *playerinfo; extern IBaseFileSystem *basefilesystem; extern IEngineSound *enginesound; +extern IServerPluginHelpers *serverpluginhelpers; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) #define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index 2ff3bdbc..4fca185f 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -387,5 +387,16 @@ native bool:PrecacheSound(const String:sound[], bool:preload=false); */ native bool:IsSoundPrecached(const String:sound[]); +/** + * Executes a client command on the server without being networked. + * + * @param client Index of the client. + * @param fmt Format of the client command. + * @param ... Format parameters + * @noreturn + * @error Invalid client index, or client not connected. + */ +native FakeClientCommand(client, const String:fmt[], any:...); + #include #include