Initial import of new version :]
This commit is contained in:
@ -1,448 +0,0 @@
|
||||
/* AMX Mod X
|
||||
*
|
||||
* by the AMX Mod X Development Team
|
||||
* originally developed by OLO
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* In addition, as a special exception, the author gives permission to
|
||||
* link the code of this program with the Half-Life Game Engine ("HL
|
||||
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
|
||||
* L.L.C ("Valve"). You must obey the GNU General Public License in all
|
||||
* respects for all of the code used other than the HL Engine and MODs
|
||||
* from Valve. If you modify this file, you may extend this exception
|
||||
* to your version of the file, but you are not obligated to do so. If
|
||||
* you do not wish to do so, delete this exception statement from your
|
||||
* version.
|
||||
*/
|
||||
|
||||
#ifndef __CVECTOR_H__
|
||||
#define __CVECTOR_H__
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// Vector
|
||||
template <class T> class CVector
|
||||
{
|
||||
bool Grow()
|
||||
{
|
||||
// automatic grow
|
||||
size_t newSize = m_Size * 2;
|
||||
if (newSize == 0)
|
||||
newSize = 8; // a good init value
|
||||
T *newData = new T[newSize];
|
||||
if (!newData)
|
||||
return false;
|
||||
if (m_Data)
|
||||
{
|
||||
for (size_t i=0; i<m_CurrentUsedSize; i++)
|
||||
newData[i] = m_Data[i];
|
||||
delete [] m_Data;
|
||||
}
|
||||
m_Data = newData;
|
||||
m_Size = newSize;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrowIfNeeded()
|
||||
{
|
||||
if (m_CurrentUsedSize >= m_Size)
|
||||
return Grow();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ChangeSize(size_t size)
|
||||
{
|
||||
// change size
|
||||
if (size == m_Size)
|
||||
return true;
|
||||
T *newData = new T[size];
|
||||
if (!newData)
|
||||
return false;
|
||||
if (m_Data)
|
||||
{
|
||||
size_t end = (m_Size < size) ? (m_Size) : size;
|
||||
for (size_t i=0; i<end; i++)
|
||||
newData[i] = m_Data[i];
|
||||
delete [] m_Data;
|
||||
}
|
||||
if (m_Size < size)
|
||||
m_CurrentSize = size;
|
||||
m_Data = newData;
|
||||
m_Size = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeMemIfPossible()
|
||||
{
|
||||
|
||||
}
|
||||
protected:
|
||||
T *m_Data;
|
||||
size_t m_Size;
|
||||
size_t m_CurrentUsedSize;
|
||||
size_t m_CurrentSize;
|
||||
public:
|
||||
class iterator
|
||||
{
|
||||
protected:
|
||||
T *m_Ptr;
|
||||
public:
|
||||
// constructors / destructors
|
||||
iterator()
|
||||
{
|
||||
m_Ptr = NULL;
|
||||
}
|
||||
|
||||
iterator(T * ptr)
|
||||
{
|
||||
m_Ptr = ptr;
|
||||
}
|
||||
|
||||
// member functions
|
||||
T * base()
|
||||
{
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
const T * base() const
|
||||
{
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
// operators
|
||||
T & operator*()
|
||||
{
|
||||
return *m_Ptr;
|
||||
}
|
||||
|
||||
T * operator->()
|
||||
{
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
iterator & operator++() // preincrement
|
||||
{
|
||||
++m_Ptr;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
iterator operator++(int) // postincrement
|
||||
{
|
||||
iterator tmp = *this;
|
||||
++m_Ptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
iterator & operator--() // predecrement
|
||||
{
|
||||
--m_Ptr;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
iterator operator--(int) // postdecrememnt
|
||||
{
|
||||
iterator tmp = *this;
|
||||
--m_Ptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool operator==(T * right) const
|
||||
{
|
||||
return (m_Ptr == right);
|
||||
}
|
||||
|
||||
bool operator==(const iterator & right) const
|
||||
{
|
||||
return (m_Ptr == right.m_Ptr);
|
||||
}
|
||||
|
||||
bool operator!=(T * right) const
|
||||
{
|
||||
return (m_Ptr != right);
|
||||
}
|
||||
|
||||
bool operator!=(const iterator & right) const
|
||||
{
|
||||
return (m_Ptr != right.m_Ptr);
|
||||
}
|
||||
|
||||
iterator & operator+=(size_t offset)
|
||||
{
|
||||
m_Ptr += offset;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
iterator & operator-=(size_t offset)
|
||||
{
|
||||
m_Ptr += offset;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
iterator operator+(size_t offset) const
|
||||
{
|
||||
iterator tmp(*this);
|
||||
tmp.m_Ptr += offset;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
iterator operator-(size_t offset) const
|
||||
{
|
||||
iterator tmp(*this);
|
||||
tmp.m_Ptr += offset;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
T & operator[](size_t offset)
|
||||
{
|
||||
return (*(*this + offset));
|
||||
}
|
||||
|
||||
const T & operator[](size_t offset) const
|
||||
{
|
||||
return (*(*this + offset));
|
||||
}
|
||||
|
||||
bool operator<(const iterator & right) const
|
||||
{
|
||||
return m_Ptr < right.m_Ptr;
|
||||
}
|
||||
|
||||
bool operator>(const iterator & right) const
|
||||
{
|
||||
return m_Ptr > right.m_Ptr;
|
||||
}
|
||||
|
||||
bool operator<=(const iterator & right) const
|
||||
{
|
||||
return m_Ptr <= right.m_Ptr;
|
||||
}
|
||||
|
||||
bool operator>=(const iterator & right) const
|
||||
{
|
||||
return m_Ptr >= right.m_Ptr;
|
||||
}
|
||||
|
||||
size_t operator-(const iterator & right) const
|
||||
{
|
||||
return m_Ptr - right.m_Ptr;
|
||||
}
|
||||
};
|
||||
|
||||
// constructors / destructors
|
||||
CVector<T>()
|
||||
{
|
||||
m_Size = 0;
|
||||
m_CurrentUsedSize = 0;
|
||||
m_Data = NULL;
|
||||
}
|
||||
|
||||
CVector<T>(const CVector<T> & other)
|
||||
{
|
||||
// copy data
|
||||
m_Data = new T [other.m_CurrentUsedSize];
|
||||
m_Size = other.m_CurrentUsedSize;
|
||||
m_CurrentUsedSize = other.m_CurrentUsedSize;
|
||||
for (size_t i=0; i<other.m_CurrentUsedSize; i++)
|
||||
m_Data[i] = other.m_Data[i];
|
||||
}
|
||||
|
||||
~CVector<T>()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
// interface
|
||||
size_t size() const
|
||||
{
|
||||
return m_CurrentUsedSize;
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return iterator(m_Data);
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
return iterator(m_Data + m_CurrentUsedSize);
|
||||
}
|
||||
|
||||
iterator iterAt(size_t pos)
|
||||
{
|
||||
if (pos > m_CurrentUsedSize)
|
||||
assert(0);
|
||||
return iterator(m_Data + pos);
|
||||
}
|
||||
|
||||
bool reserve(size_t newSize)
|
||||
{
|
||||
return ChangeSize(newSize);
|
||||
}
|
||||
|
||||
bool push_back(const T & elem)
|
||||
{
|
||||
++m_CurrentUsedSize;
|
||||
if (!GrowIfNeeded())
|
||||
{
|
||||
--m_CurrentUsedSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_Data[m_CurrentUsedSize - 1] = elem;
|
||||
return true;
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
--m_CurrentUsedSize;
|
||||
if (m_CurrentUsedSize < 0)
|
||||
m_CurrentUsedSize = 0;
|
||||
// :TODO: free memory sometimes
|
||||
}
|
||||
|
||||
bool resize(size_t newSize)
|
||||
{
|
||||
if (!ChangeSize(newSize))
|
||||
return false;
|
||||
FreeMemIfPossible();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return (m_CurrentUsedSize == 0);
|
||||
}
|
||||
|
||||
T & at(size_t pos)
|
||||
{
|
||||
if (pos > m_CurrentUsedSize)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return m_Data[pos];
|
||||
}
|
||||
|
||||
const T & at(size_t pos) const
|
||||
{
|
||||
if (pos > m_CurrentUsedSize)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return m_Data[pos];
|
||||
}
|
||||
|
||||
T & operator[](size_t pos)
|
||||
{
|
||||
return at(pos);
|
||||
}
|
||||
|
||||
const T & operator[](size_t pos) const
|
||||
{
|
||||
return at(pos);
|
||||
}
|
||||
|
||||
T & front()
|
||||
{
|
||||
if (m_CurrentUsedSize < 1)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return m_Data[0];
|
||||
}
|
||||
|
||||
const T & front() const
|
||||
{
|
||||
if (m_CurrentUsedSize < 1)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return m_Data[0];
|
||||
}
|
||||
|
||||
T & back()
|
||||
{
|
||||
if (m_CurrentUsedSize < 1)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return m_Data[m_CurrentUsedSize - 1];
|
||||
}
|
||||
|
||||
const T & back() const
|
||||
{
|
||||
if (m_CurrentUsedSize < 1)
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
return m_Data[m_CurrentUsedSize - 1];
|
||||
}
|
||||
|
||||
bool insert(iterator where, const T & value)
|
||||
{
|
||||
// we have to insert before
|
||||
// if it is begin, don't decrement
|
||||
if (where != m_Data)
|
||||
--where;
|
||||
// validate iter
|
||||
if (where < m_Data || where >= (m_Data + m_CurrentUsedSize))
|
||||
return false;
|
||||
|
||||
++m_CurrentUsedSize;
|
||||
if (!GrowIfNeeded())
|
||||
{
|
||||
--m_CurrentUsedSize;
|
||||
return false;
|
||||
}
|
||||
|
||||
memmove(where.base() + 1, where.base(), m_CurrentUsedSize - (where - m_Data));
|
||||
memcpy(where.base(), &value, sizeof(T));
|
||||
return true;
|
||||
}
|
||||
|
||||
void erase(iterator where)
|
||||
{
|
||||
// validate iter
|
||||
if (where < m_Data || where >= (m_Data + m_CurrentUsedSize))
|
||||
return false;
|
||||
|
||||
if (m_CurrentUsedSize > 1)
|
||||
{
|
||||
// move
|
||||
memmove(where.base(), where.base() + 1, m_CurrentUsedSize - 1);
|
||||
}
|
||||
|
||||
--m_CurrentUsedSize;
|
||||
// :TODO: free memory sometimes
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_Size = 0;
|
||||
m_CurrentUsedSize = 0;
|
||||
delete [] m_Data;
|
||||
m_Data = NULL;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // __CVECTOR_H__
|
||||
|
@ -31,8 +31,10 @@
|
||||
|
||||
// ***** AMXX stuff *****
|
||||
|
||||
// module interface version is 1
|
||||
#define AMXX_INTERFACE_VERSION 2
|
||||
// module interface version was 1
|
||||
// 2 - added logtag to struct (amxx1.1-rc1)
|
||||
// 3 - added new tagAMX structure (amxx1.5)
|
||||
#define AMXX_INTERFACE_VERSION 3
|
||||
|
||||
// amxx module info
|
||||
struct amxx_module_info_s
|
||||
@ -54,38 +56,55 @@ struct amxx_module_info_s
|
||||
|
||||
// *** Small stuff ***
|
||||
// The next section is copied from the amx.h file
|
||||
// Copyright (c) ITB CompuPhase, 1997-2004
|
||||
// Copyright (c) ITB CompuPhase, 1997-2005
|
||||
|
||||
#if defined __LCC__ || defined __DMC__ || defined __linux__ || defined __GNUC__
|
||||
#if defined HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
/* The ISO C99 defines the int16_t and int_32t types. If the compiler got
|
||||
* here, these types are probably undefined.
|
||||
*/
|
||||
#if defined __FreeBSD__
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
typedef short int int16_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
#if defined SN_TARGET_PS2
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
#if defined __LCC__ || defined __DMC__ || defined LINUX
|
||||
#if defined HAVE_INTTYPES_H
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
typedef long int int32_t;
|
||||
typedef unsigned long int uint32_t;
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#define HAVE_I64
|
||||
#elif defined __GNUC__
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#define HAVE_I64
|
||||
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||
/* The ISO C99 defines the int16_t and int_32t types. If the compiler got
|
||||
* here, these types are probably undefined.
|
||||
*/
|
||||
#if defined __MACH__
|
||||
#include <ppc/types.h>
|
||||
typedef unsigned short int uint16_t;
|
||||
typedef unsigned long int uint32_t;
|
||||
#elif defined __FreeBSD__
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
typedef short int int16_t;
|
||||
typedef unsigned short int uint16_t;
|
||||
#if defined SN_TARGET_PS2
|
||||
typedef int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#else
|
||||
typedef long int int32_t;
|
||||
typedef unsigned long int uint32_t;
|
||||
#endif
|
||||
#if defined __WIN32__ || defined _WIN32 || defined WIN32
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#define HAVE_I64
|
||||
#elif defined __GNUC__
|
||||
typedef long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
#define HAVE_I64
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#define HAVE_STDINT_H
|
||||
#endif
|
||||
#if defined _LP64 || defined WIN64 || defined _WIN64
|
||||
#if !defined __64BIT__
|
||||
#define __64BIT__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* calling convention for native functions */
|
||||
#if !defined AMX_NATIVE_CALL
|
||||
@ -105,24 +124,26 @@ struct amxx_module_info_s
|
||||
#define AMXEXPORT
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if !defined SMALL_CELL_SIZE
|
||||
#define SMALL_CELL_SIZE 32 /* by default, use 32-bit cells */
|
||||
#if !defined PAWN_CELL_SIZE
|
||||
#define PAWN_CELL_SIZE 32 /* by default, use 32-bit cells */
|
||||
#endif
|
||||
#if SMALL_CELL_SIZE==32
|
||||
#if PAWN_CELL_SIZE==16
|
||||
typedef uint16_t ucell;
|
||||
typedef int16_t cell;
|
||||
#elif PAWN_CELL_SIZE==32
|
||||
typedef uint32_t ucell;
|
||||
typedef int32_t cell;
|
||||
typedef float REAL;
|
||||
#elif SMALL_CELL_SIZE==64
|
||||
#define REAL float
|
||||
#elif PAWN_CELL_SIZE==64
|
||||
typedef uint64_t ucell;
|
||||
typedef int64_t cell;
|
||||
typedef double REAL;
|
||||
#define REAL double
|
||||
#else
|
||||
#error Unsupported cell size (SMALL_CELL_SIZE)
|
||||
#error Unsupported cell size (PAWN_CELL_SIZE)
|
||||
#endif
|
||||
|
||||
#define UNPACKEDMAX ((1 << (sizeof(cell)-1)*8) - 1)
|
||||
#define UNLIMITED (~1u >> 1)
|
||||
|
||||
struct tagAMX;
|
||||
typedef cell (AMX_NATIVE_CALL *AMX_NATIVE)(struct tagAMX *amx, cell *params);
|
||||
@ -140,21 +161,24 @@ typedef int (AMXAPI *AMX_DEBUG)(struct tagAMX *amx);
|
||||
#endif
|
||||
|
||||
|
||||
#if defined SN_TARGET_PS2 || defined __GNUC__
|
||||
/* Some compilers do not support the #pragma align, which should be fine. Some
|
||||
* compilers give a warning on unknown #pragmas, which is not so fine...
|
||||
*/
|
||||
#if (defined SN_TARGET_PS2 || defined __GNUC__) && !defined AMX_NO_ALIGN
|
||||
#define AMX_NO_ALIGN
|
||||
#endif
|
||||
|
||||
|
||||
#if defined __GNUC__
|
||||
#define PACKED __attribute__((packed))
|
||||
#else
|
||||
#define PACKED
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined AMX_NO_ALIGN
|
||||
#if defined __linux__
|
||||
#if defined LINUX || defined __FreeBSD__
|
||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||
#elif defined MACOS && defined __MWERKS__
|
||||
#pragma options align=mac68k
|
||||
#else
|
||||
#pragma pack(push)
|
||||
#pragma pack(1) /* structures must be packed (byte-aligned) */
|
||||
@ -175,7 +199,7 @@ typedef struct {
|
||||
* fields are valid at all times; many fields are cached in local variables.
|
||||
*/
|
||||
typedef struct tagAMX {
|
||||
unsigned char _FAR *base PACKED; /* points to the AMX header ("amxhdr") plus the code, optionally also the data */
|
||||
unsigned char _FAR *base PACKED; /* points to the AMX header plus the code, optionally also the data */
|
||||
unsigned char _FAR *data PACKED; /* points to separate data+stack+heap, may be NULL */
|
||||
AMX_CALLBACK callback PACKED;
|
||||
AMX_DEBUG debug PACKED; /* debug callback */
|
||||
@ -187,28 +211,25 @@ typedef struct tagAMX {
|
||||
cell stk PACKED; /* stack pointer: relative to base + amxhdr->dat */
|
||||
cell stp PACKED; /* top of the stack: relative to base + amxhdr->dat */
|
||||
int flags PACKED; /* current status, see amx_Flags() */
|
||||
/* for assertions and debug hook */
|
||||
cell curline PACKED;
|
||||
cell curfile PACKED;
|
||||
int dbgcode PACKED;
|
||||
cell dbgaddr PACKED;
|
||||
cell dbgparam PACKED;
|
||||
char _FAR *dbgname PACKED;
|
||||
/* user data */
|
||||
long usertags[AMX_USERNUM] PACKED;
|
||||
//okay userdata[3] in AMX Mod X is for the CPlugin * pointer
|
||||
//we're also gonna set userdata[2] to a special debug structure
|
||||
void _FAR *userdata[AMX_USERNUM] PACKED;
|
||||
/* native functions can raise an error */
|
||||
int error PACKED;
|
||||
/* passing parameters requires a "count" field */
|
||||
int paramcount;
|
||||
/* the sleep opcode needs to store the full AMX status */
|
||||
cell pri PACKED;
|
||||
cell alt PACKED;
|
||||
cell reset_stk PACKED;
|
||||
cell reset_hea PACKED;
|
||||
cell sysreq_d PACKED; /* relocated address/value for the SYSREQ.D opcode */
|
||||
/* support variables for the JIT */
|
||||
int reloc_size PACKED; /* required temporary buffer for relocations */
|
||||
long code_size PACKED; /* estimated memory footprint of the native code */
|
||||
} AMX;
|
||||
/* support variables for the JIT */
|
||||
int reloc_size PACKED; /* required temporary buffer for relocations */
|
||||
long code_size PACKED; /* estimated memory footprint of the native code */
|
||||
} PACKED AMX;
|
||||
|
||||
enum {
|
||||
AMX_ERR_NONE,
|
||||
@ -225,6 +246,7 @@ enum {
|
||||
AMX_ERR_NATIVE, /* native function failed */
|
||||
AMX_ERR_DIVIDE, /* divide by zero */
|
||||
AMX_ERR_SLEEP, /* go into sleepmode - code can be restarted */
|
||||
AMX_ERR_INVSTATE, /* invalid state for this access */
|
||||
|
||||
AMX_ERR_MEMORY = 16, /* out of memory */
|
||||
AMX_ERR_FORMAT, /* invalid file format */
|
||||
|
@ -5,12 +5,12 @@
|
||||
|
||||
// Module info
|
||||
#define MODULE_NAME "nVault"
|
||||
#define MODULE_VERSION "1.02"
|
||||
#define MODULE_VERSION "1.50"
|
||||
#define MODULE_AUTHOR "AMX Mod X Dev Team"
|
||||
#define MODULE_URL "http://www.amxmodx.org/"
|
||||
#define MODULE_LOGTAG "nVault"
|
||||
// If you want the module not to be reloaded on mapchange, remove / comment out the next line
|
||||
#define MODULE_RELOAD_ON_MAPCHANGE
|
||||
//#define MODULE_RELOAD_ON_MAPCHANGE
|
||||
|
||||
#ifdef __DATE__
|
||||
#define MODULE_DATE __DATE__
|
||||
@ -19,7 +19,7 @@
|
||||
#endif // __DATE__
|
||||
|
||||
// metamod plugin?
|
||||
// #define USE_METAMOD
|
||||
#define USE_METAMOD
|
||||
|
||||
// - AMXX Init functions
|
||||
// Also consider using FN_META_*
|
||||
|
Reference in New Issue
Block a user