643 lines
12 KiB
C++
643 lines
12 KiB
C++
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Logfile:: /Quake 2 Engine/Sin/code/game/class.cpp $
|
|
// $Revision:: 20 $
|
|
// $Author:: Jimdose $
|
|
// $Date:: 10/19/98 12:07a $
|
|
//
|
|
// Copyright (C) 1997 by Ritual Entertainment, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// This source is may not be distributed and/or modified without
|
|
// expressly written permission by Ritual Entertainment, Inc.
|
|
//
|
|
// $Log:: /Quake 2 Engine/Sin/code/game/class.cpp $
|
|
//
|
|
// 20 10/19/98 12:07a Jimdose
|
|
// made all code use fast checks for inheritance (no text lookups when
|
|
// possible)
|
|
// isSubclassOf no longer requires ::_classinfo()
|
|
//
|
|
// 19 10/07/98 11:42p Jimdose
|
|
// Got savegames working
|
|
//
|
|
// 18 9/24/98 1:49a Jimdose
|
|
// Added DisplayMemoryUsage
|
|
//
|
|
// 17 9/21/98 2:15a Jimdose
|
|
// Moved non-type specific code in SafePtr to SafePtrBase to help with save
|
|
// games
|
|
//
|
|
// 16 8/27/98 9:04p Jimdose
|
|
// NumEventCommands is now a member of Event
|
|
//
|
|
// 15 6/27/98 9:18p Jimdose
|
|
// Made lookup for event responses for faster processing
|
|
//
|
|
// 14 6/15/98 9:09p Aldie
|
|
// Fixed checkInheritance printfs
|
|
//
|
|
// 13 5/24/98 4:48p Jimdose
|
|
// Made char *'s const
|
|
//
|
|
// 12 5/11/98 8:06p Jimdose
|
|
// Added SafePtr
|
|
//
|
|
// 11 5/08/98 2:51p Jimdose
|
|
// Added archiving functions
|
|
//
|
|
// 10 3/27/98 6:35p Jimdose
|
|
// made checking of classnames case independant
|
|
//
|
|
// 9 3/23/98 1:31p Jimdose
|
|
// Revamped event and command system
|
|
//
|
|
// 8 3/04/98 1:49p Jimdose
|
|
// Changed overloaded delete so that it used delete[] instead of delete, since
|
|
// we allocate with new[];
|
|
//
|
|
// 7 3/02/98 8:49p Jimdose
|
|
// Changed the classid parameter of CLASS_DECLARATION to a quoted string so
|
|
// that you could have a NULL classid.
|
|
//
|
|
// 6 2/03/98 10:53a Jimdose
|
|
// Updated to work with Quake 2 engine
|
|
// Made class registration automatic
|
|
//
|
|
// 5 1/22/98 6:50p Jimdose
|
|
// Made Q2 compatible
|
|
//
|
|
// 3 10/27/97 3:40p Jimdose
|
|
// Included stdarg.h
|
|
//
|
|
// 2 9/26/97 6:13p Jimdose
|
|
// Added standard Ritual headers
|
|
//
|
|
// DESCRIPTION:
|
|
// Base class that all classes that are used in conjunction with Sin should
|
|
// be based off of. Class gives run-time type information about any class
|
|
// derived from it. This is really handy when you have a pointer to an object
|
|
// that you need to know if it supports certain behaviour.
|
|
//
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include "g_local.h"
|
|
#include "class.h"
|
|
#include "linklist.h"
|
|
|
|
int totalmemallocated = 0;
|
|
int numclassesallocated = 0;
|
|
|
|
static ClassDef *classlist = NULL;
|
|
|
|
ClassDef::ClassDef()
|
|
{
|
|
this->classname = NULL;
|
|
this->classID = NULL;
|
|
this->superclass = NULL;
|
|
this->responses = NULL,
|
|
this->numEvents = 0;
|
|
this->responseLookup = NULL;
|
|
this->newInstance = NULL;
|
|
this->classSize = 0;
|
|
this->super = NULL;
|
|
this->prev = this;
|
|
this->next = this;
|
|
}
|
|
|
|
ClassDef::ClassDef
|
|
(
|
|
const char *classname,
|
|
const char *classID,
|
|
const char *superclass,
|
|
ResponseDef *responses,
|
|
void *( *newInstance )( void ),
|
|
int classSize
|
|
)
|
|
|
|
{
|
|
ClassDef *node;
|
|
|
|
if ( classlist == NULL )
|
|
{
|
|
classlist = new ClassDef;
|
|
}
|
|
|
|
this->classname = classname;
|
|
this->classID = classID;
|
|
this->superclass = superclass;
|
|
this->responses = responses;
|
|
this->numEvents = 0;
|
|
this->responseLookup = NULL;
|
|
this->newInstance = newInstance;
|
|
this->classSize = classSize;
|
|
this->super = getClass( superclass );
|
|
|
|
// It's not uncommon for classes to not have a class id, so just set it
|
|
// to an empty string so that we're not checking for it all the time.
|
|
if ( !classID )
|
|
{
|
|
this->classID = "";
|
|
}
|
|
|
|
// Check if any subclasses were initialized before their superclass
|
|
for( node = classlist->next; node != classlist; node = node->next )
|
|
{
|
|
if ( ( node->super == NULL ) && ( !Q_stricmp( node->superclass, this->classname ) ) &&
|
|
( Q_stricmp( node->classname, "Class" ) ) )
|
|
{
|
|
node->super = this;
|
|
}
|
|
}
|
|
|
|
// Add to front of list
|
|
LL_Add( classlist, this, prev, next );
|
|
}
|
|
|
|
ClassDef::~ClassDef()
|
|
{
|
|
ClassDef *node;
|
|
|
|
if ( classlist != this )
|
|
{
|
|
LL_Remove( this, prev, next );
|
|
|
|
// Check if any subclasses were initialized before their superclass
|
|
for( node = classlist->next; node != classlist; node = node->next )
|
|
{
|
|
if ( node->super == this )
|
|
{
|
|
node->super = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// If the head of the list is deleted before the list is cleared, then we may have problems
|
|
assert( this->next == this->prev );
|
|
}
|
|
|
|
if ( responseLookup )
|
|
{
|
|
delete[] responseLookup;
|
|
responseLookup = NULL;
|
|
}
|
|
}
|
|
|
|
EXPORT_FROM_DLL void ClassDef::BuildResponseList
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
ResponseDef *r;
|
|
int ev;
|
|
int i;
|
|
qboolean *set;
|
|
int num;
|
|
|
|
if ( responseLookup )
|
|
{
|
|
delete[] responseLookup;
|
|
responseLookup = NULL;
|
|
}
|
|
|
|
num = Event::NumEventCommands();
|
|
responseLookup = ( Response ** )new char[ sizeof( Response * ) * num ];
|
|
memset( responseLookup, 0, sizeof( Response * ) * num );
|
|
|
|
set = new qboolean[ num ];
|
|
memset( set, 0, sizeof( qboolean ) * num );
|
|
|
|
this->numEvents = num;
|
|
|
|
for( c = this; c != NULL; c = c->super )
|
|
{
|
|
r = c->responses;
|
|
if ( r )
|
|
{
|
|
for( i = 0; r[ i ].event != NULL; i++ )
|
|
{
|
|
ev = ( int )*r[ i ].event;
|
|
if ( !set[ ev ] )
|
|
{
|
|
set[ ev ] = true;
|
|
if ( r[ i ].response )
|
|
{
|
|
responseLookup[ ev ] = &r[ i ].response;
|
|
}
|
|
else
|
|
{
|
|
responseLookup[ ev ] = NULL;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] set;
|
|
}
|
|
|
|
EXPORT_FROM_DLL void BuildEventResponses
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
int amount;
|
|
int numclasses;
|
|
|
|
amount = 0;
|
|
numclasses = 0;
|
|
for( c = classlist->next; c != classlist; c = c->next )
|
|
{
|
|
c->BuildResponseList();
|
|
|
|
amount += c->numEvents * sizeof( Response * );
|
|
numclasses++;
|
|
}
|
|
|
|
gi.dprintf( "\n------------------\nEvent system initialized:\n"
|
|
"%d classes\n%d events\n%d total memory in response list\n\n",
|
|
numclasses, Event::NumEventCommands(), amount );
|
|
}
|
|
|
|
EXPORT_FROM_DLL ClassDef *getClassForID
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
for( c = classlist->next; c != classlist; c = c->next )
|
|
{
|
|
if ( c->classID && !Q_stricmp( c->classID, name ) )
|
|
{
|
|
return c;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EXPORT_FROM_DLL ClassDef *getClass
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
for( c = classlist->next; c != classlist; c = c->next )
|
|
{
|
|
if ( !Q_stricmp( c->classname, name ) )
|
|
{
|
|
return c;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
EXPORT_FROM_DLL ClassDef *getClassList
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
return classlist;
|
|
}
|
|
|
|
EXPORT_FROM_DLL void listAllClasses
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
for( c = classlist->next; c != classlist; c = c->next )
|
|
{
|
|
gi.dprintf( "%s\n", c->classname );
|
|
}
|
|
}
|
|
|
|
EXPORT_FROM_DLL void listInheritanceOrder
|
|
(
|
|
const char *classname
|
|
)
|
|
|
|
{
|
|
ClassDef *cls;
|
|
ClassDef *c;
|
|
|
|
cls = getClass( classname );
|
|
if ( !cls )
|
|
{
|
|
gi.dprintf( "Unknown class: %s\n", classname );
|
|
return;
|
|
}
|
|
for( c = cls; c != NULL; c = c->super )
|
|
{
|
|
gi.dprintf( "%s\n", c->classname );
|
|
}
|
|
}
|
|
|
|
EXPORT_FROM_DLL qboolean checkInheritance
|
|
(
|
|
ClassDef *superclass,
|
|
ClassDef *subclass
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
for( c = subclass; c != NULL; c = c->super )
|
|
{
|
|
if ( c == superclass )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
EXPORT_FROM_DLL qboolean checkInheritance
|
|
(
|
|
ClassDef *superclass,
|
|
const char *subclass
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
c = getClass( subclass );
|
|
if ( c == NULL )
|
|
{
|
|
gi.dprintf( "Unknown class: %s\n", subclass );
|
|
return false;
|
|
}
|
|
return checkInheritance( superclass, c );
|
|
}
|
|
|
|
EXPORT_FROM_DLL qboolean checkInheritance
|
|
(
|
|
const char *superclass,
|
|
const char *subclass
|
|
)
|
|
|
|
{
|
|
ClassDef *c1;
|
|
ClassDef *c2;
|
|
|
|
c1 = getClass( superclass );
|
|
c2 = getClass( subclass );
|
|
if ( c1 == NULL )
|
|
{
|
|
gi.dprintf( "Unknown class: %s\n", superclass );
|
|
return false;
|
|
}
|
|
if ( c2 == NULL )
|
|
{
|
|
gi.dprintf( "Unknown class: %s\n", subclass );
|
|
return false;
|
|
}
|
|
return checkInheritance( c1, c2 );
|
|
}
|
|
|
|
CLASS_DECLARATION( NULL, Class, NULL );
|
|
|
|
ResponseDef Class::Responses[] =
|
|
{
|
|
{ NULL, NULL }
|
|
};
|
|
|
|
#ifdef NDEBUG
|
|
|
|
EXPORT_FROM_DLL void * Class::operator new( size_t s )
|
|
{
|
|
int *p;
|
|
|
|
s += sizeof( int );
|
|
p = ( int * )::new char[ s ];
|
|
*p = s;
|
|
totalmemallocated += s;
|
|
numclassesallocated++;
|
|
return p + 1;
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Class::operator delete( void *ptr )
|
|
{
|
|
int *p;
|
|
|
|
p = ( ( int * )ptr ) - 1;
|
|
totalmemallocated -= *p;
|
|
numclassesallocated--;
|
|
::delete[]( p );
|
|
}
|
|
|
|
#else
|
|
|
|
EXPORT_FROM_DLL void * Class::operator new( size_t s )
|
|
{
|
|
int *p;
|
|
|
|
s += sizeof( int ) * 3;
|
|
p = ( int * )::new char[ s ];
|
|
p[ 0 ] = 0x12348765;
|
|
*( int * )( ((byte *)p) + s - sizeof( int ) ) = 0x56784321;
|
|
p[ 1 ] = s;
|
|
totalmemallocated += s;
|
|
numclassesallocated++;
|
|
return p + 2;
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Class::operator delete( void *ptr )
|
|
{
|
|
int *p;
|
|
|
|
p = ( ( int * )ptr ) - 2;
|
|
|
|
assert( p[ 0 ] == 0x12348765 );
|
|
assert( *( int * )( ((byte *)p) + p[ 1 ] - sizeof( int ) ) == 0x56784321 );
|
|
|
|
totalmemallocated -= p[ 1 ];
|
|
numclassesallocated--;
|
|
::delete[]( p );
|
|
}
|
|
|
|
#endif
|
|
|
|
EXPORT_FROM_DLL void DisplayMemoryUsage
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
gi.printf( "Classes %-5d Class memory used: %d\n", numclassesallocated, totalmemallocated );
|
|
}
|
|
Class::Class()
|
|
{
|
|
SafePtrList = NULL;
|
|
}
|
|
|
|
Class::~Class()
|
|
{
|
|
while( SafePtrList != NULL )
|
|
{
|
|
SafePtrList->Clear();
|
|
}
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Class::Archive
|
|
(
|
|
Archiver &arc
|
|
)
|
|
|
|
{
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Class::Unarchive
|
|
(
|
|
Archiver &arc
|
|
)
|
|
|
|
{
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Class::warning
|
|
(
|
|
const char *function,
|
|
const char *fmt,
|
|
...
|
|
)
|
|
|
|
{
|
|
va_list argptr;
|
|
char text[ 1024 ];
|
|
|
|
va_start( argptr, fmt );
|
|
vsprintf( text, fmt, argptr );
|
|
va_end( argptr );
|
|
|
|
if ( getClassID() )
|
|
{
|
|
gi.dprintf( "%s::%s : %s\n", getClassID(), function, text );
|
|
}
|
|
else
|
|
{
|
|
gi.dprintf( "%s::%s : %s\n", getClassname(), function, text );
|
|
}
|
|
}
|
|
|
|
EXPORT_FROM_DLL void Class::error
|
|
(
|
|
const char *function,
|
|
const char *fmt,
|
|
...
|
|
)
|
|
|
|
{
|
|
va_list argptr;
|
|
char text[ 1024 ];
|
|
|
|
va_start( argptr, fmt );
|
|
vsprintf( text, fmt, argptr );
|
|
va_end( argptr );
|
|
|
|
if ( getClassID() )
|
|
{
|
|
gi.error( "%s::%s : %s\n", getClassID(), function, text );
|
|
}
|
|
else
|
|
{
|
|
gi.error( "%s::%s : %s\n", getClassname(), function, text );
|
|
}
|
|
}
|
|
|
|
EXPORT_FROM_DLL qboolean Class::inheritsFrom
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
c = getClass( name );
|
|
if ( c == NULL )
|
|
{
|
|
gi.dprintf( "Unknown class: %s\n", name );
|
|
return false;
|
|
}
|
|
return checkInheritance( c, classinfo() );
|
|
}
|
|
|
|
EXPORT_FROM_DLL qboolean Class::isInheritedBy
|
|
(
|
|
const char *name
|
|
)
|
|
|
|
{
|
|
ClassDef *c;
|
|
|
|
c = getClass( name );
|
|
if ( c == NULL )
|
|
{
|
|
gi.dprintf( "Unknown class: %s\n", name );
|
|
return false;
|
|
}
|
|
return checkInheritance( classinfo(), c );
|
|
}
|
|
|
|
EXPORT_FROM_DLL const char *Class::getClassname
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *cls;
|
|
|
|
cls = classinfo();
|
|
return cls->classname;
|
|
}
|
|
|
|
EXPORT_FROM_DLL const char *Class::getClassID
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *cls;
|
|
|
|
cls = classinfo();
|
|
return cls->classID;
|
|
}
|
|
|
|
EXPORT_FROM_DLL const char *Class::getSuperclass
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *cls;
|
|
|
|
cls = classinfo();
|
|
return cls->superclass;
|
|
}
|
|
|
|
EXPORT_FROM_DLL void *Class::newInstance
|
|
(
|
|
void
|
|
)
|
|
|
|
{
|
|
ClassDef *cls;
|
|
|
|
cls = classinfo();
|
|
return cls->newInstance();
|
|
}
|