reorganized SourceMod for the public SDK

--HG--
extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%40329
This commit is contained in:
David Anderson
2007-01-19 05:33:04 +00:00
parent f3eedff775
commit 8a46219d96
30 changed files with 1132 additions and 3 deletions
+217
View File
@@ -0,0 +1,217 @@
#ifndef _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_
#include <IShareSys.h>
#include <ILibrarySys.h>
namespace SourceMod
{
class IExtensionInterface;
typedef void * ITERATOR;
/**
* @brief Encapsulates an IExtension.
*/
class IExtension
{
public:
/**
* @brief Returns whether or not the extension is properly loaded.
*/
virtual bool IsLoaded() =0;
/**
* @brief Returns the extension's API interface
*
* @return An IExtensionInterface pointer.
*/
virtual IExtensionInterface *GetAPI() =0;
/**
* @brief Returns the filename of the extension, relative to the
* extension folder.
*
* @return A string containing the extension file name.
*/
virtual const char *GetFilename() =0;
/**
* @brief Returns the extension's identity token.
*
* @return An IdentityToken_t pointer.
*/
virtual IdentityToken_t *GetIdentity() =0;
/**
* @brief Retrieves the extension dependency list for this extension.
*
* @param pOwner Optional pointer to store the first interface's owner.
* @param pInterface Optional pointer to store the first interface.
* @return An ITERATOR pointer for the results, or NULL if no results at all.
*/
virtual ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface) =0;
/**
* @brief Finds the next dependency in the dependency list.
*
* @param iter Pointer to iterator from FindFirstDependency.
* @param pOwner Optional pointer to store the interface's owner.
* @param pInterface Optional pointer to store the interface.
* @return True if there are more results after this, false otherwise.
*/
virtual bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface) =0;
/**
* @brief Frees an ITERATOR handle from FindFirstDependency.
*
* @param iter Pointer to iterator to free.
*/
virtual void FreeDependencyIterator(ITERATOR *iter) =0;
/**
* @brief Queries the extension to see its run state.
*
* @param error Error buffer (may be NULL).
* @param maxlength Maximum length of buffer.
* @return True if extension is okay, false if not okay.
*/
virtual bool IsRunning(char *error, size_t maxlength) =0;
};
#define SMINTERFACE_EXTENSIONAPI_VERSION 1
/**
* @brief The interface an extension must expose.
*/
class IExtensionInterface
{
public:
virtual unsigned int GetExtensionVersion()
{
return SMINTERFACE_EXTENSIONAPI_VERSION;
}
public:
/**
* @brief Called when the extension is loaded.
*
* @param me Pointer back to extension.
* @param sys Pointer to interface sharing system of SourceMod.
* @param error Error buffer to print back to, if any.
* @param err_max Maximum size of error buffer.
* @param late If this extension was loaded "late" (i.e. manually).
* @return True if load should continue, false otherwise.
*/
virtual bool OnExtensionLoad(IExtension *me,
IShareSys *sys,
char *error,
size_t err_max,
bool late) =0;
/**
* @brief Called when the extension is about to be unloaded.
*/
virtual void OnExtensionUnload() =0;
/**
* @brief Called when all extensions are loaded (loading cycle is done).
* If loaded late, this will be called right after OnExtensionLoad().
*/
virtual void OnExtensionsAllLoaded() =0;
/**
* @brief Called when your pause state is about to change.
*
* @param pause True if pausing, false if unpausing.
*/
virtual void OnExtensionPauseChange(bool pause) =0;
/**
* @brief Asks the extension whether it's safe to remove an external interface it's using.
* If it's not safe, return false, and the extension will be unloaded afterwards.
* NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean up resources.
*
* @param pInterface Pointer to interface being dropped.
* @return True to continue, false to unload this extension afterwards.
*/
virtual bool QueryInterfaceDrop(SMInterface *pInterface)
{
return true;
}
/**
* @brief Notifies the extension that an external interface it uses is being removed.
*
* @param pInterface Pointer to interface being dropped.
*/
virtual void NotifyInterfaceDrop(SMInterface *pInterface)
{
}
/**
* @brief Return false to tell Core that your extension should be considered unsable.
*
* @param error Error buffer.
* @param maxlength Size of error buffer.
* @return True on success, false otherwise.
*/
virtual bool QueryRunning(char *error, size_t maxlength)
{
return true;
}
public:
virtual bool IsMetamodExtension() =0;
virtual const char *GetExtensionName() =0;
virtual const char *GetExtensionURL() =0;
virtual const char *GetExtensionTag() =0;
virtual const char *GetExtensionAuthor() =0;
virtual const char *GetExtensionVerString() =0;
virtual const char *GetExtensionDescription() =0;
virtual const char *GetExtensionDateString() =0;
};
#define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager"
#define SMINTERFACE_EXTENSIONMANAGER_VERSION 1
enum ExtensionLifetime
{
ExtLifetime_Forever, //Extension will never be unloaded automatically
ExtLifetime_Map, //Extension will be unloaded at the end of the map
};
class IExtensionManager : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_EXTENSIONMANAGER_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_EXTENSIONMANAGER_VERSION;
}
public:
/**
* @brief Loads a extension into the extension system.
*
* @param path Path to extension file, relative to the extensions folder.
* @param lifetime Lifetime of the extension.
* @param error Error buffer.
* @param err_max Maximum error buffer length.
* @return New IExtension on success, NULL on failure.
*/
virtual IExtension *LoadExtension(const char *path,
ExtensionLifetime lifetime,
char *error,
size_t err_max) =0;
/**
* @brief Attempts to unload a module.
*
* @param pExt IExtension pointer.
* @return True if successful, false otherwise.
*/
virtual bool UnloadExtension(IExtension *pExt) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_MODULE_INTERFACE_H_
+350
View File
@@ -0,0 +1,350 @@
#ifndef _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_
#define _INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_
#include <IForwardSys.h>
#include <IPluginSys.h>
#include <IPluginFunction.h>
#define SMINTERFACE_FORWARDMANAGER_NAME "IForwardManager"
#define SMINTERFACE_FORWARDMANAGER_VERSION 1
/**
* There is some very important documentation at the bottom of this file.
* Readers interested in knowing more about the forward system, scrolling down is a must!
*/
namespace SourceMod
{
enum ResultType
{
Pl_Continue = 0, /* No result */
Pl_Handled = 1, /* Result was handled, stop at the end */
Pl_Stop = 2, /* Result was handled, stop now */
};
enum ExecType
{
ET_Ignore = 0, /* Ignore all return values, return 0 */
ET_Single = 1, /* Only return the last exec, ignore all others */
ET_Event = 2, /* Acts as an event with the ResultTypes above, no mid-Stops allowed, returns highest */
ET_Hook = 3, /* Acts as a hook with the ResultTypes above, mid-Stops allowed, returns highest */
ET_Custom = 4, /* Ignored or handled by an IForwardFilter */
};
class IForward;
class IForwardFilter
{
public:
/**
* @brief Called when an error occurs executing a plugin.
*
* @param fwd IForward pointer.
* @param func IPluginFunction pointer to the failed function.
* @param err Error code.
* @return True to handle, false to pass to global error reporter.
*/
virtual bool OnErrorReport(IForward *fwd,
IPluginFunction *func,
int err)
{
return false;
}
/**
* @brief Called after each function return during execution.
* NOTE: Only used for ET_Custom.
*
* @param fwd IForward pointer.
* @param func IPluginFunction pointer to the executed function.
* @param retval Pointer to current return value (can be modified).
* @return ResultType denoting the next action to take.
*/
virtual ResultType OnFunctionReturn(IForward *fwd,
IPluginFunction *func,
cell_t *retval)
{
return Pl_Continue;
}
/**
* @brief Called when execution begins.
*/
virtual void OnExecuteBegin()
{
};
/**
* @brief Called when execution ends.
*
* @param final_ret Final return value (modifiable).
* @param success Number of successful execs.
* @param failed Number of failed execs.
*/
virtual void OnExecuteEnd(cell_t *final_ret, unsigned int success, unsigned int failed)
{
}
};
/**
* @brief Abstracts multiple function calling.
*
* NOTE: Parameters should be pushed in forward order, unlike
* the virtual machine/IPluginContext order.
* NOTE: Some functions are repeated in here because their
* documentation differs from their IPluginFunction equivalents.
* Missing are the Push functions, whose only doc change is that
* they throw SP_ERROR_PARAM on type mismatches.
*/
class IForward : public ICallable
{
public:
virtual ~IForward()
{
}
public:
/**
* @brief Returns the name of the forward.
*
* @return Forward name.
*/
virtual const char *GetForwardName() =0;
/**
* @brief Returns the number of functions in this forward.
*
* @return Number of functions in forward.
*/
virtual unsigned int GetFunctionCount() =0;
/**
* @brief Returns the method of multi-calling this forward has.
*
* @return ExecType of the forward.
*/
virtual ExecType GetExecType() =0;
/**
* @brief Executes the forward.
*
* @param result Pointer to store result in.
* @param filter Optional pointer to an IForwardFilter.
* @return Error code, if any.
*/
virtual int Execute(cell_t *result, IForwardFilter *filter=NULL) =0;
/**
* @brief Pushes an array of cells onto the current call. Different rules than ICallable.
* NOTE: On Execute, the pointer passed will be modified according to the copyback rule.
*
* @param inarray Array to copy. Cannot be NULL, unlike ICallable's version.
* @param cells Number of cells to allocate and optionally read from the input array.
* @param phys_addr Unused. If a value is passed, it will be filled with NULL.
* @param flags Whether or not changes should be copied back to the input array.
* @return Error code, if any.
*/
virtual int PushArray(cell_t *inarray,
unsigned int cells,
cell_t **phys_addr,
int flags=0) =0;
};
class IChangeableForward : public IForward
{
public:
/**
* @brief Removes a function from the call list.
* NOTE: Only removes one instance.
*
* @param func Function to remove.
* @return Whether or not the function was removed.
*/
virtual bool RemoveFunction(IPluginFunction *func) =0;
/**
* @brief Removes all instances of a plugin from the call list.
*
* @param plugin Plugin to remove instances of.
* @return Number of functions removed therein.
*/
virtual unsigned int RemoveFunctionsOfPlugin(IPlugin *plugin) =0;
/**
* @brief Adds a function to the call list.
* NOTE: Cannot be used during an incompleted call.
* NOTE: If used during a call, function is temporarily queued until calls are over.
* NOTE: Adding mulitple copies of the same function is illegal.
*
* @param func Function to add.
* @return True on success, otherwise false.
*/
virtual bool AddFunction(IPluginFunction *func) =0;
/**
* @brief Adds a function to the call list.
* NOTE: Cannot be used during an incompleted call.
* NOTE: If used during a call, function is temporarily queued until calls are over.
*
* @param ctx Context to use as a look-up.
* @param funcid Function id to add.
* @return True on success, otherwise false.
*/
virtual bool AddFunction(sp_context_t *ctx, funcid_t index) =0;
};
#define SP_PARAMTYPE_ANY 0
#define SP_PARAMFLAG_BYREF (1<<0)
#define SP_PARAMTYPE_CELL (1<<1)
#define SP_PARAMTYPE_FLOAT (2<<1)
#define SP_PARAMTYPE_STRING (3<<1)|SP_PARAMFLAG_BYREF
#define SP_PARAMTYPE_ARRAY (4<<1)|SP_PARAMFLAG_BYREF
#define SP_PARAMTYPE_VARARG (5<<1)
enum ParamType
{
Param_Any = SP_PARAMTYPE_ANY,
Param_Cell = SP_PARAMTYPE_CELL,
Param_Float = SP_PARAMTYPE_FLOAT,
Param_String = SP_PARAMTYPE_STRING,
Param_Array = SP_PARAMTYPE_ARRAY,
Param_VarArgs = SP_PARAMTYPE_VARARG,
Param_CellByRef = SP_PARAMTYPE_CELL|SP_PARAMFLAG_BYREF,
Param_FloatByRef = SP_PARAMTYPE_FLOAT|SP_PARAMFLAG_BYREF,
};
class IForwardManager : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_FORWARDMANAGER_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_FORWARDMANAGER_VERSION;
}
public:
/**
* @brief Creates a managed forward. This forward exists globally.
* The name used to create the forward is used as its public function in all target plugins.
* As new non-private plugins become loaded or unloaded, they will be automatically added
* or removed. This is ideal for global, static forwards that are never changed.
*
* @param name Name of public function to use in forward.
* @param et Execution type to be used.
* @param num_params Number of parameter this function will have.
* NOTE: For varargs, this should include the vararg parameter.
* @param types Array of type information about each parameter. If NULL, types
* are read off the vararg stream.
* @param ... If types is NULL, num_params ParamTypes should be pushed.
* @return A new IForward on success, NULL if type combination is impossible.
*/
virtual IForward *CreateForward(const char *name,
ExecType et,
unsigned int num_params,
ParamType *types,
...) =0;
/**
* @brief Creates an unmanaged forward. This forward exists privately.
* Unlike managed forwards, no functions are ever added by the Manager.
* However, functions will be removed automatically if their parent plugin is unloaded.
*
* @param name Name of forward (unused except for lookup, can be NULL for anonymous).
* @param et Execution type to be used.
* @param num_params Number of parameter this function will have.
* NOTE: For varargs, this should include the vararg parameter.
* @param types Array of type information about each parameter. If NULL, types
* are read off the vararg stream.
* @param ... If types is NULL, num_params ParamTypes should be pushed.
* @return A new IChangeableForward on success, NULL if type combination is impossible.
*/
virtual IChangeableForward *CreateForwardEx(const char *name,
ExecType et,
int num_params,
ParamType *types,
...) =0;
/**
* @brief Finds a forward by name. Does not return anonymous forwards (named NULL or "").
*
* @param name Name of forward.
* @param ifchng Optionally store either NULL or an IChangeableForward pointer
* depending on type of forward.
* @return IForward pointer, or NULL if none found matching the name.
*/
virtual IForward *FindForward(const char *name, IChangeableForward **ifchng) =0;
/**
* @brief Frees and destroys a forward object.
*
* @param forward An IForward created by CreateForward() or CreateForwardEx().
*/
virtual void ReleaseForward(IForward *forward) =0;
};
};
/**
* In the AMX Mod X model of forwarding, each forward contained a list of pairs, each pair containing
* a function ID and an AMX structure. The forward structure itself did very little but hold parameter types.
* An execution call worked like this:
* - executeForward() took in a function id and a list of parameters
* - for each contained plugin:
* - the list of parameters was preprocessed and pushed
* - the call was made
* - the list was freed and copybacks were made
* - return
*
* The advantages to this is that the system is very easy to implement, and it's fast. The disadvantage is
* varargs tend to be very unforgiving and inflexible, and thus weird problems arose with casting. You also
* lose flexibility, type checking, and the ability to reasonably use variable arguments lists in the VM.
*
* SourceMod replaces this forward system with a far more advanced, but a bit bulkier one. The idea is that
* each plugin has a table of functions, and each function is an ICallable object. As well as being an ICallable,
* each function is an IPluginFunction. An ICallable simply describes the process of adding parameters to a
* function call. An IPluginFunction describes the process of actually calling a function and performing allocation,
* copybacks, and deallocations.
*
* A very powerful forward system emerges: a Forward is just a collection of IPluginFunctions. Thus, the same
* API can be easily wrapped around a simple list, and it will look transparent to the user.
* Advantages:
* 1) "SP Forwards" from AMX Mod X are simply IPluginFunctions without a collection.
* 2) Forwards are function based, rather than plugin based, and are thus far more flexible at runtime..
* 3) [2] Individual functions can be paused and more than one function from the same plugin can be hooked.
* 4) [2] One hook type that used to map to many SP Forwards can now be centralized as one Forward.
* This helps alleviate messes like Fakemeta.
* 5) Parameter pushing is type-checked and allows for variable arguments.
*
* Note that while #2,3,4 could be added to AMX Mod X, the real binding property is #1, which makes the system
* object oriented, rather than AMX Mod X, which hides the objects behind static functions. It is entirely a design
* issue, rather than a usability one. The interesting part is when it gets to implementation, which has to cache
* parameter pushing until execution. Without this, multiple function calls can be started across one plugin, which
* will result in heap corruption given SourcePawn's implementation.
*
* Observe the new calling process:
* - Each parameter is pushed into a local cache using the ICallable interface.
* - For each function in the collection:
* - Each parameter is decoded and -pushed into the function.
* - The call is made.
* - Return
*
* Astute readers will note the (minor) problems:
* 1) More memory is used. Specifically, rather than N params of memory, you now have N params * M plugins.
* This is because, again, parameters are cached both per-function and per-forward.
* 2) There are slightly more calls going around: one extra call for each parameter, since each push is manual.
*
* HISTORICAL NOTES:
* There used to be a # about copy backs.
* Note that originally, the Forward implementation was a thin wrapper around IForwards. It did not cache pushes,
* and instead immediately fired them to each internal plugin. This was to allow users to know that pointers would
* be immediately resolved. Unfortunately, this became extremely burdensome on the API and exposed many problems,
* the major (and breaking) one was that two separate Function objects cannot be in a calling process on the same
* plugin at once. (:TODO: perhaps prevent that in the IPlugin object?) This is because heap functions lose their order
* and become impossible to re-arrange without some global heap tracking mechanis. It also made iterative copy backs
* for arrays/references overwhelmingly complex, since each plugin had to have its memory back-patched for each copy.
* Therefore, this was scrapped for cached parameters (current implementation), which is the implementation AMX Mod X
* uses. It is both faster and works better.
*/
#endif //_INCLUDE_SOURCEMOD_FORWARDINTERFACE_H_
+252
View File
@@ -0,0 +1,252 @@
#ifndef _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_
#include <IShareSys.h>
#include <sp_vm_types.h>
#define SMINTERFACE_HANDLESYSTEM_NAME "IHandleSys"
#define SMINTERFACE_HANDLESYSTEM_VERSION 1
#define DEFAULT_IDENTITY NULL
namespace SourceMod
{
/**
* Both of these types have invalid values of '0' for error checking.
*/
typedef unsigned int HandleType_t;
typedef unsigned int Handle_t;
class SourcePawn::IPluginContext;
/**
* About type checking:
* Types can be inherited - a Parent type ("Supertype") can have child types.
* When accessing handles, type checking is done. This table shows how this is resolved:
*
* HANDLE CHECK -> RESULT
* ------ ----- ------
* Parent Parent Success
* Parent Child Fail
* Child Parent Success
* Child Child Success
*/
enum HandleError
{
HandleError_None = 0, /* No error */
HandleError_Changed, /* The handle has been freed and reassigned */
HandleError_Type, /* The handle has a different type registered */
HandleError_Freed, /* The handle has been freed */
HandleError_Index, /* generic internal indexing error */
HandleError_Access, /* No access permitted to free this handle */
HandleError_Limit, /* The limited number of handles has been reached */
HandleError_Identity, /* The identity token was not usable */
HandleError_Owner, /* Owners do not match for this operation */
HandleError_Version, /* Unrecognized security structure version */
HandleError_Parameter, /* An invalid parameter was passed */
HandleError_NoInherit, /* This type cannot be inherited */
};
/**
* Access rights specific to a type
*/
enum HTypeAccessRight
{
HTypeAccess_Create = 0, /* Handles of this type can be created (DEFAULT=false) */
HTypeAccess_Inherit, /* Sub-types can inherit this type (DEFAULT=false) */
/* -------------- */
HTypeAccess_TOTAL, /* Total number of type access rights */
};
/**
* Access rights specific to a Handle. These rights are exclusive.
* For example, you do not need "read" access to delete or clone.
*/
enum HandleAccessRight
{
HandleAccess_Read, /* Can be read (DEFAULT=ident only) */
HandleAccess_Delete, /* Can be deleted (DEFAULT=owner only) */
HandleAccess_Clone, /* Can be cloned (DEFAULT=any) */
/* ------------- */
HandleAccess_TOTAL, /* Total number of access rights */
};
#define HANDLE_RESTRICT_IDENTITY (1<<0) /* Access is restricted to the identity */
#define HANDLE_RESTRICT_OWNER (1<<1) /* Access is restricted to the owner */
/**
* This is used to define per-type access rights.
*/
struct TypeAccess
{
TypeAccess()
{
hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION;
}
unsigned int hsVersion;
IdentityToken_t *ident;
bool access[HTypeAccess_TOTAL];
};
/**
* This is used to define per-Handle access rights.
*/
struct HandleAccess
{
HandleAccess()
{
hsVersion = SMINTERFACE_HANDLESYSTEM_VERSION;
}
unsigned int hsVersion;
unsigned int access[HandleAccess_TOTAL];
};
/**
* This pair of tokens is used for identification.
*/
struct HandleSecurity
{
IdentityToken_t *pOwner; /* Owner of the Handle */
IdentityToken_t *pIdentity; /* Owner of the Type */
};
class IHandleTypeDispatch
{
public:
virtual unsigned int GetDispatchVersion()
{
return SMINTERFACE_HANDLESYSTEM_VERSION;
}
public:
/**
* @brief Called when destroying a handle. Must be implemented.
*/
virtual void OnHandleDestroy(HandleType_t type, void *object) =0;
};
class IHandleSys : public SMInterface
{
public:
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_HANDLESYSTEM_VERSION;
}
virtual const char *GetInterfaceName()
{
return SMINTERFACE_HANDLESYSTEM_NAME;
}
public:
/**
* @brief Creates a new Handle type.
* NOTE: Currently, a child type may not have its own children.
* NOTE: Handle names must be unique if not private.
*
* @param name Name of handle type (NULL or "" to be anonymous)
* @param dispatch Pointer to a valid IHandleTypeDispatch object.
* @param parent Parent handle to inherit from, 0 for none.
* @param typeAccess Pointer to a TypeAccess object, NULL to use default
* or inherited permissions. Pointer can be temporary.
* @param hndlAccess Pointer to a HandleAccess object to define default
* default permissions on each Handle. NULL to use default
* permissions.
* @param ident Security token for any permissions. If typeAccess is NULL, this
* becomes the owning identity.
* @param err Optional pointer to store an error code.
* @return A new HandleType_t unique ID, or 0 on failure.
*/
virtual HandleType_t CreateType(const char *name,
IHandleTypeDispatch *dispatch,
HandleType_t parent,
const TypeAccess *typeAccess,
const HandleAccess *hndlAccess,
IdentityToken_t *ident,
HandleError *err) =0;
/**
* @brief Removes a handle type.
* NOTE: This removes all child types.
*
* @param type Type chain to remove.
* @param ident Identity token. Removal fails if the token does not match.
* @return True on success, false on failure.
*/
virtual bool RemoveType(HandleType_t type, IdentityToken_t *ident) =0;
/**
* @brief Finds a handle type by name.
*
* @param name Name of handle type to find (anonymous not allowed).
* @param type Address to store found handle in (if not found, undefined).
* @return True if found, false otherwise.
*/
virtual bool FindHandleType(const char *name, HandleType_t *type) =0;
/**
* @brief Creates a new handle.
*
* @param type Type to use on the handle.
* @param object Object to bind to the handle.
* @param owner Owner of the new Handle (may be NULL).
* @param ident Identity for type access if needed (may be NULL).
* @param err Optional pointer to store an error code.
* @return A new Handle_t, or 0 on failure.
*/
virtual Handle_t CreateHandle(HandleType_t type,
void *object,
IdentityToken_t *owner,
IdentityToken_t *ident,
HandleError *err) =0;
/**
* @brief Frees the memory associated with a handle and calls any destructors.
* NOTE: This function will decrement the internal reference counter. It will
* only perform any further action if the counter hits 0.
*
* @param type Handle_t identifier to destroy.
* @param pSecurity Security information struct (may be NULL).
* @return A HandleError error code.
*/
virtual HandleError FreeHandle(Handle_t handle, const HandleSecurity *pSecurity) =0;
/**
* @brief Clones a handle by adding to its internal reference count. Its data,
* type, and security permissions remain the same.
*
* @param handle Handle to duplicate. Any non-free handle target is valid.
* @param newhandle Stores the duplicated handle in the pointer (must not be NULL).
* @param newOwner New owner of cloned handle.
* @param pSecurity Security information struct (may be NULL).
* @return A HandleError error code.
*/
virtual HandleError CloneHandle(Handle_t handle,
Handle_t *newhandle,
IdentityToken_t *newOwner,
const HandleSecurity *pSecurity) =0;
/**
* @brief Retrieves the contents of a handle.
*
* @param handle Handle_t from which to retrieve contents.
* @param type Expected type to read as. 0 ignores typing rules.
* @param pSecurity Security information struct (may be NULL).
* @param object Optional address to store object in.
* @return HandleError error code.
*/
virtual HandleError ReadHandle(Handle_t handle,
HandleType_t type,
const HandleSecurity *pSecurity,
void **object) =0;
/**
* @brief Sets access permissions on one or more structures.
*
* @param pTypeAccess Optional TypeAccess buffer to initialize with the default values.
* @param pHandleAccess Optional HandleAccess buffer to initialize with the default values.
* @return True on success, false if version is unsupported.
*/
virtual bool InitAccessDefaults(TypeAccess *pTypeAccess, HandleAccess *pHandleAccess) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_HANDLESYSTEM_INTERFACE_H_
+155
View File
@@ -0,0 +1,155 @@
#ifndef _INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_
#define _INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_
#include <IShareSys.h>
namespace SourceMod
{
#define SMINTERFACE_LIBRARYSYS_NAME "ILibrarySys"
#define SMINTERFACE_LIBRARYSYS_VERSION 1
class ILibrary
{
public:
virtual ~ILibrary()
{
/* Calling delete will call CloseLibrary! */
};
public:
/**
* @brief Closes dynamic library and invalidates pointer.
*/
virtual void CloseLibrary() =0;
/**
* @brief Retrieves a symbol pointer from the dynamic library.
*
* @param symname Symbol name.
* @return Symbol pointer, NULL if not found.
*/
virtual void *GetSymbolAddress(const char *symname) =0;
};
/**
* @brief Directory browsing abstraction.
*/
class IDirectory
{
public:
virtual ~IDirectory()
{
}
public:
/**
* @brief Returns true if there are more files to read, false otherwise.
*/
virtual bool MoreFiles() =0;
/**
* @brief Advances to the next entry in the stream.
*/
virtual void NextEntry() =0;
/**
* @brief Returns the name of the current entry.
*/
virtual const char *GetEntryName() =0;
/**
* @brief Returns whether the current entry is a directory.
*/
virtual bool IsEntryDirectory() =0;
/**
* @brief Returns whether the current entry is a file.
*/
virtual bool IsEntryFile() =0;
/**
* @brief Returns true if the current entry is valid
* (Used similarly to MoreFiles).
*/
virtual bool IsEntryValid() =0;
};
/**
* @brief Contains various operating system specific code.
*/
class ILibrarySys : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_LIBRARYSYS_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_LIBRARYSYS_VERSION;
}
public:
/**
* @brief Opens a dynamic library file.
*
* @param path Path to library file (.dll/.so).
* @param error Buffer for any error message (may be NULL).
* @param err_max Maximum length of error buffer.
* @return Pointer to an ILibrary, NULL if failed.
*/
virtual ILibrary *OpenLibrary(const char *path, char *error, size_t err_max) =0;
/**
* @brief Opens a directory for reading.
*
* @param path Path to directory.
* @return Pointer to an IDirectory, NULL if failed.
*/
virtual IDirectory *OpenDirectory(const char *path) =0;
/**
* @brief Closes a directory and frees its handle.
*
* @param dir Pointer to IDirectory.
*/
virtual void CloseDirectory(IDirectory *dir) =0;
/**
* @brief Returns true if a path exists.
*/
virtual bool PathExists(const char *path) =0;
/**
* @brief Returns true if the path is a normal file.
*/
virtual bool IsPathFile(const char *path) =0;
/**
* @brief Returns true if the path is a normal directory.
*/
virtual bool IsPathDirectory(const char *path) =0;
/**
* @brief Gets a platform-specific error message.
* This should only be called when an ILibrary function fails.
* Win32 equivalent: GetLastError() + FormatMessage()
* POSIX equivalent: errno + strerror()
*
* @param error Error message buffer.
* @param err_max Maximum length of error buffer.
*/
virtual void GetPlatformError(char *error, size_t err_max) =0;
/**
* @brief Formats a string similar to snprintf(), except
* corrects all non-platform compatible path separators to be
* the correct platform character.
*
* @param buffer Output buffer pointer.
* @param maxlength Output buffer size.
* @param pathfmt Format string of path.
* @param ... Format string arguments.
*/
virtual size_t PathFormat(char *buffer, size_t maxlength, const char *pathfmt, ...) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_LIBRARY_INTERFACE_SYS_H_
+153
View File
@@ -0,0 +1,153 @@
#ifndef _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_
#include <IPluginSys.h>
namespace SourceMod
{
#define SM_PARAM_COPYBACK (1<<0) /* Copy an array/reference back after call */
#define SM_PARAM_STRING_UTF8 (1<<0) /* String should be UTF-8 handled */
#define SM_PARAM_STRING_COPY (1<<1) /* String should be copied into the plugin */
/**
* @brief Represents what a function needs to implement in order to be callable.
*/
class ICallable
{
public:
/**
* @brief Pushes a cell onto the current call.
*
* @param cell Parameter value to push.
* @return Error code, if any.
*/
virtual int PushCell(cell_t cell) =0;
/**
* @brief Pushes a cell by reference onto the current call.
* NOTE: On Execute, the pointer passed will be modified if copyback is enabled.
* NOTE: By reference parameters are cached and thus are not read until execution.
* This means you cannot push a pointer, change it, and push it again and expect
* two different values to come out.
*
* @param cell Address containing parameter value to push.
* @param flags Copy-back flags.
* @return Error code, if any.
*/
virtual int PushCellByRef(cell_t *cell, int flags) =0;
/**
* @brief Pushes a float onto the current call.
*
* @param float Parameter value to push.
* @return Error code, if any.
*/
virtual int PushFloat(float number) =0;
/**
* @brief Pushes a float onto the current call by reference.
* NOTE: On Execute, the pointer passed will be modified if copyback is enabled.
* NOTE: By reference parameters are cached and thus are not read until execution.
* This means you cannot push a pointer, change it, and push it again and expect
* two different values to come out.
*
* @param float Parameter value to push.
& @param flags Copy-back flags.
* @return Error code, if any.
*/
virtual int PushFloatByRef(float *number, int flags) =0;
/**
* @brief Pushes an array of cells onto the current call.
* NOTE: On Execute, the pointer passed will be modified if non-NULL and copy-back
* is enabled.
* NOTE: By reference parameters are cached and thus are not read until execution.
* This means you cannot push a pointer, change it, and push it again and expect
* two different values to come out.
*
* @param inarray Array to copy, NULL if no initial array should be copied.
* @param cells Number of cells to allocate and optionally read from the input array.
* @param phys_addr Optional return address for physical array, if one was made.
* @param flags Whether or not changes should be copied back to the input array.
* @return Error code, if any.
*/
virtual int PushArray(cell_t *inarray,
unsigned int cells,
cell_t **phys_addr,
int flags=0) =0;
/**
* @brief Pushes a string onto the current call.
*
* @param string String to push.
* @return Error code, if any.
*/
virtual int PushString(const char *string) =0;
/**
* @brief Pushes a string or string buffer.
* NOTE: On Execute, the pointer passed will be modified if copy-back is enabled.
*
* @param buffer Pointer to string buffer.
* @param length Length of buffer.
* @param sz_flags String flags.
* @param cp_flags Copy-back flags.
* @return Error code, if any.
*/
virtual int PushStringEx(char *buffer, size_t length, int sz_flags, int cp_flags) =0;
/**
* @brief Cancels a function call that is being pushed but not yet executed.
* This can be used be reset for CallFunction() use.
*/
virtual void Cancel() =0;
};
/**
* @brief Encapsulates a function call in a plugin.
* NOTE: Function calls must be atomic to one execution context.
* NOTE: This object should not be deleted. It lives for the lifetime of the plugin.
*/
class IPluginFunction : public ICallable
{
public:
/**
* @brief Executes the forward, resets the pushed parameter list, and performs any copybacks.
*
* @param result Pointer to store return value in.
* @return Error code, if any.
*/
virtual int Execute(cell_t *result) =0;
/**
* @brief Executes the function with the given parameter array.
* Parameters are read in forward order (i.e. index 0 is parameter #1)
* NOTE: You will get an error if you attempt to use CallFunction() with
* previously pushed parameters.
*
* @param param Array of cell parameters.
* @param num_params Number of parameters to push.
* @param result Pointer to store result of function on return.
* @return SourcePawn error code (if any).
*/
virtual int CallFunction(const cell_t *params, unsigned int num_params, cell_t *result) =0;
/**
* @brief Returns which plugin this function belongs to.
*
* @return IPlugin pointer to parent plugin.
*/
virtual IPlugin *GetParentPlugin() =0;
/**
* @brief Returns the physical address of a by-reference parameter.
*
* @param Parameter index to read (beginning at 0).
* @return Address, or NULL if invalid parameter specified.
*/
virtual cell_t *GetAddressOfPushedParam(unsigned int param) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_PLUGINFUNCTION_INTERFACE_H_
+302
View File
@@ -0,0 +1,302 @@
#ifndef _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_
#include <IShareSys.h>
#include <sp_vm_api.h>
#define SMINTERFACE_PLUGINSYSTEM_NAME "IPluginManager"
#define SMINTERFACE_PLUGINSYSTEM_VERSION 1
#define SM_CONTEXTVAR_USER 3
namespace SourceMod
{
class IPlugin;
/**
* @brief Encapsulates plugin public information.
*/
typedef struct sm_plugininfo_s
{
const char *name;
const char *author;
const char *description;
const char *version;
const char *url;
} sm_plugininfo_t;
/**
* @brief Describes the usability status of a plugin.
* Note: The status "Loaded" and "Created" are only reachable
* during map load.
*/
enum PluginStatus
{
Plugin_Running=0, /* Plugin is running */
/* All states below are unexecutable */
Plugin_Paused, /* Plugin is loaded but paused */
Plugin_Error, /* Plugin is loaded but errored/locked */
/* All states below do not have all natives */
Plugin_Loaded, /* Plugin has passed loading and can be finalized */
Plugin_Failed, /* Plugin has a fatal failure */
Plugin_Created, /* Plugin is created but not initialized */
Plugin_Uncompiled, /* Plugin is not yet compiled by the JIT */
Plugin_BadLoad, /* Plugin failed to load */
};
/**
* @brief Describes the object lifetime of a plugin.
*/
enum PluginType
{
PluginType_Private, /* Plugin is privately managed and receives no forwards */
PluginType_MapUpdated, /* Plugin will never be unloaded unless for updates on mapchange */
PluginType_MapOnly, /* Plugin will be removed at mapchange */
PluginType_Global, /* Plugin will never be unloaded or updated */
};
class IPluginFunction;
/**
* @brief Encapsulates a run-time plugin as maintained by SourceMod.
*/
class IPlugin
{
public:
virtual ~IPlugin()
{
}
/**
* @brief Returns the lifetime of a plugin.
*/
virtual PluginType GetType() const =0;
/**
* @brief Returns the current API context being used in the plugin.
*
* @return Pointer to an IPluginContext, or NULL if not loaded.
*/
virtual SourcePawn::IPluginContext *GetBaseContext() const =0;
/**
* @brief Returns the context structure being used in the plugin.
*
* @return Pointer to an sp_context_t, or NULL if not loaded.
*/
virtual sp_context_t *GetContext() const =0;
/**
* @brief Returns the plugin file structure.
*
* @return Pointer to an sp_plugin_t, or NULL if not loaded.
*/
virtual const sp_plugin_t *GetPluginStructure() const =0;
/**
* @brief Returns information about the plugin by reference.
*
* @return Pointer to a sm_plugininfo_t object, NULL if plugin is not loaded.
*/
virtual const sm_plugininfo_t *GetPublicInfo() const =0;
/**
* @brief Returns the plugin filename (relative to plugins dir).
*/
virtual const char *GetFilename() const =0;
/**
* @brief Returns true if a plugin is in debug mode, false otherwise.
*/
virtual bool IsDebugging() const =0;
/**
* @brief Returns the plugin status.
*/
virtual PluginStatus GetStatus() const =0;
/**
* @brief Sets whether the plugin is paused or not.
*
* @return True on successful state change, false otherwise.
*/
virtual bool SetPauseState(bool paused) =0;
/**
* @brief Returns the unique serial number of a plugin.
*/
virtual unsigned int GetSerial() const =0;
/**
* @brief Returns a function by name.
*
* @param public_name Name of the function.
* @return A new IPluginFunction pointer, NULL if not found.
*/
virtual IPluginFunction *GetFunctionByName(const char *public_name) =0;
/**
* @brief Returns a function by its id.
*
* @param func_id Function ID.
* @return A new IPluginFunction pointer, NULL if not found.
*/
virtual IPluginFunction *GetFunctionById(funcid_t func_id) =0;
/**
* @brief Returns a plugin's identity token.
*/
virtual IdentityToken_t *GetIdentity() const =0;
};
/**
* @brief Iterates over a list of plugins.
*/
class IPluginIterator
{
public:
virtual ~IPluginIterator()
{
};
public:
/**
* @brief Returns true if there are more plugins in the iterator.
*/
virtual bool MorePlugins() =0;
/**
* @brief Returns the plugin at the current iterator position.
*/
virtual IPlugin *GetPlugin() =0;
/**
* @brief Advances to the next plugin in the iterator.
*/
virtual void NextPlugin() =0;
/**
* @brief Destroys the iterator object.
* Note: You may use 'delete' in lieu of this function.
*/
virtual void Release() =0;
};
/**
* @brief Listens for plugin-oriented events.
*/
class IPluginsListener
{
public:
/**
* @brief Called when a plugin is created/mapped into memory.
*/
virtual void OnPluginCreated(IPlugin *plugin)
{
}
/**
* @brief Called when a plugin is fully loaded successfully.
*/
virtual void OnPluginLoaded(IPlugin *plugin)
{
}
/**
* @brief Called when a plugin is unloaded (only if fully loaded).
*/
virtual void OnPluginUnloaded(IPlugin *plugin)
{
}
/**
* @brief Called when a plugin is destroyed.
* NOTE: Always called if Created, even if load failed.
*/
virtual void OnPluginDestroyed(IPlugin *plugin)
{
}
};
/**
* @brief Manages the runtime loading and unloading of plugins.
*/
class IPluginManager : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_PLUGINSYSTEM_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_PLUGINSYSTEM_VERSION;
}
public:
/**
* @brief Attempts to load a plugin.
*
* @param path Path and filename of plugin, relative to plugins folder.
* @param debug Whether or not to default the plugin into debug mode.
* @param type Lifetime of the plugin.
* @param error Buffer to hold any error message.
* @param err_max Maximum length of error message buffer.
* @return A new plugin pointer on success, false otherwise.
*/
virtual IPlugin *LoadPlugin(const char *path,
bool debug,
PluginType type,
char error[],
size_t err_max) =0;
/**
* @brief Attempts to unload a plugin.
*
* @param plugin Pointer to the plugin handle.
* @return True on success, false otherwise.
*/
virtual bool UnloadPlugin(IPlugin *plugin) =0;
/**
* @brief Finds a plugin by its context.
* Note: This function should be considered O(1).
*
* @param ctx Pointer to an sp_context_t.
* @return Pointer to a matching IPlugin, or NULL if none found.
*/
virtual IPlugin *FindPluginByContext(const sp_context_t *ctx) =0;
/**
* @brief Returns the number of plugins (both failed and loaded).
*
* @return The number of internally cached plugins.
*/
virtual unsigned int GetPluginCount() =0;
/**
* @brief Returns a pointer that can be used to iterate through plugins.
* Note: This pointer must be freed using EITHER delete OR IPluginIterator::Release().
*/
virtual IPluginIterator *GetPluginIterator() =0;
/**
* @brief Adds a plugin manager listener.
*
* @param listener Pointer to a listener.
*/
virtual void AddPluginsListener(IPluginsListener *listener) =0;
/**
* @brief Removes a plugin listener.
*
* @param listener Pointer to a listener.
*/
virtual void RemovePluginsListener(IPluginsListener *listener) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_PLUGINMNGR_INTERFACE_H_
+90
View File
@@ -0,0 +1,90 @@
#ifndef _INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_
#define _INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_
/**
* @brief Note: This interface is not exposed.
* The reason should be obvious: we do not want users touching the "root" console menu.
* If we exposed this, every little plugin would be dropping down a silly set of user commands,
* whereas this menu is explicitly provided for stuff that only Core itself is capable of managing.
*/
namespace SourceMod
{
/**
* @brief Handles a root console menu action.
*/
class IRootConsoleCommand
{
public:
virtual void OnRootConsoleCommand(const char *command, unsigned int argcount) =0;
};
/**
* @brief Manages the root console menu - the "sm" command for servers.
*/
class IRootConsole
{
public:
/**
* @brief Adds a root console command handler. The command must be unique.
*
* @param cmd String containing the console command.
* @param text Description text.
* @param pHandler An IRootConsoleCommand pointer to handle the command.
* @return True on success, false on too many commands or duplicate command.
*/
virtual bool AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler) =0;
/**
* @brief Removes a root console command handler.
*
* @param cmd String containing the console command.
* @param pHandler An IRootConsoleCommand pointer for verification.
* @return True on success, false otherwise.
*/
virtual bool RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler) =0;
/**
* @brief Prints text back to the console.
*
* @param fmt Format of string.
* @param ... Format arguments.
*/
virtual void ConsolePrint(const char *fmt, ...) =0;
/**
* @brief Returns the string of an argument.
*
* @param argno The index of the argument.
* @return A string containing the argument, or nothing if invalid.
*/
virtual const char *GetArgument(unsigned int argno) =0;
/**
* @brief Returns the number of arguments.
*
* @return Number of arguments.
*/
virtual unsigned int GetArgumentCount() =0;
/**
* @brief Returns the entire argument string.
*
* @return String containing all arguments.
*/
virtual const char *GetArguments() =0;
/**
* @brief Draws a generic command/description pair.
* NOTE: The pair is currently four spaces indented and 16-N spaces of separation,
* N being the length of the command name. This is subject to change in case we
* account for Valve's font choices.
*
* @param option String containing the command option.
* @param description String containing the command description.
*/
virtual void DrawGenericOption(const char *cmd, const char *text) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_ROOT_CONSOLE_MENU_H_
+149
View File
@@ -0,0 +1,149 @@
#ifndef _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
#define _INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
#include <sp_vm_types.h>
#define NO_IDENTITY 0
namespace SourceMod
{
class IExtension;
struct IdentityToken_t;
typedef unsigned int HandleType_t;
typedef HandleType_t IdentityType_t;
/**
* @brief Defines the base functionality required by a shared interface.
*/
class SMInterface
{
public:
/**
* @brief Must return an integer defining the interface's version.
*/
virtual unsigned int GetInterfaceVersion() =0;
/**
* @brief Must return a string defining the interface's unique name.
*/
virtual const char *GetInterfaceName() =0;
/**
* @brief Must return whether the requested version number is backwards comaptible.
* Note: This can be overridden for breaking changes or custom versioning.
*
* @param version Version number to compare against.
* @return True if compatible, false otherwise.
*/
virtual bool IsVersionCompatible(unsigned int version)
{
if (version > GetInterfaceVersion())
{
return false;
}
return true;
}
};
/**
* @brief Tracks dependencies and fires dependency listeners.
*/
class IShareSys
{
public:
/**
* @brief Adds an interface to the global interface system.
*
* @param myself Object adding this interface, in order to track dependencies.
* @param iface Interface pointer (must be unique).
* @return True on success, false otherwise.
*/
virtual bool AddInterface(IExtension *myself, SMInterface *iface) =0;
/**
* @brief Requests an interface from the global interface system.
* If found, the interface's internal reference count will be increased.
*
* @param iface_name Interface name.
* @param iface_vers Interface version to attempt to match.
* @param myself Object requesting this interface, in order to track dependencies.
* @param pIface Pointer to store the return value in.
*/
virtual bool RequestInterface(const char *iface_name,
unsigned int iface_vers,
IExtension *myself,
SMInterface **pIface) =0;
/**
* @brief Adds a list of natives to the global native pool, to be bound on plugin load.
* NOTE: Adding natives currently does not bind them to any loaded plugins.
* You must manually bind late natives.
*
* @param token Identity token of parent object.
* @param natives Array of natives to add. The last entry must have NULL members.
*/
virtual void AddNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;
/**
* @brief Creates a new identity type.
* NOTE: Module authors should never need to use this. Due to the current implementation,
* there is a hardcoded limit of 15 types. Core uses up a few, so think carefully!
*
* @param name String containing type name. Must not be empty or NULL.
* @return A new HandleType_t identifier, or 0 on failure.
*/
virtual IdentityType_t CreateIdentType(const char *name) =0;
/**
* @brief Finds an identity type by name.
* DEFAULT IDENTITY TYPES:
* "PLUGIN" - An IPlugin object.
* "MODULE" - An IModule object.
* "CORE" - An SMGlobalClass or other singleton.
*
* @param name String containing type name to search for.
* @return A HandleType_t identifier if found, 0 otherwise.
*/
virtual IdentityType_t FindIdentType(const char *name) =0;
/**
* @brief Creates a new identity token. This token is guaranteed to be unique
* amongst all other open identities.
*
* @param type Identity type.
* @return A new IdentityToken_t identifier.
*/
virtual IdentityToken_t *CreateIdentity(IdentityType_t type) =0;
/**
* @brief Destroys an identity type. Note that this will delete any identities
* that are under this type.
*
* @param type Identity type.
*/
virtual void DestroyIdentType(IdentityType_t type) =0;
/**
* @brief Destroys an identity token. Any handles being owned by this token, or
* any handles being
*
* @param identity Identity to remove.
*/
virtual void DestroyIdentity(IdentityToken_t *identity) =0;
/**
* @brief Requires an extension. This tells SourceMod that without this extension,
* your extension should not be loaded. The name should not include the ".dll" or
* the ".so" part of the file name.
*
* @param myself IExtension pointer to yourself.
* @param filename File of extension to require.
* @param require Whether or not this extension is a required dependency.
* @param autoload Whether or not to autoload this extension.
*/
virtual void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_IFACE_SHARE_SYS_H_
+74
View File
@@ -0,0 +1,74 @@
#ifndef _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_
#include <IShareSys.h>
#define SMINTERFACE_SOURCEMOD_NAME "ISourceMod"
#define SMINTERFACE_SOURCEMOD_VERSION 1
namespace SourceMod
{
enum PathType
{
Path_None = 0,
Path_Game,
Path_SM,
};
class ISourceMod : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_SOURCEMOD_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_SOURCEMOD_VERSION;
}
public:
/**
* @brief Returns the full path to the mod directory.
*
* @return A string containing the full mod path.
*/
virtual const char *GetModPath() =0;
/**
* @brief Returns the full path to the SourceMod directory.
*
* @return A string containing the full SourceMod path.
*/
virtual const char *GetSourceModPath() =0;
/**
* @brief Builds a platform path for a specific target base path.
*
* @param type Type of path to use as a base.
* @param buffer Buffer to write to.
* @param maxlength Size of buffer.
* @param format Format string.
* @param ... Format arguments.
* @return Number of bytes written.
*/
virtual size_t BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...) =0;
/**
* @brief Logs a message to the SourceMod logs.
*
* @param format Message format.
* @param ... Message format parameters.
*/
virtual void LogMessage(IExtension *pExt, const char *format, ...) =0;
/**
* @brief Logs a message to the SourceMod error logs.
*
* @param format Message format.
* @param ... Message format parameters.
*/
virtual void LogError(IExtension *pExt, const char *format, ...) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_MAIN_HELPER_INTERFACE_H_
+316
View File
@@ -0,0 +1,316 @@
#ifndef _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
#define _INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
#include <IShareSys.h>
namespace SourceMod
{
/**
* The INI file format is defined as:
* WHITESPACE: 0x20, \n, \t, \r
* IDENTIFIER: A-Z a-z 0-9 _ - , + . $ ? /
* STRING: Any set of symbols
*
* Basic syntax is comprised of SECTIONs.
* A SECTION is defined as:
* [SECTIONNAME]
* OPTION
* OPTION
* OPTION...
*
* SECTIONNAME is an IDENTIFIER.
* OPTION can be repeated any number of times, once per line.
* OPTION is defined as one of:
* KEY = "VALUE"
* KEY = VALUE
* KEY
* Where KEY is an IDENTIFIER and VALUE is a STRING.
*
* WHITESPACE should always be omitted.
* COMMENTS should be stripped, and are defined as text occuring in:
* ;<TEXT>
*
* Example file below. Note that
* The second line is technically invalid. The event handler
* must decide whether this should be allowed.
* --FILE BELOW--
* [gaben]
* hi = clams
* bye = "NO CLAMS"
*
* [valve]
* cannot
* maintain
* products
*/
class ITextListener_INI
{
public:
/**
* @brief Called when a new section is encountered in an INI file.
*
* @param section Name of section in between the [ and ] characters.
* @param invalid_tokens True if invalid tokens were detected in the name.
* @param close_bracket True if a closing bracket was detected, false otherwise.
* @param extra_tokens True if extra tokens were detected on the line.
* @param curtok Contains current token in the line where the section name starts.
* You can add to this offset when failing to point to a token.
* @return True to keep parsing, false otherwise.
*/
virtual bool ReadINI_NewSection(const char *section,
bool invalid_tokens,
bool close_bracket,
bool extra_tokens,
unsigned int *curtok)
{
return true;
}
/**
* @brief Called when encountering a key/value pair in an INI file.
*
* @param key Name of key.
* @param value String containing value (with quotes stripped, if any).
* @param invalid_tokens Whether or not the key contained invalid tokens.
* @param equal_token There was an '=' sign present (in case the value is missing).
* @param quotes Whether value was enclosed in quotes.
* @param curtoken Contains the token index of the start of the value string.
* This can be changed when returning false.
* @return True to keep parsing, false otherwise.
*/
virtual bool ReadINI_KeyValue(const char *key,
const char *value,
bool invalid_tokens,
bool equal_token,
bool quotes,
unsigned int *curtok)
{
return true;
}
/**
* @brief Called after a line has been preprocessed, if it has text.
*
* @param line Contents of line.
* @param curtok Pointer to optionally store failed position in string.
* @return True to keep parsing, false otherwise.
*/
virtual bool ReadINI_RawLine(const char *line, unsigned int *cutok)
{
return true;
}
};
/**
* :TODO: write this in CFG (context free grammar) format so it makes sense
*
* The SMC file format is defined as:
* WHITESPACE: 0x20, \n, \t, \r
* IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, /*, or WHITESPACE.
* STRING: Any set of symbols enclosed in quotes.
* Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER.
*
* Basic syntax is comprised of SECTIONBLOCKs.
* A SECTIONBLOCK defined as:
*
* SECTIONNAME
* {
* OPTION
* }
*
* OPTION can be repeated any number of times inside a SECTIONBLOCK.
* A new line will terminate an OPTION, but there can be more than one OPTION per line.
* OPTION is defined any of:
* "KEY" "VALUE"
* SECTIONBLOCK
*
* SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings
* SECTIONNAME cannot have trailing characters if quoted, but the quotes can be optionally removed.
* If SECTIONNAME is not enclosed in quotes, the entire sectionname string is used (minus surrounding whitespace).
* If KEY is not enclosed in quotes, the key is terminated at first whitespace.
* If VALUE is not properly enclosed in quotes, the entire value string is used (minus surrounding whitespace).
* The VALUE may have inner quotes, but the key string may not.
*
* For an example, see configs/permissions.cfg
*
* WHITESPACE should be ignored.
* Comments are text occuring inside the following tokens, and should be stripped
* unless they are inside literal strings:
* ;<TEXT>
* //<TEXT>
* /*<TEXT> */
enum SMCParseResult
{
SMCParse_Continue, //continue parsing
SMCParse_Halt, //stop parsing here
SMCParse_HaltFail //stop parsing and return failure
};
enum SMCParseError
{
SMCParse_Okay = 0, //no error
SMCParse_StreamOpen, //stream failed to open
SMCParse_StreamError, //the stream died... somehow
SMCParse_Custom, //a custom handler threw an error
SMCParse_InvalidSection1, //a section was declared without quotes, and had extra tokens
SMCParse_InvalidSection2, //a section was declared without any header
SMCParse_InvalidSection3, //a section ending was declared with too many unknown tokens
SMCParse_InvalidSection4, //a section ending has no matching beginning
SMCParse_InvalidSection5, //a section beginning has no matching ending
SMCParse_InvalidTokens, //there were too many unidentifiable strings on one line
SMCParse_TokenOverflow, //the token buffer overflowed
SMCParse_InvalidProperty1, //a property was declared outside of any section
};
class ITextListener_SMC
{
public:
/**
* @brief Called when starting parsing.
*/
virtual void ReadSMC_ParseStart()
{
};
/**
* @brief Called when ending parsing.
*
* @param halted True if abnormally halted, false otherwise.
* @param failed True if parsing failed, false otherwise.
*/
virtual void ReadSMC_ParseEnd(bool halted, bool failed)
{
}
/**
* @brief Called when a warning occurs.
* @param error By-reference variable containing the error message of the warning.
* @param tokens Pointer to the token stream causing the error.
* @return SMCParseResult directive.
*/
virtual SMCParseResult ReadSMC_OnWarning(SMCParseError &error, const char *tokens)
{
return SMCParse_HaltFail;
}
/**
* @brief Called when entering a new section
*
* @param name Name of section, with the colon omitted.
* @param opt_quotes Whether or not the option string was enclosed in quotes.
* @return SMCParseResult directive.
*/
virtual SMCParseResult ReadSMC_NewSection(const char *name, bool opt_quotes)
{
return SMCParse_Continue;
}
/**
* @brief Called when encountering a key/value pair in a section.
*
* @param key Key string.
* @param value Value string. If no quotes were specified, this will be NULL,
and key will contain the entire string.
* @param key_quotes Whether or not the key was in quotation marks.
* @param value_quotes Whether or not the value was in quotation marks.
* @return SMCParseResult directive.
*/
virtual SMCParseResult ReadSMC_KeyValue(const char *key,
const char *value,
bool key_quotes,
bool value_quotes)
{
return SMCParse_Continue;
}
/**
* @brief Called when leaving the current section.
*
* @return SMCParseResult directive.
*/
virtual SMCParseResult ReadSMC_LeavingSection()
{
return SMCParse_Continue;
}
/**
* @brief Called after an input line has been preprocessed.
*
* @param line String containing line input.
* @param curline Number of line in file.
* @return SMCParseResult directive.
*/
virtual SMCParseResult ReadSMC_RawLine(const char *line, unsigned int curline)
{
return SMCParse_Continue;
}
};
#define SMINTERFACE_TEXTPARSERS_NAME "ITextParsers"
#define SMINTERFACE_TEXTPARSERS_VERSION 1
class ITextParsers : public SMInterface
{
public:
virtual const char *GetInterfaceName()
{
return SMINTERFACE_TEXTPARSERS_NAME;
}
virtual unsigned int GetInterfaceVersion()
{
return SMINTERFACE_TEXTPARSERS_VERSION;
}
public:
/**
* @brief Parses an INI-format file.
*
* @param file Path to file.
* @param ini_listener Event handler for reading file.
* @param line If non-NULL, will contain last line parsed (0 if file could not be opened).
* @param col If non-NULL, will contain last column parsed (undefined if file could not be opened).
* @return True if parsing succeded, false if file couldn't be opened or there was a syntax error.
*/
virtual bool ParseFile_INI(const char *file,
ITextListener_INI *ini_listener,
unsigned int *line,
unsigned int *col) =0;
/**
* @brief Parses an SMC-format text file.
* Note that the parser makes every effort to obey broken syntax.
* For example, if an open brace is missing, but the section name has a colon,
* it will let you know. It is up to the event handlers to decide whether to be strict or not.
*
* @param file Path to file.
* @param smc_listener Event handler for reading file.
* @param line If non-NULL, will contain last line parsed (0 if file could not be opened).
* @param col If non-NULL, will contain last column parsed (undefined if file could not be opened).
* @return An SMCParseError result code.
*/
virtual SMCParseError ParseFile_SMC(const char *file,
ITextListener_SMC *smc_listener,
unsigned int *line,
unsigned int *col) =0;
/**
* @brief Converts an SMCParseError to a stirng.
*
* @param err SMCParseError.
* @return String error message, or NULL if none.
*/
virtual const char *GetSMCErrorString(SMCParseError err) =0;
public:
/**
* @brief Returns the number of bytes that a multi-byte character contains in a UTF-8 stream.
* If the current character is not multi-byte, the function returns 1.
*
* @param stream Pointer to multi-byte ANSI character string.
* @return Number of bytes in current character.
*/
virtual unsigned int GetUTF8CharBytes(const char *stream) =0;
};
};
#endif //_INCLUDE_SOURCEMOD_TEXTPARSERS_INTERFACE_H_
+5
View File
@@ -0,0 +1,5 @@
#include "extension.h"
Sample g_Sample;
SMEXT_LINK(&g_Sample);
+59
View File
@@ -0,0 +1,59 @@
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
#include "smsdk_ext.h"
/**
* @brief Sample implementation of the SDK Extension.
* Note: Uncomment one of the pre-defined virtual functions in order to use it.
*/
class Sample : public SDKExtension
{
public:
/**
* @brief This is called after the initial loading sequence has been processed.
*
* @param error Error message buffer.
* @param err_max Size of error message buffer.
* @param late Whether or not the module was loaded after map load.
* @return True to succeed loading, false to fail.
*/
//virtual bool SDK_OnLoad(char *error, size_t err_max, bool late);
/**
* @brief This is called right before the extension is unloaded.
*/
//virtual void SDK_OnUnload();
/**
* @brief This is called once all known extensions have been loaded.
* Note: It is is a good idea to add natives here, if any are provided.
*/
//virtual void SDK_OnAllLoaded();
/**
* @brief Called when the pause state is changed.
*/
//virtual void SDK_OnPauseChange(bool paused);
/**
* @brief this is called when Core wants to know if your extension is working.
*
* @param error Error message buffer.
* @param err_max Size of error message buffer.
* @return True if working, false otherwise.
*/
//virtual void QueryRunning(char *error, size_t maxlength);
public:
#if defined SMEXT_CONF_METAMOD
/**
* Read smext_base.h for documentation on these.
*/
//virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late);
//virtual bool SDK_OnMetamodUnload(char *error, size_t err_max);
//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max);
#endif
};
#endif //_INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
+26
View File
@@ -0,0 +1,26 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdk", "sdk.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - Metamod|Win32 = Debug - Metamod|Win32
Debug|Win32 = Debug|Win32
Release - Metamod|Win32 = Release - Metamod|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.ActiveCfg = Debug - Metamod|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Metamod|Win32.Build.0 = Debug - Metamod|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.ActiveCfg = Release - Metamod|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Metamod|Win32.Build.0 = Release - Metamod|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32
{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
+368
View File
@@ -0,0 +1,368 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="sdk"
ProjectGUID="{B3E797CF-4E77-4C9D-B8A8-7589B6902206}"
RootNamespace="sdk"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\sample.ext.dll"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\sample.ext.dll"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Debug - Metamod|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SMEXT_CONF_METAMOD"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="tier0.lib"
OutputFile="$(OutDir)\sample.ext.dll"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release - Metamod|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SMEXT_CONF_METAMOD"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)\sample.ext.dll"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\extension.cpp"
>
</File>
<File
RelativePath=".\smsdk_ext.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\extension.h"
>
</File>
<File
RelativePath=".\smsdk_config.h"
>
</File>
<File
RelativePath=".\smsdk_ext.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
+27
View File
@@ -0,0 +1,27 @@
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
/* Basic information exposed publically */
#define SMEXT_CONF_NAME "Sample Extension"
#define SMEXT_CONF_DESCRIPTION "Sample extension to help developers"
#define SMEXT_CONF_VERSION "0.0.0.0"
#define SMEXT_CONF_AUTHOR "AlliedModders"
#define SMEXT_CONF_URL "http://www.sourcemod.net/"
#define SMEXT_CONF_LOGTAG "SAMPLE"
#define SMEXT_CONF_LICENSE "GPL"
#define SMEXT_CONF_DATESTRING __DATE__
/**
* @brief Exposes plugin's main interface.
*/
#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name;
/**
* @brief Sets whether or not this plugin required Metamod.
* NOTE: Uncomment to enable, comment to disable.
* NOTE: This is enabled automatically if a Metamod build is chosen in
* the Visual Studio project.
*/
//#define SMEXT_CONF_METAMOD
#endif //_INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
+279
View File
@@ -0,0 +1,279 @@
#include <stdio.h>
#include "smsdk_ext.h"
IShareSys *g_pShareSys = NULL;
IExtension *myself = NULL;
IHandleSys *g_pHandleSys = NULL;
ISourceMod *g_pSM = NULL;
PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
{
return g_pExtensionIface;
}
SDKExtension::SDKExtension()
{
#if defined SMEXT_CONF_METAMOD
m_SourceMMLoaded = false;
m_WeAreUnloaded = false;
m_WeGotPauseChange = false;
#endif
}
bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late)
{
g_pShareSys = sys;
myself = me;
#if defined SMEXT_CONF_METAMOD
m_WeAreUnloaded = true;
if (!m_SourceMMLoaded)
{
if (error)
{
snprintf(error, err_max, "Metamod attach failed");
}
return false;
}
#endif
SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
SM_GET_IFACE(SOURCEMOD, g_pSM);
if (SDK_OnLoad(error, err_max, late))
{
#if defined SMEXT_CONF_METAMOD
m_WeAreUnloaded = true;
#endif
return true;
}
return false;
}
bool SDKExtension::IsMetamodExtension()
{
#if defined SMEXT_CONF_METAMOD
return true;
#else
return false;
#endif
}
void SDKExtension::OnExtensionPauseChange(bool state)
{
#if defined SMEXT_CONF_METAMOD
m_WeGotPauseChange = true;
#endif
SDK_OnPauseChange(state);
}
void SDKExtension::OnExtensionsAllLoaded()
{
SDK_OnAllLoaded();
}
void SDKExtension::OnExtensionUnload()
{
#if defined SMEXT_CONF_METAMOD
m_WeAreUnloaded = true;
#endif
SDK_OnUnload();
}
const char *SDKExtension::GetExtensionAuthor()
{
return SMEXT_CONF_AUTHOR;
}
const char *SDKExtension::GetExtensionDateString()
{
return SMEXT_CONF_DATESTRING;
}
const char *SDKExtension::GetExtensionDescription()
{
return SMEXT_CONF_DESCRIPTION;
}
const char *SDKExtension::GetExtensionVerString()
{
return SMEXT_CONF_VERSION;
}
const char *SDKExtension::GetExtensionName()
{
return SMEXT_CONF_NAME;
}
const char *SDKExtension::GetExtensionTag()
{
return SMEXT_CONF_LOGTAG;
}
const char *SDKExtension::GetExtensionURL()
{
return SMEXT_CONF_URL;
}
bool SDKExtension::SDK_OnLoad(char *error, size_t err_max, bool late)
{
return true;
}
void SDKExtension::SDK_OnUnload()
{
}
void SDKExtension::SDK_OnPauseChange(bool paused)
{
}
void SDKExtension::SDK_OnAllLoaded()
{
}
#if defined SMEXT_CONF_METAMOD
PluginId g_PLID = 0;
ISmmPlugin *g_PLAPI = NULL;
SourceHook::ISourceHook *g_SHPtr = NULL;
ISmmAPI *g_SMAPI = NULL;
IVEngineServer *engine = NULL;
IServerGameDLL *gamedll = NULL;
SMM_API void *PL_EXPOSURE(const char *name, int *code)
{
if (name && !strcmp(name, PLAPI_NAME))
{
if (code)
{
*code = IFACE_OK;
}
return static_cast<void *>(g_pExtensionIface);
}
if (code)
{
*code = IFACE_FAILED;
}
return NULL;
}
bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
{
PLUGIN_SAVEVARS();
GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
m_SourceMMLoaded = true;
return SDK_OnMetamodLoad(error, maxlen, late);
}
bool SDKExtension::Unload(char *error, size_t maxlen)
{
if (!m_WeAreUnloaded)
{
if (error)
{
snprintf(error, maxlen, "This extension must be unloaded by SourceMod.");
}
return false;
}
return SDK_OnMetamodUnload(error, maxlen);
}
bool SDKExtension::Pause(char *error, size_t maxlen)
{
if (!m_WeGotPauseChange)
{
if (error)
{
snprintf(error, maxlen, "This extension must be paused by SourceMod.");
}
return false;
}
m_WeGotPauseChange = false;
return SDK_OnMetamodPauseChange(true, error, maxlen);
}
bool SDKExtension::Unpause(char *error, size_t maxlen)
{
if (!m_WeGotPauseChange)
{
if (error)
{
snprintf(error, maxlen, "This extension must be unpaused by SourceMod.");
}
return false;
}
m_WeGotPauseChange = false;
return SDK_OnMetamodPauseChange(false, error, maxlen);
}
const char *SDKExtension::GetAuthor()
{
return GetExtensionAuthor();
}
const char *SDKExtension::GetDate()
{
return GetExtensionDateString();
}
const char *SDKExtension::GetDescription()
{
return GetExtensionDescription();
}
const char *SDKExtension::GetLicense()
{
return SMEXT_CONF_LICENSE;
}
const char *SDKExtension::GetLogTag()
{
return GetExtensionTag();
}
const char *SDKExtension::GetName()
{
return GetExtensionName();
}
const char *SDKExtension::GetURL()
{
return GetExtensionURL();
}
const char *SDKExtension::GetVersion()
{
return GetExtensionVerString();
}
bool SDKExtension::SDK_OnMetamodLoad(char *error, size_t err_max, bool late)
{
return true;
}
bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t err_max)
{
return true;
}
bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max)
{
return true;
}
#endif
+142
View File
@@ -0,0 +1,142 @@
#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
#include "smsdk_config.h"
#include <IExtensionSys.h>
#include <IHandleSys.h>
#include <sp_vm_api.h>
#include <sm_platform.h>
#include <ISourceMod.h>
#if defined SMEXT_CONF_METAMOD
#include <ISmmPlugin.h>
#include <eiface.h>
#endif
using namespace SourceMod;
using namespace SourcePawn;
class SDKExtension :
#if defined SMEXT_CONF_METAMOD
public ISmmPlugin,
#endif
public IExtensionInterface
{
public:
SDKExtension();
public:
/**
* @brief This is called after the initial loading sequence has been processed.
*
* @param error Error message buffer.
* @param err_max Size of error message buffer.
* @param late Whether or not the module was loaded after map load.
* @return True to succeed loading, false to fail.
*/
virtual bool SDK_OnLoad(char *error, size_t err_max, bool late);
/**
* @brief This is called right before the extension is unloaded.
*/
virtual void SDK_OnUnload();
/**
* @brief This is called once all known extensions have been loaded.
*/
virtual void SDK_OnAllLoaded();
/**
* @brief Called when the pause state is changed.
*/
virtual void SDK_OnPauseChange(bool paused);
#if defined SMEXT_CONF_METAMOD
/**
* @brief Called when Metamod is attached, before the extension version is called.
*
* @param error Error buffer.
* @param err_max Maximum size of error buffer.
* @param late Whether or not Metamod considers this a late load.
* @return True to succeed, false to fail.
*/
virtual bool SDK_OnMetamodLoad(char *error, size_t err_max, bool late);
/**
* @brief Called when Metamod is detaching, after the extension version is called.
* NOTE: By default this is blocked unless sent from SourceMod.
*
* @param error Error buffer.
* @param err_max Maximum size of error buffer.
* @return True to succeed, false to fail.
*/
virtual bool SDK_OnMetamodUnload(char *error, size_t err_max);
/**
* @brief Called when Metamod's pause state is changing.
* NOTE: By default this is blocked unless sent from SourceMod.
*
* @param paused Pause state being set.
* @param error Error buffer.
* @param err_max Maximum size of error buffer.
* @return True to succeed, false to fail.
*/
virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t err_max);
#endif
public: //IExtensionInterface
virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t err_max, bool late);
virtual void OnExtensionUnload();
virtual void OnExtensionsAllLoaded();
virtual bool IsMetamodExtension();
virtual void OnExtensionPauseChange(bool state);
virtual const char *GetExtensionName();
virtual const char *GetExtensionURL();
virtual const char *GetExtensionTag();
virtual const char *GetExtensionAuthor();
virtual const char *GetExtensionVerString();
virtual const char *GetExtensionDescription();
virtual const char *GetExtensionDateString();
#if defined SMEXT_CONF_METAMOD
public: //ISmmPlugin
virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late);
virtual const char *GetAuthor();
virtual const char *GetName();
virtual const char *GetDescription();
virtual const char *GetURL();
virtual const char *GetLicense();
virtual const char *GetVersion();
virtual const char *GetDate();
virtual const char *GetLogTag();
virtual bool Unload(char *error, size_t maxlen);
virtual bool Pause(char *error, size_t maxlen);
virtual bool Unpause(char *error, size_t maxlen);
private:
bool m_SourceMMLoaded;
bool m_WeAreUnloaded;
bool m_WeGotPauseChange;
#endif
};
extern SDKExtension *g_pExtensionIface;
extern IShareSys *g_pShareSys;
extern IExtension *myself;
extern IHandleSys *g_pHandleSys;
extern ISourceMod *g_pSM;
#if defined SMEXT_CONF_METAMOD
PLUGIN_GLOBALVARS();
extern IVEngineServer *engine;
extern IServerGameDLL *gamedll;
#endif
#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION
#define SM_GET_IFACE(prefix,addr) \
if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) { \
if (error) { \
snprintf(error, err_max, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \
} \
return false; \
}
#endif //_INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
+39
View File
@@ -0,0 +1,39 @@
#ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_
#define _INCLUDE_SOURCEMOD_PLATFORM_H_
/**
* @file Contains platform-specific macros for abstraction.
*/
#if defined WIN32 || defined WIN64
#define PLATFORM_WINDOWS
#if !defined WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#if !defined snprintf
#define snprintf _snprintf
#endif
#if !defined stat
#define stat _stat
#endif
#define strcasecmp strcmpi
#include <windows.h>
#include <direct.h>
#define PLATFORM_LIB_EXT "dll"
#define PLATFORM_MAX_PATH MAX_PATH
#define PLATFORM_SEP_CHAR '\\'
#define PLATFORM_SEP_ALTCHAR '/'
#define PLATFORM_EXTERN_C extern "C" __declspec(dllexport)
#else if defined __linux__
#define PLATFORM_LINUX
#define PLATFORM_POSIX
#include <dirent.h>
#include <errno.h>
#define PLATFORM_MAX_PATH PATH_MAX
#define PLATFORM_LIB_EXT "so"
#define PLATFORM_SEP_CHAR '/'
#define PLATFORM_SEP_ALTCHAR '\\'
#define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default")))
#endif
#endif //_INCLUDE_SOURCEMOD_PLATFORM_H_
+163
View File
@@ -0,0 +1,163 @@
#ifndef _INCLUDE_SPFILE_HEADERS_H
#define _INCLUDE_SPFILE_HEADERS_H
#include <stddef.h>
#if defined __GNUC__ || defined HAVE_STDINT_
#include <stdint.h>
#else
#if !defined HAVE_STDINT_H
typedef unsigned __int64 uint64_t;
typedef __int64 int64_t;
typedef unsigned __int32 uint32_t;
typedef __int32 int32_t;
typedef unsigned __int16 uint16_t;
typedef __int16 int16_t;
typedef unsigned __int8 uint8_t;
typedef __int8 int8_t;
#define HAVE_STDINT_H
#endif
#endif
#define SPFILE_MAGIC 0x53504646 /* Source Pawn File Format (SPFF) */
//#define SPFILE_VERSION 0x0100
#define SPFILE_VERSION 0x0101 /* Uncompressed bytecode */
//:TODO: better compiler/nix support
#if defined __linux__
#pragma pack(1) /* structures must be packed (byte-aligned) */
#else
#pragma pack(push)
#pragma pack(1) /* structures must be packed (byte-aligned) */
#endif
#define SPFILE_COMPRESSION_NONE 0
#define SPFILE_COMPRESSION_GZ 1
typedef struct sp_file_section_s
{
uint32_t nameoffs; /* rel offset into global string table */
uint32_t dataoffs;
uint32_t size;
} sp_file_section_t;
/**
* If compression is 0, then
* disksize may be 0 to mean that
* only the imagesize is needed.
*/
typedef struct sp_file_hdr_s
{
uint32_t magic; /* magic number */
uint16_t version; /* version code */
uint8_t compression;/* compression algorithm */
uint32_t disksize; /* size on disk */
uint32_t imagesize; /* size in memory */
uint8_t sections; /* number of sections */
uint32_t stringtab; /* offset to string table */
uint32_t dataoffs; /* offset to file proper (any compression starts here) */
} sp_file_hdr_t;
#define SP_FLAG_DEBUG (1<<0)
/* section is ".code" */
typedef struct sp_file_code_s
{
uint32_t codesize; /* codesize in bytes */
uint8_t cellsize; /* cellsize in bytes */
uint8_t codeversion; /* version of opcodes supported */
uint16_t flags; /* flags */
uint32_t main; /* address to "main" if any */
uint32_t code; /* rel offset to code */
} sp_file_code_t;
/* section is .data */
typedef struct sp_file_data_s
{
uint32_t datasize; /* size of data section in memory */
uint32_t memsize; /* total mem required (includes data) */
uint32_t data; /* file offset to data (helper) */
} sp_file_data_t;
/* section is .publics */
typedef struct sp_file_publics_s
{
uint32_t address; /* address rel to code section */
uint32_t name; /* index into nametable */
} sp_file_publics_t;
/* section is .natives */
typedef struct sp_file_natives_s
{
uint32_t name; /* name of native at index */
} sp_file_natives_t;
/* section is .libraries */
typedef struct sp_file_libraries_s
{
uint32_t name; /* index into nametable */
} sp_file_libraries_t;
/* section is .pubvars */
typedef struct sp_file_pubvars_s
{
uint32_t address; /* address rel to dat section */
uint32_t name; /* index into nametable */
} sp_file_pubvars_t;
#if defined __linux__
#pragma pack() /* reset default packing */
#else
#pragma pack(pop) /* reset previous packing */
#endif
typedef struct sp_fdbg_info_s
{
uint32_t num_files; /* number of files */
uint32_t num_lines; /* number of lines */
uint32_t num_syms; /* number of symbols */
uint32_t num_arrays; /* number of symbols which are arrays */
} sp_fdbg_info_t;
/**
* Debug information structures
*/
typedef struct sp_fdbg_file_s
{
uint32_t addr; /* address into code */
uint32_t name; /* offset into debug nametable */
} sp_fdbg_file_t;
typedef struct sp_fdbg_line_s
{
uint32_t addr; /* address into code */
uint32_t line; /* line number */
} sp_fdbg_line_t;
#define SP_SYM_VARIABLE 1 /* cell that has an address and that can be fetched directly (lvalue) */
#define SP_SYM_REFERENCE 2 /* VARIABLE, but must be dereferenced */
#define SP_SYM_ARRAY 3
#define SP_SYM_REFARRAY 4 /* an array passed by reference (i.e. a pointer) */
#define SP_SYM_FUNCTION 9
typedef struct sp_fdbg_symbol_s
{
int32_t addr; /* address rel to DAT or stack frame */
int16_t tagid; /* tag id */
uint32_t codestart; /* start scope validity in code */
uint32_t codeend; /* end scope validity in code */
uint8_t ident; /* variable type */
uint8_t vclass; /* scope class (local vs global) */
uint16_t dimcount; /* dimension count (for arrays) */
uint32_t name; /* offset into debug nametable */
} sp_fdbg_symbol_t;
typedef struct sp_fdbg_arraydim_s
{
int16_t tagid; /* tag id */
uint32_t size; /* size of dimension */
} sp_fdbg_arraydim_t;
/* section is .names */
typedef char * sp_file_nametab_t;
#endif //_INCLUDE_SPFILE_HEADERS_H
+15
View File
@@ -0,0 +1,15 @@
#ifndef _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_
#define _INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_
#include "sp_vm_types.h"
inline cell_t sp_ftoc(float val)
{
return *(cell_t *)&val;
}
inline float sp_ctof(cell_t val)
{
return *(float *)&val;
}
#endif //_INCLUDE_SOURCEPAWN_VM_TYPEUTIL_H_
+631
View File
@@ -0,0 +1,631 @@
#ifndef _INCLUDE_SOURCEPAWN_VM_API_H_
#define _INCLUDE_SOURCEPAWN_VM_API_H_
#include <stdio.h>
#include "sp_vm_types.h"
#define SOURCEPAWN_VM_API_VERSION 1
#if defined SOURCEMOD_BUILD
namespace SourceMod
{
struct IdentityToken_t;
};
#endif
namespace SourcePawn
{
class IVirtualMachine;
/**
* @brief Interface to managing a debug context at runtime.
*/
class IPluginDebugInfo
{
public:
/**
* @brief Given a code pointer, finds the file it is associated with.
*
* @param addr Code address offset.
* @param filename Pointer to store filename pointer in.
*/
virtual int LookupFile(ucell_t addr, const char **filename) =0;
/**
* @brief Given a code pointer, finds the function it is associated with.
*
* @param addr Code address offset.
* @param name Pointer to store function name pointer in.
*/
virtual int LookupFunction(ucell_t addr, const char **name) =0;
/**
* @brief Given a code pointer, finds the line it is associated with.
*
* @param addr Code address offset.
* @param line Pointer to store line number in.
*/
virtual int LookupLine(ucell_t addr, uint32_t *line) =0;
};
/**
* @brief Interface to managing a context at runtime.
*/
class IPluginContext
{
public:
virtual ~IPluginContext() { };
public:
/**
* @brief Returns the parent IVirtualMachine.
*
* @return Parent virtual machine pointer.
*/
virtual IVirtualMachine *GetVirtualMachine() =0;
/**
* @brief Returns the child sp_context_t structure.
*
* @return Child sp_context_t structure.
*/
virtual sp_context_t *GetContext() =0;
/**
* @brief Returns true if the plugin is in debug mode.
*
* @return True if in debug mode, false otherwise.
*/
virtual bool IsDebugging() =0;
/**
* @brief Installs a debug break and returns the old one, if any.
* This will fail if the plugin is not debugging.
*
* @param newpfn New function pointer.
* @param oldpfn Pointer to retrieve old function pointer.
*/
virtual int SetDebugBreak(SPVM_DEBUGBREAK newpfn, SPVM_DEBUGBREAK *oldpfn) =0;
/**
* @brief Returns debug info.
*
* @return IPluginDebugInfo, or NULL if no debug info found.
*/
virtual IPluginDebugInfo *GetDebugInfo() =0;
/**
* @brief Allocs memory on the secondary stack of a plugin.
* Note that although called a heap, it is in fact a stack.
*
* @param cells Number of cells to allocate.
* @param local_addr Will be filled with data offset to heap.
* @param phys_addr Physical address to heap memory.
*/
virtual int HeapAlloc(unsigned int cells, cell_t *local_addr, cell_t **phys_addr) =0;
/**
* @brief Pops a heap address off the heap stack. Use this to free memory allocated with
* SP_HeapAlloc().
* Note that in SourcePawn, the heap is in fact a bottom-up stack. Deallocations
* with this native should be performed in precisely the REVERSE order.
*
* @param local_addr Local address to free.
*/
virtual int HeapPop(cell_t local_addr) =0;
/**
* @brief Releases a heap address using a different method than SP_HeapPop().
* This allows you to release in any order. However, if you allocate N
* objects, release only some of them, then begin allocating again,
* you cannot go back and starting freeing the originals.
* In other words, for each chain of allocations, if you start deallocating,
* then allocating more in a chain, you must only deallocate from the current
* allocation chain. This is basically HeapPop() except on a larger scale.
*
* @param local_addr Local address to free.
*/
virtual int HeapRelease(cell_t local_addr) =0;
/**
* @brief Finds a native by name.
*
* @param name Name of native.
* @param index Optionally filled with native index number.
*/
virtual int FindNativeByName(const char *name, uint32_t *index) =0;
/**
* @brief Gets native info by index.
*
* @param index Index number of native.
* @param native Optionally filled with pointer to native structure.
*/
virtual int GetNativeByIndex(uint32_t index, sp_native_t **native) =0;
/**
* @brief Gets the number of natives.
*
* @return Filled with the number of natives.
*/
virtual uint32_t GetNativesNum() =0;
/**
* @brief Finds a public function by name.
*
* @param name Name of public
* @param index Optionally filled with public index number.
*/
virtual int FindPublicByName(const char *name, uint32_t *index) =0;
/**
* @brief Gets public function info by index.
*
* @param index Public function index number.
* @param publicptr Optionally filled with pointer to public structure.
*/
virtual int GetPublicByIndex(uint32_t index, sp_public_t **publicptr) =0;
/**
* @brief Gets the number of public functions.
*
* @return Filled with the number of public functions.
*/
virtual uint32_t GetPublicsNum() =0;
/**
* @brief Gets public variable info by index.
*
* @param index Public variable index number.
* @param pubvar Optionally filled with pointer to pubvar structure.
*/
virtual int GetPubvarByIndex(uint32_t index, sp_pubvar_t **pubvar) =0;
/**
* @brief Finds a public variable by name.
*
* @param name Name of pubvar
* @param index Optionally filled with pubvar index number.
*/
virtual int FindPubvarByName(const char *name, uint32_t *index) =0;
/**
* @brief Gets the addresses of a public variable.
*
* @param index Index of public variable.
* @param local_addr Address to store local address in.
* @param phys_addr Address to store physically relocated in.
*/
virtual int GetPubvarAddrs(uint32_t index, cell_t *local_addr, cell_t **phys_addr) =0;
/**
* @brief Returns the number of public variables.
*
* @return Number of public variables.
*/
virtual uint32_t GetPubVarsNum() =0;
/**
* @brief Round-about method of converting a plugin reference to a physical address
*
* @param local_addr Local address in plugin.
* @param phys_addr Optionally filled with relocated physical address.
*/
virtual int LocalToPhysAddr(cell_t local_addr, cell_t **phys_addr) =0;
/**
* @brief Converts a local address to a physical string.
*
* @param local_addr Local address in plugin.
* @param addr Destination output pointer.
*/
virtual int LocalToString(cell_t local_addr, char **addr) =0;
/**
* @brief Converts a physical string to a local address.
*
* @param local_addr Local address in plugin.
* @param bytes Number of chars to write, including NULL terminator.
* @param source Source string to copy.
*/
virtual int StringToLocal(cell_t local_addr, size_t bytes, const char *source) =0;
/**
* @brief Converts a physical UTF-8 string to a local address.
* This function is the same as the ANSI version, except it will copy the maximum number of characters possible
* without accidentally chopping a multi-byte character.
*
* @param local_addr Local address in plugin.
* @param maxbytes Number of bytes to write, including NULL terminator.
* @param source Source string to copy.
* @param wrtnbytes Optionally set to the number of actual bytes written.
*/
virtual int StringToLocalUTF8(cell_t local_addr,
size_t maxbytes,
const char *source,
size_t *wrtnbytes) =0;
/**
* @brief Pushes a cell onto the stack. Increases the parameter count by one.
*
* @param value Cell value.
*/
virtual int PushCell(cell_t value) =0;
/**
* @brief Pushes an array of cells onto the stack. Increases the parameter count by one.
* If the function returns an error it will fail entirely, releasing anything allocated in the process.
* Note that this does not release the heap, so you should release it after
* calling Execute().
*
* @param local_addr Filled with local address to release.
* @param phys_addr Optionally filled with physical address of new array.
* @param array Cell array to copy.
* @param numcells Number of cells in the array to copy.
*/
virtual int PushCellArray(cell_t *local_addr, cell_t **phys_addr, cell_t array[], unsigned int numcells) =0;
/**
* @brief Pushes a string onto the stack (by reference) and increases the parameter count by one.
* Note that this does not release the heap, so you should release it after
* calling Execute().
*
* @param local_addr Filled with local address to release.
* @param phys_addr Optionally filled with physical address of new array.
* @param string Source string to push.
*/
virtual int PushString(cell_t *local_addr, char **phys_addr, const char *string) =0;
/**
* @brief Individually pushes each cell of an array of cells onto the stack. Increases the
* parameter count by the number of cells pushed.
* If the function returns an error it will fail entirely, releasing anything allocated in the process.
*
* @param array Array of cells to read from.
* @param numcells Number of cells to read.
*/
virtual int PushCellsFromArray(cell_t array[], unsigned int numcells) =0;
/**
* @brief Binds a list of native names and their function pointers to a context.
* If num is 0, the list is read until an entry with a NULL name is reached.
* If overwrite is non-zero, already registered natives will be overwritten.
*
* @param natives Array of natives.
* @param num Number of natives in array.
* @param overwrite Toggles overwrite.
*/
virtual int BindNatives(const sp_nativeinfo_t *natives, unsigned int num, int overwrite) =0;
/**
* @brief Binds a single native. Overwrites any existing bind.
* If the context does not contain the native that will be binded the function will return
* with a SP_ERROR_NOT_FOUND error.
*
* @param native Pointer to native.
*/
virtual int BindNative(const sp_nativeinfo_t *native) =0;
/**
* @brief Binds a single native to any non-registered native.
*
* @param native Native to bind.
*/
virtual int BindNativeToAny(SPVM_NATIVE_FUNC native) =0;
/**
* @brief Executes a function ID located in this context.
*
* @param funcid Function id to execute.
* @param result Pointer to store the return value (required).
* @return Error code (if any) from the VM.
*/
virtual int Execute(uint32_t funcid, cell_t *result) =0;
/**
* @brief Throws a error and halts any current execution.
*
* @param error The error number to set.
* @param msg Custom error message format. NULL to use default.
* @param ... Message format arguments, if any.
*/
virtual void ThrowNativeErrorEx(int error, const char *msg, ...) =0;
/**
* @brief Throws a generic native error and halts any current execution.
*
* @param msg Custom error message format. NULL to set no message.
* @param ... Message format arguments, if any.
* @return 0 for convenience.
*/
virtual cell_t ThrowNativeError(const char *msg, ...) =0;
#if defined SOURCEMOD_BUILD
/**
* @brief Returns the identity token for this context.
* Note: This is a helper function for native calls and the Handle System.
*
* @return Identity token.
*/
virtual SourceMod::IdentityToken_t *GetIdentity() =0;
#endif
};
/**
* @brief Information about a position in a call stack.
*/
struct CallStackInfo
{
const char *filename; /* NULL if not found */
unsigned int line; /* 0 if not found */
const char *function; /* NULL if not found */
};
/**
* @brief Retrieves error information from a debug hook.
*/
class IContextTrace
{
public:
/**
* @brief Returns the integer error code.
*
* @return Integer error code.
*/
virtual int GetErrorCode() =0;
/**
* @brief Returns a string describing the error.
*
* @return Error string.
*/
virtual const char *GetErrorString() =0;
/**
* @brief Returns whether debug info is available.
*
* @return True if debug info is available, false otherwise.
*/
virtual bool DebugInfoAvailable() =0;
/**
* @brief Returns a custom error message.
*
* @return A pointer to a custom error message, or NULL otherwise.
*/
virtual const char *GetCustomErrorString() =0;
/**
* @brief Returns trace info for a specific point in the backtrace, if any.
* The next subsequent call to GetTraceInfo() will return the next item in the call stack.
* Calls are retrieved in descending order (i.e. the first item is at the top of the stack/call sequence).
*
* @param trace An ErrorTraceInfo buffer to store information (NULL to ignore).
* @return True if successful, false if there are no more traces.
*/
virtual bool GetTraceInfo(CallStackInfo *trace) =0;
/**
* @brief Resets the trace to its original position (the call on the top of the stack).
*/
virtual void ResetTrace() =0;
/**
* @brief Retrieves the name of the last native called.
* Returns NULL if there was no native that caused the error.
*
* @param index Optional pointer to store index.
* @return Native name, or NULL if none.
*/
virtual const char *GetLastNative(uint32_t *index) =0;
};
/**
* @brief Provides callbacks for debug information.
*/
class IDebugListener
{
public:
virtual void OnContextExecuteError(IPluginContext *ctx, IContextTrace *error) =0;
};
/**
* @brief Contains helper functions used by VMs and the host app
*/
class ISourcePawnEngine
{
public:
/**
* @brief Loads a named file from a file pointer.
* Note: Using this means the memory will be allocated by the VM.
*
* @param fp File pointer. May be at any offset. Not closed on return.
* @param err Optional error code pointer.
* @return A new plugin structure.
*/
virtual sp_plugin_t *LoadFromFilePointer(FILE *fp, int *err) =0;
/**
* @brief Loads a file from a base memory address.
*
* @param base Base address of the plugin's memory region.
* @param plugin If NULL, a new plugin pointer is returned.
* Otherwise, the passed pointer is used.
* @param err Optional error code pointer.
* @return The resulting plugin pointer.
*/
virtual sp_plugin_t *LoadFromMemory(void *base, sp_plugin_t *plugin, int *err) =0;
/**
* Frees all of the memory associated with a plugin file.
* If allocated using SP_LoadFromMemory, the base and plugin pointer
* itself are not freed (so this may end up doing nothing).
*/
virtual int FreeFromMemory(sp_plugin_t *plugin) =0;
/**
* @brief Allocates large blocks of temporary memory.
*
* @param size Size of memory to allocate.
* @return Pointer to memory, NULL if allocation failed.
*/
virtual void *BaseAlloc(size_t size) =0;
/**
* @brief Frees memory allocated with BaseAlloc.
*
* @param memory Memory address to free.
*/
virtual void BaseFree(void *memory) =0;
/**
* @brief Allocates executable memory.
*
* @param size Size of memory to allocate.
* @return Pointer to memory, NULL if allocation failed.
*/
virtual void *ExecAlloc(size_t size) =0;
/**
* @brief Frees executable memory.
*
* @param address Address to free.
*/
virtual void ExecFree(void *address) =0;
/**
* @brief Sets the debug listener. This should only be called once.
* If called successively (using manual chaining), only the last function should
* attempt to call back into the same plugin. Otherwise, globally cached states
* can be accidentally overwritten.
*
* @param listener Pointer to an IDebugListener.
* @return Old IDebugListener, or NULL if none.
*/
virtual IDebugListener *SetDebugListener(IDebugListener *listener) =0;
/**
* @brief Returns the number of plugins on the call stack.
*
* @return Number of contexts in the call stack.
*/
virtual unsigned int GetContextCallCount() =0;
};
/**
* @brief Dummy class for encapsulating private compilation data.
*/
class ICompilation
{
public:
virtual ~ICompilation() { };
};
/**
* @brief Outlines the interface a Virtual Machine (JIT) must expose
*/
class IVirtualMachine
{
public:
/**
* @brief Returns the current API version.
*/
virtual unsigned int GetAPIVersion() =0;
/**
* @brief Returns the string name of a VM implementation.
*/
virtual const char *GetVMName() =0;
/**
* @brief Begins a new compilation
*
* @param plugin Pointer to a plugin structure.
* @return New compilation pointer.
*/
virtual ICompilation *StartCompilation(sp_plugin_t *plugin) =0;
/**
* @brief Sets a compilation option.
*
* @param co Pointer to a compilation.
* @param key Option key name.
* @param val Option value string.
* @return True if option could be set, false otherwise.
*/
virtual bool SetCompilationOption(ICompilation *co, const char *key, const char *val) =0;
/**
* @brief Finalizes a compilation into a new sp_context_t.
* Note: This will free the ICompilation pointer.
*
* @param co Compilation pointer.
* @param err Filled with error code on exit.
* @return New plugin context.
*/
virtual sp_context_t *CompileToContext(ICompilation *co, int *err) =0;
/**
* @brief Aborts a compilation and frees the ICompilation pointer.
*
* @param co Compilation pointer.
*/
virtual void AbortCompilation(ICompilation *co) =0;
/**
* @brief Frees any internal variable usage on a context.
*
* @param ctx Context structure pointer.
*/
virtual void FreeContext(sp_context_t *ctx) =0;
/**
* @brief Calls the "execute" function on a context.
*
* @param ctx Executes a function in a context.
* @param code_addr Index into the code section.
* @param result Pointer to store result into.
* @return Error code (if any).
*/
virtual int ContextExecute(sp_context_t *ctx, uint32_t code_addr, cell_t *result) =0;
/**
* @brief Given a context and a code address, returns the index of the function.
*
* @param ctx Context to search.
* @param code_addr Index into the code section.
* @param result Pointer to store result into.
* @return True if code index is valid, false otherwise.
*/
virtual bool FunctionLookup(const sp_context_t *ctx, uint32_t code_addr, unsigned int *result) =0;
/**
* @brief Returns the number of functions defined in the context.
*
* @param ctx Context to search.
* @return Number of functions.
*/
virtual unsigned int FunctionCount(const sp_context_t *ctx) =0;
/**
* @brief Returns a version string.
*
* @return Versioning string.
*/
virtual const char *GetVersionString() =0;
/**
* @brief Returns a string describing optimizations.
*
* @return String describing CPU specific optimizations.
*/
virtual const char *GetCPUOptimizations() =0;
};
};
#endif //_INCLUDE_SOURCEPAWN_VM_API_H_
+16
View File
@@ -0,0 +1,16 @@
#ifndef _INCLUDE_SOURCEPAWN_VM_BASE_H_
#define _INCLUDE_SOURCEPAWN_VM_BASE_H_
#include <sp_vm_api.h>
/* :TODO: rename this to sp_vm_linkage.h */
#if defined WIN32
#define EXPORT_LINK extern "C" __declspec(dllexport)
#else if defined __GNUC__
#define EXPORT_LINK extern "C" __attribute__((visibility("default")))
#endif
typedef SourcePawn::IVirtualMachine *(*SP_GETVM_FUNC)(SourcePawn::ISourcePawnEngine *);
#endif //_INCLUDE_SOURCEPAWN_VM_BASE_H_
+251
View File
@@ -0,0 +1,251 @@
#ifndef _INCLUDE_SOURCEPAWN_VM_TYPES_H
#define _INCLUDE_SOURCEPAWN_VM_TYPES_H
#include "sp_file_headers.h"
typedef uint32_t ucell_t;
typedef int32_t cell_t;
typedef uint32_t funcid_t;
#include "sp_typeutil.h"
#define SP_MAX_EXEC_PARAMS 32 /* Maximum number of parameters in a function */
/**
* Error codes
* NOTE: Be sure to update the error string table when changing these
*/
#define SP_ERROR_NONE 0
#define SP_ERROR_FILE_FORMAT 1 /* File format unrecognized */
#define SP_ERROR_DECOMPRESSOR 2 /* A decompressor was not found */
#define SP_ERROR_HEAPLOW 3 /* Not enough space left on the heap */
#define SP_ERROR_PARAM 4 /* Invalid parameter or parameter type */
#define SP_ERROR_INVALID_ADDRESS 5 /* A memory address was not valid */
#define SP_ERROR_NOT_FOUND 6 /* The object in question was not found */
#define SP_ERROR_INDEX 7 /* Invalid index parameter */
#define SP_ERROR_STACKLOW 8 /* Nnot enough space left on the stack */
#define SP_ERROR_NOTDEBUGGING 9 /* Debug mode was not on or debug section not found */
#define SP_ERROR_INVALID_INSTRUCTION 10 /* Invalid instruction was encountered */
#define SP_ERROR_MEMACCESS 11 /* Invalid memory access */
#define SP_ERROR_STACKMIN 12 /* Stack went beyond its minimum value */
#define SP_ERROR_HEAPMIN 13 /* Heap went beyond its minimum value */
#define SP_ERROR_DIVIDE_BY_ZERO 14 /* Division by zero */
#define SP_ERROR_ARRAY_BOUNDS 15 /* Array index is out of bounds */
#define SP_ERROR_INSTRUCTION_PARAM 16 /* Instruction had an invalid parameter */
#define SP_ERROR_STACKLEAK 17 /* A native leaked an item on the stack */
#define SP_ERROR_HEAPLEAK 18 /* A native leaked an item on the heap */
#define SP_ERROR_ARRAY_TOO_BIG 19 /* A dynamic array is too big */
#define SP_ERROR_TRACKER_BOUNDS 20 /* Tracker stack is out of bounds */
#define SP_ERROR_INVALID_NATIVE 21 /* Native was pending or invalid */
#define SP_ERROR_PARAMS_MAX 22 /* Maximum number of parameters reached */
#define SP_ERROR_NATIVE 23 /* Error originates from a native */
/**********************************************
*** The following structures are reference structures.
*** They are not essential to the API, but are used
*** to hold the back end database format of the plugin
*** binary.
**********************************************/
/**
* Information about the core plugin tables.
* These may or may not be present!
*/
typedef struct sp_plugin_infotab_s
{
const char *stringbase; /* base of string table */
uint32_t publics_num; /* number of publics */
sp_file_publics_t *publics; /* public table */
uint32_t natives_num; /* number of natives */
sp_file_natives_t *natives; /* native table */
uint32_t pubvars_num; /* number of pubvars */
sp_file_pubvars_t *pubvars; /* pubvars table */
uint32_t libraries_num; /* number of libraries */
sp_file_libraries_t *lib; /* library table */
} sp_plugin_infotab_t;
/**
* Information about the plugin's debug tables.
* These are all present if one is present.
*/
typedef struct sp_plugin_debug_s
{
const char *stringbase; /* base of string table */
uint32_t files_num; /* number of files */
sp_fdbg_file_t *files; /* files table */
uint32_t lines_num; /* number of lines */
sp_fdbg_line_t *lines; /* lines table */
uint32_t syms_num; /* number of symbols */
sp_fdbg_symbol_t *symbols; /* symbol table */
} sp_plugin_debug_t;
#define SP_FA_SELF_EXTERNAL (1<<0)
#define SP_FA_BASE_EXTERNAL (1<<1)
/**
* The rebased, in-memory format of a plugin.
* This differs from the on-disk structure to ensure
* that the format is properly read.
*/
typedef struct sp_plugin_s
{
uint8_t *base; /* base of memory */
uint8_t *pcode; /* p-code */
uint32_t pcode_size; /* size of p-code */
uint8_t *data; /* data size */
uint32_t data_size; /* size of data */
uint32_t memory; /* required memory */
uint16_t flags; /* code flags */
uint32_t allocflags; /* allocation flags */
sp_plugin_infotab_t info; /* base info table */
sp_plugin_debug_t debug; /* debug info table */
} sp_plugin_t;
/** Forward declarations */
namespace SourcePawn
{
class IPluginContext;
class IVirtualMachine;
};
struct sp_context_s;
typedef cell_t (*SPVM_NATIVE_FUNC)(SourcePawn::IPluginContext *, const cell_t *);
/**********************************************
*** The following structures are bound to the VM/JIT.
*** Changing them will result in necessary recompilation.
**********************************************/
/**
* Offsets and names to a public function.
* By default, these point back to the string table
* in the sp_plugin_infotab_t structure.
*/
typedef struct sp_public_s
{
funcid_t funcid; /* encoded function id */
uint32_t code_offs; /* code offset */
const char *name; /* name */
} sp_public_t;
/**
* Offsets and names to public variables.
* The offset is relocated and the name by default
* points back to the sp_plugin_infotab_t structure.
*/
typedef struct sp_pubvar_s
{
cell_t *offs; /* pointer to data */
const char *name; /* name */
} sp_pubvar_t;
#define SP_NATIVE_UNBOUND (0) /* Native is undefined */
#define SP_NATIVE_BOUND (1) /* Native is bound */
/**
* Native lookup table, by default names
* point back to the sp_plugin_infotab_t structure.
* A native is NULL if unit
*/
typedef struct sp_native_s
{
SPVM_NATIVE_FUNC pfn; /* function pointer */
const char * name; /* name of function */
uint32_t status; /* status flags */
} sp_native_t;
/**
* Used for setting natives from modules/host apps.
*/
typedef struct sp_nativeinfo_s
{
const char *name;
SPVM_NATIVE_FUNC func;
} sp_nativeinfo_t;
/**
* Debug file table
*/
typedef struct sp_debug_file_s
{
uint32_t addr; /* address into code */
const char * name; /* name of file */
} sp_debug_file_t;
/**
* Note that line is missing. It is not necessary since
* this can be retrieved from the base plugin info.
*/
typedef struct sp_debug_line_s
{
uint32_t addr; /* address into code */
uint32_t line; /* line no. */
} sp_debug_line_t;
typedef sp_fdbg_arraydim_t sp_debug_arraydim_t;
/**
* The majority of this struct is already located in the parent
* block. Thus, only the relocated portions are required.
*/
typedef struct sp_debug_symbol_s
{
uint32_t codestart; /* relocated code address */
uint32_t codeend; /* relocated code end address */
const char * name; /* relocated name */
sp_debug_arraydim_t *dims; /* relocated dimension struct, if any */
sp_fdbg_symbol_t *sym; /* pointer to original symbol */
} sp_debug_symbol_t;
/**
* Breaks into a debugger
* Params:
* [0] - plugin context
* [1] - frm
* [2] - cip
*/
typedef int (*SPVM_DEBUGBREAK)(struct sp_context_s *, uint32_t, uint32_t);
#define SPFLAG_PLUGIN_DEBUG (1<<0) /* plugin is in debug mode */
/**
* This is the heart of the VM. It contains all of the runtime
* information about a plugin context.
* Note that user[0..3] can be used for any user based pointers.
* vm[0..3] should not be touched, as it is reserved for the VM.
*/
typedef struct sp_context_s
{
/* general/parent information */
void *codebase; /* base of generated code and memory */
sp_plugin_t *plugin; /* pointer back to parent information */
SourcePawn::IPluginContext *context; /* pointer to IPluginContext */
SourcePawn::IVirtualMachine *vmbase; /* pointer to IVirtualMachine */
void *user[4]; /* user specific pointers */
void *vm[4]; /* VM specific pointers */
uint32_t flags; /* compilation flags */
SPVM_DEBUGBREAK dbreak; /* debug break function */
/* context runtime information */
uint8_t *memory; /* data chunk */
ucell_t mem_size; /* total memory size; */
cell_t data_size; /* data chunk size, always starts at 0 */
cell_t heap_base; /* where the heap starts */
/* execution specific data */
cell_t hp; /* heap pointer */
cell_t sp; /* stack pointer */
cell_t frm; /* frame pointer */
uint32_t pushcount; /* push count */
int32_t n_err; /* error code set by a native */
uint32_t n_idx; /* current native index being executed */
/* context rebased database */
sp_public_t *publics; /* public functions table */
sp_pubvar_t *pubvars; /* public variables table */
sp_native_t *natives; /* natives table */
sp_debug_file_t *files; /* files */
sp_debug_line_t *lines; /* lines */
sp_debug_symbol_t *symbols; /* symbols */
} sp_context_t;
#endif //_INCLUDE_SOURCEPAWN_VM_TYPES_H