From 1cc70a46eb4a34885153577d817aa09581172a19 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Feb 2007 05:26:54 +0000 Subject: [PATCH] added a crapload of random natives --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40538 --- core/smn_console.cpp | 23 +++++ core/smn_halflife.cpp | 162 +++++++++++++++++++++++++++++++++- core/sourcemm_api.cpp | 1 + core/sourcemm_api.h | 2 + core/sourcemod.cpp | 7 ++ plugins/include/console.inc | 12 +++ plugins/include/sourcemod.inc | 106 ++++++++++++++++++++++ 7 files changed, 312 insertions(+), 1 deletion(-) diff --git a/core/smn_console.cpp b/core/smn_console.cpp index e1277d71..08c2461a 100644 --- a/core/smn_console.cpp +++ b/core/smn_console.cpp @@ -512,6 +512,28 @@ static cell_t sm_ServerExecute(IPluginContext *pContext, const cell_t *params) return 1; } +static cell_t sm_ClientCommand(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); + + engine->ClientCommand(pPlayer->GetEdict(), "%s", buffer); + + return 1; +} + REGISTER_NATIVES(consoleNatives) { {"CreateConVar", sm_CreateConVar}, @@ -543,5 +565,6 @@ REGISTER_NATIVES(consoleNatives) {"ServerCommand", sm_ServerCommand}, {"InsertServerCommand", sm_InsertServerCommand}, {"ServerExecute", sm_ServerExecute}, + {"ClientCommand", sm_ClientCommand}, {NULL, NULL} }; diff --git a/core/smn_halflife.cpp b/core/smn_halflife.cpp index 32d7a6cb..214d93db 100644 --- a/core/smn_halflife.cpp +++ b/core/smn_halflife.cpp @@ -12,7 +12,9 @@ */ #include "sm_globals.h" +#include "sourcemod.h" #include "sourcemm_api.h" +#include "CPlayerManager.h" static cell_t SetRandomSeed(IPluginContext *pContext, const cell_t *params) { @@ -36,10 +38,168 @@ static cell_t GetRandomInt(IPluginContext *pContext, const cell_t *params) return engrandom->RandomInt(params[1], params[2]); } +static cell_t IsMapValid(IPluginContext *pContext, const cell_t *params) +{ + char *map; + pContext->LocalToString(params[1], &map); + + return engine->IsMapValid(map); +} + +static cell_t IsDedicatedServer(IPluginContext *pContext, const cell_t *params) +{ + return engine->IsDedicatedServer(); +} + +static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params) +{ + return engine->GetEntityCount(); +} + +static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict) + { + return 0; + } + + /* Shouldn't be necessary... not sure though */ + return pEdict->IsFree() ? 0 : 1; +} + +static cell_t CreateEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->CreateEdict(); + + if (!pEdict) + { + return 0; + } + + return engine->IndexOfEdict(pEdict); +} + +static cell_t RemoveEdict(IPluginContext *pContext, const cell_t *params) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(params[1]); + + if (!pEdict) + { + return pContext->ThrowNativeError("Edict %d is not a valid edict", params[1]); + } + + engine->RemoveEdict(pEdict); + + return 1; +} + +static cell_t GetEngineTime(IPluginContext *pContext, const cell_t *params) +{ + float fTime = engine->Time(); + return sp_ftoc(fTime); +} + +static cell_t GetGameTime(IPluginContext *pContext, const cell_t *params) +{ + return sp_ftoc(gpGlobals->curtime); +} + +static cell_t CreateFakeClient(IPluginContext *pContext, const cell_t *params) +{ + char *netname; + + pContext->LocalToString(params[1], &netname); + + edict_t *pEdict = engine->CreateFakeClient(netname); + + /* :TODO: does the engine fire forwards for us and whatnot? no idea... */ + + if (!pEdict) + { + return 0; + } + + return engine->IndexOfEdict(pEdict); +} + +static cell_t SetFakeClientConVar(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]); + } + + if (!pPlayer->IsFakeClient()) + { + return pContext->ThrowNativeError("Player %d is not a fake client", params[1]); + } + + char *cvar, *value; + + pContext->LocalToString(params[2], &cvar); + pContext->LocalToString(params[3], &value); + + engine->SetFakeClientConVarValue(pPlayer->GetEdict(), cvar, value); + + return 1; +} + +static cell_t GetGameDescription(IPluginContext *pContext, const cell_t *params) +{ + const char *description; + + if (params[3]) + { + description = gamedll->GetGameDescription(); + } else { + description = SERVER_CALL(GetGameDescription)(); + } + + size_t numBytes; + + pContext->StringToLocalUTF8(params[1], params[2], description, &numBytes); + + return numBytes; +} + +static cell_t GetMaxEntities(IPluginContext *pContext, const cell_t *params) +{ + return gpGlobals->maxEntities; +} + +static cell_t GetCurrentMap(IPluginContext *pContext, const cell_t *params) +{ + size_t bytes; + pContext->StringToLocalUTF8(params[1], params[2], STRING(gpGlobals->mapname), &bytes); + return bytes; +} + REGISTER_NATIVES(halflifeNatives) { - {"SetRandomSeed", SetRandomSeed}, + {"CreateEdict", CreateEdict}, + {"CreateFakeClient", CreateFakeClient}, + {"GetCurrentMap", GetCurrentMap}, + {"GetEngineTime", GetEngineTime}, + {"GetEntityCount", GetEntityCount}, + {"GetGameDescription", GetGameDescription}, + {"GetGameTime", GetGameTime}, + {"GetMaxEntities", GetMaxEntities}, {"GetRandomFloat", GetRandomFloat}, {"GetRandomInt", GetRandomInt}, + {"IsDedicatedServer", IsDedicatedServer}, + {"IsMapValid", IsMapValid}, + {"IsValidEntity", IsValidEntity}, + {"RemoveEdict", RemoveEdict}, + {"SetFakeClientConVar", SetFakeClientConVar}, + {"SetRandomSeed", SetRandomSeed}, {NULL, NULL}, }; diff --git a/core/sourcemm_api.cpp b/core/sourcemm_api.cpp index 10f003b0..3856b907 100644 --- a/core/sourcemm_api.cpp +++ b/core/sourcemm_api.cpp @@ -26,6 +26,7 @@ ICvar *icvar = NULL; IGameEventManager2 *gameevents = NULL; IUniformRandomStream *engrandom = NULL; CallClass *enginePatch = NULL; +CallClass *gamedllPatch = NULL; PLUGIN_EXPOSE(SourceMod, g_SourceMod_Core); diff --git a/core/sourcemm_api.h b/core/sourcemm_api.h index 6a64614a..317215d5 100644 --- a/core/sourcemm_api.h +++ b/core/sourcemm_api.h @@ -53,9 +53,11 @@ extern ISmmPluginManager *g_pMMPlugins; extern CGlobalVars *gpGlobals; extern IGameEventManager2 *gameevents; extern SourceHook::CallClass *enginePatch; +extern SourceHook::CallClass *gamedllPatch; extern IUniformRandomStream *engrandom; #define ENGINE_CALL(func) SH_CALL(enginePatch, &IVEngineServer::func) +#define SERVER_CALL(func) SH_CALL(gamedllPatch, &IServerGameDLL::func) PLUGIN_GLOBALVARS(); diff --git a/core/sourcemod.cpp b/core/sourcemod.cpp index 83823d46..950793d1 100644 --- a/core/sourcemod.cpp +++ b/core/sourcemod.cpp @@ -160,6 +160,7 @@ void SourceModBase::StartSourceMod(bool late) SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); enginePatch = SH_GET_CALLCLASS(engine); + gamedllPatch = SH_GET_CALLCLASS(gamedll); /* Notify! */ SMGlobalClass *pBase = SMGlobalClass::head; @@ -345,6 +346,12 @@ void SourceModBase::CloseSourceMod() enginePatch = NULL; } + if (gamedllPatch) + { + SH_RELEASE_CALLCLASS(gamedllPatch); + gamedllPatch = NULL; + } + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false); diff --git a/plugins/include/console.inc b/plugins/include/console.inc index 9fa93148..c9a20c20 100644 --- a/plugins/include/console.inc +++ b/plugins/include/console.inc @@ -77,6 +77,18 @@ native InsertServerCommand(const String:format[], {Handle,Float,String,_}:...); */ native ServerExecute(); +/** + * Executes a client command. Note that this will not work on clients unless + * they have cl_restrict_server_commands set to 0. + * + * @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 ClientCommand(client, const String:fmt[], {String,Float,Handle,_}:...); + /** * Sends a message to the server console. * diff --git a/plugins/include/sourcemod.inc b/plugins/include/sourcemod.inc index e62be797..fcdd3eef 100644 --- a/plugins/include/sourcemod.inc +++ b/plugins/include/sourcemod.inc @@ -373,6 +373,112 @@ native Float:GetRandomFloat(Float:fMin=0.0, Float:fMax=1.0); */ native GetRandomInt(nmin, nmax); +/** + * Returns whether a map is valid or not. + * + * @param Map name, excluding .bsp extension. + * @return True if valid, false otherwise. + */ +native bool:IsMapValid(const String:map[]); + +/** + * Returns whether the server is dedicated. + * + * @return True if dedicated, false otherwise. + */ +native bool:IsDedicatedServer(); + +/** + * Returns the number of entities in the server. + * + * @return Number of entities in the server. + */ +native GetEntityCount(); + +/** + * Returns whether or not an entity is valid. + * + * @param entity Index of the entity. + * @return True if valid, false otherwise. + */ +native bool:IsValidEntity(entity); + +/** + * Creates a new edict (the basis of a networkable entity) + * + * @return Index of the entity, 0 on failure. + */ +native CreateEdict(); + +/** + * Removes an edict from the world. + * + * @param entity Index of the entity. + * @noreturn + * @error Invalid entity index. + */ +native RemoveEntity(entity); + +/** + * Returns a high-precision time value for profiling the engine. + * + * @return A floating point time value. + */ +native Float:GetEngineTime(); + +/** + * Returns the game time based on the game tick. + * + * @return Game tick time. + */ +native Float:GetGameTime(); + +/** + * Creates a fake client. + * + * @param name Name to use. + * @return Client index on success, 0 otherwise. + */ +native CreateFakeClient(const String:name[]); + +/** + * Sets a convar value on a fake client. + * + * @param client Client index. + * @param cvar ConVar name. + * @param value ConVar value. + * @noreturn + * @error Invalid client index, client not connected, + * or client not a fake client. + */ +native SetFakeClientConVar(client, const String:cvar[], const String:value[]); + +/** + * Returns the game description from the mod. + * + * @param buffer Buffer to store the description. + * @param maxlength Maximum size of the buffer. + * @param original If true, retrieves the original game description, + * ignoring any potential hooks from plugins. + * @return Number of bytes written to the buffer (UTF-8 safe). + */ +native GetGameDescription(String:buffer[], maxlength, bool:original=false); + +/** + * Returns the maximum number of entities. + * + * @return Maximum number of entities. + */ +native GetMaxEntities(); + +/** + * Returns the current map name. + * + * @param buffer Buffer to store map name. + * @param maxlength Maximum length of buffer. + * @return Number of bytes written (UTF-8 safe). + */ +native GetCurrentMap(String:buffer[], maxlength); #include #include