Added pseudo dynamic array natives.
Changed some of the "..." tags to "any".
This commit is contained in:
parent
bfe1ff6e15
commit
d563ecb060
|
@ -20,7 +20,7 @@ OBJECTS = meta_api.cpp CFile.cpp CVault.cpp vault.cpp float.cpp file.cpp modules
|
|||
amxxfile.cpp CLang.cpp md5.cpp emsg.cpp CForward.cpp CPlugin.cpp CModule.cpp \
|
||||
CMenu.cpp util.cpp amx.cpp amxdbg.cpp natives.cpp newmenus.cpp debugger.cpp \
|
||||
optimizer.cpp format.cpp messages.cpp libraries.cpp vector.cpp sorting.cpp \
|
||||
amxmod_compat.cpp nongpl_matches.cpp CFlagManager.cpp
|
||||
amxmod_compat.cpp nongpl_matches.cpp CFlagManager.cpp datastructs.cpp
|
||||
|
||||
LINK = -lgcc -static-libgcc
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ extern AMX_NATIVE_INFO vault_Natives[];
|
|||
extern AMX_NATIVE_INFO msg_Natives[];
|
||||
extern AMX_NATIVE_INFO vector_Natives[];
|
||||
extern AMX_NATIVE_INFO g_SortNatives[];
|
||||
extern AMX_NATIVE_INFO g_DataStructNatives[];
|
||||
|
||||
#ifndef __linux__
|
||||
#define DLLOAD(path) (DLHANDLE)LoadLibrary(path)
|
||||
|
|
607
amxmodx/datastructs.cpp
Normal file
607
amxmodx/datastructs.cpp
Normal file
|
@ -0,0 +1,607 @@
|
|||
/* 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.
|
||||
*/
|
||||
|
||||
#include "amxmodx.h"
|
||||
#include "datastructs.h"
|
||||
|
||||
|
||||
// Note: All handles start at 1. 0 and below are invalid handles.
|
||||
// This way, a plugin that doesn't initialize a vector or
|
||||
// string will not be able to modify another plugin's data
|
||||
// on accident.
|
||||
CVector<CellVector*> VectorHolder;
|
||||
|
||||
|
||||
// Array:ArrayCreate(cellsize=1, reserved=32);
|
||||
static cell AMX_NATIVE_CALL ArrayCreate(AMX* amx, cell* params)
|
||||
{
|
||||
// params[1] (cellsize) is how big in cells each element is.
|
||||
// this MUST be greater than 0!
|
||||
int cellsize=params[1];
|
||||
|
||||
// params[2] (reserved) is how many elements to allocate
|
||||
// immediately when the list is created.
|
||||
// this MUST be greater than 0!
|
||||
int reserved=params[2];
|
||||
|
||||
if (cellsize<=0)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array size (%d)", cellsize);
|
||||
return -1;
|
||||
}
|
||||
if (reserved<=0)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid reserved size (%d)", reserved);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Scan through the vector list to see if any are NULL.
|
||||
// NULL means the vector was previously destroyed.
|
||||
for (unsigned int i=0; i < VectorHolder.size(); ++i)
|
||||
{
|
||||
if (VectorHolder[i]==NULL)
|
||||
{
|
||||
VectorHolder[i]=new CellVector(cellsize);
|
||||
VectorHolder[i]->Grow(reserved);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// None are NULL, create a new vector
|
||||
CellVector* NewVector=new CellVector(cellsize);
|
||||
NewVector->Grow(reserved);
|
||||
|
||||
VectorHolder.push_back(NewVector);
|
||||
|
||||
return VectorHolder.size();
|
||||
}
|
||||
// ArrayClear(Array:which)
|
||||
static cell AMX_NATIVE_CALL ArrayClear(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->Clear();
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArraySize(Array:which)
|
||||
static cell AMX_NATIVE_CALL ArraySize(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return vec->Size();
|
||||
}
|
||||
// ArrayGetArray(Array:which, item, any:output[]);
|
||||
static cell AMX_NATIVE_CALL ArrayGetArray(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->GetArray(params[2],get_amxaddr(amx, params[3]))!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cellvector handle provided (%d:%d:%d)", params[1], params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayGetCell(Array:which, item, any:&output);
|
||||
static cell AMX_NATIVE_CALL ArrayGetCell(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->GetCell(params[2],get_amxaddr(amx, params[3]))!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cellvector handle provided (%d:%d:%d)", params[1], params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayGetString(Array:which, item, any:output[], size);
|
||||
static cell AMX_NATIVE_CALL ArrayGetString(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->GetString(params[2],get_amxaddr(amx, params[3]),params[4])!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cellvector handle provided (%d:%d:%d)", params[1], params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArraySetArray(Array:which, item, any:output[]);
|
||||
static cell AMX_NATIVE_CALL ArraySetArray(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->SetArray(params[2],get_amxaddr(amx, params[3]))!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cellvector handle provided (%d:%d:%d)", params[1], params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArraySetCell(Array:which, item, any:&output);
|
||||
static cell AMX_NATIVE_CALL ArraySetCell(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->SetCell(params[2], params[3])!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cellvector handle provided (%d:%d:%d)", params[1], params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArraySetString(Array:which, item, any:output[]);
|
||||
static cell AMX_NATIVE_CALL ArraySetString(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->SetString(params[2],get_amxaddr(amx, params[3]))!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid cellvector handle provided (%d:%d:%d)", params[1], params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayPushArray(Array:which, any:output[]);
|
||||
static cell AMX_NATIVE_CALL ArrayPushArray(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetArray(vec->Push(),get_amxaddr(amx, params[2]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayPushCell(Array:which, &any:output);
|
||||
static cell AMX_NATIVE_CALL ArrayPushCell(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetCell(vec->Push(), params[2]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayPushString(Array:which, any:output[]);
|
||||
static cell AMX_NATIVE_CALL ArrayPushString(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec==NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetString(vec->Push(),get_amxaddr(amx, params[2]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
static cell AMX_NATIVE_CALL ArrayGetStringHandle(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (vec == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
cell* ptr=vec->GetCellPointer(params[2]);
|
||||
|
||||
if (ptr == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return reinterpret_cast<cell>(ptr);
|
||||
|
||||
}
|
||||
// ArrayInsertArrayAfter(Array:which, item, const value[])
|
||||
static cell AMX_NATIVE_CALL ArrayInsertArrayAfter(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int item=params[2]+1;
|
||||
|
||||
if (vec->ShiftUpFrom(item)!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayAfter (%d:%d)", params[1], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetArray(item, get_amxaddr(amx, params[3]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayInsertCellAfter(Array:which, item, value[])
|
||||
static cell AMX_NATIVE_CALL ArrayInsertCellAfter(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int item=params[2]+1;
|
||||
|
||||
if (vec->ShiftUpFrom(item)!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellAfter (%d:%d)", params[1], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetCell(item, params[3]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayInsertStringAfter(Array:which, item, const value[])
|
||||
static cell AMX_NATIVE_CALL ArrayInsertStringAfter(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int item=params[2]+1;
|
||||
|
||||
if (vec->ShiftUpFrom(item)!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringAfter (%d:%d)", params[1], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetString(item, get_amxaddr(amx, params[3]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayInsertArrayBefore(Array:which, item, const value[])
|
||||
static cell AMX_NATIVE_CALL ArrayInsertArrayBefore(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int item=params[2];
|
||||
|
||||
if (item==vec->Size())
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayBefore (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
if (vec->ShiftUpFrom(item)!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertArrayBefore (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetArray(item, get_amxaddr(amx, params[3]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayInsertCellBefore(Array:which, item, const value)
|
||||
static cell AMX_NATIVE_CALL ArrayInsertCellBefore(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int item=params[2];
|
||||
|
||||
if (item==vec->Size())
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellBefore (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
if (vec->ShiftUpFrom(item)!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertCellBefore (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetCell(item, params[3]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
// ArrayInsertStringBefore(Array:which, item, const value[])
|
||||
static cell AMX_NATIVE_CALL ArrayInsertStringBefore(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int item=params[2];
|
||||
|
||||
if (item==vec->Size())
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringBefore (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
if (vec->ShiftUpFrom(item)!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayInsertStringBefore (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
vec->SetString(item, get_amxaddr(amx, params[3]));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ArraySwap(Array:which, item1, item2)
|
||||
static cell AMX_NATIVE_CALL ArraySwap(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (vec->Swap(params[2], params[3])!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArraySwap (%d , %d:%d)",params[2], params[3], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ArrayDeleteItem(Array:which, item);
|
||||
static cell AMX_NATIVE_CALL ArrayDeleteItem(AMX* amx, cell* params)
|
||||
{
|
||||
CellVector* vec=HandleToVector(amx, params[1]);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vec->Delete(params[2])!=1)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid item specified in ArrayDeleteItem (%d:%d)", params[2], vec->Size());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// ArrayDestroy(Array:&which)
|
||||
static cell AMX_NATIVE_CALL ArrayDestroy(AMX* amx, cell* params)
|
||||
{
|
||||
// byref the handle here so we can zero it out after destroying
|
||||
// this way they cannot accidentally reuse it
|
||||
cell* handle=get_amxaddr(amx,params[1]);
|
||||
CellVector* vec=HandleToVector(amx, *handle);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete vec;
|
||||
|
||||
VectorHolder[*handle-1]=NULL;
|
||||
|
||||
*handle=0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
typedef struct ArraySort_s
|
||||
{
|
||||
int handle;
|
||||
int forward;
|
||||
cell data;
|
||||
cell size;
|
||||
|
||||
} ArraySort_t;
|
||||
|
||||
static CStack<ArraySort_t *> ArraySortStack;
|
||||
|
||||
int SortArrayList(const void *itema, const void *itemb)
|
||||
{
|
||||
ArraySort_t *Info = ArraySortStack.front();
|
||||
|
||||
return executeForwards(Info->forward, Info->handle, *((int *)itema), *((int *)itemb), Info->data, Info->size);
|
||||
|
||||
}
|
||||
// native ArraySort(Array:array, const comparefunc[], data[]="", data_size=0);
|
||||
static cell AMX_NATIVE_CALL ArraySort(AMX* amx, cell* params)
|
||||
{
|
||||
int handle=params[1];
|
||||
CellVector* vec=HandleToVector(amx, handle);
|
||||
|
||||
if (!vec)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This is kind of a cheating way to go about this but...
|
||||
// Create an array of integers as big as however many elements are in the vector.
|
||||
// Pass that array to qsort
|
||||
// After the array is sorted out, then create a NEW cellvector
|
||||
// and copy in the old data in the order of what was sorted
|
||||
int len;
|
||||
char* FuncName=get_amxstring(amx, params[2], 0, len);
|
||||
// MySortFunc(Array:array, item1, item2, const data[], data_size)
|
||||
int Forward = registerSPForwardByName(amx, FuncName, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
|
||||
if (Forward < 0)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "The public function \"%s\" was not found.", FuncName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int *IntList=new int[vec->Size()];
|
||||
|
||||
for (int i=0; i< vec->Size(); i++)
|
||||
{
|
||||
IntList[i]=i;
|
||||
}
|
||||
|
||||
ArraySort_t *Info=new ArraySort_t;
|
||||
|
||||
Info->handle=handle;
|
||||
Info->forward=Forward;
|
||||
Info->data=params[3];
|
||||
Info->size=params[4];
|
||||
|
||||
ArraySortStack.push(Info);
|
||||
qsort(IntList, vec->Size(), sizeof(int), SortArrayList);
|
||||
ArraySortStack.pop();
|
||||
|
||||
CellVector* newvec=new CellVector(vec->GetCellCount());
|
||||
|
||||
// Set the new vector's values
|
||||
for (int i=0; i< vec->Size(); i++)
|
||||
{
|
||||
if (newvec->SetArray(newvec->Push(), vec->GetCellPointer(IntList[i]))!=1)
|
||||
{
|
||||
// This should never happen..
|
||||
LogError(amx, AMX_ERR_NATIVE, "Failed to SetArray in ArraySort (i=%d, IntList=%d)",i,IntList[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the old vector
|
||||
delete vec;
|
||||
|
||||
// Now save the new vector in its handle location
|
||||
VectorHolder[handle-1]=newvec;
|
||||
|
||||
// Cleanup
|
||||
delete Info;
|
||||
delete IntList;
|
||||
|
||||
unregisterSPForward(Forward);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
AMX_NATIVE_INFO g_DataStructNatives[] =
|
||||
{
|
||||
{ "ArrayCreate", ArrayCreate },
|
||||
{ "ArrayClear", ArrayClear },
|
||||
{ "ArraySize", ArraySize },
|
||||
{ "ArrayGetArray", ArrayGetArray },
|
||||
{ "ArrayGetCell", ArrayGetCell },
|
||||
{ "ArrayGetString", ArrayGetString },
|
||||
{ "ArraySetArray", ArraySetArray },
|
||||
{ "ArraySetCell", ArraySetCell },
|
||||
{ "ArraySetString", ArraySetString },
|
||||
{ "ArrayPushArray", ArrayPushArray },
|
||||
{ "ArrayPushCell", ArrayPushCell },
|
||||
{ "ArrayPushString", ArrayPushString },
|
||||
{ "ArrayInsertArrayAfter", ArrayInsertArrayAfter },
|
||||
{ "ArrayInsertCellAfter", ArrayInsertCellAfter },
|
||||
{ "ArrayInsertStringAfter", ArrayInsertStringAfter },
|
||||
{ "ArrayInsertArrayBefore", ArrayInsertArrayBefore },
|
||||
{ "ArrayInsertCellBefore", ArrayInsertCellBefore },
|
||||
{ "ArrayInsertStringBefore", ArrayInsertStringBefore },
|
||||
{ "ArraySwap", ArraySwap },
|
||||
{ "ArrayDeleteItem", ArrayDeleteItem },
|
||||
{ "ArrayGetStringHandle", ArrayGetStringHandle },
|
||||
{ "ArrayDestroy", ArrayDestroy },
|
||||
{ "ArraySort", ArraySort },
|
||||
|
||||
{ NULL, NULL }
|
||||
};
|
323
amxmodx/datastructs.h
Normal file
323
amxmodx/datastructs.h
Normal file
|
@ -0,0 +1,323 @@
|
|||
/* 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 DATASTRUCTS_H
|
||||
#define DATASTRUCTS_H
|
||||
|
||||
class CellVector
|
||||
{
|
||||
private:
|
||||
cell* data; // allocated with malloc
|
||||
size_t cellcount; // how many cells per element
|
||||
size_t cursize; // current size of the vector (maximum elements)
|
||||
size_t count; // how many units of the vector are in use
|
||||
|
||||
public:
|
||||
CellVector(): data(NULL), cellcount(0), cursize(0), count(0)
|
||||
{
|
||||
};
|
||||
CellVector(int cellsize): data(NULL), cellcount(cellsize), cursize(0), count(0)
|
||||
{
|
||||
};
|
||||
~CellVector()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
};
|
||||
size_t GetCellCount()
|
||||
{
|
||||
return cellcount;
|
||||
};
|
||||
void Grow(size_t howmany)
|
||||
{
|
||||
cursize+=howmany;
|
||||
if (data)
|
||||
{
|
||||
data=(cell*)realloc(data, (sizeof(cell) * cellcount) * cursize);
|
||||
}
|
||||
else
|
||||
{
|
||||
data=(cell*)malloc((sizeof(cell) * cellcount) * cursize);
|
||||
}
|
||||
};
|
||||
void FreeUnused(void)
|
||||
{
|
||||
if (cursize != count &&
|
||||
data != NULL)
|
||||
{
|
||||
cursize=count;
|
||||
data=(cell*)realloc(data, cursize * (sizeof(cell) * cellcount));
|
||||
}
|
||||
};
|
||||
// Returns 1 on success
|
||||
// 0 on out of bounds.
|
||||
int GetArray(size_t which, cell* output)
|
||||
{
|
||||
// make sure it is in bounds.
|
||||
if (which >= count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// align output data
|
||||
cell* out=data + (cellcount * which);
|
||||
|
||||
memcpy(output, out, sizeof(cell) * cellcount);
|
||||
|
||||
return 1;
|
||||
};
|
||||
// Returns 1 on success
|
||||
// 0 on out of bounds
|
||||
int GetCell(size_t which, cell* output)
|
||||
{
|
||||
// check bounds
|
||||
if (which >= count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*output=*(data + (cellcount * which));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// Returns 1 on success
|
||||
// 0 on out of bounds
|
||||
int GetString(size_t which, cell* output, size_t size)
|
||||
{
|
||||
// check bounds
|
||||
if (which >= count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cell* out=data + (cellcount * which);
|
||||
|
||||
size_t count=cellcount;
|
||||
|
||||
while (size-- &&
|
||||
count-- &&
|
||||
(*output++=*out++)!='\0')
|
||||
/* do nothing */ ;
|
||||
|
||||
// If size is zero here, then the string was never null terminated.
|
||||
if (size==0)
|
||||
{
|
||||
*out='\0';
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
// Returns 1 on success
|
||||
// 0 on out of bounds
|
||||
int SetArray(size_t which, cell* output)
|
||||
{
|
||||
if (which >= count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// align output
|
||||
cell* out=data + (cellcount * which);
|
||||
|
||||
memcpy(out, output, sizeof(cell) * cellcount);
|
||||
|
||||
return 1;
|
||||
};
|
||||
// Returns 1 on success
|
||||
// 0 on out of bounds
|
||||
int SetCell(size_t which, cell output)
|
||||
{
|
||||
if (which >= count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// align output
|
||||
*(data + (cellcount * which))=output;
|
||||
|
||||
return 1;
|
||||
};
|
||||
// Returns 1 on success
|
||||
// 0 on out of bounds
|
||||
int SetString(size_t which, cell* output)
|
||||
{
|
||||
if (which >= count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
// align output
|
||||
cell* out=data + (cellcount * which);
|
||||
|
||||
memcpy(out, output, sizeof(cell) * cellcount);
|
||||
|
||||
// now force a null terminator on the last entry.
|
||||
out+=(cellcount - 1);
|
||||
*out='\0';
|
||||
|
||||
return 1;
|
||||
};
|
||||
int Push()
|
||||
{
|
||||
if (count >= cursize)
|
||||
{
|
||||
// Grow in 8s to cause less reallocation
|
||||
this->Grow(8);
|
||||
};
|
||||
|
||||
this->count++;
|
||||
|
||||
return this->count-1;
|
||||
};
|
||||
int Size()
|
||||
{
|
||||
return this->count;
|
||||
};
|
||||
void Clear()
|
||||
{
|
||||
free(data);
|
||||
data=(cell*)malloc(sizeof(cell) * cellcount);
|
||||
cursize=1;
|
||||
count=0;
|
||||
};
|
||||
cell* GetCellPointer(size_t which)
|
||||
{
|
||||
if (which >= count)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return data + (which * cellcount);
|
||||
};
|
||||
// Shifts all items from this item, and including this item up 1.
|
||||
int ShiftUpFrom(size_t which)
|
||||
{
|
||||
// No point shifting this.
|
||||
if (this->count < 0 ||
|
||||
which > this->count)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
// First make a new item.
|
||||
this->Push();
|
||||
|
||||
// If we got an InsertAfter(lastitem), then which will equal this->count - 1
|
||||
// all we needed to do was Push()
|
||||
if (which == this->count ||
|
||||
which == this->count - 1)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Allocate a temporary buffer to store data in
|
||||
size_t tempbuffsize=(sizeof(cell) * cellcount) * (this->count - which);
|
||||
|
||||
cell* temp=(cell*)malloc(tempbuffsize);
|
||||
|
||||
// Copy old data to temp buffer
|
||||
memcpy(temp, GetCellPointer(which), tempbuffsize);
|
||||
|
||||
// Now copy temp buffer to adjusted location
|
||||
memcpy(GetCellPointer(which+1), temp, tempbuffsize);
|
||||
|
||||
// cleanup
|
||||
free(temp);
|
||||
|
||||
return 1;
|
||||
|
||||
};
|
||||
// Shifts all items from this item, and including this item down 1.
|
||||
// This deletes the item specified.
|
||||
int Delete(size_t which)
|
||||
{
|
||||
// No point shifting this.
|
||||
if (this->count < 0 ||
|
||||
which >= this->count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (size_t i=which; i<this->count - 1; i++)
|
||||
{
|
||||
memcpy(GetCellPointer(i), GetCellPointer(i + 1), sizeof(cell) * cellcount);
|
||||
}
|
||||
this->count--;
|
||||
return 1;
|
||||
};
|
||||
int Swap(size_t item1, size_t item2)
|
||||
{
|
||||
if (item1 >= this->count ||
|
||||
item2 >= this->count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Make a temp buffer to store item2
|
||||
cell* temp=(cell*)malloc(sizeof(cell) * cellcount);
|
||||
memcpy(temp, GetCellPointer(item2), sizeof(cell) * cellcount);
|
||||
|
||||
// copy item1 to item2
|
||||
memcpy(GetCellPointer(item2), GetCellPointer(item1), sizeof(cell) * cellcount);
|
||||
|
||||
// copy item2 to item1
|
||||
memcpy(GetCellPointer(item1), temp, sizeof(cell) * cellcount);
|
||||
|
||||
// Cleanup
|
||||
free(temp);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
extern CVector<CellVector*> VectorHolder;
|
||||
|
||||
|
||||
inline CellVector* HandleToVector(AMX* amx, int handle)
|
||||
{
|
||||
if (handle <= 0 ||
|
||||
handle > (int)VectorHolder.size())
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", handle);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CellVector* ret=VectorHolder[handle-1];
|
||||
|
||||
if (ret == NULL)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid array handle provided (%d)", handle);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
|
@ -1,5 +1,6 @@
|
|||
#include "amxmodx.h"
|
||||
#include "format.h"
|
||||
#include "datastructs.h"
|
||||
#include "amxmod_compat.h"
|
||||
|
||||
//Adapted from Quake3's vsprintf
|
||||
|
@ -494,6 +495,21 @@ reswitch:
|
|||
AddHex(&buf_p, llen, static_cast<unsigned int>(*get_amxaddr(amx, params[arg])), width, flags);
|
||||
arg++;
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
CHECK_ARGS(0);
|
||||
// %S is passed a pointer directly to a cell string.
|
||||
cell* ptr=reinterpret_cast<cell*>(*get_amxaddr(amx, params[arg]));
|
||||
if (!ptr)
|
||||
{
|
||||
LogError(amx, AMX_ERR_NATIVE, "Invalid vector string handle provided (%d)", *get_amxaddr(amx, params[arg]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
AddString(&buf_p, llen, ptr, width, prec);
|
||||
arg++;
|
||||
break;
|
||||
}
|
||||
case 's':
|
||||
CHECK_ARGS(0);
|
||||
if (amx->flags & AMX_FLAG_OLDFILE)
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
#include "messages.h"
|
||||
#include "amxmod_compat.h"
|
||||
|
||||
#include "datastructs.h"
|
||||
#include "CFlagManager.h"
|
||||
#include "svn_version.h"
|
||||
|
||||
|
@ -388,6 +389,12 @@ int C_Spawn(edict_t *pent)
|
|||
|
||||
FlagMan.LoadFile();
|
||||
|
||||
for (unsigned int i=0; i<VectorHolder.size(); i++)
|
||||
{
|
||||
delete VectorHolder[i];
|
||||
};
|
||||
VectorHolder.clear();
|
||||
|
||||
char map_pluginsfile_path[256];
|
||||
char configs_dir[256];
|
||||
|
||||
|
|
|
@ -578,6 +578,7 @@ int set_amxnatives(AMX* amx, char error[128])
|
|||
amx_Register(amx, msg_Natives, -1);
|
||||
amx_Register(amx, vector_Natives, -1);
|
||||
amx_Register(amx, g_SortNatives, -1);
|
||||
amx_Register(amx, g_DataStructNatives, -1);
|
||||
|
||||
if (amx->flags & AMX_FLAG_OLDFILE)
|
||||
{
|
||||
|
|
|
@ -770,6 +770,14 @@
|
|||
RelativePath="..\CVector.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\datastructs.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\datastructs.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\debugger.h"
|
||||
>
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#include <sqlx>
|
||||
#endif
|
||||
|
||||
new Vector:AdminList;
|
||||
|
||||
new AdminCount;
|
||||
|
||||
new PLUGINNAME[] = "AMX Mod X"
|
||||
|
@ -108,6 +110,11 @@ public plugin_init()
|
|||
|
||||
server_cmd("exec %s/amxx.cfg", configsDir) // Execute main configuration file
|
||||
server_cmd("exec %s/sql.cfg", configsDir)
|
||||
|
||||
// Create a vector of 5 cells to store the info.
|
||||
AdminList=vector_create(5);
|
||||
|
||||
|
||||
#if defined USING_SQL
|
||||
server_cmd("amx_sqladmins")
|
||||
#else
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <messages>
|
||||
#include <vector>
|
||||
#include <sorting>
|
||||
#include <array>
|
||||
|
||||
/* Function is called just after server activation.
|
||||
* Good place for configuration loading, commands and cvars registration. */
|
||||
|
@ -97,16 +98,16 @@ native get_localinfo(const info[],output[],len);
|
|||
native show_motd(player,const message[],const header[]="");
|
||||
|
||||
/* Sends message to player. Set index to 0 to send text globaly. */
|
||||
native client_print(index,type,const message[],{Float,Sql,Result,_}:...);
|
||||
native client_print(index,type,const message[],any:...);
|
||||
|
||||
/* Sends message to player by engine. Set index to 0 to send text globaly. */
|
||||
native engclient_print(player,type,const message[],{Float,Sql,Result,_}:...);
|
||||
native engclient_print(player,type,const message[],any:...);
|
||||
|
||||
/* Sends message to console. */
|
||||
native console_print(id,const message[],{Float,Sql,Result,_}:...);
|
||||
native console_print(id,const message[],any:...);
|
||||
|
||||
/* Sends command to console. */
|
||||
native console_cmd(id,const cmd[],{Float,Sql,Result,_}:...);
|
||||
native console_cmd(id,const cmd[],any:...);
|
||||
|
||||
/* Registers event on which a given function will be called
|
||||
* Flags:
|
||||
|
@ -141,7 +142,7 @@ native register_logevent(const function[], argsnum, ... );
|
|||
native set_hudmessage(red=200, green=100, blue=0, Float:x=-1.0, Float:y=0.35, effects=0, Float:fxtime=6.0, Float:holdtime=12.0, Float:fadeintime=0.1, Float:fadeouttime=0.2,channel=4);
|
||||
|
||||
/* Displays HUD message to given player. */
|
||||
native show_hudmessage(index,const message[],{Float,Sql,Result,_}:...);
|
||||
native show_hudmessage(index,const message[],any:...);
|
||||
|
||||
/* Displays menu. Keys have bit values (key 1 is (1<<0), key 5 is (1<<4) etc.). */
|
||||
native show_menu(index,keys,const menu[], time = -1, const title[] = "");
|
||||
|
@ -150,7 +151,7 @@ native show_menu(index,keys,const menu[], time = -1, const title[] = "");
|
|||
* When you are asking for string the array and length is needed (read_data(2,name,len)).
|
||||
* Integer is returned by function (new me = read_data(3)).
|
||||
* Float is set in second parameter (read_data(3,value)). */
|
||||
native read_data(value, {Float,Sql,Result,_}:... );
|
||||
native read_data(value, any:... );
|
||||
|
||||
/* Returns number of values in client message. */
|
||||
native read_datanum();
|
||||
|
@ -171,7 +172,7 @@ native parse_loguser(const text[], name[], nlen, &userid = -2, authid[] = "", al
|
|||
|
||||
/* Prints message to server console.
|
||||
* You may use text formating (f.e. server_print("%-32s %.2f!","hello",7.345)) */
|
||||
native server_print(const message[], {Float,Sql,Result,_}:...);
|
||||
native server_print(const message[], any:...);
|
||||
|
||||
/* Returns 1 or 0. */
|
||||
native is_map_valid(const mapname[]);
|
||||
|
@ -305,13 +306,13 @@ native user_kill(index,flag=0);
|
|||
* ... - optional parameters
|
||||
* Return value:
|
||||
* always 0 */
|
||||
native log_amx(const string[], {Float,Sql,Result,_}:...);
|
||||
native log_amx(const string[], any:...);
|
||||
|
||||
/* Sends message to standard HL logs. */
|
||||
native log_message(const message[],{Float,Sql,Result,_}:...);
|
||||
native log_message(const message[],any:...);
|
||||
|
||||
/* Sends log message to specified file. */
|
||||
native log_to_file(const file[],const message[],{Float,Sql,Result,_}:...);
|
||||
native log_to_file(const file[],const message[],any:...);
|
||||
|
||||
/* Returns number of players put in server.
|
||||
* If flag is set then also connecting are counted. */
|
||||
|
@ -367,7 +368,7 @@ native find_player(const flags[], ... );
|
|||
native remove_quotes(text[]);
|
||||
|
||||
/* Executes command on player. */
|
||||
native client_cmd(index,const command[],{Float,Sql,Result,_}:...);
|
||||
native client_cmd(index,const command[],any:...);
|
||||
|
||||
/* This is an emulation of a client command (commands aren't send to client!).
|
||||
* It allows to execute some commands on players and bots.
|
||||
|
@ -376,7 +377,7 @@ native client_cmd(index,const command[],{Float,Sql,Result,_}:...);
|
|||
native engclient_cmd(index,const command[],const arg1[]="",const arg2[]="");
|
||||
|
||||
/* Executes command on a server console. */
|
||||
native server_cmd(const command[],{Float,Sql,Result,_}:...);
|
||||
native server_cmd(const command[],any:...);
|
||||
|
||||
/* Sets a cvar to given value. */
|
||||
native set_cvar_string(const cvar[],const value[]);
|
||||
|
@ -991,7 +992,7 @@ native CreateHudSyncObj(num=0, ...);
|
|||
* You must use set_hudmessage, although the channel parameter is
|
||||
* entirely ignored.
|
||||
*/
|
||||
native ShowSyncHudMsg(target, syncObj, const fmt[], {Float,Sql,Result,_}:...);
|
||||
native ShowSyncHudMsg(target, syncObj, const fmt[], any:...);
|
||||
|
||||
/**
|
||||
* Clears the display on a HudSync Object. This is essentially the same
|
||||
|
|
250
plugins/include/array.inc
Normal file
250
plugins/include/array.inc
Normal file
|
@ -0,0 +1,250 @@
|
|||
#if defined _array_included
|
||||
#endinput
|
||||
#endif
|
||||
|
||||
#define _array_included
|
||||
|
||||
/**
|
||||
* These arrays are intended to be used for a form of global storage without
|
||||
* requiring a #define that needs to be increased each time a person needs more
|
||||
* storage.
|
||||
* These are not designed to be used as a replacement for normal arrays, as
|
||||
* normal arrays are faster and should be used whenever possible.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a handle to a dynamically sized array.
|
||||
* It is very important that the cellsize you provide matches up with the buffer sizes
|
||||
* that you pass with subsequent Array{Get,Set,Push} calls.
|
||||
*
|
||||
* @param cellsize How many cells each entry in the array is.
|
||||
* @param reserved How many blank entries are created immediately when the array is created. These entries are not valid to read from until called with ArraySet.
|
||||
* @return Handle to the array.
|
||||
*/
|
||||
native Array:ArrayCreate(cellsize=1, reserved=32);
|
||||
|
||||
/**
|
||||
* Clears all entries from the array.
|
||||
*
|
||||
* @param which The array to clear.
|
||||
* @return 1 on success, 0 on failure.
|
||||
*/
|
||||
native ArrayClear(Array:which);
|
||||
|
||||
/**
|
||||
* Returns the number of elements in the array.
|
||||
*
|
||||
* @param which The array to check.
|
||||
* @return How many elements are in the array.
|
||||
*/
|
||||
native ArraySize(Array:which);
|
||||
|
||||
/**
|
||||
* Returns data within an array.
|
||||
* Make sure the output buffer matches the size the array was created with!
|
||||
*
|
||||
* @param which The array to retrieve the item from.
|
||||
* @param item The item to retrieve (zero-based).
|
||||
* @param output The output buffer to write.
|
||||
*/
|
||||
native ArrayGetArray(Array:which, item, any:output[]);
|
||||
|
||||
/**
|
||||
* Returns a single cell of data from an array.
|
||||
* Use this only with arrays that were created with a cellsize of 1!
|
||||
*
|
||||
* @param which The array to retrieve the item from.
|
||||
* @param item The item to retrieve (zero-based).
|
||||
* @param output The variable to store the value in.
|
||||
*/
|
||||
native ArrayGetCell(Array:which, item, &any:output);
|
||||
|
||||
/**
|
||||
* Returns a string value from an array.
|
||||
*
|
||||
* @param which The array to retrieve the item from.
|
||||
* @param item The item to retrieve (zero-based).
|
||||
* @param output The variable to store the value in.
|
||||
* @param size Character size of the output buffer.
|
||||
*/
|
||||
native ArrayGetString(Array:which, item, output[], size);
|
||||
|
||||
/**
|
||||
* Sets an item's data with that of a local buffer.
|
||||
* The buffer size must match what the cellsize that the array was created with!
|
||||
* The item must already exist, use ArrayPushArray to create a new item within the array.
|
||||
*
|
||||
* @param which The array to set the item from within.
|
||||
* @param item The item to set (zero-based).
|
||||
* @param input The input buffer to store.
|
||||
*/
|
||||
native ArraySetArray(Array:which, item, const any:input[]);
|
||||
|
||||
/**
|
||||
* Sets an array's single cell value. Use this only on array that were created with a cellsize of 1!
|
||||
* The item must already exist, use ArrayPushCell to create a new item within the array.
|
||||
*
|
||||
* @param which The array to set the item from within.
|
||||
* @param item The item to set (zero-based).
|
||||
* @param input The value to set.
|
||||
*/
|
||||
native ArraySetCell(Array:which, item, any:input);
|
||||
|
||||
/**
|
||||
* Sets a string value from an array.
|
||||
* The stored string will be truncated if it is longer than the cellsize the array was created with!
|
||||
* The item must already exist, use ArrayPushString to create a new item within the array.
|
||||
*
|
||||
* @param which The array to set the item from within.
|
||||
* @param item The item to set (zero-based).
|
||||
* @param input The string to set the item as.
|
||||
*/
|
||||
native ArraySetString(Array:which, item, const input[]);
|
||||
|
||||
/**
|
||||
* Creates a new item at the end of the array and sets its data with that of a local buffer.
|
||||
* The buffer size must match what the cellsize that the array was created with!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param input The input buffer to store.
|
||||
*/
|
||||
native ArrayPushArray(Array:which, const any:input[]);
|
||||
|
||||
/**
|
||||
* Creates a new item and sets the array's single cell value.
|
||||
* Use this only on array that were created with a cellsize of 1!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param input The value to set.
|
||||
*/
|
||||
native ArrayPushCell(Array:which, any:input);
|
||||
|
||||
/**
|
||||
* Creates a new element in the array and sets its value to the input buffer.
|
||||
* The stored string will be truncated if it is longer than the cellsize the array was created with!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param input The string to set the item as.
|
||||
*/
|
||||
native ArrayPushString(Array:which, const input[]);
|
||||
|
||||
/**
|
||||
* Inserts an item after the selected item. All items beyond it get shifted up 1 space.
|
||||
* The buffer size must match what the cellsize that the array was created with!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param item The item to insert after.
|
||||
* @param input The input buffer to store.
|
||||
*/
|
||||
native ArrayInsertArrayAfter(Array:which, item, const any:input[]);
|
||||
|
||||
/**
|
||||
* Inserts an item after the selected item. All items beyond it get shifted up 1 space.
|
||||
* Use this only on an array that was created with a cellsize of 1!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param item The item to insert after.
|
||||
* @param input The value to set.
|
||||
*/
|
||||
native ArrayInsertCellAfter(Array:which, item, any:input);
|
||||
|
||||
/**
|
||||
* Inserts an item after the selected item. All items beyond it get shifted up 1 space.
|
||||
* The stored string will be truncated if it is longer than the cellsize the array was created with!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param item The item to insert after.
|
||||
* @param input The value to set.
|
||||
*/
|
||||
native ArrayInsertStringAfter(Array:which, item, const input[]);
|
||||
|
||||
/**
|
||||
* Inserts an item before the selected item. All items beyond it, and the selected item get shifted up 1 space.
|
||||
* The buffer size must match what the cellsize that the array was created with!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param item The item to insert before.
|
||||
* @param input The input buffer to store.
|
||||
*/
|
||||
native ArrayInsertArrayBefore(Array:which, item, const any:input[]);
|
||||
|
||||
/**
|
||||
* Inserts an item before the selected item. All items beyond it, and the selected item get shifted up 1 space.
|
||||
* Use this only on an array that was created with a cellsize of 1!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param item The item to insert after.
|
||||
* @param input The value to set.
|
||||
*/
|
||||
native ArrayInsertCellBefore(Array:which, item, const any:input);
|
||||
|
||||
/**
|
||||
* Inserts an item before the selected item. All items beyond it, and the selected item get shifted up 1 space.
|
||||
* The stored string will be truncated if it is longer than the cellsize the array was created with!
|
||||
*
|
||||
* @param which The array to add the item to.
|
||||
* @param item The item to insert before.
|
||||
* @param input The value to set.
|
||||
*/
|
||||
native ArrayInsertStringBefore(Array:which, item, const input[]);
|
||||
|
||||
/**
|
||||
* Swaps the position of two items.
|
||||
*
|
||||
* @param which The array that contains the items.
|
||||
* @param item1 The first item to swap.
|
||||
* @param item2 The second item to swap.
|
||||
*/
|
||||
native ArraySwap(Array:which, item1, item2);
|
||||
|
||||
/**
|
||||
* Deletes an item from the array. All items beyond it get shifted down 1 space.
|
||||
*
|
||||
* @param which The array that contains the item to delete.
|
||||
* @param item The item to delete.
|
||||
*/
|
||||
native ArrayDeleteItem(Array:which, item);
|
||||
|
||||
/**
|
||||
* Creates a handle that is passable to a format compliant routine for printing as a string (with the %S parameter).
|
||||
* It is suggested to pass the function directly as a parameter to the format routine.
|
||||
* The array contents must be a null-terminated string!
|
||||
*
|
||||
* An example usage: client_print(id, print_chat, "%S", ArrayGetStringHandle(MessageArray, i));
|
||||
*
|
||||
* @param which The array the string is stored in.
|
||||
* @param item Which item to print the string value of.
|
||||
* @return Handle to the item directly. Do not use or save stale handles.
|
||||
*/
|
||||
native DoNotUse:ArrayGetStringHandle(Array:which, item);
|
||||
|
||||
/**
|
||||
* Destroys the array, and resets the handle to 0 to prevent accidental usage after it is destroyed.
|
||||
*
|
||||
* @param which The array to destroy.
|
||||
*/
|
||||
native ArrayDestroy(&Array:which);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Similar to sorting.inc's CustomSort.
|
||||
* The sorting algorithm then uses your comparison function to sort the data.
|
||||
* The function is called in the following manner:
|
||||
*
|
||||
* public MySortFunc(Array:array, item1, item2, const data[], data_size)
|
||||
*
|
||||
* array - Array handle in its current un-sorted state.
|
||||
* item1, item2 - Current item pair being compared
|
||||
* data[] - Extra data array you passed to the sort func.
|
||||
* data_size - Size of extra data you passed to the sort func.
|
||||
*
|
||||
* Your function should return:
|
||||
* -1 if item1 should go before item2
|
||||
* 0 if item1 and item2 are equal
|
||||
* 1 if item1 should go after item2
|
||||
* Note that the parameters after item2 are all optional and you do not need to specify them.
|
||||
*
|
||||
* Note that unlike the sorting.inc versions, the array passed to the callback is not in mid-sorted state.
|
||||
*/
|
||||
native ArraySort(Array:array, const comparefunc[], data[]="", data_size=0);
|
|
@ -22,7 +22,7 @@
|
|||
#pragma library engine
|
||||
#endif
|
||||
|
||||
native traceresult(type,{Float,Sql,Result,_}:...);
|
||||
native traceresult(type,any:...);
|
||||
|
||||
/* Registers a client impulse to a function. Function is passed the ID of the user. */
|
||||
native register_impulse(impulse, const function[]);
|
||||
|
@ -39,7 +39,7 @@ native register_think(const Classname[], const function[]);
|
|||
*/
|
||||
|
||||
/* Precaches an event. */
|
||||
native precache_event(type, const Name[], {Float,Sql,Result,_}:...);
|
||||
native precache_event(type, const Name[], any:...);
|
||||
|
||||
/* set/get a user's speak flags */
|
||||
native set_speak(iIndex, iSpeakFlags);
|
||||
|
@ -174,11 +174,11 @@ native playback_event(flags,invoker,eventindex,Float:delay,const Float:origin[3]
|
|||
/* Gets parameters sent from CmdStart.
|
||||
Note that you will receive modified values if any other plugin have
|
||||
changed them. */
|
||||
native get_usercmd(type,{Float,Sql,Result,_}:...);
|
||||
native get_usercmd(type,any:...);
|
||||
|
||||
/* Sets the parameters sent from CmdStart.
|
||||
Note that your changes will be seen by any other plugin doing get_usercmd() */
|
||||
native set_usercmd(type,{Float,Sql,Result,_}:...);
|
||||
native set_usercmd(type,any:...);
|
||||
|
||||
/* Converts a string offset into a real string. Some of the forwards in fakemeta
|
||||
uses string offsets. (FM_CreateNamedEntity) */
|
||||
|
|
|
@ -31,10 +31,10 @@
|
|||
* new ptr, classname[32]
|
||||
* pev(entid, pev_classname, ptr, classname, 31)
|
||||
*/
|
||||
native pev(_index,_value,{Float,Sql,Result,_}:...);
|
||||
native pev(_index,_value,any:...);
|
||||
|
||||
/* Sets entvar data for an entity. Use the pev_* enum */
|
||||
native set_pev(_index,_value,{Float,Sql,Result,_}:...);
|
||||
native set_pev(_index,_value,any:...);
|
||||
|
||||
/* returns 0 if ent is invalid, >0 if valid
|
||||
* (1 == valid, 2 == valid+pvPrivateData valid)
|
||||
|
@ -50,7 +50,7 @@ native pev_valid(entindex);
|
|||
* new ptr = pev(id, pev_viewmodel)
|
||||
* global_get(glb_pStringBase, ptr, model, 127)
|
||||
*/
|
||||
native global_get(_value, {Float,Sql,Result,_}:...);
|
||||
native global_get(_value, any:...);
|
||||
|
||||
/* Returns an integer from private data. _linuxdiff is added into the _Offset if it's used on a linux server. */
|
||||
native get_pdata_int(_index,_Offset,_linuxdiff=5);
|
||||
|
@ -77,7 +77,7 @@ native register_forward(_forwardType,const _function[],_post=0);
|
|||
native unregister_forward(_forwardType, registerId, post=0);
|
||||
|
||||
/* Returns data for metamod */
|
||||
native forward_return(type,{Float,Sql,Result,_}:...);
|
||||
native forward_return(type,any:...);
|
||||
|
||||
/* Returns the original return value of an engine function.
|
||||
* This is only valid in forwards that were registered as post.
|
||||
|
@ -89,7 +89,7 @@ native forward_return(type,{Float,Sql,Result,_}:...);
|
|||
native get_orig_retval({Float,_}:...);
|
||||
|
||||
native engfunc(type,{Float,Sql,Result,AlertType,_}:...);
|
||||
native dllfunc(type,{Float,Sql,Result,_}:...);
|
||||
native dllfunc(type,any:...);
|
||||
|
||||
//only use this with functions that pass a Trace
|
||||
// get: zero extra params - return int, one extra param = byref float or vector
|
||||
|
|
|
@ -83,7 +83,7 @@ native fgets(file, buffer[], maxlength);
|
|||
native fputs(file, const text[]);
|
||||
|
||||
//Writes a line to the file
|
||||
native fprintf(file, const fmt[], {Float,Sql,Result,_}:...);
|
||||
native fprintf(file, const fmt[], any:...);
|
||||
|
||||
//Sets the current position in a file (see SEEK_ values above)
|
||||
native fseek(file, position, start);
|
||||
|
@ -97,7 +97,7 @@ native fputc(file, data);
|
|||
native fungetc(file, data);
|
||||
|
||||
//Return the size of a file
|
||||
native filesize(const filename[], {Float,Sql,Result,_}:...);
|
||||
native filesize(const filename[], any:...);
|
||||
|
||||
//Attempts to remove a directory.
|
||||
//Note that you cannot remove a directory that has files on most
|
||||
|
|
|
@ -18,7 +18,7 @@ stock is_entity(id)
|
|||
return is_valid_ent(id);
|
||||
|
||||
/* The end of the native is buffered incase the plugin is including an NS_VERSION (no longer supported), ignore it */
|
||||
stock get_build(classname[], value, number=0,{Float,Sql,Result,_}:...)
|
||||
stock get_build(classname[], value, number=0,any:...)
|
||||
return ns_get_build(classname, value, number);
|
||||
|
||||
stock get_private_i(index, offset, linuxdiff=5)
|
||||
|
|
|
@ -34,7 +34,7 @@ native add(dest[],len,const src[],max=0);
|
|||
* slower, so you should using a source string that is the same as
|
||||
* the destination.
|
||||
*/
|
||||
native format(output[] ,len ,const format[] , {Float,Sql,Result,_}:...);
|
||||
native format(output[] ,len ,const format[] , any:...);
|
||||
|
||||
/* Same as format(), except does not perform a "copy back" check.
|
||||
* This means formatex() is faster, but DOES NOT ALLOW this type
|
||||
|
@ -45,7 +45,7 @@ native format(output[] ,len ,const format[] , {Float,Sql,Result,_}:...);
|
|||
* This is because the output is directly stored into "buffer",
|
||||
* rather than copied back at the end.
|
||||
*/
|
||||
native formatex(output[] ,len ,const format[] , {Float,Sql,Result,_}:...);
|
||||
native formatex(output[] ,len ,const format[] , any:...);
|
||||
|
||||
/* Replacement for format_args. Much faster and %L compatible.
|
||||
* This works exactly like vsnprintf() from C.
|
||||
|
|
456
plugins/testsuite/arraytest.sma
Normal file
456
plugins/testsuite/arraytest.sma
Normal file
|
@ -0,0 +1,456 @@
|
|||
#include <amxmodx>
|
||||
|
||||
|
||||
new __testnumber;
|
||||
new errcount;
|
||||
new __testfunc[32];
|
||||
new __testfuncnum;
|
||||
|
||||
enum TestType
|
||||
{
|
||||
TT_Equal = 0,
|
||||
TT_LessThan,
|
||||
TT_GreaterThan,
|
||||
TT_LessThanEqual,
|
||||
TT_GreaterThanEqual,
|
||||
TT_NotEqual
|
||||
};
|
||||
|
||||
new TestWords[6][] = {
|
||||
"==",
|
||||
"<",
|
||||
">",
|
||||
"<=",
|
||||
">=",
|
||||
"!="
|
||||
};
|
||||
|
||||
|
||||
|
||||
stock test(A,B=0,TestType:Type=TT_Equal)
|
||||
{
|
||||
++__testnumber;
|
||||
|
||||
new passed=0;
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case TT_Equal: if (A==B) passed=1;
|
||||
case TT_LessThan: if (A<B) passed=1;
|
||||
case TT_GreaterThan: if (A>B) passed=1;
|
||||
case TT_LessThanEqual: if (A<=B) passed=1;
|
||||
case TT_GreaterThanEqual: if (A>=B) passed=1;
|
||||
case TT_NotEqual: if (A!=B) passed=1;
|
||||
}
|
||||
|
||||
if (!passed)
|
||||
{
|
||||
log_amx("Failed test #%d (%d %s %d)",__testnumber,A,TestWords[_:Type],B);
|
||||
errcount++;
|
||||
}
|
||||
}
|
||||
stock starttests(const startfunc[])
|
||||
{
|
||||
__testnumber=0;
|
||||
errcount=0;
|
||||
__testfuncnum=1;
|
||||
server_print("Starting tests...");
|
||||
formatex(__testfunc,sizeof(__testfunc)-1,"%s",startfunc);
|
||||
|
||||
new func[32];
|
||||
formatex(func,sizeof(func)-1,"%s%d",__testfunc,__testfuncnum++);
|
||||
set_task(0.1,func);
|
||||
}
|
||||
|
||||
stock showres()
|
||||
{
|
||||
if (errcount==0)
|
||||
{
|
||||
new func[32];
|
||||
formatex(func,sizeof(func)-1,"%s%d",__testfunc,__testfuncnum++);
|
||||
if (get_func_id(func)==-1)
|
||||
{
|
||||
server_print("All tests ok!");
|
||||
}
|
||||
else
|
||||
{
|
||||
server_print("Test ok, moving on...");
|
||||
|
||||
set_task(0.1,func);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
server_print("Test failed, aborting.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public plugin_init()
|
||||
{
|
||||
register_srvcmd("arraytest","arraytest");
|
||||
}
|
||||
|
||||
public arraytest()
|
||||
{
|
||||
starttests("arraytest");
|
||||
}
|
||||
public arraytest1()
|
||||
{
|
||||
server_print("Testing 1000 iterations of 1-cell arrays...");
|
||||
|
||||
new Float:f;
|
||||
new Array:a=ArrayCreate(1);
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
f=float(i);
|
||||
ArrayPushCell(a,f);
|
||||
}
|
||||
new Float:r;
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
f=float(i);
|
||||
ArrayGetCell(a,i,r);
|
||||
|
||||
// This is normally bad for float "casting", but in this case it should be fine.
|
||||
test(_:f, _:r);
|
||||
|
||||
|
||||
// Reset with inversed values
|
||||
new g=_:f;
|
||||
g=~g;
|
||||
|
||||
ArraySetCell(a,i,g);
|
||||
|
||||
ArrayGetCell(a,i,r);
|
||||
|
||||
test(g, _:r);
|
||||
|
||||
}
|
||||
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
||||
stock bool:checkarray(const a[], const b[], size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
if (a[size]!=b[size])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
stock invarray(a[],size)
|
||||
{
|
||||
while (size--)
|
||||
{
|
||||
a[size] = ~a[size];
|
||||
}
|
||||
|
||||
}
|
||||
public arraytest2()
|
||||
{
|
||||
server_print("Testing 1000 iterations of 40-cell arrays...");
|
||||
|
||||
new Array:a=ArrayCreate(40);
|
||||
new buff[40];
|
||||
new buffb[40];
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
arrayset(buff,i,sizeof(buff));
|
||||
|
||||
ArrayPushArray(a, buff);
|
||||
}
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
arrayset(buff, i, sizeof(buff));
|
||||
|
||||
ArrayGetArray(a, i, buffb);
|
||||
|
||||
test(_:checkarray(buff,buffb,sizeof(buff)),1);
|
||||
|
||||
// Now overwrite the array with inversed value
|
||||
invarray(buff,sizeof(buff));
|
||||
|
||||
ArraySetArray(a, i, buff);
|
||||
|
||||
ArrayGetArray(a, i, buffb);
|
||||
|
||||
test(_:checkarray(buff,buffb,sizeof(buff)),1);
|
||||
}
|
||||
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
||||
public arraytest3()
|
||||
{
|
||||
server_print("Testing 1000 iterations of strings...");
|
||||
|
||||
// The string is 10 long, the string we're trying to pass is 20 long.
|
||||
|
||||
new Array:a=ArrayCreate(10);
|
||||
|
||||
new buff[20]="1234567890abcdefghi";
|
||||
new buffb[20];
|
||||
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
ArrayPushString(a, buff);
|
||||
}
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
ArrayGetString(a, i, buffb, sizeof(buffb)-1);
|
||||
|
||||
test(strcmp(buffb,"123456789"),0);
|
||||
|
||||
ArraySetString(a, i, "9876543210");
|
||||
|
||||
ArrayGetString(a, i, buffb, sizeof(buffb)-1);
|
||||
|
||||
test(strcmp(buffb,"987654321"),0);
|
||||
|
||||
buffb[0]=0;
|
||||
|
||||
formatex(buffb,sizeof(buffb)-1,"%S", ArrayGetStringHandle(a, i));
|
||||
|
||||
test(strcmp(buffb, "987654321"),0);
|
||||
}
|
||||
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
||||
|
||||
public sortcallback(Array:a, b, c)
|
||||
{
|
||||
static stra[40];
|
||||
static strb[40];
|
||||
|
||||
ArrayGetString(a, b, stra, sizeof(stra)-1);
|
||||
ArrayGetString(a, c, strb, sizeof(strb)-1);
|
||||
return strcmp(stra,strb);
|
||||
}
|
||||
public arraytest4()
|
||||
{
|
||||
server_print("Testing sorting function...");
|
||||
|
||||
new Array:a=ArrayCreate(40);
|
||||
|
||||
ArrayPushString(a, "z");
|
||||
ArrayPushString(a, "yz");
|
||||
ArrayPushString(a, "xyz");
|
||||
ArrayPushString(a, "wxyz");
|
||||
ArrayPushString(a, "vwxyz");
|
||||
ArrayPushString(a, "uvwxyz");
|
||||
ArrayPushString(a, "tuvwxyz");
|
||||
ArrayPushString(a, "stuvwxyz");
|
||||
ArrayPushString(a, "rstuvwxyz");
|
||||
ArrayPushString(a, "qrstuvwxyz");
|
||||
ArrayPushString(a, "pqrstuvwxyz");
|
||||
ArrayPushString(a, "opqrstuvwxyz");
|
||||
ArrayPushString(a, "nopqrstuvwxyz");
|
||||
ArrayPushString(a, "mnopqrstuvwxyz");
|
||||
ArrayPushString(a, "lmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "klmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "jklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "ijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "hijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "ghijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "fghijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "efghijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "defghijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "cdefghijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "bcdefghijklmnopqrstuvwxyz");
|
||||
ArrayPushString(a, "abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
new OldSize=ArraySize(a);
|
||||
|
||||
ArraySort(a, "sortcallback");
|
||||
|
||||
test(ArraySize(a),OldSize);
|
||||
|
||||
new buff[40];
|
||||
|
||||
ArrayGetString(a,0,buff,sizeof(buff)-1);
|
||||
|
||||
test(strcmp(buff,"abcdefghijklmnopqrstuvwxyz"),0);
|
||||
|
||||
ArrayGetString(a,25,buff,sizeof(buff)-1);
|
||||
|
||||
test(strcmp(buff,"z"),0);
|
||||
|
||||
|
||||
new start='a';
|
||||
|
||||
for (new i=0;i<OldSize;i++)
|
||||
{
|
||||
ArrayGetString(a,i,buff,sizeof(buff)-1)
|
||||
|
||||
test(buff[0],start++);
|
||||
}
|
||||
|
||||
showres();
|
||||
}
|
||||
public arraytest5()
|
||||
{
|
||||
server_print("Testing ArrayDeleteItem()...");
|
||||
new Array:a=ArrayCreate(1);
|
||||
|
||||
new v;
|
||||
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
ArrayPushCell(a, i);
|
||||
}
|
||||
for (new i=ArraySize(a) - 1; i>=0 ; i--)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
ArrayDeleteItem(a, i);
|
||||
}
|
||||
}
|
||||
test(ArraySize(a), 500);
|
||||
for (new i=0; i< 500; i++)
|
||||
{
|
||||
ArrayGetCell(a, i, v);
|
||||
|
||||
// All items should be incrementing odd numbers
|
||||
test(((i + 1) * 2) - 1, v);
|
||||
|
||||
// All remaining entries should be odd
|
||||
test((v & 1), 1);
|
||||
}
|
||||
ArrayDestroy(a);
|
||||
|
||||
a=ArrayCreate(1);
|
||||
// Repeat the same test, but check even numbers
|
||||
for (new i=0; i<1000; i++)
|
||||
{
|
||||
ArrayPushCell(a, i);
|
||||
}
|
||||
for (new i=ArraySize(a) - 1; i>=0 ; i--)
|
||||
{
|
||||
if (i % 2 == 1)
|
||||
{
|
||||
ArrayDeleteItem(a, i);
|
||||
}
|
||||
}
|
||||
test(ArraySize(a), 500);
|
||||
for (new i=0; i< 500; i++)
|
||||
{
|
||||
ArrayGetCell(a, i, v);
|
||||
|
||||
// All items should be incrementing even numbers
|
||||
test(((i + 1) * 2) - 2, v);
|
||||
|
||||
// All remaining entries should be even
|
||||
test((v & 1), 0);
|
||||
}
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
||||
public arraytest6()
|
||||
{
|
||||
server_print("Testing ArrayInsertCellAfter()...");
|
||||
|
||||
new Array:a=ArrayCreate(1);
|
||||
|
||||
for (new i=0; i<10;i++)
|
||||
{
|
||||
ArrayPushCell(a, i);
|
||||
new item=ArraySize(a)-1;
|
||||
for (new j=0; j<10; j++)
|
||||
{
|
||||
ArrayInsertCellAfter(a, item + j, j);
|
||||
}
|
||||
}
|
||||
|
||||
test(ArraySize(a), 110);
|
||||
|
||||
new v;
|
||||
for (new i=0; i<110; i++)
|
||||
{
|
||||
ArrayGetCell(a, i, v);
|
||||
|
||||
test(v, i / 10);
|
||||
for (new j=0; j<10; j++)
|
||||
{
|
||||
ArrayGetCell(a, ++i, v);
|
||||
test(v, j);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
||||
public arraytest7()
|
||||
{
|
||||
server_print("Testing ArrayInsertCellBefore()...");
|
||||
|
||||
new Array:a=ArrayCreate(1);
|
||||
|
||||
for (new i=0; i<10;i++)
|
||||
{
|
||||
ArrayPushCell(a, i);
|
||||
new item=ArraySize(a)-1;
|
||||
for (new j=0; j<10; j++)
|
||||
{
|
||||
ArrayInsertCellBefore(a, item, j);
|
||||
}
|
||||
}
|
||||
|
||||
test(ArraySize(a), 110);
|
||||
|
||||
new v;
|
||||
for (new i=0; i<110; i++)
|
||||
{
|
||||
for (new j=9; j>=0; j--)
|
||||
{
|
||||
ArrayGetCell(a, i++, v);
|
||||
test(v, j);
|
||||
}
|
||||
|
||||
ArrayGetCell(a, i, v);
|
||||
|
||||
test(v, (i - 10) / 10);
|
||||
}
|
||||
|
||||
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
||||
public arraytest8()
|
||||
{
|
||||
server_print("Testing ArraySwap()...");
|
||||
new Array:a=ArrayCreate(1);
|
||||
|
||||
for (new i=0; i<10; i++)
|
||||
{
|
||||
ArrayPushCell(a, i);
|
||||
}
|
||||
for (new i=0; i<5; i++)
|
||||
{
|
||||
ArraySwap(a, i, (10 - (i + 1)));
|
||||
}
|
||||
new v;
|
||||
for (new i=0; i<5; i++)
|
||||
{
|
||||
ArrayGetCell(a, i, v);
|
||||
|
||||
test(v, (10 - (i + 1)));
|
||||
}
|
||||
|
||||
ArrayDestroy(a);
|
||||
|
||||
showres();
|
||||
}
|
Loading…
Reference in New Issue
Block a user