mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 17:59:37 +00:00
WIP: port alien swarm and extend engine for asw
This commit is contained in:
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
_____ __ ___ __ ____ _ __
|
||||
/ ___/__ ___ _ ___ / |/ /__ ___ / /_____ __ __/ __/_______(_)__ / /_
|
||||
/ (_ / _ `/ ' \/ -_) /|_/ / _ \/ _ \/ '_/ -_) // /\ \/ __/ __/ / _ \/ __/
|
||||
\___/\_,_/_/_/_/\__/_/ /_/\___/_//_/_/\_\\__/\_, /___/\__/_/ /_/ .__/\__/
|
||||
/___/ /_/
|
||||
|
||||
See Copyright Notice in gmMachine.h
|
||||
|
||||
*/
|
||||
|
||||
#include "gmConfig.h"
|
||||
#include "gmArrayLib.h"
|
||||
#include "gmThread.h"
|
||||
#include "gmMachine.h"
|
||||
#include "gmHelpers.h"
|
||||
|
||||
// Must be last header
|
||||
#include "memdbgon.h"
|
||||
|
||||
//
|
||||
//
|
||||
// Implementation of array binding
|
||||
//
|
||||
//
|
||||
|
||||
#if GM_ARRAY_LIB
|
||||
|
||||
// Statics and globals
|
||||
gmType GM_ARRAY = GM_NULL;
|
||||
gmVariable gmUserArray::m_null;
|
||||
|
||||
|
||||
bool gmUserArray::Construct(gmMachine * a_machine, int a_size)
|
||||
{
|
||||
m_null.Nullify();
|
||||
m_array = NULL;
|
||||
m_size = 0;
|
||||
return Resize(a_machine, a_size);
|
||||
}
|
||||
|
||||
|
||||
void gmUserArray::Destruct(gmMachine * a_machine)
|
||||
{
|
||||
if(m_array)
|
||||
{
|
||||
a_machine->Sys_Free(m_array);
|
||||
m_array = NULL;
|
||||
}
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
|
||||
bool gmUserArray::Resize(gmMachine * a_machine, int a_size)
|
||||
{
|
||||
if(a_size < 0) a_size = 0;
|
||||
int copysize = (a_size > m_size) ? m_size : a_size;
|
||||
gmVariable * array = (gmVariable *) a_machine->Sys_Alloc(sizeof(gmVariable) * a_size);
|
||||
// copy contents.
|
||||
if(m_array)
|
||||
{
|
||||
memcpy(array, m_array, sizeof(gmVariable) * copysize);
|
||||
if(a_size > copysize)
|
||||
{
|
||||
memset(array + copysize, 0, sizeof(gmVariable) * (a_size - copysize));
|
||||
}
|
||||
a_machine->Sys_Free(m_array);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(array, 0, sizeof(gmVariable) * a_size);
|
||||
}
|
||||
m_array = array;
|
||||
m_size = a_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if GM_USE_INCGC
|
||||
bool gmUserArray::Trace(gmMachine * a_machine, gmGarbageCollector* a_gc, const int a_workLeftToGo, int& a_workDone)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < m_size; ++i)
|
||||
{
|
||||
if(m_array[i].IsReference())
|
||||
{
|
||||
gmObject * object = GM_MOBJECT(a_machine, m_array[i].m_value.m_ref);
|
||||
a_gc->GetNextObject(object);
|
||||
++a_workDone;
|
||||
}
|
||||
}
|
||||
|
||||
++a_workDone;
|
||||
return true;
|
||||
}
|
||||
#else //GM_USE_INCGC
|
||||
void gmUserArray::Mark(gmMachine * a_machine, gmuint32 a_mark)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < m_size; ++i)
|
||||
{
|
||||
if(m_array[i].IsReference())
|
||||
{
|
||||
gmObject * object = GM_MOBJECT(a_machine, m_array[i].m_value.m_ref);
|
||||
if(object->NeedsMark(a_mark)) object->Mark(a_machine, a_mark);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif //GM_USE_INCGC
|
||||
|
||||
|
||||
bool gmUserArray::Shift(int a_shift)
|
||||
{
|
||||
if(a_shift < 0) // shift left
|
||||
{
|
||||
a_shift = -a_shift;
|
||||
if(a_shift >= m_size)
|
||||
{
|
||||
memset(m_array, 0, m_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = m_size - a_shift;
|
||||
memmove(m_array, m_array + a_shift, sizeof(gmVariable) * size);
|
||||
memset(m_array + size, 0, sizeof(gmVariable) * a_shift);
|
||||
}
|
||||
}
|
||||
else if(a_shift > 0) // shift right
|
||||
{
|
||||
if(a_shift >= m_size)
|
||||
{
|
||||
memset(m_array, 0, m_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = m_size - a_shift;
|
||||
memmove(m_array + a_shift, m_array, sizeof(gmVariable) * size);
|
||||
memset(m_array, 0, sizeof(gmVariable) * a_shift);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int gmUserArray::Move(int a_dest, int a_src, int a_size)
|
||||
{
|
||||
int start = a_src;
|
||||
int dest = a_dest;
|
||||
int size = a_size;
|
||||
|
||||
if(start < 0)
|
||||
{
|
||||
size += start;
|
||||
dest -= start;
|
||||
start = 0;
|
||||
}
|
||||
|
||||
if(dest < 0)
|
||||
{
|
||||
size += dest;
|
||||
start -= dest;
|
||||
dest = 0;
|
||||
}
|
||||
|
||||
if(size <= 0) return 0;
|
||||
if(start >= m_size) return 0;
|
||||
if(dest >= m_size) return 0;
|
||||
if((dest + size) < 0) return 0;
|
||||
|
||||
if(start + size > m_size)
|
||||
{
|
||||
size = m_size - start;
|
||||
}
|
||||
if(dest + size > m_size)
|
||||
{
|
||||
size = m_size - dest;
|
||||
}
|
||||
if(size <= 0) return 0;
|
||||
|
||||
GM_ASSERT(dest >= 0);
|
||||
GM_ASSERT(start >= 0);
|
||||
GM_ASSERT(start + size <= m_size);
|
||||
GM_ASSERT(dest + size <= m_size);
|
||||
|
||||
memmove(m_array + dest, m_array + start, sizeof(gmVariable) * size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
gmUserArray* gmUserArray_Create(gmMachine* a_machine, int a_size)
|
||||
{
|
||||
gmUserArray * newArray = (gmUserArray *) a_machine->Sys_Alloc(sizeof(gmUserArray));
|
||||
newArray->Construct(a_machine, a_size);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
|
||||
// functions
|
||||
|
||||
static int GM_CDECL gmfArray(gmThread * a_thread) // size
|
||||
{
|
||||
GM_INT_PARAM(size, 0, 0);
|
||||
gmUserArray * array = (gmUserArray *) a_thread->GetMachine()->Sys_Alloc(sizeof(gmUserArray));
|
||||
array->Construct(a_thread->GetMachine(), size);
|
||||
a_thread->PushNewUser(array, GM_ARRAY);
|
||||
return GM_OK;
|
||||
}
|
||||
|
||||
static int GM_CDECL gmfArraySize(gmThread * a_thread) // return size
|
||||
{
|
||||
gmUserObject * arrayObject = a_thread->ThisUserObject();
|
||||
GM_ASSERT(arrayObject->m_userType == GM_ARRAY);
|
||||
if(arrayObject->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) arrayObject->m_user;
|
||||
a_thread->PushInt(array->Size());
|
||||
}
|
||||
return GM_OK;
|
||||
}
|
||||
|
||||
static int GM_CDECL gmfArrayResize(gmThread * a_thread) // size
|
||||
{
|
||||
GM_INT_PARAM(size, 0, 0);
|
||||
gmUserObject * arrayObject = a_thread->ThisUserObject();
|
||||
GM_ASSERT(arrayObject->m_userType == GM_ARRAY);
|
||||
if(arrayObject->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) arrayObject->m_user;
|
||||
array->Resize(a_thread->GetMachine(), size);
|
||||
}
|
||||
return GM_OK;
|
||||
}
|
||||
|
||||
static int GM_CDECL gmfArrayShift(gmThread * a_thread) // shift
|
||||
{
|
||||
GM_CHECK_NUM_PARAMS(1);
|
||||
GM_CHECK_INT_PARAM(shift, 0);
|
||||
|
||||
gmUserObject * arrayObject = a_thread->ThisUserObject();
|
||||
GM_ASSERT(arrayObject->m_userType == GM_ARRAY);
|
||||
if(arrayObject->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) arrayObject->m_user;
|
||||
array->Shift(shift);
|
||||
}
|
||||
return GM_OK;
|
||||
}
|
||||
|
||||
static int GM_CDECL gmfArrayMove(gmThread * a_thread) // dst, src, size
|
||||
{
|
||||
GM_CHECK_NUM_PARAMS(3);
|
||||
GM_CHECK_INT_PARAM(dst, 0);
|
||||
GM_CHECK_INT_PARAM(src, 1);
|
||||
GM_CHECK_INT_PARAM(size, 2);
|
||||
|
||||
gmUserObject * arrayObject = a_thread->ThisUserObject();
|
||||
GM_ASSERT(arrayObject->m_userType == GM_ARRAY);
|
||||
if(arrayObject->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) arrayObject->m_user;
|
||||
array->Move(dst, src, size);
|
||||
}
|
||||
return GM_OK;
|
||||
}
|
||||
|
||||
static void GM_CDECL gmArrayGetInd(gmThread * a_thread, gmVariable * a_operands)
|
||||
{
|
||||
gmUserObject * arrayObject = (gmUserObject *) GM_OBJECT(a_operands->m_value.m_ref);
|
||||
GM_ASSERT(arrayObject->m_userType == GM_ARRAY);
|
||||
gmUserArray * array = (gmUserArray *) arrayObject->m_user;
|
||||
if(a_operands[1].m_type == GM_INT)
|
||||
{
|
||||
int index = a_operands[1].m_value.m_int;
|
||||
*a_operands = array->GetAt(index);
|
||||
return;
|
||||
}
|
||||
a_operands->Nullify();
|
||||
}
|
||||
|
||||
static void GM_CDECL gmArraySetInd(gmThread * a_thread, gmVariable * a_operands)
|
||||
{
|
||||
gmUserObject * arrayObject = (gmUserObject *) GM_OBJECT(a_operands->m_value.m_ref);
|
||||
GM_ASSERT(arrayObject->m_userType == GM_ARRAY);
|
||||
gmUserArray * array = (gmUserArray *) arrayObject->m_user;
|
||||
if(a_operands[1].m_type == GM_INT)
|
||||
{
|
||||
int index = a_operands[1].m_value.m_int;
|
||||
|
||||
#if GM_USE_INCGC
|
||||
//Apply write barrier
|
||||
gmVariable oldVar = array->GetAt(index);
|
||||
if(oldVar.IsReference())
|
||||
{
|
||||
a_thread->GetMachine()->GetGC()->WriteBarrier((gmObject*)oldVar.m_value.m_ref);
|
||||
}
|
||||
#endif //GM_USE_INCGC
|
||||
|
||||
array->SetAt(index, a_operands[2]);
|
||||
}
|
||||
}
|
||||
|
||||
#if GM_USE_INCGC
|
||||
static void GM_CDECL gmGCDestructArrayUserType(gmMachine * a_machine, gmUserObject* a_object)
|
||||
{
|
||||
if(a_object->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) a_object->m_user;
|
||||
array->Destruct(a_machine);
|
||||
a_machine->Sys_Free(array);
|
||||
}
|
||||
a_object->m_user = NULL;
|
||||
}
|
||||
|
||||
static bool GM_CDECL gmGCTraceArrayUserType(gmMachine * a_machine, gmUserObject* a_object, gmGarbageCollector* a_gc, const int a_workLeftToGo, int& a_workDone)
|
||||
{
|
||||
if(a_object->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) a_object->m_user;
|
||||
return array->Trace(a_machine, a_gc, a_workLeftToGo, a_workDone);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#else //GM_USE_INCGC
|
||||
static void GM_CDECL gmMarkArrayUserType(gmMachine * a_machine, gmUserObject * a_object, gmuint32 a_mark)
|
||||
{
|
||||
if(a_object->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) a_object->m_user;
|
||||
array->Mark(a_machine, a_mark);
|
||||
}
|
||||
}
|
||||
|
||||
static void GM_CDECL gmGCArrayUserType(gmMachine * a_machine, gmUserObject * a_object, gmuint32 a_mark)
|
||||
{
|
||||
if(a_object->m_user)
|
||||
{
|
||||
gmUserArray * array = (gmUserArray *) a_object->m_user;
|
||||
array->Destruct(a_machine);
|
||||
a_machine->Sys_Free(array);
|
||||
}
|
||||
a_object->m_user = NULL;
|
||||
}
|
||||
#endif //GM_USE_INCGC
|
||||
|
||||
// libs
|
||||
|
||||
static gmFunctionEntry s_arrayLib[] =
|
||||
{
|
||||
/*gm
|
||||
\lib gm
|
||||
*/
|
||||
/*gm
|
||||
\function array
|
||||
\brief array will create a fixed size array object
|
||||
\param int size optional (0)
|
||||
\return array
|
||||
*/
|
||||
{"array", gmfArray},
|
||||
};
|
||||
|
||||
static gmFunctionEntry s_arrayTypeLib[] =
|
||||
{
|
||||
/*gm
|
||||
\lib array
|
||||
*/
|
||||
/*gm
|
||||
\function Size
|
||||
\brief Size will return the current size of the fixed array
|
||||
\return int array size
|
||||
*/
|
||||
{"Size", gmfArraySize},
|
||||
/*gm
|
||||
\function Resize
|
||||
\brief Resize will resize the array to a new size
|
||||
\param int size optional (0)
|
||||
\return null
|
||||
*/
|
||||
{"Resize", gmfArrayResize},
|
||||
/*gm
|
||||
\function Shift
|
||||
\brief Shift will shift slide the array elements by a delta, nulls are shifted in
|
||||
\param int delta
|
||||
\return null
|
||||
*/
|
||||
{"Shift", gmfArrayShift},
|
||||
/*gm
|
||||
\function Move
|
||||
\brief Move will perform a non destructive move on the array
|
||||
\param int dst
|
||||
\param int src
|
||||
\param int size
|
||||
\return null
|
||||
*/
|
||||
{"Move", gmfArrayMove},
|
||||
};
|
||||
|
||||
void gmBindArrayLib(gmMachine * a_machine)
|
||||
{
|
||||
gmUserArray::m_null.Nullify(); //Init static null
|
||||
|
||||
a_machine->RegisterLibrary(s_arrayLib, sizeof(s_arrayLib) / sizeof(s_arrayLib[0]));
|
||||
GM_ARRAY = a_machine->CreateUserType("array");
|
||||
a_machine->RegisterTypeLibrary(GM_ARRAY, s_arrayTypeLib, sizeof(s_arrayTypeLib) / sizeof(s_arrayTypeLib[0]));
|
||||
#if GM_USE_INCGC
|
||||
a_machine->RegisterUserCallbacks(GM_ARRAY, gmGCTraceArrayUserType, gmGCDestructArrayUserType);
|
||||
#else //GM_USE_INCGC
|
||||
a_machine->RegisterUserCallbacks(GM_ARRAY, gmMarkArrayUserType, gmGCArrayUserType);
|
||||
#endif //GM_USE_INCGC
|
||||
a_machine->RegisterTypeOperator(GM_ARRAY, O_GETIND, NULL, gmArrayGetInd);
|
||||
a_machine->RegisterTypeOperator(GM_ARRAY, O_SETIND, NULL, gmArraySetInd);
|
||||
}
|
||||
|
||||
#endif // GM_ARRAY_LIB
|
||||
Reference in New Issue
Block a user