3 * ================================================================
5 * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
6 * ================================================================
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License,
10 * version 3.0, as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to
21 * link the code of this program (as well as its derivative works) to
22 * "Half-Life 2," the "Source Engine," the "SourcePawn JIT," and any
23 * Game MODs that run on software by the Valve Corporation. You must
24 * obey the GNU General Public License in all respects for all other
25 * code used. Additionally, AlliedModders LLC grants this exception
26 * to all derivative works. AlliedModders LLC defines further
27 * exceptions, found in LICENSE.txt (as of this writing, version
28 * JULY-31-2007), or <http://www.sourcemod.net/license.php>.
35 #include "sm_stringutil.h"
36 #include "sm_globals.h"
37 #include "sourcemod.h"
38 #include "PluginSys.h"
39 #include "HandleSys.h"
40 #include "LibrarySys.h"
42 #if defined PLATFORM_WINDOWS
44 #elif defined PLATFORM_LINUX
47 #include <sys/times.h>
50 HandleType_t g_PlIter;
52 class CoreNativeHelpers :
54 public IHandleTypeDispatch
57 void OnSourceModAllInitialized()
60 g_HandleSys.InitAccessDefaults(NULL, &hacc);
61 hacc.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
63 g_PlIter = g_HandleSys.CreateType("PluginIterator", this, 0, NULL, NULL, g_pCoreIdent, NULL);
65 void OnHandleDestroy(HandleType_t type, void *object)
67 IPluginIterator *iter = (IPluginIterator *)object;
70 void OnSourceModShutdown()
72 g_HandleSys.RemoveType(g_PlIter, g_pCoreIdent);
74 } g_CoreNativeHelpers;
77 static cell_t ThrowError(IPluginContext *pContext, const cell_t *params)
81 g_SourceMod.SetGlobalTarget(LANG_SERVER);
83 g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 1);
85 if (pContext->GetContext()->n_err == SP_ERROR_NONE)
87 pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", buffer);
93 static cell_t GetTime(IPluginContext *pContext, const cell_t *params)
95 time_t t = time(NULL);
97 pContext->LocalToPhysAddr(params[1], &addr);
101 return static_cast<cell_t>(t);
104 static cell_t FormatTime(IPluginContext *pContext, const cell_t *params)
106 char *format, *buffer;
107 pContext->LocalToString(params[1], &buffer);
108 pContext->LocalToString(params[3], &format);
110 time_t t = (params[4] == -1) ? time(NULL) : (time_t)params[4];
111 strftime(buffer, params[2], format, localtime(&t));
116 static cell_t GetPluginIterator(IPluginContext *pContext, const cell_t *params)
118 IPluginIterator *iter = g_PluginSys.GetPluginIterator();
120 Handle_t hndl = g_HandleSys.CreateHandle(g_PlIter, iter, pContext->GetIdentity(), g_pCoreIdent, NULL);
122 if (hndl == BAD_HANDLE)
130 static cell_t MorePlugins(IPluginContext *pContext, const cell_t *params)
132 Handle_t hndl = (Handle_t)params[1];
134 IPluginIterator *pIter;
137 sec.pIdentity = g_pCoreIdent;
138 sec.pOwner = pContext->GetIdentity();
140 if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
142 return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
145 return pIter->MorePlugins() ? 1 : 0;
148 static cell_t ReadPlugin(IPluginContext *pContext, const cell_t *params)
150 Handle_t hndl = (Handle_t)params[1];
152 IPluginIterator *pIter;
155 sec.pIdentity = g_pCoreIdent;
156 sec.pOwner = pContext->GetIdentity();
158 if ((err=g_HandleSys.ReadHandle(hndl, g_PlIter, &sec, (void **)&pIter)) != HandleError_None)
160 return pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
163 CPlugin *pPlugin = (CPlugin *)pIter->GetPlugin();
171 return pPlugin->GetMyHandle();
174 CPlugin *GetPluginFromHandle(IPluginContext *pContext, Handle_t hndl)
176 if (hndl == BAD_HANDLE)
178 return g_PluginSys.GetPluginByCtx(pContext->GetContext());
181 CPlugin *pPlugin = (CPlugin *)g_PluginSys.PluginFromHandle(hndl, &err);
184 pContext->ThrowNativeError("Could not read Handle %x (error %d)", hndl, err);
190 static cell_t GetPluginStatus(IPluginContext *pContext, const cell_t *params)
192 CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
198 return pPlugin->GetStatus();
201 static cell_t GetPluginFilename(IPluginContext *pContext, const cell_t *params)
203 CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
209 pContext->StringToLocalUTF8(params[2], params[3], pPlugin->GetFilename(), NULL);
214 static cell_t IsPluginDebugging(IPluginContext *pContext, const cell_t *params)
216 CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
222 return pPlugin->IsDebugging() ? 1 : 0;
225 /* Local to plugins only */
228 PlInfo_Name, /**< Plugin name */
229 PlInfo_Author, /**< Plugin author */
230 PlInfo_Description, /**< Plugin description */
231 PlInfo_Version, /**< Plugin verison */
232 PlInfo_URL, /**< Plugin URL */
235 static cell_t GetPluginInfo(IPluginContext *pContext, const cell_t *params)
237 CPlugin *pPlugin = GetPluginFromHandle(pContext, params[1]);
243 const sm_plugininfo_t *info = pPlugin->GetPublicInfo();
250 const char *str = NULL;
252 switch ((PluginInfo)params[2])
264 case PlInfo_Description:
266 str = info->description;
281 if (!str || str[0] == '\0')
286 pContext->StringToLocalUTF8(params[3], params[4], str, NULL);
291 static cell_t SetFailState(IPluginContext *pContext, const cell_t *params)
294 pContext->LocalToString(params[1], &str);
296 CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
297 pPlugin->SetErrorState(Plugin_Error, "%s", str);
299 return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", str);
302 static cell_t GetSysTickCount(IPluginContext *pContext, const cell_t *params)
304 #if defined PLATFORM_WINDOWS
305 return (cell_t)GetTickCount();
306 #elif defined PLATFORM_LINUX
308 clock_t ticks = times(&tm);
309 long ticks_per_sec = sysconf(_SC_CLK_TCK);
310 double fticks = (double)ticks / (double)ticks_per_sec;
312 if (fticks > INT_MAX)
314 double r = (int)(fticks / INT_MAX) * (double)INT_MAX;
317 return (cell_t)fticks;
321 static cell_t AutoExecConfig(IPluginContext *pContext, const cell_t *params)
323 CPlugin *plugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
326 pContext->LocalToString(params[2], &cfg);
327 pContext->LocalToString(params[3], &folder);
331 static char temp_str[255];
332 static char temp_file[PLATFORM_MAX_PATH];
335 g_LibSys.GetFileFromPath(temp_str, sizeof(temp_str), plugin->GetFilename());
336 if ((ptr = strstr(temp_str, ".smx")) != NULL)
341 /* We have the raw filename! */
342 UTIL_Format(temp_file, sizeof(temp_file), "plugin.%s", temp_str);
346 plugin->AddConfig(params[1] ? true : false, cfg, folder);
351 static cell_t MarkNativeAsOptional(IPluginContext *pContext, const cell_t *params)
355 sp_context_t *ctx = pContext->GetContext();
357 pContext->LocalToString(params[1], &name);
358 if (pContext->FindNativeByName(name, &idx) != SP_ERROR_NONE)
360 /* Oops! This HAS to silently fail! */
364 ctx->natives[idx].flags |= SP_NTVFLAG_OPTIONAL;
369 static cell_t RegPluginLibrary(IPluginContext *pContext, const cell_t *params)
372 CPlugin *pl = g_PluginSys.GetPluginByCtx(pContext->GetContext());
374 pContext->LocalToString(params[1], &name);
376 pl->AddLibrary(name);
381 static cell_t LibraryExists(IPluginContext *pContext, const cell_t *params)
384 pContext->LocalToString(params[1], &str);
386 return g_PluginSys.LibraryExists(str) ? 1 : 0;
389 REGISTER_NATIVES(coreNatives)
391 {"AutoExecConfig", AutoExecConfig},
392 {"GetPluginFilename", GetPluginFilename},
393 {"GetPluginInfo", GetPluginInfo},
394 {"GetPluginIterator", GetPluginIterator},
395 {"GetPluginStatus", GetPluginStatus},
396 {"GetSysTickCount", GetSysTickCount},
397 {"GetTime", GetTime},
398 {"IsPluginDebugging", IsPluginDebugging},
399 {"MorePlugins", MorePlugins},
400 {"ReadPlugin", ReadPlugin},
401 {"ThrowError", ThrowError},
402 {"SetFailState", SetFailState},
403 {"FormatTime", FormatTime},
404 {"MarkNativeAsOptional", MarkNativeAsOptional},
405 {"RegPluginLibrary", RegPluginLibrary},
406 {"LibraryExists", LibraryExists},