1682 lines
38 KiB
C++
1682 lines
38 KiB
C++
// Copyright (C) 2007 Id Software, Inc.
|
|
//
|
|
|
|
#include "../precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "../Game_local.h"
|
|
#include "Script_DLL.h"
|
|
#include "Script_ScriptObject.h"
|
|
#include "Script_Helper.h"
|
|
#include "Script_Program.h"
|
|
|
|
extern const idEventDefInternal EV_Thread_Execute;
|
|
|
|
#pragma warning( push )
|
|
#pragma warning( disable: 4312 )
|
|
|
|
class MainCoroutine : public sdDLLThread {
|
|
public:
|
|
MainCoroutine() { s_current = this; s_main = this; storedStackPointer = ( char* )0xFFFFFFFF; flags.threadDying = false; name = "main"; }
|
|
virtual void Routine() {}
|
|
virtual void SetStackEntryPoint( char* value ) { ; }
|
|
};
|
|
#pragma warning( pop )
|
|
|
|
static MainCoroutine* s_MainCoroutine;
|
|
|
|
idLinkList< sdDLLThread > sdDLLThread::s_threads;
|
|
sdDLLThread* sdDLLThread::s_current = NULL;
|
|
sdDLLThread* sdDLLThread::s_main = NULL;
|
|
char* sdDLLThread::s_errorThrown = NULL;
|
|
|
|
#if defined( ID_WIN_X86_ASM )
|
|
|
|
#define STACK_SET( value ) \
|
|
__asm { \
|
|
mov ESP, value \
|
|
}
|
|
|
|
#define STACK_GET( value ) \
|
|
__asm { \
|
|
mov value, ESP \
|
|
}
|
|
|
|
#define PUSH_REGS \
|
|
__asm { \
|
|
pusha \
|
|
}
|
|
|
|
#define POP_REGS \
|
|
__asm { \
|
|
popa \
|
|
}
|
|
|
|
#elif defined( __linux__ ) || defined( MACOS_X )
|
|
|
|
// this one is not actually used, the stack is restored at the same address so we never have to modify esp
|
|
//#define STACK_SET( value ) __asm__ __volatile__ ( "movl %0, %%esp; sub $0x1c, %%esp;" : : "m" ( value ) : )
|
|
#define STACK_SET( value ) assert( false )
|
|
// don't save/restore the locals of Coroutine_Enter, only the stack
|
|
// could have used ebp also, but then we depend on -fno-omit-frame-pointer
|
|
// if the code in Coroutine_Enter changes (or even depending on compile settings), it's very possible the offset needs to be adjusted
|
|
// (to adjust the offsets, look at the Coroutine_Enter assembly generated by the compiler)
|
|
#ifdef _DEBUG
|
|
#define STACK_GET( value ) __asm__ __volatile__ ( "movl %%esp, %0; add $0x1c, %0;" : "=m" ( value ) : : )
|
|
#else
|
|
#define STACK_GET( value ) __asm__ __volatile__ ( "movl %%esp, %0; add $0x2c, %0;" : "=m" ( value ) : : )
|
|
#endif
|
|
|
|
#define PUSH_REGS
|
|
#define POP_REGS
|
|
|
|
#else
|
|
|
|
#define STACK_SET( value )
|
|
#define STACK_GET( value )
|
|
#define PUSH_REGS
|
|
#define POP_REGS
|
|
|
|
#endif
|
|
|
|
/*
|
|
================
|
|
sdDLLTypeObject::sdDLLTypeObject
|
|
================
|
|
*/
|
|
sdDLLTypeObject::sdDLLTypeObject( const sdDLLProgram::sdDLLClassInfo* _info ) {
|
|
info = _info;
|
|
instance = info->allocator();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLTypeObject::SetHandle
|
|
================
|
|
*/
|
|
void sdDLLTypeObject::SetHandle( int handle ) {
|
|
instance->__S_SetHandle( handle );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLTypeObject::GetVariable
|
|
================
|
|
*/
|
|
etype_t sdDLLTypeObject::GetVariable( const char *name, byte** data ) const {
|
|
for ( const sdDLLProgram::sdDLLClassInfo* i = info; i != NULL; i = i->superClass ) {
|
|
int key = i->variablesHash.GenerateKey( name );
|
|
|
|
for ( int index = i->variablesHash.GetFirst( key ); index != -1; index = i->variablesHash.GetNext( index ) ) {
|
|
if ( idStr::Cmp( i->variables[ index ]->GetName(), name ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
// fixme: type check
|
|
variableLookup_t lookup = i->variables[ index ]->GetLookup();
|
|
*data = ( *instance.*lookup )();
|
|
return i->variables[ index ]->GetType();
|
|
}
|
|
}
|
|
|
|
return ev_error;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
================
|
|
sdDLLFunction::sdDLLFunction
|
|
================
|
|
*/
|
|
sdDLLFunction::sdDLLFunction( sdFunctionInfo* fInfo ) {
|
|
name = fInfo->name;
|
|
function = fInfo->function;
|
|
wrapper = fInfo->wrapper;
|
|
|
|
numParms = 0;
|
|
parmSizeTotal = 0;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLClassFunction::sdDLLClassFunction
|
|
================
|
|
*/
|
|
sdDLLClassFunction::sdDLLClassFunction( sdClassFunctionInfo* fInfo ) {
|
|
name = fInfo->name;
|
|
function = fInfo->function;
|
|
wrapper = fInfo->wrapper;
|
|
numParms = fInfo->numParms;
|
|
parmSizeTotal = fInfo->parmSizeTotal;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLClassVariable::sdDLLClassVariable
|
|
================
|
|
*/
|
|
sdDLLClassVariable::sdDLLClassVariable( sdClassVariableInfo* vInfo ) {
|
|
name = vInfo->name;
|
|
lookup = vInfo->variable;
|
|
|
|
switch ( vInfo->type ) {
|
|
case V_FLOAT:
|
|
type = ev_float;
|
|
break;
|
|
case V_BOOLEAN:
|
|
type = ev_boolean;
|
|
break;
|
|
case V_VECTOR:
|
|
type = ev_vector;
|
|
break;
|
|
case V_OBJECT:
|
|
type = ev_object;
|
|
break;
|
|
case V_STRING:
|
|
type = ev_string;
|
|
break;
|
|
case V_WSTRING:
|
|
type = ev_wstring;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::sdDLLProgram
|
|
================
|
|
*/
|
|
sdDLLProgram::sdDLLProgram( void ) {
|
|
dllHandle = NULL;
|
|
dllInterface.Init( this );
|
|
scriptInterface = NULL;
|
|
returnValue.intValue = 0;
|
|
defaultType = NULL;
|
|
|
|
FreeScriptObjects();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::CloseDLL
|
|
================
|
|
*/
|
|
void sdDLLProgram::CloseDLL( void ) {
|
|
if ( dllHandle == NULL ) {
|
|
return;
|
|
}
|
|
sys->DLL_Unload( dllHandle );
|
|
dllHandle = NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::Init
|
|
================
|
|
*/
|
|
bool sdDLLProgram::Init( void ) {
|
|
Shutdown();
|
|
|
|
s_MainCoroutine = new MainCoroutine();
|
|
|
|
char dllPath[ MAX_OSPATH ];
|
|
|
|
if ( gameLocal.mapMetaData->GetBool( "no_compiled_script" ) ) {
|
|
return false;
|
|
}
|
|
|
|
const char* suffix = gameLocal.mapMetaData->GetString( "compiledscript_suffix" );
|
|
|
|
fileSystem->FindDLL( va( "compiledscript%s", suffix ), dllPath, false, true );
|
|
if ( dllPath[ 0 ] == '\0' ) {
|
|
gameLocal.Warning( "sdDLLProgram::Init : Couldn't find '%s' dynamic library", dllPath );
|
|
return false;
|
|
}
|
|
|
|
dllHandle = sys->DLL_Load( dllPath, true );
|
|
if ( dllHandle == NULL ) {
|
|
gameLocal.Warning( "sdDLLProgram::Init : Couldn't load '%s' dynamic library", dllPath );
|
|
return false;
|
|
}
|
|
scriptInitFunc_t initFunc = ( scriptInitFunc_t )sys->DLL_GetProcAddress( dllHandle, "InitScripts" );
|
|
if ( initFunc == NULL ) {
|
|
CloseDLL();
|
|
gameLocal.Warning( "sdDLLProgram::Init : Couldn't Initialize Script DLL" );
|
|
return false;
|
|
}
|
|
|
|
scriptInterface = initFunc( &dllInterface );
|
|
if ( scriptInterface == NULL ) {
|
|
CloseDLL();
|
|
gameLocal.Warning( "sdDLLProgram::Init : No Script Interface Provided by DLL" );
|
|
return false;
|
|
}
|
|
|
|
int scriptVersion = scriptInterface->GetVersion();
|
|
if ( scriptVersion != COMPILED_SCRIPT_INTERFACE_VERSION ) {
|
|
gameLocal.Warning( "sdDLLProgram::Init : Version mismatch, expected %d, got %d", COMPILED_SCRIPT_INTERFACE_VERSION, scriptVersion );
|
|
return false;
|
|
}
|
|
|
|
int ourSize = sizeof( sdClassFunctionInfo );
|
|
int theirSize = scriptInterface->GetClassFunctionInfoSize();
|
|
|
|
if ( theirSize != ourSize ) {
|
|
CloseDLL();
|
|
gameLocal.Warning( "sdDLLProgram::Init : Size Mismatch on sdClassFunctionInfo" );
|
|
return false;
|
|
}
|
|
|
|
idList< const sdClassInfo* > dllClasses;
|
|
|
|
const sdClassInfo* baseClassInfo = scriptInterface->GetClassInfo();
|
|
for ( const sdClassInfo* c = baseClassInfo; c != NULL; c = c->next ) {
|
|
sdDLLClassInfo* newInfo = new sdDLLClassInfo(); // FIXME: Block Alloc
|
|
|
|
dllClasses.Alloc() = c;
|
|
|
|
newInfo->superClass = NULL;
|
|
|
|
newInfo->allocator = c->allocator;
|
|
newInfo->name = c->name;
|
|
|
|
int hashKey = classInfoHash.GenerateKey( c->name );
|
|
classInfoHash.Add( hashKey, classInfo.Num() );
|
|
classInfo.Alloc() = newInfo;
|
|
|
|
for ( sdClassFunctionInfo* fInfo = c->functionInfo; fInfo->name != NULL; fInfo++ ) {
|
|
newInfo->functionHash.Add( newInfo->functionHash.GenerateKey( fInfo->name ), newInfo->functions.Num() );
|
|
newInfo->functions.Alloc() = new sdDLLClassFunction( fInfo ); // FIXME: Block Alloc
|
|
}
|
|
|
|
for ( sdClassVariableInfo* vInfo = c->variableInfo; vInfo->name != NULL; vInfo++ ) {
|
|
newInfo->variablesHash.Add( newInfo->variablesHash.GenerateKey( vInfo->name ), newInfo->variables.Num() );
|
|
newInfo->variables.Alloc() = new sdDLLClassVariable( vInfo ); // FIXME: Block Alloc
|
|
}
|
|
}
|
|
|
|
int index = 0;
|
|
for ( const sdClassInfo* c = baseClassInfo; c != NULL; c = c->next, index++ ) {
|
|
if ( c->superClass == NULL ) {
|
|
continue;
|
|
}
|
|
|
|
bool found = false;
|
|
for ( int i = 0; i < dllClasses.Num(); i++ ) {
|
|
if ( c->superClass == dllClasses[ i ] ) {
|
|
classInfo[ index ]->superClass = classInfo[ i ];
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !found ) {
|
|
assert( false );
|
|
}
|
|
}
|
|
|
|
sdFunctionInfo* baseFunctionInfo = scriptInterface->GetFunctionInfo();
|
|
for ( sdFunctionInfo* f = baseFunctionInfo; f != NULL; f = f->next ) {
|
|
sdDLLFunction* newInfo = new sdDLLFunction( f );
|
|
|
|
int hashKey = functionInfoHash.GenerateKey( f->name );
|
|
functionInfoHash.Add( hashKey, functionInfo.Num() );
|
|
functionInfo.Alloc() = newInfo;
|
|
}
|
|
|
|
defaultType = FindTypeInfo( "default" );
|
|
|
|
freeThreadNums.SetNum( MAX_THREADS );
|
|
for ( int i = 0; i < MAX_THREADS; i++ ) {
|
|
freeThreadNums[ i ] = i;
|
|
}
|
|
|
|
gameLocal.Printf( "Loaded '%s'\n", dllPath );
|
|
gameLocal.Printf( " %i classes\n", dllClasses.Num() );
|
|
gameLocal.Printf( " %i global functions\n", functionInfo.Num() );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::Restart
|
|
================
|
|
*/
|
|
void sdDLLProgram::Restart( void ) {
|
|
Shutdown();
|
|
Init();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::Disassemble
|
|
================
|
|
*/
|
|
void sdDLLProgram::Disassemble( void ) const {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::OnError
|
|
================
|
|
*/
|
|
bool sdDLLProgram::OnError( const char* text ) {
|
|
return sdDLLThread::OnError( text );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::Shutdown
|
|
================
|
|
*/
|
|
void sdDLLProgram::Shutdown( void ) {
|
|
freeThreadNums.Clear();
|
|
|
|
classInfo.DeleteContents( true );
|
|
classInfoHash.Clear();
|
|
|
|
functionInfo.DeleteContents( true );
|
|
functionInfoHash.Clear();
|
|
|
|
scriptInterface = NULL;
|
|
|
|
threadAllocator.Shutdown();
|
|
|
|
for ( int i = 0; i < freeStacks.Num(); i++ ) {
|
|
freeStacks[ i ].DeleteContents( true );
|
|
}
|
|
freeStacks.Clear();
|
|
|
|
delete s_MainCoroutine;
|
|
s_MainCoroutine = NULL;
|
|
|
|
CloseDLL();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::CreateThread
|
|
================
|
|
*/
|
|
sdProgramThread* sdDLLProgram::CreateThread( void ) {
|
|
if ( freeThreadNums.Num() == 0 ) {
|
|
gameLocal.Error( "sdDLLProgram::CreateThread No Free Threads" );
|
|
return NULL;
|
|
}
|
|
|
|
int count = freeThreadNums.Num();
|
|
int index = freeThreadNums[ count - 1 ];
|
|
freeThreadNums.SetNum( count - 1, false );
|
|
|
|
sdDLLThread* thread = threadAllocator.Alloc();
|
|
thread->Create( this, index );
|
|
return thread;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::FindFunction
|
|
================
|
|
*/
|
|
const sdProgram::sdFunction* sdDLLProgram::FindFunction( const char* name ) {
|
|
int hashKey = functionInfoHash.GenerateKey( name );
|
|
for ( int index = functionInfoHash.GetFirst( hashKey ); index != -1; index = functionInfoHash.GetNext( index ) ) {
|
|
if ( idStr::Cmp( functionInfo[ index ]->GetName(), name ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
return functionInfo[ index ];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::FindFunction
|
|
================
|
|
*/
|
|
const sdProgram::sdFunction* sdDLLProgram::FindFunction( const char* name, const sdProgram::sdTypeObject* object ) {
|
|
const sdDLLTypeObject* t = reinterpret_cast< const sdDLLTypeObject* >( object );
|
|
|
|
const sdDLLClassInfo* info = t->GetInfo();
|
|
|
|
for ( const sdDLLClassInfo* i = info; i != NULL; i = i->superClass ) {
|
|
int hashKey = i->functionHash.GenerateKey( name );
|
|
for ( int index = i->functionHash.GetFirst( hashKey ); index != -1; index = i->functionHash.GetNext( index ) ) {
|
|
if ( idStr::Cmp( i->functions[ index ]->GetName(), name ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
return i->functions[ index ];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::AllocType
|
|
================
|
|
*/
|
|
sdProgram::sdTypeObject* sdDLLProgram::AllocType( sdProgram::sdTypeObject* oldType, const sdTypeInfo* type ) {
|
|
FreeType( oldType );
|
|
return new sdDLLTypeObject( reinterpret_cast< const sdDLLClassInfo* >( type ) );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::FindTypeInfo
|
|
================
|
|
*/
|
|
const sdProgram::sdTypeInfo* sdDLLProgram::FindTypeInfo( const char* typeName ) {
|
|
int key = classInfoHash.GenerateKey( typeName );
|
|
for ( int index = classInfoHash.GetFirst( key ); index != -1; index = classInfoHash.GetNext( index ) ) {
|
|
if ( idStr::Cmp( classInfo[ index ]->name.c_str(), typeName ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
return classInfo[ index ];
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::GetNumClasses
|
|
================
|
|
*/
|
|
int sdDLLProgram::GetNumClasses( void ) const {
|
|
return classInfo.Num();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::GetClass
|
|
================
|
|
*/
|
|
const sdProgram::sdTypeInfo* sdDLLProgram::GetClass( int index ) const {
|
|
return classInfo[ index ];
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::AllocType
|
|
================
|
|
*/
|
|
sdProgram::sdTypeObject* sdDLLProgram::AllocType( sdProgram::sdTypeObject* oldType, const char* typeName ) {
|
|
const sdProgram::sdTypeInfo* typeInfo = FindTypeInfo( typeName );
|
|
if ( typeInfo != NULL ) {
|
|
return AllocType( oldType, typeInfo );
|
|
}
|
|
|
|
gameLocal.Error( "sdDLLProgram::AllocType Invalid Type Name: '%s'", typeName );
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::FreeType
|
|
================
|
|
*/
|
|
void sdDLLProgram::FreeType( sdProgram::sdTypeObject* oldType ) {
|
|
delete oldType;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::FreeThread
|
|
================
|
|
*/
|
|
void sdDLLProgram::FreeThread( sdProgramThread* thread ) {
|
|
sdDLLThread* _thread = ( sdDLLThread* )thread;
|
|
_thread->Clear();
|
|
threadAllocator.Free( _thread );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::OnThreadShutdown
|
|
================
|
|
*/
|
|
void sdDLLProgram::OnThreadShutdown( sdDLLThread* thread ) {
|
|
freeThreadNums.Alloc() = thread->GetThreadNum();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::AllocStack
|
|
================
|
|
*/
|
|
char* sdDLLProgram::AllocStack( size_t size, size_t& usedSize ) {
|
|
const int index = ( int )( ( ( size + 511 ) / 512 ) - 1 );
|
|
usedSize = ( index + 1 ) * 512;
|
|
|
|
if ( index >= freeStacks.Num() ) {
|
|
freeStacks.SetNum( index + 1 );
|
|
}
|
|
|
|
int num = freeStacks[ index ].Num();
|
|
if ( num > 0 ) {
|
|
char* stack = freeStacks[ index ][ num - 1 ];
|
|
freeStacks[ index ].SetNum( num - 1, false );
|
|
return stack;
|
|
}
|
|
|
|
return new char[ usedSize ];
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::FreeStack
|
|
================
|
|
*/
|
|
void sdDLLProgram::FreeStack( char* stack, size_t size ) {
|
|
if ( stack == NULL ) {
|
|
return;
|
|
}
|
|
|
|
assert( ( size % 512 ) == 0 );
|
|
|
|
const int index = ( int )( ( size / 512 ) - 1 );
|
|
|
|
assert( index < freeStacks.Num() );
|
|
|
|
freeStacks[ index ].Alloc() = stack;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::CreateThread
|
|
================
|
|
*/
|
|
sdProgramThread* sdDLLProgram::CreateThread( const sdScriptHelper& h ) {
|
|
const sdDLLClassFunction* function = reinterpret_cast< const sdDLLClassFunction* >( h.GetFunction() );
|
|
|
|
if ( ( function->GetParmSizeTotal() + 4 ) != h.GetSize() ) {
|
|
gameLocal.Warning( "idProgram::CreateThread Function '%s' Called With Incorrect Number Of Arguments", function->GetName() );
|
|
assert( false );
|
|
return NULL;
|
|
}
|
|
|
|
sdDLLThread* thread = reinterpret_cast< sdDLLThread* >( CreateThread() );
|
|
|
|
thread->ManualControl();
|
|
|
|
static byte buffer[ MAX_STRING_LEN * 12 ];
|
|
byte* p = buffer;
|
|
|
|
const sdScriptHelper::parmsList_t& args = h.GetArgs();
|
|
for ( int i = 0; i < args.Num(); i++ ) {
|
|
if ( args[ i ].string ) {
|
|
memcpy( p, args[ i ].string, MAX_STRING_LEN );
|
|
p += MAX_STRING_LEN;
|
|
} else {
|
|
*( int* )p = args[ i ].integer;
|
|
p += sizeof( int );
|
|
}
|
|
}
|
|
|
|
thread->call1.Init( h.GetObject(), function, buffer, this );
|
|
thread->Call( &thread->call1, false );
|
|
|
|
return thread;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::KillThread
|
|
================
|
|
*/
|
|
void sdDLLProgram::KillThread( int number ) { // FIXME, these numbers need to be really unique, not just an index
|
|
sdDLLThread::KillThread( number );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::KillThread
|
|
================
|
|
*/
|
|
void sdDLLProgram::KillThread( const char* name ) {
|
|
sdDLLThread::KillThread( name );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::GetCurrentThread
|
|
================
|
|
*/
|
|
sdProgramThread* sdDLLProgram::GetCurrentThread( void ) {
|
|
return sdDLLThread::GetActiveThread();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnStringInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnStringInternal( const char* value ) {
|
|
stringValue = value;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnWStringInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnWStringInternal( const wchar_t* value ) {
|
|
wstringValue = value;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnFloatInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnFloatInternal( float value ) {
|
|
returnValue.floatValue = value;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnVectorInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnVectorInternal( const idVec3& value ) {
|
|
vectorValue = value;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnEntityInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnEntityInternal( idEntity* value ) {
|
|
idScriptObject* obj = value ? value->GetScriptObject() : NULL;
|
|
returnValue.objectValue = obj->GetHandle();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnIntegerInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnIntegerInternal( int value ) {
|
|
returnValue.intValue = value;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ReturnObjectInternal
|
|
================
|
|
*/
|
|
void sdDLLProgram::ReturnObjectInternal( idScriptObject* value ) {
|
|
returnValue.objectValue = value->GetHandle();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::ListThreads
|
|
================
|
|
*/
|
|
void sdDLLProgram::ListThreads( void ) const {
|
|
sdDLLThread::ListThreads();
|
|
|
|
int count = 0;
|
|
int size = 0;
|
|
for ( int i = 0; i < freeStacks.Num(); i++ ) {
|
|
int localCount = freeStacks[ i ].Num();
|
|
size += ( ( i + 1 ) * 512 ) * localCount;
|
|
count += localCount;
|
|
}
|
|
|
|
gameLocal.Printf( "Total Free Thread Stacks: %d\n", count );
|
|
gameLocal.Printf( "Total Free Thread Stack Size: %d\n", size );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLProgram::PruneThreads
|
|
================
|
|
*/
|
|
void sdDLLProgram::PruneThreads( void ) {
|
|
sdDLLThread::PruneThreads();
|
|
}
|
|
|
|
|
|
|
|
|
|
CLASS_DECLARATION( sdSysCallThread, sdDLLThread )
|
|
END_CLASS
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::sdDLLThread
|
|
================
|
|
*/
|
|
sdDLLThread::sdDLLThread( void ) {
|
|
localStack = NULL;
|
|
call = NULL;
|
|
program = NULL;
|
|
|
|
threadNode.SetOwner( this );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Create
|
|
================
|
|
*/
|
|
void sdDLLThread::Create( sdDLLProgram* _program, int _threadNum ) {
|
|
Init();
|
|
program = _program;
|
|
threadNum = _threadNum;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Init
|
|
================
|
|
*/
|
|
void sdDLLThread::Init( void ) {
|
|
Clear();
|
|
threadNode.AddToFront( s_threads );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Clear
|
|
================
|
|
*/
|
|
void sdDLLThread::Clear( void ) {
|
|
FreeStack();
|
|
|
|
if ( program != NULL ) {
|
|
program->OnThreadShutdown( this );
|
|
}
|
|
|
|
if ( call != &call1 && call != &call2 ) {
|
|
delete call;
|
|
}
|
|
|
|
if ( this == s_current ) {
|
|
s_current = s_MainCoroutine;
|
|
}
|
|
|
|
call = NULL;
|
|
pauseTime = 0;
|
|
program = NULL;
|
|
threadNum = -1;
|
|
storedStackSize = 0;
|
|
actualStackSize = 0;
|
|
storedStackPointer = NULL;
|
|
|
|
name.Clear();
|
|
|
|
callee = NULL;
|
|
caller = NULL;
|
|
|
|
flags.manualDelete = false;
|
|
flags.manualControl = false;
|
|
flags.waitFrame = false;
|
|
flags.threadDying = true;
|
|
flags.reset = false;
|
|
flags.doneProcessing = true;
|
|
flags.guiThread = false;
|
|
|
|
threadNode.Remove();
|
|
GetAutoNode().Remove();
|
|
|
|
CancelEvents( &EV_Thread_Execute );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::~sdDLLThread
|
|
================
|
|
*/
|
|
sdDLLThread::~sdDLLThread( void ) {
|
|
Clear();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::KillThread
|
|
================
|
|
*/
|
|
void sdDLLThread::KillThread( int number ) {
|
|
for ( sdDLLThread* thread = s_threads.Next(); thread != NULL; thread = thread->threadNode.Next() ) {
|
|
if ( thread->GetThreadNum() != number ) {
|
|
continue;
|
|
}
|
|
|
|
thread->EndThread();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::KillThread
|
|
================
|
|
*/
|
|
void sdDLLThread::KillThread( const char* name ) {
|
|
for ( sdDLLThread* thread = s_threads.Next(); thread != NULL; thread = thread->threadNode.Next() ) {
|
|
if ( idStr::Cmp( thread->name.c_str(), name ) != 0 ) {
|
|
continue;
|
|
}
|
|
|
|
thread->EndThread();
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::CallFunction
|
|
================
|
|
*/
|
|
void sdDLLThread::CallFunction( const sdProgram::sdFunction* function ) {
|
|
// assert( reinterpret_cast< const sdDLLFunction* >( function )->GetNumParameters() == 0 );
|
|
call2.Init( function, NULL );
|
|
SetCall( &call2 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::CallFunction
|
|
================
|
|
*/
|
|
void sdDLLThread::CallFunction( idScriptObject* obj, const sdProgram::sdFunction* function ) {
|
|
assert( reinterpret_cast< const sdDLLClassFunction* >( function )->GetNumParameters() == 0 );
|
|
call1.Init( obj, function, NULL, program );
|
|
SetCall( &call1 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::DelayedStart
|
|
================
|
|
*/
|
|
void sdDLLThread::DelayedStart( int delay ) {
|
|
CancelEvents( &EV_Thread_Execute );
|
|
PostEventMS( &EV_Thread_Execute, delay );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Execute
|
|
================
|
|
*/
|
|
bool sdDLLThread::Execute( void ) {
|
|
int now = GetThreadTime();
|
|
|
|
if ( flags.manualControl && ( pauseTime > now ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( flags.reset ) {
|
|
Reset();
|
|
flags.reset = false;
|
|
}
|
|
|
|
if ( !Finished() ) {
|
|
sdDLLThread::Call( this );
|
|
}
|
|
|
|
if ( s_current == s_MainCoroutine ) {
|
|
if ( s_errorThrown != NULL ) {
|
|
idStr temp = s_errorThrown;
|
|
delete s_errorThrown;
|
|
s_errorThrown = NULL;
|
|
|
|
gameLocal.Error( "%s", temp.c_str() );
|
|
}
|
|
}
|
|
|
|
if ( Finished() ) {
|
|
if ( !flags.manualDelete ) {
|
|
program->FreeThread( this );
|
|
}
|
|
return true;
|
|
} else if ( !flags.manualControl ) {
|
|
if ( flags.waitFrame ) {
|
|
flags.waitFrame = false;
|
|
if ( flags.guiThread ) {
|
|
PostGUIEventMS( &EV_Thread_Execute, NEXT_FRAME_EVENT_TIME );
|
|
} else {
|
|
PostEventMS( &EV_Thread_Execute, NEXT_FRAME_EVENT_TIME );
|
|
}
|
|
} else if ( pauseTime > now ) {
|
|
if ( flags.guiThread ) {
|
|
PostGUIEventMS( &EV_Thread_Execute, pauseTime - now );
|
|
} else {
|
|
PostEventMS( &EV_Thread_Execute, pauseTime - now );
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::ManualDelete
|
|
================
|
|
*/
|
|
void sdDLLThread::ManualDelete( void ) {
|
|
flags.manualDelete = true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::ManualControl
|
|
================
|
|
*/
|
|
void sdDLLThread::ManualControl( void ) {
|
|
flags.manualControl = true;
|
|
CancelEvents( &EV_Thread_Execute );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::EndThread
|
|
================
|
|
*/
|
|
void sdDLLThread::EndThread( void ) {
|
|
if ( flags.threadDying ) {
|
|
return;
|
|
}
|
|
|
|
flags.threadDying = true;
|
|
if ( this == GetActiveThread() ) {
|
|
Coroutine_Detach( this );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::DoneProcessing
|
|
================
|
|
*/
|
|
void sdDLLThread::DoneProcessing( void ) {
|
|
if ( flags.doneProcessing ) {
|
|
return;
|
|
}
|
|
flags.doneProcessing = true;
|
|
if ( this == GetActiveThread() ) {
|
|
Coroutine_Detach( this );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::SetName
|
|
================
|
|
*/
|
|
void sdDLLThread::SetName( const char* _name ) {
|
|
name = _name;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Error
|
|
================
|
|
*/
|
|
void sdDLLThread::Error( const char* fmt, ... ) const {
|
|
va_list argptr;
|
|
char text[ 1024 ];
|
|
|
|
va_start( argptr, fmt );
|
|
vsprintf( text, fmt, argptr );
|
|
va_end( argptr );
|
|
|
|
common->Error( "Thread '%s': %s", name.c_str(), text );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Warning
|
|
================
|
|
*/
|
|
void sdDLLThread::Warning( const char* fmt, ... ) const {
|
|
va_list argptr;
|
|
char text[ 1024 ];
|
|
|
|
va_start( argptr, fmt );
|
|
vsprintf( text, fmt, argptr );
|
|
va_end( argptr );
|
|
|
|
common->Warning( "Thread '%s': %s", name.c_str(), text );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::EnableDebugInfo
|
|
================
|
|
*/
|
|
void sdDLLThread::EnableDebugInfo( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::DisableDebugInfo
|
|
================
|
|
*/
|
|
void sdDLLThread::DisableDebugInfo( void ) {
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::IsWaiting
|
|
================
|
|
*/
|
|
bool sdDLLThread::IsWaiting( void ) const {
|
|
return pauseTime > GetThreadTime();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Wait
|
|
================
|
|
*/
|
|
void sdDLLThread::Wait( float time ) {
|
|
if ( time <= 0.f ) {
|
|
WaitFrame();
|
|
return;
|
|
}
|
|
|
|
pauseTime = GetThreadTime() + SEC2MS( time );
|
|
Coroutine_Detach( this );
|
|
}
|
|
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Call
|
|
================
|
|
*/
|
|
void sdDLLThread::Call( sdProcedureCall* call, bool guiThread ) {
|
|
flags.guiThread = guiThread;
|
|
SetCall( call );
|
|
}
|
|
|
|
#ifdef USE_UCONTEXT
|
|
static bool context_jump = false;
|
|
#endif
|
|
|
|
/*
|
|
================
|
|
Coroutine_Enter
|
|
================
|
|
*/
|
|
void Coroutine_Enter( sdDLLThread *self ) {
|
|
#if defined( MACOS_X ) || defined( __linux__ ) || ( defined( _WIN32 ) && !defined( _XENON ) )
|
|
|
|
PUSH_REGS;
|
|
|
|
// store a stack if we are detaching
|
|
// must not be dying off either, as that means the call here is just for exit purposes
|
|
if ( sdDLLThread::s_current->callee == NULL && !sdDLLThread::s_current->flags.doneProcessing && !sdDLLThread::s_current->flags.threadDying ) {
|
|
assert( sdDLLThread::s_current != s_MainCoroutine );
|
|
|
|
char* temp;
|
|
STACK_GET( temp );
|
|
|
|
sdDLLThread::s_current->AllocStack( temp );
|
|
}
|
|
|
|
#ifdef USE_UCONTEXT
|
|
assert( !context_jump );
|
|
int ret = getcontext( &sdDLLThread::s_current->context );
|
|
if ( ret != 0 ) {
|
|
gameLocal.Error( "getcontext %s failed", sdDLLThread::s_current->name.c_str() );
|
|
}
|
|
if ( context_jump ) {
|
|
context_jump = false;
|
|
#else
|
|
if ( setjmp( sdDLLThread::s_current->environment ) ) {
|
|
#endif
|
|
if ( sdDLLThread::s_current->IsStackSaved() ) {
|
|
char* temp;
|
|
STACK_GET( temp );
|
|
assert( sdDLLThread::s_current->storedStackPointer - sdDLLThread::s_current->storedStackSize == temp );
|
|
memcpy( temp, sdDLLThread::s_current->localStack, sdDLLThread::s_current->storedStackSize );
|
|
|
|
sdDLLThread::s_current->FreeStack();
|
|
}
|
|
|
|
POP_REGS;
|
|
|
|
return;
|
|
}
|
|
|
|
sdDLLThread::s_current = self;
|
|
self->flags.doneProcessing = false;
|
|
|
|
if ( sdDLLThread::s_current->flags.threadDying ) {
|
|
Coroutine_Detach( self );
|
|
}
|
|
|
|
if ( self->storedStackPointer == NULL ) {
|
|
|
|
sdDLLThread::s_current->FreeStack();
|
|
|
|
char* temp;
|
|
STACK_GET( temp );
|
|
self->storedStackPointer = temp;
|
|
|
|
self->Routine();
|
|
|
|
Coroutine_Detach( self );
|
|
|
|
// detach never returns
|
|
assert( false );
|
|
}
|
|
|
|
assert( sdDLLThread::s_current == self );
|
|
|
|
#ifdef USE_UCONTEXT
|
|
context_jump = true;
|
|
setcontext( &self->context );
|
|
// never returns
|
|
gameLocal.Error( "setcontext %s failed", self->name.c_str() );
|
|
#else
|
|
longjmp( self->environment, 1 );
|
|
#endif
|
|
|
|
#else
|
|
assert( false );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
===============
|
|
Coroutine_Detach
|
|
===============
|
|
*/
|
|
void Coroutine_Detach( sdDLLThread *self ) {
|
|
assert( self == sdDLLThread::s_current );
|
|
assert( sdDLLThread::s_current != s_MainCoroutine );
|
|
|
|
sdDLLThread* next = self->caller;
|
|
assert( next != NULL );
|
|
assert( next->callee == self );
|
|
|
|
next->callee = NULL;
|
|
self->caller = NULL;
|
|
|
|
Coroutine_Enter( next );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::Call
|
|
================
|
|
*/
|
|
void sdDLLThread::Call( sdDLLThread* next ) {
|
|
assert( next != NULL );
|
|
|
|
if ( next->caller ) {
|
|
gameLocal.Error( "Attempt to Call an attached Coroutine" );
|
|
}
|
|
s_current->callee = next;
|
|
next->caller = s_current;
|
|
while ( next->callee ) {
|
|
next = next->callee;
|
|
}
|
|
if ( next == s_current ) {
|
|
gameLocal.Error( "Attempt to Call an operating Coroutine" );
|
|
}
|
|
Coroutine_Enter( next );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::ListThreads
|
|
================
|
|
*/
|
|
void sdDLLThread::ListThreads( void ) {
|
|
int n = 0;
|
|
for ( sdDLLThread* thread = s_threads.Next(); thread; thread = thread->threadNode.Next(), n++ ) {
|
|
gameLocal.Printf( "%3i: %d: %-20s\n", thread->threadNum, thread->actualStackSize, thread->name.c_str() );
|
|
}
|
|
gameLocal.Printf( "%d active threads\n\n", n );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::PruneThreads
|
|
================
|
|
*/
|
|
void sdDLLThread::PruneThreads( void ) {
|
|
sdDLLThread* next = NULL;
|
|
for ( sdDLLThread* thread = s_threads.Next(); thread; thread = next ) {
|
|
next = thread->threadNode.Next();
|
|
|
|
if ( thread == s_MainCoroutine ) {
|
|
continue;
|
|
}
|
|
|
|
if ( thread->flags.manualDelete ) {
|
|
continue;
|
|
}
|
|
|
|
thread->program->FreeThread( thread );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::OnError
|
|
================
|
|
*/
|
|
bool sdDLLThread::OnError( const char* text ) {
|
|
assert( s_MainCoroutine != NULL );
|
|
|
|
if ( s_current == s_MainCoroutine ) {
|
|
return false;
|
|
}
|
|
|
|
const char* callstack = sys->GetCurCallStackStr( 16 );
|
|
const char* temp = va( "%s\nThread: %s\n%s", callstack, s_current->name.c_str(), text );
|
|
|
|
int len = idStr::Length( temp ) + 1;
|
|
s_errorThrown = new char[ len ];
|
|
idStr::Copynz( s_errorThrown, temp, len );
|
|
|
|
sdDLLThread* chain = s_MainCoroutine;
|
|
while ( true ) {
|
|
chain = chain->callee;
|
|
chain->EndThread();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLThread::StackTrace
|
|
================
|
|
*/
|
|
void sdDLLThread::StackTrace( void ) const {
|
|
gameLocal.Printf( "<COMPILED SCRIPTS - STACK UNAVAILABLE>\n" );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::FindEvent
|
|
================
|
|
*/
|
|
const idEventDef* sdDLLScriptInterface::FindEvent( const char* name ) {
|
|
return idEventDef::FindEvent( name );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::AllocThread
|
|
================
|
|
*/
|
|
int sdDLLScriptInterface::AllocThread( sdProcedureCall* call ) {
|
|
sdDLLThread* thread = reinterpret_cast< sdDLLThread* >( program->CreateThread() );
|
|
thread->Call( call, false );
|
|
thread->DelayedStart( 0 );
|
|
return thread->GetThreadNum();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::AllocThread
|
|
================
|
|
*/
|
|
int sdDLLScriptInterface::AllocThread( sdCompiledScript_ClassBase* object, const char* name, sdProcedureCall* call ) {
|
|
assert( object != NULL );
|
|
|
|
sdDLLThread* thread = reinterpret_cast< sdDLLThread* >( program->CreateThread() );
|
|
thread->Call( call, false );
|
|
thread->DelayedStart( 0 );
|
|
|
|
idScriptObject* obj = GetScriptObject( object->__S_GetHandle() );
|
|
assert( obj != NULL );
|
|
|
|
thread->GetAutoNode().AddToEnd( obj->GetAutoThreads() );
|
|
|
|
idEntity* ent = obj->GetClass()->Cast< idEntity >();
|
|
if ( ent != NULL ) {
|
|
thread->SetName( va( "%s_%s", name, ent->name.c_str() ) );
|
|
}
|
|
|
|
return thread->GetThreadNum();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::AllocThread
|
|
================
|
|
*/
|
|
int sdDLLScriptInterface::AllocGuiThread( sdProcedureCall* call ) {
|
|
sdDLLThread* thread = reinterpret_cast< sdDLLThread* >( program->CreateThread() );
|
|
thread->Call( call, true );
|
|
thread->DelayedStart( 0 );
|
|
return thread->GetThreadNum();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::AllocThread
|
|
================
|
|
*/
|
|
int sdDLLScriptInterface::AllocGuiThread( sdCompiledScript_ClassBase* object, const char* name, sdProcedureCall* call ) {
|
|
assert( object != NULL );
|
|
|
|
sdDLLThread* thread = reinterpret_cast< sdDLLThread* >( program->CreateThread() );
|
|
thread->Call( call, true );
|
|
thread->DelayedStart( 0 );
|
|
|
|
idScriptObject* obj = GetScriptObject( object->__S_GetHandle() );
|
|
assert( obj != NULL );
|
|
|
|
thread->GetAutoNode().AddToEnd( obj->GetAutoThreads() );
|
|
|
|
idEntity* ent = obj->GetClass()->Cast< idEntity >();
|
|
if ( ent != NULL ) {
|
|
thread->SetName( va( "%s_%s", name, ent->name.c_str() ) );
|
|
}
|
|
|
|
return thread->GetThreadNum();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::DoAllocObject
|
|
================
|
|
*/
|
|
sdCompiledScript_ClassBase* sdDLLScriptInterface::DoAllocObject( const char* name ) {
|
|
idScriptObject* obj = program->AllocScriptObject( NULL, name );
|
|
|
|
sdScriptHelper h1;
|
|
obj->CallNonBlockingScriptEvent( obj->GetPreConstructor(), h1 );
|
|
|
|
return reinterpret_cast< sdDLLTypeObject* >( obj->GetObject() )->GetInstance();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::AllocObject
|
|
================
|
|
*/
|
|
sdCompiledScript_ClassBase* sdDLLScriptInterface::AllocObject( const char* name ) {
|
|
sdCompiledScript_ClassBase* obj = DoAllocObject( name );
|
|
return obj;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::FreeObject
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::DoFreeObject( sdCompiledScript_ClassBase* instance ) {
|
|
idScriptObject* obj = program->GetScriptObject( instance->__S_GetHandle() );
|
|
if ( obj == NULL ) {
|
|
return;
|
|
}
|
|
|
|
sdScriptHelper h1;
|
|
obj->CallNonBlockingScriptEvent( obj->GetDestructor(), h1 );
|
|
|
|
program->FreeScriptObject( obj );
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::FreeObject
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::FreeObject( sdCompiledScript_ClassBase* instance ) {
|
|
if ( instance == NULL ) {
|
|
return;
|
|
}
|
|
|
|
DoFreeObject( instance );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetObject
|
|
================
|
|
*/
|
|
sdCompiledScript_ClassBase* sdDLLScriptInterface::GetObject( int handle ) {
|
|
idScriptObject* obj = program->GetScriptObject( handle );
|
|
if ( obj == NULL ) {
|
|
return NULL;
|
|
}
|
|
return reinterpret_cast< sdDLLTypeObject* >( obj->GetObject() )->GetInstance();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::SysCall
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::DoSysCall( const idEventDef* event, const UINT_PTR* data ) {
|
|
if ( !sdDLLThread::GetActiveThread()->ProcessEventArgPtr( event, data ) ) {
|
|
gameLocal.Warning( "sdDLLScriptInterface::SysCall Invalid Event '%s'", event->GetName() );
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::SysCall
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::SysCall( const idEventDef* event, const UINT_PTR* data ) {
|
|
DoSysCall( event, data );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::DoEventCall
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::DoEventCall( const idEventDef* event, sdCompiledScript_ClassBase* obj, const UINT_PTR* data ) {
|
|
idScriptObject* scriptObject = GetScriptObject( obj->__S_GetHandle() );
|
|
if ( scriptObject != NULL ) {
|
|
idClass* cls = scriptObject->GetClass();
|
|
|
|
if ( cls != NULL ) {
|
|
if ( !cls->ProcessEventArgPtr( event, data ) ) {
|
|
gameLocal.Warning( "sdDLLScriptInterface::EventCall Invalid Event '%s'", event->GetName() );
|
|
}
|
|
} else {
|
|
gameLocal.Warning( "sdDLLScriptInterface::EventCall Event Call On a NULL Object '%s'", event->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::EventCall
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::EventCall( const idEventDef* event, sdCompiledScript_ClassBase* obj, const UINT_PTR* data ) {
|
|
if ( obj == NULL ) {
|
|
return;
|
|
}
|
|
|
|
DoEventCall( event, obj, data );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::Wait
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::Wait( float time ) {
|
|
sdDLLThread* thread = sdDLLThread::GetActiveThread();
|
|
assert( thread != NULL );
|
|
thread->Wait( time );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::Wait
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::WaitFrame( void ) {
|
|
sdDLLThread* thread = sdDLLThread::GetActiveThread();
|
|
assert( thread != NULL );
|
|
thread->WaitFrame();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedFloat
|
|
================
|
|
*/
|
|
float sdDLLScriptInterface::GetReturnedFloat( void ) {
|
|
return program->GetReturnedFloat();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedBoolean
|
|
================
|
|
*/
|
|
bool sdDLLScriptInterface::GetReturnedBoolean( void ) {
|
|
return program->GetReturnedInteger() != 0 ? true : false;
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedObject
|
|
================
|
|
*/
|
|
sdCompiledScript_ClassBase* sdDLLScriptInterface::GetReturnedObject( void ) {
|
|
idScriptObject* obj = program->GetReturnedObject();
|
|
if ( obj == NULL ) {
|
|
return NULL;
|
|
}
|
|
return reinterpret_cast< sdDLLTypeObject* >( obj->GetObject() )->GetInstance();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedString
|
|
================
|
|
*/
|
|
const char* sdDLLScriptInterface::GetReturnedString( void ) {
|
|
return program->GetReturnedString();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedVector
|
|
================
|
|
*/
|
|
float* sdDLLScriptInterface::GetReturnedVector( void ) {
|
|
return const_cast< float* >( program->GetReturnedVector()->ToFloatPtr() );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedInteger
|
|
================
|
|
*/
|
|
int sdDLLScriptInterface::GetReturnedInteger( void ) {
|
|
return program->GetReturnedInteger();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetReturnedWString
|
|
================
|
|
*/
|
|
const wchar_t* sdDLLScriptInterface::GetReturnedWString( void ) {
|
|
return program->GetReturnedWString();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetScriptObject
|
|
================
|
|
*/
|
|
idScriptObject* sdDLLScriptInterface::GetScriptObject( int handle ) {
|
|
return program->GetScriptObject( handle );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::GetEntity
|
|
================
|
|
*/
|
|
idEntity* sdDLLScriptInterface::GetEntity( int handle ) {
|
|
idScriptObject* object = program->GetScriptObject( handle );
|
|
if ( object == NULL ) {
|
|
return NULL;
|
|
}
|
|
return object->GetClass()->Cast< idEntity >();
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::ReturnString
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::ReturnString( const char* value ) {
|
|
program->ReturnStringInternal( value );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::ReturnWString
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::ReturnWString( const wchar_t* value ) {
|
|
program->ReturnWStringInternal( value );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::ReturnVector
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::ReturnVector( float* value ) {
|
|
program->ReturnVectorInternal( ( const idVec3& ) value );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::ReturnFloat
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::ReturnFloat( float value ) {
|
|
program->ReturnFloat( value );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::ReturnBoolean
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::ReturnBoolean( bool value ) {
|
|
program->ReturnIntegerInternal( value ? 1 : 0 );
|
|
}
|
|
|
|
/*
|
|
================
|
|
sdDLLScriptInterface::ReturnObject
|
|
================
|
|
*/
|
|
void sdDLLScriptInterface::ReturnObject( sdCompiledScript_ClassBase* obj ) {
|
|
program->ReturnObjectInternal( obj ? GetScriptObject( obj->__S_GetHandle() ) : NULL );
|
|
}
|
|
|