Added pseudo dynamic array natives.
Changed some of the "..." tags to "any".
This commit is contained in:
@ -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"
|
||||
>
|
||||
|
Reference in New Issue
Block a user