diff --git a/code/client/skeletor_imports.cpp b/code/client/skeletor_imports.cpp deleted file mode 100644 index 261febb6..00000000 --- a/code/client/skeletor_imports.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -// skeletor_imports.cpp : Skeletor imports - -#include "q_shared.h" -#include "qcommon.h" -#include "dbgheap.h" - -void Skel_DPrintf( const char *fmt, ... ) -{ - char msg[ 4096 ]; - va_list va; - - va_start( va, fmt ); - vsprintf( msg, fmt, va ); - va_end( va ); - - Com_DPrintf( "%s", msg ); -} - -#ifndef _DEBUG_MEM - -void Skel_Free( void *ptr ) -{ - Z_Free( ptr ); -} - -void *Skel_Alloc( size_t size ) -{ - return Z_TagMalloc( size, TAG_SKEL ); -} - -#endif - -void Skel_FreeFile( void *buffer ) -{ - FS_FreeFile( buffer ); -} - -int Skel_ReadFileEx( const char *qpath, void **buffer, qboolean quiet ) -{ - return FS_ReadFileEx( qpath, buffer, quiet ); -} diff --git a/code/game/actor.h b/code/game/actor.h index d0256231..61a914b4 100644 --- a/code/game/actor.h +++ b/code/game/actor.h @@ -28,6 +28,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" #include "simpleactor.h" #include "actorenemy.h" +#include "level.h" +#include "game.h" #include #include #include "grenadehint.h" diff --git a/code/globalcpp/archive.cpp b/code/game/archive.cpp similarity index 99% rename from code/globalcpp/archive.cpp rename to code/game/archive.cpp index 14ce4594..b4052dc7 100644 --- a/code/globalcpp/archive.cpp +++ b/code/game/archive.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "glb_local.h" #include "archive.h" +#include "level.h" #include #ifdef GAME_DLL diff --git a/code/globalcpp/archive.h b/code/game/archive.h similarity index 100% rename from code/globalcpp/archive.h rename to code/game/archive.h diff --git a/code/game/b_files.cpp b/code/game/b_files.cpp deleted file mode 100644 index 87e0329b..00000000 --- a/code/game/b_files.cpp +++ /dev/null @@ -1,487 +0,0 @@ -// -// b_files.c -// - - -#include "b_local.h" - -#if 0 -// -// parse support routines -// - -static qboolean Nav_ParseLiteral( char **data, const char *string ) { - char *token; - - token = COM_ParseExt( data, qtrue ); - if ( token[0] == 0 ) { - gi.Printf( ERROR "unexpected EOF\n" ); - return qtrue; - } - - if ( Q_stricmp( token, string ) ) { - gi.Printf( ERROR "required string '%s' missing\n", string ); - return qtrue; - } - - return qfalse; -} - - -static qboolean Nav_ParseString( char **data, char **s ) { - *s = COM_ParseExt( data, qfalse ); - if ( s[0] == 0 ) { - gi.Printf( ERROR "unexpected EOF\n" ); - return qtrue; - } - return qfalse; -} - - -static qboolean Nav_ParseInt( char **data, int *i ) { - char *token; - - token = COM_ParseExt( data, qfalse ); - if ( token[0] == 0 ) { - gi.Printf( ERROR "unexpected EOF\n" ); - return qtrue; - } - - *i = atoi( token ); - return qfalse; -} - - -// -// bot parameters file : scripts/bots.cfg -// - -char botParms[0x10000]; - - -static int MethodNameToNumber( const char *name ) { - if ( !Q_stricmp( name, "EXPONENTIAL" ) ) { - return METHOD_EXPONENTIAL; - } - if ( !Q_stricmp( name, "LINEAR" ) ) { - return METHOD_LINEAR; - } - if ( !Q_stricmp( name, "LOGRITHMIC" ) ) { - return METHOD_LOGRITHMIC; - } - if ( !Q_stricmp( name, "ALWAYS" ) ) { - return METHOD_ALWAYS; - } - if ( !Q_stricmp( name, "NEVER" ) ) { - return METHOD_NEVER; - } - - return -1; -} - - -static int ItemNameToNumber( const char *name, int itemType ) { - int n; - - for ( n = 0; n < bg_numItems; n++ ) { - if ( bg_itemlist[n].type != itemType ) { - continue; - } - if ( Q_stricmp( bg_itemlist[n].classname, name ) == 0 ) { - return bg_itemlist[n].tag; - } - } - - return -1; -} - - -void Bot_ParseParms( const char *botName, gentity_t *bot, char *userinfo ) { - char *token; - char *value; - char *p; - int n; - int count; - - if ( !botName || !botName[0]) { - botName = "Player"; - } - - strcpy( userinfo, "\\name\\" ); - strcat( userinfo, botName ); - - // fill in defaults - bot->bot->reactions = 3; - bot->bot->aim = 3; - bot->bot->move = 3; - bot->bot->aggression = 3; - bot->bot->intelligence = 3; - bot->bot->hfov = 90 / 2; - bot->bot->vfov = 68 / 2; - bot->bot->healthMethod = METHOD_LOGRITHMIC; - bot->bot->armorMethod = METHOD_LINEAR; - bot->bot->ammoMethod = METHOD_EXPONENTIAL; - bot->bot->allWeaponOrder[0] = WP_BFG; - bot->bot->allWeaponOrder[1] = WP_ROCKET_LAUNCHER; - bot->bot->allWeaponOrder[2] = WP_RAILGUN; - bot->bot->allWeaponOrder[3] = WP_PLASMAGUN; - bot->bot->allWeaponOrder[4] = WP_GRENADE_LAUNCHER; - bot->bot->allWeaponOrder[5] = WP_SHOTGUN; - bot->bot->allWeaponOrder[6] = WP_MACHINEGUN; - bot->bot->allWeaponOrder[7] = WP_NONE; - - p = botParms; - COM_BeginParseSession(); - - // look for the right bot - while ( p ) { - token = COM_ParseExt( &p, qtrue ); - if ( token[0] == 0 ) - return; - - if ( !Q_stricmp( token, botName ) ) { - break; - } - - SkipBracedSection( &p ); - } - if ( !p ) { - return; - } - - if ( Nav_ParseLiteral( &p, "{" ) ) { - return; - } - - // parse the bot info block - while ( 1 ) { - token = COM_ParseExt( &p, qtrue ); - if ( !token[0] ) { - gi.Printf( "ERROR: unexpected EOF while parsing '%s'\n", botName ); - return; - } - - if ( !Q_stricmp( token, "}" ) ) { - break; - } - - // model - if ( !Q_stricmp( token, "model" ) ) { - if ( Nav_ParseString( &p, &value ) ) { - continue; - } - strcat ( userinfo, "\\model\\" ); - strcat ( userinfo, value ); - continue; - } - - // reactions - if ( !Q_stricmp( token, "reactions" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 1 || n > 5 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->reactions = n; - continue; - } - - // aim - if ( !Q_stricmp( token, "aim" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 1 || n > 5 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->aim = n; - continue; - } - - // move - if ( !Q_stricmp( token, "move" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 1 || n > 5 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->move = n; - continue; - } - - // aggression - if ( !Q_stricmp( token, "aggression" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 1 || n > 5 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->aggression = n; - continue; - } - - // intelligence - if ( !Q_stricmp( token, "intelligence" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 1 || n > 5 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->intelligence = n; - continue; - } - - // hfov - if ( !Q_stricmp( token, "hfov" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 30 || n > 180 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->hfov = n / 2; - continue; - } - - // vfov - if ( !Q_stricmp( token, "vfov" ) ) { - if ( Nav_ParseInt( &p, &n ) ) { - SkipRestOfLine( &p ); - continue; - } - if ( n < 30 || n > 180 ) { - gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->vfov = n / 2; - continue; - } - - // healthMethod - if ( !Q_stricmp( token, "healthMethod" ) ) { - if ( Nav_ParseString( &p, &value ) ) { - continue; - } - n = MethodNameToNumber( value ); - if ( n == -1 ) { - gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->healthMethod = n; - continue; - } - - // armorMethod - if ( !Q_stricmp( token, "armorMethod" ) ) { - if ( Nav_ParseString( &p, &value ) ) { - continue; - } - n = MethodNameToNumber( value ); - if ( n == -1 ) { - gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->armorMethod = n; - continue; - } - - // ammoMethod - if ( !Q_stricmp( token, "ammoMethod" ) ) { - if ( Nav_ParseString( &p, &value ) ) { - continue; - } - n = MethodNameToNumber( value ); - if ( n == -1 ) { - gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->ammoMethod = n; - continue; - } - - // weapons - if ( !Q_stricmp( token, "weapons" ) ) { - for ( count = 0; count < MAX_WEAPONS; count++ ) { - if ( Nav_ParseString( &p, &value ) ) { - break; - } - if ( *value == 0 ) { - break; - } - n = ItemNameToNumber( value, IT_WEAPON ); - if ( n == -1 ) { - gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); - continue; - } - bot->bot->allWeaponOrder[count] = n; - } - if ( count < MAX_WEAPONS ) { - bot->bot->allWeaponOrder[count] = WP_NONE; - } - continue; - } - - // snd - if ( !Q_stricmp( token, "snd" ) ) { - if ( Nav_ParseString( &p, &value ) ) { - continue; - } - strcat( userinfo, "\\snd\\" ); - strcat( userinfo, value ); - continue; - } - - gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, botName ); - SkipRestOfLine( &p ); - } -} - - -void Bot_LoadParms( void ) { - int len; - char filename[MAX_QPATH]; - char *buffer; - - sprintf( filename, "scripts/bots.cfg" ); - gi.Printf( "Parsing %s\n", filename ); - len = gi.FS_ReadFile( filename, &buffer, qtrue ); - if ( len == -1 ) { - gi.Printf( "file not found\n" ); - } - - if ( len >= sizeof( botParms ) ) { - gi.Error( ERR_DROP, "scripts/bots.cfg is too large" ); - } - strncpy( botParms, buffer, sizeof( botParms ) - 1 ); - gi.FS_FreeFile( buffer ); -} -#endif - - -// -// navigation data : maps/*.nav -// - -void Nav_LoadRoutes( void ) { - int len; - navheader_t *header; - int value; - int n; - str filename; - - Swap_Init(); - - surfaceCount = 0; - surface = NULL; - neighborCount = 0; - neighbor = NULL; - - // load the file - filename = "maps/"; - filename += level.mapname + ".nav"; - - gi.Printf( "Loading %s\n", filename.c_str() ); - len = gi.FS_ReadFile( filename.c_str(), ( void ** )&navFileData, qtrue ); - if ( len == -1 ) { - gi.Printf( WARNING "no navigation data\n" ); - return; - } - if ( len < sizeof( navheader_t ) ) { - gi.Printf( ERROR "no nav file header\n" ); - goto cleanup; - } - - // process the header - header = (navheader_t *)navFileData; - header->id = LittleLong( header->id ); - header->version = LittleLong( header->version ); - header->surfaceCount = LittleLong( header->surfaceCount ); - header->neighborCount = LittleLong( header->neighborCount ); - - // validate the header fields - if ( header->id != NAVFILE_ID ) { - gi.Printf( ERROR "incorrect nav file id\n" ); - goto cleanup; - } - if ( header->version != NAVFILE_VERSION ) { - gi.Printf( ERROR "incorrect nav file version (%i, should be %i)\n", header->version, NAVFILE_VERSION ); - goto cleanup; - } - - value = /* header */ sizeof( navheader_t ) + - /* surfaces */ header->surfaceCount * sizeof( nsurface_t ) + - /* neighbors */ header->neighborCount * sizeof( nneighbor_t ) + - /* routes */ header->surfaceCount * header->surfaceCount * sizeof( byte ); - - if ( value != len ) { - gi.Printf( ERROR "incorrect nav file length (%i, should be %i)\n", len, value ); - goto cleanup; - } - - surfaceCount = header->surfaceCount; - neighborCount = header->neighborCount; - - // process surfaces - surface = (nsurface_t *)(navFileData + sizeof( navheader_t ) ); - for ( n = 0; n < surfaceCount; n++ ) { - surface[n].origin[0] = LittleFloat( surface[n].origin[0] ); - surface[n].origin[1] = LittleFloat( surface[n].origin[1] ); - surface[n].origin[2] = LittleFloat( surface[n].origin[2] ); - - surface[n].absmin[0] = LittleFloat( surface[n].absmin[0] ); - surface[n].absmin[1] = LittleFloat( surface[n].absmin[1] ); - - surface[n].absmax[0] = LittleFloat( surface[n].absmax[0] ); - surface[n].absmax[1] = LittleFloat( surface[n].absmax[1] ); - - surface[n].flags = LittleLong( surface[n].flags ); - surface[n].neighborCount = LittleLong( surface[n].neighborCount ); - surface[n].neighborIndex = LittleLong( surface[n].neighborIndex ); - surface[n].parm = LittleLong( surface[n].parm ); - } - - // process neighbors - neighbor = (nneighbor_t *)((byte *)surface + surfaceCount * sizeof( nsurface_t )); - for ( n = 0; n < neighborCount; n++ ) { - neighbor[n].origin[0] = LittleFloat( neighbor[n].origin[0] ); - neighbor[n].origin[1] = LittleFloat( neighbor[n].origin[1] ); - neighbor[n].origin[2] = LittleFloat( neighbor[n].origin[2] ); - - neighbor[n].absmin[0] = LittleFloat( neighbor[n].absmin[0] ); - neighbor[n].absmin[1] = LittleFloat( neighbor[n].absmin[1] ); - - neighbor[n].absmax[0] = LittleFloat( neighbor[n].absmax[0] ); - neighbor[n].absmax[1] = LittleFloat( neighbor[n].absmax[1] ); - - neighbor[n].surfaceNum = LittleLong( neighbor[n].surfaceNum ); - neighbor[n].flags = LittleLong( neighbor[n].flags ); - neighbor[n].cost = LittleLong( neighbor[n].cost ); - neighbor[n].filler = LittleLong( neighbor[n].filler ); - } - - // process routes - route = (byte *)neighbor + neighborCount * sizeof( nneighbor_t ); - - gi.Printf( "...loaded %i surfaces and %i neighbors\n", surfaceCount, neighborCount ); - return; - -cleanup: - gi.FS_FreeFile ( navFileData ); - navFileData = NULL; -} diff --git a/code/game/b_local.h b/code/game/b_local.h deleted file mode 100644 index 6c1284b6..00000000 --- a/code/game/b_local.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifndef __B_LOCAL_H__ -#define __B_LOCAL_H__ - -#include "g_local.h" - -// -// This section should be moved to QFILES.H -// - -#define NAVFILE_ID (('I')+('N'<<8)+('A'<<16)+('V'<<24)) -#define NAVFILE_VERSION 2 - -typedef struct { - unsigned id; - unsigned version; - unsigned surfaceCount; - unsigned neighborCount; -} navheader_t; - - -#define MAX_SURFACES 4096 - -#define SF_PUSH 0x00000001 -#define SF_WATERLEVEL1 0x00000002 -#define SF_WATERLEVEL2 0x00000004 -#define SF_WATER_NOAIR 0x00000008 -#define SF_DUCK 0x00000010 -#define SF_PAIN 0x00000020 -#define SF_TELEPORTER 0x00000040 -#define SF_PLATHIGH 0x00000080 -#define SF_PLATLOW 0x00000100 - -typedef struct { - vec3_t origin; - vec2_t absmin; - vec2_t absmax; - int parm; - unsigned flags; - unsigned neighborCount; - unsigned neighborIndex; -} nsurface_t; - - -#define MAX_NEIGHBORS 16384 - -#define NF_JUMP 0x00000001 -#define NF_DUCK 0x00000002 -#define NF_PLAT 0x00000004 -#define NF_FALL1 0x00000008 -#define NF_FALL2 0x00000010 - -typedef struct { - vec3_t origin; - vec2_t absmin; // region within this surface that is the portal to the other surface - vec2_t absmax; - int surfaceNum; - unsigned flags; // jump, prerequisite button, will take falling damage, etc... - float cost; - unsigned filler; // to be used as a "string index" into an array of targetnames for buttons, etc -} nneighbor_t; - -#define WARNING "\033" "3" "WARNING: " -#define ERROR "\033" "1" "ERROR: " - - -// file buffers - -extern char botParms[0x10000]; -extern char *navFileData; - - -// -// Navigation susbsystem -// - -#define NAVF_DUCK 0x00000001 -#define NAVF_JUMP 0x00000002 -#define NAVF_HOLD 0x00000004 -#define NAVF_SLOW 0x00000008 - -#define METHOD_EXPONENTIAL 1 -#define METHOD_LINEAR 2 -#define METHOD_LOGRITHMIC 3 -#define METHOD_ALWAYS 4 -#define METHOD_NEVER 5 - -// combat maneuvers -#define CM_NONE 0 - -#define CM_CLOSE_DISTANCE 1 -#define CM_OPEN_DISTANCE 2 -#define CM_HOLD_DISTANCE 3 - -#define CM_GET_ITEM 4 -#define CM_RUN_AWAY 5 - -#define CM_CIRCLE 6 -#define CM_DUCK 7 - -typedef enum {SPOT_ORIGIN, SPOT_HEAD, SPOT_WEAPON, SPOT_LEGS, SPOT_GROUND} spot_t; - -#define BOT_TIME_TO_LOSE_SIGHT 2000 - -#define SF_FROMMAPFILE 0x80000000 - -#define DEBUG_LEVEL_DETAIL 4 -#define DEBUG_LEVEL_INFO 3 -#define DEBUG_LEVEL_WARNING 2 -#define DEBUG_LEVEL_ERROR 1 -#define DEBUG_LEVEL_NONE 0 - - -// -// b_main.c -// -void Debug_Printf( cvar_t *cv, int level, char *fmt, ... ); -void Debug_BotPrintf( gentity_t *bot, cvar_t *cv, int debugLevel, char *fmt, ... ); - - -// -// b_ai.c -// -extern cvar_t *debugBotAI; -extern cvar_t *debugBotFreeze; - -void Bot_InitAI( void ); -void Bot_Pain( gentity_t *bot, gentity_t *other, int damage ); -void Bot_Touch( gentity_t *bot, gentity_t *other, trace_t *trace ); -void BotSpawn( gentity_t *bot ); -void Bot_Fetch_f( void ); - -// -// b_nav.c -// -extern char *navFileData; -extern int surfaceCount; -extern nsurface_t *surface; -extern int neighborCount; -extern nneighbor_t *neighbor; -extern byte *route; - - -void Nav_InitPreSpawn( void ); -void Nav_InitPostSpawn( void ); -void Nav_Shutdown( void ); -void Nav_ShowPath( gentity_t *bot ); -int Nav_GroundSurfaceNumber( gentity_t *ent ); -int Nav_ItemSurfaceNumber( gentity_t *ent ); -int Nav_EntitySurfaceNumber( gentity_t *ent ); -int Nav_MoveToGoal( gentity_t *bot, vec3_t dir, int *flags ); - -// -// b_items.c -// -void Nav_InitRoamList( void ); -qboolean WeaponIsOnLevel( int weapon ); -gentity_t *Nav_ChooseRoamGoal( void ); - -// -// b_files.c -// -void Bot_ParseParms( const char *botName, gentity_t *bot, char *userinfo ); -void Bot_LoadParms( void ); -void Nav_LoadRoutes( void ); -void Nav_SaveRoutes( void ); - -#endif diff --git a/code/game/b_nav.cpp b/code/game/b_nav.cpp deleted file mode 100644 index 2bc70b1d..00000000 --- a/code/game/b_nav.cpp +++ /dev/null @@ -1,632 +0,0 @@ - -// -// b_nav.c -// - -//FIXME make botInfo, etc visible here too and get rid of all the mutliple dereferences like bot->bot-> - -#include "b_local.h" - - -#define NAVF_EDGEZONE 0x00000001 - -#define INFINITE 1000000 - -#define BOTAI_PUSHED (1<<0) - -cvar_t *nav_showsectors; - -char *navFileData; - -int surfaceCount; -nsurface_t *surface; -int neighborCount; -nneighbor_t *neighbor; -byte *route; - -//#if 0 - -static int spawnpadModelIndex; - - -int Nav_SurfaceUnderPlayer( gentity_t *player ) { - vec3_t start; - vec3_t end; - vec3_t p; - trace_t tr; - float bestDist; - int bestSurf; - vec3_t v; - int n; - float dist; - - VectorCopy( player->s.origin, start ); - VectorCopy( player->s.origin, end ); - end[2] -= 4096; - - gi.trace ( &tr, start, player->mins, player->maxs, end, player->s.number, MASK_DEADSOLID, true ); - -// p[0] = ((int)tr.endpos[0] + 8) & (~16); -// p[1] = ((int)tr.endpos[1] + 8) & (~16); - p[0] = tr.endpos[0]; - p[1] = tr.endpos[1]; - p[2] = floor(tr.endpos[2]+player->mins[2]); - - bestDist = INFINITE; - bestSurf = -1; - - for ( n = 0; n < surfaceCount; n++ ) { - if ( Q_fabs( surface[n].origin[2] - p[2] ) > 24 ) { - continue; - } - - VectorSubtract( p, surface[n].origin, v ); - dist = VectorLength( v ); - if ( dist < bestDist ) { - bestDist = dist; - bestSurf = n; - } - - if ( surface[n].origin[2] != p[2] ) { - continue; - } - if ( surface[n].absmin[0] > p[0] ) { - continue; - } - if ( surface[n].absmax[0] < p[0] ) { - continue; - } - if ( surface[n].absmin[1] > p[1] ) { - continue; - } - if ( surface[n].absmax[1] < p[1] ) { - continue; - } - return n; - } - -// gi.Printf( "guess for %s at %s\n", ent->classname, vtos( p ) ); - return bestSurf; -} - - -/* -============= -Nav_GroundSurfaceNumber - -Returns the surface number for where an entity is currently located. -If the entity is not on the ground, it returns -1. - -FIXME we can make this more efficient - right now surfaces are in Z sorted order - we could make a Z index and binary search it to get to right z group fast -============= -*/ -int Nav_GroundSurfaceNumber( gentity_t *ent ) { - vec3_t p; - vec3_t v; - int n; - float dist; - float bestDist; - int bestSurf; - gentity_t *groundEntity; - - // if ent is not on the ground it is not on a surface - if ( ent->s.groundEntityNum == -1 ) { - return -1; - } - -// p[0] = ((int)ent->s.origin[0] + 8) & (~16); -// p[1] = ((int)ent->s.origin[1] + 8) & (~16); - p[0] = ent->s.origin[0]; - p[1] = ent->s.origin[1]; - p[2] = floor(ent->s.origin[2]+ent->mins[2]); - - // if ground is not the world we need to handle it differently. - if ( ent->s.groundEntityNum != ENTITYNUM_WORLD ) { - groundEntity = &g_entities[ent->s.groundEntityNum]; - - // check for sitting on a spawn pad - if ( !groundEntity->bmodel && groundEntity->s.modelindex == spawnpadModelIndex ) { - p[2] -= 8.0; - } - // check for plats - /* else if ( groundEntity->bmodel && Q_stricmp( groundEntity->classname, "func_plat" ) == 0 ) { - // if at the top the return PLATHIGH surface number, otherwise return PLATLOW surface number - if ( VectorCompare( groundEntity->currentOrigin, groundEntity->pos2 ) ) { - return surface[groundEntity->navSurfaceNum].parm; - } - return groundEntity->navSurfaceNum; - } */ - } - - bestDist = INFINITE; - bestSurf = -1; - - for ( n = 0; n < surfaceCount; n++ ) { - if ( Q_fabs( surface[n].origin[2] - p[2] ) > 24 ) { - continue; - } - - VectorSubtract( p, surface[n].origin, v ); - dist = VectorLength( v ); - if ( dist < bestDist ) { - bestDist = dist; - bestSurf = n; - } - - if ( surface[n].origin[2] != p[2] ) { - continue; - } - if ( surface[n].absmin[0] > p[0] ) { - continue; - } - if ( surface[n].absmax[0] < p[0] ) { - continue; - } - if ( surface[n].absmin[1] > p[1] ) { - continue; - } - if ( surface[n].absmax[1] < p[1] ) { - continue; - } - return n; - } - -// gi.Printf( "guess for %s at %s\n", ent->classname, vtos( p ) ); - return bestSurf; -} - - -/* -============= -Nav_ItemSurfaceNumber - -Returns the surface number for where an item entity is currently located. -If the entity is not on the ground, it returns -1. This is a specialized -copy of Nav_GroundSurfaceNumber for items that caches the result. -============= -*/ -int Nav_ItemSurfaceNumber( gentity_t *ent ) { - if ( !VectorCompare( ent->s.origin, ent->navOrigin ) && level.time > ent->navTime ) { - VectorCopy( ent->s.origin, ent->navOrigin ); - ent->navTime = level.time; - ent->navSurfaceNum = Nav_GroundSurfaceNumber( ent ); - } - return ent->navSurfaceNum; -} - - -/* -============= -Nav_EntitySurfaceNumber -============= -*/ -int Nav_EntitySurfaceNumber( gentity_t *ent ) { - if ( ent->s.eType == ET_ITEM ) { - return Nav_ItemSurfaceNumber( ent ); - } - - /*if ( ent->classname&& strcmp( ent->classname, "bot_goal" ) == 0 ) { - return Nav_SurfaceUnderPlayer( ent ); - }*/ - - return Nav_GroundSurfaceNumber( ent ); -} - - -/* -============= -PathEdge -============= -*/ - -static nneighbor_t *PathEdge( int sourceSurfNum, int destSurfNum ) { - int base; - int n; - - base = surface[sourceSurfNum].neighborIndex; - for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) { - if ( neighbor[base+n].surfaceNum == destSurfNum ) { - return &neighbor[base+n]; - } - } - return NULL; -} - -/* -============= -PointIsInEdgeRegion -============= -*/ - -static qboolean PointIsInEdgeRegion( vec3_t p, nneighbor_t *n ) { - if ( p[0] < n->absmin[0] ) { - return qfalse; - } - if ( p[0] > n->absmax[0] ) { - return qfalse; - } - if ( p[1] < n->absmin[1] ) { - return qfalse; - } - if ( p[1] > n->absmax[1] ) { - return qfalse; - } - return qtrue; -} - - - -/* -============= -Nav_MoveToGoal -============= -*/ - -int Nav_MoveToGoal( gentity_t *bot, vec3_t dir, int *flags ) { - int currentSurf; - int nextSurf; - int thirdSurf; - int goalSurf; - int routeIndex; - nneighbor_t *edge; - nneighbor_t *nextEdge; - //gentity_t *ent; - //float dist; - - *flags = 0; - VectorCopy( bot->navDir, dir ); - - currentSurf = bot->currentSurface; - - // if bot is airborne, just keep heading the same - if ( currentSurf == -1 ) { - if ( bot->aiFlags & BOTAI_PUSHED ) { - //gi.Printf( "bot was bounced\n" ); - *flags |= NAVF_HOLD; - } - //gi.Printf( "not on ground\n" ); - return 0; - } - if ( bot->pushedTime < level.time ) { - bot->aiFlags &= ~BOTAI_PUSHED; - } - - if ( !bot->goalEntity ) { -// gi.Printf( ERROR "Nav_MoveToGoal called with no goalEntity set\n" ); - return -1; - } - - goalSurf = Nav_EntitySurfaceNumber( bot->goalEntity ); - if ( goalSurf == -1 ) { - return -1; - } - - // if we've changed surfaces, the surface to surface navigation flags and timer need to be cleared - if ( currentSurf != bot->lastSurface ) { - bot->navFlags = 0; - bot->navTime = 0; - //gi.Printf( "surface changed from %i to %i\n", bot->bot->lastSurface, bot->bot->currentSurface ); - } - - if ( currentSurf == goalSurf ) { - //gi.Printf( "On target surface\n" ); - VectorSubtract( bot->goalEntity->s.origin, bot->s.origin, dir ); - //VectorCopy( dir, bot->bot->navDir ); - VectorCopy( dir, bot->navDir ); - return 0; - } - - routeIndex = route[currentSurf * surfaceCount + goalSurf]; - if ( routeIndex == 255 ) { - //gi.Printf( "Nav_MoveToGoal - no known route from %i to %i\n", currentSurf, goalSurf ); - return -1; - } - if ( routeIndex >= surface[currentSurf].neighborCount ) { - gi.Printf( ERROR "Nav_MoveToGoal - bad routeIndex\n" ); - return -1; - } - nextSurf = neighbor[surface[currentSurf].neighborIndex + routeIndex].surfaceNum; - - edge = PathEdge( currentSurf, nextSurf ); - if ( !edge ) { - gi.Printf( ERROR "Nav_MoveToGoal - %i does not have %i as a neighbor\n", currentSurf, nextSurf ); - VectorClear( dir ); - return -1; - } - - if ( ! ( bot->navFlags & NAVF_EDGEZONE ) ) { - if ( PointIsInEdgeRegion( bot->s.origin, edge ) ) { - //gi.Printf( "hit edge\n" ); - bot->navFlags |= NAVF_EDGEZONE; - bot->navTime = level.time; - } - } - - // if we are in the edge zone - if ( bot->navFlags & NAVF_EDGEZONE ) { - // if we're trying to get onto a plat, we must make sure it's there - /*if ( surface[nextSurf].flags & SF_PLATLOW ) { - ent = &g_entities[surface[surface[nextSurf].parm].parm]; //FIXME this works for now, but I don't like it - if ( VectorCompare( ent->currentOrigin, ent->pos1 ) == 0 ) { - *flags |= NAVF_HOLD; - //gi.Printf(" wait for plat2\n" ); - } - }*/ - - // if we're riding up on a plat, we don't need to move - if ( surface[nextSurf].flags & SF_PLATHIGH ) { - *flags |= NAVF_HOLD; - //gi.Printf(" hold on plat\n" ); - } - - // if the next surface contains the goalEntity, head towards it - if ( nextSurf == goalSurf ) { - //gi.Printf( "next surf has goal - targeting directly\n" ); - VectorSubtract( bot->goalEntity->s.origin, bot->s.origin, dir ); - //VectorCopy( dir, bot->bot->navDir ); - VectorCopy( dir, bot->navDir ); - } - // start heading towards the next edge - else { - routeIndex = route[nextSurf * surfaceCount + goalSurf]; - if ( routeIndex == 255 ) { - gi.Printf( ERROR "Nav_MoveToGoal - no known route from %i to %i\n", nextSurf, goalSurf ); - return -1; - } - if ( routeIndex >= surface[nextSurf].neighborCount ) { - gi.Printf( ERROR "Nav_MoveToGoal - bad routeIndex\n" ); - return -1; - } - thirdSurf = neighbor[surface[nextSurf].neighborIndex + routeIndex].surfaceNum; - nextEdge = PathEdge( nextSurf, thirdSurf ); - if ( !nextEdge ) { - gi.Printf( ERROR "Nav_MoveToGoal - %i does not have %i as a neighbor\n", nextSurf, thirdSurf ); - VectorClear( dir ); - return -1; - } - //gi.Printf( "targeting next edge\n" ); - if ( surface[nextSurf].flags & SF_PLATHIGH ) { - VectorSubtract( nextEdge->origin, surface[nextSurf].origin, dir ); - } - else { - VectorSubtract( nextEdge->origin, bot->s.origin, dir ); - } - //VectorCopy( dir, bot->bot->navDir ); - VectorCopy( dir, bot->navDir ); - } - - if ( edge->flags & NF_DUCK ) { - *flags |= NAVF_DUCK; - } - if ( edge->flags & NF_JUMP ) { - *flags |= NAVF_JUMP; - } - } - else { - VectorSubtract( edge->origin, bot->s.origin, dir ); - //VectorCopy( dir, bot->bot->navDir ); - VectorCopy( dir, bot->navDir ); - - /*if ( surface[nextSurf].flags & SF_PLATLOW ) { - ent = &g_entities[surface[surface[nextSurf].parm].parm]; //FIXME this works for now, but I don't like it - if ( VectorCompare( ent->currentOrigin, ent->pos1 ) == 0 ) { - dist = VectorLength( dir ); - if ( dist > 64 ) { - *flags |= NAVF_SLOW; - //gi.Printf(" slow for plat\n" ); - } - else { - *flags |= NAVF_HOLD; - //gi.Printf(" wait for plat\n" ); - } - } - }*/ - } - - return 0; -} - - -void Nav_ShowPath( gentity_t *bot ) { -#if 0 - gentity_t *tent; - int m, n; - - if ( !bot->bot->goalEntity ) { - return; - } - - tent = G_TempEntity( bot->s.origin, EV_DEBUG_LINE ); - VectorCopy( bot->bot->currentWaypoint->s.origin, tent->s.origin2 ); - - m = bot->bot->currentWaypoint->count; - for (;;) { - if ( m == bot->bot->finalWaypoint->count ) { - break; - } - n = route[m*maxwaypoints+bot->bot->finalWaypoint->count]; - if ( n == -1 ) { - break; - } - tent = G_TempEntity( rents[m]->s.origin, EV_DEBUG_LINE ); - VectorCopy( rents[n]->s.origin, tent->s.origin2 ); - m = n; - } - - if ( bot->bot->finalWaypoint != bot->bot->goalEntity ) { - tent = G_TempEntity( bot->bot->finalWaypoint->s.origin, EV_DEBUG_LINE ); - VectorCopy( bot->bot->goalEntity->s.origin, tent->s.origin2 ); - } -#endif - /* gentity_t *tent; - int m, n; - gentity_t *player; - int pSurf; - - player = &g_entities[1]; - pSurf = Nav_GroundSurfaceNumber( player ); - - tent = G_TempEntity( player->s.origin, EV_DEBUG_LINE ); - VectorCopy( surface[pSurf].origin, tent->s.origin2 ); */ -} -//#endif - - -/* -// Init and Shutdown -// -// -*/ - -static void Nav_Cleanup( void ) { - if ( navFileData ) { - gi.FS_FreeFile ( navFileData ); - navFileData = NULL; - } - surfaceCount = 0; - neighborCount = 0; -} - -void Nav_InitPreSpawn( void ) { - nav_showsectors = gi.cvar( "nav_showsectors", "0", 0 ); - Nav_Cleanup(); - Nav_LoadRoutes(); -} - -void Nav_InitPostSpawn( void ) { -#if 0 - int n; - nsurface_t *s; - gentity_t *ent; - - // FIXME resolve targetnames here (like button needed to open a door) - - // get the modelindex for the spawnpad model so we can use it for surface determination - spawnpadModelIndex = G_ModelIndex( "models/objects/dmspot.md3" ); - - // set the navSurface for plats - for ( n = 0; n < surfaceCount; n++ ) { - s = &surface[n]; - if ( s->flags & SF_PLATLOW ) { - ent = &g_entities[surface[s->parm].parm]; //FIXME this works for now, but I don't like it - ent->navSurfaceNum = n; - } - } -#endif -} - - -void Nav_Shutdown ( void ) { - Nav_Cleanup(); -} - -void Nav_Test_f( void ) { -#if 0 - gentity_t *player; - gentity_t *goal; - char *goalname; - int pSurf; - int gSurf; - int cSurf; - int n; - gentity_t *tent; - - player = &g_entities[0]; - pSurf = Nav_GroundSurfaceNumber( player ); - - goalname = gi.argv(2); - if ( !goalname[0] ) { - gi.Printf( "Player1 is at (%f, %f, %f) on surface %i\n", player->s.origin[0], player->s.origin[1], player->s.origin[2] + player->mins[2], pSurf ); - return; - } - - goal = NULL; - goal = G_Find( goal, FOFS( classname ), goalname ); - if ( !goal ) { - gi.Printf( "no %s on level\n", goalname ); - return; - } - gSurf = Nav_EntitySurfaceNumber( goal ); - - - cSurf = pSurf; - while ( cSurf != gSurf ) { - n = route[cSurf * surfaceCount + gSurf]; - if ( n == 255 ) { - //gi.Printf( "no known route from %i to %i\n", cSurf, gSurf ); - return; - } - if ( n >= surface[cSurf].neighborCount ) { - gi.Printf( ERROR "bad routeIndex\n" ); - return; - } - n = neighbor[surface[cSurf].neighborIndex + n].surfaceNum; - - if ( cSurf == pSurf ) { - tent = G_TempEntity( player->s.origin, EV_DEBUG_LINE ); - } - else { - tent = G_TempEntity( surface[cSurf].origin, EV_DEBUG_LINE ); - } - if ( n == gSurf ) { - VectorCopy( goal->s.origin, tent->s.origin2 ); - } - else { - VectorCopy( surface[n].origin, tent->s.origin2 ); - } - - cSurf = n; - } -#endif -} - -void Nav_Gen_f( void ); - -void Cmd_Nav_f( void ) -{ - char *cmd; - - cmd = gi.argv(1); - - if ( Q_stricmp ( cmd, "gen" ) == 0 ) { - Nav_Gen_f(); - Nav_InitPreSpawn(); - } - else if ( Q_stricmp ( cmd, "test" ) == 0 ) { - Nav_Test_f(); - } - else { - gi.Printf("Unknown nav command '%s'\n", cmd); - } -} - -void Nav_ShowStuff - ( - void - ) - - { - int i; - nsurface_t *surf; - - if ( !nav_showsectors->integer ) - { - return; - } - - G_Color4f( 1, 1, 0, 1 ); - for( i = 0; i < surfaceCount; i++ ) - { - surf = &surface[ i ]; - - G_BeginLine(); - G_Vertex( Vector( surf->absmin[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) ); - G_Vertex( Vector( surf->absmin[ 0 ], surf->absmax[ 1 ], surf->origin[ 2 ] ) ); - G_Vertex( Vector( surf->absmax[ 0 ], surf->absmax[ 1 ], surf->origin[ 2 ] ) ); - G_Vertex( Vector( surf->absmax[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) ); - G_Vertex( Vector( surf->absmin[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) ); - G_EndLine(); - } - } diff --git a/code/game/b_navgen.cpp b/code/game/b_navgen.cpp deleted file mode 100644 index 65b18374..00000000 --- a/code/game/b_navgen.cpp +++ /dev/null @@ -1,3089 +0,0 @@ -// -// b_navgen.c -// - -/* -Path costs - time is the cost basis - For normal paths: take dist(sSurf.origin->edge + pmoveEndSpot->tSurf.origin) and - divide by speed to get time. Adjust for duck/wade/swim. Add on time used for - the pmoves to get from edge to pmoveEndspot. - Teleporter: fixed cost of teleport delay (currently 160ms, should be a shared define) - Plats: take vertical distance and divide by plat speed to get move time; add on - any delays (this assumes plats are always at bottom waiting for us) - Trains: ??? -*/ - -/* -FIXME for Q3MAP - When done in game, plates are seen at their low position. Once this is in Q3MAP they will - be seen in their high position requiring a bit of rework of that code. I've noted most of it. -*/ - - -#include -#include "b_local.h" -#include "mover.h" - - -// these defines are placeholders for when this code moves into Q3MAP and is multithreaded -#define ThreadLock() -#define ThreadUnlock() - -#define INFINITE 1000000 - -// these defines MUST match those in bg_pmove!!! -#define MIN_WALK_NORMAL 0.7 -#define STEPSIZE 18 -#define DEFAULT_VIEWHEIGHT 26 -#define CROUCH_VIEWHEIGHT 12 - -#define DUCKSCALE 0.25 -#define SWIMSCALE 0.50 -#define WADESCALE 0.70 - -// these defines MUST match the values used in the game dll -#define DEFAULT_MINS_0 -48 -#define DEFAULT_MINS_1 -48 -#define DEFAULT_MINS_2 0 -#define DEFAULT_MAXS_0 48 -#define DEFAULT_MAXS_1 48 -#define DEFAULT_MAXS_2 76 -#define CROUCH_MAXS_2 49 - -// although this is a derived value, it needs to match the game -#define MAX_JUMPHEIGHT 32 - -// these are used to drive the pmove based reachability function -#define MAX_PMOVES 64 -#define PMOVE_MSEC 50 -#define PLAYER_SPEED 320 - -// defines for ranges and granularity of the spot testing -#define XY_MIN -4080 -#define XY_MAX 4080 -#define XY_STEP 16 -#define Z_MIN -4096 -#define Z_MAX 4064 -#define Z_STEP 1 - -#define MAX_SPOTS 65536 -#define MAX_SPOTINDEX (((XY_MAX - XY_MIN) / XY_STEP) + 2 ) - -typedef struct { - unsigned flags; - int surfaceNum; - vec3_t origin; - int parm; -} nspot_t; - -static nspot_t *spot; -static int spotCount; - -static int sortIndex[MAX_SPOTS]; -static int spotIndex[MAX_SPOTINDEX]; -static int spotIndexCount; - - -#if 0 //Q3MAP -nsurface_t *surface; -int surfaceCount; - - -nneighbor_t *neighbor; -int neighborCount; - -byte *route; -#endif - -/* -============= -VectorToString - -This is just a convenience function -for printing vectors -============= -*/ -char *vtos( const vec3_t v ) { - static int index; - static char str[8][32]; - char *s; - - // use an array so that multiple vtos won't collide - s = str[index]; - index = (index + 1)&7; - - Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]); - - return s; -} - -// -// FindSpots -// - -static vec3_t mins; -static vec3_t duckMaxs; -static vec3_t standMaxs; - -//FIXME this should NOT be global -static gentity_t *test; - -static void FindSpotsInY( int num ) { - trace_t tr; - trace_t tr2; - vec3_t origin; - vec3_t point2; - vec3_t testpoint; - qboolean roof; - float viewheight; - int cont; - float sample1; - float sample2; - int waterlevel; - //int numEnts; - //gentity_t *ents[MAX_GENTITIES]; - gentity_t *ent; - qboolean n; - vec3_t absmin; - vec3_t absmax; - int spotNum; - float height; - //gentity_t *target; - //gentity_t *destTarget; - - origin[0] = XY_MIN + num * XY_STEP; - - for ( origin[1] = XY_MIN; origin[1] <= XY_MAX; origin[1] += XY_STEP ) { - origin[2] = Z_MAX; - tr.endpos[2] = Z_MAX + Z_STEP; - point2[0] = origin[0]; - point2[1] = origin[1]; - point2[2] = Z_MIN; - roof = qtrue; - height = Z_STEP; - -// gi.Printf( "begin %i %i\n", (int)origin[0], (int)origin[1] ); - while ( origin[2] > Z_MIN ) { - origin[2] = tr.endpos[2] - height; - height = Z_STEP; - - gi.trace( &tr, origin, mins, duckMaxs, point2, ENTITYNUM_NONE, MASK_DEADSOLID, true ); - - // did we fall out the bottom? yes = this xy finished - if ( tr.endpos[2] <= point2[2] ) { -// gi.Printf( " done - fell out\n" ); - break; - } - - // were we in solid the whole time? yes = this xy finished - if ( tr.allsolid ) { -// gi.Printf( " done - all solid\n" ); - break; - } - - // did we end up inside a solid? - gi.trace( &tr2, tr.endpos, mins, duckMaxs, tr.endpos, ENTITYNUM_NONE, MASK_DEADSOLID, true ); - if ( tr2.startsolid ) { -// gi.Printf( " in solid @ %f\n", tr.endpos[2] - 24.0 ); - continue; - } - - // did we land on the roof of the level? yes = move z down a step from point of contact - if ( roof ) { -// gi.Printf( " fell onto level @ %f\n", tr.endpos[2] - 24.0 ); - roof = qfalse; - continue; - } - - // is this too steep to stand on? yes = move z down a step from point of contact - if ( tr.plane.normal[2] < MIN_WALK_NORMAL ) { -// gi.Printf( " spot too steep @ %f\n", tr.endpos[2] - 24.0 ); - continue; - } - -// FIXME rule out any we want ignored here - // see if we are on a special entity - ent = &g_entities[tr.entityNum]; - if ( ent->s.number != ENTITYNUM_WORLD ) { - if ( ent->entity && ent->entity->isSubclassOf( Mover ) ) { - continue; - } -#if 0 - if ( Q_stricmp( ent->entname, "func_plat" ) == 0 ) { - //FIXME what do we need to do if we are - } -#endif - } - - // see if we are outside the world - VectorCopy( tr.endpos, test->s.origin ); - gi.linkentity( test ); - n = test->linked; - gi.unlinkentity( test ); - if ( n == qfalse ) { -// gi.Printf( " outside world c @ %s\n", vtos( tr.endpos ) ); - continue; - } - - if ( spotCount == MAX_SPOTS ) { - gi.Printf( "MAX_SPOTS exceeded\n" ); - //FIXME in Q3MAP this should be an exit() - return; - } - - // we found a valid standing location, add it to spot list - ThreadLock(); - spotNum = spotCount++; - ThreadUnlock(); - -// gi.Printf( " found spot @ %f %f %f\n", tr.endpos[0], tr.endpos[1], tr.endpos[2] - 24.0); -// VectorCopy( tr.endpos, spot[spotNum].origin ); - spot[spotNum].origin[0] = tr.endpos[0]; - spot[spotNum].origin[1] = tr.endpos[1]; - spot[spotNum].origin[2] = COORDINATE_TO_FLOAT * (int)(tr.endpos[2]*FLOAT_TO_COORDINATE); - spot[spotNum].flags = 0; - spot[spotNum].surfaceNum = -1; - - // see if we are on a special entity - ent = &g_entities[tr.entityNum]; - if ( ent->s.number != ENTITYNUM_WORLD ) { -#if 0 - if ( Q_stricmp( ent->entname, "func_plat" ) == 0 ) { - spot[spotNum].flags |= SF_PLATLOW; // Q3MAP: SF_PLATHIGH - height = Z_STEP; // Q3MAP: ent->pos2[2] - ent->pos1[2]; - spot[spotNum].parm = tr.entityNum; - } -// else if ( Q_stricmp( ent->entname, "func_train" ) == 0 ) { -// spot[spotNum].flags |= SF_TRAIN; -// } -#endif - } - - // check if we must be ducked - VectorAdd( tr.endpos, mins, absmin ); - gi.trace( &tr2, tr.endpos, mins, standMaxs, tr.endpos, ENTITYNUM_NONE, MASK_DEADSOLID, true ); - if ( tr2.allsolid ) { - spot[spotNum].flags |= SF_DUCK; - viewheight = CROUCH_VIEWHEIGHT; - VectorAdd( tr.endpos, duckMaxs, absmax ); - } - else { - viewheight = DEFAULT_VIEWHEIGHT; - VectorAdd( tr.endpos, standMaxs, absmax ); - } - - // check water depth and type (depends on duck state to set viewheight) - waterlevel = 0; - testpoint[0] = tr.endpos[0]; - testpoint[1] = tr.endpos[1]; - testpoint[2] = tr.endpos[2] + mins[2] + 1; - cont = gi.pointcontents( testpoint, 0 ); - - if ( cont & MASK_WATER ) { - sample2 = viewheight - mins[2]; - sample1 = sample2 / 2; - - if ( cont & (CONTENTS_LAVA | CONTENTS_SLIME) ) { - spot[spotNum].flags |= SF_PAIN; - } - - waterlevel = 1; - testpoint[2] = tr.endpos[2] + mins[2] + sample1; - cont = gi.pointcontents( testpoint, 0 ); - if (cont & MASK_WATER) { - waterlevel = 2; - testpoint[2] = tr.endpos[2] + mins[2] + sample2; - cont = gi.pointcontents( testpoint, 0 ); - if (cont & MASK_WATER) { - waterlevel = 3; - } - } - } - if ( waterlevel & 1) { - spot[spotNum].flags |= SF_WATERLEVEL1; - } - if ( waterlevel & 2) { - spot[spotNum].flags |= SF_WATERLEVEL2; - } - - // if water depth 3, see if there is air above us - if ( waterlevel == 3) { - if ( spot[spotNum].flags & SF_DUCK ) { - spot[spotNum].flags |= SF_WATER_NOAIR; - } - else { - gi.trace( &tr2, tr.endpos, mins, standMaxs, origin, ENTITYNUM_NONE, MASK_DEADSOLID, true ); - testpoint[0] = tr2.endpos[0]; - testpoint[1] = tr2.endpos[1]; - testpoint[2] = tr2.endpos[2] + DEFAULT_VIEWHEIGHT; - cont = gi.pointcontents( testpoint, 0 ); - if (cont & MASK_WATER) { - spot[spotNum].flags |= SF_WATER_NOAIR; - } - } - } -#if 0 - // check if this spot is in a trigger we care about - numEnts = gi.EntitiesInBox( absmin, absmax, ents, MAX_GENTITIES ); - for ( n = 0; n < numEnts; n++ ) { - ent = ents[n]; -// if ( Q_stricmp ( ent->entname, "misc_teleporter" ) == 0 ) { - if ( Q_stricmp ( ent->entname, "trigger_teleport" ) == 0 ) { - spot[spotNum].flags |= SF_TELEPORTER; - destTarget = NULL; - destTarget = G_Find( destTarget, FOFS( targetname ), ent->target ); - if ( !destTarget ) { - gi.Printf( "target_teleporter with no target\n" ); - spot[spotNum].parm = 0; - } - else { - spot[spotNum].parm = destTarget->s.number; - } - } - if ( !( ent->contents & CONTENTS_TRIGGER ) ) { - continue; - } - if ( Q_stricmp ( ent->entname, "trigger_hurt" ) == 0 ) { - spot[spotNum].flags |= SF_PAIN; - } - if ( Q_stricmp ( ent->entname, "trigger_push" ) == 0 ) { - spot[spotNum].flags |= SF_PUSH; - spot[spotNum].parm = ent->s.number; - } - if ( Q_stricmp ( ent->entname, "trigger_multiple" ) == 0 ) { - target = NULL; - while ( (target = G_Find( target, FOFS( targetname ), ent->target ) ) != NULL ) { - if ( target == ent ) { - continue; - } - if ( Q_stricmp ( target->entname, "target_teleporter" ) == 0 ) { - spot[spotNum].flags |= SF_TELEPORTER; - destTarget = NULL; - destTarget = G_Find( destTarget, FOFS( targetname ), target->target ); - if ( !destTarget ) { - gi.Printf( "target_teleporter with no target\n" ); - spot[spotNum].parm = 0; - } - else { - spot[spotNum].parm = destTarget->s.number; - } - } - if ( Q_stricmp ( target->entname, "target_push" ) == 0 ) { - spot[spotNum].flags |= SF_PUSH; - spot[spotNum].parm = target->s.number; - } - } - } - } -#endif - } - } -} - -static void FindSpots( void ) { - int n; - //gentity_t *ent; - //gentity_t *target; - //int spotNum; - - spot = ( nspot_t * )gi.TagMalloc ( MAX_SPOTS * sizeof(spot[0]), TAG_GAME ); - spotCount = 0; - - for ( n = 0; n < MAX_SPOTS; n++ ) { - spot[n].flags = 0; - } - - VectorSet( mins, DEFAULT_MINS_0, DEFAULT_MINS_1, DEFAULT_MINS_2 ); - VectorSet( standMaxs, DEFAULT_MAXS_0, DEFAULT_MAXS_1, DEFAULT_MAXS_2 ); - VectorSet( duckMaxs, DEFAULT_MAXS_0, DEFAULT_MAXS_1, CROUCH_MAXS_2 ); - - test = G_Spawn(); - test->s.eType = ET_GENERAL; - VectorCopy( mins, test->mins ); - VectorCopy( duckMaxs, test->maxs ); - - // RunThreadsOn( (XY_MAX - XY_MIN) / XY_STEP, qtrue, FindSpotsInY ); - for ( n = 0; n < ((XY_MAX - XY_MIN) / XY_STEP); n++ ) { - gi.DebugPrintf( "FindSpotsInY %d/%d\n", n, ((XY_MAX - XY_MIN) / XY_STEP) ); - FindSpotsInY( n ); - } - - G_FreeEdict( test ); - - -#if 0 - //FIXME add spots for trigger_teleport - for ( n = 0; n < globals.num_entities; n++ ) { - ent = &g_entities[n]; - if ( !ent->inuse ) { - continue; - } - if ( Q_stricmp ( ent->entname, "misc_teleporter" ) == 0 ) { - if ( Q_stricmp ( ent->entname, "trigger_teleport" ) == 0 ) { - target = NULL; - target = G_Find( target, FOFS( targetname ), ent->target ); - if ( !target ) { - continue; - } - spotNum = spotCount++; - spot[spotNum].origin[0] = ent->s.origin[0]; - spot[spotNum].origin[1] = ent->s.origin[1]; - spot[spotNum].origin[2] = COORDINATE_TO_FLOAT * (int)(ent->s.origin[2]*FLOAT_TO_COORDINATE); - spot[spotNum].flags = SF_TELEPORTER; - spot[spotNum].surfaceNum = -1; - spot[spotNum].parm = target - &g_entities[0]; - } - } - -#endif - gi.Printf( " %i spots\n", spotCount ); -} - - -// -// FindSurfaces -// - -#define MAX_SURFACES 4096 - -static int zstart; -static int zend; -//static int surfaceSizes[10]; - -static int CompareSpotsByZ( const void *a, const void *b ) { - nspot_t *s1 = &spot[*(int *)a]; - nspot_t *s2 = &spot[*(int *)b]; - - // z - if ( s1->origin[2] > s2->origin[2] ) { - return -1; - } - if ( s1->origin[2] < s2->origin[2] ) { - return 1; - } - - // x - if ( s1->origin[0] < s2->origin[0] ) { - return -1; - } - if ( s1->origin[0] > s2->origin[0] ) { - return 1; - } - - // y - if ( s1->origin[1] < s2->origin[1] ) { - return -1; - } - if ( s1->origin[1] > s2->origin[1] ) { - return 1; - } - - return 0; -} - -static void BuildSpotIndexByZ( void ) { - int n; - int i; - float z; - float cz; - - for ( n = 0; n < spotCount; n++ ) { - sortIndex[n] = n; - } - for ( n = 0; n < (((XY_MAX - XY_MIN) / XY_STEP) + 2); n++ ) { - spotIndex[n] = 0; - } - qsort( sortIndex, spotCount, sizeof(sortIndex[0]), CompareSpotsByZ ); - - i = 0; - cz = -8192; - for ( n = 0; n < spotCount; n++ ) { - z = spot[sortIndex[n]].origin[2]; - if ( z != cz ) { - spotIndex[i++] = n; - cz = z; - if ( i >= ( MAX_SPOTINDEX - 1 ) ) - { - gi.Printf( "MAX_SPOTINDEX exceeded\n" ); - //FIXME in Q3MAP this should be an exit() - break; - } - } - } - spotIndexCount = i; - spotIndex[i] = n; -} - -static int SpotIndex( vec3_t origin, int flags ) { - int n; - -// gi.Printf( " SpotIndex( %s )\n", vtos( origin ) ); - - for ( n = zstart; n < zend; n++ ) { - if ( spot[sortIndex[n]].origin[0] < origin[0] ) { - continue; - } - if ( spot[sortIndex[n]].origin[0] > origin[0] ) { - return -1; - } - if ( spot[sortIndex[n]].origin[1] < origin[1] ) { - continue; - } - if ( spot[sortIndex[n]].origin[1] > origin[1] ) { - return -1; - } - if ( spot[sortIndex[n]].surfaceNum != -1 ) { - return -1; - } - if ( spot[sortIndex[n]].flags != flags ) { - return -1; - } - return sortIndex[n]; - } - return -1; -} - -static void BuildSurface( int index ) { - int surfaceNum; - int plusx; - int minusx; - int plusy; - int minusy; - qboolean plusxLock; - qboolean minusxLock; - qboolean plusyLock; - qboolean minusyLock; - float xmin, xmax, x; - float ymin, ymax, y; - vec3_t test; - int n; - int count; - int tbm[256]; - int sCount; - nsurface_t *surf; - //int surfaceNum2; - //gentity_t *ent; - //float height; - - if ( surfaceCount == MAX_SURFACES ) { - gi.Printf( "MAX_SURFACES exceeded\n" ); - //FIXME in Q3MAP this should be an exit() - return; - } - - ThreadLock(); - surfaceNum = surfaceCount++; - ThreadUnlock(); - - spot[index].surfaceNum = surfaceNum; - - plusx = 0; - minusx = 0; - plusy = 0; - minusy = 0; - plusxLock = qfalse; - minusxLock = qfalse; - plusyLock = qfalse; - minusyLock = qfalse; - test[2] = spot[index].origin[2]; - sCount = 1; - - while ( !plusxLock || !minusxLock || !plusyLock || !minusyLock ) { - if ( !plusxLock ) { - plusx++; - count = 0; - test[0] = spot[index].origin[0] + plusx * XY_STEP; - ymin = spot[index].origin[1] - minusy * XY_STEP; - ymax = spot[index].origin[1] + plusy * XY_STEP; - for ( y = ymin; y <= ymax; y += XY_STEP ) { - test[1] = y; - n = SpotIndex( test, spot[index].flags ); - if ( n == -1 ) { - plusx--; - plusxLock = qtrue; - break; - } - tbm[count++] = n; - } - for ( n = 0; n < count; n ++ ) { - spot[tbm[n]].surfaceNum = surfaceNum; - } - sCount += count; - } - - if ( !minusxLock ) { - minusx++; - count = 0; - test[0] = spot[index].origin[0] - minusx * XY_STEP; - ymin = spot[index].origin[1] - minusy * XY_STEP; - ymax = spot[index].origin[1] + plusy * XY_STEP; - for ( y = ymin; y <= ymax; y += XY_STEP ) { - test[1] = y; - n = SpotIndex( test, spot[index].flags ); - if ( n == -1 ) { - minusx--; - minusxLock = qtrue; - break; - } - tbm[count++] = n; - } - for ( n = 0; n < count; n ++ ) { - spot[tbm[n]].surfaceNum = surfaceNum; - } - sCount += count; - } - - if ( !plusyLock ) { - plusy++; - count = 0; - test[1] = spot[index].origin[1] + plusy * XY_STEP; - xmin = spot[index].origin[0] - minusx * XY_STEP; - xmax = spot[index].origin[0] + plusx * XY_STEP; - for ( x = xmin; x <= xmax; x += XY_STEP ) { - test[0] = x; - n = SpotIndex( test, spot[index].flags ); - if ( n == -1 ) { - plusy--; - plusyLock = qtrue; - break; - } - tbm[count++] = n; - } - for ( n = 0; n < count; n ++ ) { - spot[tbm[n]].surfaceNum = surfaceNum; - } - sCount += count; - } - - if ( !minusyLock ) { - minusy++; - count = 0; - test[1] = spot[index].origin[1] - minusy * XY_STEP; - xmin = spot[index].origin[0] - minusx * XY_STEP; - xmax = spot[index].origin[0] + plusx * XY_STEP; - for ( x = xmin; x <= xmax; x += XY_STEP ) { - test[0] = x; - n = SpotIndex( test, spot[index].flags ); - if ( n == -1 ) { - minusy--; - minusyLock = qtrue; - break; - } - tbm[count++] = n; - } - for ( n = 0; n < count; n ++ ) { - spot[tbm[n]].surfaceNum = surfaceNum; - } - sCount += count; - } - } - -#if 0 - if ( sCount <= 1 ) { - surfaceSizes[0]++; - } - else if ( sCount <= 2 ) { - surfaceSizes[1]++; - } - else if ( sCount <= 4 ) { - surfaceSizes[2]++; - } - else if ( sCount <= 8 ) { - surfaceSizes[3]++; - } - else if ( sCount <= 16 ) { - surfaceSizes[4]++; - } - else if ( sCount <= 32 ) { - surfaceSizes[5]++; - } - else if ( sCount <= 64 ) { - surfaceSizes[6]++; - } - else if ( sCount <= 128 ) { - surfaceSizes[7]++; - } - else if ( sCount <= 256 ) { - surfaceSizes[8]++; - } - else { - surfaceSizes[9]++; - } -#endif - - surf = &surface[surfaceNum]; - surf->flags = spot[index].flags; - - surf->absmin[0] = spot[index].origin[0] - ( minusx * XY_STEP ); - surf->absmin[1] = spot[index].origin[1] - ( minusy * XY_STEP ); - - surf->absmax[0] = spot[index].origin[0] + ( plusx * XY_STEP ); - surf->absmax[1] = spot[index].origin[1] + ( plusy * XY_STEP ); - - surf->origin[0] = ( surf->absmin[0] + surf->absmax[0] ) * 0.5; - surf->origin[1] = ( surf->absmin[1] + surf->absmax[1] ) * 0.5; - surf->origin[2] = spot[index].origin[2]; - - gi.DebugPrintf( "Spot %d : origin %s\n", index, vtos( surf->origin ) ); - -// gi.Printf( "Surface from %s ", vtos( surf->absmin ) ); -// gi.Printf( "to %s", vtos( surf->absmax) ); -// gi.Printf( "at %s\n", vtos( surf->origin) ); -#if 0 - // if this is a plat high position, build to plat low surface - // Q#MAP: numerous changes in here - if ( spot[index].flags & SF_PLATLOW ) { //Q3MAP: SF_PLATHIGH - // grab another surface - ThreadLock(); - surfaceNum2 = surfaceCount++; - ThreadUnlock(); - - // make a copy of the other plat surface - memcpy( &surface[surfaceNum2], &surface[surfaceNum], sizeof( nsurface_t ) ); - -// // switch the flag from high to low -// surface[surfaceNum2].flags &= ~SF_PLATHIGH; -// surface[surfaceNum2].flags |= SF_PLATLOW; - // switch the flag from low to high - surface[surfaceNum2].flags &= ~SF_PLATLOW; - surface[surfaceNum2].flags |= SF_PLATHIGH; - - // adjust the z value - ent = &g_entities[spot[index].parm]; - height = ent->pos2[2] - ent->pos1[2]; -// surface[surfaceNum2].origin[2] -= height; - surface[surfaceNum2].origin[2] += height; - - // set low plat surface parm to high plat surface number -// surface[surfaceNum2].parm = surfaceNum; - surface[surfaceNum].parm = surfaceNum2; - -// // set high plat surface parm plat cost -// surface[surfaceNum].parm = (height / ent->speed) * 1000; -// surface[surfaceNum2].parm = (height / ent->speed) * 1000; - // set high plat surface parm to plat entity number -// surface[surfaceNum].parm = spot[index].parm; - surface[surfaceNum2].parm = spot[index].parm; - } -#endif - if ( spot[index].flags & SF_PUSH ) { - surf->parm = spot[index].parm; - } - - if ( spot[index].flags & SF_TELEPORTER ) { - surf->parm = spot[index].parm; - } -} - -static void FindSurfacesAtZ( int zIndex ) { - int n; - - zstart = spotIndex[zIndex]; - zend = spotIndex[zIndex + 1]; - - for ( n = zstart; n < zend; n++ ) { - if ( spot[sortIndex[n]].surfaceNum == -1 ) { - BuildSurface( sortIndex[n] ); - } - } -} - -static void FindSurfaces( void ) { - int n; - - surface = ( nsurface_t * )gi.TagMalloc ( MAX_SURFACES * sizeof(surface[0]), TAG_GAME ); - surfaceCount = 0; - -// memset( surfaceSizes, 0, sizeof( surfaceSizes ) ); - BuildSpotIndexByZ(); - -// RunThreadsOn( spotIndexCount, qtrue, FindSurfacesAtZ ); - for ( n = 0; n < spotIndexCount; n++ ) { - FindSurfacesAtZ( n ); - } - - gi.TagFree( spot ); - -#if 0 - gi.Printf( "%3i @ 1\n", surfaceSizes[0] ); - gi.Printf( "%3i @ 2\n", surfaceSizes[1] ); - gi.Printf( "%3i @ 3-4\n", surfaceSizes[2] ); - gi.Printf( "%3i @ 5-8\n", surfaceSizes[3] ); - gi.Printf( "%3i @ 9-16\n", surfaceSizes[4] ); - gi.Printf( "%3i @ 17-32\n", surfaceSizes[5] ); - gi.Printf( "%3i @ 33-64\n", surfaceSizes[6] ); - gi.Printf( "%3i @ 65-128\n", surfaceSizes[7] ); - gi.Printf( "%3i @ 129-256\n", surfaceSizes[8] ); - gi.Printf( "%3i @ 257+\n", surfaceSizes[9] ); -#endif - - gi.Printf( " %i surfaces\n", surfaceCount ); -} - -int FindSpot( vec3_t origin, int flags, float min_height ) -{ - int n; - - for ( n = 0; n < spotCount ; n++ ) - { - if ( spot[sortIndex[n]].origin[0] < origin[0] ) { - continue; - } - if ( spot[sortIndex[n]].origin[0] > origin[0] ) { - return -1; - } - if ( spot[sortIndex[n]].origin[1] < origin[1] ) { - continue; - } - if ( spot[sortIndex[n]].origin[1] > origin[1] ) { - return -1; - } - if ( spot[sortIndex[n]].origin[2] <= min_height ) { - continue; - } - if ( spot[sortIndex[n]].surfaceNum != -1 ) { - return -1; - } - if ( spot[sortIndex[n]].flags != flags ) { - return -1; - } - return sortIndex[n]; - } - return -1; -} - -int FindUsedSpot( vec3_t origin, float min_height ) -{ - int n; - - for ( n = 0; n < spotCount ; n++ ) - { - if ( spot[sortIndex[n]].origin[0] < origin[0] ) { - continue; - } - if ( spot[sortIndex[n]].origin[0] > origin[0] ) { - return -1; - } - if ( spot[sortIndex[n]].origin[1] < origin[1] ) { - continue; - } - if ( spot[sortIndex[n]].origin[1] > origin[1] ) { - return -1; - } - if ( spot[sortIndex[n]].origin[2] <= min_height ) { - continue; - } - return sortIndex[n]; - } - return -1; -} - -int FindSpotInSurface( vec3_t origin, int surfaceNum ) -{ - int index; - float current_height; - - - current_height = Z_MIN; - - while( 1 ) - { - index = FindUsedSpot( origin, current_height ); - - if (index == -1) - return -1; - - if (spot[index].surfaceNum == surfaceNum) - return index; - - current_height = spot[index].origin[2]; - } - - return -1; -} - -qboolean IsConvex( int surfaceNum, vec3_t check_point, int n ) -{ - float i, j; - float x1, y1; - float x2, y2; - float step; - int test_y; - float y_diff; - vec3_t test_point; - int test = 0; - - - if (check_point[0] < spot[n].origin[0]) - { - x1 = check_point[0]; - y1 = check_point[1]; - - x2 = spot[n].origin[0]; - y2 = spot[n].origin[1]; - } - else - { - x1 = spot[n].origin[0]; - y1 = spot[n].origin[1]; - - x2 = check_point[0]; - y2 = check_point[1]; - } - - if (x2 - x1 != 0) - step = (y2 - y1) / (x2 - x1) / XY_STEP; - else - step = 0; - - j = 0; - - for ( i = x1 ; i < x2 ; i += XY_STEP ) - { - // Test points here - - test_point[0] = i; - - test_y = j + .5; - - y_diff = j - test_y; - - if (0) //((y_diff < .05) && (y_diff > -.05)) - { - test_point[1] = y1 + ((int)j) * XY_STEP; - - if (FindSpotInSurface( test_point, surfaceNum ) == -1) - //return qfalse; - test++; - else - test = 0; - - } - else - { - - test_point[1] = y1 + ((int)j) * XY_STEP; - - if (FindSpotInSurface( test_point, surfaceNum ) == -1) - { - if (j > 0) - test_point[1] = y1 + ((int)(j + 1)) * XY_STEP; - else - test_point[1] = y1 + ((int)(j - 1)) * XY_STEP; - - if (FindSpotInSurface( test_point, surfaceNum ) == -1) - //return qfalse; - test++; - else - test = 0; - } - else - test = 0; - } - - if (test == 3) - return qfalse; - - j += step; - } - - return qtrue; -} - -qboolean CanAddPoint1( int surfaceNum, int n ) -{ - int i, j; - float z_diff; - int index; - vec3_t check_point; - float current_height; - int has_neighbor_point; - - - // Make sure can walk to nearest points in this surface - - has_neighbor_point = qfalse; - - for ( i = -1 ; i <= 1 ; i++ ) - { - check_point[0] = spot[n].origin[0] + i * XY_STEP; - - for ( j = -1 ; j <= 1 ; j++ ) - { - check_point[1] = spot[n].origin[1] + j * XY_STEP; - - if (! ((i == 0) && (j == 0)) ) - { - // Find point in same surface - - current_height = Z_MIN; - - while( 1 ) - { - index = FindUsedSpot( check_point, current_height ); - - if (index == -1) - break; - - if (spot[index].surfaceNum == surfaceNum) - { - has_neighbor_point = qtrue; - - z_diff = spot[index].origin[2] - spot[n].origin[2]; - if (z_diff < 0) - z_diff = -z_diff; - - if (z_diff > STEPSIZE) - return qfalse; - - break; - } - - current_height = spot[index].origin[2]; - } - } - } - } - - // Make sure it was next to at least one other point in this surface - - if (!has_neighbor_point) - return qfalse; - - return qtrue; -} - -qboolean CanAddPoint2( int surfaceNum, int n ) -{ - int i, j; - vec3_t check_point; - vec2_t absmin; - vec2_t absmax; - qboolean skip_top, skip_left, skip_right, skip_bottom; - - - // Setup ansolute mins and maxs correctly - - if (spot[n].origin[0] < surface[surfaceNum].absmin[0]) - { - absmin[0] = spot[n].origin[0]; - skip_left = qtrue; - } - else - { - absmin[0] = surface[surfaceNum].absmin[0]; - skip_left = qfalse; - } - - if (spot[n].origin[0] > surface[surfaceNum].absmax[0]) - { - absmax[0] = spot[n].origin[0]; - skip_right = qtrue; - } - else - { - absmax[0] = surface[surfaceNum].absmax[0]; - skip_right = qfalse; - } - - if (spot[n].origin[1] < surface[surfaceNum].absmin[1]) - { - absmin[1] = spot[n].origin[1]; - skip_top = qtrue; - } - else - { - absmin[1] = surface[surfaceNum].absmin[1]; - skip_top = qfalse; - } - - if (spot[n].origin[1] > surface[surfaceNum].absmax[1]) - { - absmax[1] = spot[n].origin[1]; - skip_bottom = qtrue; - } - else - { - absmax[1] = surface[surfaceNum].absmax[1]; - skip_bottom = qfalse; - } - - // Test top and bottom points for convexness - - for( i = absmin[0] ; i <= absmax[0] ; i += XY_STEP ) - { - check_point[0] = i; - - // Find top point in this column - - if (!skip_top) - { - for( j = absmin[1] ; j <= absmax[1] ; j += XY_STEP ) - { - check_point[1] = j; - - if (FindSpotInSurface( check_point, surfaceNum ) != -1) - { - // Test for convexness - - if (!IsConvex( surfaceNum, check_point, n )) - return qfalse; - - break; - } - } - } - - // Find bottom point in this column - - if (!skip_bottom) - { - for( j = absmax[1] ; j >= absmin[1] ; j -= XY_STEP ) - { - check_point[1] = j; - - if (FindSpotInSurface( check_point, surfaceNum ) != -1) - { - // Test for convexness - - if (!IsConvex( surfaceNum, check_point, n )) - return qfalse; - - break; - } - } - } - } - - // Test left and right points for convexness - - for( j = absmin[1] ; j <= absmax[1] ; j += XY_STEP ) - { - check_point[1] = j; - - // Find left point in this row - - if (!skip_left) - { - for( i = absmin[0] ; i <= absmax[0] ; i += XY_STEP ) - { - check_point[0] = i; - - if (FindSpotInSurface( check_point, surfaceNum ) != -1) - { - // Test for convexness - - if (!IsConvex( surfaceNum, check_point, n )) - return qfalse; - - break; - } - } - } - - // Find right point in this row - - if (!skip_right) - { - for( i = absmax[0] ; i >= absmin[0] ; i -= XY_STEP ) - { - check_point[0] = i; - - if (FindSpotInSurface( check_point, surfaceNum ) != -1) - { - // Test for convexness - - if (!IsConvex( surfaceNum, check_point, n )) - return qfalse; - - break; - } - } - } - } - - - /* for ( i = -1 ; i <= 1 ; i++ ) - { - check_point[0] = spot[n].origin[0] + i * XY_STEP; - - for ( j = -1 ; j <= 1 ; j++ ) - { - check_point[1] = spot[n].origin[1] + j * XY_STEP; - - if (! ((i == 0) && (j == 0)) ) - { - // Find point in same surface - - current_height = Z_MIN; - - while( 1 ) - { - index = FindUsedSpot( check_point, current_height ); - - if (index == -1) - break; - - if (spot[index].surfaceNum == surfaceNum) - break; - - current_height = spot[index].origin[2]; - } - - if (index == -1) - { - current_height = Z_MIN; - - while( 1 ) - { - index = FindUsedSpot( check_point, current_height ); - - if (index == -1) - break; - - if (spot[index].surfaceNum == surfaceNum) - break; - - current_height = spot[index].origin[2]; - } - - if (index != -1) - return qfalse; - } - } - } - } */ - - return qtrue; -} - -void AddPointToSurface( int surfaceNum, int n ) -{ - spot[n].surfaceNum = surfaceNum; - - if (spot[n].origin[0] < surface[surfaceNum].absmin[0]) - surface[surfaceNum].absmin[0] = spot[n].origin[0]; - - if (spot[n].origin[0] > surface[surfaceNum].absmax[0]) - surface[surfaceNum].absmax[0] = spot[n].origin[0]; - - if (spot[n].origin[1] < surface[surfaceNum].absmin[1]) - surface[surfaceNum].absmin[1] = spot[n].origin[1]; - - if (spot[n].origin[1] > surface[surfaceNum].absmax[1]) - surface[surfaceNum].absmax[1] = spot[n].origin[1]; -} - -static void BuildConvexSurface( int index ) -{ - int surfaceNum; - int plusx; - int minusx; - int plusy; - int minusy; - qboolean plusxLock; - qboolean minusxLock; - qboolean plusyLock; - qboolean minusyLock; - qboolean plusxhold, minusxhold, plusyhold, minusyhold; - qboolean plusxalreadyheld, minusxalreadyheld, plusyalreadyheld, minusyalreadyheld; - float xmin, xmax, x; - float ymin, ymax, y; - vec3_t test; - int n; - int count; - int tbm[256]; - int sCount; - nsurface_t *surf; - qboolean valid_direction; - float current_height; - int i; - - - - if ( surfaceCount == MAX_SURFACES ) - { - gi.Printf( "MAX_SURFACES exceeded\n" ); - return; - } - - //if (surfaceCount > 100) - // return; - - ThreadLock(); - surfaceNum = surfaceCount++; - ThreadUnlock(); - - spot[index].surfaceNum = surfaceNum; - - surface[surfaceNum].absmin[0] = spot[index].origin[0]; - surface[surfaceNum].absmax[0] = spot[index].origin[0]; - surface[surfaceNum].absmin[1] = spot[index].origin[1]; - surface[surfaceNum].absmax[1] = spot[index].origin[1]; - - plusx = 0; - minusx = 0; - plusy = 0; - minusy = 0; - - plusxLock = qfalse; - minusxLock = qfalse; - plusyLock = qfalse; - minusyLock = qfalse; - - plusxhold = qfalse; - minusxhold = qfalse; - plusyhold = qfalse; - minusyhold = qfalse; - - plusxalreadyheld = qfalse; - minusxalreadyheld = qfalse; - plusyalreadyheld = qfalse; - minusyalreadyheld = qfalse; - - test[2] = spot[index].origin[2]; - sCount = 1; - - while ( !plusxLock || !minusxLock || !plusyLock || !minusyLock ) - { - if ( ( plusxLock || plusxhold ) && ( minusxLock || minusxhold ) && ( plusyLock || plusyhold ) && ( minusyLock || minusyhold ) ) - { - // Remove all of the holds - - plusxhold = qfalse; - minusxhold = qfalse; - plusyhold = qfalse; - minusyhold = qfalse; - - plusxalreadyheld = qtrue; - minusxalreadyheld = qtrue; - plusyalreadyheld = qtrue; - minusyalreadyheld = qtrue; - } - - if ( !plusxLock && !plusxhold ) - { - plusx++; - count = 0; - test[0] = spot[index].origin[0] + plusx * XY_STEP; - ymin = spot[index].origin[1] - minusy * XY_STEP; - ymax = spot[index].origin[1] + plusy * XY_STEP; - valid_direction = qfalse; - - for ( y = ymin; y <= ymax; y += XY_STEP ) - { - // Find this spot - - test[1] = y; - current_height = Z_MIN; - n = FindSpot( test, spot[index].flags, current_height ); - - while( n != -1 ) - { - // See if this point can be added and the surface stay convex - - if ( CanAddPoint1( surfaceNum, n ) ) - { - // Add this point to this surface - - spot[n].surfaceNum = surfaceNum; - tbm[count] = n; - count++; - - break; - } - - // Get the next spot at this x, y - - current_height = spot[n].origin[2]; - n = FindSpot( test, spot[index].flags, current_height ); - } - } - - if ( plusxalreadyheld ) - { - for( i = 0 ; i < count ; i++ ) - { - if ( CanAddPoint2( surfaceNum, tbm[i] ) ) - { - AddPointToSurface( surfaceNum, tbm[i] ); - valid_direction = qtrue; - } - else - spot[tbm[i]].surfaceNum = -1; - } - } - else - { - valid_direction = qtrue; - - if (count == (ymax - ymin) / XY_STEP + 1) - { - for( i = 0 ; i < count ; i++ ) - AddPointToSurface( surfaceNum, tbm[i] ); - } - else - { - for( i = 0 ; i < count ; i++ ) - spot[tbm[i]].surfaceNum = -1; - plusxhold = qtrue; - plusx--; - } - } - - if ( !valid_direction ) - { - plusx--; - plusxLock = qtrue; - } - } - - if ( !minusxLock && !minusxhold ) - { - minusx++; - count = 0; - test[0] = spot[index].origin[0] - minusx * XY_STEP; - ymin = spot[index].origin[1] - minusy * XY_STEP; - ymax = spot[index].origin[1] + plusy * XY_STEP; - valid_direction = qfalse; - - for ( y = ymin; y <= ymax; y += XY_STEP ) - { - // Find this spot - - test[1] = y; - current_height = Z_MIN; - n = FindSpot( test, spot[index].flags, current_height ); - - while( n != -1 ) - { - // See if this point can be added and the surface stay convex - - if ( CanAddPoint1( surfaceNum, n ) ) - { - // Add this point to this surface - - spot[n].surfaceNum = surfaceNum; - tbm[count] = n; - count++; - - break; - } - - // Get the next spot at this x, y - - current_height = spot[n].origin[2]; - n = FindSpot( test, spot[index].flags, current_height ); - } - } - - if ( minusxalreadyheld ) - { - for( i = 0 ; i < count ; i++ ) - { - if ( CanAddPoint2( surfaceNum, tbm[i] ) ) - { - AddPointToSurface( surfaceNum, tbm[i] ); - valid_direction = qtrue; - } - else - spot[tbm[i]].surfaceNum = -1; - } - } - else - { - valid_direction = qtrue; - - if (count == (ymax - ymin) / XY_STEP + 1) - { - for( i = 0 ; i < count ; i++ ) - AddPointToSurface( surfaceNum, tbm[i] ); - } - else - { - for( i = 0 ; i < count ; i++ ) - spot[tbm[i]].surfaceNum = -1; - minusxhold = qtrue; - minusx--; - } - } - - if ( !valid_direction ) - { - minusx--; - minusxLock = qtrue; - } - } - - if ( !plusyLock && !plusyhold ) - { - plusy++; - count = 0; - test[1] = spot[index].origin[1] + plusy * XY_STEP; - xmin = spot[index].origin[0] - minusx * XY_STEP; - xmax = spot[index].origin[0] + plusx * XY_STEP; - valid_direction = qfalse; - - for ( x = xmin; x <= xmax; x += XY_STEP ) - { - // Find this spot - - test[0] = x; - current_height = Z_MIN; - n = FindSpot( test, spot[index].flags, current_height ); - - while( n != -1 ) - { - // See if this point can be added and the surface stay convex - - if ( CanAddPoint1( surfaceNum, n ) ) - { - // Add this point to this surface - - spot[n].surfaceNum = surfaceNum; - tbm[count] = n; - count++; - - break; - } - - // Get the next spot at this x, y - - current_height = spot[n].origin[2]; - n = FindSpot( test, spot[index].flags, current_height ); - } - } - - if ( plusyalreadyheld ) - { - for( i = 0 ; i < count ; i++ ) - { - if ( CanAddPoint2( surfaceNum, tbm[i] ) ) - { - AddPointToSurface( surfaceNum, tbm[i] ); - valid_direction = qtrue; - } - else - spot[tbm[i]].surfaceNum = -1; - } - } - else - { - valid_direction = qtrue; - - if (count == (xmax - xmin) / XY_STEP + 1) - { - for( i = 0 ; i < count ; i++ ) - AddPointToSurface( surfaceNum, tbm[i] ); - } - else - { - for( i = 0 ; i < count ; i++ ) - spot[tbm[i]].surfaceNum = -1; - plusyhold = qtrue; - plusy--; - } - } - - if ( !valid_direction ) - { - plusy--; - plusyLock = qtrue; - } - } - - if ( !minusyLock && !minusyhold ) - { - minusy++; - count = 0; - test[1] = spot[index].origin[1] - minusy * XY_STEP; - xmin = spot[index].origin[0] - minusx * XY_STEP; - xmax = spot[index].origin[0] + plusx * XY_STEP; - valid_direction = qfalse; - - for ( x = xmin; x <= xmax; x += XY_STEP ) - { - // Find this spot - - test[0] = x; - current_height = Z_MIN; - n = FindSpot( test, spot[index].flags, current_height ); - - while( n != -1 ) - { - // See if this point can be added and the surface stay convex - - if ( CanAddPoint1( surfaceNum, n ) ) - { - // Add this point to this surface - - spot[n].surfaceNum = surfaceNum; - tbm[count] = n; - count++; - - break; - } - - // Get the next spot at this x, y - - current_height = spot[n].origin[2]; - n = FindSpot( test, spot[index].flags, current_height ); - } - } - - if ( minusyalreadyheld ) - { - for( i = 0 ; i < count ; i++ ) - { - if ( CanAddPoint2( surfaceNum, tbm[i] ) ) - { - AddPointToSurface( surfaceNum, tbm[i] ); - valid_direction = qtrue; - } - else - spot[tbm[i]].surfaceNum = -1; - } - } - else - { - valid_direction = qtrue; - - if (count == (xmax - xmin) / XY_STEP + 1) - { - for( i = 0 ; i < count ; i++ ) - AddPointToSurface( surfaceNum, tbm[i] ); - } - else - { - for( i = 0 ; i < count ; i++ ) - spot[tbm[i]].surfaceNum = -1; - minusyhold = qtrue; - minusy--; - } - } - - if ( !valid_direction ) - { - minusy--; - minusyLock = qtrue; - } - } - } - - // Setup surface info - - surf = &surface[surfaceNum]; - surf->flags = spot[index].flags; - - surf->absmin[0] = spot[index].origin[0] - ( minusx * XY_STEP ); - surf->absmin[1] = spot[index].origin[1] - ( minusy * XY_STEP ); - - surf->absmax[0] = spot[index].origin[0] + ( plusx * XY_STEP ); - surf->absmax[1] = spot[index].origin[1] + ( plusy * XY_STEP ); - - surf->origin[0] = ( surf->absmin[0] + surf->absmax[0] ) * 0.5; - surf->origin[1] = ( surf->absmin[1] + surf->absmax[1] ) * 0.5; - surf->origin[2] = spot[index].origin[2]; - - gi.DebugPrintf( "surface #%d - Spot %d : origin %s\n", surfaceNum, index, vtos( surf->origin ) ); -} - -static int CompareSpots( const void *a, const void *b ) { - nspot_t *s1 = &spot[*(int *)a]; - nspot_t *s2 = &spot[*(int *)b]; - - // x - if ( s1->origin[0] < s2->origin[0] ) { - return -1; - } - if ( s1->origin[0] > s2->origin[0] ) { - return 1; - } - - // y - if ( s1->origin[1] < s2->origin[1] ) { - return -1; - } - if ( s1->origin[1] > s2->origin[1] ) { - return 1; - } - - // z - if ( s1->origin[2] > s2->origin[2] ) { - return -1; - } - if ( s1->origin[2] < s2->origin[2] ) { - return 1; - } - - return 0; -} - -static void SortSpots( void ) -{ - int n; - //int i; - //float z; - //float cz; - - for ( n = 0; n < spotCount; n++ ) - sortIndex[n] = n; - - for ( n = 0; n < (((XY_MAX - XY_MIN) / XY_STEP) + 2); n++ ) - spotIndex[n] = 0; - - qsort( sortIndex, spotCount, sizeof(sortIndex[0]), CompareSpots ); -} - -static void FindConvexSurfaces( void ) -{ - int n; - - surface = ( nsurface_t * )gi.TagMalloc ( MAX_SURFACES * sizeof(surface[0]), TAG_GAME ); - surfaceCount = 0; - - SortSpots(); - - for ( n = 0; n < spotCount; n++ ) - { - if ( spot[sortIndex[n]].surfaceNum == -1 ) - BuildConvexSurface( sortIndex[n] ); - } - - gi.TagFree( spot ); - - gi.Printf( " %i surfaces\n", surfaceCount ); -} - -// -// FindNeighbors -// - -// stats on point to edge reachability testing -typedef struct { - int count; - int accept; - int reject1; - int reject2; - int reject3; - int pmoveCount; -} reachStats_t; - -// stats on surface to surface testing -typedef struct { - int count; - int accept; - int reject; - int treject1; - int treject2; - int treject3; - int treject4; - int zeroNeighbors; -} surfaceStats_t; - -// per source surface info -// -// The reason for the local neighbors array and MAX_NEIGHBORS_PER_SURFACE is so FindSurfaceNeighbors -// can be run on many surfaces at once when multithreaded. - -#define MAX_NEIGHBORS_PER_SURFACE 256 - -typedef struct { - int number; - nsurface_t *surface; - int neighborCount; - nneighbor_t neighbor[MAX_NEIGHBORS_PER_SURFACE]; -} sourceSurfaceInfo_t; - -// per target surface info -typedef struct { - int number; - nsurface_t *surface; - qboolean edgeActive; - vec2_t edgeStart; - vec2_t edgeEnd; - int edgeFlags; - float cost; -} targetSurfaceInfo_t; - -// per thread neighbor testing info block -typedef struct { - reachStats_t rStats; - surfaceStats_t sStats; - sourceSurfaceInfo_t sSurf; - targetSurfaceInfo_t tSurf; -} surfaceThreadInfo_t; - -// global (per map) instances of stats; used to sum all the per thread stats -static reachStats_t reachStats; -static surfaceStats_t surfStats; - - -#define FLOAT_TO_VELOCITY 16.0 -#define VELOCITY_TO_FLOAT (1.0/FLOAT_TO_VELOCITY) - -static int SurfaceNumberAtPoint( vec3_t point ) { - vec3_t p; - int n; - - p[0] = point[0]; - p[1] = point[1]; - p[2] = floor( point[2] ); - - for ( n = 0; n < surfaceCount; n++ ) { - if ( floor( surface[n].origin[2] ) != p[2] ) { - continue; - } - if ( ( surface[n].absmin[0] - 16 ) > p[0] ) { - continue; - } - if ( ( surface[n].absmax[0] + 16 ) < p[0] ) { - continue; - } - if ( ( surface[n].absmin[1] - 16 ) > p[1] ) { - continue; - } - if ( ( surface[n].absmax[1] + 16 ) < p[1] ) { - continue; - } - return n; - } - - return -1; -} - - -static qboolean PointIsOnSurfaceNumber( vec3_t point, int n ) { - vec3_t p; - - p[0] = point[0]; - p[1] = point[1]; - p[2] = floor( point[2] ); - - if ( floor( surface[n].origin[2] ) != p[2] ) { - return qfalse; - } - if ( ( surface[n].absmin[0] - 16 ) > p[0] ) { - return qfalse; - } - if ( ( surface[n].absmax[0] + 16 ) < p[0] ) { - return qfalse; - } - if ( ( surface[n].absmin[1] - 16 ) > p[1] ) { - return qfalse; - } - if ( ( surface[n].absmax[1] + 16 ) < p[1] ) { - return qfalse; - } - return qtrue; -} - -static void ReachTrace(trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contents, qboolean cylinder ) - { - trace_t tr; - - gi.trace ( &tr, start, mins, maxs, end, passEntityNum, contents, cylinder ); - - //FIXME this is FUGLY - while ( tr.entityNum && ( g_entities[tr.entityNum].s.eType == ET_MOVER ) ) - { - if ( Q_stricmp( g_entities[tr.entityNum].entname, "func_plat" ) == 0 ) - { - *result = tr; - return; - } - gi.trace ( &tr, tr.endpos, mins, maxs, end, tr.entityNum, contents, cylinder ); - if ( tr.fraction == 0.0 ) - { - *result = tr; - return; - } - } - *result = tr; - return; - } - -//FIXME try start running, start walking, and start motionless (special flags set if slower speed required) -static qboolean CanReach( surfaceThreadInfo_t *info, vec3_t start, vec3_t dir, int *flags ) { - pmove_t pm; - playerState_t ps; - int n; - int currentSurface; - vec3_t lastOrigin; - - info->rStats.count++; - - *flags = 0; - - VectorNormalize( dir ); - VectorCopy( start, lastOrigin ); - - memset( &pm, 0, sizeof( pm ) ); - memset( &ps, 0, sizeof( ps ) ); - pm.ps = &ps; - pm.cmd.msec = PMOVE_MSEC; - pm.cmd.buttons = 0; - pm.cmd.weapon = 0; - pm.cmd.angles[0] = 0; - pm.cmd.angles[1] = 0; - pm.cmd.angles[2] = 0; - pm.cmd.forwardmove = 127; - pm.cmd.rightmove = 0; - pm.cmd.upmove = 0; - pm.tracemask = MASK_DEADSOLID; - pm.noFootsteps = qtrue; - pm.trace = ReachTrace; - pm.pointcontents = gi.pointcontents; - - ps.pm_type = PM_NORMAL; - ps.gravity = sv_gravity->value; - ps.speed = PLAYER_SPEED; - VectorCopy( start, ps.origin ); -// VectorClear( ps.velocity ); - VectorScale( dir, ps.speed, ps.velocity ); - ps.delta_angles[0] = 0; - ps.delta_angles[1] = ANGLE2SHORT ( vectoyaw ( dir ) ); - ps.delta_angles[2] = 0; - ps.groundEntityNum = 0; - ps.clientNum = 0; // FIXME? was ent->s.number; - - // do we need to start ducked? - if ( info->sSurf.surface->flags & SF_DUCK ) { - ps.pm_flags |= PMF_DUCKED; - } - - // does the target surface require us to be ducked - if ( info->tSurf.surface->flags & SF_DUCK ) { - ps.pm_flags |= PMF_DUCKED; - pm.cmd.upmove = -127; - } - - // do we need to jump up? - if ( ( info->tSurf.surface->origin[2] - info->sSurf.surface->origin[2] ) > STEPSIZE ) { - // if we're ducked we can't jump so it is unreachable - if ( ps.pm_flags & PMF_DUCKED ) { - return qfalse; - } - pm.cmd.upmove = 127; - *flags |= NF_JUMP; - } - - // junk we need to fill in so PMove behaves correctly - for( n = 0; n < MAX_STATS; n++ ) { - ps.stats[n] = 0; - } - ps.stats[STAT_HEALTH] = 100; - for( n = 0; n < PW_NUM_POWERUPS; n++ ) { - ps.powerups[n] = 0; - } - - for ( n = 0; n < MAX_PMOVES; n++ ) { - - Pmove( &pm ); - info->rStats.pmoveCount++; - - if( VectorCompare( ps.origin, lastOrigin ) != 0 ) { - info->rStats.reject1++; - return qfalse; - } - VectorCopy( ps.origin, lastOrigin ); - - if ( ps.groundEntityNum == -1 ) { - continue; - } - - currentSurface = SurfaceNumberAtPoint( ps.origin ); - - // FIXME - this happens at the spot under a door - if ( currentSurface == -1 ) { - continue; - } - - if ( pm.pmoveEvent == EV_FALL_FAR ) { - *flags |= NF_FALL2; - } - else if ( pm.pmoveEvent == EV_FALL_MEDIUM ) { - *flags |= NF_FALL1; - } - - if ( PointIsOnSurfaceNumber( ps.origin, info->tSurf.number ) ) { - info->rStats.accept++; - return qtrue; - } - - if ( !PointIsOnSurfaceNumber( ps.origin, info->sSurf.number ) ) { - info->rStats.reject2++; - return qfalse; - } - } - - info->rStats.reject3++; - return qfalse; -} - - -static int FindDestination_Push( surfaceThreadInfo_t *info, gentity_t *pushEnt, int *flags ) { - return -1; -#if 0 - vec3_t dir; - pmove_t pm; - playerState_t ps; - int n; - int currentSurface; - qboolean leftGround; - vec3_t pushVel; - vec3_t absmin; - vec3_t absmax; - int numEnts; - gentity_t *ents[MAX_GENTITIES]; - - *flags = 0; - VectorCopy( pushEnt->movedir, dir ); - VectorCopy( dir, pushVel ); - VectorNormalize( dir ); - - memset( &pm, 0, sizeof( pm ) ); - memset( &ps, 0, sizeof( ps ) ); - pm.ps = &ps; - pm.cmd.msec = PMOVE_MSEC; - pm.cmd.buttons = 0; - pm.cmd.weapon = 0; - pm.cmd.angles[0] = 0; - pm.cmd.angles[1] = 0; - pm.cmd.angles[2] = 0; - pm.cmd.forwardmove = 0; - pm.cmd.rightmove = 0; - pm.cmd.upmove = 0; - pm.tracemask = MASK_DEADSOLID; - pm.noFootsteps = qtrue; - pm.trace = ReachTrace; - pm.pointcontents = gi.pointcontents; - - ps.pm_type = PM_NORMAL; - ps.gravity = g_gravity->value; - ps.speed = PLAYER_SPEED; - VectorCopy( info->sSurf.surface->origin, ps.origin ); - VectorCopy( pushVel, ps.velocity ); - ps.delta_angles[0] = 0; - ps.delta_angles[1] = ANGLE2SHORT ( vectoyaw ( dir ) ); - ps.delta_angles[2] = 0; - ps.groundEntityNum = 0; - ps.playernum = 1; - - // junk we need to fill in so PMove behaves correctly - for( n = 0; n < MAX_STATS; n++ ) { - ps.stats[n] = 0; - } - ps.stats[STAT_HEALTH] = 100; - for( n = 0; n < PW_NUM_POWERUPS; n++ ) { - ps.powerups[n] = 0; - } - - leftGround = qfalse; - for ( n = 0; n < MAX_PMOVES; n++ ) { - VectorAdd( ps.origin, mins, absmin ); - VectorAdd( ps.origin, standMaxs, absmax ); - numEnts = gi.EntitiesInBox( absmin, absmax, ents, MAX_GENTITIES ); - for ( n = 0; n < numEnts; n++ ) { - if ( ents[n] == pushEnt ) { - VectorCopy( pushVel, ps.velocity ); - } - } - - Pmove( &pm ); - if ( ps.groundEntityNum == -1 ) { - leftGround = qtrue; - continue; - } - - currentSurface = SurfaceNumberAtPoint( ps.origin ); - - if ( currentSurface == info->sSurf.number && !leftGround ) { - continue; - } - - if ( pm.pmoveEvent == EV_FALL_FAR ) { - *flags |= NF_FALL2; - } - else if ( pm.pmoveEvent == EV_FALL_MEDIUM ) { - *flags |= NF_FALL1; - } - - info->tSurf.cost = n * PMOVE_MSEC; - - return currentSurface; - } - - return -1; -#endif -} - - -// TeleportPlayer( activator, dest->s.origin, dest->s.angles ); -// AngleVectors( angles, player->client->ps.velocity, NULL, NULL ); -// VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity ); - -static int FindDestination_Teleport( surfaceThreadInfo_t *info, gentity_t *destEnt, int *flags ) { - pmove_t pm; - playerState_t ps; - int n; - int currentSurface; - vec3_t lastOrigin; - vec3_t angles; - - *flags = 0; - - VectorCopy( destEnt->s.origin, lastOrigin ); - lastOrigin[2] += 1; - - AngleVectors( destEnt->s.angles, angles, NULL, NULL ); - - memset( &pm, 0, sizeof( pm ) ); - memset( &ps, 0, sizeof( ps ) ); - pm.ps = &ps; - pm.cmd.msec = PMOVE_MSEC; - pm.cmd.buttons = 0; - pm.cmd.weapon = 0; - pm.cmd.angles[0] = 0; - pm.cmd.angles[1] = 0; - pm.cmd.angles[2] = 0; - pm.cmd.forwardmove = 0; - pm.cmd.rightmove = 0; - pm.cmd.upmove = 0; - pm.tracemask = MASK_DEADSOLID; - pm.noFootsteps = qtrue; - pm.trace = ReachTrace; - pm.pointcontents = gi.pointcontents; - - ps.pm_type = PM_NORMAL; - ps.gravity = sv_gravity->value; - ps.speed = PLAYER_SPEED; - VectorCopy( lastOrigin, ps.origin ); - VectorScale( angles, 400, ps.velocity ); - ps.delta_angles[0] = 0; - ps.delta_angles[1] = ANGLE2SHORT ( angles[YAW] ); - ps.delta_angles[2] = 0; - ps.groundEntityNum = 0; - ps.clientNum = 0; - - // junk we need to fill in so PMove behaves correctly - for( n = 0; n < MAX_STATS; n++ ) { - ps.stats[n] = 0; - } - ps.stats[STAT_HEALTH] = 100; - for( n = 0; n < PW_NUM_POWERUPS; n++ ) { - ps.powerups[n] = 0; - } - - n = 0; - while ( 1 ) { - n++; - Pmove( &pm ); - info->rStats.pmoveCount++; - - if( VectorCompare( ps.origin, lastOrigin ) != 0 ) { - break; - } - VectorCopy( ps.origin, lastOrigin ); - - if ( ps.groundEntityNum == -1 ) { - continue; - } - - currentSurface = SurfaceNumberAtPoint( ps.origin ); - - if ( pm.pmoveEvent == EV_FALL_FAR ) { - *flags |= NF_FALL2; - } - else if ( pm.pmoveEvent == EV_FALL_MEDIUM ) { - *flags |= NF_FALL1; - } - - info->tSurf.cost = n * PMOVE_MSEC; - - return currentSurface; - } - - return -1; -} - - -static vec3_t testDir[] = { {0, 1, 0}, {-1, 0, 0}, {0, -1, 0}, {1, 0, 0}, {-0.5, 0.5, 0}, {0.5, 0.5, 0}, {-0.5, -0.5, 0}, {0.5, -0.5, 0} }; - -static void EdgeOpen( surfaceThreadInfo_t *info, vec3_t spot, int flags ) { - info->tSurf.edgeActive = qtrue; - info->tSurf.edgeStart[0] = spot[0]; - info->tSurf.edgeStart[1] = spot[1]; - info->tSurf.edgeEnd[0] = spot[0]; - info->tSurf.edgeEnd[1] = spot[1]; - info->tSurf.edgeFlags = flags; -} - -static void EdgeClose( surfaceThreadInfo_t *info ) { - nneighbor_t *n; - vec3_t vec; - float d; - - n = &info->sSurf.neighbor[info->sSurf.neighborCount]; - - n->surfaceNum = info->tSurf.number; - if ( info->tSurf.edgeStart[0] <= info->tSurf.edgeEnd[0] ) { - n->absmin[0] = info->tSurf.edgeStart[0]; - n->absmax[0] = info->tSurf.edgeEnd[0]; - } - else { - n->absmin[0] = info->tSurf.edgeEnd[0]; - n->absmax[0] = info->tSurf.edgeStart[0]; - } - if ( info->tSurf.edgeStart[1] <= info->tSurf.edgeEnd[1] ) { - n->absmin[1] = info->tSurf.edgeStart[1]; - n->absmax[1] = info->tSurf.edgeEnd[1]; - } - else { - n->absmin[1] = info->tSurf.edgeEnd[1]; - n->absmax[1] = info->tSurf.edgeStart[1]; - } - - n->origin[0] = (n->absmin[0] + n->absmax[0]) * 0.5; - n->origin[1] = (n->absmin[1] + n->absmax[1]) * 0.5; - n->origin[2] = info->sSurf.surface->origin[2]; - - n->flags = info->tSurf.edgeFlags; - - // calc path cost - - if ( info->tSurf.cost ) { - n->cost = info->tSurf.cost; - } - else { - // take dist from source origin to point - VectorSubtract( info->sSurf.surface->origin, n->origin, vec ); - d = VectorLength( vec ); - - // add any movement weights - if ( ( info->sSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) == (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { - d /= SWIMSCALE; - } - else if ( info->sSurf.surface->flags & SF_DUCK ) { - d /= DUCKSCALE; - } - else if ( info->sSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { - d /= WADESCALE; - } - - // save that as first segment distance - n->cost = d; - - // take dist from point to target origin - VectorSubtract( info->tSurf.surface->origin, n->origin, vec ); - d = VectorLength( vec ); - - // add any movement weights - if ( ( info->tSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) == (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { - d /= SWIMSCALE; - } - else if ( info->tSurf.surface->flags & SF_DUCK ) { - d /= DUCKSCALE; - } - else if ( info->tSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { - d /= WADESCALE; - } - - // add that to first distance - n->cost += d; - - // convert distance to time - n->cost = ( n->cost / (float)PLAYER_SPEED ) * 1000.0; - - // possibly add a jump cost - if ( n->flags & NF_JUMP ) { - n->cost += 250.0; //FIXME what is a good value to use here? track actual time used for transitional pmoves! - } - } - - if ( info->tSurf.surface->flags & SF_DUCK ) { - n->flags |= NF_DUCK; - } - -// gi.Printf( "s%i to s%i: edge %f,%f to %f,%f f=%i\n", info->sSurf.number, info->tSurf.number, edgeStart[0], edgeStart[1], edgeEnd[0], edgeEnd[1], *edgeFlags ); -// gi.Printf( "s%i to s%i\n", info->sSurf.number, info->tSurf.number ); - info->tSurf.edgeActive = qfalse; - - info->sSurf.neighborCount++; - if ( info->sSurf.neighborCount == MAX_NEIGHBORS_PER_SURFACE ) { - gi.Printf( "MAX_NEIGHBORS_PER_SURFACE exceeded\n" ); - } -} - -static void EdgeUpdate( surfaceThreadInfo_t *info, qboolean reachable, vec3_t spot, int flags ) { -// gi.Printf( "s1=%i s2=%i spot=%s result=%i f=%i\n", info->sSurf.number, info->tSurf.number, vtos( spot ), reachable, flags ); - if ( reachable ) { - if ( info->tSurf.edgeActive ) { - if ( flags == info->tSurf.edgeFlags ) { - // continue edge - info->tSurf.edgeEnd[0] = spot[0]; - info->tSurf.edgeEnd[1] = spot[1]; - } - else { - EdgeClose( info ); - EdgeOpen( info, spot, flags ); - } - } - else { - EdgeOpen( info, spot, flags ); - } - } - else { - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - } -} - - -static void TestReachSurface( surfaceThreadInfo_t *info ) { - int edgeCode; - float xStart, xEnd; - float yStart, yEnd; - float x, y, z; - vec3_t spot; - int flags; - qboolean reachable; - - // determine which edges of s1 are facing s2 - edgeCode = 0; - - if ( info->tSurf.surface->absmin[1] > info->sSurf.surface->absmax[1] ) { - edgeCode |= 1; - } - if ( info->tSurf.surface->absmax[0] < info->sSurf.surface->absmin[0] ) { - edgeCode |= 2; - } - if ( info->tSurf.surface->absmin[0] > info->sSurf.surface->absmax[0] ) { - edgeCode |= 4; - } - if ( info->tSurf.surface->absmax[1] < info->sSurf.surface->absmin[1] ) { - edgeCode |= 8; - } - - if ( info->tSurf.surface->absmax[1] > info->sSurf.surface->absmax[1] && info->tSurf.surface->absmin[0] <= info->sSurf.surface->absmax[0] && info->tSurf.surface->absmax[0] >= info->sSurf.surface->absmin[0] ) { - edgeCode |= 1; - } - if ( info->tSurf.surface->absmin[0] < info->sSurf.surface->absmin[0] && info->tSurf.surface->absmin[1] <= info->sSurf.surface->absmax[1] && info->tSurf.surface->absmax[1] >= info->sSurf.surface->absmin[1] ) { - edgeCode |= 2; - } - if ( info->tSurf.surface->absmax[0] > info->sSurf.surface->absmax[0] && info->tSurf.surface->absmin[1] <= info->sSurf.surface->absmax[1] && info->tSurf.surface->absmax[1] >= info->sSurf.surface->absmin[1] ) { - edgeCode |= 4; - } - if ( info->tSurf.surface->absmin[1] < info->sSurf.surface->absmin[1] && info->tSurf.surface->absmin[0] <= info->sSurf.surface->absmax[0] && info->tSurf.surface->absmax[0] >= info->sSurf.surface->absmin[0] ) { - edgeCode |= 8; - } - - if ( edgeCode == 0 ) { - gi.Printf( "bad edgeCode\n" ); - return; - } - - // get coordinates for corners - xStart = info->sSurf.surface->absmin[0]; - xEnd = info->sSurf.surface->absmax[0]; - yStart = info->sSurf.surface->absmin[1]; - yEnd = info->sSurf.surface->absmax[1]; - z = info->sSurf.surface->origin[2]; - - // run through the spots on the relevant edges - // for each spot, see if the target surface is reachable from there - info->tSurf.edgeActive = qfalse; - - if ( edgeCode & 1 ) { - for ( x = xStart; x <= xEnd; x += XY_STEP ) { - VectorSet( spot, x, yEnd, z ); - reachable = CanReach( info, spot, testDir[0], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - if ( edgeCode & 2 ) { - for ( y = yStart; y <= yEnd; y += XY_STEP ) { - VectorSet( spot, xStart, y, z ); - reachable = CanReach( info, spot, testDir[1], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - if ( edgeCode & 4 ) { - for ( y = yStart; y <= yEnd; y += XY_STEP ) { - VectorSet( spot, xEnd, y, z ); - reachable = CanReach( info, spot, testDir[3], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - if ( edgeCode & 8 ) { - for ( x = xStart; x <= xEnd; x += XY_STEP ) { - VectorSet( spot, x, yStart, z ); - reachable = CanReach( info, spot, testDir[2], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - // special checks for corners - if ( ( edgeCode & 3 ) == 3 ) { - VectorSet( spot, xStart, yEnd, z ); - reachable = CanReach( info, spot, testDir[4], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - if ( ( edgeCode & 5 ) == 5 ) { - VectorSet( spot, xEnd, yEnd, z ); - reachable = CanReach( info, spot, testDir[5], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - if ( ( edgeCode & 10 ) == 10 ) { - VectorSet( spot, xStart, yStart, z ); - reachable = CanReach( info, spot, testDir[6], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } - - if ( ( edgeCode & 12 ) == 12 ) { - VectorSet( spot, xEnd, yStart, z ); - reachable = CanReach( info, spot, testDir[7], &flags ); - EdgeUpdate( info, reachable, spot, flags ); - } - if ( info->tSurf.edgeActive ) { - EdgeClose( info ); - } -} - - -static void TestReachSurface_Push( surfaceThreadInfo_t *info, gentity_t *pushEnt ) { - int flags; - int destSurf; - - //Q3MAP we will need to calculate movedir the same way the game dll does - - destSurf = FindDestination_Push( info, pushEnt, &flags ); - if ( destSurf == -1 ) { - gi.Printf( "pusher at %s never hit ground?\n", vtos( info->sSurf.surface->origin ) ); - } - else if ( destSurf != info->sSurf.number ) { - info->tSurf.number = destSurf; - info->tSurf.surface = &surface[destSurf]; - info->tSurf.edgeActive = qfalse; - EdgeUpdate( info, qtrue, info->sSurf.surface->origin, flags ); - EdgeClose( info ); - gi.Printf( "pusher at %s ", vtos( info->sSurf.surface->origin ) ); - gi.Printf( "hits surface at %s ", vtos( info->tSurf.surface->origin ) ); - gi.Printf( "(%i,%i)-(%i,%i)\n", (int)info->tSurf.surface->absmin[0], (int)info->tSurf.surface->absmin[1], (int)info->tSurf.surface->absmax[0], (int)info->tSurf.surface->absmax[1] ); - } - else { - gi.Printf( WARNING "bad pusher at %s\n", vtos( info->sSurf.surface->origin ) ); - } -} - - -static void TestReachSurface_Teleport( surfaceThreadInfo_t *info, gentity_t *teleportEnt ) { - int flags; - int destSurf; - - destSurf = FindDestination_Teleport( info, teleportEnt, &flags ); - if ( destSurf != -1 ) { - info->tSurf.number = destSurf; - info->tSurf.surface = &surface[destSurf]; - info->tSurf.edgeActive = qfalse; - EdgeUpdate( info, qtrue, info->sSurf.surface->origin, flags ); - EdgeClose( info ); - } -} - - -static void CreatePlatNeighbor( surfaceThreadInfo_t *info ) { -#if 0 - nneighbor_t *n; - gentity_t *ent; - - n = &info->sSurf.neighbor[info->sSurf.neighborCount]; - ent = &g_entities[info->tSurf.surface->parm]; - - n->surfaceNum = info->tSurf.number; - - n->absmin[0] = info->sSurf.surface->absmin[0] + 8; - n->absmin[1] = info->sSurf.surface->absmin[1] + 8; - - n->absmax[0] = info->sSurf.surface->absmax[0] - 8; - n->absmax[1] = info->sSurf.surface->absmax[1] - 8; - - VectorCopy( info->sSurf.surface->origin, n->origin ); - n->flags = NF_PLAT; - n->cost = ( ( ent->pos2[2] - ent->pos1[2] ) / (float)PLAYER_SPEED ) * 1000.0; - info->sSurf.neighborCount++; -#endif -} - - -static void FindSurfaceNeighbors( int surfaceNum ) { - int n; - int oldCount; - surfaceThreadInfo_t info; - gentity_t *ent; - - memset( &info, 0, sizeof( info ) ); - info.sSurf.number = surfaceNum; - info.sSurf.surface = &surface[surfaceNum]; - info.sSurf.neighborCount = 0; - - //FIXME we must handle special surface cases here - push, teleport - // they don't need to check every other surface, where player will wind - // up is predetermined (roughly at least) - - // teleporter special case - if ( info.sSurf.surface->flags & SF_TELEPORTER ) { - ent = &g_entities[info.sSurf.surface->parm]; - TestReachSurface_Teleport( &info, ent ); - goto updateGlobals; - } - - // trigger_push special case - if ( info.sSurf.surface->flags & SF_PUSH ) { - ent = &g_entities[info.sSurf.surface->parm]; - TestReachSurface_Push( &info, ent ); - goto updateGlobals; - } -#if 0 - // Q3MAP: reverse this - // if this is a PLATHIGH surface, we need to temporarily relink the plat to the high position - if ( info.sSurf.surface->flags & SF_PLATHIGH ) { - ent = &g_entities[info.sSurf.surface->parm]; - VectorCopy( ent->pos2, ent->s.origin ); - VectorCopy( ent->pos2, ent->currentOrigin ); - gi.linkentity( ent ); - } -#endif - for ( n = 0; n < surfaceCount; n++ ) { - if ( n == info.sSurf.number ) { - info.sStats.treject1++; - continue; - } - - info.tSurf.number = n; - info.tSurf.surface = &surface[n]; - - // plat high surfaces are a special case as a target - // only the corresponding plat low should have them as a neighbor - if ( info.tSurf.surface->flags & SF_PLATHIGH ) { - if ( info.sSurf.surface->flags & SF_PLATLOW ) { - CreatePlatNeighbor( &info ); - info.sStats.accept++; - } - continue; - } - - // reject if surf is too high to be reached - if ( ( info.tSurf.surface->origin[2] - info.sSurf.surface->origin[2] ) > MAX_JUMPHEIGHT ) { - info.sStats.treject2++; - continue; - } - - // reject is surf XY range is a subset of our own (meaning it is underneath us and not directly reachable) - if ( ( info.tSurf.surface->absmin[0] >= info.sSurf.surface->absmin[0] ) && ( info.tSurf.surface->absmin[1] >= info.sSurf.surface->absmin[1] ) && - ( info.tSurf.surface->absmax[0] <= info.sSurf.surface->absmax[0] ) && ( info.tSurf.surface->absmax[1] <= info.sSurf.surface->absmax[1] ) ) { - info.sStats.treject3++; - continue; - } - - // reject if surf origin is not in PVS - if ( !gi.inPVSIgnorePortals( info.tSurf.surface->origin, info.sSurf.surface->origin ) ) { - info.sStats.treject4++; - continue; - } - - // see if it's a neighbor - info.sStats.count++; - oldCount = info.sSurf.neighborCount; - TestReachSurface( &info ); - if ( info.sSurf.neighborCount != oldCount ) { - info.sStats.accept++; - } - else { - info.sStats.reject++; - } - } - -#if 0 - // Q3MAP: reverse this - // if this is a PLATHIGH surface, we need to restore the plat to the low position - if ( info.sSurf.surface->flags & SF_PLATHIGH ) { - ent = &g_entities[info.sSurf.surface->parm]; - VectorCopy( ent->pos1, ent->s.origin ); - VectorCopy( ent->pos1, ent->currentOrigin ); - gi.linkentity( ent ); - } -#endif - if ( neighborCount + info.sSurf.neighborCount > MAX_NEIGHBORS ) { - gi.Printf( "MAX_NEIGHBORS exceeded\n" ); - return; - } - -updateGlobals: - // grab the critical section lock to do global variable updates - ThreadLock(); - - // reserve the block of neighbors we need - surface[info.sSurf.number].neighborIndex = neighborCount; - neighborCount += info.sSurf.neighborCount; - - // update global stats - surfStats.count += info.sStats.count; - surfStats.accept += info.sStats.accept; - surfStats.reject += info.sStats.reject; - surfStats.treject1 += info.sStats.treject1; - surfStats.treject2 += info.sStats.treject2; - surfStats.treject3 += info.sStats.treject3; - surfStats.treject4 += info.sStats.treject4; - if ( info.sSurf.neighborCount == 0 ) { - surfStats.zeroNeighbors++; - } - - reachStats.count += info.rStats.count; - reachStats.accept += info.rStats.accept; - reachStats.reject1 += info.rStats.reject1; - reachStats.reject2 += info.rStats.reject2; - reachStats.reject3 += info.rStats.reject3; - reachStats.pmoveCount += info.rStats.pmoveCount; - - // release the lock - ThreadUnlock(); - - // now we can fill in the block of neighbors from our cache - surface[info.sSurf.number].neighborCount = info.sSurf.neighborCount; - if ( info.sSurf.neighborCount ) { - memcpy( &neighbor[surface[info.sSurf.number].neighborIndex], info.sSurf.neighbor, info.sSurf.neighborCount * sizeof( info.sSurf.neighbor[0] ) ); - } - -} - - -static void FindNeighbors( void ) { - int n; - - neighbor = ( nneighbor_t * )gi.TagMalloc ( MAX_NEIGHBORS * sizeof(neighbor[0]), TAG_GAME ); - neighborCount = 0; - - memset( &reachStats, 0, sizeof( reachStats ) ); - memset( &surfStats, 0, sizeof( surfStats ) ); - -// RunThreadsOn( spotIndexCount, qtrue, FindSurfaceNeighbors ); -//#if 0 - for ( n = 0; n < surfaceCount; n++ ) { - gi.DebugPrintf( "FindSurfaceNeighbors %d/%d\n", n, surfaceCount ); - FindSurfaceNeighbors( n ); - } -//#endif - - gi.Printf( " %i neighbors (avg %.2f per surf)\n", neighborCount, (float)neighborCount/(float)surfaceCount ); - gi.Printf( " %i surfaces with 0 neighbors\n", surfStats.zeroNeighbors ); - - gi.Printf( " surface to surface testing stats:\n" ); - gi.Printf( " %i combinations\n", surfaceCount * surfaceCount ); - gi.Printf( " %i trivial rejects (%i %i %i %i)\n", surfStats.treject1 + surfStats.treject2 + surfStats.treject3 + surfStats.treject4, surfStats.treject1, surfStats.treject2, surfStats.treject3, surfStats.treject4 ); - gi.Printf( " %i full tests (%.2f avg per surf)\n", surfStats.count, (float)surfStats.count / (float)surfaceCount ); - gi.Printf( " %i accepted, %i rejected\n", surfStats.accept, surfStats.reject ); - - gi.Printf( " spot to surface testing stats:\n" ); - gi.Printf( " %i tests (%.2f avg per surf)\n", reachStats.count, (float)reachStats.count / (float)surfaceCount ); - gi.Printf( " %i accepted, %i rejected (%i %i %i)\n", reachStats.accept, reachStats.reject1 + reachStats.reject2 + reachStats.reject3, reachStats.reject1, reachStats.reject2, reachStats.reject3 ); - gi.Printf( " %.2f avg pmoves per test\n", (float)reachStats.pmoveCount / (float)reachStats.count ); -} - - -// -// InflateSurfaces -// - -static void InflateSurfaces( void ) { - int n; - - // inflate surfaces by 16 along both axis - // also drop the Z value by mins - for ( n = 0; n < surfaceCount; n++ ) { - surface[n].absmin[0] -= 0; - surface[n].absmin[1] -= 0; - surface[n].absmax[0] += 0; - surface[n].absmax[1] += 0; - surface[n].origin[2] = floor( surface[n].origin[2] + mins[2] ); - } - - // inflate neighbor edges by 16 along the fixed axis - for ( n = 0; n < neighborCount; n++ ) { - if ( neighbor[n].absmin[0] == neighbor[n].absmax[0] ) { - neighbor[n].absmin[0] -= 0; - neighbor[n].absmax[0] += 0; - } - if ( neighbor[n].absmin[1] == neighbor[n].absmax[1] ) { - neighbor[n].absmin[1] -= 0; - neighbor[n].absmax[1] += 0; - } - neighbor[n].origin[2] = floor( neighbor[n].origin[2] + mins[2] ); - } -} - - -// -// CalculateAllRoutes -// - -typedef enum { - nodestate_estimate, - nodestate_final -} nodeState_t; - -typedef struct { - float cost; - nodeState_t state; - int predecessor; -} nodeInfo_t; - -static nodeInfo_t *nodeInfo; - - -static int NeighborIndex( int sourceSurfNum, int destSurfNum ) { - int base; - int n; - - if ( destSurfNum == -1 ) { - return -1; - } - base = surface[sourceSurfNum].neighborIndex; - for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) { - if ( neighbor[base+n].surfaceNum == destSurfNum ) { - return n; - } - } - return -1; -} - - -static nneighbor_t *PathEdge( int sourceSurfNum, int destSurfNum ) { - int base; - int n; - - base = surface[sourceSurfNum].neighborIndex; - for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) { - if ( neighbor[base+n].surfaceNum == destSurfNum ) { - return &neighbor[base+n]; - } - } - return NULL; -} - - -/* -============= -SurfaceDistance - -Returns the cost of moving from sourceSurfNum to targetSurfNum, 0 if there -is no direct path. -============= -*/ - -static float SurfaceDistance( int sourceSurfNum, int destSurfNum ) { - nneighbor_t *n; - - n = PathEdge( sourceSurfNum, destSurfNum ); - if ( n ) { - return n->cost; - } - return 0; -} - - -/* -============= -CalculateRoutes - -Takes the surfaces and neighbors tablea and uses Dijkstra's algorithm to -determine the shortest route from one surface to another. -============= -*/ - -static void CalculateRoutes( int rootSurfaceNum ) { - int n; - int currentNode; - int testNode; - float bestCost; - int bestNode; - float d; - - // initialize the node info - for ( n = 0; n < surfaceCount; n++ ) { - nodeInfo[n].cost = INFINITE; - nodeInfo[n].state = nodestate_estimate; - nodeInfo[n].predecessor = -1; - } - - // prime thing to get the loop started - currentNode = rootSurfaceNum; - nodeInfo[rootSurfaceNum].cost= 0; - - // calculate the shortest path info - // we loop surfaceCount times; a new final node is determined each iteration - n = 0; - while ( currentNode != -1 ) { - - bestCost = INFINITE; - bestNode = -1; - - // test each node - for ( testNode = 0; testNode < surfaceCount; testNode++ ) { - // do not test it against itself - if ( testNode == currentNode ) { - continue; - } - - // leave final nodes alone - if ( nodeInfo[testNode].state == nodestate_final ) { - continue; - } - - if ( surface[testNode].neighborCount == 0 ) { - continue; - } - - // update adjacent nodes - d = SurfaceDistance( currentNode, testNode ); - if ( d != 0 ) { - // see if we can improve the current estimate at the test node - if ( nodeInfo[currentNode].cost + d < nodeInfo[testNode].cost ) - { - nodeInfo[testNode].predecessor = currentNode; - nodeInfo[testNode].cost = nodeInfo[currentNode].cost + d; - } - } - - // see if this is our new best estimate - if ( nodeInfo[testNode].cost < bestCost ) { - bestCost = nodeInfo[testNode].cost; - bestNode = testNode; - } - } - - // mark current node as final and best node as new current node - nodeInfo[currentNode].state = nodestate_final; - currentNode = bestNode; - n++; - } - - // now fill in the route info - for ( n = 0; n < surfaceCount; n++ ) { - if ( n == rootSurfaceNum ) { - route[rootSurfaceNum * surfaceCount + n] = 255; - continue; - } - testNode = n; - while ( ( testNode != -1 ) && ( nodeInfo[testNode].predecessor != rootSurfaceNum ) ) { - testNode = nodeInfo[testNode].predecessor; - } - if ( testNode == -1 ) { - route[rootSurfaceNum * surfaceCount + n] = 255; - continue; - } - route[rootSurfaceNum * surfaceCount + n] = NeighborIndex( rootSurfaceNum, testNode ); - } -} - - -static void CalculateAllRoutes( void ) { - int n; - - route = ( byte * )gi.TagMalloc ( surfaceCount * surfaceCount * sizeof( byte ), TAG_GAME ); - nodeInfo = ( nodeInfo_t * )gi.TagMalloc ( surfaceCount * sizeof( nodeInfo[0] ), TAG_GAME ); - - for ( n = 0; n < surfaceCount; n++ ) { - CalculateRoutes( n ); - } - - gi.TagFree( nodeInfo ); -} - - - -// -// WriteNavigationData -// - -static void WriteNavigationData( void ) { - FILE *f; - int n; - navheader_t outHeader; - nsurface_t outSurface; - nneighbor_t outNeighbor; - str filename; - str osFilename; - - Swap_Init(); - - filename = str( "maps/" ) + level.mapname.c_str() + ".nav"; - gi.Printf( "Writing %s.\n", filename.c_str() ); - osFilename = gi.FS_PrepFileWrite( filename.c_str() ); - f = fopen( osFilename.c_str(), "wb" ); - if ( !f ) - { - gi.Printf( "Open failed.\n" ); - return; - } - - // write version header - outHeader.id = LittleLong( NAVFILE_ID ); - outHeader.version = LittleLong( NAVFILE_VERSION ); - outHeader.surfaceCount = LittleLong( surfaceCount ); - outHeader.neighborCount = LittleLong( neighborCount ); - fwrite( &outHeader, sizeof( outHeader ), 1, f ); - - // write surfaces - for ( n = 0; n < surfaceCount; n++ ) { - outSurface.origin[0] = LittleFloat( surface[n].origin[0] ); - outSurface.origin[1] = LittleFloat( surface[n].origin[1] ); - outSurface.origin[2] = LittleFloat( surface[n].origin[2] ); - - outSurface.absmin[0] = LittleFloat( surface[n].absmin[0] ); - outSurface.absmin[1] = LittleFloat( surface[n].absmin[1] ); - - outSurface.absmax[0] = LittleFloat( surface[n].absmax[0] ); - outSurface.absmax[1] = LittleFloat( surface[n].absmax[1] ); - - outSurface.flags = LittleLong( surface[n].flags ); - outSurface.neighborCount = LittleLong( surface[n].neighborCount ); - outSurface.neighborIndex = LittleLong( surface[n].neighborIndex ); - outSurface.parm = LittleLong( surface[n].parm ); - - fwrite( &outSurface, sizeof( outSurface ), 1, f ); - - gi.Printf( "surface%02i f=%04x n=%i@%i z=%i ", n, surface[n].flags, surface[n].neighborCount, surface[n].neighborIndex, (int)surface[n].origin[2] ); - gi.Printf( "(%i,%i)-(%i,%i)\n", (int)surface[n].absmin[0], (int)surface[n].absmin[1], (int)surface[n].absmax[0], (int)surface[n].absmax[1] ); - } - - // write neighbors - for ( n = 0; n < neighborCount; n++ ) { - outNeighbor.origin[0] = LittleFloat( neighbor[n].origin[0] ); - outNeighbor.origin[1] = LittleFloat( neighbor[n].origin[1] ); - outNeighbor.origin[2] = LittleFloat( neighbor[n].origin[2] ); - - outNeighbor.absmin[0] = LittleFloat( neighbor[n].absmin[0] ); - outNeighbor.absmin[1] = LittleFloat( neighbor[n].absmin[1] ); - - outNeighbor.absmax[0] = LittleFloat( neighbor[n].absmax[0] ); - outNeighbor.absmax[1] = LittleFloat( neighbor[n].absmax[1] ); - - outNeighbor.surfaceNum = LittleLong( neighbor[n].surfaceNum ); - outNeighbor.flags = LittleLong( neighbor[n].flags ); - outNeighbor.cost = LittleLong( neighbor[n].cost ); - outNeighbor.filler = LittleLong( neighbor[n].filler ); - - fwrite( &outNeighbor, sizeof( outNeighbor ), 1, f ); - - gi.Printf( "neighbor%03i f=%04x surface=%02i cost=%f\n", n, neighbor[n].flags, neighbor[n].surfaceNum, neighbor[n].cost ); - } - - // write routes - fwrite( route, surfaceCount * surfaceCount * sizeof( byte ), 1, f ); - - fclose( f ); -} - - -// -// Nav_Gen_f -// - -void Nav_Gen_f( void ) { - int start; - int elapsed; - int i; - gentity_t *ent; - - for( i = 0; i < globals.num_entities; i++ ) - { - ent = &g_entities[i]; - if ( ent->entity && ent->entity->isSubclassOf( Mover ) ) - { - ent->entity->unlink(); - } - } - - // FindSpots - gi.Printf( "FindSpots\n" ); - start = gi.Milliseconds(); - FindSpots(); - elapsed = gi.Milliseconds() - start; - gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); - - // FindSurfaces - gi.Printf( "FindSurfaces\n" ); - start = gi.Milliseconds(); - //FindSurfaces(); - FindConvexSurfaces(); - elapsed = gi.Milliseconds() - start; - gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); - - // FindNeighbors - gi.Printf( "FindNeighbors\n" ); - start = gi.Milliseconds(); - FindNeighbors(); - elapsed = gi.Milliseconds() - start; - gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); - - // InflateSurfaces - gi.Printf( "InflateSurfaces\n" ); - start = gi.Milliseconds(); - InflateSurfaces(); - elapsed = gi.Milliseconds() - start; - gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); - - // CalculateAllRoutes - gi.Printf( "CalculateAllRoutes\n" ); - start = gi.Milliseconds(); - CalculateAllRoutes(); - elapsed = gi.Milliseconds() - start; - gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); - - // WriteNavigationData - start = gi.Milliseconds(); - WriteNavigationData(); - elapsed = gi.Milliseconds() - start; - gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); - - gi.TagFree( route ); - gi.TagFree( neighbor ); - gi.TagFree( surface ); - - for( i = 0; i < globals.num_entities; i++ ) - { - ent = &g_entities[i]; - if ( ent->entity && ent->entity->isSubclassOf( Mover ) ) - { - ent->entity->link(); - } - } -} diff --git a/code/game/barrels.cpp b/code/game/barrels.cpp index e08fb791..e28e47b1 100644 --- a/code/game/barrels.cpp +++ b/code/game/barrels.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "barrels.h" #include "weaputils.h" +#include "level.h" /***************************************************************************** /*QUAKED func_barrel (0 0.25 0.5) ? INDESTRUCTABLE diff --git a/code/globalcpp/baseimp.h b/code/game/baseimp.h similarity index 100% rename from code/globalcpp/baseimp.h rename to code/game/baseimp.h diff --git a/code/game/be_aas.h b/code/game/be_aas.h deleted file mode 100644 index b46d3051..00000000 --- a/code/game/be_aas.h +++ /dev/null @@ -1,210 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_aas.h - * - * desc: Area Awareness System, stuff exported to the AI - * - * $Archive: /Code/DLLs/game/be_aas.h $ - * $Author: Steven $ - * $Revision: 2 $ - * $Modtime: 10/13/03 9:01a $ - * $Date: 10/13/03 9:11a $ - * - *****************************************************************************/ - -#ifndef MAX_STRINGFIELD -#define MAX_STRINGFIELD 80 -#endif - -//travel flags -#define TFL_INVALID 0x00000001 //traveling temporary not possible -#define TFL_WALK 0x00000002 //walking -#define TFL_CROUCH 0x00000004 //crouching -#define TFL_BARRIERJUMP 0x00000008 //jumping onto a barrier -#define TFL_JUMP 0x00000010 //jumping -#define TFL_LADDER 0x00000020 //climbing a ladder -#define TFL_WALKOFFLEDGE 0x00000080 //walking of a ledge -#define TFL_SWIM 0x00000100 //swimming -#define TFL_WATERJUMP 0x00000200 //jumping out of the water -#define TFL_TELEPORT 0x00000400 //teleporting -#define TFL_ELEVATOR 0x00000800 //elevator -#define TFL_ROCKETJUMP 0x00001000 //rocket jumping -#define TFL_BFGJUMP 0x00002000 //bfg jumping -#define TFL_GRAPPLEHOOK 0x00004000 //grappling hook -#define TFL_DOUBLEJUMP 0x00008000 //double jump -#define TFL_RAMPJUMP 0x00010000 //ramp jump -#define TFL_STRAFEJUMP 0x00020000 //strafe jump -#define TFL_JUMPPAD 0x00040000 //jump pad -#define TFL_AIR 0x00080000 //travel through air -#define TFL_WATER 0x00100000 //travel through water -#define TFL_SLIME 0x00200000 //travel through slime -#define TFL_LAVA 0x00400000 //travel through lava -#define TFL_DONOTENTER 0x00800000 //travel through donotenter area -#define TFL_FUNCBOB 0x01000000 //func bobbing -#define TFL_FLIGHT 0x02000000 //flight -#define TFL_BRIDGE 0x04000000 //move over a bridge -// -#define TFL_NOTTEAM1 0x08000000 //not team 1 -#define TFL_NOTTEAM2 0x10000000 //not team 2 - -//default travel flags -#define TFL_DEFAULT TFL_WALK|TFL_CROUCH|TFL_BARRIERJUMP|\ - TFL_JUMP|TFL_LADDER|\ - TFL_WALKOFFLEDGE|TFL_SWIM|TFL_WATERJUMP|\ - TFL_TELEPORT|TFL_ELEVATOR|\ - TFL_AIR|TFL_WATER|TFL_JUMPPAD|TFL_FUNCBOB - -// already defined in g_public.h in tiki tech, moved to l_util.h so the botlib stuff compiles but the gamecode also compiles -/* -typedef enum -{ - SOLID_NOT, // no interaction with other objects - SOLID_TRIGGER, // only touch when inside, after moving - SOLID_BBOX, // touch on edge - SOLID_BSP // bsp clip, touch on edge -} solid_t; -*/ - -//a trace is returned when a box is swept through the AAS world -typedef struct aas_trace_s -{ - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - int ent; // entity blocking the trace - int lastarea; // last area the trace was in (zero if none) - int area; // area blocking the trace (zero if none) - int planenum; // number of the plane that was hit -} aas_trace_t; - -// Defined in botlib.h - -//bsp_trace_t hit surface -/* -typedef struct bsp_surface_s -{ - char name[16]; - int flags; - int value; -} bsp_surface_t; - -//a trace is returned when a box is swept through the BSP world -typedef struct bsp_trace_s -{ - qboolean allsolid; // if true, plane is not valid - qboolean startsolid; // if true, the initial point was in a solid area - float fraction; // time completed, 1.0 = didn't hit anything - vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - float exp_dist; // expanded plane distance - int sidenum; // number of the brush side hit - bsp_surface_t surface; // hit surface - int contents; // contents on other side of surface hit - int ent; // number of entity hit -} bsp_trace_t; -*/ -// - - -//entity info -typedef struct aas_entityinfo_s -{ - int valid; // true if updated this frame - int type; // entity type - int flags; // entity flags - float ltime; // local time - float update_time; // time between last and current update - int number; // number of the entity - vec3_t origin; // origin of the entity - vec3_t angles; // angles of the model - vec3_t old_origin; // for lerping - vec3_t lastvisorigin; // last visible origin - vec3_t mins; // bounding box minimums - vec3_t maxs; // bounding box maximums - int groundent; // ground entity - int solid; // solid type - int modelindex; // model used - int modelindex2; // weapons, CTF flags, etc - int frame; // model frame number - int event; // impulse events -- muzzle flashes, footsteps, etc - int eventParm; // even parameter - int powerups; // bit flags - int weapon; // determines weapon and flash model, etc - int legsAnim; // mask off ANIM_TOGGLEBIT - int torsoAnim; // mask off ANIM_TOGGLEBIT -} aas_entityinfo_t; - -// area info -typedef struct aas_areainfo_s -{ - int contents; - int flags; - int presencetype; - int cluster; - vec3_t mins; - vec3_t maxs; - vec3_t center; -} aas_areainfo_t; - -// client movement prediction stop events, stop as soon as: -#define SE_NONE 0 -#define SE_HITGROUND 1 // the ground is hit -#define SE_LEAVEGROUND 2 // there's no ground -#define SE_ENTERWATER 4 // water is entered -#define SE_ENTERSLIME 8 // slime is entered -#define SE_ENTERLAVA 16 // lava is entered -#define SE_HITGROUNDDAMAGE 32 // the ground is hit with damage -#define SE_GAP 64 // there's a gap -#define SE_TOUCHJUMPPAD 128 // touching a jump pad area -#define SE_TOUCHTELEPORTER 256 // touching teleporter -#define SE_ENTERAREA 512 // the given stoparea is entered -#define SE_HITGROUNDAREA 1024 // a ground face in the area is hit -#define SE_HITBOUNDINGBOX 2048 // hit the specified bounding box -#define SE_TOUCHCLUSTERPORTAL 4096 // touching a cluster portal - -typedef struct aas_clientmove_s -{ - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - vec3_t velocity; //velocity at the end of movement prediction - aas_trace_t trace; //last trace - int presencetype; //presence type at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - float time; //time predicted ahead - int frames; //number of frames predicted ahead -} aas_clientmove_t; - -// alternate route goals -#define ALTROUTEGOAL_ALL 1 -#define ALTROUTEGOAL_CLUSTERPORTALS 2 -#define ALTROUTEGOAL_VIEWPORTALS 4 - -typedef struct aas_altroutegoal_s -{ - vec3_t origin; - int areanum; - unsigned short starttraveltime; - unsigned short goaltraveltime; - unsigned short extratraveltime; -} aas_altroutegoal_t; - -// route prediction stop events -#define RSE_NONE 0 -#define RSE_NOROUTE 1 //no route to goal -#define RSE_USETRAVELTYPE 2 //stop as soon as on of the given travel types is used -#define RSE_ENTERCONTENTS 4 //stop when entering the given contents -#define RSE_ENTERAREA 8 //stop when entering the given area - -typedef struct aas_predictroute_s -{ - vec3_t endpos; //position at the end of movement prediction - int endarea; //area at end of movement prediction - int stopevent; //event that made the prediction stop - int endcontents; //contents at the end of movement prediction - int endtravelflags; //end travel flags - int numareas; //number of areas predicted ahead - int time; //time predicted ahead (in hundreth of a sec) -} aas_predictroute_t; diff --git a/code/game/be_ai_char.h b/code/game/be_ai_char.h deleted file mode 100644 index b28801b8..00000000 --- a/code/game/be_ai_char.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_char.h - * - * desc: bot characters - * - * $Archive: /Code/DLLs/game/be_ai_char.h $ - * $Author: Jwaters $ - * $Revision: 1 $ - * $Modtime: 5/17/02 11:35a $ - * $Date: 7/31/02 10:45a $ - * - *****************************************************************************/ - -//loads a bot character from a file -int BotLoadCharacter(char *charfile, float skill); -//frees a bot character -void BotFreeCharacter(int character); -//returns a float characteristic -float Characteristic_Float(int character, int index); -//returns a bounded float characteristic -float Characteristic_BFloat(int character, int index, float min, float max); -//returns an integer characteristic -int Characteristic_Integer(int character, int index); -//returns a bounded integer characteristic -int Characteristic_BInteger(int character, int index, int min, int max); -//returns a string characteristic -void Characteristic_String(int character, int index, char *buf, int size); -//free cached bot characters -void BotShutdownCharacters(void); diff --git a/code/game/be_ai_chat.h b/code/game/be_ai_chat.h deleted file mode 100644 index 13f9894d..00000000 --- a/code/game/be_ai_chat.h +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -/***************************************************************************** - * name: be_ai_chat.h - * - * desc: char AI - * - * $Archive: /Code/DLLs/game/be_ai_chat.h $ - * $Author: Jwaters $ - * $Revision: 1 $ - * $Modtime: 5/17/02 11:35a $ - * $Date: 7/31/02 10:45a $ - * - *****************************************************************************/ - -#define MAX_MESSAGE_SIZE 256 -#define MAX_CHATTYPE_NAME 32 -#define MAX_MATCHVARIABLES 8 - -#define CHAT_GENDERLESS 0 -#define CHAT_GENDERFEMALE 1 -#define CHAT_GENDERMALE 2 - -#define CHAT_ALL 0 -#define CHAT_TEAM 1 -#define CHAT_TELL 2 - -//a console message -typedef struct bot_consolemessage_s -{ - int handle; - float time; //message time - int type; //message type - char message[MAX_MESSAGE_SIZE]; //message - struct bot_consolemessage_s *prev, *next; //prev and next in list -} bot_consolemessage_t; - -//match variable -typedef struct bot_matchvariable_s -{ - char offset; - int length; -} bot_matchvariable_t; -//returned to AI when a match is found -typedef struct bot_match_s -{ - char string[MAX_MESSAGE_SIZE]; - int type; - int subtype; - bot_matchvariable_t variables[MAX_MATCHVARIABLES]; -} bot_match_t; - -//setup the chat AI -int BotSetupChatAI(void); -//shutdown the chat AI -void BotShutdownChatAI(void); -//returns the handle to a newly allocated chat state -int BotAllocChatState(void); -//frees the chatstate -void BotFreeChatState(int handle); -//adds a console message to the chat state -void BotQueueConsoleMessage(int chatstate, int type, char *message); -//removes the console message from the chat state -void BotRemoveConsoleMessage(int chatstate, int handle); -//returns the next console message from the state -int BotNextConsoleMessage(int chatstate, bot_consolemessage_t *cm); -//returns the number of console messages currently stored in the state -int BotNumConsoleMessages(int chatstate); -//selects a chat message of the given type -void BotInitialChat(int chatstate, char *type, int mcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); -//returns the number of initial chat messages of the given type -int BotNumInitialChats(int chatstate, char *type); -//find and select a reply for the given message -int BotReplyChat(int chatstate, char *message, int mcontext, int vcontext, char *var0, char *var1, char *var2, char *var3, char *var4, char *var5, char *var6, char *var7); -//returns the length of the currently selected chat message -int BotChatLength(int chatstate); -//enters the selected chat message -void BotEnterChat(int chatstate, int clientto, int sendto); -//get the chat message ready to be output -void BotGetChatMessage(int chatstate, char *buf, int size); -//checks if the first string contains the second one, returns index into first string or -1 if not found -int StringContains(char *str1, char *str2, int casesensitive); -//finds a match for the given string using the match templates -int BotFindMatch(char *str, bot_match_t *match, unsigned long int context); -//returns a variable from a match -void BotMatchVariable(bot_match_t *match, int variable, char *buf, int size); -//unify all the white spaces in the string -void UnifyWhiteSpaces(char *string); -//replace all the context related synonyms in the string -void BotReplaceSynonyms(char *string, unsigned long int context); -//loads a chat file for the chat state -int BotLoadChatFile(int chatstate, char *chatfile, char *chatname); -//store the gender of the bot in the chat state -void BotSetChatGender(int chatstate, int gender); -//store the bot name in the chat state -void BotSetChatName(int chatstate, char *name, int client); - diff --git a/code/game/be_ai_gen.h b/code/game/be_ai_gen.h deleted file mode 100644 index 8f0a8e29..00000000 --- a/code/game/be_ai_gen.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_gen.h - * - * desc: genetic selection - * - * $Archive: /Code/DLLs/game/be_ai_gen.h $ - * $Author: Jwaters $ - * $Revision: 1 $ - * $Modtime: 5/17/02 11:35a $ - * $Date: 7/31/02 10:45a $ - * - *****************************************************************************/ - -int GeneticParentsAndChildSelection(int numranks, float *ranks, int *parent1, int *parent2, int *child); diff --git a/code/game/be_ai_goal.h b/code/game/be_ai_goal.h deleted file mode 100644 index cd64e0d0..00000000 --- a/code/game/be_ai_goal.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -/***************************************************************************** - * name: be_ai_goal.h - * - * desc: goal AI - * - * $Archive: /Code/DLLs/game/be_ai_goal.h $ - * $Author: Jwaters $ - * $Revision: 1 $ - * $Modtime: 5/17/02 11:35a $ - * $Date: 7/31/02 10:45a $ - * - *****************************************************************************/ - -#define MAX_AVOIDGOALS 256 -#define MAX_GOALSTACK 8 - -#define GFL_NONE 0 -#define GFL_ITEM 1 -#define GFL_ROAM 2 -#define GFL_DROPPED 4 - -//a bot goal -typedef struct bot_goal_s -{ - vec3_t origin; //origin of the goal - int areanum; //area number of the goal - vec3_t mins, maxs; //mins and maxs of the goal - int entitynum; //number of the goal entity - int number; //goal number - int flags; //goal flags - int iteminfo; //item information -} bot_goal_t; - -//reset the whole goal state, but keep the item weights -void BotResetGoalState(int goalstate); -//reset avoid goals -void BotResetAvoidGoals(int goalstate); -//remove the goal with the given number from the avoid goals -void BotRemoveFromAvoidGoals(int goalstate, int number); -//push a goal onto the goal stack -void BotPushGoal(int goalstate, bot_goal_t *goal); -//pop a goal from the goal stack -void BotPopGoal(int goalstate); -//empty the bot's goal stack -void BotEmptyGoalStack(int goalstate); -//dump the avoid goals -void BotDumpAvoidGoals(int goalstate); -//dump the goal stack -void BotDumpGoalStack(int goalstate); -//get the name name of the goal with the given number -void BotGoalName(int number, char *name, int size); -//get the top goal from the stack -int BotGetTopGoal(int goalstate, bot_goal_t *goal); -//get the second goal on the stack -int BotGetSecondGoal(int goalstate, bot_goal_t *goal); -//choose the best long term goal item for the bot -int BotChooseLTGItem(int goalstate, vec3_t origin, int *inventory, int travelflags); -//choose the best nearby goal item for the bot -//the item may not be further away from the current bot position than maxtime -//also the travel time from the nearby goal towards the long term goal may not -//be larger than the travel time towards the long term goal from the current bot position -int BotChooseNBGItem(int goalstate, vec3_t origin, int *inventory, int travelflags, - bot_goal_t *ltg, float maxtime); -//returns true if the bot touches the goal -int BotTouchingGoal(vec3_t origin, bot_goal_t *goal); -//returns true if the goal should be visible but isn't -int BotItemGoalInVisButNotVisible(int viewer, vec3_t eye, vec3_t viewangles, bot_goal_t *goal); -//search for a goal for the given classname, the index can be used -//as a start point for the search when multiple goals are available with that same classname -int BotGetLevelItemGoal(int index, char *classname, bot_goal_t *goal); -//get the next camp spot in the map -int BotGetNextCampSpotGoal(int num, bot_goal_t *goal); -//get the map location with the given name -int BotGetMapLocationGoal(char *name, bot_goal_t *goal); -//returns the avoid goal time -float BotAvoidGoalTime(int goalstate, int number); -//set the avoid goal time -void BotSetAvoidGoalTime(int goalstate, int number, float avoidtime); -//initializes the items in the level -void BotInitLevelItems(void); -//regularly update dynamic entity items (dropped weapons, flags etc.) -void BotUpdateEntityItems(void); -//interbreed the goal fuzzy logic -void BotInterbreedGoalFuzzyLogic(int parent1, int parent2, int child); -//save the goal fuzzy logic to disk -void BotSaveGoalFuzzyLogic(int goalstate, char *filename); -//mutate the goal fuzzy logic -void BotMutateGoalFuzzyLogic(int goalstate, float range); -//loads item weights for the bot -int BotLoadItemWeights(int goalstate, char *filename); -//frees the item weights of the bot -void BotFreeItemWeights(int goalstate); -//returns the handle of a newly allocated goal state -int BotAllocGoalState(int client); -//free the given goal state -void BotFreeGoalState(int handle); -//setup the goal AI -int BotSetupGoalAI(void); -//shut down the goal AI -void BotShutdownGoalAI(void); diff --git a/code/game/be_ai_move.h b/code/game/be_ai_move.h deleted file mode 100644 index 253ea4c4..00000000 --- a/code/game/be_ai_move.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_move.h - * - * desc: movement AI - * - * $Archive: /Code/DLLs/game/be_ai_move.h $ - * $Author: Jwaters $ - * $Revision: 1 $ - * $Modtime: 5/17/02 11:35a $ - * $Date: 7/31/02 10:45a $ - * - *****************************************************************************/ - -//movement types -#define MOVE_WALK 1 -#define MOVE_CROUCH 2 -#define MOVE_JUMP 4 -#define MOVE_GRAPPLE 8 -#define MOVE_ROCKETJUMP 16 -#define MOVE_BFGJUMP 32 -//move flags -#define MFL_BARRIERJUMP 1 //bot is performing a barrier jump -#define MFL_ONGROUND 2 //bot is in the ground -#define MFL_SWIMMING 4 //bot is swimming -#define MFL_AGAINSTLADDER 8 //bot is against a ladder -#define MFL_WATERJUMP 16 //bot is waterjumping -#define MFL_TELEPORTED 32 //bot is being teleported -#define MFL_GRAPPLEPULL 64 //bot is being pulled by the grapple -#define MFL_ACTIVEGRAPPLE 128 //bot is using the grapple hook -#define MFL_GRAPPLERESET 256 //bot has reset the grapple -#define MFL_WALK 512 //bot should walk slowly -// move result flags -#define MOVERESULT_MOVEMENTVIEW 1 //bot uses view for movement -#define MOVERESULT_SWIMVIEW 2 //bot uses view for swimming -#define MOVERESULT_WAITING 4 //bot is waiting for something -#define MOVERESULT_MOVEMENTVIEWSET 8 //bot has set the view in movement code -#define MOVERESULT_MOVEMENTWEAPON 16 //bot uses weapon for movement -#define MOVERESULT_ONTOPOFOBSTACLE 32 //bot is ontop of obstacle -#define MOVERESULT_ONTOPOF_FUNCBOB 64 //bot is ontop of a func_bobbing -#define MOVERESULT_ONTOPOF_ELEVATOR 128 //bot is ontop of an elevator (func_plat) -#define MOVERESULT_BLOCKEDBYAVOIDSPOT 256 //bot is blocked by an avoid spot -// -#define MAX_AVOIDREACH 1 -#define MAX_AVOIDSPOTS 32 -// avoid spot types -#define AVOID_CLEAR 0 //clear all avoid spots -#define AVOID_ALWAYS 1 //avoid always -#define AVOID_DONTBLOCK 2 //never totally block -// restult types -#define RESULTTYPE_ELEVATORUP 1 //elevator is up -#define RESULTTYPE_WAITFORFUNCBOBBING 2 //waiting for func bobbing to arrive -#define RESULTTYPE_BADGRAPPLEPATH 4 //grapple path is obstructed -#define RESULTTYPE_INSOLIDAREA 8 //stuck in solid area, this is bad - -//structure used to initialize the movement state -//the or_moveflags MFL_ONGROUND, MFL_TELEPORTED and MFL_WATERJUMP come from the playerstate -typedef struct bot_initmove_s -{ - vec3_t origin; //origin of the bot - vec3_t velocity; //velocity of the bot - vec3_t viewoffset; //view offset - int entitynum; //entity number of the bot - int client; //client number of the bot - float thinktime; //time the bot thinks - int presencetype; //presencetype of the bot - vec3_t viewangles; //view angles of the bot - int or_moveflags; //values ored to the movement flags -} bot_initmove_t; - -//NOTE: the ideal_viewangles are only valid if MFL_MOVEMENTVIEW is set -typedef struct bot_moveresult_s -{ - int failure; //true if movement failed all together - int type; //failure or blocked type - int blocked; //true if blocked by an entity - int blockentity; //entity blocking the bot - int traveltype; //last executed travel type - int flags; //result flags - int weapon; //weapon used for movement - vec3_t movedir; //movement direction - vec3_t ideal_viewangles; //ideal viewangles for the movement -} bot_moveresult_t; - -// bk001204: from code/botlib/be_ai_move.c -// TTimo 04/12/2001 was moved here to avoid dup defines -typedef struct bot_avoidspot_s -{ - vec3_t origin; - float radius; - int type; -} bot_avoidspot_t; - -//resets the whole move state -void BotResetMoveState(int movestate); -//moves the bot to the given goal -void BotMoveToGoal(bot_moveresult_t *result, int movestate, bot_goal_t *goal, int travelflags); -//moves the bot in the specified direction using the specified type of movement -int BotMoveInDirection(int movestate, vec3_t dir, float speed, int type); -//reset avoid reachability -void BotResetAvoidReach(int movestate); -//resets the last avoid reachability -void BotResetLastAvoidReach(int movestate); -//returns a reachability area if the origin is in one -int BotReachabilityArea(vec3_t origin, int client); -//view target based on movement -int BotMovementViewTarget(int movestate, bot_goal_t *goal, int travelflags, float lookahead, vec3_t target); -//predict the position of a player based on movement towards a goal -int BotPredictVisiblePosition(vec3_t origin, int areanum, bot_goal_t *goal, int travelflags, vec3_t target); -//returns the handle of a newly allocated movestate -int BotAllocMoveState(void); -//frees the movestate with the given handle -void BotFreeMoveState(int handle); -//initialize movement state before performing any movement -void BotInitMoveState(int handle, bot_initmove_t *initmove); -//add a spot to avoid (if type == AVOID_CLEAR all spots are removed) -void BotAddAvoidSpot(int movestate, vec3_t origin, float radius, int type); -//must be called every map change -void BotSetBrushModelTypes(void); -//setup movement AI -int BotSetupMoveAI(void); -//shutdown movement AI -void BotShutdownMoveAI(void); - diff --git a/code/game/be_ai_weap.h b/code/game/be_ai_weap.h deleted file mode 100644 index e6a3df70..00000000 --- a/code/game/be_ai_weap.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ai_weap.h - * - * desc: weapon AI - * - * $Archive: /Code/DLLs/game/be_ai_weap.h $ - * $Author: Jwaters $ - * $Revision: 4 $ - * $Modtime: 8/19/02 3:51p $ - * $Date: 8/19/02 4:08p $ - * - *****************************************************************************/ - -//projectile flags -#define PFL_WINDOWDAMAGE 1 //projectile damages through window -#define PFL_RETURN 2 //set when projectile returns to owner -//weapon flags -#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event -//damage types -#define DAMAGETYPE_IMPACT 1 //damage on impact -#define DAMAGETYPE_RADIAL 2 //radial damage -#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile - -typedef struct projectileinfo_s -{ - char name[MAX_STRINGFIELD]; - char model[MAX_STRINGFIELD]; - int flags; - float gravity; - int damage; - float radius; - int visdamage; - int damagetype; - int healthinc; - float push; - float detonation; - float bounce; - float bouncefric; - float bouncestop; -} projectileinfo_t; - -typedef struct weaponinfo_s -{ - int valid; //true if the weapon info is valid - int number; //number of the weapon - char name[MAX_STRINGFIELD]; - char model[MAX_STRINGFIELD]; - int level; - int weaponindex; - int flags; - char projectile[MAX_STRINGFIELD]; - int numprojectiles; - float hspread; - float vspread; - float speed; - float acceleration; - vec3_t recoil; - vec3_t offset; - vec3_t angleoffset; - float extrazvelocity; - int ammoamount; - int ammoindex; - float activate; - float reload; - float spinup; - float spindown; - int primarydangerous; // if primary and/or alternate fire are REALLY DANGEROUS - int altdangerous; - projectileinfo_t proj; //pointer to the used projectile -} weaponinfo_t; - -//setup the weapon AI -int BotSetupWeaponAI(void); -//shut down the weapon AI -void BotShutdownWeaponAI(void); -//returns the best weapon to fight with -int BotChooseBestFightWeapon(int weaponstate, int *inventory); -//returns the information of the current weapon -void BotGetWeaponInfo(int weaponstate, int weapon, weaponinfo_t *weaponinfo); -//loads the weapon weights -int BotLoadWeaponWeights(int weaponstate, char *filename); -//returns a handle to a newly allocated weapon state -int BotAllocWeaponState(void); -//frees the weapon state -void BotFreeWeaponState(int weaponstate); -//resets the whole weapon state -void BotResetWeaponState(int weaponstate); diff --git a/code/game/be_ea.h b/code/game/be_ea.h deleted file mode 100644 index 71e1d83f..00000000 --- a/code/game/be_ea.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// - -/***************************************************************************** - * name: be_ea.h - * - * desc: elementary actions - * - * $Archive: /Code/DLLs/game/be_ea.h $ - * $Author: Jwaters $ - * $Revision: 2 $ - * $Modtime: 8/08/02 12:17p $ - * $Date: 8/08/02 1:38p $ - * - *****************************************************************************/ - -//ClientCommand elementary actions -void EA_Say(int client, char *str); -void EA_SayTeam(int client, char *str); -void EA_Command(int client, const char *command ); - -void EA_Action(int client, int action); -void EA_Crouch(int client); -void EA_Walk(int client); -void EA_MoveUp(int client); -void EA_MoveDown(int client); -void EA_MoveForward(int client); -void EA_MoveBack(int client); -void EA_MoveLeft(int client); -void EA_MoveRight(int client); -void EA_ToggleFireState(int client); -void EA_Attack(int client, int primarydangerous, int altdangerous); -void EA_Respawn(int client); -void EA_Talk(int client); -void EA_Gesture(int client); -void EA_Use(int client); - -//regular elementary actions -void EA_SelectWeapon(int client, int weapon); -void EA_Jump(int client); -void EA_DelayedJump(int client); -void EA_Move(int client, vec3_t dir, float speed); -void EA_View(int client, vec3_t viewangles); - -//send regular input to the server -void EA_EndRegular(int client, float thinktime); -void EA_GetInput(int client, float thinktime, bot_input_t *input); -void EA_ResetInput(int client); -//setup and shutdown routines -int EA_Setup(void); -void EA_Shutdown(void); diff --git a/code/game/beam.cpp b/code/game/beam.cpp index 5549dc3f..eb0cf60c 100644 --- a/code/game/beam.cpp +++ b/code/game/beam.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "beam.h" #include "../qcommon/qfiles.h" +#include "game.h" /*****************************************************************************/ /*QUAKED func_beam (0 0.25 .5) (-8 -8 -8) (8 8 8) START_ON PERSIST WAVE NOISE diff --git a/code/game/bspline.cpp b/code/game/bspline.cpp index 772708af..6da094e6 100644 --- a/code/game/bspline.cpp +++ b/code/game/bspline.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" #include "BSpline.h" +#include "game.h" void BSpline::Set ( diff --git a/code/game/camera.h b/code/game/camera.h index 0716c862..3a5491fd 100644 --- a/code/game/camera.h +++ b/code/game/camera.h @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "entity.h" #include "bspline.h" #include "container.h" +#include "level.h" #define CAMERA_SWITCHTIME 0.5f diff --git a/code/globalcpp/compiler.cpp b/code/game/compiler.cpp similarity index 99% rename from code/globalcpp/compiler.cpp rename to code/game/compiler.cpp index 75f736bf..a7bce56c 100644 --- a/code/globalcpp/compiler.cpp +++ b/code/game/compiler.cpp @@ -1108,7 +1108,7 @@ void ScriptCompiler::EmitSwitch( sval_t val, unsigned int sourcePos ) EmitOpcode( OP_SWITCH, sourcePos ); *reinterpret_cast< StateScript ** >( code_pos ) = stateScript; - code_pos += sizeof( unsigned int ); + code_pos += sizeof(StateScript*); bStartCanBreak = bCanBreak; iStartBreakJumpLocCount = iBreakJumpLocCount; diff --git a/code/globalcpp/compiler.h b/code/game/compiler.h similarity index 100% rename from code/globalcpp/compiler.h rename to code/game/compiler.h diff --git a/code/game/consoleevent.cpp b/code/game/consoleevent.cpp new file mode 100644 index 00000000..2878e66e --- /dev/null +++ b/code/game/consoleevent.cpp @@ -0,0 +1,87 @@ +#include "consoleevent.h" +#include "g_local.h" + +//=============================== +// ConsoleEvent +//=============================== + +MEM_BlockAlloc< ConsoleEvent, MEM_BLOCKSIZE > ConsoleEvent_allocator; + +CLASS_DECLARATION(Event, ConsoleEvent, NULL) +{ + { NULL, NULL } +}; + +/* +======================= +new ConsoleEvent +======================= +*/ +void* ConsoleEvent::operator new(size_t size) +{ + return ConsoleEvent_allocator.Alloc(); +} + +/* +======================= +delete ptr +======================= +*/ +void ConsoleEvent::operator delete(void* ptr) +{ + ConsoleEvent_allocator.Free(ptr); +} + +/* +======================= +ConsoleEvent +======================= +*/ +ConsoleEvent::ConsoleEvent(void) +{ + m_consoleedict = NULL; +} + +/* +======================= +SetConsoleEdict +======================= +*/ +void ConsoleEvent::SetConsoleEdict(gentity_t* edict) +{ + m_consoleedict = edict; +} + +/* +======================= +GetConsoleEdict +======================= +*/ +gentity_t* ConsoleEvent::GetConsoleEdict(void) +{ + if (m_consoleedict) + return m_consoleedict; + + return g_entities; +} + +/* +======================= +ErrorInternal +======================= +*/ +void ConsoleEvent::ErrorInternal(Listener* l, str text) +{ + gentity_t* edict = GetConsoleEdict(); + str eventname = getName(); + + gi.DPrintf("^~^~^ Game ( Event '%s', Client '%s' ) : %s\n", + eventname.c_str(), + edict->client ? edict->client->pers.netname : "", + text.c_str()); + + gi.SendServerCommand(GetConsoleEdict() - g_entities, + "print \"Console: '%s' : %s\n\"", + eventname.c_str(), + text.c_str()); +} diff --git a/code/game/consoleevent.h b/code/game/consoleevent.h new file mode 100644 index 00000000..ad64e556 --- /dev/null +++ b/code/game/consoleevent.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include "g_public.h" + +class ConsoleEvent : public Event +{ +private: + gentity_t* m_consoleedict; + +public: + CLASS_PROTOTYPE(ConsoleEvent); + + void* operator new(size_t size); + void operator delete(void* ptr); + + ConsoleEvent(); + ConsoleEvent(str name) : Event(name) { m_consoleedict = NULL; } + + void SetConsoleEdict(gentity_t* edict); + gentity_t* GetConsoleEdict(void); + + virtual void ErrorInternal(Listener* l, str text); +}; + +extern MEM_BlockAlloc< ConsoleEvent, MEM_BLOCKSIZE > ConsoleEvent_allocator; diff --git a/code/globalcpp/crc32.h b/code/game/crc32.h similarity index 100% rename from code/globalcpp/crc32.h rename to code/game/crc32.h diff --git a/code/globalcpp/dbgheap.cpp b/code/game/dbgheap.cpp similarity index 100% rename from code/globalcpp/dbgheap.cpp rename to code/game/dbgheap.cpp diff --git a/code/globalcpp/dbgheap.h b/code/game/dbgheap.h similarity index 100% rename from code/globalcpp/dbgheap.h rename to code/game/dbgheap.h diff --git a/code/game/debuglines.cpp b/code/game/debuglines.cpp index 1901729a..a91b9eb9 100644 --- a/code/game/debuglines.cpp +++ b/code/game/debuglines.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // #include "debuglines.h" +#include "game.h" #define NUM_CIRCLE_SEGMENTS 24 diff --git a/code/game/decals.cpp b/code/game/decals.cpp index 555bf06d..08094774 100644 --- a/code/game/decals.cpp +++ b/code/game/decals.cpp @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // decals.cpp: Decal entities #include "decals.h" - +#include "level.h" CLASS_DECLARATION( Entity, Decal, NULL ) { diff --git a/code/game/earthquake.cpp b/code/game/earthquake.cpp index 97d2baaf..92149b01 100644 --- a/code/game/earthquake.cpp +++ b/code/game/earthquake.cpp @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "earthquake.h" #include "weapon.h" #include "sentient.h" +#include "level.h" /*****************************************************************************/ /*QUAKED func_viewjitter (0 0.25 0.5) (-8 -8 -8) (8 8 8) diff --git a/code/game/g_active.cpp b/code/game/g_active.cpp index f9f53d54..ef12972b 100644 --- a/code/game/g_active.cpp +++ b/code/game/g_active.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" #include "entity.h" +#include "game.h" // FIXME: OLD Q3 CODE #if 0 diff --git a/code/game/g_main.cpp b/code/game/g_main.cpp index edf0422c..20af0c91 100644 --- a/code/game/g_main.cpp +++ b/code/game/g_main.cpp @@ -1464,11 +1464,8 @@ GetGameAPI Gets game imports and returns game exports ================ */ -#ifndef WIN32 extern "C" -__attribute__((visibility("default"))) -#endif -gameExport_t* GetGameAPI( gameImport_t *import ) +gameExport_t * GetGameAPI(gameImport_t * import) { gi = *import; diff --git a/code/game/g_mmove.cpp b/code/game/g_mmove.cpp index a0306f2b..591a59e0 100644 --- a/code/game/g_mmove.cpp +++ b/code/game/g_mmove.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" #include "entity.h" +#include "game.h" typedef struct { qboolean validGroundTrace; diff --git a/code/game/g_public.h b/code/game/g_public.h index ffc31ec2..1cbfad8e 100644 --- a/code/game/g_public.h +++ b/code/game/g_public.h @@ -23,6 +23,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // g_public.h -- game module information visible to server +#pragma once + +#include "bg_public.h" + #define GAME_API_VERSION 12 // entity->svFlags @@ -807,6 +811,14 @@ typedef struct gameExport_s { #ifdef __cplusplus extern "C" #endif + +#ifdef GAME_DLL +#ifdef WIN32 +__declspec(dllexport) +#else +__attribute__((visibility("default"))) +#endif +#endif gameExport_t* GetGameAPI( gameImport_t *import ); #if 0 diff --git a/code/game/g_session.cpp b/code/game/g_session.cpp index 62011042..6ebe3ba7 100644 --- a/code/game/g_session.cpp +++ b/code/game/g_session.cpp @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // #include "g_local.h" +#include "game.h" /* diff --git a/code/globalcpp/g_spawn.cpp b/code/game/g_spawn.cpp similarity index 100% rename from code/globalcpp/g_spawn.cpp rename to code/game/g_spawn.cpp diff --git a/code/globalcpp/g_spawn.h b/code/game/g_spawn.h similarity index 100% rename from code/globalcpp/g_spawn.h rename to code/game/g_spawn.h diff --git a/code/game/game.cpp b/code/game/game.cpp index 223b5eb7..996a64f3 100644 --- a/code/game/game.cpp +++ b/code/game/game.cpp @@ -26,12 +26,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "scriptmaster.h" #include "world.h" -#ifdef GAME_DLL -#include "../game/camera.h" -#include "../game/entity.h" -#include "../game/player.h" -#include "../game/dm_manager.h" -#endif +#include "camera.h" +#include "entity.h" +#include "player.h" +#include "dm_manager.h" Game game; diff --git a/code/game/game.h b/code/game/game.h index 6acb5e00..5e609805 100644 --- a/code/game/game.h +++ b/code/game/game.h @@ -22,12 +22,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // game.h: General Game Info -#ifndef __GAME_H__ -#define __GAME_H__ +#pragma once -#include "glb_local.h" -#include "listener.h" #include "level.h" +#include "listener.h" +#include "g_public.h" class Game : public Listener { @@ -46,6 +45,8 @@ public: ~Game(); }; +class SimpleArchivedEntity; + /* * Functions prototypes */ @@ -238,5 +239,3 @@ void G_TouchTriggers( ); extern Game game; - -#endif /* __GAME_H__ */ diff --git a/code/game/gamecmds.cpp b/code/game/gamecmds.cpp index 598c7053..5c50e787 100644 --- a/code/game/gamecmds.cpp +++ b/code/game/gamecmds.cpp @@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "player.h" #include #include "playerbot.h" +#include "consoleevent.h" typedef struct { diff --git a/code/globalcpp/gamescript.cpp b/code/game/gamescript.cpp similarity index 99% rename from code/globalcpp/gamescript.cpp rename to code/game/gamescript.cpp index af6fe123..dce8a3f3 100644 --- a/code/globalcpp/gamescript.cpp +++ b/code/game/gamescript.cpp @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "gamescript.h" #include "compiler.h" #include "scriptmaster.h" +#include "level.h" static unsigned char *current_progBuffer = NULL; diff --git a/code/globalcpp/gamescript.h b/code/game/gamescript.h similarity index 100% rename from code/globalcpp/gamescript.h rename to code/game/gamescript.h diff --git a/code/game/gibs.cpp b/code/game/gibs.cpp index d4bf8681..9d6bfece 100644 --- a/code/game/gibs.cpp +++ b/code/game/gibs.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "gibs.h" #include "decals.h" +#include "level.h" Event EV_ThrowGib ( diff --git a/code/globalcpp/glb_local.h b/code/game/glb_local.h similarity index 98% rename from code/globalcpp/glb_local.h rename to code/game/glb_local.h index b597834f..673a55f3 100644 --- a/code/globalcpp/glb_local.h +++ b/code/game/glb_local.h @@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define glbs gi #include "g_local.h" -#include #include "qcommon.h" #else diff --git a/code/globalcpp/hud.cpp b/code/game/hud.cpp similarity index 100% rename from code/globalcpp/hud.cpp rename to code/game/hud.cpp diff --git a/code/globalcpp/hud.h b/code/game/hud.h similarity index 100% rename from code/globalcpp/hud.h rename to code/game/hud.h diff --git a/code/game/inventoryitem.cpp b/code/game/inventoryitem.cpp index 497072e3..0cfccfe9 100644 --- a/code/game/inventoryitem.cpp +++ b/code/game/inventoryitem.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "inventoryitem.h" #include "weaputils.h" +#include "level.h" Event EV_InventoryItem_Shoot ( diff --git a/code/game/item.cpp b/code/game/item.cpp index 29c9eecc..aa8c2ee2 100644 --- a/code/game/item.cpp +++ b/code/game/item.cpp @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "inventoryitem.h" #include "scriptmaster.h" #include "health.h" +#include "game.h" typedef struct { str name; diff --git a/code/game/level.h b/code/game/level.h index 81ff927b..fb921e01 100644 --- a/code/game/level.h +++ b/code/game/level.h @@ -22,10 +22,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // level.h: General Level Info -#ifndef __LEVEL_H__ -#define __LEVEL_H__ +#pragma once #include "listener.h" +#include "g_public.h" #define MAX_HEAD_SENTIENTS 2 #define MAX_EARTHQUAKES 10 @@ -290,5 +290,3 @@ qboolean Level::Reborn { return reborn; } - -#endif diff --git a/code/globalcpp/md5.cpp b/code/game/md5.cpp similarity index 100% rename from code/globalcpp/md5.cpp rename to code/game/md5.cpp diff --git a/code/globalcpp/md5.h b/code/game/md5.h similarity index 100% rename from code/globalcpp/md5.h rename to code/game/md5.h diff --git a/code/game/mover.cpp b/code/game/mover.cpp index 40186450..9b447159 100644 --- a/code/game/mover.cpp +++ b/code/game/mover.cpp @@ -29,6 +29,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "entity.h" #include "trigger.h" #include "mover.h" +#include "level.h" #define MOVE_ANGLES 1 #define MOVE_ORIGIN 2 diff --git a/code/game/navigate.h b/code/game/navigate.h index 3b3948af..5d8f66bd 100644 --- a/code/game/navigate.h +++ b/code/game/navigate.h @@ -34,6 +34,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "stack.h" #include "container.h" #include "doors.h" +#include "sentient.h" #include "../qcommon/qfiles.h" diff --git a/code/globalcpp/object.cpp b/code/game/object.cpp similarity index 100% rename from code/globalcpp/object.cpp rename to code/game/object.cpp diff --git a/code/globalcpp/object.h b/code/game/object.h similarity index 100% rename from code/globalcpp/object.h rename to code/game/object.h diff --git a/code/globalcpp/parm.cpp b/code/game/parm.cpp similarity index 100% rename from code/globalcpp/parm.cpp rename to code/game/parm.cpp diff --git a/code/globalcpp/parm.h b/code/game/parm.h similarity index 100% rename from code/globalcpp/parm.h rename to code/game/parm.h diff --git a/code/globalcpp/parser/parsetree.cpp b/code/game/parser/parsetree.cpp similarity index 100% rename from code/globalcpp/parser/parsetree.cpp rename to code/game/parser/parsetree.cpp diff --git a/code/globalcpp/parser/parsetree.h b/code/game/parser/parsetree.h similarity index 100% rename from code/globalcpp/parser/parsetree.h rename to code/game/parser/parsetree.h diff --git a/code/globalcpp/parser/yyLexer.cpp b/code/game/parser/yyLexer.cpp similarity index 100% rename from code/globalcpp/parser/yyLexer.cpp rename to code/game/parser/yyLexer.cpp diff --git a/code/globalcpp/parser/yyLexer.h b/code/game/parser/yyLexer.h similarity index 100% rename from code/globalcpp/parser/yyLexer.h rename to code/game/parser/yyLexer.h diff --git a/code/globalcpp/parser/yyLexer.l b/code/game/parser/yyLexer.l similarity index 100% rename from code/globalcpp/parser/yyLexer.l rename to code/game/parser/yyLexer.l diff --git a/code/globalcpp/parser/yyParser.cpp b/code/game/parser/yyParser.cpp similarity index 100% rename from code/globalcpp/parser/yyParser.cpp rename to code/game/parser/yyParser.cpp diff --git a/code/globalcpp/parser/yyParser.h b/code/game/parser/yyParser.h similarity index 100% rename from code/globalcpp/parser/yyParser.h rename to code/game/parser/yyParser.h diff --git a/code/globalcpp/parser/yyParser.yy b/code/game/parser/yyParser.yy similarity index 100% rename from code/globalcpp/parser/yyParser.yy rename to code/game/parser/yyParser.yy diff --git a/code/game/playerbot.cpp b/code/game/playerbot.cpp index f55c60ef..1b7028ce 100644 --- a/code/game/playerbot.cpp +++ b/code/game/playerbot.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" #include "actor.h" #include "playerbot.h" +#include "consoleevent.h" // We assume that we have limited access to the server-side // and that most logic come from the playerstate_s structure diff --git a/code/game/portal.cpp b/code/game/portal.cpp index db2381f6..1f1b4b53 100644 --- a/code/game/portal.cpp +++ b/code/game/portal.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // portal.cpp: Portals - surfaces that are mirrors or cameras #include "portal.h" +#include "game.h" /*QUAKED portal_surface (1 0 1) (-8 -8 -8) (8 8 8) The portal surface nearest this entity will show a view from the targeted portal_camera, or a mirror view if untargeted. diff --git a/code/globalcpp/scriptmaster.cpp b/code/game/scriptmaster.cpp similarity index 99% rename from code/globalcpp/scriptmaster.cpp rename to code/game/scriptmaster.cpp index bcda40e3..7aaee54d 100644 --- a/code/globalcpp/scriptmaster.cpp +++ b/code/game/scriptmaster.cpp @@ -59,6 +59,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../game/huddraw.h" #include "../game/weaputils.h" #include "../game/camera.h" +#include "../game/consoleevent.h" #define SCRIPT_Printf gi.Printf #define SCRIPT_DPrintf gi.DPrintf @@ -2162,88 +2163,6 @@ Event EV_ScriptThread_CancelWaiting "internal event" ); -con_timer::con_timer( void ) -{ - m_inttime = 0; - m_bDirty = false; -} - -void con_timer::AddElement( Class *e, int inttime ) -{ - Element element; - - element.obj = e; - element.inttime = inttime; - - m_Elements.AddObject( element ); - - if( inttime <= m_inttime ) { - SetDirty(); - } -} - -void con_timer::RemoveElement( Class *e ) -{ - for( int i = m_Elements.NumObjects(); i > 0; i-- ) - { - Element *index = &m_Elements.ObjectAt( i ); - - if( index->obj == e ) - { - m_Elements.RemoveObjectAt( i ); - return; - } - } -} - -Class *con_timer::GetNextElement( int& foundtime ) -{ - int best_inttime; - int i; - int foundIndex; - Class *result; - - foundIndex = 0; - best_inttime = m_inttime; - - for( i = m_Elements.NumObjects(); i > 0; i-- ) - { - if( m_Elements.ObjectAt( i ).inttime <= best_inttime ) - { - best_inttime = m_Elements.ObjectAt( i ).inttime; - foundIndex = i; - } - } - - if( foundIndex ) - { - result = m_Elements.ObjectAt( foundIndex ).obj; - m_Elements.RemoveObjectAt( foundIndex ); - foundtime = best_inttime; - } - else - { - result = NULL; - m_bDirty = false; - } - - return result; -} - -void con_timer::ArchiveElement( Archiver& arc, Element *e ) -{ - arc.ArchiveObjectPointer( &e->obj ); - arc.ArchiveInteger( &e->inttime ); -} - -void con_timer::Archive( Archiver& arc ) -{ - arc.ArchiveBool( &m_bDirty ); - arc.ArchiveInteger( &m_inttime ); - - m_Elements.Archive( arc, con_timer::ArchiveElement ); -} - void ScriptMaster::Archive( Archiver& arc ) { ScriptClass *scr; diff --git a/code/globalcpp/scriptmaster.h b/code/game/scriptmaster.h similarity index 96% rename from code/globalcpp/scriptmaster.h rename to code/game/scriptmaster.h index 462c1706..9e499890 100644 --- a/code/globalcpp/scriptmaster.h +++ b/code/game/scriptmaster.h @@ -28,6 +28,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "class.h" #include "listener.h" #include "scriptvm.h" +#include #define MAX_COMMANDS 20 #define MAX_EXECUTION_TIME 3000 @@ -35,37 +36,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA void Showmenu( str name, qboolean bForce ); void Hidemenu( str name, qboolean bForce ); -class con_timer : public Class -{ -public: - class Element - { - public: - Class *obj; - int inttime; - }; - -private: - Container< con_timer::Element > m_Elements; - bool m_bDirty; - int m_inttime; - -public: - con_timer(); - - void AddElement( Class *e, int inttime ); - void RemoveElement( Class *e ); - - Class *GetNextElement( int& foundTime ); - - void SetDirty( void ) { m_bDirty = true; }; - bool IsDirty( void ) { return m_bDirty; }; - void SetTime( int inttime ) { m_inttime = inttime; }; - - static void ArchiveElement( Archiver& arc, Element *e ); - virtual void Archive( Archiver& arc ); -}; - #define MAX_VAR_STACK 1024 #define MAX_FASTEVENT 10 diff --git a/code/globalcpp/scriptopcodes.cpp b/code/game/scriptopcodes.cpp similarity index 100% rename from code/globalcpp/scriptopcodes.cpp rename to code/game/scriptopcodes.cpp diff --git a/code/globalcpp/scriptopcodes.h b/code/game/scriptopcodes.h similarity index 100% rename from code/globalcpp/scriptopcodes.h rename to code/game/scriptopcodes.h diff --git a/code/game/scriptslave.cpp b/code/game/scriptslave.cpp index f438c004..73402f78 100644 --- a/code/game/scriptslave.cpp +++ b/code/game/scriptslave.cpp @@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "weapon.h" #include "gibs.h" #include "explosion.h" +#include "game.h" /*****************************************************************************/ /*QUAKED script_object (0 0.5 1) ? NOT_SOLID diff --git a/code/globalcpp/scripttimer.cpp b/code/game/scripttimer.cpp similarity index 98% rename from code/globalcpp/scripttimer.cpp rename to code/game/scripttimer.cpp index 71c336a7..5d8c67fc 100644 --- a/code/globalcpp/scripttimer.cpp +++ b/code/game/scripttimer.cpp @@ -23,10 +23,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // scripttimer.cpp: Scripted Timer & Fader // -#include "glb_local.h" -#include "scripttimer.h" +#include "ScriptTimer.h" #include "level.h" + +#if defined(GAME_DLL) #include "archive.h" +#endif Event EV_ScriptTimer_Think ( diff --git a/code/globalcpp/scripttimer.h b/code/game/scripttimer.h similarity index 93% rename from code/globalcpp/scripttimer.h rename to code/game/scripttimer.h index 80306922..96fff34a 100644 --- a/code/globalcpp/scripttimer.h +++ b/code/game/scripttimer.h @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ -// scripttimer.cpp: Scripted Timer & Fader +// ScriptTimer.cpp: Scripted Timer & Fader // #ifndef __SCRIPTTIMER_H__ @@ -53,9 +53,11 @@ public: CLASS_PROTOTYPE( ScriptTimer ); ScriptTimer( timertype_e type = TIMER_NORMAL ); - virtual ~ScriptTimer(); + ~ScriptTimer(); - virtual void Archive( Archiver &arc ); +#if defined(ARCHIVE_SUPPORTED) + void Archive( Archiver &arc ) override; +#endif void Think( Event *ev ); diff --git a/code/game/scriptvm.cpp b/code/game/scriptvm.cpp new file mode 100644 index 00000000..4e1dc9e8 --- /dev/null +++ b/code/game/scriptvm.cpp @@ -0,0 +1,2353 @@ +/* +=========================================================================== +Copyright (C) 2015 the OpenMoHAA team + +This file is part of OpenMoHAA source code. + +OpenMoHAA source code 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. + +OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// scriptvm.cpp : Script virtual machine, interprets and execute scripts + +#include "glb_local.h" +#include "scriptmaster.h" +#include "scriptvm.h" +#include "compiler.h" +#include "game.h" +#include "level.h" +#include "parm.h" +#include "world.h" + +#ifdef CGAME_DLL + +#define VM_Printf cgi.Printf +#define VM_DPrintf cgi.DPrintf + +#elif defined GAME_DLL + +#define VM_Printf gi.Printf +#define VM_DPrintf gi.DPrintf2 + +#else + +#define VM_Printf printf +#define VM_DPrintf printf + +#endif + +//==================== +// ScriptClass +//==================== + +MEM_BlockAlloc< ScriptClass, MEM_BLOCKSIZE > ScriptClass_allocator; + +CLASS_DECLARATION(Listener, ScriptClass, NULL) +{ + { NULL, NULL } +}; + +/* +==================== +new ScriptClass +==================== +*/ +void* ScriptClass::operator new(size_t size) +{ + return ScriptClass_allocator.Alloc(); +} + +/* +==================== +delete ptr +==================== +*/ +void ScriptClass::operator delete(void* ptr) +{ + ScriptClass_allocator.Free(ptr); +} + +/* +==================== +ScriptClass +==================== +*/ +ScriptClass::ScriptClass(GameScript* gameScript, Listener* self) +{ + m_Self = self; + m_Script = gameScript; + m_Threads = NULL; +} + +/* +==================== +ScriptClass +==================== +*/ +ScriptClass::ScriptClass() +{ + m_Self = NULL; + m_Script = NULL; + m_Threads = NULL; +} + +/* +==================== +~ScriptClass +==================== +*/ +ScriptClass::~ScriptClass() +{ + if (m_Script == NULL) { + ScriptError("Attempting to delete dead class."); + } + + KillThreads(); + + if (!m_Script->m_Filename) + { + // This is a temporary gamescript + delete m_Script; + } +} + +/* +==================== +Archive +==================== +*/ +void ScriptClass::Archive(Archiver& arc) +{ +} + +/* +==================== +ArchiveInternal +==================== +*/ +void ScriptClass::ArchiveInternal(Archiver& arc) +{ + Listener::Archive(arc); + + arc.ArchiveObjectPosition(this); + arc.ArchiveSafePointer(&m_Self); + GameScript::Archive(arc, m_Script); +} + +/* +==================== +ArchiveScript +==================== +*/ +void ScriptClass::ArchiveScript(Archiver& arc, ScriptClass** obj) +{ + ScriptClass* scr; + ScriptVM* m_current; + ScriptThread* m_thread; + int num; + int i; + + if (arc.Saving()) + { + scr = *obj; + scr->ArchiveInternal(arc); + + num = 0; + for (m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next) + num++; + + arc.ArchiveInteger(&num); + + for (m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next) + m_current->m_Thread->ArchiveInternal(arc); + } + else + { + scr = new ScriptClass(); + scr->ArchiveInternal(arc); + + arc.ArchiveInteger(&num); + + for (i = 0; i < num; i++) + { + m_thread = new ScriptThread(scr, NULL); + m_thread->ArchiveInternal(arc); + } + + *obj = scr; + } +} + +/* +==================== +ArchiveCodePos +==================== +*/ +void ScriptClass::ArchiveCodePos(Archiver& arc, unsigned char** codePos) +{ + m_Script->ArchiveCodePos(arc, codePos); +} + +/* +==================== +CreateThreadInternal +==================== +*/ +ScriptThread* ScriptClass::CreateThreadInternal(const ScriptVariable& label) +{ + GameScript* scr; + ScriptThread* thread = NULL; + + if (label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING) + { + ScriptClass* scriptClass = Director.CurrentScriptClass(); + scr = scriptClass->GetScript(); + + if (label.GetType() == VARIABLE_CONSTSTRING) + thread = Director.CreateScriptThread(scr, m_Self, label.constStringValue()); + else + thread = Director.CreateScriptThread(scr, m_Self, label.stringValue()); + } + else if (label.GetType() == VARIABLE_CONSTARRAY && label.arraysize() > 1) + { + ScriptVariable* script = label[1]; + ScriptVariable* labelname = label[2]; + + if (script->GetType() == VARIABLE_CONSTSTRING) + scr = Director.GetGameScript(script->constStringValue()); + else + scr = Director.GetGameScript(script->stringValue()); + + if (labelname->GetType() == VARIABLE_CONSTSTRING) + thread = Director.CreateScriptThread(scr, m_Self, labelname->constStringValue()); + else + thread = Director.CreateScriptThread(scr, m_Self, labelname->stringValue()); + } + else + { + ScriptError("ScriptClass::CreateThreadInternal: bad argument format"); + } + + return thread; +} + +/* +==================== +CreateScriptInternal +==================== +*/ +ScriptThread* ScriptClass::CreateScriptInternal(const ScriptVariable& label) +{ + GameScript* scr; + ScriptThread* thread = NULL; + + if (label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING) + { + if (label.GetType() == VARIABLE_CONSTSTRING) + thread = Director.CreateScriptThread(Director.GetGameScript(label.stringValue()), m_Self, ""); + else + thread = Director.CreateScriptThread(Director.GetGameScript(label.constStringValue()), m_Self, ""); + } + else if (label.GetType() == VARIABLE_CONSTARRAY && label.arraysize() > 1) + { + ScriptVariable* script = label[1]; + ScriptVariable* labelname = label[2]; + + if (script->GetType() == VARIABLE_CONSTSTRING) + scr = Director.GetGameScript(script->constStringValue()); + else + scr = Director.GetGameScript(script->stringValue()); + + if (labelname->GetType() == VARIABLE_CONSTSTRING) + thread = Director.CreateScriptThread(scr, m_Self, labelname->constStringValue()); + else + thread = Director.CreateScriptThread(scr, m_Self, labelname->stringValue()); + } + else + { + ScriptError("ScriptClass::CreateScriptInternal: bad label type '%s'", label.GetTypeName()); + } + + return thread; +} + +/* +==================== +AddThread +==================== +*/ +void ScriptClass::AddThread(ScriptVM* m_ScriptVM) +{ + m_ScriptVM->next = m_Threads; + m_Threads = m_ScriptVM; +} + +/* +==================== +KillThreads +==================== +*/ +void ScriptClass::KillThreads() +{ + if (!m_Threads) { + return; + } + + ScriptVM* m_current; + ScriptVM* m_next; + + m_current = m_Threads; + + do + { + m_current->m_ScriptClass = NULL; + + m_next = m_current->next; + delete m_current->m_Thread; + + } while (m_current = m_next); + + m_Threads = NULL; +} + +/* +==================== +RemoveThread +==================== +*/ +void ScriptClass::RemoveThread(ScriptVM* m_ScriptVM) +{ + if (m_Threads == m_ScriptVM) + { + m_Threads = m_ScriptVM->next; + + if (m_Threads == NULL) { + delete this; + } + } + else + { + ScriptVM* m_current = m_Threads; + ScriptVM* i; + + for (i = m_Threads->next; i != m_ScriptVM; i = i->next) { + m_current = i; + } + + m_current->next = i->next; + } +} + +/* +==================== +Filename +==================== +*/ +str ScriptClass::Filename() +{ + return m_Script->Filename(); +} + +/* +==================== +FindLabel +==================== +*/ +unsigned char* ScriptClass::FindLabel(str label) +{ + return m_Script->m_State.FindLabel(label); +} + +/* +==================== +FindLabel +==================== +*/ +unsigned char* ScriptClass::FindLabel(const_str label) +{ + return m_Script->m_State.FindLabel(label); +} + +/* +==================== +NearestLabel +==================== +*/ +const_str ScriptClass::NearestLabel(unsigned char* pos) +{ + return m_Script->m_State.NearestLabel(pos); +} + +/* +==================== +GetCatchStateScript +==================== +*/ +StateScript* ScriptClass::GetCatchStateScript(unsigned char* in, unsigned char*& out) +{ + return m_Script->GetCatchStateScript(in, out); +} + +/* +==================== +GetScript +==================== +*/ +GameScript* ScriptClass::GetScript() +{ + return m_Script; +} + +/* +==================== +GetSelf +==================== +*/ +Listener* ScriptClass::GetSelf() +{ + return static_cast(m_Self.Pointer()); +} + +//==================== +// ScriptVM +//==================== + + +MEM_BlockAlloc< ScriptVM, char[256] > ScriptVM_allocator; + +/* +==================== +new ScriptVM +==================== +*/ +void* ScriptVM::operator new(size_t size) +{ + return ScriptVM_allocator.Alloc(); +} + +/* +==================== +delete ptr +==================== +*/ +void ScriptVM::operator delete(void* ptr) +{ + ScriptVM_allocator.Free(ptr); +} + +/* +==================== +ScriptVM +==================== +*/ +ScriptVM::ScriptVM(ScriptClass* scriptClass, unsigned char* pCodePos, ScriptThread* thread) +{ + next = NULL; + + m_Thread = thread; + m_ScriptClass = scriptClass; + + m_Stack = NULL; + + m_PrevCodePos = NULL; + m_CodePos = pCodePos; + + state = STATE_RUNNING; + m_ThreadState = THREAD_RUNNING; + + m_pOldData = NULL; + m_OldDataSize = 0; + + m_bMarkStack = false; + m_StackPos = NULL; + + m_bAllowContextSwitch = true; + + localStackSize = m_ScriptClass->GetScript()->GetRequiredStackSize(); + + if (localStackSize <= 0) { + localStackSize = 1; + } + + localStack = new ScriptVariable[localStackSize]; + + pTop = localStack; + + m_ScriptClass->AddThread(this); +} + +/* +==================== +~ScriptVM +==================== +*/ +ScriptVM::~ScriptVM() +{ + fastEvent.data = m_pOldData; + fastEvent.dataSize = m_OldDataSize; + + // clean-up the call stack + while (callStack.NumObjects()) + { + LeaveFunction(); + } + + delete[] localStack; +} + +/* +==================== +Archive +==================== +*/ +void ScriptVM::Archive(Archiver& arc) +{ + int stack = 0; + + if (arc.Saving()) + { + if (m_Stack) + stack = m_Stack->m_Count; + + arc.ArchiveInteger(&stack); + } + else + { + arc.ArchiveInteger(&stack); + + if (stack) + { + m_Stack = new ScriptStack; + m_Stack->m_Array = new ScriptVariable[stack]; + m_Stack->m_Count = stack; + } + } + + for (int i = 1; i <= stack; i++) + { + m_Stack->m_Array[i].ArchiveInternal(arc); + } + + m_ReturnValue.ArchiveInternal(arc); + m_ScriptClass->ArchiveCodePos(arc, &m_PrevCodePos); + m_ScriptClass->ArchiveCodePos(arc, &m_CodePos); + arc.ArchiveByte(&state); + arc.ArchiveByte(&m_ThreadState); +} + +/* +==================== +error + +Triggers an error +==================== +*/ +void ScriptVM::error(const char* format, ...) +{ + char buffer[4000]; + va_list va; + + va_start(va, format); + vsprintf(buffer, format, va); + va_end(va); + + glbs.Printf("----------------------------------------------------------\n%s\n", buffer); + m_ReturnValue.setStringValue("$.INTERRUPTED"); +} + +/* +==================== +executeCommand +==================== +*/ +void ScriptVM::executeCommand(Listener* listener, int iParamCount, int eventnum, bool bReturn) +{ + Event ev; + ScriptVariable* var; + + ev = Event(eventnum); + + if (bReturn) + { + var = pTop; + } + else + { + var = pTop + 1; + } + + ev.dataSize = iParamCount; + ev.data = new ScriptVariable[ev.dataSize]; + ev.fromScript = true; + + for (int i = 0; i < iParamCount; i++) { + ev.data[i] = var[i]; + } + + listener->ProcessScriptEvent(ev); + + if (ev.NumArgs() > iParamCount) { + *pTop = ev.GetValue(ev.NumArgs()); + } + else { + pTop->Clear(); + } +} + +/* +==================== +executeGetter +==================== +*/ +bool ScriptVM::executeGetter(Listener* listener, str& name) +{ + Event ev; + int eventnum = Event::FindGetterEventNum(name); + + if (eventnum && listener->classinfo()->GetDef(eventnum)) + { + ev = Event(eventnum); + ev.fromScript = true; + + if (listener->ProcessScriptEvent(ev)) + { + + if (ev.NumArgs() > 0) { + *pTop = ev.GetValue(ev.NumArgs()); + } + else { + pTop->Clear(); + } + + return true; + } + else + { + return false; + } + } + else + { + eventnum = Event::FindSetterEventNum(name); + assert(!eventnum || !listener->classinfo()->GetDef(eventnum)); + if (eventnum && listener->classinfo()->GetDef(eventnum)) + { + ScriptError("Cannot get a write-only variable"); + } + } + + return false; +} + +/* +==================== +executeSetter +==================== +*/ +bool ScriptVM::executeSetter(Listener* listener, str& name) +{ + Event ev; + int eventnum = Event::FindSetterEventNum(name); + + if (eventnum && listener->classinfo()->GetDef(eventnum)) + { + ev = Event(eventnum); + ev.fromScript = true; + + ev.AddValue(*pTop); + + if (listener->ProcessScriptEvent(ev)) + { + return true; + } + else + { + return false; + } + } + else + { + eventnum = Event::FindGetterEventNum(name); + if (eventnum && listener->classinfo()->GetDef(eventnum)) + { + ScriptError("Cannot set a read-only variable"); + } + } + + return false; +} + +/* +==================== +jump +==================== +*/ +void ScriptVM::jump(int offset) +{ + m_CodePos += offset; +} + +/* +==================== +jumpBool +==================== +*/ +void ScriptVM::jumpBool(int offset, bool booleanValue) +{ + if (booleanValue) + { + jump(offset); + } + else + { + m_CodePos += sizeof(unsigned int); + } +} + +/* +==================== +loadTop +==================== +*/ +void ScriptVM::loadTop(Listener* listener, bool noTop) +{ + int index; + + index = *reinterpret_cast(m_CodePos); + m_CodePos += sizeof(unsigned int); + + if (index != -1) + { + str& variable = Director.GetString(index); + + if (!executeSetter(listener, variable)) + { + listener->Vars()->SetVariable(variable, *pTop); + } + } + + if (!noTop) { + pTop--; + } +} + +/* +==================== +storeTop +==================== +*/ +void ScriptVM::storeTop(Listener* listener, bool noTop) +{ + str variable; + int index; + + index = *reinterpret_cast(m_CodePos); + m_CodePos += sizeof(unsigned int); + + if (index != -1) + { + variable = Director.GetString(index); + } + + if (!noTop) { + pTop++; + } + + if (index != -1 && !executeGetter(listener, variable)) + { + *pTop = *listener->Vars()->GetOrCreateVariable(index); + } +} + +/* +==================== +ProgBuffer + +Returns the current program buffer +==================== +*/ +unsigned char* ScriptVM::ProgBuffer(void) +{ + return m_CodePos; +} + +/* +==================== +EnterFunction + +Sets a new instruction pointer +==================== +*/ +void ScriptVM::EnterFunction(Event* ev) +{ + ScriptCallStack* stack; + str label = ev->GetString(1); + + SetFastData(ev->data + 1, ev->dataSize - 1); + + unsigned char* codePos = m_ScriptClass->FindLabel(label); + + if (!codePos) + { + ScriptError("ScriptVM::EnterFunction: label '%s' does not exist in '%s'.", label.c_str(), Filename().c_str()); + } + + stack = new ScriptCallStack; + + stack->codePos = m_CodePos; + + stack->pTop = pTop; + stack->returnValue = m_ReturnValue; + stack->localStack = localStack; + stack->m_Self = m_ScriptClass->GetSelf(); + + callStack.AddObject(stack); + + m_CodePos = codePos; + + localStack = new ScriptVariable[localStackSize]; + + pTop = localStack; + m_ReturnValue.Clear(); +} + +/* +==================== +LeaveFunction + +Returns to the previous function +==================== +*/ +void ScriptVM::LeaveFunction() +{ + int num = callStack.NumObjects(); + + if (num) + { + ScriptCallStack* stack = callStack.ObjectAt(num); + + pTop = stack->pTop; + *pTop = m_ReturnValue; + + m_CodePos = stack->codePos; + m_ReturnValue = stack->returnValue; + m_ScriptClass->m_Self = stack->m_Self; + + delete[] localStack; + + localStack = stack->localStack; + + delete stack; + + callStack.RemoveObjectAt(num); + } + else + { + delete m_Thread; + } +} + +/* +==================== +End + +End with a return value +==================== +*/ +void ScriptVM::End(const ScriptVariable& returnValue) +{ + m_ReturnValue.setPointer(returnValue); + + LeaveFunction(); +} + +/* +==================== +End +==================== +*/ +void ScriptVM::End() +{ + m_ReturnValue.ClearPointer(); + + LeaveFunction(); +} + +/* +==================== +Execute + +Executes a program +==================== +*/ +void ScriptVM::Execute(ScriptVariable* data, int dataSize, str label) +{ + unsigned char* opcode; + bool doneProcessing = false; + bool deleteThread = false; + bool eventCalled = false; + + ScriptVariable* a; + ScriptVariable* b; + ScriptVariable* c; + + int index, iParamCount; + + Listener* listener; + + Event ev; + Event* ev2; + ScriptVariable* var = NULL; + + static str str_null = ""; + str& value = str_null; + + ConSimple* targetList; + + if (label != "") + { + // Throw if label is not found + if (!(m_CodePos = m_ScriptClass->FindLabel(label))) + { + ScriptError("ScriptVM::Execute: label '%s' does not exist in '%s'.", label.c_str(), Filename().c_str()); + } + } + + if (Director.stackCount >= MAX_STACK_DEPTH) + { + state = STATE_EXECUTION; + + ScriptException::next_abort = -1; + ScriptException exc("stack overflow"); + + throw exc; + } + + Director.stackCount++; + + if (dataSize) + { + SetFastData(data, dataSize); + } + + state = STATE_RUNNING; + + Director.cmdTime = glbs.Milliseconds(); + Director.cmdCount = 0; + + while (!doneProcessing && state == STATE_RUNNING) + { + m_PrevCodePos = m_CodePos; + + Director.cmdCount++; + + try + { + if (Director.cmdCount > 9999 && glbs.Milliseconds() - Director.cmdTime > Director.maxTime) + { + if (level.m_LoopProtection) + { + Director.cmdTime = glbs.Milliseconds(); + + deleteThread = true; + state = STATE_EXECUTION; + + if (level.m_LoopDrop) { + ScriptException::next_abort = -1; + } + + ScriptError("Command overflow. Possible infinite loop in thread.\n"); + } + + VM_DPrintf("Update of script position - This is not an error.\n"); + VM_DPrintf("=================================================\n"); + m_ScriptClass->GetScript()->PrintSourcePos(opcode, true); + VM_DPrintf("=================================================\n"); + + Director.cmdCount = 0; + } + + if (!m_bMarkStack) + { + assert(pTop >= localStack && pTop < localStack + localStackSize); + if (pTop < localStack) + { + deleteThread = true; + state = STATE_EXECUTION; + + error("VM stack error. Negative stack value %d.\n", pTop - localStack); + break; + } + else if (pTop >= localStack + localStackSize) + { + deleteThread = true; + state = STATE_EXECUTION; + + error("VM stack error. Exceeded the maximum stack size %d.\n", localStackSize); + break; + } + } + + index = 0; + eventCalled = false; + + opcode = m_CodePos++; + switch (*opcode) + { + case OP_BIN_BITWISE_AND: + a = pTop--; + b = pTop; + + *b &= *a; + break; + + case OP_BIN_BITWISE_OR: + a = pTop--; + b = pTop; + + *b |= *a; + break; + + case OP_BIN_BITWISE_EXCL_OR: + a = pTop--; + b = pTop; + + *b ^= *a; + break; + + case OP_BIN_EQUALITY: + a = pTop--; + b = pTop; + + b->setIntValue(*b == *a); + break; + + case OP_BIN_INEQUALITY: + a = pTop--; + b = pTop; + + b->setIntValue(*b != *a); + break; + + case OP_BIN_GREATER_THAN: + a = pTop--; + b = pTop; + + b->greaterthan(*a); + break; + + case OP_BIN_GREATER_THAN_OR_EQUAL: + a = pTop--; + b = pTop; + + b->greaterthanorequal(*a); + break; + + case OP_BIN_LESS_THAN: + a = pTop--; + b = pTop; + + b->lessthan(*a); + break; + + case OP_BIN_LESS_THAN_OR_EQUAL: + a = pTop--; + b = pTop; + + b->lessthanorequal(*a); + break; + + case OP_BIN_PLUS: + a = pTop--; + b = pTop; + + *b += *a; + break; + + case OP_BIN_MINUS: + a = pTop--; + b = pTop; + + *b -= *a; + break; + + case OP_BIN_MULTIPLY: + a = pTop--; + b = pTop; + + *b *= *a; + break; + + case OP_BIN_DIVIDE: + a = pTop--; + b = pTop; + + *b /= *a; + break; + + case OP_BIN_PERCENTAGE: + a = pTop--; + b = pTop; + + *b %= *a; + break; + + case OP_BIN_SHIFT_LEFT: + a = pTop--; + b = pTop; + + *b <<= *a; + break; + + case OP_BIN_SHIFT_RIGHT: + a = pTop--; + b = pTop; + + *b >>= *a; + break; + + case OP_BOOL_JUMP_FALSE4: + jumpBool(*reinterpret_cast(m_CodePos) + sizeof(unsigned int), !pTop->m_data.intValue); + + pTop--; + + break; + + case OP_BOOL_JUMP_TRUE4: + jumpBool(*reinterpret_cast(m_CodePos) + sizeof(unsigned int), pTop->m_data.intValue ? true : false); + + pTop--; + + break; + + case OP_VAR_JUMP_FALSE4: + jumpBool(*reinterpret_cast(m_CodePos) + sizeof(unsigned int), !pTop->booleanValue()); + + pTop--; + + break; + + case OP_VAR_JUMP_TRUE4: + jumpBool(*reinterpret_cast(m_CodePos) + sizeof(unsigned int), pTop->booleanValue()); + + pTop--; + + break; + + case OP_BOOL_LOGICAL_AND: + if (pTop->m_data.intValue) + { + pTop--; + m_CodePos += sizeof(unsigned int); + } + else + { + m_CodePos += *reinterpret_cast(m_CodePos) + sizeof(unsigned int); + } + + break; + + case OP_BOOL_LOGICAL_OR: + if (!pTop->m_data.intValue) + { + pTop--; + m_CodePos += sizeof(unsigned int); + } + else + { + m_CodePos += *reinterpret_cast(m_CodePos) + sizeof(unsigned int); + } + + break; + + case OP_VAR_LOGICAL_AND: + if (pTop->booleanValue()) + { + pTop--; + m_CodePos += sizeof(unsigned int); + } + else + { + pTop->SetFalse(); + m_CodePos += *reinterpret_cast(m_CodePos) + sizeof(unsigned int); + } + break; + + case OP_VAR_LOGICAL_OR: + if (!pTop->booleanValue()) + { + pTop--; + m_CodePos += sizeof(unsigned int); + } + else + { + pTop->SetTrue(); + m_CodePos += *reinterpret_cast(m_CodePos) + sizeof(unsigned int); + } + break; + + case OP_BOOL_STORE_FALSE: + pTop++; + pTop->SetFalse(); + break; + + case OP_BOOL_STORE_TRUE: + pTop++; + pTop->SetTrue(); + break; + + case OP_BOOL_UN_NOT: + pTop->m_data.intValue = (pTop->m_data.intValue == 0); + break; + + case OP_CALC_VECTOR: + c = pTop--; + b = pTop--; + a = pTop; + + pTop->setVectorValue(Vector(a->floatValue(), b->floatValue(), c->floatValue())); + break; + + case OP_EXEC_CMD0: + iParamCount = 0; + goto __execCmd; + + case OP_EXEC_CMD1: + iParamCount = 1; + goto __execCmd; + + case OP_EXEC_CMD2: + iParamCount = 2; + goto __execCmd; + + case OP_EXEC_CMD3: + iParamCount = 3; + goto __execCmd; + + case OP_EXEC_CMD4: + iParamCount = 4; + goto __execCmd; + + case OP_EXEC_CMD5: + iParamCount = 5; + goto __execCmd; + + case OP_EXEC_CMD_COUNT1: + iParamCount = *m_CodePos++; + + __execCmd: + index = *reinterpret_cast(m_CodePos); + + m_CodePos += sizeof(unsigned int); + + pTop -= iParamCount; + + try + { + executeCommand(m_Thread, iParamCount, index); + } + catch (ScriptException& exc) + { + throw exc; + } + + break; + + case OP_EXEC_CMD_METHOD0: + iParamCount = 0; + goto __execCmdMethod; + + case OP_EXEC_CMD_METHOD1: + iParamCount = 1; + goto __execCmdMethod; + + case OP_EXEC_CMD_METHOD2: + iParamCount = 2; + goto __execCmdMethod; + + case OP_EXEC_CMD_METHOD3: + iParamCount = 3; + goto __execCmdMethod; + + case OP_EXEC_CMD_METHOD4: + iParamCount = 4; + goto __execCmdMethod; + + case OP_EXEC_CMD_METHOD5: + iParamCount = 5; + goto __execCmdMethod; + + __execCmdMethod: + m_CodePos--; + goto __execCmdMethodInternal; + + case OP_EXEC_CMD_METHOD_COUNT1: + iParamCount = *m_CodePos; + + __execCmdMethodInternal: + a = pTop--; + + try + { + index = *reinterpret_cast(m_CodePos + sizeof(byte)); + + pTop -= iParamCount; + + if (a->arraysize() < 0) + { + ScriptError("command '%s' applied to NIL", Event::GetEventName(index).c_str()); + } + + ScriptVariable array = *a; + Listener* listener; + + array.CastConstArrayValue(); + + for (int i = array.arraysize(); i > 0; i--) + { + if (!(listener = array[i]->listenerValue())) + { + ScriptError("command '%s' applied to NULL listener", Event::GetEventName(index).c_str()); + } + + executeCommand(listener, iParamCount, index); + } + } + catch (ScriptException& exc) + { + m_CodePos += sizeof(byte) + sizeof(unsigned int); + + throw exc; + } + + m_CodePos += sizeof(byte) + sizeof(unsigned int); + + break; + + case OP_EXEC_METHOD0: + iParamCount = 0; + goto __execMethod; + + case OP_EXEC_METHOD1: + iParamCount = 1; + goto __execMethod; + + case OP_EXEC_METHOD2: + iParamCount = 2; + goto __execMethod; + + case OP_EXEC_METHOD3: + iParamCount = 3; + goto __execMethod; + + case OP_EXEC_METHOD4: + iParamCount = 4; + goto __execMethod; + + case OP_EXEC_METHOD5: + iParamCount = 5; + + __execMethod: + m_CodePos--; + goto __execMethodInternal; + + case OP_EXEC_METHOD_COUNT1: + iParamCount = *m_CodePos; + + __execMethodInternal: + a = pTop--; + + try + { + index = *reinterpret_cast(m_CodePos + sizeof(byte)); + + pTop -= iParamCount; + pTop++; // push the return value + + Listener* listener = a->listenerValue(); + + if (!listener) + { + ScriptError("command '%s' applied to NULL listener", Event::GetEventName(index).c_str()); + } + + executeCommand(listener, iParamCount, index, true); + } + catch (ScriptException& exc) + { + m_CodePos += sizeof(byte) + sizeof(unsigned int); + + throw exc; + } + + m_CodePos += sizeof(byte) + sizeof(unsigned int); + + break; + + case OP_FUNC: + ev.Clear(); + + if (!*m_CodePos++) + { + str& label = Director.GetString(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(unsigned int); + + try + { + listener = pTop->listenerValue(); + + if (!listener) + { + ScriptError("function '%s' applied to NULL listener", label.c_str()); + } + } + catch (ScriptException& exc) + { + pTop -= *m_CodePos++; + + throw exc; + } + + pTop--; + + ev.AddString(label); + + int params = *m_CodePos++; + + var = pTop; + pTop -= params; + + for (int i = 0; i < params; var++, i++) { + ev.AddValue(*var); + } + + pTop++; + EnterFunction(&ev); + + m_ScriptClass->m_Self = listener; + } + else + { + str filename, label; + + filename = Director.GetString(*reinterpret_cast(m_CodePos)); + m_CodePos += sizeof(unsigned int); + label = Director.GetString(*reinterpret_cast(m_CodePos)); + m_CodePos += sizeof(unsigned int); + + try + { + listener = pTop->listenerValue(); + + if (!listener) + { + ScriptError("function '%s' in '%s' applied to NULL listener", label.c_str(), filename.c_str()); + } + } + catch (ScriptException& exc) + { + pTop -= *m_CodePos++; + + throw exc; + } + + pTop--; + + ScriptVariable constarray; + ScriptVariable* pVar = new ScriptVariable[2]; + + pVar[0].setStringValue(filename); + pVar[1].setStringValue(label); + + constarray.setConstArrayValue(pVar, 2); + + delete[] pVar; + + ev2 = new Event(EV_Listener_WaitCreateReturnThread); + ev2->AddValue(constarray); + + int params = *m_CodePos++; + + var = pTop; + pTop -= params; + + for (int i = 0; i < params; var++, i++) { + ev2->AddValue(*var); + } + + pTop++; + *pTop = listener->ProcessEventReturn(ev2); + } + break; + + case OP_JUMP4: + m_CodePos += *reinterpret_cast(m_CodePos) + sizeof(unsigned int); + break; + + case OP_JUMP_BACK4: + m_CodePos -= *reinterpret_cast(m_CodePos); + break; + + case OP_LOAD_ARRAY_VAR: + a = pTop--; + b = pTop--; + c = pTop--; + + b->setArrayAt(*a, *c); + break; + + case OP_LOAD_FIELD_VAR: + a = pTop--; + + try + { + listener = a->listenerValue(); + + if (listener == NULL) + { + value = Director.GetString(*reinterpret_cast(m_CodePos)); + ScriptError("Field '%s' applied to NULL listener", value.c_str()); + } + else + { + eventCalled = true; + loadTop(listener); + } + } + catch (ScriptException& exc) + { + pTop--; + + if (!eventCalled) { + m_CodePos += sizeof(unsigned int); + } + + throw exc; + } + + break; + + case OP_LOAD_CONST_ARRAY1: + index = *reinterpret_cast(m_CodePos); + m_CodePos += sizeof(short); + + pTop -= index - 1; + pTop->setConstArrayValue(pTop, index); + break; + + case OP_LOAD_GAME_VAR: + loadTop(&game); + break; + + case OP_LOAD_GROUP_VAR: + loadTop(m_ScriptClass); + break; + + case OP_LOAD_LEVEL_VAR: + loadTop(&level); + break; + + case OP_LOAD_LOCAL_VAR: + loadTop(m_Thread); + break; + + case OP_LOAD_OWNER_VAR: + if (!m_ScriptClass->m_Self) + { + pTop--; + m_CodePos += sizeof(unsigned int); + ScriptError("self is NULL"); + } + + if (!m_ScriptClass->m_Self->GetScriptOwner()) + { + pTop--; + m_CodePos += sizeof(unsigned int); + ScriptError("self.owner is NULL"); + } + + loadTop(m_ScriptClass->m_Self->GetScriptOwner()); + break; + + case OP_LOAD_PARM_VAR: + loadTop(&parm); + break; + + case OP_LOAD_SELF_VAR: + if (!m_ScriptClass->m_Self) + { + pTop--; + m_CodePos += sizeof(unsigned int); + ScriptError("self is NULL"); + } + + loadTop(m_ScriptClass->m_Self); + break; + + case OP_LOAD_STORE_GAME_VAR: + loadTop(&game, true); + break; + + case OP_LOAD_STORE_GROUP_VAR: + loadTop(m_ScriptClass, true); + break; + + case OP_LOAD_STORE_LEVEL_VAR: + loadTop(&level, true); + break; + + case OP_LOAD_STORE_LOCAL_VAR: + loadTop(m_Thread, true); + break; + + case OP_LOAD_STORE_OWNER_VAR: + if (!m_ScriptClass->m_Self) + { + m_CodePos += sizeof(unsigned int); + ScriptError("self is NULL"); + } + + if (!m_ScriptClass->m_Self->GetScriptOwner()) + { + m_CodePos += sizeof(unsigned int); + ScriptError("self.owner is NULL"); + } + + loadTop(m_ScriptClass->m_Self->GetScriptOwner(), true); + break; + + case OP_LOAD_STORE_PARM_VAR: + loadTop(&parm, true); + break; + + case OP_LOAD_STORE_SELF_VAR: + if (!m_ScriptClass->m_Self) + { + ScriptError("self is NULL"); + } + + loadTop(m_ScriptClass->m_Self, true); + break; + + case OP_MARK_STACK_POS: + m_StackPos = pTop; + m_bMarkStack = true; + break; + + case OP_STORE_PARAM: + if (fastEvent.dataSize) + { + pTop = fastEvent.data++; + fastEvent.dataSize--; + } + else + { + pTop = m_StackPos + 1; + pTop->Clear(); + } + break; + + case OP_RESTORE_STACK_POS: + pTop = m_StackPos; + m_bMarkStack = false; + break; + + case OP_STORE_ARRAY: + pTop--; + pTop->evalArrayAt(*(pTop + 1)); + break; + + case OP_STORE_ARRAY_REF: + pTop--; + pTop->setArrayRefValue(*(pTop + 1)); + break; + + case OP_STORE_FIELD_REF: + case OP_STORE_FIELD: + try + { + value = Director.GetString(*reinterpret_cast(m_CodePos)); + + listener = pTop->listenerValue(); + + if (listener == NULL) + { + ScriptError("Field '%s' applied to NULL listener", value.c_str()); + } + else + { + eventCalled = true; + storeTop(listener, true); + } + + if (*opcode == OP_STORE_FIELD_REF) + { + pTop->setRefValue(listener->vars->GetOrCreateVariable(value)); + } + } + catch (ScriptException& exc) + { + if (*opcode == OP_STORE_FIELD_REF) + { + pTop->setRefValue(pTop); + } + + if (!eventCalled) { + m_CodePos += sizeof(unsigned int); + } + + throw exc; + } + break; + + case OP_STORE_FLOAT: + pTop++; + pTop->setFloatValue(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(float); + + break; + + case OP_STORE_INT0: + pTop++; + pTop->setIntValue(0); + + break; + + case OP_STORE_INT1: + pTop++; + pTop->setIntValue(*m_CodePos++); + + break; + + case OP_STORE_INT2: + pTop++; + pTop->setIntValue(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(short); + + break; + + case OP_STORE_INT3: + pTop++; + pTop->setIntValue(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(short3); + break; + + case OP_STORE_INT4: + pTop++; + pTop->setIntValue(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(int); + + break; + + case OP_STORE_GAME_VAR: + storeTop(&game); + break; + + case OP_STORE_GROUP_VAR: + storeTop(m_ScriptClass); + break; + + case OP_STORE_LEVEL_VAR: + storeTop(&level); + break; + + case OP_STORE_LOCAL_VAR: + storeTop(m_Thread); + break; + + case OP_STORE_OWNER_VAR: + if (!m_ScriptClass->m_Self) + { + pTop++; + m_CodePos += sizeof(unsigned int); + ScriptError("self is NULL"); + } + + if (!m_ScriptClass->m_Self->GetScriptOwner()) + { + pTop++; + m_CodePos += sizeof(unsigned int); + ScriptError("self.owner is NULL"); + } + + storeTop(m_ScriptClass->m_Self->GetScriptOwner()); + break; + + case OP_STORE_PARM_VAR: + storeTop(&parm); + break; + + case OP_STORE_SELF_VAR: + if (!m_ScriptClass->m_Self) + { + pTop++; + m_CodePos += sizeof(unsigned int); + ScriptError("self is NULL"); + } + + storeTop(m_ScriptClass->m_Self); + break; + + case OP_STORE_GAME: + pTop++; + pTop->setListenerValue(&game); + break; + + case OP_STORE_GROUP: + pTop++; + pTop->setListenerValue(m_ScriptClass); + break; + + case OP_STORE_LEVEL: + pTop++; + pTop->setListenerValue(&level); + break; + + case OP_STORE_LOCAL: + pTop++; + pTop->setListenerValue(m_Thread); + break; + + case OP_STORE_OWNER: + pTop++; + + if (!m_ScriptClass->m_Self) + { + pTop++; + ScriptError("self is NULL"); + } + + pTop->setListenerValue(m_ScriptClass->m_Self->GetScriptOwner()); + break; + + case OP_STORE_PARM: + pTop++; + pTop->setListenerValue(&parm); + break; + + case OP_STORE_SELF: + pTop++; + pTop->setListenerValue(m_ScriptClass->m_Self); + break; + + case OP_STORE_NIL: + pTop++; + pTop->Clear(); + break; + + case OP_STORE_NULL: + pTop++; + pTop->setListenerValue(NULL); + break; + + case OP_STORE_STRING: + pTop++; + pTop->setConstStringValue(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(unsigned int); + + break; + + case OP_STORE_VECTOR: + pTop++; + pTop->setVectorValue(*reinterpret_cast(m_CodePos)); + + m_CodePos += sizeof(Vector); + + break; + + case OP_SWITCH: + if (!Switch(*reinterpret_cast(m_CodePos), *pTop)) + { + m_CodePos += sizeof(StateScript*); + } + + pTop--; + break; + + case OP_UN_CAST_BOOLEAN: + pTop->CastBoolean(); + break; + + case OP_UN_COMPLEMENT: + pTop->complement(); + break; + + case OP_UN_MINUS: + pTop->minus(); + break; + + case OP_UN_DEC: + (*pTop)--; + break; + + case OP_UN_INC: + (*pTop)++; + break; + + case OP_UN_SIZE: + pTop->setIntValue((int)pTop->size()); + break; + + case OP_UN_TARGETNAME: + targetList = world->GetExistingTargetList(pTop->stringValue()); + + if (!targetList) + { + value = pTop->stringValue(); + + pTop->setListenerValue(NULL); + + if (*m_CodePos >= OP_BIN_EQUALITY && *m_CodePos <= OP_BIN_GREATER_THAN_OR_EQUAL || *m_CodePos >= OP_BOOL_UN_NOT && *m_CodePos <= OP_UN_CAST_BOOLEAN) { + ScriptError("Targetname '%s' does not exist.", value.c_str()); + } + + break; + } + + if (targetList->NumObjects() == 1) + { + pTop->setListenerValue(targetList->ObjectAt(1)); + } + else if (targetList->NumObjects() > 1) + { + pTop->setContainerValue((Container< SafePtr< Listener > > *)targetList); + } + else + { + value = pTop->stringValue(); + + pTop->setListenerValue(NULL); + + if (*m_CodePos >= OP_BIN_EQUALITY && *m_CodePos <= OP_BIN_GREATER_THAN_OR_EQUAL || *m_CodePos >= OP_BOOL_UN_NOT && *m_CodePos <= OP_UN_CAST_BOOLEAN) { + ScriptError("Targetname '%s' does not exist.", value.c_str()); + } + + break; + } + + break; + + case OP_VAR_UN_NOT: + pTop->setIntValue(pTop->booleanValue()); + break; + + case OP_DONE: + End(); + break; + + case OP_NOP: + break; + + default: + if (*opcode < OP_MAX) + { + glbs.DPrintf("unknown opcode %d ('%s')\n", *opcode, OpcodeName(*opcode)); + } + else + { + glbs.DPrintf("unknown opcode %d\n", *opcode); + } + break; + } + } + catch (ScriptException& exc) + { + HandleScriptException(exc); + } + } + + Director.stackCount--; + + if (deleteThread || state == STATE_WAITING) + { + delete m_Thread; + } + else if (state == STATE_SUSPENDED) + { + state = STATE_EXECUTION; + } + + if (state == STATE_DESTROYED) + { + delete this; + } +} + +/* +==================== +HandleScriptException +==================== +*/ +void ScriptVM::HandleScriptException(ScriptException& exc) +{ + if (m_ScriptClass) + { + m_ScriptClass->GetScript()->PrintSourcePos(m_PrevCodePos, true); + } + else + { + glbs.DPrintf("unknown source pos"); + } + + if (exc.bAbort) + { + ScriptException e(exc.string); + + e.bAbort = exc.bAbort; + e.bIsForAnim = exc.bIsForAnim; + + state = STATE_EXECUTION; + throw e; + } + + glbs.Printf("^~^~^ Script Error : %s\n\n", exc.string.c_str()); + + if (m_ScriptClass->GetScript()->ScriptCheck()) + { + if (g_scriptcheck->integer != 2 || !exc.bIsForAnim) + { + ScriptException e("Script check failed"); + + e.bAbort = exc.bAbort; + e.bIsForAnim = exc.bIsForAnim; + + state = STATE_EXECUTION; + throw e; + } + } + Director.cmdCount += 100; +} + +/* +==================== +SetFastData + +Sets the starting virtual machine parameters +==================== +*/ +void ScriptVM::SetFastData(ScriptVariable* data, int dataSize) +{ + if (fastEvent.data) + { + fastEvent.data = m_pOldData; + fastEvent.dataSize = m_OldDataSize; + + fastEvent.Clear(); + + m_pOldData = NULL; + m_OldDataSize = 0; + } + + if (dataSize) + { + fastEvent.data = new ScriptVariable[dataSize]; + fastEvent.dataSize = dataSize; + + for (int i = 0; i < dataSize; i++) + { + fastEvent.data[i] = data[i]; + } + + m_pOldData = fastEvent.data; + m_OldDataSize = fastEvent.dataSize; + } +} + +/* +==================== +NotifyDelete +==================== +*/ +void ScriptVM::NotifyDelete(void) +{ + switch (state) + { + case STATE_DESTROYED: + ScriptError("Attempting to delete a dead thread."); + break; + + case STATE_RUNNING: + case STATE_SUSPENDED: + case STATE_WAITING: + state = STATE_DESTROYED; + + if (m_ScriptClass) { + m_ScriptClass->RemoveThread(this); + } + + break; + + case STATE_EXECUTION: + state = STATE_DESTROYED; + + if (m_ScriptClass) { + m_ScriptClass->RemoveThread(this); + } + + delete this; + + break; + } +} + +/* +==================== +Resume +==================== +*/ +void ScriptVM::Resume(qboolean bForce) +{ + if (state == STATE_SUSPENDED || (bForce && state != STATE_DESTROYED)) { + state = STATE_RUNNING; + } +} + +/* +==================== +Suspend +==================== +*/ +void ScriptVM::Suspend() +{ + if (state == STATE_DESTROYED) { + ScriptError("Cannot suspend a dead thread."); + } + else if (!state) { + state = STATE_SUSPENDED; + } +} + +/* +==================== +Switch + +Switch statement +==================== +*/ +bool ScriptVM::Switch(StateScript* stateScript, ScriptVariable& var) +{ + unsigned char* pos; + + fastEvent.dataSize = 0; + + pos = stateScript->FindLabel(var.stringValue()); + + if (!pos) + { + pos = stateScript->FindLabel(""); + + if (!pos) { + return false; + } + } + + m_CodePos = pos; + + return true; +} + +/* +==================== +Filename +==================== +*/ +str ScriptVM::Filename(void) +{ + return m_ScriptClass->Filename(); +} + +/* +==================== +Label +==================== +*/ +str ScriptVM::Label(void) +{ + const_str label = m_ScriptClass->NearestLabel(m_CodePos); + + if (!label) + { + return ""; + } + + return Director.GetString(label); +} + +/* +==================== +GetScriptClass +==================== +*/ +ScriptClass* ScriptVM::GetScriptClass(void) +{ + return m_ScriptClass; +} + +/* +==================== +IsSuspended +==================== +*/ +bool ScriptVM::IsSuspended(void) +{ + return state == STATE_SUSPENDED; +} + +/* +==================== +State +==================== +*/ +int ScriptVM::State(void) +{ + return state; +} + +/* +==================== +ThreadState +==================== +*/ +int ScriptVM::ThreadState(void) +{ + return m_ThreadState; +} + +/* +==================== +EventGoto +==================== +*/ +void ScriptVM::EventGoto(Event* ev) +{ + str label = ev->GetString(1); + + SetFastData(ev->data + 1, ev->dataSize - 1); + + unsigned char* codePos = m_ScriptClass->FindLabel(label); + + if (!codePos) + { + ScriptError("ScriptVM::EventGoto: label '%s' does not exist in '%s'.", label.c_str(), Filename().c_str()); + } + + m_CodePos = codePos; +} + +/* +==================== +EventThrow + +Called when throwing an exception +==================== +*/ +bool ScriptVM::EventThrow(Event* ev) +{ + str label = ev->GetString(1); + + SetFastData(ev->data, ev->dataSize); + + fastEvent.eventnum = ev->eventnum; + + while (1) + { + StateScript* stateScript = m_ScriptClass->GetCatchStateScript(m_PrevCodePos, m_PrevCodePos); + + if (!stateScript) { + break; + } + + m_CodePos = stateScript->FindLabel(label); + + if (m_CodePos) + { + fastEvent.data++; + fastEvent.dataSize--; + + return true; + } + } + + return false; +} + +/* +==================== +AllowContextSwitch +==================== +*/ +void ScriptVM::AllowContextSwitch(bool allow) +{ + m_bAllowContextSwitch = allow; +} + +/* +==================== +RequestContextSwitch + +Requests a context switch +==================== +*/ +void ScriptVM::RequestContextSwitch(void) +{ + if (!m_bAllowContextSwitch || !Director.m_bAllowContextSwitch) { + return; + } + + //glbs.DPrintf( "Performing context switch\n" ); + + Director.AddContextSwitch(m_Thread); + + m_ThreadState = THREAD_CONTEXT_SWITCH; + Suspend(); +} + +bool ScriptVM::CanScriptTracePrint +( + void +) +{ + if (g_scripttrace->integer < 1 || g_scripttrace->integer > 4) + { + return false; + } + if (g_scripttrace->integer <= 2) + { + return true; + } + if (!m_ScriptClass) + { + return false; + } + if (!*g_monitor->string || !m_ScriptClass->m_Self || !m_ScriptClass->m_Self->isInheritedBy(&SimpleEntity::ClassInfo) || ((SimpleEntity*)m_ScriptClass->m_Self.Pointer())->targetname != g_monitor->string) + { + if (g_monitorNum->integer >= 0) + { + if (m_ScriptClass->m_Self && m_ScriptClass->m_Self->isInheritedBy(&Entity::ClassInfo) && ((Entity*)m_ScriptClass->m_Self.Pointer())->entnum == g_monitorNum->integer) + { + return true; + } + } + return false; + } + return true; + +} diff --git a/code/globalcpp/scriptvm.h b/code/game/scriptvm.h similarity index 100% rename from code/globalcpp/scriptvm.h rename to code/game/scriptvm.h diff --git a/code/game/sentient.h b/code/game/sentient.h index 0074f488..0dd84ad7 100644 --- a/code/game/sentient.h +++ b/code/game/sentient.h @@ -114,7 +114,6 @@ inline ActiveWeapon::ActiveWeapon ) { - weapon = NULL; hand = WEAPON_ERROR; } @@ -394,7 +393,7 @@ inline void Sentient::ClearNewActiveWeapon ) { - newActiveWeapon.weapon = NULL; + newActiveWeapon.weapon.Clear(); newActiveWeapon.hand = WEAPON_ERROR; } diff --git a/code/globalcpp/simpleentity.cpp b/code/game/simpleentity.cpp similarity index 99% rename from code/globalcpp/simpleentity.cpp rename to code/game/simpleentity.cpp index de09d284..70bad5da 100644 --- a/code/globalcpp/simpleentity.cpp +++ b/code/game/simpleentity.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "glb_local.h" #include "simpleentity.h" #include "world.h" +#include "level.h" Event EV_SimpleEntity_GetAngle ( diff --git a/code/globalcpp/simpleentity.h b/code/game/simpleentity.h similarity index 100% rename from code/globalcpp/simpleentity.h rename to code/game/simpleentity.h diff --git a/code/globalcpp/slre.c b/code/game/slre.c similarity index 100% rename from code/globalcpp/slre.c rename to code/game/slre.c diff --git a/code/globalcpp/slre.h b/code/game/slre.h similarity index 100% rename from code/globalcpp/slre.h rename to code/game/slre.h diff --git a/code/game/spawners.cpp b/code/game/spawners.cpp index 566d5317..0610a19f 100644 --- a/code/game/spawners.cpp +++ b/code/game/spawners.cpp @@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ******************************************************************************/ #include "spawners.h" +#include "game.h" Event EV_Spawn_ModelName ( diff --git a/code/game/specialfx.cpp b/code/game/specialfx.cpp index 0fdfaa4d..4061e1d7 100644 --- a/code/game/specialfx.cpp +++ b/code/game/specialfx.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "g_local.h" #include "specialfx.h" +#include "level.h" /*****************************************************************************/ /*QUAKED func_fulcrum (0 0 1) ? X_AXIS_ONLY Y_AXIS_ONLY diff --git a/code/game/viewthing.cpp b/code/game/viewthing.cpp index c2cbda8d..1b6a7042 100644 --- a/code/game/viewthing.cpp +++ b/code/game/viewthing.cpp @@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "animate.h" #include "viewthing.h" +#include "game.h" +#include "level.h" Event EV_ViewThing_Think ( diff --git a/code/game/weaputils.h b/code/game/weaputils.h index e49cd315..2978fc14 100644 --- a/code/game/weaputils.h +++ b/code/game/weaputils.h @@ -39,6 +39,7 @@ extern Event EV_Projectile_Explode; extern Event EV_Projectile_UpdateBeam; class Weapon; +class Sentient; class Projectile : public Animate { diff --git a/code/game/windows.cpp b/code/game/windows.cpp index ad8f04cf..b0695591 100644 --- a/code/game/windows.cpp +++ b/code/game/windows.cpp @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // #include "windows.h" +#include "game.h" Event EV_Window_Setup ( diff --git a/code/globalcpp/world.cpp b/code/game/world.cpp similarity index 99% rename from code/globalcpp/world.cpp rename to code/game/world.cpp index f79699d1..095fb10c 100644 --- a/code/globalcpp/world.cpp +++ b/code/game/world.cpp @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // world.cpp : Holds the target list, and general info (fog and such). #include "world.h" +#include "level.h" #include #ifdef GAME_DLL diff --git a/code/globalcpp/world.h b/code/game/world.h similarity index 100% rename from code/globalcpp/world.h rename to code/game/world.h diff --git a/code/globalcpp/archive_dummy.cpp b/code/globalcpp/archive_dummy.cpp deleted file mode 100644 index 6fea7a7a..00000000 --- a/code/globalcpp/archive_dummy.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -// archive.cpp: OpenMoHAA Archiver - -#include "glb_local.h" -#include "archive.h" -#include - -#ifdef GAME_DLL -#include "../game/entity.h" -#endif - - -CLASS_DECLARATION( Class, FileRead, NULL ) -{ - { NULL, NULL } -}; - -FileRead::FileRead() -{ -} - -FileRead::~FileRead() -{ -} - -void FileRead::Close - ( - bool bDoCompression - ) - -{ -} - -const char *FileRead::Filename -( -void -) - -{ - return ""; -} - -size_t FileRead::Length -( -void -) - -{ - return length; -} - -size_t FileRead::Pos -( -void -) - -{ - return 0; -} - -qboolean FileRead::Seek -( -size_t newpos -) - -{ - return qfalse; -} - -qboolean FileRead::Open - ( - const char *name - ) - -{ - return qfalse; -} - -qboolean FileRead::Read - ( - void *dest, - size_t size - ) - -{ - return qfalse; -} - -CLASS_DECLARATION( Class, Archiver, NULL ) -{ - { NULL, NULL } -}; - -Archiver::Archiver() -{ -} - -Archiver::~Archiver() -{ -} - -void Archiver::FileError - ( - const char *fmt, - ... - ) - -{ -} - -void Archiver::Close - ( - void - ) - -{ -} - -/**************************************************************************************** - -File Read/Write functions - -*****************************************************************************************/ - -qboolean Archiver::Read -( -const char *name, -qboolean harderror -) - -{ - return qfalse; -} - -qboolean Archiver::Create - ( - const char *name, - qboolean harderror - ) - -{ - return qfalse; -} - - -inline void Archiver::CheckRead -( -void -) - -{ -} - -inline void Archiver::CheckWrite -( -void -) - -{ -} - -inline size_t Archiver::ReadSize -( -void -) - -{ -} - -inline void Archiver::CheckSize -( -int type, -size_t size -) - -{ -} - -inline void Archiver::WriteSize -( -size_t size -) - -{ -} - -inline int Archiver::ReadType -( -void -) - -{ -} - -inline void Archiver::WriteType - ( - int type - ) - -{ -} - - -inline void Archiver::CheckType - ( - int type - ) - -{ -} - -/**************************************************************************************** - -File Archive functions - -*****************************************************************************************/ - -//#define ARCHIVE_USE_TYPES 1 - -inline void Archiver::ArchiveData - ( - int type, - void *data, - size_t size - ) - -{ -} - - -#define ARCHIVE( func, type ) \ -void Archiver::Archive##func \ - ( \ - type * v \ - ) \ - \ -{ \ -} - -ARCHIVE( Vector, Vector ); -ARCHIVE( Integer, int ); -ARCHIVE( Unsigned, unsigned ); -ARCHIVE( Size, size_t ); -ARCHIVE( Byte, byte ); -ARCHIVE( Char, char ); -ARCHIVE( Short, short ); -ARCHIVE( UnsignedShort, unsigned short ); -ARCHIVE( Float, float ); -ARCHIVE( Double, double ); -ARCHIVE( Boolean, qboolean ); -ARCHIVE( Quat, Quat ); -ARCHIVE( Bool, bool ); -ARCHIVE( Position, int ); - -void Archiver::ArchiveSvsTime - ( - int *time - ) - -{ -} - -void Archiver::ArchiveVec2 - ( - vec2_t vec - ) - -{ -} - -void Archiver::ArchiveVec3 - ( - vec3_t vec - ) - -{ -} - -void Archiver::ArchiveVec4 - ( - vec4_t vec - ) - -{ -} - -void Archiver::ArchiveObjectPointer -( -Class ** ptr -) - -{ -} - -void Archiver::ArchiveObjectPosition( void *obj ) -{ -} - -void Archiver::ArchiveSafePointer -( -SafePtrBase * ptr -) - -{ -} - -void Archiver::ArchiveEventPointer -( -Event ** ev -) - -{ -} - -void Archiver::ArchiveRaw -( -void *data, -size_t size -) - -{ -} - -void Archiver::ArchiveString -( -str * string -) - -{ -} - -void Archiver::ArchiveConfigString( int cs ) -{ -} - -Class * Archiver::ReadObject - ( - void - ) - -{ - return NULL; -} - -void Archiver::ArchiveObject - ( - Class *obj - ) - -{ -} - -qboolean Archiver::ObjectPositionExists( void *obj ) -{ - return qfalse; -} - -void Archiver::SetSilent( bool bSilent ) -{ -} diff --git a/code/globalcpp/basemain.cpp b/code/globalcpp/basemain.cpp deleted file mode 100644 index fb27dcd9..00000000 --- a/code/globalcpp/basemain.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -void BaseInit( void ) -{ - developer = new cvar_t; - g_scriptcheck = new cvar_t; - g_showopcodes = new cvar_t; - precache = new cvar_t; - sv_scriptfiles = new cvar_t; - - memset( developer, 0, sizeof( cvar_t ) ); - memset( g_scriptcheck, 0, sizeof( cvar_t ) ); - memset( g_showopcodes, 0, sizeof( cvar_t ) ); - memset( precache, 0, sizeof( cvar_t ) ); - memset( sv_scriptfiles, 0, sizeof( cvar_t ) ); - - Com_FillBaseImports(); - - Swap_Init(); - Z_InitMemory(); - - Cmd_Init(); - Cvar_Init(); - - FS_InitFilesystem2(); - - L_InitEvents(); - -#ifndef NO_SCRIPTENGINE - level.m_LoopProtection = false; - world = new World; - - Director.Init(); - Director.Reset( false ); - - Director.maxTime = 50; -#endif -} - -void BaseRunFrame( double frametime ) -{ - level.setFrametime( frametime ); - level.setTime( clock() ); - -#ifndef NO_SCRIPTENGINE - Director.SetTime( level.inttime ); - Director.m_bAllowContextSwitch = true; -#endif - - L_ProcessPendingEvents(); -#ifndef NO_SCRIPTENGINE - Director.ExecuteRunning(); -#endif -} - -void BaseIdle( void ) -{ - double frametime = 0; - double lastframetime; - double tick = 0; - - bi.Printf( "BaseIdle()\n" ); - - tick = ( double )clock();// / 1000.0; - lastframetime = tick; - - while( 1 ) - { - tick = ( double )clock();// / 1000.0; - - frametime = ( tick - lastframetime ); - lastframetime = tick; - - BaseRunFrame( frametime ); - - Sleep( 50 ); - } -} - - -#ifdef _WINDLL -void InitModule(); -void ShutdownModule(); - -BOOL APIENTRY DllMain(HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved -) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - BaseInit(); - InitModule(); - break; - case DLL_PROCESS_DETACH: - ShutdownModule(); - - L_ShutdownEvents(); - - Com_Shutdown(); - FS_Shutdown(qtrue); - break; - } - return TRUE; -} -#else - -int MainEvent(const Container< Event * >& conev); - -int main( int argc, char **argv ) -{ - Container< Event * > conev; - Event *ev; - int i; - char *arg; - - BaseInit(); - - // copy the argument list - for( i = 0; i < argc; i++ ) - { - arg = argv[ i ]; - - if( strlen( arg ) <= 1 ) { - continue; - } - - if( *arg != '/' && *arg != '-' && *arg != '+' ) { - continue; - } - - ev = new Event( arg + 1 ); - - for( i++; i < argc; i++ ) - { - arg = argv[ i ]; - if( *arg == '/' || *arg == '-' || *arg == '+' ) { - i--; - break; - } - - ev->AddString( argv[ i ] ); - } - - conev.AddObject( ev ); - } - - MainEvent( conev ); - - conev.FreeObjectList(); - - L_ShutdownEvents(); - - Com_Shutdown(); - FS_Shutdown( qtrue ); -} - -#endif diff --git a/code/globalcpp/basemain.h b/code/globalcpp/basemain.h deleted file mode 100644 index 0dbb0a57..00000000 --- a/code/globalcpp/basemain.h +++ /dev/null @@ -1,4 +0,0 @@ -#include "listener.h" - -void BaseRunFrame( double frametime ); -void BaseIdle( void ); diff --git a/code/globalcpp/console.cpp b/code/globalcpp/console.cpp deleted file mode 100644 index 40a8dd6c..00000000 --- a/code/globalcpp/console.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -// console.h: TU Console. - -#include "console.h" -#include - -CLASS_DECLARATION( Listener, ConsoleInput, NULL ) -{ - { NULL, NULL } -}; - - -#ifdef WIN32 - -HANDLE WINAPI WIN_CreateThread - ( - LPSECURITY_ATTRIBUTES lpThreadAttributes, - SIZE_T dwStackSize, - LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter, - DWORD dwCreationFlags, - LPDWORD lpThreadId - ) - -{ - return CreateThread( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId ); -} - - -DWORD WINAPI InputThread - ( - LPVOID lpParameter - ) - -{ - ConsoleInput *console = ( ConsoleInput * )lpParameter; - console->Input_Idle(); - return 0; -} - -#else - -void *InputThread - ( - void *arg - ) - -{ - ConsoleInput *console = ( ConsoleInput * )lpParameter; - console->Input_Idle(); - return NULL; -} - -#endif - -ConsoleInput::ConsoleInput() -{ -} - -ConsoleInput::ConsoleInput( Listener *consoleEvent ) -{ - m_pConsoleEvent = consoleEvent; -} - -void ConsoleInput::InitInput( void ) -{ -#ifdef WIN32 - WIN_CreateThread( NULL, 0, InputThread, ( void * )this, 0, NULL ); -#else - pthread_t thread; - - pthread_create( &thread, NULL, ( void * ( *)( void * ) )&InputThread, ( void * )this ); -#endif -} - -bool ConsoleInput::CheckEvent - ( - Event *ev - ) - -{ - EventDef *def = m_pConsoleEvent->classinfo()->GetDef( ev->eventnum ); - - if( !def ) - { - return false; - } - - if( !( def->flags & EV_CONSOLE ) ) - { - return false; - } - - return true; -} - -void ConsoleInput::PrintHelp - ( - void - ) - -{ - ResponseDef< Class > *r; - - bi.Printf( "Command list :\n\n" ); - - r = m_pConsoleEvent->classinfo()->responses; - while( r->event ) - { - r->def->PrintEventDocumentation( stdout, false ); - r++; - } -} - -bool ConsoleInput::Execute - ( - const char *data - ) - -{ - char *buffer; - const char *com_token; - str sCommand; - - buffer = ( char * )malloc( strlen( data ) + 1 ); - strcpy( buffer, data ); - - com_token = COM_Parse( &buffer ); - - if( !com_token ) - { - Com_Printf( "Enter a valid command.\n" ); - free( buffer ); - return false; - } - - sCommand = com_token; - - if( Event::FindEventNum( sCommand ) ) - { - Event *ev = new Event( sCommand ); - - while( 1 ) - { - com_token = COM_Parse( &buffer ); - - if( !com_token[ 0 ] ) - break; - - ev->AddString( com_token ); - } - - if( CheckEvent( ev ) ) - { - m_pConsoleEvent->ProcessEvent( ev ); - } - else - { - Com_Printf( "Command '%s' not available from console.\n", sCommand.c_str() ); - free( buffer ); - return false; - } - } - else - { - Com_Printf( "Command '%s' is not valid. Type help for more info.\n", sCommand.c_str() ); - free( buffer ); - return false; - } - - free( buffer ); - return true; -} - -bool ConsoleInput::Execute - ( - int argc, - char *argv[] - ) - -{ - size_t iLength = 0; - int i; - char *data; - - for( i = 1; i < argc; i++ ) - { - iLength += strlen( argv[ i ] ) + 1; - } - - if( iLength <= 1 ) - { - return false; - } - - data = ( char * )malloc( iLength + 1 ); - - memset( data, 0, iLength + 1 ); - - for( i = 1; i < argc; i++ ) - { - strcat( data, argv[ i ] ); - strcat( data, " " ); - } - - bool bResult = Execute( data ); - free( data ); - - return bResult; -} - -void ConsoleInput::Input_Idle - ( - void - ) - -{ - char *szBuffer = ( char * )malloc( 255 ); - int i; - - while( 1 ) - { - i = 0; - - /*while( !feof( stdin ) ) - { - szBuffer[ i ] = getchar(); - - if( szBuffer[ i ] == '\r' || szBuffer[ i ] == '\n' ) - { - szBuffer[ i ] = 0; - break; - } - - if( szBuffer[ i ] == '\b' ) - { - szBuffer[ i ] = 0; - i--; - } - else - { - i++; - } - } - */ - - fgets( szBuffer, 255, stdin ); - OemToCharBuff( szBuffer, szBuffer, 255 ); - - Execute( szBuffer ); - } -} diff --git a/code/globalcpp/console.h b/code/globalcpp/console.h deleted file mode 100644 index 238c2ba1..00000000 --- a/code/globalcpp/console.h +++ /dev/null @@ -1,52 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -// console.h: Console. - -#ifndef __CONSOLE_H__ -#define __CONSOLE_H__ - -#include - -class ConsoleInput : public Listener { -private: - Listener *m_pConsoleEvent; - -public: - void Input_Idle( void ); - -public: - CLASS_PROTOTYPE( ConsoleInput ); - - ConsoleInput(); - ConsoleInput( Listener *consoleEvent ); - - void InitInput( void ); - - bool Execute( const char *data ); - bool Execute( int argc, char *argv[] ); - - bool CheckEvent( Event *ev ); - void PrintHelp( void ); -}; - -#endif /* __CONSOLE_H__ */ diff --git a/code/globalcpp/dummy/dummy_base.cpp b/code/globalcpp/dummy/dummy_base.cpp deleted file mode 100644 index 5d5f4110..00000000 --- a/code/globalcpp/dummy/dummy_base.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include -#include -#include -#include "dummy_base.h" -#include "../client/client.h" -#include - -clientStatic_t cls; -baseImport_t bi; - -cvar_t *developer; -cvar_t *g_scriptcheck; -cvar_t *g_showopcodes; -cvar_t *precache; -cvar_t *sv_scriptfiles; - -void Com_FillBaseImports() { - bi.Printf = BI_Printf; - bi.DPrintf = BI_DPrintf; - bi.Error = BI_Error; - bi.Free = BI_Free; - bi.Malloc = BI_Malloc; - - bi.Milliseconds = BI_Milliseconds; - - bi.FS_FreeFile = FS_FreeFile; - bi.FS_ReadFile = FS_ReadFile2; - bi.FS_CanonicalFilename = FS_CanonicalFilename; -} - -void Z_InitMemory() { -} - -void Cmd_Init( void ) { -} - -void Cvar_Init( void ) { -} - -void FS_InitFilesystem( void ) { -} - -void FS_InitFilesystem2( void ) { -} - -void QDECL Com_Error( int level, const char *error, ... ) { - va_list argptr; - char *buffer; - int size; - - va_start( argptr, error ); - size = vsnprintf( NULL, 0, error, argptr ); - va_end( argptr ); - - buffer = ( char * )bi.Malloc( size + 1 ); - buffer[ size ] = 0; - - va_start( argptr, error ); - vsnprintf( buffer, size, error, argptr ); - va_end( argptr ); - - bi.Error( level, "%s", buffer ); - bi.Free( buffer ); -} - -void QDECL Com_Printf( const char *msg, ... ) { - va_list argptr; - char *buffer; - int size; - - va_start( argptr, msg ); - size = vsnprintf( NULL, 0, msg, argptr ); - va_end( argptr ); - - buffer = ( char * )bi.Malloc( size + 1 ); - buffer[ size ] = 0; - - va_start( argptr, msg ); - vsnprintf( buffer, size, msg, argptr ); - va_end( argptr ); - - bi.Printf( "%s", buffer ); - bi.Free( buffer ); -} - -void QDECL Com_DPrintf( const char *msg, ... ) { - va_list argptr; - char *buffer; - int size; - - va_start( argptr, msg ); - size = vsnprintf( NULL, 0, msg, argptr ); - va_end( argptr ); - - buffer = ( char * )bi.Malloc( size + 1 ); - buffer[ size ] = 0; - - va_start( argptr, msg ); - vsnprintf( buffer, size, msg, argptr ); - va_end( argptr ); - - bi.DPrintf( "%s", buffer ); - bi.Free( buffer ); -} - -void BI_Printf( const char *msg, ... ) -{ - va_list argptr; - char *buffer; - int size; - - va_start( argptr, msg ); - size = vsnprintf( NULL, 0, msg, argptr ); - va_end( argptr ); - - buffer = ( char * )bi.Malloc( size + 1 ); - buffer[ size ] = 0; - - va_start( argptr, msg ); - vsnprintf( buffer, size, msg, argptr ); - va_end( argptr ); - - printf( "%s", buffer ); - - bi.Free( buffer ); -} - -void BI_DPrintf( const char *msg, ... ) -{ -#ifdef _DEBUG - va_list argptr; - char *buffer; - int size; - - if( !developer->integer ) { - return; - } - - va_start( argptr, msg ); - size = vsnprintf( NULL, 0, msg, argptr ); - va_end( argptr ); - - buffer = ( char * )bi.Malloc( size + 1 ); - buffer[ size ] = 0; - - va_start( argptr, msg ); - vsnprintf( buffer, size, msg, argptr ); - va_end( argptr ); - - printf( "%s", buffer ); - - bi.Free( buffer ); -#endif -} - -void BI_Error( int level, const char *msg, ... ) -{ - va_list argptr; - char *buffer; - int size; - - va_start( argptr, msg ); - size = vsnprintf( NULL, 0, msg, argptr ); - va_end( argptr ); - - buffer = ( char * )bi.Malloc( size + 1 ); - buffer[ size ] = 0; - - va_start( argptr, msg ); - vsnprintf( buffer, size, msg, argptr ); - va_end( argptr ); - - BI_Printf( "%s", buffer ); - - bi.Free( buffer ); -} - -int BI_Milliseconds( void ) -{ - return GetTickCount(); -} - -void *BI_Malloc( int size ) -{ - return malloc( size ); -} - -void BI_Free( void *ptr ) -{ - free( ptr ); -} - -void FS_FreeFile( void *buffer ) -{ - bi.Free( buffer ); -} - -int FS_ReadFile2( const char *name, void **buffer, qboolean bSilent ) -{ - str filename = name; - FILE *file = fopen( filename, "rb+" ); - int size; - char *p; - - if( file == NULL ) - { - return -1; - } - - fseek( file, 0, SEEK_END ); - size = ftell( file ); - rewind( file ); - - *buffer = bi.Malloc( size + 1 ); - memset( *buffer, 0, size ); - fread( *buffer, size, 1, file ); - - fclose( file ); - - - p = ( char * )*buffer; - p[ size ] = 0; - - return size; -} - -void FS_CanonicalFilename( char *filename ) -{ - char *p = filename; - - while( *p ) - { - if( p[ 0 ] == '/' && p[ 1 ] == '/' ) - { - char *p2 = p + 1; - - while( *p2 ) - { - p2[ 0 ] = p2[ 1 ]; - p2++; - } - } - - p++; - } -} diff --git a/code/globalcpp/dummy/dummy_base.h b/code/globalcpp/dummy/dummy_base.h deleted file mode 100644 index e19f2200..00000000 --- a/code/globalcpp/dummy/dummy_base.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef __DUMY_BASE_H__ -#define __DUMY_BASE_H__ - -#include -#include "q_shared.h" - -#ifdef __cplusplus -extern "C" { -#endif - -void Com_FillBaseImports(); -void Z_InitMemory(); - -void Cmd_Init( void ); -void Cvar_Init( void ); -void FS_InitFilesystem( void ); - -void BI_Printf( const char *msg, ... ); -void BI_DPrintf( const char *msg, ... ); -void BI_Error( int level, const char *msg, ... ); -int BI_Milliseconds( void ); -void * BI_Malloc( int size ); -void BI_Free( void *ptr ); -int FS_ReadFile2( const char *name, void **buffer, qboolean bSilent ); - -//void FS_FreeFile( void *buffer ); -//int FS_ReadFile( const char *name, void **buffer, bool bSilent ); -//void FS_CanonicalFilename( char *filename ); - -#ifdef __cplusplus -} -#endif - -#endif /* __DUMY_BASE_H__ */ diff --git a/code/globalcpp/dummy/dummy_game.cpp b/code/globalcpp/dummy/dummy_game.cpp deleted file mode 100644 index 082bd8e3..00000000 --- a/code/globalcpp/dummy/dummy_game.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "game.h" - -Game game; - -void CacheResource( const char *name ) -{ - -} - -SimpleEntity *G_FindTarget( SimpleEntity *next, const char *classname ) -{ - return NULL; -} - -Vector G_GetMovedir( float angle ) -{ - if( angle == -1.0f ) - { - return Vector( 0.0f, 0.0f, 1.0f ); - } - else if( angle == -2.0f ) - { - return Vector( 0.0f, 0.0f, -1.0f ); - } - - angle *= ( M_PI * 2.0f / 360.0f ); - return Vector( cos( angle ), sin( angle ), 0.0f ); -} - -float G_Random( float value ) -{ - return fmod( rand(), value ); -} - -CLASS_DECLARATION( Listener, Game, NULL ) -{ - { NULL, NULL } -}; diff --git a/code/globalcpp/dummy/dummy_level.cpp b/code/globalcpp/dummy/dummy_level.cpp deleted file mode 100644 index 7566be0e..00000000 --- a/code/globalcpp/dummy/dummy_level.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -// game.cpp : TU Level. - -#include "level.h" - -Level level; - -void Level::setTime( int levelTime ) -{ - svsTime = levelTime; - inttime = levelTime - svsStartTime; - svsFloatTime = levelTime / 1000.0f; - time = inttime / 1000.0f; -} - -void Level::setFrametime( int frametime ) -{ - intframetime = frametime; - this->frametime = frametime / 1000.0f; -} - -CLASS_DECLARATION( Listener, Level, NULL ) -{ - { NULL, NULL } -}; diff --git a/code/globalcpp/dummy/game.h b/code/globalcpp/dummy/game.h deleted file mode 100644 index 7c3ded39..00000000 --- a/code/globalcpp/dummy/game.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef __GAME_H__ -#define __GAME_H__ - -#include - -class Game : public Listener { - CLASS_PROTOTYPE( Game ); -}; - -extern Game game; - -SimpleEntity *G_FindTarget( SimpleEntity *next, const char *classname ); -Vector G_GetMovedir( float angle ); -float G_Random( float value ); - -#endif /* __GAME_H__*/ \ No newline at end of file diff --git a/code/globalcpp/dummy/level.h b/code/globalcpp/dummy/level.h deleted file mode 100644 index a60a373e..00000000 --- a/code/globalcpp/dummy/level.h +++ /dev/null @@ -1,68 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#ifndef __LEVEL_H__ -#define __LEVEL_H__ - -#include - -class SimpleArchivedEntity; - -class Level : public Listener { -public: - bool m_LoopDrop; - bool m_LoopProtection; - - str m_mapscript; - str current_map; - - // Level time - int framenum; - int inttime; - int intframetime; - - float time; - float frametime; - - int spawnflags; - - // Server time - int svsTime; - float svsFloatTime; - int svsStartTime; - int svsEndTime; - - bool m_bScriptSpawn; - bool m_bRejectSpawn; - - Container< SimpleArchivedEntity * > m_SimpleArchivedEntities; - -public: - CLASS_PROTOTYPE( Level ); - - void setTime( int _svsTime_ ); - void setFrametime( int frameTime ); -}; - -extern Level level; - -#endif /* __LEVEL_H__*/ \ No newline at end of file diff --git a/code/globalcpp/pipe.cpp b/code/globalcpp/pipe.cpp deleted file mode 100644 index af2ed87c..00000000 --- a/code/globalcpp/pipe.cpp +++ /dev/null @@ -1,356 +0,0 @@ -#include "pipe.h" -#include - -MessageEvent::MessageEvent() -{ - Buffer = NULL; - BufferSize = 0; - AllocatedSize = 0; - Position = NULL; - bReadMode = false; -} - -MessageEvent::~MessageEvent() -{ - if (Buffer) - { - free(Buffer); - } -} - -void MessageEvent::Reset() -{ - if (Buffer) - { - free(Buffer); - } - - Buffer = NULL; - BufferSize = 0; - AllocatedSize = 0; - Position = NULL; - bReadMode = false; -} - -byte* MessageEvent::SetReadMode(size_t size) -{ - Reset(); - - Buffer = (byte*)malloc(size); - BufferSize = size; - AllocatedSize = size; - Position = Buffer; - bReadMode = true; - - return Buffer; -} - -bool MessageEvent::ReadBool() -{ - return !FinishedReading() ? *Position++ : false; -} - -str MessageEvent::ReadString() -{ - str Value; - - while (1) - { - char CharValue = ReadByte(); - if (CharValue <= 0) - { - break; - } - - Value += CharValue; - } - - return Value; -} - -byte MessageEvent::ReadByte() -{ - if (FinishedReading()) - { - return -1; - } - - return *Position++; -} - -int MessageEvent::ReadInteger() -{ - if (FinishedReading()) - { - return -1; - } - - int Value = *(int*)Position; - Position += 4; - return Value; -} - -void MessageEvent::WriteBool(bool Value) -{ - if (bReadMode) - { - return; - } - - BufferSize += sizeof(bool); - EnsureAllocated(); - - *Position++ = Value; -} - -void MessageEvent::WriteInteger(int Value) -{ - if (bReadMode) - { - return; - } - - BufferSize += sizeof(int); - EnsureAllocated(); - - *(int*)Position = Value; - Position += 4; -} - -void MessageEvent::WriteString(const char* Value) -{ - if (bReadMode) - { - return; - } - - size_t length = strlen(Value) + 1; - - BufferSize += length; - EnsureAllocated(); - - for (size_t i = 0; i < length; i++) - { - *Position++ = Value[i]; - } -} - -byte* MessageEvent::GetData() const -{ - return Buffer; -} - -size_t MessageEvent::GetDataSize() const -{ - return BufferSize; -} - -bool MessageEvent::FinishedReading() -{ - return !bReadMode || (Position - Buffer >= BufferSize); -} - -void MessageEvent::EnsureAllocated() -{ - if (!bReadMode && AllocatedSize < BufferSize) - { - AllocatedSize = BufferSize + 20; - - if (Buffer) - { - size_t p = Position - Buffer; - - Buffer = (byte*)realloc(Buffer, AllocatedSize); - Position = Buffer + p; - } - else - { - Buffer = (byte*)malloc(AllocatedSize); - Position = Buffer; - } - } -} - -PipeClass::PipeClass() -{ - m_phSourceReadHandle = NULL; - m_phSourceWriteHandle = NULL; - m_phTargetReadHandle = NULL; - m_phTargetWriteHandle = NULL; - - SECURITY_ATTRIBUTES PipeAttributes; - PipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); - PipeAttributes.bInheritHandle = TRUE; - PipeAttributes.lpSecurityDescriptor = NULL; - - CreatePipe(&m_phSourceReadHandle, &m_phSourceWriteHandle, &PipeAttributes, 65535); - CreatePipe(&m_phTargetReadHandle, &m_phTargetWriteHandle, &PipeAttributes, 65535); - - SetHandleInformation(m_phSourceWriteHandle, HANDLE_FLAG_INHERIT, 1); - SetHandleInformation(m_phTargetReadHandle, HANDLE_FLAG_INHERIT, 1); -} - -PipeClass::PipeClass(void* SourceHandle, void* TargetHandle) -{ - m_phSourceReadHandle = SourceHandle; - m_phTargetWriteHandle = TargetHandle; - - m_phSourceWriteHandle = NULL; - m_phTargetReadHandle = NULL; -} - -PipeClass::~PipeClass() -{ - if (m_phSourceReadHandle) - { - CloseHandle(m_phSourceReadHandle); - } - - if (m_phSourceWriteHandle) - { - CloseHandle(m_phSourceWriteHandle); - } - - if (m_phTargetReadHandle) - { - CloseHandle(m_phTargetReadHandle); - } - - if (m_phTargetWriteHandle) - { - CloseHandle(m_phTargetWriteHandle); - } -} - -/* -void PipeClass::ProcessPipe( bool bWait ) -{ - Container ConEvent = Read( bWait ); - - for( int i = 1; i <= ConEvent.NumObjects(); i++ ) - { - ProcessEvent( ConEvent.ObjectAt( i ) ); - } -} -*/ - -bool PipeClass::IsValid() const -{ - LARGE_INTEGER FileSize; - - return GetFileSizeEx(m_phSourceReadHandle, &FileSize); -} - -bool PipeClass::IsValidForWriting() const -{ - LARGE_INTEGER FileSize; - - return GetFileSizeEx(m_phTargetWriteHandle, &FileSize); -} - -void PipeClass::Read(MessageEvent* Msg, bool bWait) -{ - ReadPipeData(Msg, bWait); -} - -/* -Container PipeClass::Read( bool bWait ) -{ - char *buffer; - const char *com_token; - str sCommand; - Container ConEvent; - - str data = ReadPipeData( bWait ); - - buffer = ( char * )malloc( data.length() + 1 ); - strcpy( buffer, data.c_str() ); - - char *b = buffer; - - while( 1 ) - { - com_token = COM_Parse( &b ); - - if( !com_token || !com_token[ 0 ] ) - { - break; - } - - sCommand = com_token; - - Event *ev = new Event( sCommand ); - - while( 1 ) - { - com_token = COM_GetToken( ( const char ** )&b, false ); - - if( !com_token[ 0 ] ) - break; - - ev->AddString( com_token ); - } - - ConEvent.AddObject( ev ); - } - - free( buffer ); - return ConEvent; -} - -void PipeClass::Send( const str& data ) -{ - WritePipeData( data ); -} -*/ - -void PipeClass::Send(const MessageEvent* Msg) -{ - WritePipeData(Msg); -} - -bool PipeClass::HasData() -{ - LARGE_INTEGER FileSize; - - BOOL bSuccess = GetFileSizeEx(m_phSourceReadHandle, &FileSize); - return bSuccess && FileSize.LowPart; -} - -void* PipeClass::GetSourceNativeHandle() -{ - return m_phSourceWriteHandle; -} - -void* PipeClass::GetTargetNativeHandle() -{ - return m_phTargetReadHandle; -} - -void PipeClass::ReadPipeData(MessageEvent* Msg, bool bWait) -{ - LARGE_INTEGER FileSize; - - BOOL bSuccess = GetFileSizeEx(m_phSourceReadHandle, &FileSize); - if (bSuccess && (FileSize.LowPart || bWait)) - { - DWORD size; - - if (ReadFile(m_phSourceReadHandle, &size, sizeof(DWORD), NULL, NULL)) - { - byte* buffer = Msg->SetReadMode(size); - ReadFile(m_phSourceReadHandle, buffer, size, NULL, NULL); - } - } -} - -void PipeClass::WritePipeData(const MessageEvent* Msg) -{ - DWORD size = (DWORD)Msg->GetDataSize(); - - // Write the size of the message - WriteFile(m_phTargetWriteHandle, &size, sizeof(DWORD), NULL, NULL); - - // Write the message - WriteFile(m_phTargetWriteHandle, Msg->GetData(), size, NULL, NULL); -} diff --git a/code/globalcpp/pipe.h b/code/globalcpp/pipe.h deleted file mode 100644 index dd81194c..00000000 --- a/code/globalcpp/pipe.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include "listener.h" - -class MessageEvent { -private: - byte* Buffer; - size_t AllocatedSize; - size_t BufferSize; - byte* Position; - bool bReadMode; - -public: - MessageEvent(); - MessageEvent(byte* Buffer, size_t Size); - ~MessageEvent(); - - void Reset(); - byte* SetReadMode(size_t Size); - - bool ReadBool(); - int ReadInteger(); - str ReadString(); - byte ReadByte(); - - void WriteBool(bool Value); - void WriteInteger(int Value); - void WriteString(const char* Value); - - byte* GetData() const; - size_t GetDataSize() const; - -private: - bool FinishedReading(); - void EnsureAllocated(); -}; - -class PipeClass { -private: - void *m_phSourceReadHandle; - void *m_phSourceWriteHandle; - void *m_phTargetReadHandle; - void *m_phTargetWriteHandle; - -public: - PipeClass(); - PipeClass(void* SourceHandle, void* TargetHandle); - ~PipeClass(); - - bool IsValid() const; - bool IsValidForWriting() const; - void Read(MessageEvent* Msg, bool bWait = false); - void Send(const MessageEvent* Msg); - bool HasData(); - - void* GetSourceNativeHandle(); - void* GetTargetNativeHandle(); - -private: - void ReadPipeData(MessageEvent* Msg, bool bWait = false ); - void WritePipeData(const MessageEvent* Msg); -}; diff --git a/code/globalcpp/scriptvm.cpp b/code/globalcpp/scriptvm.cpp deleted file mode 100644 index e553b623..00000000 --- a/code/globalcpp/scriptvm.cpp +++ /dev/null @@ -1,2361 +0,0 @@ -/* -=========================================================================== -Copyright (C) 2015 the OpenMoHAA team - -This file is part of OpenMoHAA source code. - -OpenMoHAA source code 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. - -OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -// scriptvm.cpp : Script virtual machine, interprets and execute scripts - -#include "glb_local.h" -#include "scriptmaster.h" -#include "scriptvm.h" -#include "compiler.h" -#include "game.h" -#include "level.h" -#include "parm.h" -#include "world.h" - -#ifdef CGAME_DLL - -#define VM_Printf cgi.Printf -#define VM_DPrintf cgi.DPrintf - -#elif defined GAME_DLL - -#define VM_Printf gi.Printf -#define VM_DPrintf gi.DPrintf2 - -#else - -#define VM_Printf printf -#define VM_DPrintf printf - -#endif - -//==================== -// ScriptClass -//==================== - -MEM_BlockAlloc< ScriptClass, MEM_BLOCKSIZE > ScriptClass_allocator; - -CLASS_DECLARATION( Listener, ScriptClass, NULL ) -{ - { NULL, NULL } -}; - -/* -==================== -new ScriptClass -==================== -*/ -void *ScriptClass::operator new( size_t size ) -{ - return ScriptClass_allocator.Alloc(); -} - -/* -==================== -delete ptr -==================== -*/ -void ScriptClass::operator delete( void *ptr ) -{ - ScriptClass_allocator.Free( ptr ); -} - -/* -==================== -ScriptClass -==================== -*/ -ScriptClass::ScriptClass( GameScript *gameScript, Listener *self ) -{ - m_Self = self; - m_Script = gameScript; - m_Threads = NULL; -} - -/* -==================== -ScriptClass -==================== -*/ -ScriptClass::ScriptClass() -{ - m_Self = NULL; - m_Script = NULL; - m_Threads = NULL; -} - -/* -==================== -~ScriptClass -==================== -*/ -ScriptClass::~ScriptClass() -{ - if( m_Script == NULL ) { - ScriptError( "Attempting to delete dead class." ); - } - - KillThreads(); - - if( !m_Script->m_Filename ) - { - // This is a temporary gamescript - delete m_Script; - } -} - -/* -==================== -Archive -==================== -*/ -void ScriptClass::Archive( Archiver& arc ) -{ -} - -/* -==================== -ArchiveInternal -==================== -*/ -void ScriptClass::ArchiveInternal( Archiver& arc ) -{ - Listener::Archive( arc ); - - arc.ArchiveObjectPosition( this ); - arc.ArchiveSafePointer( &m_Self ); - GameScript::Archive( arc, m_Script ); -} - -/* -==================== -ArchiveScript -==================== -*/ -void ScriptClass::ArchiveScript( Archiver& arc, ScriptClass **obj ) -{ - ScriptClass *scr; - ScriptVM *m_current; - ScriptThread *m_thread; - int num; - int i; - - if( arc.Saving() ) - { - scr = *obj; - scr->ArchiveInternal( arc ); - - num = 0; - for( m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next ) - num++; - - arc.ArchiveInteger( &num ); - - for( m_current = scr->m_Threads; m_current != NULL; m_current = m_current->next ) - m_current->m_Thread->ArchiveInternal( arc ); - } - else - { - scr = new ScriptClass(); - scr->ArchiveInternal( arc ); - - arc.ArchiveInteger( &num ); - - for( i = 0; i < num; i++ ) - { - m_thread = new ScriptThread( scr, NULL ); - m_thread->ArchiveInternal( arc ); - } - - *obj = scr; - } -} - -/* -==================== -ArchiveCodePos -==================== -*/ -void ScriptClass::ArchiveCodePos( Archiver& arc, unsigned char **codePos ) -{ - m_Script->ArchiveCodePos( arc, codePos ); -} - -/* -==================== -CreateThreadInternal -==================== -*/ -ScriptThread *ScriptClass::CreateThreadInternal( const ScriptVariable& label ) -{ - GameScript *scr; - ScriptThread *thread = NULL; - - if( label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING ) - { - ScriptClass *scriptClass = Director.CurrentScriptClass(); - scr = scriptClass->GetScript(); - - if( label.GetType() == VARIABLE_CONSTSTRING ) - thread = Director.CreateScriptThread( scr, m_Self, label.constStringValue() ); - else - thread = Director.CreateScriptThread( scr, m_Self, label.stringValue() ); - } - else if( label.GetType() == VARIABLE_CONSTARRAY && label.arraysize() > 1 ) - { - ScriptVariable *script = label[ 1 ]; - ScriptVariable *labelname = label[ 2 ]; - - if( script->GetType() == VARIABLE_CONSTSTRING ) - scr = Director.GetGameScript( script->constStringValue() ); - else - scr = Director.GetGameScript( script->stringValue() ); - - if( labelname->GetType() == VARIABLE_CONSTSTRING ) - thread = Director.CreateScriptThread( scr, m_Self, labelname->constStringValue() ); - else - thread = Director.CreateScriptThread( scr, m_Self, labelname->stringValue() ); - } - else - { - ScriptError( "ScriptClass::CreateThreadInternal: bad argument format" ); - } - - return thread; -} - -/* -==================== -CreateScriptInternal -==================== -*/ -ScriptThread *ScriptClass::CreateScriptInternal( const ScriptVariable& label ) -{ - GameScript *scr; - ScriptThread *thread = NULL; - - if( label.GetType() == VARIABLE_STRING || label.GetType() == VARIABLE_CONSTSTRING ) - { - if( label.GetType() == VARIABLE_CONSTSTRING ) - thread = Director.CreateScriptThread( Director.GetGameScript( label.stringValue() ), m_Self, "" ); - else - thread = Director.CreateScriptThread( Director.GetGameScript( label.constStringValue() ), m_Self, "" ); - } - else if( label.GetType() == VARIABLE_CONSTARRAY && label.arraysize() > 1 ) - { - ScriptVariable *script = label[ 1 ]; - ScriptVariable *labelname = label[ 2 ]; - - if( script->GetType() == VARIABLE_CONSTSTRING ) - scr = Director.GetGameScript( script->constStringValue() ); - else - scr = Director.GetGameScript( script->stringValue() ); - - if( labelname->GetType() == VARIABLE_CONSTSTRING ) - thread = Director.CreateScriptThread( scr, m_Self, labelname->constStringValue() ); - else - thread = Director.CreateScriptThread( scr, m_Self, labelname->stringValue() ); - } - else - { - ScriptError( "ScriptClass::CreateScriptInternal: bad label type '%s'", label.GetTypeName() ); - } - - return thread; -} - -/* -==================== -AddThread -==================== -*/ -void ScriptClass::AddThread( ScriptVM *m_ScriptVM ) -{ - m_ScriptVM->next = m_Threads; - m_Threads = m_ScriptVM; -} - -/* -==================== -KillThreads -==================== -*/ -void ScriptClass::KillThreads() -{ - if( !m_Threads ) { - return; - } - - ScriptVM *m_current; - ScriptVM *m_next; - - m_current = m_Threads; - - do - { - m_current->m_ScriptClass = NULL; - - m_next = m_current->next; - delete m_current->m_Thread; - - } while( m_current = m_next ); - - m_Threads = NULL; -} - -/* -==================== -RemoveThread -==================== -*/ -void ScriptClass::RemoveThread( ScriptVM *m_ScriptVM ) -{ - if( m_Threads == m_ScriptVM ) - { - m_Threads = m_ScriptVM->next; - - if( m_Threads == NULL ) { - delete this; - } - } - else - { - ScriptVM *m_current = m_Threads; - ScriptVM *i; - - for( i = m_Threads->next; i != m_ScriptVM; i = i->next ) { - m_current = i; - } - - m_current->next = i->next; - } -} - -/* -==================== -Filename -==================== -*/ -str ScriptClass::Filename() -{ - return m_Script->Filename(); -} - -/* -==================== -FindLabel -==================== -*/ -unsigned char *ScriptClass::FindLabel( str label ) -{ - return m_Script->m_State.FindLabel( label ); -} - -/* -==================== -FindLabel -==================== -*/ -unsigned char *ScriptClass::FindLabel( const_str label ) -{ - return m_Script->m_State.FindLabel( label ); -} - -/* -==================== -NearestLabel -==================== -*/ -const_str ScriptClass::NearestLabel( unsigned char *pos ) -{ - return m_Script->m_State.NearestLabel( pos ); -} - -/* -==================== -GetCatchStateScript -==================== -*/ -StateScript *ScriptClass::GetCatchStateScript( unsigned char *in, unsigned char *&out ) -{ - return m_Script->GetCatchStateScript( in, out ); -} - -/* -==================== -GetScript -==================== -*/ -GameScript *ScriptClass::GetScript() -{ - return m_Script; -} - -/* -==================== -GetSelf -==================== -*/ -Listener *ScriptClass::GetSelf() -{ - return static_cast< Listener * >( m_Self.Pointer() ); -} - -//==================== -// ScriptVM -//==================== - - -MEM_BlockAlloc< ScriptVM, char[ 256 ] > ScriptVM_allocator; - -/* -==================== -new ScriptVM -==================== -*/ -void *ScriptVM::operator new( size_t size ) -{ - return ScriptVM_allocator.Alloc(); -} - -/* -==================== -delete ptr -==================== -*/ -void ScriptVM::operator delete( void *ptr ) -{ - ScriptVM_allocator.Free( ptr ); -} - -/* -==================== -ScriptVM -==================== -*/ -ScriptVM::ScriptVM( ScriptClass *scriptClass, unsigned char *pCodePos, ScriptThread *thread ) -{ - next = NULL; - - m_Thread = thread; - m_ScriptClass = scriptClass; - - m_Stack = NULL; - - m_PrevCodePos = NULL; - m_CodePos = pCodePos; - - state = STATE_RUNNING; - m_ThreadState = THREAD_RUNNING; - - m_pOldData = NULL; - m_OldDataSize = 0; - - m_bMarkStack = false; - m_StackPos = NULL; - - m_bAllowContextSwitch = true; - - localStackSize = m_ScriptClass->GetScript()->GetRequiredStackSize(); - - if( localStackSize <= 0 ) { - localStackSize = 1; - } - - localStack = new ScriptVariable[ localStackSize ]; - - pTop = localStack; - - m_ScriptClass->AddThread( this ); -} - -/* -==================== -~ScriptVM -==================== -*/ -ScriptVM::~ScriptVM() -{ - fastEvent.data = m_pOldData; - fastEvent.dataSize = m_OldDataSize; - - // clean-up the call stack - while( callStack.NumObjects() ) - { - LeaveFunction(); - } - - delete[] localStack; -} - -/* -==================== -Archive -==================== -*/ -void ScriptVM::Archive( Archiver& arc ) -{ - int stack = 0; - - if( arc.Saving() ) - { - if( m_Stack ) - stack = m_Stack->m_Count; - - arc.ArchiveInteger( &stack ); - } - else - { - arc.ArchiveInteger( &stack ); - - if( stack ) - { - m_Stack = new ScriptStack; - m_Stack->m_Array = new ScriptVariable[ stack ]; - m_Stack->m_Count = stack; - } - } - - for( int i = 1; i <= stack; i++ ) - { - m_Stack->m_Array[ i ].ArchiveInternal( arc ); - } - - m_ReturnValue.ArchiveInternal( arc ); - m_ScriptClass->ArchiveCodePos( arc, &m_PrevCodePos ); - m_ScriptClass->ArchiveCodePos( arc, &m_CodePos ); - arc.ArchiveByte( &state ); - arc.ArchiveByte( &m_ThreadState ); -} - -/* -==================== -error - -Triggers an error -==================== -*/ -void ScriptVM::error( const char *format, ... ) -{ - char buffer[ 4000 ]; - va_list va; - - va_start( va, format ); - vsprintf( buffer, format, va ); - va_end( va ); - - glbs.Printf( "----------------------------------------------------------\n%s\n", buffer ); - m_ReturnValue.setStringValue( "$.INTERRUPTED" ); -} - -/* -==================== -executeCommand -==================== -*/ -void ScriptVM::executeCommand( Listener *listener, int iParamCount, int eventnum, bool bReturn ) -{ - Event ev; - ScriptVariable *var; - - ev = Event( eventnum ); - - if( bReturn ) - { - var = pTop; - } - else - { - var = pTop + 1; - } - - ev.dataSize = iParamCount; - ev.data = new ScriptVariable[ ev.dataSize ]; - ev.fromScript = true; - - for( int i = 0; i < iParamCount; i++ ) { - ev.data[ i ] = var[ i ]; - } - - listener->ProcessScriptEvent( ev ); - - if( ev.NumArgs() > iParamCount ) { - *pTop = ev.GetValue( ev.NumArgs() ); - } else { - pTop->Clear(); - } -} - -/* -==================== -executeGetter -==================== -*/ -bool ScriptVM::executeGetter( Listener *listener, str& name ) -{ - Event ev; - int eventnum = Event::FindGetterEventNum( name ); - - if( eventnum && listener->classinfo()->GetDef( eventnum ) ) - { - ev = Event( eventnum ); - ev.fromScript = true; - - if( listener->ProcessScriptEvent( ev ) ) - { - - if( ev.NumArgs() > 0 ) { - *pTop = ev.GetValue( ev.NumArgs() ); - } else { - pTop->Clear(); - } - - return true; - } - else - { - return false; - } - } - else - { - eventnum = Event::FindSetterEventNum( name ); - assert( !eventnum || !listener->classinfo()->GetDef( eventnum ) ); - if( eventnum && listener->classinfo()->GetDef( eventnum ) ) - { - ScriptError( "Cannot get a write-only variable" ); - } - } - - return false; -} - -/* -==================== -executeSetter -==================== -*/ -bool ScriptVM::executeSetter( Listener *listener, str& name ) -{ - Event ev; - int eventnum = Event::FindSetterEventNum( name ); - - if( eventnum && listener->classinfo()->GetDef( eventnum ) ) - { - ev = Event( eventnum ); - ev.fromScript = true; - - ev.AddValue( *pTop ); - - if( listener->ProcessScriptEvent( ev ) ) - { - return true; - } - else - { - return false; - } - } - else - { - eventnum = Event::FindGetterEventNum( name ); - if( eventnum && listener->classinfo()->GetDef( eventnum ) ) - { - ScriptError( "Cannot set a read-only variable" ); - } - } - - return false; -} - -/* -==================== -jump -==================== -*/ -void ScriptVM::jump( int offset ) -{ - m_CodePos += offset; -} - -/* -==================== -jumpBool -==================== -*/ -void ScriptVM::jumpBool( int offset, bool booleanValue ) -{ - if( booleanValue ) - { - jump( offset ); - } - else - { - m_CodePos += sizeof( unsigned int ); - } -} - -/* -==================== -loadTop -==================== -*/ -void ScriptVM::loadTop( Listener *listener, bool noTop ) -{ - int index; - - index = *reinterpret_cast< int * >( m_CodePos ); - m_CodePos += sizeof( unsigned int ); - - if( index != -1 ) - { - str& variable = Director.GetString( index ); - - if( !executeSetter( listener, variable ) ) - { - listener->Vars()->SetVariable( variable, *pTop ); - } - } - - if( !noTop ) { - pTop--; - } -} - -/* -==================== -storeTop -==================== -*/ -void ScriptVM::storeTop( Listener *listener, bool noTop ) -{ - str variable; - int index; - - index = *reinterpret_cast< int * >( m_CodePos ); - m_CodePos += sizeof( unsigned int ); - - if( index != -1 ) - { - variable = Director.GetString( index ); - } - - if( !noTop ) { - pTop++; - } - - if( index != -1 && !executeGetter( listener, variable ) ) - { - *pTop = *listener->Vars()->GetOrCreateVariable( index ); - } -} - -/* -==================== -ProgBuffer - -Returns the current program buffer -==================== -*/ -unsigned char *ScriptVM::ProgBuffer( void ) -{ - return m_CodePos; -} - -/* -==================== -EnterFunction - -Sets a new instruction pointer -==================== -*/ -void ScriptVM::EnterFunction( Event *ev ) -{ - ScriptCallStack *stack; - str label = ev->GetString( 1 ); - - SetFastData( ev->data + 1, ev->dataSize - 1 ); - - unsigned char *codePos = m_ScriptClass->FindLabel( label ); - - if( !codePos ) - { - ScriptError( "ScriptVM::EnterFunction: label '%s' does not exist in '%s'.", label.c_str(), Filename().c_str() ); - } - - stack = new ScriptCallStack; - - stack->codePos = m_CodePos; - - stack->pTop = pTop; - stack->returnValue = m_ReturnValue; - stack->localStack = localStack; - stack->m_Self = m_ScriptClass->GetSelf(); - - callStack.AddObject( stack ); - - m_CodePos = codePos; - - localStack = new ScriptVariable[ localStackSize ]; - - pTop = localStack; - m_ReturnValue.Clear(); -} - -/* -==================== -LeaveFunction - -Returns to the previous function -==================== -*/ -void ScriptVM::LeaveFunction() -{ - int num = callStack.NumObjects(); - - if( num ) - { - ScriptCallStack *stack = callStack.ObjectAt( num ); - - pTop = stack->pTop; - *pTop = m_ReturnValue; - - m_CodePos = stack->codePos; - m_ReturnValue = stack->returnValue; - m_ScriptClass->m_Self = stack->m_Self; - - delete[] localStack; - - localStack = stack->localStack; - - delete stack; - - callStack.RemoveObjectAt( num ); - } - else - { - delete m_Thread; - } -} - -/* -==================== -End - -End with a return value -==================== -*/ -void ScriptVM::End( const ScriptVariable& returnValue ) -{ - m_ReturnValue.setPointer( returnValue ); - - LeaveFunction(); -} - -/* -==================== -End -==================== -*/ -void ScriptVM::End() -{ - m_ReturnValue.ClearPointer(); - - LeaveFunction(); -} - -/* -==================== -Execute - -Executes a program -==================== -*/ -void ScriptVM::Execute( ScriptVariable *data, int dataSize, str label ) -{ - unsigned char *opcode; - bool doneProcessing = false; - bool deleteThread = false; - bool eventCalled = false; - - ScriptVariable *a; - ScriptVariable *b; - ScriptVariable *c; - - int index, iParamCount; - - Listener *listener; - - Event ev; - Event *ev2; - ScriptVariable *var = NULL; - - static str str_null = ""; - str& value = str_null; - - ConSimple *targetList; - - if( label != "" ) - { - // Throw if label is not found - if( !( m_CodePos = m_ScriptClass->FindLabel( label ) ) ) - { - ScriptError( "ScriptVM::Execute: label '%s' does not exist in '%s'.", label.c_str(), Filename().c_str() ); - } - } - - if( Director.stackCount >= MAX_STACK_DEPTH ) - { - state = STATE_EXECUTION; - - ScriptException::next_abort = -1; - ScriptException exc( "stack overflow" ); - - throw exc; - } - - Director.stackCount++; - - if( dataSize ) - { - SetFastData( data, dataSize ); - } - - state = STATE_RUNNING; - - Director.cmdTime = glbs.Milliseconds(); - Director.cmdCount = 0; - - while( !doneProcessing && state == STATE_RUNNING ) - { - m_PrevCodePos = m_CodePos; - - Director.cmdCount++; - - try - { - if( !Director.m_bAllowContextSwitch ) - { - if( Director.cmdCount > 9999 && glbs.Milliseconds() - Director.cmdTime > Director.maxTime ) - { - if( level.m_LoopProtection ) - { - Director.cmdTime = glbs.Milliseconds(); - - deleteThread = true; - state = STATE_EXECUTION; - - if( level.m_LoopDrop ) { - ScriptException::next_abort = -1; - } - - ScriptError( "Command overflow. Possible infinite loop in thread.\n" ); - } - - VM_DPrintf( "Update of script position - This is not an error.\n" ); - VM_DPrintf( "=================================================\n" ); - m_ScriptClass->GetScript()->PrintSourcePos( opcode, true ); - VM_DPrintf( "=================================================\n" ); - - Director.cmdCount = 0; - } - } - else - { - if( glbs.Milliseconds() - Director.cmdTime > Director.maxTime ) - { - // Request a context switch - RequestContextSwitch(); - } - } - - if( !m_bMarkStack ) - { - assert( pTop >= localStack && pTop < localStack + localStackSize ); - if( pTop < localStack ) - { - deleteThread = true; - state = STATE_EXECUTION; - - error( "VM stack error. Negative stack value %d.\n", pTop - localStack ); - break; - } - else if( pTop >= localStack + localStackSize ) - { - deleteThread = true; - state = STATE_EXECUTION; - - error( "VM stack error. Exceeded the maximum stack size %d.\n", localStackSize ); - break; - } - } - - index = 0; - eventCalled = false; - - opcode = m_CodePos++; - switch( *opcode ) - { - case OP_BIN_BITWISE_AND: - a = pTop--; - b = pTop; - - *b &= *a; - break; - - case OP_BIN_BITWISE_OR: - a = pTop--; - b = pTop; - - *b |= *a; - break; - - case OP_BIN_BITWISE_EXCL_OR: - a = pTop--; - b = pTop; - - *b ^= *a; - break; - - case OP_BIN_EQUALITY: - a = pTop--; - b = pTop; - - b->setIntValue( *b == *a ); - break; - - case OP_BIN_INEQUALITY: - a = pTop--; - b = pTop; - - b->setIntValue( *b != *a ); - break; - - case OP_BIN_GREATER_THAN: - a = pTop--; - b = pTop; - - b->greaterthan( *a ); - break; - - case OP_BIN_GREATER_THAN_OR_EQUAL: - a = pTop--; - b = pTop; - - b->greaterthanorequal( *a ); - break; - - case OP_BIN_LESS_THAN: - a = pTop--; - b = pTop; - - b->lessthan( *a ); - break; - - case OP_BIN_LESS_THAN_OR_EQUAL: - a = pTop--; - b = pTop; - - b->lessthanorequal( *a ); - break; - - case OP_BIN_PLUS: - a = pTop--; - b = pTop; - - *b += *a; - break; - - case OP_BIN_MINUS: - a = pTop--; - b = pTop; - - *b -= *a; - break; - - case OP_BIN_MULTIPLY: - a = pTop--; - b = pTop; - - *b *= *a; - break; - - case OP_BIN_DIVIDE: - a = pTop--; - b = pTop; - - *b /= *a; - break; - - case OP_BIN_PERCENTAGE: - a = pTop--; - b = pTop; - - *b %= *a; - break; - - case OP_BIN_SHIFT_LEFT: - a = pTop--; - b = pTop; - - *b <<= *a; - break; - - case OP_BIN_SHIFT_RIGHT: - a = pTop--; - b = pTop; - - *b >>= *a; - break; - - case OP_BOOL_JUMP_FALSE4: - jumpBool( *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ), !pTop->m_data.intValue ); - - pTop--; - - break; - - case OP_BOOL_JUMP_TRUE4: - jumpBool( *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ), pTop->m_data.intValue ? true : false ); - - pTop--; - - break; - - case OP_VAR_JUMP_FALSE4: - jumpBool( *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ), !pTop->booleanValue() ); - - pTop--; - - break; - - case OP_VAR_JUMP_TRUE4: - jumpBool( *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ), pTop->booleanValue() ); - - pTop--; - - break; - - case OP_BOOL_LOGICAL_AND: - if( pTop->m_data.intValue ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - } - else - { - m_CodePos += *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ); - } - - break; - - case OP_BOOL_LOGICAL_OR: - if( !pTop->m_data.intValue ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - } - else - { - m_CodePos += *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ); - } - - break; - - case OP_VAR_LOGICAL_AND: - if( pTop->booleanValue() ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - } - else - { - pTop->SetFalse(); - m_CodePos += *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ); - } - break; - - case OP_VAR_LOGICAL_OR: - if( !pTop->booleanValue() ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - } - else - { - pTop->SetTrue(); - m_CodePos += *reinterpret_cast< unsigned int * >( m_CodePos ) + sizeof( unsigned int ); - } - break; - - case OP_BOOL_STORE_FALSE: - pTop++; - pTop->SetFalse(); - break; - - case OP_BOOL_STORE_TRUE: - pTop++; - pTop->SetTrue(); - break; - - case OP_BOOL_UN_NOT: - pTop->m_data.intValue = ( pTop->m_data.intValue == 0 ); - break; - - case OP_CALC_VECTOR: - c = pTop--; - b = pTop--; - a = pTop; - - pTop->setVectorValue( Vector( a->floatValue(), b->floatValue(), c->floatValue() ) ); - break; - - case OP_EXEC_CMD0: - iParamCount = 0; - goto __execCmd; - - case OP_EXEC_CMD1: - iParamCount = 1; - goto __execCmd; - - case OP_EXEC_CMD2: - iParamCount = 2; - goto __execCmd; - - case OP_EXEC_CMD3: - iParamCount = 3; - goto __execCmd; - - case OP_EXEC_CMD4: - iParamCount = 4; - goto __execCmd; - - case OP_EXEC_CMD5: - iParamCount = 5; - goto __execCmd; - - case OP_EXEC_CMD_COUNT1: - iParamCount = *m_CodePos++; - -__execCmd: - index = *reinterpret_cast< unsigned int * >( m_CodePos ); - - m_CodePos += sizeof( unsigned int ); - - pTop -= iParamCount; - - try - { - executeCommand( m_Thread, iParamCount, index ); - } - catch( ScriptException& exc ) - { - throw exc; - } - - break; - - case OP_EXEC_CMD_METHOD0: - iParamCount = 0; - goto __execCmdMethod; - - case OP_EXEC_CMD_METHOD1: - iParamCount = 1; - goto __execCmdMethod; - - case OP_EXEC_CMD_METHOD2: - iParamCount = 2; - goto __execCmdMethod; - - case OP_EXEC_CMD_METHOD3: - iParamCount = 3; - goto __execCmdMethod; - - case OP_EXEC_CMD_METHOD4: - iParamCount = 4; - goto __execCmdMethod; - - case OP_EXEC_CMD_METHOD5: - iParamCount = 5; - goto __execCmdMethod; - -__execCmdMethod: - m_CodePos--; - goto __execCmdMethodInternal; - - case OP_EXEC_CMD_METHOD_COUNT1: - iParamCount = *m_CodePos; - -__execCmdMethodInternal: - a = pTop--; - - try - { - index = *reinterpret_cast< unsigned int * >( m_CodePos + sizeof( byte ) ); - - pTop -= iParamCount; - - if( a->arraysize() < 0 ) - { - ScriptError( "command '%s' applied to NIL", Event::GetEventName( index ).c_str() ); - } - - ScriptVariable array = *a; - Listener *listener; - - array.CastConstArrayValue(); - - for( int i = array.arraysize(); i > 0; i-- ) - { - if( !( listener = array[ i ]->listenerValue() ) ) - { - ScriptError( "command '%s' applied to NULL listener", Event::GetEventName( index ).c_str() ); - } - - executeCommand( listener, iParamCount, index ); - } - } - catch( ScriptException& exc ) - { - m_CodePos += sizeof( byte ) + sizeof( unsigned int ); - - throw exc; - } - - m_CodePos += sizeof( byte ) + sizeof( unsigned int ); - - break; - - case OP_EXEC_METHOD0: - iParamCount = 0; - goto __execMethod; - - case OP_EXEC_METHOD1: - iParamCount = 1; - goto __execMethod; - - case OP_EXEC_METHOD2: - iParamCount = 2; - goto __execMethod; - - case OP_EXEC_METHOD3: - iParamCount = 3; - goto __execMethod; - - case OP_EXEC_METHOD4: - iParamCount = 4; - goto __execMethod; - - case OP_EXEC_METHOD5: - iParamCount = 5; - -__execMethod: - m_CodePos--; - goto __execMethodInternal; - - case OP_EXEC_METHOD_COUNT1: - iParamCount = *m_CodePos; - -__execMethodInternal: - a = pTop--; - - try - { - index = *reinterpret_cast< unsigned int * >( m_CodePos + sizeof( byte ) ); - - pTop -= iParamCount; - pTop++; // push the return value - - Listener *listener = a->listenerValue(); - - if( !listener ) - { - ScriptError( "command '%s' applied to NULL listener", Event::GetEventName( index ).c_str() ); - } - - executeCommand( listener, iParamCount, index, true ); - } - catch( ScriptException& exc ) - { - m_CodePos += sizeof( byte ) + sizeof( unsigned int ); - - throw exc; - } - - m_CodePos += sizeof( byte ) + sizeof( unsigned int ); - - break; - - case OP_FUNC: - ev.Clear(); - - if( !*m_CodePos++ ) - { - str& label = Director.GetString( *reinterpret_cast< unsigned int * >( m_CodePos ) ); - - m_CodePos += sizeof( unsigned int ); - - try - { - listener = pTop->listenerValue(); - - if( !listener ) - { - ScriptError( "function '%s' applied to NULL listener", label.c_str() ); - } - } - catch( ScriptException& exc ) - { - pTop -= *m_CodePos++; - - throw exc; - } - - pTop--; - - ev.AddString( label ); - - int params = *m_CodePos++; - - var = pTop; - pTop -= params; - - for( int i = 0; i < params; var++, i++ ) { - ev.AddValue( *var ); - } - - pTop++; - EnterFunction( &ev ); - - m_ScriptClass->m_Self = listener; - } - else - { - str filename, label; - - filename = Director.GetString( *reinterpret_cast< unsigned int * >( m_CodePos ) ); - m_CodePos += sizeof( unsigned int ); - label = Director.GetString( *reinterpret_cast< unsigned int * >( m_CodePos ) ); - m_CodePos += sizeof( unsigned int ); - - try - { - listener = pTop->listenerValue(); - - if( !listener ) - { - ScriptError( "function '%s' in '%s' applied to NULL listener", label.c_str(), filename.c_str() ); - } - } - catch( ScriptException& exc ) - { - pTop -= *m_CodePos++; - - throw exc; - } - - pTop--; - - ScriptVariable constarray; - ScriptVariable *pVar = new ScriptVariable[ 2 ]; - - pVar[ 0 ].setStringValue( filename ); - pVar[ 1 ].setStringValue( label ); - - constarray.setConstArrayValue( pVar, 2 ); - - delete[] pVar; - - ev2 = new Event( EV_Listener_WaitCreateReturnThread ); - ev2->AddValue( constarray ); - - int params = *m_CodePos++; - - var = pTop; - pTop -= params; - - for( int i = 0; i < params; var++, i++ ) { - ev2->AddValue( *var ); - } - - pTop++; - *pTop = listener->ProcessEventReturn( ev2 ); - } - break; - - case OP_JUMP4: - m_CodePos += *reinterpret_cast< int * >( m_CodePos ) + sizeof( unsigned int ); - break; - - case OP_JUMP_BACK4: - m_CodePos -= *reinterpret_cast< int * >( m_CodePos ); - break; - - case OP_LOAD_ARRAY_VAR: - a = pTop--; - b = pTop--; - c = pTop--; - - b->setArrayAt( *a, *c ); - break; - - case OP_LOAD_FIELD_VAR: - a = pTop--; - - try - { - listener = a->listenerValue(); - - if( listener == NULL ) - { - value = Director.GetString( *reinterpret_cast< int * >( m_CodePos ) ); - ScriptError( "Field '%s' applied to NULL listener", value.c_str() ); - } - else - { - eventCalled = true; - loadTop( listener ); - } - } - catch( ScriptException& exc ) - { - pTop--; - - if( !eventCalled ) { - m_CodePos += sizeof( unsigned int ); - } - - throw exc; - } - - break; - - case OP_LOAD_CONST_ARRAY1: - index = *reinterpret_cast< short * >( m_CodePos ); - m_CodePos += sizeof( short ); - - pTop -= index - 1; - pTop->setConstArrayValue( pTop, index ); - break; - - case OP_LOAD_GAME_VAR: - loadTop( &game ); - break; - - case OP_LOAD_GROUP_VAR: - loadTop( m_ScriptClass ); - break; - - case OP_LOAD_LEVEL_VAR: - loadTop( &level ); - break; - - case OP_LOAD_LOCAL_VAR: - loadTop( m_Thread ); - break; - - case OP_LOAD_OWNER_VAR: - if( !m_ScriptClass->m_Self ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - ScriptError( "self is NULL" ); - } - - if( !m_ScriptClass->m_Self->GetScriptOwner() ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - ScriptError( "self.owner is NULL" ); - } - - loadTop( m_ScriptClass->m_Self->GetScriptOwner() ); - break; - - case OP_LOAD_PARM_VAR: - loadTop( &parm ); - break; - - case OP_LOAD_SELF_VAR: - if( !m_ScriptClass->m_Self ) - { - pTop--; - m_CodePos += sizeof( unsigned int ); - ScriptError( "self is NULL" ); - } - - loadTop( m_ScriptClass->m_Self ); - break; - - case OP_LOAD_STORE_GAME_VAR: - loadTop( &game, true ); - break; - - case OP_LOAD_STORE_GROUP_VAR: - loadTop( m_ScriptClass, true ); - break; - - case OP_LOAD_STORE_LEVEL_VAR: - loadTop( &level, true ); - break; - - case OP_LOAD_STORE_LOCAL_VAR: - loadTop( m_Thread, true ); - break; - - case OP_LOAD_STORE_OWNER_VAR: - if( !m_ScriptClass->m_Self ) - { - m_CodePos += sizeof( unsigned int ); - ScriptError( "self is NULL" ); - } - - if( !m_ScriptClass->m_Self->GetScriptOwner() ) - { - m_CodePos += sizeof( unsigned int ); - ScriptError( "self.owner is NULL" ); - } - - loadTop( m_ScriptClass->m_Self->GetScriptOwner(), true ); - break; - - case OP_LOAD_STORE_PARM_VAR: - loadTop( &parm, true ); - break; - - case OP_LOAD_STORE_SELF_VAR: - if( !m_ScriptClass->m_Self ) - { - ScriptError( "self is NULL" ); - } - - loadTop( m_ScriptClass->m_Self, true ); - break; - - case OP_MARK_STACK_POS: - m_StackPos = pTop; - m_bMarkStack = true; - break; - - case OP_STORE_PARAM: - if( fastEvent.dataSize ) - { - pTop = fastEvent.data++; - fastEvent.dataSize--; - } - else - { - pTop = m_StackPos + 1; - pTop->Clear(); - } - break; - - case OP_RESTORE_STACK_POS: - pTop = m_StackPos; - m_bMarkStack = false; - break; - - case OP_STORE_ARRAY: - pTop--; - pTop->evalArrayAt( *( pTop + 1 ) ); - break; - - case OP_STORE_ARRAY_REF: - pTop--; - pTop->setArrayRefValue( *( pTop + 1 ) ); - break; - - case OP_STORE_FIELD_REF: - case OP_STORE_FIELD: - try - { - value = Director.GetString( *reinterpret_cast< int * >( m_CodePos ) ); - - listener = pTop->listenerValue(); - - if( listener == NULL ) - { - ScriptError( "Field '%s' applied to NULL listener", value.c_str() ); - } - else - { - eventCalled = true; - storeTop( listener, true ); - } - - if( *opcode == OP_STORE_FIELD_REF ) - { - pTop->setRefValue( listener->vars->GetOrCreateVariable( value ) ); - } - } - catch( ScriptException& exc ) - { - if( *opcode == OP_STORE_FIELD_REF ) - { - pTop->setRefValue( pTop ); - } - - if( !eventCalled ) { - m_CodePos += sizeof( unsigned int ); - } - - throw exc; - } - break; - - case OP_STORE_FLOAT: - pTop++; - pTop->setFloatValue( *reinterpret_cast< float * >( m_CodePos ) ); - - m_CodePos += sizeof( float ); - - break; - - case OP_STORE_INT0: - pTop++; - pTop->setIntValue( 0 ); - - break; - - case OP_STORE_INT1: - pTop++; - pTop->setIntValue( *m_CodePos++ ); - - break; - - case OP_STORE_INT2: - pTop++; - pTop->setIntValue( *reinterpret_cast< short * >( m_CodePos ) ); - - m_CodePos += sizeof( short ); - - break; - - case OP_STORE_INT3: - pTop++; - pTop->setIntValue( *reinterpret_cast< short3 * >( m_CodePos ) ); - - m_CodePos += sizeof( short3 ); - break; - - case OP_STORE_INT4: - pTop++; - pTop->setIntValue( *reinterpret_cast< int * >( m_CodePos ) ); - - m_CodePos += sizeof( int ); - - break; - - case OP_STORE_GAME_VAR: - storeTop( &game ); - break; - - case OP_STORE_GROUP_VAR: - storeTop( m_ScriptClass ); - break; - - case OP_STORE_LEVEL_VAR: - storeTop( &level ); - break; - - case OP_STORE_LOCAL_VAR: - storeTop( m_Thread ); - break; - - case OP_STORE_OWNER_VAR: - if( !m_ScriptClass->m_Self ) - { - pTop++; - m_CodePos += sizeof( unsigned int ); - ScriptError( "self is NULL" ); - } - - if( !m_ScriptClass->m_Self->GetScriptOwner() ) - { - pTop++; - m_CodePos += sizeof( unsigned int ); - ScriptError( "self.owner is NULL" ); - } - - storeTop( m_ScriptClass->m_Self->GetScriptOwner() ); - break; - - case OP_STORE_PARM_VAR: - storeTop( &parm ); - break; - - case OP_STORE_SELF_VAR: - if( !m_ScriptClass->m_Self ) - { - pTop++; - m_CodePos += sizeof( unsigned int ); - ScriptError( "self is NULL" ); - } - - storeTop( m_ScriptClass->m_Self ); - break; - - case OP_STORE_GAME: - pTop++; - pTop->setListenerValue( &game ); - break; - - case OP_STORE_GROUP: - pTop++; - pTop->setListenerValue( m_ScriptClass ); - break; - - case OP_STORE_LEVEL: - pTop++; - pTop->setListenerValue( &level ); - break; - - case OP_STORE_LOCAL: - pTop++; - pTop->setListenerValue( m_Thread ); - break; - - case OP_STORE_OWNER: - pTop++; - - if( !m_ScriptClass->m_Self ) - { - pTop++; - ScriptError( "self is NULL" ); - } - - pTop->setListenerValue( m_ScriptClass->m_Self->GetScriptOwner() ); - break; - - case OP_STORE_PARM: - pTop++; - pTop->setListenerValue( &parm ); - break; - - case OP_STORE_SELF: - pTop++; - pTop->setListenerValue( m_ScriptClass->m_Self ); - break; - - case OP_STORE_NIL: - pTop++; - pTop->Clear(); - break; - - case OP_STORE_NULL: - pTop++; - pTop->setListenerValue( NULL ); - break; - - case OP_STORE_STRING: - pTop++; - pTop->setConstStringValue( *reinterpret_cast< unsigned int * >( m_CodePos ) ); - - m_CodePos += sizeof( unsigned int ); - - break; - - case OP_STORE_VECTOR: - pTop++; - pTop->setVectorValue( *reinterpret_cast< Vector * >( m_CodePos ) ); - - m_CodePos += sizeof( Vector ); - - break; - - case OP_SWITCH: - if( !Switch( *reinterpret_cast< StateScript ** >( m_CodePos ), *pTop ) ) - { - m_CodePos += sizeof( unsigned int ); - } - - pTop--; - break; - - case OP_UN_CAST_BOOLEAN: - pTop->CastBoolean(); - break; - - case OP_UN_COMPLEMENT: - pTop->complement(); - break; - - case OP_UN_MINUS: - pTop->minus(); - break; - - case OP_UN_DEC: - ( *pTop )--; - break; - - case OP_UN_INC: - ( *pTop )++; - break; - - case OP_UN_SIZE: - pTop->setIntValue( ( int )pTop->size() ); - break; - - case OP_UN_TARGETNAME: - targetList = world->GetExistingTargetList( pTop->stringValue() ); - - if( !targetList ) - { - value = pTop->stringValue(); - - pTop->setListenerValue( NULL ); - - if( *m_CodePos >= OP_BIN_EQUALITY && *m_CodePos <= OP_BIN_GREATER_THAN_OR_EQUAL || *m_CodePos >= OP_BOOL_UN_NOT && *m_CodePos <= OP_UN_CAST_BOOLEAN ) { - ScriptError( "Targetname '%s' does not exist.", value.c_str() ); - } - - break; - } - - if( targetList->NumObjects() == 1 ) - { - pTop->setListenerValue( targetList->ObjectAt( 1 ) ); - } - else if( targetList->NumObjects() > 1 ) - { - pTop->setContainerValue( ( Container< SafePtr< Listener > > * )targetList ); - } - else - { - value = pTop->stringValue(); - - pTop->setListenerValue( NULL ); - - if( *m_CodePos >= OP_BIN_EQUALITY && *m_CodePos <= OP_BIN_GREATER_THAN_OR_EQUAL || *m_CodePos >= OP_BOOL_UN_NOT && *m_CodePos <= OP_UN_CAST_BOOLEAN ) { - ScriptError( "Targetname '%s' does not exist.", value.c_str() ); - } - - break; - } - - break; - - case OP_VAR_UN_NOT: - pTop->setIntValue( pTop->booleanValue() ); - break; - - case OP_DONE: - End(); - break; - - case OP_NOP: - break; - - default: - if( *opcode < OP_MAX ) - { - glbs.DPrintf( "unknown opcode %d ('%s')\n", *opcode, OpcodeName( *opcode ) ); - } - else - { - glbs.DPrintf( "unknown opcode %d\n", *opcode ); - } - break; - } - } - catch( ScriptException& exc ) - { - HandleScriptException( exc ); - } - } - - Director.stackCount--; - - if( deleteThread || state == STATE_WAITING ) - { - delete m_Thread; - } - else if( state == STATE_SUSPENDED ) - { - state = STATE_EXECUTION; - } - - if( state == STATE_DESTROYED ) - { - delete this; - } -} - -/* -==================== -HandleScriptException -==================== -*/ -void ScriptVM::HandleScriptException( ScriptException& exc ) -{ - if( m_ScriptClass ) - { - m_ScriptClass->GetScript()->PrintSourcePos( m_PrevCodePos, true ); - } - else - { - glbs.DPrintf( "unknown source pos" ); - } - - if( exc.bAbort ) - { - ScriptException e( exc.string ); - - e.bAbort = exc.bAbort; - e.bIsForAnim = exc.bIsForAnim; - - state = STATE_EXECUTION; - throw e; - } - - glbs.Printf( "^~^~^ Script Error : %s\n\n", exc.string.c_str() ); - - if (m_ScriptClass->GetScript()->ScriptCheck()) - { - if (g_scriptcheck->integer != 2 || !exc.bIsForAnim) - { - ScriptException e("Script check failed"); - - e.bAbort = exc.bAbort; - e.bIsForAnim = exc.bIsForAnim; - - state = STATE_EXECUTION; - throw e; - } - } - Director.cmdCount += 100; -} - -/* -==================== -SetFastData - -Sets the starting virtual machine parameters -==================== -*/ -void ScriptVM::SetFastData( ScriptVariable *data, int dataSize ) -{ - if( fastEvent.data ) - { - fastEvent.data = m_pOldData; - fastEvent.dataSize = m_OldDataSize; - - fastEvent.Clear(); - - m_pOldData = NULL; - m_OldDataSize = 0; - } - - if( dataSize ) - { - fastEvent.data = new ScriptVariable[ dataSize ]; - fastEvent.dataSize = dataSize; - - for( int i = 0; i < dataSize; i++ ) - { - fastEvent.data[ i ] = data[ i ]; - } - - m_pOldData = fastEvent.data; - m_OldDataSize = fastEvent.dataSize; - } -} - -/* -==================== -NotifyDelete -==================== -*/ -void ScriptVM::NotifyDelete( void ) -{ - switch( state ) - { - case STATE_DESTROYED: - ScriptError( "Attempting to delete a dead thread." ); - break; - - case STATE_RUNNING: - case STATE_SUSPENDED: - case STATE_WAITING: - state = STATE_DESTROYED; - - if( m_ScriptClass ) { - m_ScriptClass->RemoveThread( this ); - } - - break; - - case STATE_EXECUTION: - state = STATE_DESTROYED; - - if( m_ScriptClass ) { - m_ScriptClass->RemoveThread( this ); - } - - delete this; - - break; - } -} - -/* -==================== -Resume -==================== -*/ -void ScriptVM::Resume( qboolean bForce ) -{ - if( state == STATE_SUSPENDED || ( bForce && state != STATE_DESTROYED ) ) { - state = STATE_RUNNING; - } -} - -/* -==================== -Suspend -==================== -*/ -void ScriptVM::Suspend() -{ - if( state == STATE_DESTROYED ) { - ScriptError( "Cannot suspend a dead thread." ); - } else if( !state ) { - state = STATE_SUSPENDED; - } -} - -/* -==================== -Switch - -Switch statement -==================== -*/ -bool ScriptVM::Switch( StateScript *stateScript, ScriptVariable& var ) -{ - unsigned char *pos; - - fastEvent.dataSize = 0; - - pos = stateScript->FindLabel( var.stringValue() ); - - if( !pos ) - { - pos = stateScript->FindLabel( "" ); - - if( !pos ) { - return false; - } - } - - m_CodePos = pos; - - return true; -} - -/* -==================== -Filename -==================== -*/ -str ScriptVM::Filename( void ) -{ - return m_ScriptClass->Filename(); -} - -/* -==================== -Label -==================== -*/ -str ScriptVM::Label( void ) -{ - const_str label = m_ScriptClass->NearestLabel( m_CodePos ); - - if( !label ) - { - return ""; - } - - return Director.GetString( label ); -} - -/* -==================== -GetScriptClass -==================== -*/ -ScriptClass *ScriptVM::GetScriptClass( void ) -{ - return m_ScriptClass; -} - -/* -==================== -IsSuspended -==================== -*/ -bool ScriptVM::IsSuspended( void ) -{ - return state == STATE_SUSPENDED; -} - -/* -==================== -State -==================== -*/ -int ScriptVM::State( void ) -{ - return state; -} - -/* -==================== -ThreadState -==================== -*/ -int ScriptVM::ThreadState( void ) -{ - return m_ThreadState; -} - -/* -==================== -EventGoto -==================== -*/ -void ScriptVM::EventGoto( Event *ev ) -{ - str label = ev->GetString( 1 ); - - SetFastData( ev->data + 1, ev->dataSize - 1 ); - - unsigned char *codePos = m_ScriptClass->FindLabel( label ); - - if( !codePos ) - { - ScriptError( "ScriptVM::EventGoto: label '%s' does not exist in '%s'.", label.c_str(), Filename().c_str() ); - } - - m_CodePos = codePos; -} - -/* -==================== -EventThrow - -Called when throwing an exception -==================== -*/ -bool ScriptVM::EventThrow( Event *ev ) -{ - str label = ev->GetString( 1 ); - - SetFastData( ev->data, ev->dataSize ); - - fastEvent.eventnum = ev->eventnum; - - while( 1 ) - { - StateScript *stateScript = m_ScriptClass->GetCatchStateScript( m_PrevCodePos, m_PrevCodePos ); - - if( !stateScript ) { - break; - } - - m_CodePos = stateScript->FindLabel( label ); - - if( m_CodePos ) - { - fastEvent.data++; - fastEvent.dataSize--; - - return true; - } - } - - return false; -} - -/* -==================== -AllowContextSwitch -==================== -*/ -void ScriptVM::AllowContextSwitch( bool allow ) -{ - m_bAllowContextSwitch = allow; -} - -/* -==================== -RequestContextSwitch - -Requests a context switch -==================== -*/ -void ScriptVM::RequestContextSwitch( void ) -{ - if( !m_bAllowContextSwitch || !Director.m_bAllowContextSwitch ) { - return; - } - - //glbs.DPrintf( "Performing context switch\n" ); - - Director.AddContextSwitch( m_Thread ); - - m_ThreadState = THREAD_CONTEXT_SWITCH; - Suspend(); -} - -bool ScriptVM::CanScriptTracePrint - ( - void - ) -{ - if (g_scripttrace->integer < 1 || g_scripttrace->integer > 4) - { - return false; - } - if (g_scripttrace->integer <= 2) - { - return true; - } - if (!m_ScriptClass) - { - return false; - } - if (!*g_monitor->string || !m_ScriptClass->m_Self || !m_ScriptClass->m_Self->isInheritedBy(&SimpleEntity::ClassInfo) || ((SimpleEntity *)m_ScriptClass->m_Self.Pointer())->targetname != g_monitor->string) - { - if (g_monitorNum->integer >= 0) - { - if (m_ScriptClass->m_Self && m_ScriptClass->m_Self->isInheritedBy(&Entity::ClassInfo) && ((Entity *)m_ScriptClass->m_Self.Pointer())->entnum == g_monitorNum->integer) - { - return true; - } - } - return false; - } - return true; - -} diff --git a/code/globalcpp/Linklist.h b/code/qcommon/Linklist.h similarity index 100% rename from code/globalcpp/Linklist.h rename to code/qcommon/Linklist.h diff --git a/code/globalcpp/class.cpp b/code/qcommon/class.cpp similarity index 98% rename from code/globalcpp/class.cpp rename to code/qcommon/class.cpp index fdab964f..4ea26e64 100644 --- a/code/globalcpp/class.cpp +++ b/code/qcommon/class.cpp @@ -22,13 +22,22 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // class.cpp: General class. -#include "glb_local.h" -#include "scriptmaster.h" -#include +#include "class.h" +#include "listener.h" +#include + +#ifdef GAME_DLL +#include "level.h" +#include #define CLASS_Printf if( level.current_map ) glbs.Printf #define CLASS_DPrintf if( level.current_map ) glbs.DPrintf #define CLASS_Error if( level.current_map ) glbs.Error +#else +#define CLASS_Printf Com_Printf +#define CLASS_DPrintf Com_DPrintf +#define CLASS_Error Com_Error +#endif ClassDef *ClassDef::classlist; int ClassDef::numclasses; @@ -228,12 +237,6 @@ void *Class::operator new( size_t s ) p = ( size_t * )gi.Malloc( s ); #elif defined ( CGAME_DLL ) p = ( size_t * )cgi.Malloc( s ); -#else - p = ( size_t * )glbs.Malloc( s ); -#endif - -#ifdef _DEBUG - m_Heap.ReferencePointer( p ); #endif *p = s; @@ -253,16 +256,10 @@ void Class::operator delete( void *ptr ) totalmemallocated -= *p; numclassesallocated--; -#ifdef _DEBUG - m_Heap.DereferencePointer( p ); -#endif - #ifdef GAME_DLL gi.Free( p ); #elif defined ( CGAME_DLL ) cgi.Free( p ); -#else - glbs.Free( p ); #endif } @@ -576,7 +573,7 @@ void ClassDef::BuildEventResponses( void ) numclasses++; } - glbs.DPrintf( "\n------------------\nEvent system initialized: " + CLASS_DPrintf( "\n------------------\nEvent system initialized: " "%d classes %d events %d total memory in response list\n\n", numclasses, Event::NumEventCommands(), amount ); } diff --git a/code/globalcpp/class.h b/code/qcommon/class.h similarity index 98% rename from code/globalcpp/class.h rename to code/qcommon/class.h index 3f54dac5..c3803049 100644 --- a/code/globalcpp/class.h +++ b/code/qcommon/class.h @@ -25,15 +25,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __CLASS_H__ #define __CLASS_H__ -#if defined ( GAME_DLL ) +#include "q_shared.h" +#include "container.h" +#include "con_set.h" +#include "str.h" -#include "g_local.h" - -#else - -#include "glb_local.h" - -#endif +#include "const_str.h" class Class; class Event; diff --git a/code/qcommon/cm_public.h b/code/qcommon/cm_public.h index 460667d5..2defd4a3 100644 --- a/code/qcommon/cm_public.h +++ b/code/qcommon/cm_public.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "qfiles.h" +#include "q_shared.h" #ifdef __cplusplus extern "C" { diff --git a/code/qcommon/common.cpp b/code/qcommon/common.cpp index e0d533df..a046c7a9 100644 --- a/code/qcommon/common.cpp +++ b/code/qcommon/common.cpp @@ -31,11 +31,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #endif -#include - extern "C" { -baseImport_t bi; cvar_t *sv_scriptfiles; cvar_t *g_scriptcheck; cvar_t *g_showopcodes; @@ -762,35 +759,6 @@ void B_Free( void *ptr ) { return Z_Free( ptr ); } -/* -==================== -Com_FillBaseImports -==================== -*/ -void Com_FillBaseImports( void ) { - bi.Printf = Com_Printf; - bi.DPrintf = Com_DPrintf; - bi.Error = Com_Error; - bi.Malloc = B_Malloc; - bi.Free = B_Free; - bi.Milliseconds = Sys_Milliseconds; - bi.FS_ReadFile = FS_ReadFileEx; - bi.FS_FreeFile = FS_FreeFile; - bi.FS_CanonicalFilename = FS_CanonicalFilename; - bi.FS_FileNewer = FS_FileNewer; - bi.FS_Flush = FS_Flush; - bi.FS_FOpenFileAppend = FS_FOpenFileAppend; - bi.FS_FOpenFileWrite = FS_FOpenFileWrite; - bi.FS_FreeFileList = FS_FreeFileList; - bi.FS_ListFiles = FS_ListFiles; - bi.FS_PrepFileWrite = FS_PrepFileWrite; - bi.FS_Read = FS_Read; - bi.FS_Seek = FS_Seek; - bi.FS_Tell = FS_FTell; - bi.FS_Write = FS_Write; - bi.FS_WriteFile = FS_WriteFile; -} - void CL_ShutdownCGame( void ); void CL_ShutdownUI( void ); void SV_ShutdownGameProgs( void ); @@ -1303,8 +1271,6 @@ void Com_Init( char *commandLine ) { // cvar and command buffer management Com_ParseCommandLine( commandLine ); - Com_FillBaseImports(); - Swap_Init(); Cbuf_Init(); Z_InitMemory(); diff --git a/code/qcommon/con_set.cpp b/code/qcommon/con_set.cpp index c94f088a..4c154d39 100644 --- a/code/qcommon/con_set.cpp +++ b/code/qcommon/con_set.cpp @@ -22,7 +22,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // con_set.cpp: C++ map/set classes -#include "glb_local.h" +#include "con_set.h" +#include "short3.h" +#include "str.h" +#include "vector.h" // Basic Hash functions diff --git a/code/qcommon/con_set.h b/code/qcommon/con_set.h index dcc952f2..3d6f00ae 100644 --- a/code/qcommon/con_set.h +++ b/code/qcommon/con_set.h @@ -25,7 +25,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __CON_SET_H__ #define __CON_SET_H__ +#include + class Class; +class Archiver; template< typename key, typename value > class con_map_enum; @@ -55,7 +58,7 @@ public: Entry(); -#ifndef NO_ARCHIVE +#ifdef ARCHIVE_SUPPORTED void Archive( Archiver& arc ); #endif }; @@ -85,7 +88,7 @@ public: con_set(); ~con_set(); -#ifndef NO_ARCHIVE +#ifdef ARCHIVE_SUPPORTED void Archive( Archiver& arc ); #endif @@ -135,7 +138,7 @@ private: con_set< key, value > m_con_set; public: -#ifndef NO_ARCHIVE +#ifdef ARCHIVE_SUPPORTED void Archive( Archiver& arc ); #endif diff --git a/code/qcommon/con_timer.cpp b/code/qcommon/con_timer.cpp new file mode 100644 index 00000000..8011712d --- /dev/null +++ b/code/qcommon/con_timer.cpp @@ -0,0 +1,90 @@ +#include "con_timer.h" + +#if defined (ARCHIVE_SUPPORTED) +#include "archive.h" +#endif + +con_timer::con_timer(void) +{ + m_inttime = 0; + m_bDirty = false; +} + +void con_timer::AddElement(Class* e, int inttime) +{ + Element element; + + element.obj = e; + element.inttime = inttime; + + m_Elements.AddObject(element); + + if (inttime <= m_inttime) { + SetDirty(); + } +} + +void con_timer::RemoveElement(Class* e) +{ + for (int i = m_Elements.NumObjects(); i > 0; i--) + { + Element* index = &m_Elements.ObjectAt(i); + + if (index->obj == e) + { + m_Elements.RemoveObjectAt(i); + return; + } + } +} + +Class* con_timer::GetNextElement(int& foundtime) +{ + int best_inttime; + int i; + int foundIndex; + Class* result; + + foundIndex = 0; + best_inttime = m_inttime; + + for (i = m_Elements.NumObjects(); i > 0; i--) + { + if (m_Elements.ObjectAt(i).inttime <= best_inttime) + { + best_inttime = m_Elements.ObjectAt(i).inttime; + foundIndex = i; + } + } + + if (foundIndex) + { + result = m_Elements.ObjectAt(foundIndex).obj; + m_Elements.RemoveObjectAt(foundIndex); + foundtime = best_inttime; + } + else + { + result = NULL; + m_bDirty = false; + } + + return result; +} + +#if defined(ARCHIVE_SUPPORTED) + +void con_timer::ArchiveElement(Archiver& arc, Element* e) +{ + arc.ArchiveObjectPointer(&e->obj); + arc.ArchiveInteger(&e->inttime); +} + +void con_timer::Archive(Archiver& arc) +{ + arc.ArchiveBool(&m_bDirty); + arc.ArchiveInteger(&m_inttime); + + m_Elements.Archive(arc, con_timer::ArchiveElement); +} +#endif diff --git a/code/qcommon/con_timer.h b/code/qcommon/con_timer.h new file mode 100644 index 00000000..da8d2b47 --- /dev/null +++ b/code/qcommon/con_timer.h @@ -0,0 +1,34 @@ +#include "class.h" + +class con_timer : public Class +{ +public: + class Element + { + public: + Class* obj; + int inttime; + }; + +private: + Container< con_timer::Element > m_Elements; + bool m_bDirty; + int m_inttime; + +public: + con_timer(); + + void AddElement(Class* e, int inttime); + void RemoveElement(Class* e); + + Class* GetNextElement(int& foundTime); + + void SetDirty(void) { m_bDirty = true; }; + bool IsDirty(void) { return m_bDirty; }; + void SetTime(int inttime) { m_inttime = inttime; }; + +#if defined (ARCHIVE_SUPPORTED) + static void ArchiveElement(class Archiver& arc, Element* e); + void Archive(class Archiver& arc) override; +#endif +}; \ No newline at end of file diff --git a/code/globalcpp/const_str.h b/code/qcommon/const_str.h similarity index 98% rename from code/globalcpp/const_str.h rename to code/qcommon/const_str.h index 21ab0773..7956e8cb 100644 --- a/code/globalcpp/const_str.h +++ b/code/qcommon/const_str.h @@ -22,8 +22,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // const_str.h: Strings constant, improve performance in string comparison -#ifndef __CONST_STR_H__ -#define __CONST_STR_H__ +#pragma once + +typedef unsigned int const_str; + +#ifdef GAME_DLL enum { @@ -126,4 +129,12 @@ enum STRING_LENGTH_ }; +#else + +enum +{ + STRING_NULL = 0, + STRING_EMPTY = 1 +}; + #endif diff --git a/code/globalcpp/container.h b/code/qcommon/container.h similarity index 100% rename from code/globalcpp/container.h rename to code/qcommon/container.h diff --git a/code/globalcpp/containerclass.h b/code/qcommon/containerclass.h similarity index 96% rename from code/globalcpp/containerclass.h rename to code/qcommon/containerclass.h index 06335aba..1b4f843c 100644 --- a/code/globalcpp/containerclass.h +++ b/code/qcommon/containerclass.h @@ -22,8 +22,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // containerclass.h: C++ Class Container for use with SafePtr -#ifndef __CONTAINERCLASS_H__ -#define __CONTAINERCLASS_H__ +#pragma once #include "container.h" @@ -58,5 +57,3 @@ public: Type& operator[]( const int index ) const { return value[ index ]; } Container& operator=( const Container& container ) { return value = container; } }; - -#endif /* __CONTAINERCLASS_H__ */ diff --git a/code/globalcpp/listener.cpp b/code/qcommon/listener.cpp similarity index 95% rename from code/globalcpp/listener.cpp rename to code/qcommon/listener.cpp index f35b3ff3..d28c806c 100644 --- a/code/globalcpp/listener.cpp +++ b/code/qcommon/listener.cpp @@ -22,17 +22,18 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // listener.cpp : Listener. -#include "glb_local.h" #include "scriptvariable.h" +#include "scriptexception.h" #include "linklist.h" -#include "archive.h" #ifndef NO_SCRIPTENGINE +#include "archive.h" #include "scriptmaster.h" #endif #if defined( GAME_DLL ) #include "../game/player.h" +#include "../game/consoleevent.h" #include "animate.h" #elif defined ( CGAME_DLL ) #elif defined ( UI_LIB ) @@ -351,6 +352,8 @@ int HashCode< command_t >( const command_t& key ) return HashCode< str >( key.command ); } +#if defined(ARCHIVE_SUPPORTED) + void ArchiveListenerPtr ( Archiver& arc, @@ -378,12 +381,124 @@ void Entry< const_str, ConList >::Archive ) { -#ifndef NO_SCRIPTENGINE Director.ArchiveString( arc, key ); -#endif value.Archive( arc ); } +/* +======================= +Archive +======================= +*/ +void Event::Archive( Archiver &arc ) +{ + if( arc.Loading() ) { + fromScript = false; + } + + Class::Archive( arc ); + + arc.ArchiveUnsignedShort( &eventnum ); + arc.ArchiveUnsignedShort( &dataSize ); + + if( arc.Loading() ) + { + data = new ScriptVariable[ dataSize + 1 ]; + } + + for( int i = dataSize; i > 0; i-- ) + { + data[ i ].ArchiveInternal( arc ); + } +} + +void L_ArchiveEvents +( + Archiver& arc +) + +{ + EventQueueNode* event; + int num; + + num = 0; + for (event = Event::EventQueue.next; event != &Event::EventQueue; event = event->next) + { + Listener* obj; + + assert(event); + + obj = event->GetSourceObject(); + + assert(obj); + +#if defined ( GAME_DLL ) + if (obj->isSubclassOf(Entity) && + (((Entity*)obj)->flags & FL_DONTSAVE)) + { + continue; + } +#endif + + num++; + } + + arc.ArchiveInteger(&num); + for (event = Event::EventQueue.next; event != &Event::EventQueue; event = event->next) + { + Listener* obj; + + assert(event); + + obj = event->GetSourceObject(); + + assert(obj); + +#if defined ( GAME_DLL ) + if (obj->isSubclassOf(Entity) && + (((Entity*)obj)->flags & FL_DONTSAVE)) + { + continue; + } +#endif + + event->event->Archive(arc); + arc.ArchiveInteger(&event->inttime); + arc.ArchiveInteger(&event->flags); + arc.ArchiveSafePointer(&event->m_sourceobject); + } +} + +void L_UnarchiveEvents +( + Archiver& arc +) + +{ + EventQueueNode* node; + Event* e; + int i, numEvents; + + // the FreeEvents list would already be allocated at this point + // clear out any events that may exist + L_ClearEventList(); + + arc.ArchiveInteger(&numEvents); + for (i = 0; i < numEvents; i++) + { + node = new EventQueueNode(); + e = new Event(); + e->Archive(arc); + + arc.ArchiveInteger(&node->inttime); + arc.ArchiveInteger(&node->flags); + arc.ArchiveSafePointer(&node->m_sourceobject); + + LL_Add(&Event::EventQueue, node, next, prev); + } +} +#endif + void L_ClearEventList() { EventQueueNode *node = Event::EventQueue.next, *tmp; @@ -423,7 +538,6 @@ void L_InitEvents( void ) g_eventstats = gi.Cvar_Get( "g_eventstats", "0", 0 ); #endif - gi.Printf("L_InitEvents\n"); Event::LoadEvents(); ClassDef::BuildEventResponses(); @@ -449,7 +563,7 @@ void L_ProcessPendingEvents() assert( obj ); - if( node->inttime > level.inttime ) + if( node->inttime > EVENT_time) { break; } @@ -486,92 +600,6 @@ void L_ShutdownEvents( void ) Listener::EventSystemStarted = false; } -void L_ArchiveEvents - ( - Archiver &arc - ) - -{ - EventQueueNode *event; - int num; - - num = 0; - for( event = Event::EventQueue.next; event != &Event::EventQueue; event = event->next ) - { - Listener * obj; - - assert( event ); - - obj = event->GetSourceObject(); - - assert( obj ); - -#if defined ( GAME_DLL ) - if( obj->isSubclassOf( Entity ) && - ( ( ( Entity * )obj )->flags & FL_DONTSAVE ) ) - { - continue; - } -#endif - - num++; - } - - arc.ArchiveInteger( &num ); - for( event = Event::EventQueue.next; event != &Event::EventQueue; event = event->next ) - { - Listener * obj; - - assert( event ); - - obj = event->GetSourceObject(); - - assert( obj ); - -#if defined ( GAME_DLL ) - if( obj->isSubclassOf( Entity ) && - ( ( ( Entity * )obj )->flags & FL_DONTSAVE ) ) - { - continue; - } -#endif - - event->event->Archive( arc ); - arc.ArchiveInteger( &event->inttime ); - arc.ArchiveInteger( &event->flags ); - arc.ArchiveSafePointer( &event->m_sourceobject ); - } -} - -void L_UnarchiveEvents - ( - Archiver &arc - ) - -{ - EventQueueNode *node; - Event *e; - int i, numEvents; - - // the FreeEvents list would already be allocated at this point - // clear out any events that may exist - L_ClearEventList(); - - arc.ArchiveInteger( &numEvents ); - for( i = 0; i < numEvents; i++ ) - { - node = new EventQueueNode(); - e = new Event(); - e->Archive( arc ); - - arc.ArchiveInteger( &node->inttime ); - arc.ArchiveInteger( &node->flags ); - arc.ArchiveSafePointer( &node->m_sourceobject ); - - LL_Add( &Event::EventQueue, node, next, prev ); - } -} - //=========================================================================== // EventArgDef //=========================================================================== @@ -721,7 +749,7 @@ void EV_Print( FILE *stream, const char *format, ... ) } else { - glbs.DPrintf( buffer ); + EVENT_DPrintf( buffer ); } va_end( va ); @@ -1762,33 +1790,6 @@ void Event::LoadEvents() } } -/* -======================= -Archive -======================= -*/ -void Event::Archive( Archiver &arc ) -{ - if( arc.Loading() ) { - fromScript = false; - } - - Class::Archive( arc ); - - arc.ArchiveUnsignedShort( &eventnum ); - arc.ArchiveUnsignedShort( &dataSize ); - - if( arc.Loading() ) - { - data = new ScriptVariable[ dataSize + 1 ]; - } - - for( int i = dataSize; i > 0; i-- ) - { - data[ i ].ArchiveInternal( arc ); - } -} - /* ======================= Event @@ -1860,12 +1861,12 @@ void Event::ErrorInternal( Listener *l, str text ) str classname; str eventname; - glbs.DPrintf( "^~^~^ Game" ); + EVENT_DPrintf( "^~^~^ Game" ); classname = l->getClassname(); eventname = getName(); - glbs.DPrintf( " (Event: '%s', Object: '%s') : %s\n", eventname.c_str(), classname.c_str(), text.c_str() ); + EVENT_DPrintf( " (Event: '%s', Object: '%s') : %s\n", eventname.c_str(), classname.c_str(), text.c_str() ); } /* @@ -1967,7 +1968,7 @@ Event::Event( str command ) eventnum = commandList.findKeyIndex( c ); if( !eventnum ) { - glbs.DPrintf( "^~^~^ Event '%s' does not exist.\n", command.c_str() ); + EVENT_DPrintf( "^~^~^ Event '%s' does not exist.\n", command.c_str() ); } fromScript = qfalse; @@ -2024,7 +2025,7 @@ Event::Event( str command, uchar type ) if( !eventnum ) { - glbs.DPrintf( "^~^~^ Event '%s' does not exist.\n", command.c_str() ); + EVENT_DPrintf( "^~^~^ Event '%s' does not exist.\n", command.c_str() ); } fromScript = qfalse; @@ -2551,96 +2552,6 @@ str& Event::getName() return GetEventName( eventnum ); } -#if defined ( GAME_DLL ) - -//=============================== -// ConsoleEvent -//=============================== - - -MEM_BlockAlloc< ConsoleEvent, MEM_BLOCKSIZE > ConsoleEvent_allocator; - -CLASS_DECLARATION( Event, ConsoleEvent, NULL ) -{ - { NULL, NULL } -}; - -/* -======================= -new ConsoleEvent -======================= -*/ -void *ConsoleEvent::operator new( size_t size ) -{ - return ConsoleEvent_allocator.Alloc(); -} - -/* -======================= -delete ptr -======================= -*/ -void ConsoleEvent::operator delete( void *ptr ) -{ - ConsoleEvent_allocator.Free( ptr ); -} - -/* -======================= -ConsoleEvent -======================= -*/ -ConsoleEvent::ConsoleEvent( void ) -{ - m_consoleedict = NULL; -} - -/* -======================= -SetConsoleEdict -======================= -*/ -void ConsoleEvent::SetConsoleEdict( gentity_t *edict ) -{ - m_consoleedict = edict; -} - -/* -======================= -GetConsoleEdict -======================= -*/ -gentity_t *ConsoleEvent::GetConsoleEdict( void ) -{ - if( m_consoleedict ) - return m_consoleedict; - - return g_entities; -} - -/* -======================= -ErrorInternal -======================= -*/ -void ConsoleEvent::ErrorInternal( Listener *l, str text ) -{ - gentity_t *edict = GetConsoleEdict(); - str eventname = getName(); - - gi.DPrintf( "^~^~^ Game ( Event '%s', Client '%s' ) : %s\n", - eventname.c_str(), - edict->client ? edict->client->pers.netname : "", - text.c_str() ); - - gi.SendServerCommand( GetConsoleEdict() - g_entities, - "print \"Console: '%s' : %s\n\"", - eventname.c_str(), - text.c_str() ); -} - -#endif - //==================================== // Listener //==================================== @@ -2896,9 +2807,9 @@ EventQueueNode *Listener::PostEventInternal( Event *ev, float delay, int flags ) if( !ev->eventnum ) { #ifdef _DEBUG - glbs.DPrintf( "^~^~^ Failed execution of event '%s' for class '%s'\n", ev->name.c_str(), getClassname() ); + EVENT_DPrintf( "^~^~^ Failed execution of event '%s' for class '%s'\n", ev->name.c_str(), getClassname() ); #else - glbs.DPrintf( "^~^~^ Failed execution of event for class '%s'\n", getClassname() ); + EVENT_DPrintf( "^~^~^ Failed execution of event for class '%s'\n", getClassname() ); #endif } @@ -2909,7 +2820,7 @@ EventQueueNode *Listener::PostEventInternal( Event *ev, float delay, int flags ) node = new EventQueueNode; i = Event::EventQueue.next; - inttime = level.inttime + ( delay * 1000.0f + 0.5f ); + inttime = EVENT_time + ( delay * 1000.0f + 0.5f ); while( i != &Event::EventQueue && inttime > i->inttime ) { @@ -3066,7 +2977,7 @@ bool Listener::ProcessEvent( Event *ev ) catch( ScriptException& exc ) { ev->ErrorInternal( this, exc.string ); - glbs.DPrintf( "%s\n", exc.string.c_str() ); + EVENT_DPrintf( "%s\n", exc.string.c_str() ); } delete ev; @@ -3224,7 +3135,7 @@ qboolean Listener::ProcessPendingEvents( void ) processedEvents = false; - t = level.inttime; + t = EVENT_time; event = Event::EventQueue.next; while( event != &Event::EventQueue ) @@ -4692,7 +4603,7 @@ void Listener::ExecuteThread( str scriptName, str labelName, Event *params ) } catch( ScriptException& exc ) { - glbs.DPrintf( "Listener::ExecuteThread: %s\n", exc.string.c_str() ); + EVENT_DPrintf( "Listener::ExecuteThread: %s\n", exc.string.c_str() ); } } @@ -4718,7 +4629,7 @@ void Listener::ExecuteThread( str scriptName, str labelName, Event& params ) } catch( ScriptException& exc ) { - glbs.DPrintf( "Listener::ExecuteThread: %s\n", exc.string.c_str() ); + EVENT_DPrintf( "Listener::ExecuteThread: %s\n", exc.string.c_str() ); } } diff --git a/code/globalcpp/listener.h b/code/qcommon/listener.h similarity index 95% rename from code/globalcpp/listener.h rename to code/qcommon/listener.h index ad419ee5..abddf13f 100644 --- a/code/globalcpp/listener.h +++ b/code/qcommon/listener.h @@ -22,11 +22,13 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // listener.h: Listener -#ifndef __LISTENER_H__ -#define __LISTENER_H__ +#pragma once -#include "glb_local.h" #include "class.h" +#include "containerclass.h" +#include "con_arrayset.h" +#include "str.h" +#include "vector.h" class Entity; class Listener; @@ -327,9 +329,11 @@ public: uchar type = EV_NORMAL ); - virtual ~Event(); + ~Event(); - virtual void Archive( Archiver &arc ); +#if defined(ARCHIVE_SUPPORTED) + void Archive( Archiver &arc ) override; +#endif #ifdef _GAME_DLL eventInfo_t *getInfo(); @@ -396,30 +400,6 @@ public: int NumArgs(); }; -#ifdef GAME_DLL - -class ConsoleEvent : public Event -{ -private: - gentity_t *m_consoleedict; - -public: - CLASS_PROTOTYPE( ConsoleEvent ); - - void *operator new( size_t size ); - void operator delete( void *ptr ); - - ConsoleEvent(); - ConsoleEvent( str name ) : Event( name ) { m_consoleedict = NULL; } - - void SetConsoleEdict( gentity_t *edict ); - gentity_t *GetConsoleEdict( void ); - - virtual void ErrorInternal( Listener *l, str text ); -}; - -#endif - typedef struct eventInfo { Event *ev; @@ -457,10 +437,10 @@ public: template< class Type1, class Type2 > class con_map; -typedef ContainerClass< SafePtr< Listener > > ConList; -typedef con_map< Event *, EventDef * > eventMap; +using ConList = ContainerClass< SafePtr< Listener > >; +using eventMap = con_map< Event *, EventDef * >; -typedef SafePtr< Listener > ListenerPtr; +using ListenerPtr = SafePtr< Listener >; class Listener : public Class { @@ -629,9 +609,6 @@ extern cvar_t *g_watch; extern cvar_t *g_eventstats; extern MEM_BlockAlloc< Event, MEM_BLOCKSIZE > Event_allocator; -#ifdef GAME_DLL -extern MEM_BlockAlloc< ConsoleEvent, MEM_BLOCKSIZE > ConsoleEvent_allocator; -#endif #if defined( GAME_DLL ) // @@ -695,8 +672,3 @@ void L_ProcessPendingEvents(); void L_ShutdownEvents( void ); void L_ArchiveEvents( Archiver& arc ); void L_UnarchiveEvents( Archiver& arc ); - -#include "game.h" -#include "level.h" - -#endif /* __LISTENER_H__ */ diff --git a/code/globalcpp/lz77.cpp b/code/qcommon/lz77.cpp similarity index 100% rename from code/globalcpp/lz77.cpp rename to code/qcommon/lz77.cpp diff --git a/code/globalcpp/lz77.h b/code/qcommon/lz77.h similarity index 100% rename from code/globalcpp/lz77.h rename to code/qcommon/lz77.h diff --git a/code/qcommon/mem_blockalloc.cpp b/code/qcommon/mem_blockalloc.cpp index 41f6e98c..fdf675ef 100644 --- a/code/qcommon/mem_blockalloc.cpp +++ b/code/qcommon/mem_blockalloc.cpp @@ -22,14 +22,32 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // mem_blockalloc.cpp: Fast block memory manager -#include +#if defined(GAME_DLL) + +#include "g_local.h" void *MEM_Alloc( int size ) { - return glbs.Malloc( size ); + return gi.Malloc( size ); } void MEM_Free( void *ptr ) { - return glbs.Free( ptr ); + return gi.Free( ptr ); } + +#else + +#include "qcommon.h" + +void* MEM_Alloc(int size) +{ + return Z_Malloc(size); +} + +void MEM_Free(void* ptr) +{ + return Z_Free(ptr); +} + +#endif diff --git a/code/qcommon/mem_blockalloc.h b/code/qcommon/mem_blockalloc.h index 91aa7477..0dd73033 100644 --- a/code/qcommon/mem_blockalloc.h +++ b/code/qcommon/mem_blockalloc.h @@ -25,8 +25,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __MEM_BLOCKALLOC_H__ #define __MEM_BLOCKALLOC_H__ -#include -#include "dbgheap.h" +#include "linklist.h" #define MEM_BLOCKSIZE char[ 256 ] diff --git a/code/qcommon/mem_tempalloc.cpp b/code/qcommon/mem_tempalloc.cpp index d89265b3..e850e2ad 100644 --- a/code/qcommon/mem_tempalloc.cpp +++ b/code/qcommon/mem_tempalloc.cpp @@ -22,12 +22,23 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // mem_tempalloc.cpp: Fast temporary memory manager -#include #include +#ifdef GAME_DLL +#include "g_local.h" + +#define MEM_TempAllocate(x) gi.Malloc(x) +#define MEM_TempFree(x) gi.Free(x) +#else +#include "qcommon.h" + +#define MEM_TempAllocate(x) Z_Malloc(x) +#define MEM_TempFree(x) Z_Free(x) +#endif + MEM_TempAlloc::MEM_TempAlloc() { - m_CurrentMemoryBlock = NULL; + m_CurrentMemoryBlock = nullptr; } void *MEM_TempAlloc::Alloc( size_t len ) @@ -47,7 +58,7 @@ void *MEM_TempAlloc::Alloc( size_t len ) if( len < 65536 ) len = 65536; - m_CurrentMemoryBlock = ( unsigned char * )glbs.Malloc( len + sizeof( unsigned char * ) ); + m_CurrentMemoryBlock = ( unsigned char * )MEM_TempAllocate( len + sizeof( unsigned char * ) ); *( unsigned char ** )m_CurrentMemoryBlock = prev_block; result = m_CurrentMemoryBlock + sizeof( unsigned char * ); } @@ -62,7 +73,7 @@ void MEM_TempAlloc::FreeAll( void ) while( m_CurrentMemoryBlock ) { prev_block = *( unsigned char ** )m_CurrentMemoryBlock; - glbs.Free( m_CurrentMemoryBlock ); + MEM_TempFree( m_CurrentMemoryBlock ); m_CurrentMemoryBlock = prev_block; } } diff --git a/code/qcommon/q_shared.h b/code/qcommon/q_shared.h index 8e67ac1f..ce6afc5f 100644 --- a/code/qcommon/q_shared.h +++ b/code/qcommon/q_shared.h @@ -579,7 +579,7 @@ void ByteToDir( int b, vec3_t dir ); #define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) #define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) #define VectorAdd2D(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1]) -#define VectorSub2D(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1]) +#define VectorSub2D(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1]) #define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) #define VectorCopy2D(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1]) #define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) diff --git a/code/qcommon/qfiles.h b/code/qcommon/qfiles.h index 58f77dee..e5a996dd 100644 --- a/code/qcommon/qfiles.h +++ b/code/qcommon/qfiles.h @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __QFILES_H__ #define __QFILES_H__ +#include "q_shared.h" + // // qfiles.h: quake file formats // This file must be identical in the quake and utils directories diff --git a/code/globalcpp/safeptr.h b/code/qcommon/safeptr.h similarity index 96% rename from code/globalcpp/safeptr.h rename to code/qcommon/safeptr.h index 8db74913..f859aa04 100644 --- a/code/globalcpp/safeptr.h +++ b/code/qcommon/safeptr.h @@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __SAFEPTR_H__ #define __SAFEPTR_H__ +#include "linklist.h" + class SafePtrBase { private: @@ -63,7 +65,7 @@ inline void SafePtrBase::RemoveReference( Class *ptr ) { if( ptr->SafePtrList->next == this ) { - ptr->SafePtrList = NULL; + ptr->SafePtrList = nullptr; } else { @@ -82,15 +84,15 @@ inline void SafePtrBase::Clear( void ) if( ptr ) { RemoveReference( ptr ); - ptr = NULL; + ptr = nullptr; } } inline SafePtrBase::SafePtrBase() { - prev = NULL; - next = NULL; - ptr = NULL; + prev = nullptr; + next = nullptr; + ptr = nullptr; } inline SafePtrBase::~SafePtrBase() @@ -113,7 +115,7 @@ inline void SafePtrBase::InitSafePtr( Class *newptr ) } ptr = newptr; - if( ptr == NULL ) + if( ptr == nullptr ) { return; } @@ -220,7 +222,7 @@ inline bool operator!=( SafePtr a, SafePtr b ) template inline bool SafePtr::operator !( ) const { - return ptr == NULL; + return ptr == nullptr; } template diff --git a/code/globalcpp/script.cpp b/code/qcommon/script.cpp similarity index 92% rename from code/globalcpp/script.cpp rename to code/qcommon/script.cpp index b2e661a9..37bbb8c2 100644 --- a/code/globalcpp/script.cpp +++ b/code/qcommon/script.cpp @@ -30,9 +30,38 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // make this behaviour toggleable. // -#include "glb_local.h" #include "script.h" +#if defined(GAME_DLL) + +#include "g_local.h" + +#define FILE_FS_FreeFile gi.FS_FreeFile +#define FILE_FS_ReadFile(a,b) gi.FS_ReadFile(a,b,true) +#define FILE_Malloc gi.Malloc +#define FILE_Free gi.Free +#define FILE_Error gi.Error + +#elif defined(CGAME_DLL) + +#define FILE_FS_FreeFile cgi.FS_FreeFile +#define FILE_FS_ReadFile(a,b) cgi.FS_ReadFile(a,b,true) +#define FILE_Malloc cgi.Malloc +#define FILE_Free cgi.Free +#define FILE_Error cgi.Error + +#else + +#include "qcommon.h" + +#define FILE_FS_FreeFile FS_FreeFile +#define FILE_FS_ReadFile(a,b) FS_ReadFile(a,b) +#define FILE_Malloc Z_Malloc +#define FILE_Free Z_Free +#define FILE_Error Com_Error + +#endif + typedef unsigned char byte; CLASS_DECLARATION( Class, Script, NULL ) @@ -76,7 +105,7 @@ void Script::Close( void ) { if ( releaseBuffer && buffer ) { - glbs.Free( ( void * )buffer ); + FILE_Free( ( void * )buffer ); } buffer = NULL; @@ -220,7 +249,7 @@ void Script::CheckOverflow( void ) { if ( script_p >= end_p ) { - glbs.Error( ERR_DROP, "End of token file reached prematurely reading %s\n", filename.c_str() ); + FILE_Error( ERR_DROP, "End of token file reached prematurely reading %s\n", filename.c_str() ); } } @@ -245,7 +274,7 @@ void Script::SkipWhiteSpace( qboolean crossline ) { if ( !crossline ) { - glbs.Error( ERR_DROP, "Line %i is incomplete in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "Line %i is incomplete in file %s\n", line, filename.c_str() ); } line++; @@ -593,7 +622,7 @@ const char *Script::GrabNextToken( qboolean crossline ) if ( token_p == &token[ MAXTOKEN ] ) { - glbs.Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() ); } if ( script_p == end_p ) @@ -675,7 +704,7 @@ const char *Script::GetMacroString( const char *theMacroName ) sptr++; // We didn't find what we were looking for - glbs.Error( ERR_DROP, "No Macro Text found for %s in file %s\n", theMacroName, filename.c_str() ); + FILE_Error( ERR_DROP, "No Macro Text found for %s in file %s\n", theMacroName, filename.c_str() ); return 0; } @@ -825,7 +854,7 @@ const char *Script::GetLine( qboolean crossline ) } else { - glbs.Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() ); } return token; @@ -862,7 +891,7 @@ const char *Script::GetRaw( void ) } else { - glbs.Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "Token too large on line %i in file %s\n", line, filename.c_str() ); } return token; @@ -895,7 +924,7 @@ const char *Script::GetString( qboolean crossline ) if ( *script_p != '"' ) { - glbs.Error( ERR_DROP, "Expecting string on line %i in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "Expecting string on line %i in file %s\n", line, filename.c_str() ); } script_p++; @@ -906,7 +935,7 @@ const char *Script::GetString( qboolean crossline ) { if ( *script_p == TOKENEOL ) { - glbs.Error( ERR_DROP, "Line %i is incomplete while reading string in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "Line %i is incomplete while reading string in file %s\n", line, filename.c_str() ); } if ( ( *script_p == '\\' ) && ( script_p < ( end_p - 1 ) ) ) @@ -930,13 +959,13 @@ const char *Script::GetString( qboolean crossline ) if ( script_p >= end_p ) { - glbs.Error( ERR_DROP, "End of token file reached prematurely while reading string on\n" + FILE_Error( ERR_DROP, "End of token file reached prematurely while reading string on\n" "line %d in file %s\n", startline, filename.c_str() ); } if ( token_p == &token[ MAXTOKEN ] ) { - glbs.Error( ERR_DROP, "String too large on line %i in file %s\n", line, filename.c_str() ); + FILE_Error( ERR_DROP, "String too large on line %i in file %s\n", line, filename.c_str() ); } } @@ -1126,7 +1155,7 @@ void Script::LoadFile( const char *name ) Close(); - length = glbs.FS_ReadFile( name, ( void ** )&tempbuf, true ); + length = FILE_FS_ReadFile( name, ( void ** )&tempbuf ); hasError = false; @@ -1137,12 +1166,12 @@ void Script::LoadFile( const char *name ) } // create our own space - buffer = ( byte * )glbs.Malloc( length + 1 ); + buffer = ( byte * )FILE_Malloc( length + 1 ); // copy the file over to our space memcpy( buffer, tempbuf, length ); buffer[ length ] = 0; // free the file - glbs.FS_FreeFile( tempbuf ); + FILE_FS_FreeFile( tempbuf ); const_buffer = ( char * )buffer; @@ -1163,7 +1192,7 @@ void Script::LoadFile( const char *name, int length, const char *buf ) Close(); // create our own space - this->buffer = ( const char * )glbs.Malloc( length ); + this->buffer = ( const char * )FILE_Malloc( length ); this->length = length; // copy the file over to our space memcpy( ( void * )this->buffer, buf, length ); diff --git a/code/globalcpp/script.h b/code/qcommon/script.h similarity index 97% rename from code/globalcpp/script.h rename to code/qcommon/script.h index f4c8550c..7ad80279 100644 --- a/code/globalcpp/script.h +++ b/code/qcommon/script.h @@ -28,7 +28,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "class.h" #include "vector.h" #include "str.h" + +#if defined(ARCHIVE_SUPPORTED) #include "archive.h" +#endif #define TOKENCOMMENT (';') #define TOKENCOMMENT2 ('#') @@ -80,7 +83,9 @@ class Script : public Class CLASS_PROTOTYPE( Script ); +#if defined(ARCHIVE_SUPPORTED) virtual void Archive( Archiver &arc ); +#endif ~Script(); Script( const char* filename ); @@ -134,6 +139,8 @@ class Script : public Class void AddMacro(const char *name, const char *value); }; +#if defined(ARCHIVE_SUPPORTED) + inline void Script::Archive ( Archiver &arc @@ -176,5 +183,6 @@ inline void Script::Archive //qboolean releaseBuffer; } +#endif #endif diff --git a/code/qcommon/str.h b/code/qcommon/str.h index 5fac2d54..716cdd50 100644 --- a/code/qcommon/str.h +++ b/code/qcommon/str.h @@ -164,8 +164,6 @@ class str void SkipPath(); }; -typedef unsigned int const_str; - char *strstrip( char *string ); char *strlwc( char *string ); diff --git a/code/qcommon/tiki.h b/code/qcommon/tiki.h index be9dfb3a..c2c36f47 100644 --- a/code/qcommon/tiki.h +++ b/code/qcommon/tiki.h @@ -145,12 +145,12 @@ typedef struct dloaddef_s { #include "../skeletor/skeletor.h" +#include "../qcommon/tiki_main.h" #include "../tiki/tiki_anim.h" #include "../tiki/tiki_cache.h" #include "../tiki/tiki_commands.h" #include "../tiki/tiki_files.h" #include "../tiki/tiki_imports.h" -#include "../tiki/tiki_main.h" #include "../tiki/tiki_parse.h" #include "../tiki/tiki_skel.h" #include "../tiki/tiki_tag.h" diff --git a/code/tiki/tiki_main.cpp b/code/qcommon/tiki_main.cpp similarity index 98% rename from code/tiki/tiki_main.cpp rename to code/qcommon/tiki_main.cpp index 212333c2..560e206c 100644 --- a/code/tiki/tiki_main.cpp +++ b/code/qcommon/tiki_main.cpp @@ -24,8 +24,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -#include "tiki_shared.h" -#include "dbgheap.h" +#include "../tiki/tiki_shared.h" int cache_numskel = 0; int cache_maxskel = 0; diff --git a/code/tiki/tiki_main.h b/code/qcommon/tiki_main.h similarity index 100% rename from code/tiki/tiki_main.h rename to code/qcommon/tiki_main.h diff --git a/code/qcommon/tiki_script.cpp b/code/qcommon/tiki_script.cpp index 4503c582..1319a95a 100644 --- a/code/qcommon/tiki_script.cpp +++ b/code/qcommon/tiki_script.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include -#include "dbgheap.h" TikiScript *TikiScript::currentScript; diff --git a/code/globalcpp/vector.h b/code/qcommon/vector.h similarity index 99% rename from code/globalcpp/vector.h rename to code/qcommon/vector.h index 2ef46f9a..3385a538 100644 --- a/code/globalcpp/vector.h +++ b/code/qcommon/vector.h @@ -25,8 +25,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #ifndef __VECTOR_H__ #define __VECTOR_H__ -#include -#include +#include +#include +#include //#define X 0 //#define Y 1 diff --git a/code/qcommon/vm.c b/code/qcommon/vm.c deleted file mode 100644 index 2eeb4cc7..00000000 --- a/code/qcommon/vm.c +++ /dev/null @@ -1,888 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vm.c -- virtual machine - -/* - - -intermix code and data -symbol table - -a dll has one imported function: VM_SystemCall -and one exported function: Perform - - -*/ - -#include "vm_local.h" - - -vm_t *currentVM = NULL; -vm_t *lastVM = NULL; -int vm_debugLevel; - -#define MAX_VM 3 -vm_t vmTable[MAX_VM]; - - -void VM_VmInfo_f( void ); -void VM_VmProfile_f( void ); - - - -#if 0 // 64bit! -// converts a VM pointer to a C pointer and -// checks to make sure that the range is acceptable -void *VM_VM2C( vmptr_t p, int length ) { - return (void *)p; -} -#endif - -void VM_Debug( int level ) { - vm_debugLevel = level; -} - -/* -============== -VM_Init -============== -*/ -void VM_Init( void ) { - Cvar_Get( "vm_cgame", "0", CVAR_ARCHIVE ); - Cvar_Get( "vm_game", "0", CVAR_ARCHIVE ); - Cvar_Get( "vm_ui", "0", CVAR_ARCHIVE ); - - Cmd_AddCommand ("vmprofile", VM_VmProfile_f ); - Cmd_AddCommand ("vminfo", VM_VmInfo_f ); - - Com_Memset( vmTable, 0, sizeof( vmTable ) ); -} - - -/* -=============== -VM_ValueToSymbol - -Assumes a program counter value -=============== -*/ -const char *VM_ValueToSymbol( vm_t *vm, int value ) { - vmSymbol_t *sym; - static char text[MAX_TOKEN_CHARS]; - - sym = vm->symbols; - if ( !sym ) { - return "NO SYMBOLS"; - } - - // find the symbol - while ( sym->next && sym->next->symValue <= value ) { - sym = sym->next; - } - - if ( value == sym->symValue ) { - return sym->symName; - } - - Com_sprintf( text, sizeof( text ), "%s+%i", sym->symName, value - sym->symValue ); - - return text; -} - -/* -=============== -VM_ValueToFunctionSymbol - -For profiling, find the symbol behind this value -=============== -*/ -vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ) { - vmSymbol_t *sym; - static vmSymbol_t nullSym; - - sym = vm->symbols; - if ( !sym ) { - return &nullSym; - } - - while ( sym->next && sym->next->symValue <= value ) { - sym = sym->next; - } - - return sym; -} - - -/* -=============== -VM_SymbolToValue -=============== -*/ -int VM_SymbolToValue( vm_t *vm, const char *symbol ) { - vmSymbol_t *sym; - - for ( sym = vm->symbols ; sym ; sym = sym->next ) { - if ( !strcmp( symbol, sym->symName ) ) { - return sym->symValue; - } - } - return 0; -} - - -/* -===================== -VM_SymbolForCompiledPointer -===================== -*/ -#if 0 // 64bit! -const char *VM_SymbolForCompiledPointer( vm_t *vm, void *code ) { - int i; - - if ( code < (void *)vm->codeBase ) { - return "Before code block"; - } - if ( code >= (void *)(vm->codeBase + vm->codeLength) ) { - return "After code block"; - } - - // find which original instruction it is after - for ( i = 0 ; i < vm->codeLength ; i++ ) { - if ( (void *)vm->instructionPointers[i] > code ) { - break; - } - } - i--; - - // now look up the bytecode instruction pointer - return VM_ValueToSymbol( vm, i ); -} -#endif - - - -/* -=============== -ParseHex -=============== -*/ -int ParseHex( const char *text ) { - int value; - int c; - - value = 0; - while ( ( c = *text++ ) != 0 ) { - if ( c >= '0' && c <= '9' ) { - value = value * 16 + c - '0'; - continue; - } - if ( c >= 'a' && c <= 'f' ) { - value = value * 16 + 10 + c - 'a'; - continue; - } - if ( c >= 'A' && c <= 'F' ) { - value = value * 16 + 10 + c - 'A'; - continue; - } - } - - return value; -} - -/* -=============== -VM_LoadSymbols -=============== -*/ -void VM_LoadSymbols( vm_t *vm ) { - int len; - const char *token; - char *mapfile, *text_p; - char name[MAX_QPATH]; - char symbols[MAX_QPATH]; - vmSymbol_t **prev, *sym; - int count; - int value; - int chars; - int segment; - int numInstructions; - - // don't load symbols if not developer - if ( !developer->integer ) { - return; - } - - COM_StripExtension(vm->name, name, sizeof(name)); - Com_sprintf( symbols, sizeof( symbols ), "vm/%s.map", name ); - len = FS_ReadFile( symbols, (void **)&mapfile ); - if ( !mapfile ) { - Com_Printf( "Couldn't load symbol file: %s\n", symbols ); - return; - } - - numInstructions = vm->instructionPointersLength >> 2; - - // parse the symbols - text_p = mapfile; - prev = &vm->symbols; - count = 0; - - while ( 1 ) { - token = COM_Parse( &text_p ); - if ( !token[0] ) { - break; - } - segment = ParseHex( token ); - if ( segment ) { - COM_Parse( &text_p ); - COM_Parse( &text_p ); - continue; // only load code segment values - } - - token = COM_Parse( &text_p ); - if ( !token[0] ) { - Com_Printf( "WARNING: incomplete line at end of file\n" ); - break; - } - value = ParseHex( token ); - - token = COM_Parse( &text_p ); - if ( !token[0] ) { - Com_Printf( "WARNING: incomplete line at end of file\n" ); - break; - } - chars = strlen( token ); - sym = Hunk_Alloc( sizeof( *sym ) + chars, h_high ); - *prev = sym; - prev = &sym->next; - sym->next = NULL; - - // convert value from an instruction number to a code offset - if ( value >= 0 && value < numInstructions ) { - value = vm->instructionPointers[value]; - } - - sym->symValue = value; - Q_strncpyz( sym->symName, token, chars + 1 ); - - count++; - } - - vm->numSymbols = count; - Com_Printf( "%i symbols parsed from %s\n", count, symbols ); - FS_FreeFile( mapfile ); -} - -/* -============ -VM_DllSyscall - -Dlls will call this directly - - rcg010206 The horror; the horror. - - The syscall mechanism relies on stack manipulation to get it's args. - This is likely due to C's inability to pass "..." parameters to - a function in one clean chunk. On PowerPC Linux, these parameters - are not necessarily passed on the stack, so while (&arg[0] == arg) - is true, (&arg[1] == 2nd function parameter) is not necessarily - accurate, as arg's value might have been stored to the stack or - other piece of scratch memory to give it a valid address, but the - next parameter might still be sitting in a register. - - Quake's syscall system also assumes that the stack grows downward, - and that any needed types can be squeezed, safely, into a signed int. - - This hack below copies all needed values for an argument to a - array in memory, so that Quake can get the correct values. This can - also be used on systems where the stack grows upwards, as the - presumably standard and safe stdargs.h macros are used. - - As for having enough space in a signed int for your datatypes, well, - it might be better to wait for DOOM 3 before you start porting. :) - - The original code, while probably still inherently dangerous, seems - to work well enough for the platforms it already works on. Rather - than add the performance hit for those platforms, the original code - is still in use there. - - For speed, we just grab 15 arguments, and don't worry about exactly - how many the syscall actually needs; the extra is thrown away. - -============ -*/ -intptr_t QDECL VM_DllSyscall( intptr_t arg, ... ) { -#if !id386 - // rcg010206 - see commentary above - intptr_t args[16]; - int i; - va_list ap; - - args[0] = arg; - - va_start(ap, arg); - for (i = 1; i < sizeof (args) / sizeof (args[i]); i++) - args[i] = va_arg(ap, intptr_t); - va_end(ap); - - return currentVM->systemCall( args ); -#else // original id code - return currentVM->systemCall( &arg ); -#endif -} - -/* -================= -VM_LoadQVM - -Load a .qvm file -================= -*/ -vmHeader_t *VM_LoadQVM( vm_t *vm, qboolean alloc ) { - int length; - int dataLength; - int i; - char filename[MAX_QPATH]; - vmHeader_t *header; - - // load the image - Com_sprintf( filename, sizeof(filename), "vm/%s.qvm", vm->name ); - Com_Printf( "Loading vm file %s...\n", filename ); - length = FS_ReadFile( filename, (void **)&header ); - if ( !header ) { - Com_Printf( "Failed.\n" ); - VM_Free( vm ); - return NULL; - } - - if( LittleLong( header->vmMagic ) == VM_MAGIC_VER2 ) { - Com_Printf( "...which has vmMagic VM_MAGIC_VER2\n" ); - - // byte swap the header - for ( i = 0 ; i < sizeof( vmHeader_t ) / 4 ; i++ ) { - ((int *)header)[i] = LittleLong( ((int *)header)[i] ); - } - - // validate - if ( header->jtrgLength < 0 - || header->bssLength < 0 - || header->dataLength < 0 - || header->litLength < 0 - || header->codeLength <= 0 ) { - VM_Free( vm ); - Com_Error( ERR_FATAL, "%s has bad header", filename ); - } - } else if( LittleLong( header->vmMagic ) == VM_MAGIC ) { - // byte swap the header - // sizeof( vmHeader_t ) - sizeof( int ) is the 1.32b vm header size - for ( i = 0 ; i < ( sizeof( vmHeader_t ) - sizeof( int ) ) / 4 ; i++ ) { - ((int *)header)[i] = LittleLong( ((int *)header)[i] ); - } - - // validate - if ( header->bssLength < 0 - || header->dataLength < 0 - || header->litLength < 0 - || header->codeLength <= 0 ) { - VM_Free( vm ); - Com_Error( ERR_FATAL, "%s has bad header", filename ); - } - } else { - VM_Free( vm ); - Com_Error( ERR_FATAL, "%s does not have a recognisable " - "magic number in its header", filename ); - } - - // round up to next power of 2 so all data operations can - // be mask protected - dataLength = header->dataLength + header->litLength + header->bssLength; - for ( i = 0 ; dataLength > ( 1 << i ) ; i++ ) { - } - dataLength = 1 << i; - - if( alloc ) { - // allocate zero filled space for initialized and uninitialized data - vm->dataBase = Hunk_Alloc( dataLength, h_high ); - vm->dataMask = dataLength - 1; - } else { - // clear the data - Com_Memset( vm->dataBase, 0, dataLength ); - } - - // copy the intialized data - Com_Memcpy( vm->dataBase, (byte *)header + header->dataOffset, header->dataLength + header->litLength ); - - // byte swap the longs - for ( i = 0 ; i < header->dataLength ; i += 4 ) { - *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) ); - } - - if( header->vmMagic == VM_MAGIC_VER2 ) { - vm->numJumpTableTargets = header->jtrgLength >> 2; - Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets ); - - if( alloc ) { - vm->jumpTableTargets = Hunk_Alloc( header->jtrgLength, h_high ); - } else { - Com_Memset( vm->jumpTableTargets, 0, header->jtrgLength ); - } - - Com_Memcpy( vm->jumpTableTargets, (byte *)header + header->dataOffset + - header->dataLength + header->litLength, header->jtrgLength ); - - // byte swap the longs - for ( i = 0 ; i < header->jtrgLength ; i += 4 ) { - *(int *)(vm->jumpTableTargets + i) = LittleLong( *(int *)(vm->jumpTableTargets + i ) ); - } - } - - return header; -} - -/* -================= -VM_Restart - -Reload the data, but leave everything else in place -This allows a server to do a map_restart without changing memory allocation -================= -*/ -vm_t *VM_Restart( vm_t *vm ) { - vmHeader_t *header; - - // DLL's can't be restarted in place - if ( vm->dllHandle ) { - char name[MAX_QPATH]; - intptr_t (*systemCall)( intptr_t *parms ); - - systemCall = vm->systemCall; - Q_strncpyz( name, vm->name, sizeof( name ) ); - - VM_Free( vm ); - - vm = VM_Create( name, systemCall, VMI_NATIVE ); - return vm; - } - - // load the image - Com_Printf( "VM_Restart()\n" ); - - if( !( header = VM_LoadQVM( vm, qfalse ) ) ) { - Com_Error( ERR_DROP, "VM_Restart failed.\n" ); - return NULL; - } - - // free the original file - FS_FreeFile( header ); - - return vm; -} - -/* -================ -VM_Create - -If image ends in .qvm it will be interpreted, otherwise -it will attempt to load as a system dll -================ -*/ - -#define STACK_SIZE 0x20000 - -vm_t *VM_Create( const char *module, intptr_t (*systemCalls)(intptr_t *), - vmInterpret_t interpret ) { - vm_t *vm; - vmHeader_t *header; - int i, remaining; - - if ( !module || !module[0] || !systemCalls ) { - Com_Error( ERR_FATAL, "VM_Create: bad parms" ); - } - - remaining = Hunk_MemoryRemaining(); - - // see if we already have the VM - for ( i = 0 ; i < MAX_VM ; i++ ) { - if (!Q_stricmp(vmTable[i].name, module)) { - vm = &vmTable[i]; - return vm; - } - } - - // find a free vm - for ( i = 0 ; i < MAX_VM ; i++ ) { - if ( !vmTable[i].name[0] ) { - break; - } - } - - if ( i == MAX_VM ) { - Com_Error( ERR_FATAL, "VM_Create: no free vm_t" ); - } - - vm = &vmTable[i]; - - Q_strncpyz( vm->name, module, sizeof( vm->name ) ); - vm->systemCall = systemCalls; - - if ( interpret == VMI_NATIVE ) { - // try to load as a system dll - Com_Printf( "Loading dll file %s.\n", vm->name ); - vm->dllHandle = Sys_LoadDll( module, vm->fqpath , &vm->entryPoint, VM_DllSyscall ); - if ( vm->dllHandle ) { - return vm; - } - - Com_Printf( "Failed to load dll, looking for qvm.\n" ); - interpret = VMI_COMPILED; - } - - // load the image - if( !( header = VM_LoadQVM( vm, qtrue ) ) ) { - return NULL; - } - - // allocate space for the jump targets, which will be filled in by the compile/prep functions - vm->instructionPointersLength = header->instructionCount * 4; - vm->instructionPointers = Hunk_Alloc( vm->instructionPointersLength, h_high ); - - // copy or compile the instructions - vm->codeLength = header->codeLength; - - vm->compiled = qfalse; - -#ifdef NO_VM_COMPILED - if(interpret >= VMI_COMPILED) { - Com_Printf("Architecture doesn't have a bytecode compiler, using interpreter\n"); - interpret = VMI_BYTECODE; - } -#else - if ( interpret >= VMI_COMPILED ) { - vm->compiled = qtrue; - VM_Compile( vm, header ); - } -#endif - // VM_Compile may have reset vm->compiled if compilation failed - if (!vm->compiled) - { - VM_PrepareInterpreter( vm, header ); - } - - // free the original file - FS_FreeFile( header ); - - // load the map file - VM_LoadSymbols( vm ); - - // the stack is implicitly at the end of the image - vm->programStack = vm->dataMask + 1; - vm->stackBottom = vm->programStack - STACK_SIZE; - - Com_Printf("%s loaded in %d bytes on the hunk\n", module, remaining - Hunk_MemoryRemaining()); - - return vm; -} - -/* -============== -VM_Free -============== -*/ -void VM_Free( vm_t *vm ) { - - if(vm->destroy) - vm->destroy(vm); - - if ( vm->dllHandle ) { - Sys_UnloadDll( vm->dllHandle ); - Com_Memset( vm, 0, sizeof( *vm ) ); - } -#if 0 // now automatically freed by hunk - if ( vm->codeBase ) { - Z_Free( vm->codeBase ); - } - if ( vm->dataBase ) { - Z_Free( vm->dataBase ); - } - if ( vm->instructionPointers ) { - Z_Free( vm->instructionPointers ); - } -#endif - Com_Memset( vm, 0, sizeof( *vm ) ); - - currentVM = NULL; - lastVM = NULL; -} - -void VM_Clear(void) { - int i; - for (i=0;ientryPoint ) { - return (void *)(currentVM->dataBase + intValue); - } - else { - return (void *)(currentVM->dataBase + (intValue & currentVM->dataMask)); - } -} - -void *VM_ExplicitArgPtr( vm_t *vm, intptr_t intValue ) { - if ( !intValue ) { - return NULL; - } - - // currentVM is missing on reconnect here as well? - if ( currentVM==NULL ) - return NULL; - - // - if ( vm->entryPoint ) { - return (void *)(vm->dataBase + intValue); - } - else { - return (void *)(vm->dataBase + (intValue & vm->dataMask)); - } -} - - -/* -============== -VM_Call - - -Upon a system call, the stack will look like: - -sp+32 parm1 -sp+28 parm0 -sp+24 return value -sp+20 return address -sp+16 local1 -sp+14 local0 -sp+12 arg1 -sp+8 arg0 -sp+4 return stack -sp return address - -An interpreted function will immediately execute -an OP_ENTER instruction, which will subtract space for -locals from sp -============== -*/ -#define MAX_STACK 256 -#define STACK_MASK (MAX_STACK-1) - -intptr_t QDECL VM_Call( vm_t *vm, int callnum, ... ) { - vm_t *oldVM; - intptr_t r; - int i; - - if ( !vm ) { - Com_Error( ERR_FATAL, "VM_Call with NULL vm" ); - } - - oldVM = currentVM; - currentVM = vm; - lastVM = vm; - - if ( vm_debugLevel ) { - Com_Printf( "VM_Call( %d )\n", callnum ); - } - - // if we have a dll loaded, call it directly - if ( vm->entryPoint ) { - //rcg010207 - see dissertation at top of VM_DllSyscall() in this file. - int args[10]; - va_list ap; - va_start(ap, callnum); - for (i = 0; i < sizeof (args) / sizeof (args[i]); i++) { - args[i] = va_arg(ap, int); - } - va_end(ap); - - r = vm->entryPoint( callnum, args[0], args[1], args[2], args[3], - args[4], args[5], args[6], args[7], - args[8], args[9]); - } else { -#if id386 // i386 calling convention doesn't need conversion -#ifndef NO_VM_COMPILED - if ( vm->compiled ) - r = VM_CallCompiled( vm, (int*)&callnum ); - else -#endif - r = VM_CallInterpreted( vm, (int*)&callnum ); -#else - struct { - int callnum; - int args[10]; - } a; - va_list ap; - - a.callnum = callnum; - va_start(ap, callnum); - for (i = 0; i < sizeof (a.args) / sizeof (a.args[0]); i++) { - a.args[i] = va_arg(ap, int); - } - va_end(ap); -#ifndef NO_VM_COMPILED - if ( vm->compiled ) - r = VM_CallCompiled( vm, &a.callnum ); - else -#endif - r = VM_CallInterpreted( vm, &a.callnum ); -#endif - } - - if ( oldVM != NULL ) - currentVM = oldVM; - return r; -} - -//================================================================= - -static int QDECL VM_ProfileSort( const void *a, const void *b ) { - vmSymbol_t *sa, *sb; - - sa = *(vmSymbol_t **)a; - sb = *(vmSymbol_t **)b; - - if ( sa->profileCount < sb->profileCount ) { - return -1; - } - if ( sa->profileCount > sb->profileCount ) { - return 1; - } - return 0; -} - -/* -============== -VM_VmProfile_f - -============== -*/ -void VM_VmProfile_f( void ) { - vm_t *vm; - vmSymbol_t **sorted, *sym; - int i; - double total; - - if ( !lastVM ) { - return; - } - - vm = lastVM; - - if ( !vm->numSymbols ) { - return; - } - - sorted = Z_Malloc( vm->numSymbols * sizeof( *sorted ) ); - sorted[0] = vm->symbols; - total = sorted[0]->profileCount; - for ( i = 1 ; i < vm->numSymbols ; i++ ) { - sorted[i] = sorted[i-1]->next; - total += sorted[i]->profileCount; - } - - qsort( sorted, vm->numSymbols, sizeof( *sorted ), VM_ProfileSort ); - - for ( i = 0 ; i < vm->numSymbols ; i++ ) { - int perc; - - sym = sorted[i]; - - perc = 100 * (float) sym->profileCount / total; - Com_Printf( "%2i%% %9i %s\n", perc, sym->profileCount, sym->symName ); - sym->profileCount = 0; - } - - Com_Printf(" %9.0f total\n", total ); - - Z_Free( sorted ); -} - -/* -============== -VM_VmInfo_f - -============== -*/ -void VM_VmInfo_f( void ) { - vm_t *vm; - int i; - - Com_Printf( "Registered virtual machines:\n" ); - for ( i = 0 ; i < MAX_VM ; i++ ) { - vm = &vmTable[i]; - if ( !vm->name[0] ) { - break; - } - Com_Printf( "%s : ", vm->name ); - if ( vm->dllHandle ) { - Com_Printf( "native\n" ); - continue; - } - if ( vm->compiled ) { - Com_Printf( "compiled on load\n" ); - } else { - Com_Printf( "interpreted\n" ); - } - Com_Printf( " code length : %7i\n", vm->codeLength ); - Com_Printf( " table length: %7i\n", vm->instructionPointersLength ); - Com_Printf( " data length : %7i\n", vm->dataMask + 1 ); - } -} - -/* -=============== -VM_LogSyscalls - -Insert calls to this while debugging the vm compiler -=============== -*/ -void VM_LogSyscalls( int *args ) { - static int callnum; - static FILE *f; - - if ( !f ) { - f = fopen("syscalls.log", "w" ); - } - callnum++; - fprintf(f, "%i: %p (%i) = %i %i %i %i\n", callnum, (void*)(args - (int *)currentVM->dataBase), - args[0], args[1], args[2], args[3], args[4] ); -} diff --git a/code/qcommon/vm_interpreted.c b/code/qcommon/vm_interpreted.c deleted file mode 100644 index 3a41e6b7..00000000 --- a/code/qcommon/vm_interpreted.c +++ /dev/null @@ -1,921 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "vm_local.h" - -//#define DEBUG_VM -#ifdef DEBUG_VM -static char *opnames[256] = { - "OP_UNDEF", - - "OP_IGNORE", - - "OP_BREAK", - - "OP_ENTER", - "OP_LEAVE", - "OP_CALL", - "OP_PUSH", - "OP_POP", - - "OP_CONST", - - "OP_LOCAL", - - "OP_JUMP", - - //------------------- - - "OP_EQ", - "OP_NE", - - "OP_LTI", - "OP_LEI", - "OP_GTI", - "OP_GEI", - - "OP_LTU", - "OP_LEU", - "OP_GTU", - "OP_GEU", - - "OP_EQF", - "OP_NEF", - - "OP_LTF", - "OP_LEF", - "OP_GTF", - "OP_GEF", - - //------------------- - - "OP_LOAD1", - "OP_LOAD2", - "OP_LOAD4", - "OP_STORE1", - "OP_STORE2", - "OP_STORE4", - "OP_ARG", - - "OP_BLOCK_COPY", - - //------------------- - - "OP_SEX8", - "OP_SEX16", - - "OP_NEGI", - "OP_ADD", - "OP_SUB", - "OP_DIVI", - "OP_DIVU", - "OP_MODI", - "OP_MODU", - "OP_MULI", - "OP_MULU", - - "OP_BAND", - "OP_BOR", - "OP_BXOR", - "OP_BCOM", - - "OP_LSH", - "OP_RSHI", - "OP_RSHU", - - "OP_NEGF", - "OP_ADDF", - "OP_SUBF", - "OP_DIVF", - "OP_MULF", - - "OP_CVIF", - "OP_CVFI" -}; -#endif - -#if idppc - -//FIXME: these, um... look the same to me -#if defined(__GNUC__) -static ID_INLINE unsigned int loadWord(void *addr) { - unsigned int word; - - asm("lwbrx %0,0,%1" : "=r" (word) : "r" (addr)); - return word; -} -#else -static ID_INLINE unsigned int __lwbrx(register void *addr, - register int offset) { - register unsigned int word; - - asm("lwbrx %0,%2,%1" : "=r" (word) : "r" (addr), "b" (offset)); - return word; -} -#define loadWord(addr) __lwbrx(addr,0) -#endif - -#else - static ID_INLINE int loadWord(void *addr) { - int word; - memcpy(&word, addr, 4); - return LittleLong(word); - } -#endif - -char *VM_Indent( vm_t *vm ) { - static char *string = " "; - if ( vm->callLevel > 20 ) { - return string; - } - return string + 2 * ( 20 - vm->callLevel ); -} - -void VM_StackTrace( vm_t *vm, int programCounter, int programStack ) { - int count; - - count = 0; - do { - Com_Printf( "%s\n", VM_ValueToSymbol( vm, programCounter ) ); - programStack = *(int *)&vm->dataBase[programStack+4]; - programCounter = *(int *)&vm->dataBase[programStack]; - } while ( programCounter != -1 && ++count < 32 ); - -} - - -/* -==================== -VM_PrepareInterpreter -==================== -*/ -void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ) { - int op; - int pc; - byte *code; - int instruction; - int *codeBase; - - vm->codeBase = Hunk_Alloc( vm->codeLength*4, h_high ); // we're now int aligned -// memcpy( vm->codeBase, (byte *)header + header->codeOffset, vm->codeLength ); - - // we don't need to translate the instructions, but we still need - // to find each instructions starting point for jumps - pc = 0; - instruction = 0; - code = (byte *)header + header->codeOffset; - codeBase = (int *)vm->codeBase; - - while ( instruction < header->instructionCount ) { - vm->instructionPointers[ instruction ] = pc; - instruction++; - - op = code[ pc ]; - codeBase[pc] = op; - if ( pc > header->codeLength ) { - Com_Error( ERR_FATAL, "VM_PrepareInterpreter: pc > header->codeLength" ); - } - - pc++; - - // these are the only opcodes that aren't a single byte - switch ( op ) { - case OP_ENTER: - case OP_CONST: - case OP_LOCAL: - case OP_LEAVE: - case OP_EQ: - case OP_NE: - case OP_LTI: - case OP_LEI: - case OP_GTI: - case OP_GEI: - case OP_LTU: - case OP_LEU: - case OP_GTU: - case OP_GEU: - case OP_EQF: - case OP_NEF: - case OP_LTF: - case OP_LEF: - case OP_GTF: - case OP_GEF: - case OP_BLOCK_COPY: - codeBase[pc+0] = loadWord(&code[pc]); - pc += 4; - break; - case OP_ARG: - codeBase[pc+0] = code[pc]; - pc += 1; - break; - default: - break; - } - - } - pc = 0; - instruction = 0; - code = (byte *)header + header->codeOffset; - codeBase = (int *)vm->codeBase; - - while ( instruction < header->instructionCount ) { - op = code[ pc ]; - instruction++; - pc++; - switch ( op ) { - case OP_ENTER: - case OP_CONST: - case OP_LOCAL: - case OP_LEAVE: - case OP_EQ: - case OP_NE: - case OP_LTI: - case OP_LEI: - case OP_GTI: - case OP_GEI: - case OP_LTU: - case OP_LEU: - case OP_GTU: - case OP_GEU: - case OP_EQF: - case OP_NEF: - case OP_LTF: - case OP_LEF: - case OP_GTF: - case OP_GEF: - case OP_BLOCK_COPY: - switch(op) { - case OP_EQ: - case OP_NE: - case OP_LTI: - case OP_LEI: - case OP_GTI: - case OP_GEI: - case OP_LTU: - case OP_LEU: - case OP_GTU: - case OP_GEU: - case OP_EQF: - case OP_NEF: - case OP_LTF: - case OP_LEF: - case OP_GTF: - case OP_GEF: - codeBase[pc] = vm->instructionPointers[codeBase[pc]]; - break; - default: - break; - } - pc += 4; - break; - case OP_ARG: - pc += 1; - break; - default: - break; - } - - } -} - -/* -============== -VM_Call - - -Upon a system call, the stack will look like: - -sp+32 parm1 -sp+28 parm0 -sp+24 return stack -sp+20 return address -sp+16 local1 -sp+14 local0 -sp+12 arg1 -sp+8 arg0 -sp+4 return stack -sp return address - -An interpreted function will immediately execute -an OP_ENTER instruction, which will subtract space for -locals from sp -============== -*/ -#define MAX_STACK 256 -#define STACK_MASK (MAX_STACK-1) - -#define DEBUGSTR va("%s%i", VM_Indent(vm), opStack-stack ) - -int VM_CallInterpreted( vm_t *vm, int *args ) { - int stack[MAX_STACK]; - int *opStack; - int programCounter; - int programStack; - int stackOnEntry; - byte *image; - int *codeImage; - int v1; - int dataMask; -#ifdef DEBUG_VM - vmSymbol_t *profileSymbol; -#endif - - // interpret the code - vm->currentlyInterpreting = qtrue; - - // we might be called recursively, so this might not be the very top - programStack = stackOnEntry = vm->programStack; - -#ifdef DEBUG_VM - profileSymbol = VM_ValueToFunctionSymbol( vm, 0 ); - // uncomment this for debugging breakpoints - vm->breakFunction = 0; -#endif - // set up the stack frame - - image = vm->dataBase; - codeImage = (int *)vm->codeBase; - dataMask = vm->dataMask; - - // leave a free spot at start of stack so - // that as long as opStack is valid, opStack-1 will - // not corrupt anything - opStack = stack; - programCounter = 0; - - programStack -= 48; - - *(int *)&image[ programStack + 44] = args[9]; - *(int *)&image[ programStack + 40] = args[8]; - *(int *)&image[ programStack + 36] = args[7]; - *(int *)&image[ programStack + 32] = args[6]; - *(int *)&image[ programStack + 28] = args[5]; - *(int *)&image[ programStack + 24] = args[4]; - *(int *)&image[ programStack + 20] = args[3]; - *(int *)&image[ programStack + 16] = args[2]; - *(int *)&image[ programStack + 12] = args[1]; - *(int *)&image[ programStack + 8 ] = args[0]; - *(int *)&image[ programStack + 4 ] = 0; // return stack - *(int *)&image[ programStack ] = -1; // will terminate the loop on return - - vm->callLevel = 0; - - VM_Debug(0); - -// vm_debugLevel=2; - // main interpreter loop, will exit when a LEAVE instruction - // grabs the -1 program counter - -#define r2 codeImage[programCounter] - - while ( 1 ) { - int opcode, r0, r1; -// unsigned int r2; - -nextInstruction: - r0 = ((int *)opStack)[0]; - r1 = ((int *)opStack)[-1]; -nextInstruction2: -#ifdef DEBUG_VM - if ( (unsigned)programCounter >= vm->codeLength ) { - Com_Error( ERR_DROP, "VM pc out of range" ); - } - - if ( opStack < stack ) { - Com_Error( ERR_DROP, "VM opStack underflow" ); - } - if ( opStack >= stack+MAX_STACK ) { - Com_Error( ERR_DROP, "VM opStack overflow" ); - } - - if ( programStack <= vm->stackBottom ) { - Com_Error( ERR_DROP, "VM stack overflow" ); - } - - if ( programStack & 3 ) { - Com_Error( ERR_DROP, "VM program stack misaligned" ); - } - - if ( vm_debugLevel > 1 ) { - Com_Printf( "%s %s\n", DEBUGSTR, opnames[opcode] ); - } - profileSymbol->profileCount++; -#endif - opcode = codeImage[ programCounter++ ]; - - switch ( opcode ) { -#ifdef DEBUG_VM - default: - Com_Error( ERR_DROP, "Bad VM instruction" ); // this should be scanned on load! -#endif - case OP_BREAK: - vm->breakCount++; - goto nextInstruction2; - case OP_CONST: - opStack++; - r1 = r0; - r0 = *opStack = r2; - - programCounter += 4; - goto nextInstruction2; - case OP_LOCAL: - opStack++; - r1 = r0; - r0 = *opStack = r2+programStack; - - programCounter += 4; - goto nextInstruction2; - - case OP_LOAD4: -#ifdef DEBUG_VM - if ( *opStack & 3 ) { - Com_Error( ERR_DROP, "OP_LOAD4 misaligned" ); - } -#endif - r0 = *opStack = *(int *)&image[ r0&dataMask ]; - goto nextInstruction2; - case OP_LOAD2: - r0 = *opStack = *(unsigned short *)&image[ r0&dataMask ]; - goto nextInstruction2; - case OP_LOAD1: - r0 = *opStack = image[ r0&dataMask ]; - goto nextInstruction2; - - case OP_STORE4: - *(int *)&image[ r1&(dataMask & ~3) ] = r0; - opStack -= 2; - goto nextInstruction; - case OP_STORE2: - *(short *)&image[ r1&(dataMask & ~1) ] = r0; - opStack -= 2; - goto nextInstruction; - case OP_STORE1: - image[ r1&dataMask ] = r0; - opStack -= 2; - goto nextInstruction; - - case OP_ARG: - // single byte offset from programStack - *(int *)&image[ codeImage[programCounter] + programStack ] = r0; - opStack--; - programCounter += 1; - goto nextInstruction; - - case OP_BLOCK_COPY: - { - int *src, *dest; - int i, count, srci, desti; - - count = r2; - // MrE: copy range check - srci = r0 & dataMask; - desti = r1 & dataMask; - count = ((srci + count) & dataMask) - srci; - count = ((desti + count) & dataMask) - desti; - - src = (int *)&image[ r0&dataMask ]; - dest = (int *)&image[ r1&dataMask ]; - if ( ( (intptr_t)src | (intptr_t)dest | count ) & 3 ) { - // happens in westernq3 - Com_Printf( S_COLOR_YELLOW "Warning: OP_BLOCK_COPY not dword aligned\n"); - } - count >>= 2; - for ( i = count-1 ; i>= 0 ; i-- ) { - dest[i] = src[i]; - } - programCounter += 4; - opStack -= 2; - } - goto nextInstruction; - - case OP_CALL: - // save current program counter - *(int *)&image[ programStack ] = programCounter; - - // jump to the location on the stack - programCounter = r0; - opStack--; - if ( programCounter < 0 ) { - // system call - int r; - int temp; -#ifdef DEBUG_VM - int stomped; - - if ( vm_debugLevel ) { - Com_Printf( "%s---> systemcall(%i)\n", DEBUGSTR, -1 - programCounter ); - } -#endif - // save the stack to allow recursive VM entry - temp = vm->callLevel; - vm->programStack = programStack - 4; -#ifdef DEBUG_VM - stomped = *(int *)&image[ programStack + 4 ]; -#endif - *(int *)&image[ programStack + 4 ] = -1 - programCounter; - -//VM_LogSyscalls( (int *)&image[ programStack + 4 ] ); - { - intptr_t* argptr = (intptr_t *)&image[ programStack + 4 ]; - #if __WORDSIZE == 64 - // the vm has ints on the stack, we expect - // longs so we have to convert it - intptr_t argarr[16]; - int i; - for (i = 0; i < 16; ++i) { - argarr[i] = *(int*)&image[ programStack + 4 + 4*i ]; - } - argptr = argarr; - #endif - r = vm->systemCall( argptr ); - } - -#ifdef DEBUG_VM - // this is just our stack frame pointer, only needed - // for debugging - *(int *)&image[ programStack + 4 ] = stomped; -#endif - - // save return value - opStack++; - *opStack = r; - programCounter = *(int *)&image[ programStack ]; - vm->callLevel = temp; -#ifdef DEBUG_VM - if ( vm_debugLevel ) { - Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) ); - } -#endif - } else if ( (unsigned)programCounter >= vm->codeLength ) { - Com_Error( ERR_DROP, "VM program counter out of range in OP_CALL" ); - } else { - programCounter = vm->instructionPointers[ programCounter ]; - } - goto nextInstruction; - - // push and pop are only needed for discarded or bad function return values - case OP_PUSH: - opStack++; - goto nextInstruction; - case OP_POP: - opStack--; - goto nextInstruction; - - case OP_ENTER: -#ifdef DEBUG_VM - profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter ); -#endif - // get size of stack frame - v1 = r2; - - programCounter += 4; - programStack -= v1; -#ifdef DEBUG_VM - // save old stack frame for debugging traces - *(int *)&image[programStack+4] = programStack + v1; - if ( vm_debugLevel ) { - Com_Printf( "%s---> %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter - 5 ) ); - if ( vm->breakFunction && programCounter - 5 == vm->breakFunction ) { - // this is to allow setting breakpoints here in the debugger - vm->breakCount++; -// vm_debugLevel = 2; -// VM_StackTrace( vm, programCounter, programStack ); - } - vm->callLevel++; - } -#endif - goto nextInstruction; - case OP_LEAVE: - // remove our stack frame - v1 = r2; - - programStack += v1; - - // grab the saved program counter - programCounter = *(int *)&image[ programStack ]; -#ifdef DEBUG_VM - profileSymbol = VM_ValueToFunctionSymbol( vm, programCounter ); - if ( vm_debugLevel ) { - vm->callLevel--; - Com_Printf( "%s<--- %s\n", DEBUGSTR, VM_ValueToSymbol( vm, programCounter ) ); - } -#endif - // check for leaving the VM - if ( programCounter == -1 ) { - goto done; - } else if ( (unsigned)programCounter >= vm->codeLength ) { - Com_Error( ERR_DROP, "VM program counter out of range in OP_LEAVE" ); - } - goto nextInstruction; - - /* - =================================================================== - BRANCHES - =================================================================== - */ - - case OP_JUMP: - programCounter = r0; - programCounter = vm->instructionPointers[ programCounter ]; - opStack--; - goto nextInstruction; - - case OP_EQ: - opStack -= 2; - if ( r1 == r0 ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_NE: - opStack -= 2; - if ( r1 != r0 ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_LTI: - opStack -= 2; - if ( r1 < r0 ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_LEI: - opStack -= 2; - if ( r1 <= r0 ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_GTI: - opStack -= 2; - if ( r1 > r0 ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_GEI: - opStack -= 2; - if ( r1 >= r0 ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_LTU: - opStack -= 2; - if ( ((unsigned)r1) < ((unsigned)r0) ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_LEU: - opStack -= 2; - if ( ((unsigned)r1) <= ((unsigned)r0) ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_GTU: - opStack -= 2; - if ( ((unsigned)r1) > ((unsigned)r0) ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_GEU: - opStack -= 2; - if ( ((unsigned)r1) >= ((unsigned)r0) ) { - programCounter = r2; //vm->instructionPointers[r2]; - goto nextInstruction; - } else { - programCounter += 4; - goto nextInstruction; - } - - case OP_EQF: - if ( ((float *)opStack)[-1] == *(float *)opStack ) { - programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; - goto nextInstruction; - } else { - programCounter += 4; - opStack -= 2; - goto nextInstruction; - } - - case OP_NEF: - if ( ((float *)opStack)[-1] != *(float *)opStack ) { - programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; - goto nextInstruction; - } else { - programCounter += 4; - opStack -= 2; - goto nextInstruction; - } - - case OP_LTF: - if ( ((float *)opStack)[-1] < *(float *)opStack ) { - programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; - goto nextInstruction; - } else { - programCounter += 4; - opStack -= 2; - goto nextInstruction; - } - - case OP_LEF: - if ( ((float *)opStack)[-1] <= *(float *)opStack ) { - programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; - goto nextInstruction; - } else { - programCounter += 4; - opStack -= 2; - goto nextInstruction; - } - - case OP_GTF: - if ( ((float *)opStack)[-1] > *(float *)opStack ) { - programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; - goto nextInstruction; - } else { - programCounter += 4; - opStack -= 2; - goto nextInstruction; - } - - case OP_GEF: - if ( ((float *)opStack)[-1] >= *(float *)opStack ) { - programCounter = r2; //vm->instructionPointers[r2]; - opStack -= 2; - goto nextInstruction; - } else { - programCounter += 4; - opStack -= 2; - goto nextInstruction; - } - - - //=================================================================== - - case OP_NEGI: - *opStack = -r0; - goto nextInstruction; - case OP_ADD: - opStack[-1] = r1 + r0; - opStack--; - goto nextInstruction; - case OP_SUB: - opStack[-1] = r1 - r0; - opStack--; - goto nextInstruction; - case OP_DIVI: - opStack[-1] = r1 / r0; - opStack--; - goto nextInstruction; - case OP_DIVU: - opStack[-1] = ((unsigned)r1) / ((unsigned)r0); - opStack--; - goto nextInstruction; - case OP_MODI: - opStack[-1] = r1 % r0; - opStack--; - goto nextInstruction; - case OP_MODU: - opStack[-1] = ((unsigned)r1) % (unsigned)r0; - opStack--; - goto nextInstruction; - case OP_MULI: - opStack[-1] = r1 * r0; - opStack--; - goto nextInstruction; - case OP_MULU: - opStack[-1] = ((unsigned)r1) * ((unsigned)r0); - opStack--; - goto nextInstruction; - - case OP_BAND: - opStack[-1] = ((unsigned)r1) & ((unsigned)r0); - opStack--; - goto nextInstruction; - case OP_BOR: - opStack[-1] = ((unsigned)r1) | ((unsigned)r0); - opStack--; - goto nextInstruction; - case OP_BXOR: - opStack[-1] = ((unsigned)r1) ^ ((unsigned)r0); - opStack--; - goto nextInstruction; - case OP_BCOM: - *opStack = ~ ((unsigned)r0); - goto nextInstruction; - - case OP_LSH: - opStack[-1] = r1 << r0; - opStack--; - goto nextInstruction; - case OP_RSHI: - opStack[-1] = r1 >> r0; - opStack--; - goto nextInstruction; - case OP_RSHU: - opStack[-1] = ((unsigned)r1) >> r0; - opStack--; - goto nextInstruction; - - case OP_NEGF: - *(float *)opStack = -*(float *)opStack; - goto nextInstruction; - case OP_ADDF: - *(float *)(opStack-1) = *(float *)(opStack-1) + *(float *)opStack; - opStack--; - goto nextInstruction; - case OP_SUBF: - *(float *)(opStack-1) = *(float *)(opStack-1) - *(float *)opStack; - opStack--; - goto nextInstruction; - case OP_DIVF: - *(float *)(opStack-1) = *(float *)(opStack-1) / *(float *)opStack; - opStack--; - goto nextInstruction; - case OP_MULF: - *(float *)(opStack-1) = *(float *)(opStack-1) * *(float *)opStack; - opStack--; - goto nextInstruction; - - case OP_CVIF: - *(float *)opStack = (float)*opStack; - goto nextInstruction; - case OP_CVFI: - *opStack = (int) *(float *)opStack; - goto nextInstruction; - case OP_SEX8: - *opStack = (signed char)*opStack; - goto nextInstruction; - case OP_SEX16: - *opStack = (short)*opStack; - goto nextInstruction; - } - } - -done: - vm->currentlyInterpreting = qfalse; - - if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "Interpreter error: opStack = %ld", (long int) (opStack - stack) ); - } - - vm->programStack = stackOnEntry; - - // return the result - return *opStack; -} diff --git a/code/qcommon/vm_local.h b/code/qcommon/vm_local.h deleted file mode 100644 index 8e81b369..00000000 --- a/code/qcommon/vm_local.h +++ /dev/null @@ -1,183 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -#include "q_shared.h" -#include "qcommon.h" - -typedef enum { - OP_UNDEF, - - OP_IGNORE, - - OP_BREAK, - - OP_ENTER, - OP_LEAVE, - OP_CALL, - OP_PUSH, - OP_POP, - - OP_CONST, - OP_LOCAL, - - OP_JUMP, - - //------------------- - - OP_EQ, - OP_NE, - - OP_LTI, - OP_LEI, - OP_GTI, - OP_GEI, - - OP_LTU, - OP_LEU, - OP_GTU, - OP_GEU, - - OP_EQF, - OP_NEF, - - OP_LTF, - OP_LEF, - OP_GTF, - OP_GEF, - - //------------------- - - OP_LOAD1, - OP_LOAD2, - OP_LOAD4, - OP_STORE1, - OP_STORE2, - OP_STORE4, // *(stack[top-1]) = stack[top] - OP_ARG, - - OP_BLOCK_COPY, - - //------------------- - - OP_SEX8, - OP_SEX16, - - OP_NEGI, - OP_ADD, - OP_SUB, - OP_DIVI, - OP_DIVU, - OP_MODI, - OP_MODU, - OP_MULI, - OP_MULU, - - OP_BAND, - OP_BOR, - OP_BXOR, - OP_BCOM, - - OP_LSH, - OP_RSHI, - OP_RSHU, - - OP_NEGF, - OP_ADDF, - OP_SUBF, - OP_DIVF, - OP_MULF, - - OP_CVIF, - OP_CVFI -} opcode_t; - - - -typedef int vmptr_t; - -typedef struct vmSymbol_s { - struct vmSymbol_s *next; - int symValue; - int profileCount; - char symName[1]; // variable sized -} vmSymbol_t; - -#define VM_OFFSET_PROGRAM_STACK 0 -#define VM_OFFSET_SYSTEM_CALL 4 - -struct vm_s { - // DO NOT MOVE OR CHANGE THESE WITHOUT CHANGING THE VM_OFFSET_* DEFINES - // USED BY THE ASM CODE - int programStack; // the vm may be recursively entered - intptr_t (*systemCall)( intptr_t *parms ); - - //------------------------------------ - - char name[MAX_QPATH]; - - // for dynamic linked modules - void *dllHandle; - intptr_t (QDECL *entryPoint)( int callNum, ... ); - void (*destroy)(vm_t* self); - - // for interpreted modules - qboolean currentlyInterpreting; - - qboolean compiled; - byte *codeBase; - int codeLength; - - int *instructionPointers; - int instructionPointersLength; - - byte *dataBase; - int dataMask; - - int stackBottom; // if programStack < stackBottom, error - - int numSymbols; - struct vmSymbol_s *symbols; - - int callLevel; // for debug indenting - int breakFunction; // increment breakCount on function entry to this - int breakCount; - - char fqpath[MAX_QPATH+1] ; - - byte *jumpTableTargets; - int numJumpTableTargets; -}; - - -extern vm_t *currentVM; -extern int vm_debugLevel; - -void VM_Compile( vm_t *vm, vmHeader_t *header ); -int VM_CallCompiled( vm_t *vm, int *args ); - -void VM_PrepareInterpreter( vm_t *vm, vmHeader_t *header ); -int VM_CallInterpreted( vm_t *vm, int *args ); - -vmSymbol_t *VM_ValueToFunctionSymbol( vm_t *vm, int value ); -int VM_SymbolToValue( vm_t *vm, const char *symbol ); -const char *VM_ValueToSymbol( vm_t *vm, int value ); -void VM_LogSyscalls( int *args ); - diff --git a/code/qcommon/vm_none.c b/code/qcommon/vm_none.c deleted file mode 100644 index c7e5ba08..00000000 --- a/code/qcommon/vm_none.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "vm_local.h" - -int VM_CallCompiled( vm_t *vm, int *args ) { - exit(99); - return 0; -} - -void VM_Compile( vm_t *vm, vmHeader_t *header ) { - exit(99); -} diff --git a/code/qcommon/vm_ppc.c b/code/qcommon/vm_ppc.c deleted file mode 100644 index c0b1add9..00000000 --- a/code/qcommon/vm_ppc.c +++ /dev/null @@ -1,2064 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vm_ppc.c -// ppc dynamic compiler - -#include "vm_local.h" -#include - -#define DEBUG_VM 0 - -#if DEBUG_VM -static char *opnames[256] = { - "OP_UNDEF", - - "OP_IGNORE", - - "OP_BREAK", - - "OP_ENTER", - "OP_LEAVE", - "OP_CALL", - "OP_PUSH", - "OP_POP", - - "OP_CONST", - - "OP_LOCAL", - - "OP_JUMP", - - //------------------- - - "OP_EQ", - "OP_NE", - - "OP_LTI", - "OP_LEI", - "OP_GTI", - "OP_GEI", - - "OP_LTU", - "OP_LEU", - "OP_GTU", - "OP_GEU", - - "OP_EQF", - "OP_NEF", - - "OP_LTF", - "OP_LEF", - "OP_GTF", - "OP_GEF", - - //------------------- - - "OP_LOAD1", - "OP_LOAD2", - "OP_LOAD4", - "OP_STORE1", - "OP_STORE2", - "OP_STORE4", - "OP_ARG", - - "OP_BLOCK_COPY", - - //------------------- - - "OP_SEX8", - "OP_SEX16", - - "OP_NEGI", - "OP_ADD", - "OP_SUB", - "OP_DIVI", - "OP_DIVU", - "OP_MODI", - "OP_MODU", - "OP_MULI", - "OP_MULU", - - "OP_BAND", - "OP_BOR", - "OP_BXOR", - "OP_BCOM", - - "OP_LSH", - "OP_RSHI", - "OP_RSHU", - - "OP_NEGF", - "OP_ADDF", - "OP_SUBF", - "OP_DIVF", - "OP_MULF", - - "OP_CVIF", - "OP_CVFI" -}; -#endif - -typedef enum { - R_REAL_STACK = 1, - // registers 3-11 are the parameter passing registers - - // state - R_STACK = 3, // local - R_OPSTACK, // global - - // constants - R_MEMBASE, // global - R_MEMMASK, - R_ASMCALL, // global - R_INSTRUCTIONS, // global - R_NUM_INSTRUCTIONS, // global - R_CVM, // currentVM - - // temps - R_TOP = 11, - R_SECOND = 12, - R_EA = 2 // effective address calculation - -} regNums_t; - -#define RG_REAL_STACK r1 -#define RG_STACK r3 -#define RG_OPSTACK r4 -#define RG_MEMBASE r5 -#define RG_MEMMASK r6 -#define RG_ASMCALL r7 -#define RG_INSTRUCTIONS r8 -#define RG_NUM_INSTRUCTIONS r9 -#define RG_CVM r10 -#define RG_TOP r12 -#define RG_SECOND r13 -#define RG_EA r14 - -// The deepest value I saw in the Quake3 games was 9. -#define OP_STACK_MAX_DEPTH 16 - -// These are all volatile and thus must be saved upon entry to the VM code. -// NOTE: These are General Purpose Registers (GPR) numbers like the -// R_ definitions in the regNums_t enum above (31 is the max) -static int opStackIntRegisters[OP_STACK_MAX_DEPTH] = -{ - 16, 17, 18, 19, - 20, 21, 22, 23, - 24, 25, 26, 27, - 28, 29, 30, 31 -}; - -static unsigned int *opStackLoadInstructionAddr[OP_STACK_MAX_DEPTH]; - -// We use different registers for the floating point -// operand stack (these are volatile in the PPC ABI) -// NOTE: these are Floating Point Register (FPR) numbers, not -// General Purpose Register (GPR) numbers -static int opStackFloatRegisters[OP_STACK_MAX_DEPTH] = -{ - 0, 1, 2, 3, - 4, 5, 6, 7, - 8, 9, 10, 11, - 12, 13, 14, 15 -}; - -static int opStackRegType[OP_STACK_MAX_DEPTH] = -{ - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 -}; - -// this doesn't have the low order bits set for instructions i'm not using... -typedef enum { - PPC_TDI = 0x08000000, - PPC_TWI = 0x0c000000, - PPC_MULLI = 0x1c000000, - PPC_SUBFIC = 0x20000000, - PPC_CMPI = 0x28000000, - PPC_CMPLI = 0x2c000000, - PPC_ADDIC = 0x30000000, - PPC_ADDIC_ = 0x34000000, - PPC_ADDI = 0x38000000, - PPC_ADDIS = 0x3c000000, - PPC_BC = 0x40000000, - PPC_SC = 0x44000000, - PPC_B = 0x48000000, - - PPC_MCRF = 0x4c000000, - PPC_BCLR = 0x4c000020, - PPC_RFID = 0x4c000000, - PPC_CRNOR = 0x4c000000, - PPC_RFI = 0x4c000000, - PPC_CRANDC = 0x4c000000, - PPC_ISYNC = 0x4c000000, - PPC_CRXOR = 0x4c000000, - PPC_CRNAND = 0x4c000000, - PPC_CREQV = 0x4c000000, - PPC_CRORC = 0x4c000000, - PPC_CROR = 0x4c000000, -//------------ - PPC_BCCTR = 0x4c000420, - PPC_RLWIMI = 0x50000000, - PPC_RLWINM = 0x54000000, - PPC_RLWNM = 0x5c000000, - PPC_ORI = 0x60000000, - PPC_ORIS = 0x64000000, - PPC_XORI = 0x68000000, - PPC_XORIS = 0x6c000000, - PPC_ANDI_ = 0x70000000, - PPC_ANDIS_ = 0x74000000, - PPC_RLDICL = 0x78000000, - PPC_RLDICR = 0x78000000, - PPC_RLDIC = 0x78000000, - PPC_RLDIMI = 0x78000000, - PPC_RLDCL = 0x78000000, - PPC_RLDCR = 0x78000000, - PPC_CMP = 0x7c000000, - PPC_TW = 0x7c000000, - PPC_SUBFC = 0x7c000010, - PPC_MULHDU = 0x7c000000, - PPC_ADDC = 0x7c000014, - PPC_MULHWU = 0x7c000000, - PPC_MFCR = 0x7c000000, - PPC_LWAR = 0x7c000000, - PPC_LDX = 0x7c000000, - PPC_LWZX = 0x7c00002e, - PPC_SLW = 0x7c000030, - PPC_CNTLZW = 0x7c000000, - PPC_SLD = 0x7c000000, - PPC_AND = 0x7c000038, - PPC_CMPL = 0x7c000040, - PPC_SUBF = 0x7c000050, - PPC_LDUX = 0x7c000000, -//------------ - PPC_DCBST = 0x7c000000, - PPC_LWZUX = 0x7c00006c, - PPC_CNTLZD = 0x7c000000, - PPC_ANDC = 0x7c000000, - PPC_TD = 0x7c000000, - PPC_MULHD = 0x7c000000, - PPC_MULHW = 0x7c000000, - PPC_MTSRD = 0x7c000000, - PPC_MFMSR = 0x7c000000, - PPC_LDARX = 0x7c000000, - PPC_DCBF = 0x7c000000, - PPC_LBZX = 0x7c0000ae, - PPC_NEG = 0x7c000000, - PPC_MTSRDIN = 0x7c000000, - PPC_LBZUX = 0x7c000000, - PPC_NOR = 0x7c0000f8, - PPC_SUBFE = 0x7c000000, - PPC_ADDE = 0x7c000000, - PPC_MTCRF = 0x7c000000, - PPC_MTMSR = 0x7c000000, - PPC_STDX = 0x7c000000, - PPC_STWCX_ = 0x7c000000, - PPC_STWX = 0x7c00012e, - PPC_MTMSRD = 0x7c000000, - PPC_STDUX = 0x7c000000, - PPC_STWUX = 0x7c00016e, - PPC_SUBFZE = 0x7c000000, - PPC_ADDZE = 0x7c000000, - PPC_MTSR = 0x7c000000, - PPC_STDCX_ = 0x7c000000, - PPC_STBX = 0x7c0001ae, - PPC_SUBFME = 0x7c000000, - PPC_MULLD = 0x7c000000, -//------------ - PPC_ADDME = 0x7c000000, - PPC_MULLW = 0x7c0001d6, - PPC_MTSRIN = 0x7c000000, - PPC_DCBTST = 0x7c000000, - PPC_STBUX = 0x7c000000, - PPC_ADD = 0x7c000214, - PPC_DCBT = 0x7c000000, - PPC_LHZX = 0x7c00022e, - PPC_EQV = 0x7c000000, - PPC_TLBIE = 0x7c000000, - PPC_ECIWX = 0x7c000000, - PPC_LHZUX = 0x7c000000, - PPC_XOR = 0x7c000278, - PPC_MFSPR = 0x7c0002a6, - PPC_LWAX = 0x7c000000, - PPC_LHAX = 0x7c000000, - PPC_TLBIA = 0x7c000000, - PPC_MFTB = 0x7c000000, - PPC_LWAUX = 0x7c000000, - PPC_LHAUX = 0x7c000000, - PPC_STHX = 0x7c00032e, - PPC_ORC = 0x7c000338, - PPC_SRADI = 0x7c000000, - PPC_SLBIE = 0x7c000000, - PPC_ECOWX = 0x7c000000, - PPC_STHUX = 0x7c000000, - PPC_OR = 0x7c000378, - PPC_DIVDU = 0x7c000000, - PPC_DIVWU = 0x7c000396, - PPC_MTSPR = 0x7c0003a6, - PPC_DCBI = 0x7c000000, - PPC_NAND = 0x7c000000, - PPC_DIVD = 0x7c000000, -//------------ - PPC_DIVW = 0x7c0003d6, - PPC_SLBIA = 0x7c000000, - PPC_MCRXR = 0x7c000000, - PPC_LSWX = 0x7c000000, - PPC_LWBRX = 0x7c000000, - PPC_LFSX = 0x7c00042e, - PPC_SRW = 0x7c000430, - PPC_SRD = 0x7c000000, - PPC_TLBSYNC = 0x7c000000, - PPC_LFSUX = 0x7c000000, - PPC_MFSR = 0x7c000000, - PPC_LSWI = 0x7c000000, - PPC_SYNC = 0x7c000000, - PPC_LFDX = 0x7c000000, - PPC_LFDUX = 0x7c000000, - PPC_MFSRIN = 0x7c000000, - PPC_STSWX = 0x7c000000, - PPC_STWBRX = 0x7c000000, - PPC_STFSX = 0x7c00052e, - PPC_STFSUX = 0x7c000000, - PPC_STSWI = 0x7c000000, - PPC_STFDX = 0x7c000000, - PPC_DCBA = 0x7c000000, - PPC_STFDUX = 0x7c000000, - PPC_LHBRX = 0x7c000000, - PPC_SRAW = 0x7c000630, - PPC_SRAD = 0x7c000000, - PPC_SRAWI = 0x7c000000, - PPC_EIEIO = 0x7c000000, - PPC_STHBRX = 0x7c000000, - PPC_EXTSH = 0x7c000734, - PPC_EXTSB = 0x7c000774, - PPC_ICBI = 0x7c000000, -//------------ - PPC_STFIWX = 0x7c0007ae, - PPC_EXTSW = 0x7c000000, - PPC_DCBZ = 0x7c000000, - PPC_LWZ = 0x80000000, - PPC_LWZU = 0x84000000, - PPC_LBZ = 0x88000000, - PPC_LBZU = 0x8c000000, - PPC_STW = 0x90000000, - PPC_STWU = 0x94000000, - PPC_STB = 0x98000000, - PPC_STBU = 0x9c000000, - PPC_LHZ = 0xa0000000, - PPC_LHZU = 0xa4000000, - PPC_LHA = 0xa8000000, - PPC_LHAU = 0xac000000, - PPC_STH = 0xb0000000, - PPC_STHU = 0xb4000000, - PPC_LMW = 0xb8000000, - PPC_STMW = 0xbc000000, - PPC_LFS = 0xc0000000, - PPC_LFSU = 0xc4000000, - PPC_LFD = 0xc8000000, - PPC_LFDU = 0xcc000000, - PPC_STFS = 0xd0000000, - PPC_STFSU = 0xd4000000, - PPC_STFD = 0xd8000000, - PPC_STFDU = 0xdc000000, - PPC_LD = 0xe8000000, - PPC_LDU = 0xe8000001, - PPC_LWA = 0xe8000002, - PPC_FDIVS = 0xec000024, - PPC_FSUBS = 0xec000028, - PPC_FADDS = 0xec00002a, -//------------ - PPC_FSQRTS = 0xec000000, - PPC_FRES = 0xec000000, - PPC_FMULS = 0xec000032, - PPC_FMSUBS = 0xec000000, - PPC_FMADDS = 0xec000000, - PPC_FNMSUBS = 0xec000000, - PPC_FNMADDS = 0xec000000, - PPC_STD = 0xf8000000, - PPC_STDU = 0xf8000001, - PPC_FCMPU = 0xfc000000, - PPC_FRSP = 0xfc000018, - PPC_FCTIW = 0xfc000000, - PPC_FCTIWZ = 0xfc00001e, - PPC_FDIV = 0xfc000000, - PPC_FSUB = 0xfc000028, - PPC_FADD = 0xfc000000, - PPC_FSQRT = 0xfc000000, - PPC_FSEL = 0xfc000000, - PPC_FMUL = 0xfc000000, - PPC_FRSQRTE = 0xfc000000, - PPC_FMSUB = 0xfc000000, - PPC_FMADD = 0xfc000000, - PPC_FNMSUB = 0xfc000000, - PPC_FNMADD = 0xfc000000, - PPC_FCMPO = 0xfc000000, - PPC_MTFSB1 = 0xfc000000, - PPC_FNEG = 0xfc000050, - PPC_MCRFS = 0xfc000000, - PPC_MTFSB0 = 0xfc000000, - PPC_FMR = 0xfc000000, - PPC_MTFSFI = 0xfc000000, - PPC_FNABS = 0xfc000000, - PPC_FABS = 0xfc000000, -//------------ - PPC_MFFS = 0xfc000000, - PPC_MTFSF = 0xfc000000, - PPC_FCTID = 0xfc000000, - PPC_FCTIDZ = 0xfc000000, - PPC_FCFID = 0xfc000000 - -} ppcOpcodes_t; - - -// the newly generated code -static unsigned *buf; -static int compiledOfs; // in dwords -static int pass; - -// fromt the original bytecode -static byte *code; -static int pc; - -void AsmCall( void ); - -double itofConvert[2]; - -static int Constant4( void ) { - int v; - - v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24); - pc += 4; - return v; -} - -static int Constant1( void ) { - int v; - - v = code[pc]; - pc += 1; - return v; -} - -static void Emit4( char *opname, int i ) { - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\t%08lx\n",&buf[compiledOfs],opname,i&0x3ffffff); - #endif - buf[ compiledOfs ] = i; - compiledOfs++; -} - -static void Inst( char *opname, int opcode, int destReg, int aReg, int bReg ) { - unsigned r; - - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static void Inst4( char *opname, int opcode, int destReg, int aReg, int bReg, int cReg ) { - unsigned r; - - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,r%d,r%d\n",&buf[compiledOfs],opname,destReg,aReg,bReg,cReg); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) | ( cReg << 6 ); - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static void InstImm( char *opname, int opcode, int destReg, int aReg, int immediate ) { - unsigned r; - - if ( immediate > 32767 || immediate < -32768 ) { - Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range, opcode %x,%d,%d", immediate, opcode, destReg, aReg ); - } - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static void InstImmU( char *opname, int opcode, int destReg, int aReg, int immediate ) { - unsigned r; - - if ( immediate > 0xffff || immediate < 0 ) { - Com_Error( ERR_FATAL, "VM_Compile: immediate value %i out of range", immediate ); - } - #if DEBUG_VM - if(pass == 1) - printf("\t\t\t%p %s\tr%d,r%d,0x%x\n",&buf[compiledOfs],opname,destReg,aReg,immediate); - #endif - r = opcode | ( destReg << 21 ) | ( aReg << 16 ) | ( immediate & 0xffff ); - buf[ compiledOfs ] = r; - compiledOfs++; -} - -static int pop0, pop1, oc0, oc1; -static vm_t *tvm; -static int instruction; -static byte *jused; - -static void spillOpStack(int depth) -{ - // Store out each register on the operand stack to it's correct location. - int i; - - for(i = 0; i < depth; i++) - { - assert(opStackRegType[i]); - assert(opStackRegType[i] == 1); - switch(opStackRegType[i]) - { - case 1: // Integer register - InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_OPSTACK, i*4+4); - break; - case 2: // Float register - InstImm( "stfs", PPC_STFS, opStackFloatRegisters[i], R_OPSTACK, i*4+4); - break; - } - opStackRegType[i] = 0; - } -} - -static void loadOpStack(int depth) -{ - // Back off operand stack pointer and reload all operands. -// InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -(depth)*4 ); - - int i; - - for(i = 0; i < depth; i++) - { - assert(opStackRegType[i] == 0); - // For now we're stuck reloading everything as an integer. - opStackLoadInstructionAddr[i] = &buf[compiledOfs]; - InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_OPSTACK, i*4+4); - opStackRegType[i] = 1; - } -} - -static void makeFloat(int depth) -{ - //assert(opStackRegType[depth] == 1); - if(opStackRegType[depth] == 1) - { - unsigned instruction; - unsigned destReg, aReg, bReg, imm; - - if(opStackLoadInstructionAddr[depth]) - { - // Repatch load instruction to use LFS instead of LWZ - instruction = *opStackLoadInstructionAddr[depth]; - // Figure out if it's LWZ or LWZX - if((instruction & 0xfc000000) == PPC_LWZ) - { - //printf("patching LWZ at %p to LFS at depth %ld\n",opStackLoadInstructionAddr[depth],depth); - //printf("old instruction: %08lx\n",instruction); - // Extract registers - destReg = (instruction >> 21) & 31; - aReg = (instruction >> 16) & 31; - imm = instruction & 0xffff; - - // Calculate correct FP register to use. - // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc! - //printf("old dest: %ld\n",destReg); - destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0]; - instruction = PPC_LFS | ( destReg << 21 ) | ( aReg << 16 ) | imm ; - //printf("new dest: %ld\n",destReg); - //printf("new instruction: %08lx\n",instruction); - } - else - { - //printf("patching LWZX at %p to LFSX at depth %ld\n",opStackLoadInstructionAddr[depth],depth); - //printf("old instruction: %08lx\n",instruction); - // Extract registers - destReg = (instruction >> 21) & 31; - aReg = (instruction >> 16) & 31; - bReg = (instruction >> 11) & 31; - // Calculate correct FP register to use. - // THIS ASSUMES REGISTER USAGE FOR THE STACK IS n, n+1, n+2, etc! - //printf("old dest: %ld\n",destReg); - destReg = (destReg - opStackIntRegisters[0]) + opStackFloatRegisters[0]; - instruction = PPC_LFSX | ( destReg << 21 ) | ( aReg << 16 ) | ( bReg << 11 ) ; - //printf("new dest: %ld\n",destReg); - //printf("new instruction: %08lx\n",instruction); - } - *opStackLoadInstructionAddr[depth] = instruction; - opStackLoadInstructionAddr[depth] = 0; - } - else - { - //printf("doing float constant load at %p for depth %ld\n",&buf[compiledOfs],depth); - // It was likely loaded as a constant so we have to save/load it. A more - // interesting implementation might be to generate code to do a "PC relative" - // load from the VM code region. - InstImm( "stw", PPC_STW, opStackIntRegisters[depth], R_OPSTACK, depth*4+4); - // For XXX make sure we force enough NOPs to get the load into - // another dispatch group to avoid pipeline flush. - Inst( "ori", PPC_ORI, 0, 0, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0 ); - InstImm( "lfs", PPC_LFS, opStackFloatRegisters[depth], R_OPSTACK, depth*4+4); - } - opStackRegType[depth] = 2; - } -} - -// TJW: Unused -#if 0 -static void fltop() { - if (rtopped == qfalse) { - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - } -} -#endif - -#if 0 -static void fltopandsecond() { - InstImm( PPC_LFS, R_TOP, R_OPSTACK, 0 ); // get value from opstack - InstImm( PPC_LFS, R_SECOND, R_OPSTACK, -4 ); // get value from opstack - InstImm( PPC_ADDI, R_OPSTACK, R_OPSTACK, -8 ); - rtopped = qfalse; - return; -} -#endif - -#define assertInteger(depth) assert(opStackRegType[depth] == 1) - -/* -================= -VM_Compile -================= -*/ -void VM_Compile( vm_t *vm, vmHeader_t *header ) { - int op; - int maxLength; - int v; - int i; - int opStackDepth; - - int mainFunction; - - // set up the into-to-float variables - ((int *)itofConvert)[0] = 0x43300000; - ((int *)itofConvert)[1] = 0x80000000; - ((int *)itofConvert)[2] = 0x43300000; - - // allocate a very large temp buffer, we will shrink it later - maxLength = header->codeLength * 8; - buf = Z_Malloc( maxLength ); - jused = Z_Malloc(header->instructionCount + 2); - Com_Memset(jused, 0, header->instructionCount+2); - - // compile everything twice, so the second pass will have valid instruction - // pointers for branches - for ( pass = -1 ; pass < 2 ; pass++ ) { - - // translate all instructions - pc = 0; - mainFunction = 0; - opStackDepth = 0; - - pop0 = 343545; - pop1 = 2443545; - oc0 = -2343535; - oc1 = 24353454; - tvm = vm; - code = (byte *)header + header->codeOffset; - compiledOfs = 0; -#ifndef __GNUC__ - // metrowerks seems to require this header in front of functions - Emit4( (int)(buf+2) ); - Emit4( 0 ); -#endif - - for ( instruction = 0 ; instruction < header->instructionCount ; instruction++ ) { - if ( compiledOfs*4 > maxLength - 16 ) { - Com_Error( ERR_DROP, "VM_Compile: maxLength exceeded" ); - } - - op = code[ pc ]; - if ( !pass ) { - vm->instructionPointers[ instruction ] = compiledOfs * 4; - } - pc++; - switch ( op ) { - case 0: - break; - case OP_BREAK: - #if DEBUG_VM - if(pass == 1) - printf("%08lx BREAK\n",instruction); - #endif - InstImmU( "addi", PPC_ADDI, R_TOP, 0, 0 ); - InstImm( "lwz", PPC_LWZ, R_TOP, R_TOP, 0 ); // *(int *)0 to crash to debugger - break; - case OP_ENTER: - opStackDepth = 0; - v = Constant4(); - #if DEBUG_VM - if(pass == 1) - printf("%08x ENTER\t%04x\n",instruction,v); - #endif - opStackRegType[opStackDepth] = 0; - mainFunction++; - if(mainFunction == 1) - { - // Main VM entry point is the first thing we compile, so save off operand stack - // registers here. This avoids issues with trying to trick the native compiler - // into doing it, and properly matches the PowerPC ABI - InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, -OP_STACK_MAX_DEPTH*4 ); // sub R_STACK, R_STACK, imm - for(i = 0; i < OP_STACK_MAX_DEPTH; i++) - InstImm( "stw", PPC_STW, opStackIntRegisters[i], R_REAL_STACK, i*4); - } - InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, -v ); // sub R_STACK, R_STACK, imm - break; - case OP_CONST: - v = Constant4(); - #if DEBUG_VM - if(pass == 1) - printf("%08x CONST\t%08x\n",instruction,v); - #endif - opStackLoadInstructionAddr[opStackDepth] = 0; - if ( v < 32768 && v >= -32768 ) { - InstImmU( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], 0, v & 0xffff ); - } else { - InstImmU( "addis", PPC_ADDIS, opStackIntRegisters[opStackDepth], 0, (v >> 16)&0xffff ); - if ( v & 0xffff ) { - InstImmU( "ori", PPC_ORI, opStackIntRegisters[opStackDepth], opStackIntRegisters[opStackDepth], v & 0xffff ); - } - } - opStackRegType[opStackDepth] = 1; - opStackDepth += 1; - if (code[pc] == OP_JUMP) { - jused[v] = 1; - } - break; - case OP_LOCAL: - oc1 = Constant4(); - #if DEBUG_VM - if(pass == 1) - printf("%08x LOCAL\t%08x\n",instruction,oc1); - #endif - if (code[pc] == OP_LOAD4 || code[pc] == OP_LOAD2 || code[pc] == OP_LOAD1) { - oc1 &= vm->dataMask; - } - InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth], R_STACK, oc1 ); - opStackRegType[opStackDepth] = 1; - opStackLoadInstructionAddr[opStackDepth] = 0; - opStackDepth += 1; - break; - case OP_ARG: - v = Constant1(); - #if DEBUG_VM - if(pass == 1) - printf("%08x ARG \t%08x\n",instruction,v); - #endif - InstImm( "addi", PPC_ADDI, R_EA, R_STACK, v ); // location to put it - if(opStackRegType[opStackDepth-1] == 1) - Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], R_EA, R_MEMBASE ); - else - Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], R_EA, R_MEMBASE ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - - break; - case OP_CALL: - #if DEBUG_VM - if(pass == 1) - printf("%08x CALL\n",instruction); - #endif - assertInteger(opStackDepth-1); - assert(opStackDepth > 0); - Inst( "mflr", PPC_MFSPR, R_SECOND, 8, 0 ); // move from link register - InstImm( "stwu", PPC_STWU, R_SECOND, R_REAL_STACK, -16 ); // save off the old return address - - // Spill operand stack registers. - spillOpStack(opStackDepth); - - // We need to leave R_OPSTACK pointing to the top entry on the stack, which is the call address. - // It will be consumed (and R4 decremented) by the AsmCall code. - InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4); - - Inst( "mtctr", PPC_MTSPR, R_ASMCALL, 9, 0 ); // move to count register - Inst( "bctrl", PPC_BCCTR | 1, 20, 0, 0 ); // jump and link to the count register - - // R4 now points to the top of the operand stack, which has the return value in it. We want to - // back off the pointer to point to the base of our local operand stack and then reload the stack. - - InstImm("addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4); - - // Reload operand stack. - loadOpStack(opStackDepth); - - InstImm( "lwz", PPC_LWZ, R_SECOND, R_REAL_STACK, 0 ); // fetch the old return address - InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, 16 ); - Inst( "mtlr", PPC_MTSPR, R_SECOND, 8, 0 ); // move to link register - break; - case OP_PUSH: - #if DEBUG_VM - if(pass == 1) - printf("%08x PUSH\n",instruction); - #endif - opStackRegType[opStackDepth] = 1; // Garbage int value. - opStackDepth += 1; - break; - case OP_POP: - #if DEBUG_VM - if(pass == 1) - printf("%08x POP\n",instruction); - #endif - opStackDepth -= 1; - opStackRegType[opStackDepth] = 0; // ?? - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_LEAVE: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEAVE\n",instruction); - #endif - assert(opStackDepth == 1); - assert(opStackRegType[0] != 0); - // Save return value onto top of op stack. We also have to increment R_OPSTACK - switch(opStackRegType[0]) - { - case 1: // Integer register - InstImm( "stw", PPC_STWU, opStackIntRegisters[0], R_OPSTACK, 4); - break; - case 2: // Float register - InstImm( "stfs", PPC_STFSU, opStackFloatRegisters[0], R_OPSTACK, 4); - break; - } - InstImm( "addi", PPC_ADDI, R_STACK, R_STACK, Constant4() ); // add R_STACK, R_STACK, imm - if(mainFunction == 1) - { - for(i = 0; i < OP_STACK_MAX_DEPTH; i++) - InstImm( "lwz", PPC_LWZ, opStackIntRegisters[i], R_REAL_STACK, i*4); - InstImm( "addi", PPC_ADDI, R_REAL_STACK, R_REAL_STACK, OP_STACK_MAX_DEPTH*4 ); - } - opStackDepth--; - opStackRegType[opStackDepth] = 0; - opStackLoadInstructionAddr[opStackDepth] = 0; - Inst( "blr", PPC_BCLR, 20, 0, 0 ); // branch unconditionally to link register - break; - case OP_LOAD4: - #if DEBUG_VM - if(pass == 1) - printf("%08x LOAD4\n",instruction); - #endif - // We should try to figure out whether to use LWZX or LFSX based - // on some kind of code analysis after subsequent passes. I think what - // we could do is store the compiled load instruction address along with - // the register type. When we hit the first mismatched operator, we go back - // and patch the load. Since LCC's operand stack should be at 0 depth by the - // time we hit a branch, this should work fairly well. FIXME FIXME FIXME. - assertInteger(opStackDepth-1); - opStackLoadInstructionAddr[opStackDepth-1] = &buf[ compiledOfs ]; - Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base - opStackRegType[opStackDepth-1] = 1; - break; - case OP_LOAD2: - #if DEBUG_VM - if(pass == 1) - printf("%08x LOAD2\n",instruction); - #endif - assertInteger(opStackDepth-1); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - Inst( "lhzx", PPC_LHZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base - opStackRegType[opStackDepth-1] = 1; - break; - case OP_LOAD1: - #if DEBUG_VM - if(pass == 1) - printf("%08x LOAD1\n",instruction); - #endif - assertInteger(opStackDepth-1); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - Inst( "lbzx", PPC_LBZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE );// load from memory base - opStackRegType[opStackDepth-1] = 1; - break; - case OP_STORE4: - #if DEBUG_VM - if(pass == 1) - printf("%08x STORE4\n",instruction); - #endif - assertInteger(opStackDepth-2); - if(opStackRegType[opStackDepth-1] == 1) - Inst( "stwx", PPC_STWX, opStackIntRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - else - Inst( "stfsx", PPC_STFSX, opStackFloatRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - case OP_STORE2: - #if DEBUG_VM - if(pass == 1) - printf("%08x STORE2\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "sthx", PPC_STHX, opStackIntRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - case OP_STORE1: - #if DEBUG_VM - if(pass == 1) - printf("%08x STORE1\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "stbx", PPC_STBX, opStackIntRegisters[opStackDepth-1], - opStackIntRegisters[opStackDepth-2], R_MEMBASE ); // store from memory base - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - - case OP_EQ: - #if DEBUG_VM - if(pass == 1) - printf("%08x EQ\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (v&0x3ffffff) ); - break; - case OP_NE: - #if DEBUG_VM - if(pass == 1) - printf("%08x NE\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 2, v ); - - break; - case OP_LTI: - #if DEBUG_VM - if(pass == 1) - printf("%08x LTI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 0, v ); - break; - case OP_LEI: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 1, v ); - break; - case OP_GTI: - #if DEBUG_VM - if(pass == 1) - printf("%08x GTI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 1, v ); - break; - case OP_GEI: - #if DEBUG_VM - if(pass == 1) - printf("%08x GEI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmp", PPC_CMP, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 0, v ); - break; - case OP_LTU: - #if DEBUG_VM - if(pass == 1) - printf("%08x LTU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 0, v ); - break; - case OP_LEU: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 1, v ); - break; - case OP_GTU: - #if DEBUG_VM - if(pass == 1) - printf("%08x GTU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 1, v ); - break; - case OP_GEU: - #if DEBUG_VM - if(pass == 1) - printf("%08x GEU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "cmpl", PPC_CMPL, 0, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 0, v ); - break; - - case OP_EQF: - #if DEBUG_VM - if(pass == 1) - printf("%08x EQF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 2, v ); - break; - case OP_NEF: - #if DEBUG_VM - if(pass == 1) - printf("%08x NEF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 2, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 2, v ); - break; - case OP_LTF: - #if DEBUG_VM - if(pass == 1) - printf("%08x LTF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 0, v ); - break; - case OP_LEF: - #if DEBUG_VM - if(pass == 1) - printf("%08x LEF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 1, v ); - break; - case OP_GTF: - #if DEBUG_VM - if(pass == 1) - printf("%08x GTF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 4, 1, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 12, 1, v ); - break; - case OP_GEF: - #if DEBUG_VM - if(pass == 1) - printf("%08x GEF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fcmpu", PPC_FCMPU, 0, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - i = Constant4(); - jused[i] = 1; - InstImm( "bc", PPC_BC, 12, 0, 8 ); - if ( pass==1 ) { - v = vm->instructionPointers[ i ] - (int)&buf[compiledOfs]; - } else { - v = 0; - } - Emit4("b", PPC_B | (unsigned int)(v&0x3ffffff) ); -// InstImm( "bc", PPC_BC, 4, 0, v ); - break; - - case OP_NEGI: - #if DEBUG_VM - if(pass == 1) - printf("%08x NEGI\n",instruction); - #endif - assertInteger(opStackDepth-1); - InstImm( "subfic", PPC_SUBFIC, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_ADD: - #if DEBUG_VM - if(pass == 1) - printf("%08x ADD\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_SUB: - #if DEBUG_VM - if(pass == 1) - printf("%08x SUB\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_DIVI: - #if DEBUG_VM - if(pass == 1) - printf("%08x DIVI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divw", PPC_DIVW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_DIVU: - #if DEBUG_VM - if(pass == 1) - printf("%08x DIVU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divwu", PPC_DIVWU, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MODI: - #if DEBUG_VM - if(pass == 1) - printf("%08x MODI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divw", PPC_DIVW, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA ); - Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MODU: - #if DEBUG_VM - if(pass == 1) - printf("%08x MODU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "divwu", PPC_DIVWU, R_EA, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - Inst( "mullw", PPC_MULLW, R_EA, opStackIntRegisters[opStackDepth-1], R_EA ); - Inst( "subf", PPC_SUBF, opStackIntRegisters[opStackDepth-2], R_EA, opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MULI: - case OP_MULU: - #if DEBUG_VM - if(pass == 1) - printf("%08x MULI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "mullw", PPC_MULLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-2] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BAND: - #if DEBUG_VM - if(pass == 1) - printf("%08x BAND\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "and", PPC_AND, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BOR: - #if DEBUG_VM - if(pass == 1) - printf("%08x BOR\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "or", PPC_OR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BXOR: - #if DEBUG_VM - if(pass == 1) - printf("%08x BXOR\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "xor", PPC_XOR, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_BCOM: - #if DEBUG_VM - if(pass == 1) - printf("%08x BCOM\n",instruction); - #endif - assertInteger(opStackDepth-1); - Inst( "nor", PPC_NOR, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1] ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_LSH: - #if DEBUG_VM - if(pass == 1) - printf("%08x LSH\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "slw", PPC_SLW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_RSHI: - #if DEBUG_VM - if(pass == 1) - printf("%08x RSHI\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "sraw", PPC_SRAW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_RSHU: - #if DEBUG_VM - if(pass == 1) - printf("%08x RSHU\n",instruction); - #endif - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - Inst( "srw", PPC_SRW, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - - case OP_NEGF: - #if DEBUG_VM - if(pass == 1) - printf("%08x NEGF\n",instruction); - #endif - makeFloat(opStackDepth-1); - Inst( "fneg", PPC_FNEG, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_ADDF: - #if DEBUG_VM - if(pass == 1) - printf("%08x ADDF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fadds", PPC_FADDS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_SUBF: - #if DEBUG_VM - if(pass == 1) - printf("%08x SUBF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fsubs", PPC_FSUBS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_DIVF: - #if DEBUG_VM - if(pass == 1) - printf("%08x DIVF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst( "fdivs", PPC_FDIVS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - case OP_MULF: - #if DEBUG_VM - if(pass == 1) - printf("%08x MULF\n",instruction); - #endif - makeFloat(opStackDepth-1); - makeFloat(opStackDepth-2); - Inst4( "fmuls", PPC_FMULS, opStackFloatRegisters[opStackDepth-2], opStackFloatRegisters[opStackDepth-2], 0, opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - - case OP_CVIF: - #if DEBUG_VM - if(pass == 1) - printf("%08x CVIF\n",instruction); - #endif - assertInteger(opStackDepth-1); - //makeInteger(opStackDepth-1); - v = (int)&itofConvert; - InstImmU( "addis", PPC_ADDIS, R_EA, 0, (v >> 16)&0xffff ); - InstImmU( "ori", PPC_ORI, R_EA, R_EA, v & 0xffff ); - InstImmU( "xoris", PPC_XORIS, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0x8000 ); - InstImm( "stw", PPC_STW, opStackIntRegisters[opStackDepth-1], R_EA, 12 ); - InstImm( "lfd", PPC_LFD, opStackFloatRegisters[opStackDepth-1], R_EA, 0 ); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - InstImm( "lfd", PPC_LFD, 13, R_EA, 8 ); - Inst( "fsub", PPC_FSUB, opStackFloatRegisters[opStackDepth-1], 13, opStackFloatRegisters[opStackDepth-1] ); - opStackRegType[opStackDepth-1] = 2; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - // Inst( PPC_FRSP, R_TOP, 0, R_TOP ); - break; - case OP_CVFI: - #if DEBUG_VM - if(pass == 1) - printf("%08x CVFI\n",instruction); - #endif - makeFloat(opStackDepth-1); - - InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, opStackDepth*4); - - Inst( "fctiwz", PPC_FCTIWZ, opStackFloatRegisters[opStackDepth-1], 0, opStackFloatRegisters[opStackDepth-1] ); - Inst( "stfiwx", PPC_STFIWX, opStackFloatRegisters[opStackDepth-1], 0, R_OPSTACK ); // save value to opstack (dummy area now) - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - Inst( "ori", PPC_ORI, 0, 0, 0); - InstImm( "lwz", PPC_LWZ, opStackIntRegisters[opStackDepth-1], R_OPSTACK, 0 ); - - InstImm( "addi", PPC_ADDI, R_OPSTACK, R_OPSTACK, -opStackDepth*4); - - opStackRegType[opStackDepth-1] = 1; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_SEX8: - #if DEBUG_VM - if(pass == 1) - printf("%08x SEX8\n",instruction); - #endif - assertInteger(opStackDepth-1); - Inst( "extsb", PPC_EXTSB, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - case OP_SEX16: - #if DEBUG_VM - if(pass == 1) - printf("%08x SEX16\n",instruction); - #endif - assertInteger(opStackDepth-1); - Inst( "extsh", PPC_EXTSH, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 0 ); - opStackLoadInstructionAddr[opStackDepth-1] = 0; - break; - - case OP_BLOCK_COPY: - v = Constant4() >> 2; - #if DEBUG_VM - if(pass == 1) - printf("%08x BLOCK_COPY\t%08lx\n",instruction,v<<2); - #endif - assert(opStackDepth >= 2); - assertInteger(opStackDepth-1); - assertInteger(opStackDepth-2); - InstImmU( "addi", PPC_ADDI, R_EA, 0, v ); // count - // FIXME: range check - Inst( "mtctr", PPC_MTSPR, R_EA, 9, 0 ); // move to count register - - Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_MEMBASE ); - InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], -4 ); - Inst( "add", PPC_ADD, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], R_MEMBASE ); - InstImm( "addi", PPC_ADDI, opStackIntRegisters[opStackDepth-2], opStackIntRegisters[opStackDepth-2], -4 ); - - InstImm( "lwzu", PPC_LWZU, R_EA, opStackIntRegisters[opStackDepth-1], 4 ); // source - InstImm( "stwu", PPC_STWU, R_EA, opStackIntRegisters[opStackDepth-2], 4 ); // dest - Inst( "b", PPC_BC | 0xfff8 , 16, 0, 0 ); // loop - opStackRegType[opStackDepth-1] = 0; - opStackRegType[opStackDepth-2] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-2] = 0; - opStackDepth -= 2; - break; - - case OP_JUMP: - #if DEBUG_VM - if(pass == 1) - printf("%08x JUMP\n",instruction); - #endif - assert(opStackDepth == 1); - assertInteger(opStackDepth-1); - - Inst( "rlwinm", PPC_RLWINM | ( 29 << 1 ), opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], 2 ); - // FIXME: range check - Inst( "lwzx", PPC_LWZX, opStackIntRegisters[opStackDepth-1], opStackIntRegisters[opStackDepth-1], R_INSTRUCTIONS ); - Inst( "mtctr", PPC_MTSPR, opStackIntRegisters[opStackDepth-1], 9, 0 ); // move to count register - Inst( "bctr", PPC_BCCTR, 20, 0, 0 ); // jump to the count register - opStackRegType[opStackDepth-1] = 0; - opStackLoadInstructionAddr[opStackDepth-1] = 0; - opStackDepth -= 1; - break; - default: - Com_Error( ERR_DROP, "VM_CompilePPC: bad opcode %i at instruction %i, offset %i", op, instruction, pc ); - } - pop0 = pop1; - pop1 = op; - assert(opStackDepth >= 0); - assert(opStackDepth < OP_STACK_MAX_DEPTH); - - //printf("%4d\t%s\n",opStackDepth,opnames[op]); - } - - Com_Printf( "VM file %s pass %d compiled to %i bytes of code\n", vm->name, (pass+1), compiledOfs*4 ); - - if ( pass == 0 ) { - // copy to an exact size buffer on the hunk - vm->codeLength = compiledOfs * 4; - vm->codeBase = Hunk_Alloc( vm->codeLength, h_low ); - Com_Memcpy( vm->codeBase, buf, vm->codeLength ); - - //printf("codeBase: %p\n",vm->codeBase); - - Z_Free( buf ); - - // offset all the instruction pointers for the new location - for ( i = 0 ; i < header->instructionCount ; i++ ) { - vm->instructionPointers[i] += (int)vm->codeBase; - //printf("%08x %08lx\n",i,vm->instructionPointers[i]); - } - - // go back over it in place now to fixup reletive jump targets - buf = (unsigned *)vm->codeBase; - } else if ( pass == 1 ) { - // clear the instruction cache for generated code - msync(vm->codeBase, vm->codeLength, MS_INVALIDATE); - } - } - if(0) - { - char buf[256]; - printf("wait..\n"); - gets(buf); - } - Z_Free( jused ); -} - -/* -============== -VM_CallCompiled - -This function is called directly by the generated code -============== -*/ -int VM_CallCompiled( vm_t *vm, int *args ) { - int stack[1024]; - int programStack; - int stackOnEntry; - byte *image; - - currentVM = vm; - - //printf("VM_CallCompiled: %p %08lx %08lx %08lx\n", - // vm, args[0],args[1],args[2]); - - // interpret the code - vm->currentlyInterpreting = qtrue; - - // we might be called recursively, so this might not be the very top - programStack = vm->programStack; - stackOnEntry = programStack; - image = vm->dataBase; - - // set up the stack frame - programStack -= 48; - - *(int *)&image[ programStack + 44] = args[9]; - *(int *)&image[ programStack + 40] = args[8]; - *(int *)&image[ programStack + 36] = args[7]; - *(int *)&image[ programStack + 32] = args[6]; - *(int *)&image[ programStack + 28] = args[5]; - *(int *)&image[ programStack + 24] = args[4]; - *(int *)&image[ programStack + 20] = args[3]; - *(int *)&image[ programStack + 16] = args[2]; - *(int *)&image[ programStack + 12] = args[1]; - *(int *)&image[ programStack + 8 ] = args[0]; - *(int *)&image[ programStack + 4 ] = 0; // return stack - *(int *)&image[ programStack ] = -1; // will terminate the loop on return - - // Cheesy... manually save registers used by VM call... - // off we go into generated code... - // the PPC calling standard says the parms will all go into R3 - R11, so - // no special asm code is needed here -#ifdef __GNUC__ - ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( - programStack, (int)&stack, - (int)image, vm->dataMask, (int)&AsmCall, - (int)vm->instructionPointers, vm->instructionPointersLength, - (int)vm ); -#else - ((void(*)(int, int, int, int, int, int, int, int))(vm->codeBase))( - programStack, (int)&stack, - (int)image, vm->dataMask, *(int *)&AsmCall /* skip function pointer header */, - (int)vm->instructionPointers, vm->instructionPointersLength, - (int)vm ); -#endif - vm->programStack = stackOnEntry; - - vm->currentlyInterpreting = qfalse; - - return stack[1]; -} - - -/* -================== -AsmCall - -Put this at end of file because gcc messes up debug line numbers -================== -*/ -#ifdef __GNUC__ - -void AsmCall( void ) { -asm ( - // pop off the destination instruction -" lwz r12,0(r4) \n" // RG_TOP, 0(RG_OPSTACK) -" addi r4,r4,-4 \n" // RG_OPSTACK, RG_OPSTACK, -4 \n" - - // see if it is a system trap -" cmpwi r12,0 \n" // RG_TOP, 0 \n" -" bc 12,0, systemTrap \n" - - // calling another VM function, so lookup in instructionPointers -" slwi r12,r12,2 \n" // RG_TOP,RG_TOP,2 - // FIXME: range check -" lwzx r12, r8, r12 \n" // RG_TOP, RG_INSTRUCTIONS(RG_TOP) -" mtctr r12 \n" // RG_TOP -); - -#if defined(MACOS_X) && defined(__OPTIMIZE__) - // On Mac OS X, gcc doesn't push a frame when we are optimized, so trying to tear it down results in grave disorder. -//#warning Mac OS X optimization on, not popping GCC AsmCall frame -#else - // Mac OS X Server and unoptimized compiles include a GCC AsmCall frame - asm ( -" lwz r1,0(r1) \n" // pop off the GCC AsmCall frame -" lmw r30,-8(r1) \n" -); -#endif - -asm ( -" bcctr 20,0 \n" // when it hits a leave, it will branch to the current link register - - // calling a system trap -"systemTrap: \n" - // convert to positive system call number -" subfic r12,r12,-1 \n" - - // save all our registers, including the current link register -" mflr r13 \n" // RG_SECOND // copy off our link register -" addi r1,r1,-92 \n" // required 24 byets of linkage, 32 bytes of parameter, plus our saves -" stw r3,56(r1) \n" // RG_STACK, -36(REAL_STACK) -" stw r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK) -" stw r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK) -" stw r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK) -" stw r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK) -" stw r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK) -" stw r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) -" stw r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK) -" stw r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) // link register - - // save the vm stack position to allow recursive VM entry -" addi r13,r3,-4 \n" // RG_TOP, RG_STACK, -4 -" stw r13,0(r10) \n" //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM) - - // save the system call number as the 0th parameter -" add r3,r3,r5 \n" // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls -" stwu r12,4(r3) \n" // RG_TOP, 4(r3) - - // make the system call with the address of all the VM parms as a parameter - // vm->systemCalls( &parms ) -" lwz r12,4(r10) \n" // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM) -" mtctr r12 \n" // RG_TOP -" bcctrl 20,0 \n" -" mr r12,r3 \n" // RG_TOP, r3 - - // pop our saved registers -" lwz r3,56(r1) \n" // RG_STACK, 0(RG_REAL_STACK) -" lwz r4,60(r1) \n" // RG_OPSTACK, 4(RG_REAL_STACK) -" lwz r5,64(r1) \n" // RG_MEMBASE, 8(RG_REAL_STACK) -" lwz r6,68(r1) \n" // RG_MEMMASK, 12(RG_REAL_STACK) -" lwz r7,72(r1) \n" // RG_ASMCALL, 16(RG_REAL_STACK) -" lwz r8,76(r1) \n" // RG_INSTRUCTIONS, 20(RG_REAL_STACK) -" lwz r9,80(r1) \n" // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) -" lwz r10,84(r1) \n" // RG_VM, 28(RG_REAL_STACK) -" lwz r13,88(r1) \n" // RG_SECOND, 32(RG_REAL_STACK) -" addi r1,r1,92 \n" // RG_REAL_STACK, RG_REAL_STACK, 36 - - // restore the old link register -" mtlr r13 \n" // RG_SECOND - - // save off the return value -" stwu r12,4(r4) \n" // RG_TOP, 0(RG_OPSTACK) - - // GCC adds its own prolog / epliog code - ); -} -#else - -// codewarrior version - -void asm AsmCall( void ) { - - // pop off the destination instruction - - lwz r12,0(r4) // RG_TOP, 0(RG_OPSTACK) - - addi r4,r4,-4 // RG_OPSTACK, RG_OPSTACK, -4 - - - - // see if it is a system trap - - cmpwi r12,0 // RG_TOP, 0 - - bc 12,0, systemTrap - - - - // calling another VM function, so lookup in instructionPointers - - slwi r12,r12,2 // RG_TOP,RG_TOP,2 - - // FIXME: range check - - lwzx r12, r8, r12 // RG_TOP, RG_INSTRUCTIONS(RG_TOP) - - mtctr r12 // RG_TOP - - - - bcctr 20,0 // when it hits a leave, it will branch to the current link register - - - - // calling a system trap - -systemTrap: - - // convert to positive system call number - - subfic r12,r12,-1 - - - - // save all our registers, including the current link register - - mflr r13 // RG_SECOND // copy off our link register - - addi r1,r1,-92 // required 24 byets of linkage, 32 bytes of parameter, plus our saves - - stw r3,56(r1) // RG_STACK, -36(REAL_STACK) - - stw r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK) - - stw r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK) - - stw r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK) - - stw r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK) - - stw r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK) - - stw r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) - - stw r10,84(r1) // RG_VM, 28(RG_REAL_STACK) - - stw r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) // link register - - - - // save the vm stack position to allow recursive VM entry - - addi r13,r3,-4 // RG_TOP, RG_STACK, -4 - - stw r13,0(r10) //RG_TOP, VM_OFFSET_PROGRAM_STACK(RG_VM) - - - - // save the system call number as the 0th parameter - - add r3,r3,r5 // r3, RG_STACK, RG_MEMBASE // r3 is the first parameter to vm->systemCalls - - stwu r12,4(r3) // RG_TOP, 4(r3) - - - - // make the system call with the address of all the VM parms as a parameter - - // vm->systemCalls( &parms ) - - lwz r12,4(r10) // RG_TOP, VM_OFFSET_SYSTEM_CALL(RG_VM) - - - - // perform macos cross fragment fixup crap - - lwz r9,0(r12) - - stw r2,52(r1) // save old TOC - - lwz r2,4(r12) - - - - mtctr r9 // RG_TOP - - bcctrl 20,0 - - - - lwz r2,52(r1) // restore TOC - - - - mr r12,r3 // RG_TOP, r3 - - - - // pop our saved registers - - lwz r3,56(r1) // RG_STACK, 0(RG_REAL_STACK) - - lwz r4,60(r1) // RG_OPSTACK, 4(RG_REAL_STACK) - - lwz r5,64(r1) // RG_MEMBASE, 8(RG_REAL_STACK) - - lwz r6,68(r1) // RG_MEMMASK, 12(RG_REAL_STACK) - - lwz r7,72(r1) // RG_ASMCALL, 16(RG_REAL_STACK) - - lwz r8,76(r1) // RG_INSTRUCTIONS, 20(RG_REAL_STACK) - - lwz r9,80(r1) // RG_NUM_INSTRUCTIONS, 24(RG_REAL_STACK) - - lwz r10,84(r1) // RG_VM, 28(RG_REAL_STACK) - - lwz r13,88(r1) // RG_SECOND, 32(RG_REAL_STACK) - - addi r1,r1,92 // RG_REAL_STACK, RG_REAL_STACK, 36 - - - - // restore the old link register - - mtlr r13 // RG_SECOND - - - - // save off the return value - - stwu r12,4(r4) // RG_TOP, 0(RG_OPSTACK) - - - - blr - -} - - - - -#endif diff --git a/code/qcommon/vm_x86.c b/code/qcommon/vm_x86.c deleted file mode 100644 index fe1cbda7..00000000 --- a/code/qcommon/vm_x86.c +++ /dev/null @@ -1,1237 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vm_x86.c -- load time compiler and execution environment for x86 - -#include "vm_local.h" -#ifdef _WIN32 -#include -#endif - -#ifdef __FreeBSD__ -#include -#endif - -#ifndef _WIN32 -#include // for PROT_ stuff -#endif - -/* need this on NX enabled systems (i386 with PAE kernel or - * noexec32=on x86_64) */ -#ifdef __linux__ -#define VM_X86_MMAP -#endif - -static void VM_Destroy_Compiled(vm_t* self); - -/* - - eax scratch - ebx scratch - ecx scratch (required for shifts) - edx scratch (required for divisions) - esi program stack - edi opstack - -*/ - -// TTimo: initialised the statics, this fixes a crash when entering a compiled VM -static byte *buf = NULL; -static byte *jused = NULL; -static int compiledOfs = 0; -static byte *code = NULL; -static int pc = 0; - -static int *instructionPointers = NULL; - -#define FTOL_PTR - -#ifdef _MSC_VER - -#if defined( FTOL_PTR ) -int _ftol( float ); -static int ftolPtr = (int)_ftol; -#endif - -void AsmCall( void ); -static int asmCallPtr = (int)AsmCall; - -#else // _MSC_VER - -#if defined( FTOL_PTR ) - -int qftol( void ); -int qftol027F( void ); -int qftol037F( void ); -int qftol0E7F( void ); -int qftol0F7F( void ); - - -static int ftolPtr = (int)0; -#endif // FTOL_PTR - -void doAsmCall( void ); -static int asmCallPtr = (int)0; -#endif - - -static int callMask = 0; - -static int instruction, pass; -static int lastConst = 0; -static int oc0, oc1, pop0, pop1; - -typedef enum -{ - LAST_COMMAND_NONE = 0, - LAST_COMMAND_MOV_EDI_EAX, - LAST_COMMAND_SUB_DI_4, - LAST_COMMAND_SUB_DI_8, -} ELastCommand; - -static ELastCommand LastCommand; - -/* -================= -AsmCall -================= -*/ -#ifdef _MSC_VER -__declspec( naked ) void AsmCall( void ) { -int programStack; -int *opStack; -int syscallNum; -vm_t* savedVM; - -__asm { - mov eax, dword ptr [edi] - sub edi, 4 - or eax,eax - jl systemCall - // calling another vm function - shl eax,2 - add eax, dword ptr [instructionPointers] - call dword ptr [eax] - mov eax, dword ptr [edi] - and eax, [callMask] - ret -systemCall: - - // convert negative num to system call number - // and store right before the first arg - neg eax - dec eax - - push ebp - mov ebp, esp - sub esp, __LOCAL_SIZE - - mov dword ptr syscallNum, eax // so C code can get at it - mov dword ptr programStack, esi // so C code can get at it - mov dword ptr opStack, edi - - push ecx - push esi // we may call recursively, so the - push edi // statics aren't guaranteed to be around -} - - savedVM = currentVM; - - // save the stack to allow recursive VM entry - currentVM->programStack = programStack - 4; - *(int *)((byte *)currentVM->dataBase + programStack + 4) = syscallNum; -//VM_LogSyscalls( (int *)((byte *)currentVM->dataBase + programStack + 4) ); - *(opStack+1) = currentVM->systemCall( (int *)((byte *)currentVM->dataBase + programStack + 4) ); - - currentVM = savedVM; - -_asm { - pop edi - pop esi - pop ecx - add edi, 4 // we added the return value - - mov esp, ebp - pop ebp - - ret -} - -} - -#else //!_MSC_VER - -#if defined(__MINGW32__) || defined(MACOS_X) // _ is prepended to compiled symbols -#define CMANG(sym) "_"#sym -#else -#define CMANG(sym) #sym -#endif - -static int callProgramStack; -static int *callOpStack; -static int callSyscallNum; - -void callAsmCall(void) -{ - vm_t *savedVM; - int *callOpStack2; - - savedVM = currentVM; - callOpStack2 = callOpStack; - - // save the stack to allow recursive VM entry - currentVM->programStack = callProgramStack - 4; - *(int *)((byte *)currentVM->dataBase + callProgramStack + 4) = callSyscallNum; - //VM_LogSyscalls((int *)((byte *)currentVM->dataBase + callProgramStack + 4) ); - *(callOpStack2+1) = currentVM->systemCall( (intptr_t *)((byte *)currentVM->dataBase + callProgramStack + 4) ); - - currentVM = savedVM; -} - -// Note the C space function AsmCall is never actually called, and is in fact -// arbitrarily named (though this is not true for the MSC version). When a vm -// makes a system call, control jumps straight to the doAsmCall label. -void AsmCall( void ) { - __asm__( CMANG(doAsmCall) ": \n\t" \ - " movl (%%edi),%%eax \n\t" \ - " subl $4,%%edi \n\t" \ - " orl %%eax,%%eax \n\t" \ - " jl systemCall \n\t" \ - " shll $2,%%eax \n\t" \ - " addl %3,%%eax \n\t" \ - " call *(%%eax) \n\t" \ - " movl (%%edi),%%eax \n\t" \ - " andl " CMANG(callMask) ", %%eax \n\t" \ - " jmp doret \n\t" \ - "systemCall: \n\t" \ - " negl %%eax \n\t" \ - " decl %%eax \n\t" \ - " movl %%eax,%0 \n\t" \ - " movl %%esi,%1 \n\t" \ - " movl %%edi,%2 \n\t" \ - " pushl %%ecx \n\t" \ - " pushl %%esi \n\t" \ - " pushl %%edi \n\t" \ - " call " CMANG(callAsmCall) " \n\t" \ - " popl %%edi \n\t" \ - " popl %%esi \n\t" \ - " popl %%ecx \n\t" \ - " addl $4,%%edi \n\t" \ - "doret: \n\t" \ - " ret \n\t" \ - : "=rm" (callSyscallNum), "=rm" (callProgramStack), "=rm" (callOpStack) \ - : "m" (instructionPointers) \ - : "ax", "di", "si", "cx" \ - ); -} -#endif - -static int Constant4( void ) { - int v; - - v = code[pc] | (code[pc+1]<<8) | (code[pc+2]<<16) | (code[pc+3]<<24); - pc += 4; - return v; -} - -static int Constant1( void ) { - int v; - - v = code[pc]; - pc += 1; - return v; -} - -static void Emit1( int v ) -{ - buf[ compiledOfs ] = v; - compiledOfs++; - - LastCommand = LAST_COMMAND_NONE; -} - -#if 0 -static void Emit2( int v ) { - Emit1( v & 255 ); - Emit1( ( v >> 8 ) & 255 ); -} -#endif - -static void Emit4( int v ) { - Emit1( v & 255 ); - Emit1( ( v >> 8 ) & 255 ); - Emit1( ( v >> 16 ) & 255 ); - Emit1( ( v >> 24 ) & 255 ); -} - -static int Hex( int c ) { - if ( c >= 'a' && c <= 'f' ) { - return 10 + c - 'a'; - } - if ( c >= 'A' && c <= 'F' ) { - return 10 + c - 'A'; - } - if ( c >= '0' && c <= '9' ) { - return c - '0'; - } - - Com_Error( ERR_DROP, "Hex: bad char '%c'", c ); - - return 0; -} -static void EmitString( const char *string ) { - int c1, c2; - int v; - - while ( 1 ) { - c1 = string[0]; - c2 = string[1]; - - v = ( Hex( c1 ) << 4 ) | Hex( c2 ); - Emit1( v ); - - if ( !string[2] ) { - break; - } - string += 3; - } -} - - - -static void EmitCommand(ELastCommand command) -{ - switch(command) - { - case LAST_COMMAND_MOV_EDI_EAX: - EmitString( "89 07" ); // mov dword ptr [edi], eax - break; - - case LAST_COMMAND_SUB_DI_4: - EmitString( "83 EF 04" ); // sub edi, 4 - break; - - case LAST_COMMAND_SUB_DI_8: - EmitString( "83 EF 08" ); // sub edi, 8 - break; - default: - break; - } - LastCommand = command; -} - -static void EmitAddEDI4(vm_t *vm) { - if (LastCommand == LAST_COMMAND_SUB_DI_4 && jused[instruction-1] == 0) - { // sub di,4 - compiledOfs -= 3; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - return; - } - if (LastCommand == LAST_COMMAND_SUB_DI_8 && jused[instruction-1] == 0) - { // sub di,8 - compiledOfs -= 3; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "83 EF 04" ); // sub edi,4 - return; - } - EmitString( "83 C7 04" ); // add edi,4 -} - -static void EmitMovEAXEDI(vm_t *vm) { - if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) - { // mov [edi], eax - compiledOfs -= 2; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - return; - } - if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || - pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) - { - return; - } - if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) - { // mov edi, 0x123456 - compiledOfs -= 6; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( lastConst ); - return; - } - EmitString( "8B 07" ); // mov eax, dword ptr [edi] -} - -qboolean EmitMovEBXEDI(vm_t *vm, int andit) { - if (LastCommand == LAST_COMMAND_MOV_EDI_EAX) - { // mov [edi], eax - compiledOfs -= 2; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "8B D8"); // mov bx, eax - return qfalse; - } - if (pop1 == OP_DIVI || pop1 == OP_DIVU || pop1 == OP_MULI || pop1 == OP_MULU || - pop1 == OP_STORE4 || pop1 == OP_STORE2 || pop1 == OP_STORE1 ) - { - EmitString( "8B D8"); // mov bx, eax - return qfalse; - } - if (pop1 == OP_CONST && buf[compiledOfs-6] == 0xC7 && buf[compiledOfs-5] == 0x07 ) - { // mov edi, 0x123456 - compiledOfs -= 6; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "BB" ); // mov ebx, 0x12345678 - if (andit) { - Emit4( lastConst & andit ); - } else { - Emit4( lastConst ); - } - return qtrue; - } - - EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] - return qfalse; -} - -/* -================= -VM_Compile -================= -*/ -void VM_Compile( vm_t *vm, vmHeader_t *header ) { - int op; - int maxLength; - int v; - int i; - qboolean opt; - - // allocate a very large temp buffer, we will shrink it later - maxLength = header->codeLength * 8; - buf = Z_Malloc( maxLength ); - jused = Z_Malloc(header->instructionCount + 2 ); - - Com_Memset(jused, 0, header->instructionCount+2); - - // ensure that the optimisation pass knows about all the jump - // table targets - for( i = 0; i < vm->numJumpTableTargets; i++ ) { - jused[ *(int *)(vm->jumpTableTargets + ( i * sizeof( int ) ) ) ] = 1; - } - - for(pass=0;pass<2;pass++) { - oc0 = -23423; - oc1 = -234354; - pop0 = -43435; - pop1 = -545455; - - // translate all instructions - pc = 0; - instruction = 0; - code = (byte *)header + header->codeOffset; - compiledOfs = 0; - - LastCommand = LAST_COMMAND_NONE; - - while ( instruction < header->instructionCount ) { - if ( compiledOfs > maxLength - 16 ) { - Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" ); - } - - vm->instructionPointers[ instruction ] = compiledOfs; - instruction++; - - if ( pc > header->codeLength ) { - Com_Error( ERR_FATAL, "VM_CompileX86: pc > header->codeLength" ); - } - - op = code[ pc ]; - pc++; - switch ( op ) { - case 0: - break; - case OP_BREAK: - EmitString( "CC" ); // int 3 - break; - case OP_ENTER: - EmitString( "81 EE" ); // sub esi, 0x12345678 - Emit4( Constant4() ); - break; - case OP_CONST: - if (code[pc+4] == OP_LOAD4) { - EmitAddEDI4(vm); - EmitString( "BB" ); // mov ebx, 0x12345678 - Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); - EmitString( "8B 03" ); // mov eax, dword ptr [ebx] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - pc++; // OP_LOAD4 - instruction += 1; - break; - } - if (code[pc+4] == OP_LOAD2) { - EmitAddEDI4(vm); - EmitString( "BB" ); // mov ebx, 0x12345678 - Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); - EmitString( "0F B7 03" ); // movzx eax, word ptr [ebx] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - pc++; // OP_LOAD4 - instruction += 1; - break; - } - if (code[pc+4] == OP_LOAD1) { - EmitAddEDI4(vm); - EmitString( "BB" ); // mov ebx, 0x12345678 - Emit4( (Constant4()&vm->dataMask) + (int)vm->dataBase); - EmitString( "0F B6 03" ); // movzx eax, byte ptr [ebx] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - pc++; // OP_LOAD4 - instruction += 1; - break; - } - if (code[pc+4] == OP_STORE4) { - opt = EmitMovEBXEDI(vm, (vm->dataMask & ~3)); - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( Constant4() ); -// if (!opt) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~3 ); -// } - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_STORE4 - instruction += 1; - break; - } - if (code[pc+4] == OP_STORE2) { - opt = EmitMovEBXEDI(vm, (vm->dataMask & ~1)); - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( Constant4() ); -// if (!opt) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~1 ); -// } - EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_STORE4 - instruction += 1; - break; - } - if (code[pc+4] == OP_STORE1) { - opt = EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "B8" ); // mov eax, 0x12345678 - Emit4( Constant4() ); -// if (!opt) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask ); -// } - EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_STORE4 - instruction += 1; - break; - } - if (code[pc+4] == OP_ADD) { - EmitString( "81 07" ); // add dword ptr [edi], 0x1234567 - Emit4( Constant4() ); - pc++; // OP_ADD - instruction += 1; - break; - } - if (code[pc+4] == OP_SUB) { - EmitString( "81 2F" ); // sub dword ptr [edi], 0x1234567 - Emit4( Constant4() ); - pc++; // OP_ADD - instruction += 1; - break; - } - EmitAddEDI4(vm); - EmitString( "C7 07" ); // mov dword ptr [edi], 0x12345678 - lastConst = Constant4(); - Emit4( lastConst ); - if (code[pc] == OP_JUMP) { - jused[lastConst] = 1; - } - break; - case OP_LOCAL: - EmitAddEDI4(vm); - EmitString( "8D 86" ); // lea eax, [0x12345678 + esi] - oc0 = oc1; - oc1 = Constant4(); - Emit4( oc1 ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - case OP_ARG: - EmitMovEAXEDI(vm); // mov eax,dword ptr [edi] - EmitString( "89 86" ); // mov dword ptr [esi+database],eax - // FIXME: range check - Emit4( Constant1() + (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_CALL: - EmitString( "C7 86" ); // mov dword ptr [esi+database],0x12345678 - Emit4( (int)vm->dataBase ); - Emit4( pc ); - EmitString( "FF 15" ); // call asmCallPtr - Emit4( (int)&asmCallPtr ); - break; - case OP_PUSH: - EmitAddEDI4(vm); - break; - case OP_POP: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_LEAVE: - v = Constant4(); - EmitString( "81 C6" ); // add esi, 0x12345678 - Emit4( v ); - EmitString( "C3" ); // ret - break; - case OP_LOAD4: - if (code[pc] == OP_CONST && code[pc+5] == OP_ADD && code[pc+6] == OP_STORE4) { - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - compiledOfs -= 11; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - } - pc++; // OP_CONST - v = Constant4(); - EmitMovEBXEDI(vm, vm->dataMask); - if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "FF 83"); // inc dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - } else { - EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitString( "05" ); // add eax, const - Emit4( v ); - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - } else { - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - } - } - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_ADD - pc++; // OP_STORE - instruction += 3; - break; - } - - if (code[pc] == OP_CONST && code[pc+5] == OP_SUB && code[pc+6] == OP_STORE4) { - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - compiledOfs -= 11; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - } - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - pc++; // OP_CONST - v = Constant4(); - if (v == 1 && oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "FF 8B"); // dec dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - } else { - EmitString( "2D" ); // sub eax, const - Emit4( v ); - if (oc0 == oc1 && pop0 == OP_LOCAL && pop1 == OP_LOCAL) { - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - } else { - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "8B 1F" ); // mov ebx, dword ptr [edi] - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - } - } - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - pc++; // OP_SUB - pc++; // OP_STORE - instruction += 3; - break; - } - - if (buf[compiledOfs-2] == 0x89 && buf[compiledOfs-1] == 0x07) { - compiledOfs -= 2; - vm->instructionPointers[ instruction-1 ] = compiledOfs; - EmitString( "8B 80"); // mov eax, dword ptr [eax + 0x1234567] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - } - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "8B 83" ); // mov eax, dword ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - case OP_LOAD2: - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "0F B7 83" ); // movzx eax, word ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - case OP_LOAD1: - EmitMovEBXEDI(vm, vm->dataMask); - EmitString( "0F B6 83" ); // movzx eax, byte ptr [ebx + 0x12345678] - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - case OP_STORE4: - EmitMovEAXEDI(vm); - EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4] -// if (pop1 != OP_CALL) { -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~3 ); -// } - EmitString( "89 83" ); // mov dword ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - break; - case OP_STORE2: - EmitMovEAXEDI(vm); - EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4] -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask & ~1 ); - EmitString( "66 89 83" ); // mov word ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - break; - case OP_STORE1: - EmitMovEAXEDI(vm); - EmitString( "8B 5F FC" ); // mov ebx, dword ptr [edi-4] -// EmitString( "81 E3" ); // and ebx, 0x12345678 -// Emit4( vm->dataMask ); - EmitString( "88 83" ); // mov byte ptr [ebx+0x12345678], eax - Emit4( (int)vm->dataBase ); - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - break; - - case OP_EQ: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_NE: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_LTI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7D 06" ); // jnl +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_LEI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7F 06" ); // jnle +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_GTI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7E 06" ); // jng +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_GEI: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "7C 06" ); // jnge +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_LTU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "73 06" ); // jnb +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_LEU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "77 06" ); // jnbe +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_GTU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "76 06" ); // jna +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_GEU: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "8B 47 04" ); // mov eax, dword ptr [edi+4] - EmitString( "3B 47 08" ); // cmp eax, dword ptr [edi+8] - EmitString( "72 06" ); // jnae +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_EQF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 40" ); // test ah,0x40 - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_NEF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 40" ); // test ah,0x40 - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_LTF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 01" ); // test ah,0x01 - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_LEF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 41" ); // test ah,0x41 - EmitString( "74 06" ); // je +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_GTF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 41" ); // test ah,0x41 - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_GEF: - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - EmitString( "D9 47 04" ); // fld dword ptr [edi+4] - EmitString( "D8 5F 08" ); // fcomp dword ptr [edi+8] - EmitString( "DF E0" ); // fnstsw ax - EmitString( "F6 C4 01" ); // test ah,0x01 - EmitString( "75 06" ); // jne +6 - EmitString( "FF 25" ); // jmp [0x12345678] - v = Constant4(); - jused[v] = 1; - Emit4( (int)vm->instructionPointers + v*4 ); - break; - case OP_NEGI: - EmitString( "F7 1F" ); // neg dword ptr [edi] - break; - case OP_ADD: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "01 47 FC" ); // add dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_SUB: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "29 47 FC" ); // sub dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_DIVI: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "99" ); // cdq - EmitString( "F7 3F" ); // idiv dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_DIVU: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "33 D2" ); // xor edx, edx - EmitString( "F7 37" ); // div dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_MODI: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "99" ); // cdq - EmitString( "F7 3F" ); // idiv dword ptr [edi] - EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_MODU: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "33 D2" ); // xor edx, edx - EmitString( "F7 37" ); // div dword ptr [edi] - EmitString( "89 57 FC" ); // mov dword ptr [edi-4],edx - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_MULI: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "F7 2F" ); // imul dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_MULU: - EmitString( "8B 47 FC" ); // mov eax,dword ptr [edi-4] - EmitString( "F7 27" ); // mul dword ptr [edi] - EmitString( "89 47 FC" ); // mov dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_BAND: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "21 47 FC" ); // and dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_BOR: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "09 47 FC" ); // or dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_BXOR: - EmitMovEAXEDI(vm); // mov eax, dword ptr [edi] - EmitString( "31 47 FC" ); // xor dword ptr [edi-4],eax - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_BCOM: - EmitString( "F7 17" ); // not dword ptr [edi] - break; - case OP_LSH: - EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] - EmitString( "D3 67 FC" ); // shl dword ptr [edi-4], cl - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_RSHI: - EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] - EmitString( "D3 7F FC" ); // sar dword ptr [edi-4], cl - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_RSHU: - EmitString( "8B 0F" ); // mov ecx, dword ptr [edi] - EmitString( "D3 6F FC" ); // shr dword ptr [edi-4], cl - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_NEGF: - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D9 E0" ); // fchs - EmitString( "D9 1F" ); // fstp dword ptr [edi] - break; - case OP_ADDF: - EmitString( "D9 47 FC" ); // fld dword ptr [edi-4] - EmitString( "D8 07" ); // fadd dword ptr [edi] - EmitString( "D9 5F FC" ); // fstp dword ptr [edi-4] - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - break; - case OP_SUBF: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D8 67 04" ); // fsub dword ptr [edi+4] - EmitString( "D9 1F" ); // fstp dword ptr [edi] - break; - case OP_DIVF: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D8 77 04" ); // fdiv dword ptr [edi+4] - EmitString( "D9 1F" ); // fstp dword ptr [edi] - break; - case OP_MULF: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "D8 4f 04" ); // fmul dword ptr [edi+4] - EmitString( "D9 1F" ); // fstp dword ptr [edi] - break; - case OP_CVIF: - EmitString( "DB 07" ); // fild dword ptr [edi] - EmitString( "D9 1F" ); // fstp dword ptr [edi] - break; - case OP_CVFI: -#ifndef FTOL_PTR // WHENHELLISFROZENOVER - // not IEEE complient, but simple and fast - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "DB 1F" ); // fistp dword ptr [edi] -#else // FTOL_PTR - // call the library conversion function - EmitString( "D9 07" ); // fld dword ptr [edi] - EmitString( "FF 15" ); // call ftolPtr - Emit4( (int)&ftolPtr ); - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax -#endif - break; - case OP_SEX8: - EmitString( "0F BE 07" ); // movsx eax, byte ptr [edi] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - case OP_SEX16: - EmitString( "0F BF 07" ); // movsx eax, word ptr [edi] - EmitCommand(LAST_COMMAND_MOV_EDI_EAX); // mov dword ptr [edi], eax - break; - - case OP_BLOCK_COPY: - // FIXME: range check - EmitString( "56" ); // push esi - EmitString( "57" ); // push edi - EmitString( "8B 37" ); // mov esi,[edi] - EmitString( "8B 7F FC" ); // mov edi,[edi-4] - EmitString( "B9" ); // mov ecx,0x12345678 - Emit4( Constant4() >> 2 ); - EmitString( "B8" ); // mov eax, datamask - Emit4( vm->dataMask ); - EmitString( "BB" ); // mov ebx, database - Emit4( (int)vm->dataBase ); - EmitString( "23 F0" ); // and esi, eax - EmitString( "03 F3" ); // add esi, ebx - EmitString( "23 F8" ); // and edi, eax - EmitString( "03 FB" ); // add edi, ebx - EmitString( "F3 A5" ); // rep movsd - EmitString( "5F" ); // pop edi - EmitString( "5E" ); // pop esi - EmitCommand(LAST_COMMAND_SUB_DI_8); // sub edi, 8 - break; - - case OP_JUMP: - EmitCommand(LAST_COMMAND_SUB_DI_4); // sub edi, 4 - EmitString( "8B 47 04" ); // mov eax,dword ptr [edi+4] - // FIXME: range check - EmitString( "FF 24 85" ); // jmp dword ptr [instructionPointers + eax * 4] - Emit4( (int)vm->instructionPointers ); - break; - default: - Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc ); - } - pop0 = pop1; - pop1 = op; - } - } - - // copy to an exact size buffer on the hunk - vm->codeLength = compiledOfs; -#ifdef VM_X86_MMAP - vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if(vm->codeBase == (void*)-1) - Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory"); -#elif _WIN32 - // allocate memory with EXECUTE permissions under windows. - vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if(!vm->codeBase) - Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed"); -#else - vm->codeBase = malloc(compiledOfs); -#endif - - Com_Memcpy( vm->codeBase, buf, compiledOfs ); - -#ifdef VM_X86_MMAP - if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) - Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed"); -#elif _WIN32 - { - DWORD oldProtect = 0; - - // remove write permissions. - if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect)) - Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed"); - } -#endif - - Z_Free( buf ); - Z_Free( jused ); - Com_Printf( "VM file %s compiled to %i bytes of code\n", vm->name, compiledOfs ); - - vm->destroy = VM_Destroy_Compiled; - - // offset all the instruction pointers for the new location - for ( i = 0 ; i < header->instructionCount ; i++ ) { - vm->instructionPointers[i] += (int)vm->codeBase; - } -} - -void VM_Destroy_Compiled(vm_t* self) -{ -#ifdef VM_X86_MMAP - munmap(self->codeBase, self->codeLength); -#elif _WIN32 - VirtualFree(self->codeBase, self->codeLength, MEM_RELEASE); -#else - free(self->codeBase); -#endif -} - -/* -============== -VM_CallCompiled - -This function is called directly by the generated code -============== -*/ -int VM_CallCompiled( vm_t *vm, int *args ) { - int stack[1024]; - int programCounter; - int programStack; - int stackOnEntry; - byte *image; - void *entryPoint; - void *opStack; - int *oldInstructionPointers; - - oldInstructionPointers = instructionPointers; - - currentVM = vm; - instructionPointers = vm->instructionPointers; - - // interpret the code - vm->currentlyInterpreting = qtrue; - - callMask = vm->dataMask; - - // we might be called recursively, so this might not be the very top - programStack = vm->programStack; - stackOnEntry = programStack; - - // set up the stack frame - image = vm->dataBase; - - programCounter = 0; - - programStack -= 48; - - *(int *)&image[ programStack + 44] = args[9]; - *(int *)&image[ programStack + 40] = args[8]; - *(int *)&image[ programStack + 36] = args[7]; - *(int *)&image[ programStack + 32] = args[6]; - *(int *)&image[ programStack + 28] = args[5]; - *(int *)&image[ programStack + 24] = args[4]; - *(int *)&image[ programStack + 20] = args[3]; - *(int *)&image[ programStack + 16] = args[2]; - *(int *)&image[ programStack + 12] = args[1]; - *(int *)&image[ programStack + 8 ] = args[0]; - *(int *)&image[ programStack + 4 ] = 0; // return stack - *(int *)&image[ programStack ] = -1; // will terminate the loop on return - - // off we go into generated code... - entryPoint = vm->codeBase; - opStack = &stack; - -#ifdef _MSC_VER - __asm { - pushad - mov esi, programStack; - mov edi, opStack - call entryPoint - mov programStack, esi - mov opStack, edi - popad - } -#else - { - static int memProgramStack; - static void *memOpStack; - static void *memEntryPoint; - - memProgramStack = programStack; - memOpStack = opStack; - memEntryPoint = entryPoint; - - __asm__(" pushal \n" \ - " movl %0,%%esi \n" \ - " movl %1,%%edi \n" \ - " call *%2 \n" \ - " movl %%esi,%0 \n" \ - " movl %%edi,%1 \n" \ - " popal \n" \ - : "=m" (memProgramStack), "=m" (memOpStack) \ - : "m" (memEntryPoint), "m" (memProgramStack), "m" (memOpStack) \ - : "si", "di" \ - ); - - programStack = memProgramStack; - opStack = memOpStack; - } -#endif - - if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "opStack corrupted in compiled code" ); - } - if ( programStack != stackOnEntry - 48 ) { - Com_Error( ERR_DROP, "programStack corrupted in compiled code" ); - } - - vm->programStack = stackOnEntry; - - // in case we were recursively called by another vm - instructionPointers = oldInstructionPointers; - - return *(int *)opStack; -} diff --git a/code/qcommon/vm_x86_64.c b/code/qcommon/vm_x86_64.c deleted file mode 100644 index c0fbfb05..00000000 --- a/code/qcommon/vm_x86_64.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. -Copyright (C) 2005 Ludwig Nussel - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// vm_x86_64.c -- load time compiler and execution environment for x86-64 - -#include "vm_local.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -//#define USE_GAS -//#define DEBUG_VM - -#ifdef DEBUG_VM -#define Dfprintf(fd, args...) fprintf(fd, ##args) -static FILE* qdasmout; -#else -#define Dfprintf(args...) -#endif - -#define VM_X86_64_MMAP - -#ifndef USE_GAS -void assembler_set_output(char* buf); -size_t assembler_get_code_size(void); -void assembler_init(int pass); -void assemble_line(const char* input, size_t len); -#ifdef Dfprintf -#undef Dfprintf -#define Dfprintf(args...) -#endif -#endif // USE_GAS - -static void VM_Destroy_Compiled(vm_t* self); - -/* - - |=====================| - ^ dataMask ^- programStack rdi - | - +- r8 - - eax scratch - ebx scratch - ecx scratch (required for shifts) - edx scratch (required for divisions) - rsi stack pointer (opStack) - rdi program frame pointer (programStack) - r8 pointer data (vm->dataBase) - r10 start of generated code -*/ - - -static long callAsmCall(long callProgramStack, long callSyscallNum) -{ - vm_t *savedVM; - long ret = 0x77; - long args[11]; -// int iargs[11]; - int i; - -// Dfprintf(stderr, "callAsmCall(%ld, %ld)\n", callProgramStack, callSyscallNum); -// Com_Printf("-> callAsmCall %s, level %d, num %ld\n", currentVM->name, currentVM->callLevel, callSyscallNum); - - savedVM = currentVM; - - // save the stack to allow recursive VM entry - currentVM->programStack = callProgramStack - 4; - - args[0] = callSyscallNum; -// iargs[0] = callSyscallNum; - for(i = 0; i < 10; ++i) - { -// iargs[i+1] = *(int *)((byte *)currentVM->dataBase + callProgramStack + 8 + 4*i); - args[i+1] = *(int *)((byte *)currentVM->dataBase + callProgramStack + 8 + 4*i); - } - ret = currentVM->systemCall(args); - - currentVM = savedVM; -// Com_Printf("<- callAsmCall %s, level %d, num %ld\n", currentVM->name, currentVM->callLevel, callSyscallNum); - - return ret; -} - -#ifdef DEBUG_VM -static char *opnames[256] = { - "OP_UNDEF", - - "OP_IGNORE", - - "OP_BREAK", - - "OP_ENTER", - "OP_LEAVE", - "OP_CALL", - "OP_PUSH", - "OP_POP", - - "OP_CONST", - - "OP_LOCAL", - - "OP_JUMP", - - //------------------- - - "OP_EQ", - "OP_NE", - - "OP_LTI", - "OP_LEI", - "OP_GTI", - "OP_GEI", - - "OP_LTU", - "OP_LEU", - "OP_GTU", - "OP_GEU", - - "OP_EQF", - "OP_NEF", - - "OP_LTF", - "OP_LEF", - "OP_GTF", - "OP_GEF", - - //------------------- - - "OP_LOAD1", - "OP_LOAD2", - "OP_LOAD4", - "OP_STORE1", - "OP_STORE2", - "OP_STORE4", - "OP_ARG", - - "OP_BLOCK_COPY", - - //------------------- - - "OP_SEX8", - "OP_SEX16", - - "OP_NEGI", - "OP_ADD", - "OP_SUB", - "OP_DIVI", - "OP_DIVU", - "OP_MODI", - "OP_MODU", - "OP_MULI", - "OP_MULU", - - "OP_BAND", - "OP_BOR", - "OP_BXOR", - "OP_BCOM", - - "OP_LSH", - "OP_RSHI", - "OP_RSHU", - - "OP_NEGF", - "OP_ADDF", - "OP_SUBF", - "OP_DIVF", - "OP_MULF", - - "OP_CVIF", - "OP_CVFI" -}; -#endif // DEBUG_VM - -static unsigned char op_argsize[256] = -{ - [OP_ENTER] = 4, - [OP_LEAVE] = 4, - [OP_CONST] = 4, - [OP_LOCAL] = 4, - [OP_EQ] = 4, - [OP_NE] = 4, - [OP_LTI] = 4, - [OP_LEI] = 4, - [OP_GTI] = 4, - [OP_GEI] = 4, - [OP_LTU] = 4, - [OP_LEU] = 4, - [OP_GTU] = 4, - [OP_GEU] = 4, - [OP_EQF] = 4, - [OP_NEF] = 4, - [OP_LTF] = 4, - [OP_LEF] = 4, - [OP_GTF] = 4, - [OP_GEF] = 4, - [OP_ARG] = 1, - [OP_BLOCK_COPY] = 4, -}; - -#ifdef USE_GAS -#define emit(x...) \ - do { fprintf(fh_s, ##x); fputc('\n', fh_s); } while(0) -#else -void emit(const char* fmt, ...) -{ - va_list ap; - char line[4096]; - va_start(ap, fmt); - vsnprintf(line, sizeof(line), fmt, ap); - va_end(ap); - assemble_line(line, strlen(line)); -} -#endif // USE_GAS - -#ifdef USE_GAS -#define JMPIARG \ - emit("jmp i_%08x", iarg); -#else -#define JMPIARG \ - emit("movq $%lu, %%rax", vm->codeBase+vm->instructionPointers[iarg]); \ - emit("jmpq *%rax"); -#endif - -// integer compare and jump -#define IJ(op) \ - emit("subq $8, %%rsi"); \ - emit("movl 4(%%rsi), %%eax"); \ - emit("cmpl 8(%%rsi), %%eax"); \ - emit(op " i_%08x", instruction+1); \ - JMPIARG \ - neednilabel = 1; - -#ifdef USE_X87 -#define FJ(bits, op) \ - emit("subq $8, %%rsi");\ - emit("flds 4(%%rsi)");\ - emit("fcomps 8(%%rsi)");\ - emit("fnstsw %%ax");\ - emit("testb $" #bits ", %%ah");\ - emit(op " i_%08x", instruction+1);\ - JMPIARG \ - neednilabel = 1; -#define XJ(x) -#else -#define FJ(x, y) -#define XJ(op) \ - emit("subq $8, %%rsi");\ - emit("movss 4(%%rsi), %%xmm0");\ - emit("ucomiss 8(%%rsi), %%xmm0");\ - emit("jp i_%08x", instruction+1);\ - emit(op " i_%08x", instruction+1);\ - JMPIARG \ - neednilabel = 1; -#endif - -#define SIMPLE(op) \ - emit("subq $4, %%rsi"); \ - emit("movl 4(%%rsi), %%eax"); \ - emit(op " %%eax, 0(%%rsi)"); - -#ifdef USE_X87 -#define FSIMPLE(op) \ - emit("subq $4, %%rsi"); \ - emit("flds 0(%%rsi)"); \ - emit(op " 4(%%rsi)"); \ - emit("fstps 0(%%rsi)"); -#define XSIMPLE(op) -#else -#define FSIMPLE(op) -#define XSIMPLE(op) \ - emit("subq $4, %%rsi"); \ - emit("movss 0(%%rsi), %%xmm0"); \ - emit(op " 4(%%rsi), %%xmm0"); \ - emit("movss %%xmm0, 0(%%rsi)"); -#endif - -#define SHIFT(op) \ - emit("subq $4, %%rsi"); \ - emit("movl 4(%%rsi), %%ecx"); \ - emit("movl 0(%%rsi), %%eax"); \ - emit(op " %%cl, %%eax"); \ - emit("movl %%eax, 0(%%rsi)"); - -#if 1 -#define RANGECHECK(reg) \ - emit("andl $0x%x, %%" #reg, vm->dataMask); -#elif 0 -#define RANGECHECK(reg) \ - emit("pushl %%" #reg); \ - emit("andl $0x%x, %%" #reg, ~vm->dataMask); \ - emit("jz rangecheck_ok_i_%08x", instruction); \ - emit("int3"); \ - emit("rangecheck_ok_i_%08x:", instruction); \ - emit("popl %%" #reg); \ - emit("andl $0x%x, %%" #reg, vm->dataMask); -#else -#define RANGECHECK(reg) -#endif - -#ifdef DEBUG_VM -#define NOTIMPL(x) \ - do { Com_Error(ERR_DROP, "instruction not implemented: %s\n", opnames[x]); } while(0) -#else -#define NOTIMPL(x) \ - do { Com_Printf(S_COLOR_RED "instruction not implemented: %x\n", x); vm->compiled = qfalse; return; } while(0) -#endif - -static void* getentrypoint(vm_t* vm) -{ -#ifdef USE_GAS - return vm->codeBase+64; // skip ELF header -#else - return vm->codeBase; -#endif // USE_GAS -} - -#ifdef USE_GAS -char* mmapfile(const char* fn, size_t* size) -{ - int fd = -1; - char* mem = NULL; - struct stat stb; - - fd = open(fn, O_RDONLY); - if(fd == -1) - goto out; - - if(fstat(fd, &stb) == -1) - goto out; - - *size = stb.st_size; - - mem = mmap(NULL, stb.st_size, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); - if(mem == (void*)-1) - mem = NULL; - -out: - if(fd != -1) - close(fd); - - return mem; -} - -static int doas(char* in, char* out, unsigned char** compiledcode) -{ - unsigned char* mem; - size_t size = -1; - pid_t pid; - - Com_Printf("running assembler < %s > %s\n", in, out); - pid = fork(); - if(pid == -1) - { - Com_Printf(S_COLOR_RED "can't fork\n"); - return -1; - } - - if(!pid) - { - char* const argv[] = { - "as", - "-o", - out, - in, - NULL - }; - - execvp(argv[0], argv); - _exit(-1); - } - else - { - int status; - if(waitpid(pid, &status, 0) == -1) - { - Com_Printf(S_COLOR_RED "can't wait for as: %s\n", strerror(errno)); - return -1; - } - - if(!WIFEXITED(status)) - { - Com_Printf(S_COLOR_RED "as died\n"); - return -1; - } - if(WEXITSTATUS(status)) - { - Com_Printf(S_COLOR_RED "as failed with status %d\n", WEXITSTATUS(status)); - return -1; - } - } - - Com_Printf("done\n"); - - mem = (unsigned char*)mmapfile(out, &size); - if(!mem) - { - Com_Printf(S_COLOR_RED "can't mmap object file %s: %s\n", out, strerror(errno)); - return -1; - } - - *compiledcode = mem; - - return size; -} -#endif // USE_GAS - -static void block_copy_vm(unsigned dest, unsigned src, unsigned count) -{ - unsigned dataMask = currentVM->dataMask; - - if ((dest & dataMask) != dest - || (src & dataMask) != src - || ((dest+count) & dataMask) != dest + count - || ((src+count) & dataMask) != src + count) - { - Com_Error(ERR_DROP, "OP_BLOCK_COPY out of range!\n"); - } - - memcpy(currentVM->dataBase+dest, currentVM->dataBase+src, count); -} - -/* -================= -VM_Compile -================= -*/ -void VM_Compile( vm_t *vm, vmHeader_t *header ) { - unsigned char op; - int pc; - unsigned instruction; - char* code; - unsigned iarg = 0; - unsigned char barg = 0; - int neednilabel = 0; - struct timeval tvstart = {0, 0}; - -#ifdef USE_GAS - byte* compiledcode; - int compiledsize; - void* entryPoint; - char fn_s[2*MAX_QPATH]; // output file for assembler code - char fn_o[2*MAX_QPATH]; // file written by as -#ifdef DEBUG_VM - char fn_d[MAX_QPATH]; // disassembled -#endif - FILE* fh_s; - int fd_s, fd_o; - - gettimeofday(&tvstart, NULL); - - Com_Printf("compiling %s\n", vm->name); - -#ifdef DEBUG_VM - snprintf(fn_s, sizeof(fn_s), "%.63s.s", vm->name); - snprintf(fn_o, sizeof(fn_o), "%.63s.o", vm->name); - fd_s = open(fn_s, O_CREAT|O_WRONLY|O_TRUNC, 0644); - fd_o = open(fn_o, O_CREAT|O_WRONLY|O_TRUNC, 0644); -#else - snprintf(fn_s, sizeof(fn_s), "/tmp/%.63s.s_XXXXXX", vm->name); - snprintf(fn_o, sizeof(fn_o), "/tmp/%.63s.o_XXXXXX", vm->name); - fd_s = mkstemp(fn_s); - fd_o = mkstemp(fn_o); -#endif - if(fd_s == -1 || fd_o == -1) - { - if(fd_s != -1) close(fd_s); - if(fd_o != -1) close(fd_o); - unlink(fn_s); - unlink(fn_o); - - Com_Printf(S_COLOR_RED "can't create temporary file %s for vm\n", fn_s); - vm->compiled = qfalse; - return; - } - -#ifdef DEBUG_VM - strcpy(fn_d,vm->name); - strcat(fn_d, ".qdasm"); - - qdasmout = fopen(fn_d, "w"); -#endif - - fh_s = fdopen(fd_s, "wb"); - if(!fh_s) - { - Com_Printf(S_COLOR_RED "can't write %s\n", fn_s); - vm->compiled = qfalse; - return; - } - - emit("start:"); - emit("or %%r8, %%r8"); // check whether to set up instruction pointers - emit("jnz main"); - emit("jmp setupinstructionpointers"); - - emit("main:"); -#else // USE_GAS - int pass; - size_t compiledOfs = 0; - - gettimeofday(&tvstart, NULL); - - for (pass = 0; pass < 2; ++pass) { - - if(pass) - { - compiledOfs = assembler_get_code_size(); - vm->codeLength = compiledOfs; - vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); - if(vm->codeBase == (void*)-1) - Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory"); - - assembler_set_output((char*)vm->codeBase); - } - - assembler_init(pass); - -#endif // USE_GAS - - // translate all instructions - pc = 0; - code = (char *)header + header->codeOffset; - - for ( instruction = 0; instruction < header->instructionCount; ++instruction ) - { - op = code[ pc ]; - ++pc; - -#ifndef USE_GAS - vm->instructionPointers[instruction] = assembler_get_code_size(); -#endif - - /* store current instruction number in r15 for debugging */ -#if 1 - emit("nop"); - emit("movq $%d, %%r15", instruction); - emit("nop"); -#endif - - if(op_argsize[op] == 4) - { - iarg = *(int*)(code+pc); - pc += 4; - Dfprintf(qdasmout, "%s %8u\n", opnames[op], iarg); - } - else if(op_argsize[op] == 1) - { - barg = code[pc++]; - Dfprintf(qdasmout, "%s %8hhu\n", opnames[op], barg); - } - else - { - Dfprintf(qdasmout, "%s\n", opnames[op]); - } - -#ifdef USE_GAS - emit("i_%08x:", instruction); -#else - if(neednilabel) - { - emit("i_%08x:", instruction); - neednilabel = 0; - } -#endif - - switch ( op ) - { - case OP_UNDEF: - NOTIMPL(op); - break; - case OP_IGNORE: - emit("nop"); - break; - case OP_BREAK: - emit("int3"); - break; - case OP_ENTER: - emit("subl $%d, %%edi", iarg); - RANGECHECK(edi); - break; - case OP_LEAVE: - emit("addl $%d, %%edi", iarg); // get rid of stack frame - emit("ret"); - break; - case OP_CALL: - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); - emit("movl $%d, 0(%%r8, %%rdi, 1)", instruction+1); // save next instruction - emit("orl %%eax, %%eax"); - emit("jl callSyscall%d", instruction); - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); - emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address - emit("addq %%r10, %%rax"); - emit("callq *%%rax"); - emit("jmp i_%08x", instruction+1); - emit("callSyscall%d:", instruction); -// emit("fnsave 4(%%rsi)"); - emit("push %%rsi"); - emit("push %%rdi"); - emit("push %%r8"); - emit("push %%r9"); - emit("push %%r10"); - emit("movq %%rsp, %%rbx"); // we need to align the stack pointer - emit("subq $8, %%rbx"); // | - emit("andq $127, %%rbx"); // | - emit("subq %%rbx, %%rsp"); // <-+ - emit("push %%rbx"); - emit("negl %%eax"); // convert to actual number - emit("decl %%eax"); - // first argument already in rdi - emit("movq %%rax, %%rsi"); // second argument in rsi - emit("movq $%lu, %%rax", (unsigned long)callAsmCall); - emit("callq *%%rax"); - emit("pop %%rbx"); - emit("addq %%rbx, %%rsp"); - emit("pop %%r10"); - emit("pop %%r9"); - emit("pop %%r8"); - emit("pop %%rdi"); - emit("pop %%rsi"); -// emit("frstor 4(%%rsi)"); - emit("addq $4, %%rsi"); - emit("movl %%eax, (%%rsi)"); // store return value - neednilabel = 1; - break; - case OP_PUSH: - emit("addq $4, %%rsi"); - break; - case OP_POP: - emit("subq $4, %%rsi"); - break; - case OP_CONST: - emit("addq $4, %%rsi"); - emit("movl $%d, 0(%%rsi)", iarg); - break; - case OP_LOCAL: - emit("movl %%edi, %%ebx"); - emit("addl $%d,%%ebx", iarg); - emit("addq $4, %%rsi"); - emit("movl %%ebx, 0(%%rsi)"); - break; - case OP_JUMP: - emit("movl 0(%%rsi), %%eax"); // get instr from stack - emit("subq $4, %%rsi"); - emit("movq $%lu, %%rbx", (unsigned long)vm->instructionPointers); - emit("movl (%%rbx, %%rax, 4), %%eax"); // load new relative jump address - emit("addq %%r10, %%rax"); - emit("jmp *%%rax"); - break; - case OP_EQ: - IJ("jne"); - break; - case OP_NE: - IJ("je"); - break; - case OP_LTI: - IJ("jnl"); - break; - case OP_LEI: - IJ("jnle"); - break; - case OP_GTI: - IJ("jng"); - break; - case OP_GEI: - IJ("jnge"); - break; - case OP_LTU: - IJ("jnb"); - break; - case OP_LEU: - IJ("jnbe"); - break; - case OP_GTU: - IJ("jna"); - break; - case OP_GEU: - IJ("jnae"); - break; - case OP_EQF: - FJ(0x40, "jz"); - XJ("jnz"); - break; - case OP_NEF: - FJ(0x40, "jnz"); -#ifndef USE_X87 - emit("subq $8, %%rsi"); - emit("movss 4(%%rsi), %%xmm0"); - emit("ucomiss 8(%%rsi), %%xmm0"); - emit("jp dojump_i_%08x", instruction); - emit("jz i_%08x", instruction+1); - emit("dojump_i_%08x:", instruction); - JMPIARG - neednilabel = 1; -#endif - break; - case OP_LTF: - FJ(0x01, "jz"); - XJ("jnc"); - break; - case OP_LEF: - FJ(0x41, "jz"); - XJ("ja"); - break; - case OP_GTF: - FJ(0x41, "jnz"); - XJ("jbe"); - break; - case OP_GEF: - FJ(0x01, "jnz"); - XJ("jb"); - break; - case OP_LOAD1: - emit("movl 0(%%rsi), %%eax"); // get value from stack - RANGECHECK(eax); - emit("movb 0(%%r8, %%rax, 1), %%al"); // deref into eax - emit("andq $255, %%rax"); - emit("movl %%eax, 0(%%rsi)"); // store on stack - break; - case OP_LOAD2: - emit("movl 0(%%rsi), %%eax"); // get value from stack - RANGECHECK(eax); - emit("movw 0(%%r8, %%rax, 1), %%ax"); // deref into eax - emit("movl %%eax, 0(%%rsi)"); // store on stack - break; - case OP_LOAD4: - emit("movl 0(%%rsi), %%eax"); // get value from stack - RANGECHECK(eax); // not a pointer!? - emit("movl 0(%%r8, %%rax, 1), %%eax"); // deref into eax - emit("movl %%eax, 0(%%rsi)"); // store on stack - break; - case OP_STORE1: - emit("movl 0(%%rsi), %%eax"); // get value from stack - emit("andq $255, %%rax"); - emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx); - emit("movb %%al, 0(%%r8, %%rbx, 1)"); // store in memory - emit("subq $8, %%rsi"); - break; - case OP_STORE2: - emit("movl 0(%%rsi), %%eax"); // get value from stack - emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx); - emit("movw %%ax, 0(%%r8, %%rbx, 1)"); // store in memory - emit("subq $8, %%rsi"); - break; - case OP_STORE4: - emit("movl -4(%%rsi), %%ebx"); // get pointer from stack - RANGECHECK(ebx); - emit("movl 0(%%rsi), %%ecx"); // get value from stack - emit("movl %%ecx, 0(%%r8, %%rbx, 1)"); // store in memory - emit("subq $8, %%rsi"); - break; - case OP_ARG: - emit("subq $4, %%rsi"); - emit("movl 4(%%rsi), %%eax"); // get value from stack - emit("movl $0x%hhx, %%ebx", barg); - emit("addl %%edi, %%ebx"); - RANGECHECK(ebx); - emit("movl %%eax, 0(%%r8,%%rbx, 1)"); // store in args space - break; - case OP_BLOCK_COPY: - - emit("subq $8, %%rsi"); - emit("push %%rsi"); - emit("push %%rdi"); - emit("push %%r8"); - emit("push %%r9"); - emit("push %%r10"); - emit("movl 4(%%rsi), %%edi"); // 1st argument dest - emit("movl 8(%%rsi), %%esi"); // 2nd argument src - emit("movl $%d, %%edx", iarg); // 3rd argument count - emit("movq $%lu, %%rax", (unsigned long)block_copy_vm); - emit("callq *%%rax"); - emit("pop %%r10"); - emit("pop %%r9"); - emit("pop %%r8"); - emit("pop %%rdi"); - emit("pop %%rsi"); - - break; - case OP_SEX8: - emit("movw 0(%%rsi), %%ax"); - emit("andq $255, %%rax"); - emit("cbw"); - emit("cwde"); - emit("movl %%eax, 0(%%rsi)"); - break; - case OP_SEX16: - emit("movw 0(%%rsi), %%ax"); - emit("cwde"); - emit("movl %%eax, 0(%%rsi)"); - break; - case OP_NEGI: - emit("negl 0(%%rsi)"); - break; - case OP_ADD: - SIMPLE("addl"); - break; - case OP_SUB: - SIMPLE("subl"); - break; - case OP_DIVI: - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("cdq"); - emit("idivl 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); - break; - case OP_DIVU: - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("xorq %%rdx, %%rdx"); - emit("divl 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); - break; - case OP_MODI: - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("xorl %%edx, %%edx"); - emit("cdq"); - emit("idivl 4(%%rsi)"); - emit("movl %%edx, 0(%%rsi)"); - break; - case OP_MODU: - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("xorl %%edx, %%edx"); - emit("divl 4(%%rsi)"); - emit("movl %%edx, 0(%%rsi)"); - break; - case OP_MULI: - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("imull 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); - break; - case OP_MULU: - emit("subq $4, %%rsi"); - emit("movl 0(%%rsi), %%eax"); - emit("mull 4(%%rsi)"); - emit("movl %%eax, 0(%%rsi)"); - break; - case OP_BAND: - SIMPLE("andl"); - break; - case OP_BOR: - SIMPLE("orl"); - break; - case OP_BXOR: - SIMPLE("xorl"); - break; - case OP_BCOM: - emit("notl 0(%%rsi)"); - break; - case OP_LSH: - SHIFT("shl"); - break; - case OP_RSHI: - SHIFT("sarl"); - break; - case OP_RSHU: - SHIFT("shrl"); - break; - case OP_NEGF: -#ifdef USE_X87 - emit("flds 0(%%rsi)"); - emit("fchs"); - emit("fstps 0(%%rsi)"); -#else - emit("movl $0x80000000, %%eax"); - emit("xorl %%eax, 0(%%rsi)"); -#endif - break; - case OP_ADDF: - FSIMPLE("fadds"); - XSIMPLE("addss"); - break; - case OP_SUBF: - FSIMPLE("fsubs"); - XSIMPLE("subss"); - break; - case OP_DIVF: - FSIMPLE("fdivs"); - XSIMPLE("divss"); - break; - case OP_MULF: - FSIMPLE("fmuls"); - XSIMPLE("mulss"); - break; - case OP_CVIF: -#ifdef USE_X87 - emit("filds 0(%%rsi)"); - emit("fstps 0(%%rsi)"); -#else - emit("movl 0(%%rsi), %%eax"); - emit("cvtsi2ss %%eax, %%xmm0"); - emit("movss %%xmm0, 0(%%rsi)"); -#endif - break; - case OP_CVFI: -#ifdef USE_X87 - emit("flds 0(%%rsi)"); - emit("fnstcw 4(%%rsi)"); - emit("movw $0x0F7F, 8(%%rsi)"); // round toward zero - emit("fldcw 8(%%rsi)"); - emit("fistpl 0(%%rsi)"); - emit("fldcw 4(%%rsi)"); -#else - emit("movss 0(%%rsi), %%xmm0"); - emit("cvttss2si %%xmm0, %%eax"); - emit("movl %%eax, 0(%%rsi)"); -#endif - break; - default: - NOTIMPL(op); - break; - } - } - -#ifdef USE_GAS - emit("setupinstructionpointers:"); - emit("movq $%lu, %%rax", (unsigned long)vm->instructionPointers); - for ( instruction = 0; instruction < header->instructionCount; ++instruction ) - { - emit("movl $i_%08x-start, %d(%%rax)", instruction, instruction*4); - } - emit("ret"); - - emit("debugger:"); - if(1); - { - int i = 6; - while(i--) - { - emit("nop"); - emit("int3"); - } - } - - fflush(fh_s); - fclose(fh_s); - - compiledsize = doas(fn_s, fn_o, &compiledcode); - if(compiledsize == -1) - { - vm->compiled = qfalse; - goto out; - } - - vm->codeBase = compiledcode; // remember to skip ELF header! - vm->codeLength = compiledsize; - -#else // USE_GAS - } - assembler_init(0); - - if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC)) - Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed"); -#endif // USE_GAS - - vm->destroy = VM_Destroy_Compiled; - -#ifdef USE_GAS - entryPoint = getentrypoint(vm); - -// __asm__ __volatile__ ("int3"); - Com_Printf("computing jump table\n"); - - // call code with r8 set to zero to set up instruction pointers - __asm__ __volatile__ ( - " xorq %%r8,%%r8 \r\n" \ - " movq %0,%%r10 \r\n" \ - " callq *%%r10 \r\n" \ - : - : "m" (entryPoint) - : "%r8", "%r10", "%rax" - ); - -#ifdef DEBUG_VM - fflush(qdasmout); - fclose(qdasmout); -#endif - -out: - close(fd_o); - -#ifndef DEBUG_VM - if(!com_developer->integer) - { - unlink(fn_o); - unlink(fn_s); - } -#endif -#endif // USE_GAS - - if(vm->compiled) - { - struct timeval tvdone = {0, 0}; - struct timeval dur = {0, 0}; - Com_Printf( "VM file %s compiled to %i bytes of code (%p - %p)\n", vm->name, vm->codeLength, vm->codeBase, vm->codeBase+vm->codeLength ); - - gettimeofday(&tvdone, NULL); - timersub(&tvdone, &tvstart, &dur); - Com_Printf( "compilation took %lu.%06lu seconds\n", dur.tv_sec, dur.tv_usec ); - } -} - - -void VM_Destroy_Compiled(vm_t* self) -{ -#ifdef USE_GAS - munmap(self->codeBase, self->codeLength); -#elif _WIN32 - VirtualFree(self->codeBase, self->codeLength, MEM_RELEASE); -#else - munmap(self->codeBase, self->codeLength); -#endif -} - -/* -============== -VM_CallCompiled - -This function is called directly by the generated code -============== -*/ - -#ifdef DEBUG_VM -static char* memData; -#endif - -int VM_CallCompiled( vm_t *vm, int *args ) { - int programCounter; - int programStack; - int stackOnEntry; - byte *image; - void *entryPoint; - void *opStack; - int stack[1024] = { 0xDEADBEEF }; - - currentVM = vm; - - ++vm->callLevel; -// Com_Printf("entering %s level %d, call %d, arg1 = 0x%x\n", vm->name, vm->callLevel, args[0], args[1]); - - // interpret the code - vm->currentlyInterpreting = qtrue; - -// callMask = vm->dataMask; - - // we might be called recursively, so this might not be the very top - programStack = vm->programStack; - stackOnEntry = programStack; - - // set up the stack frame - image = vm->dataBase; -#ifdef DEBUG_VM - memData = (char*)image; -#endif - - programCounter = 0; - - programStack -= 48; - - *(int *)&image[ programStack + 44] = args[9]; - *(int *)&image[ programStack + 40] = args[8]; - *(int *)&image[ programStack + 36] = args[7]; - *(int *)&image[ programStack + 32] = args[6]; - *(int *)&image[ programStack + 28] = args[5]; - *(int *)&image[ programStack + 24] = args[4]; - *(int *)&image[ programStack + 20] = args[3]; - *(int *)&image[ programStack + 16] = args[2]; - *(int *)&image[ programStack + 12] = args[1]; - *(int *)&image[ programStack + 8 ] = args[0]; - *(int *)&image[ programStack + 4 ] = 0x77777777; // return stack - *(int *)&image[ programStack ] = -1; // will terminate the loop on return - - // off we go into generated code... - entryPoint = getentrypoint(vm); - opStack = &stack; - - __asm__ __volatile__ ( - " movq %5,%%rsi \r\n" \ - " movl %4,%%edi \r\n" \ - " movq %2,%%r10 \r\n" \ - " movq %3,%%r8 \r\n" \ - " subq $24, %%rsp # fix alignment as call pushes one value \r\n" \ - " callq *%%r10 \r\n" \ - " addq $24, %%rsp \r\n" \ - " movl %%edi, %0 \r\n" \ - " movq %%rsi, %1 \r\n" \ - : "=m" (programStack), "=m" (opStack) - : "m" (entryPoint), "m" (vm->dataBase), "m" (programStack), "m" (opStack) - : "%rsi", "%rdi", "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r10", "%r15", "%xmm0" - ); - - if ( opStack != &stack[1] ) { - Com_Error( ERR_DROP, "opStack corrupted in compiled code (offset %ld)\n", (long int) ((void *) &stack[1] - opStack)); - } - if ( programStack != stackOnEntry - 48 ) { - Com_Error( ERR_DROP, "programStack corrupted in compiled code\n" ); - } - -// Com_Printf("exiting %s level %d\n", vm->name, vm->callLevel); - --vm->callLevel; - vm->programStack = stackOnEntry; - - return *(int *)opStack; -} diff --git a/code/qcommon/vm_x86_64_assembler.c b/code/qcommon/vm_x86_64_assembler.c deleted file mode 100644 index 1eda764f..00000000 --- a/code/qcommon/vm_x86_64_assembler.c +++ /dev/null @@ -1,1419 +0,0 @@ -/* -=========================================================================== -vm_x86_64_assembler.c -- assembler for x86-64 - -Copyright (C) 2007 Ludwig Nussel , Novell inc. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include -#include -#include -#include - -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -typedef unsigned long u64; - -static char* out; -static unsigned compiledOfs; -static unsigned assembler_pass; - -static const char* cur_line; - -static FILE* fout; - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -#define crap(fmt, args...) do { \ - _crap(__FUNCTION__, fmt, ##args); \ -} while(0) - -#define CRAP_INVALID_ARGS crap("invalid arguments %s, %s", argtype2str(arg1.type),argtype2str(arg2.type)); - -#ifdef DEBUG -#define debug(fmt, args...) printf(fmt, ##args) -#else -#define debug(fmt, args...) -#endif - -static void _crap(const char* func, const char* fmt, ...) -{ - va_list ap; - fprintf(stderr, "%s() - ", func); - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fputc('\n', stderr); - if(cur_line && cur_line[0]) - fprintf(stderr, "-> %s\n", cur_line); - exit(1); -} - -static void emit1(unsigned char v) -{ - if(assembler_pass) - { - out[compiledOfs++] = v; - if(fout) fwrite(&v, 1, 1, fout); - debug("%02hhx ", v); - } - else - { - ++compiledOfs; - } -} - -static inline void emit2(u16 v) -{ - emit1(v&0xFF); - emit1((v>>8)&0xFF); -} - -static inline void emit4(u32 v) -{ - emit1(v&0xFF); - emit1((v>>8)&0xFF); - emit1((v>>16)&0xFF); - emit1((v>>24)&0xFF); -} - -static inline void emit8(u64 v) -{ - emit4(v&0xFFFFFFFF); - emit4((v>>32)&0xFFFFFFFF); -} - -enum { - REX_W = 0x08, - REX_R = 0x04, - REX_X = 0x02, - REX_B = 0x01, -}; - -enum { - MODRM_MOD_00 = 0x00, - MODRM_MOD_01 = 0x01 << 6, - MODRM_MOD_10 = 0x02 << 6, - MODRM_MOD_11 = 0x03 << 6, - MODRM_RM_SIB = 0x04, -}; - -typedef enum -{ - T_NONE = 0x00, - T_REGISTER = 0x01, - T_IMMEDIATE = 0x02, - T_MEMORY = 0x04, - T_LABEL = 0x08, - T_ABSOLUTE = 0x80 -} argtype_t; - -typedef enum { - R_8 = 0x100, - R_16 = 0x200, - R_64 = 0x800, - R_MSZ = 0xF00, // size mask - R_XMM = 0x2000, // xmm register. year, sucks - R_EAX = 0x00, - R_EBX = 0x03, - R_ECX = 0x01, - R_EDX = 0x02, - R_ESI = 0x06, - R_EDI = 0x07, - R_ESP = 0x04, - R_RAX = R_EAX | R_64, - R_RBX = R_EBX | R_64, - R_RCX = R_ECX | R_64, - R_RDX = R_EDX | R_64, - R_RSI = R_ESI | R_64, - R_RDI = R_EDI | R_64, - R_RSP = R_ESP | R_64, - R_R8 = 0x08 | R_64, - R_R9 = 0x09 | R_64, - R_R10 = 0x0A | R_64, - R_R15 = 0x0F | R_64, - R_AL = R_EAX | R_8, - R_AX = R_EAX | R_16, - R_CL = R_ECX | R_8, - R_XMM0 = 0x00 | R_XMM, - R_MGP = 0x0F, // mask for general purpose registers -} reg_t; - -typedef enum { - MODRM_SIB = 0, - MODRM_NOSIB = 0x3, -} modrm_sib_t; - -typedef struct { - unsigned disp; - argtype_t basetype; - union { - u64 imm; - reg_t reg; - } base; - argtype_t indextype; - union { - u64 imm; - reg_t reg; - } index; - unsigned scale; -} memref_t; - -#define LABELLEN 32 - -typedef struct { - argtype_t type; - union { - u64 imm; - reg_t reg; - memref_t mem; - char label[LABELLEN]; - } v; - int absolute:1; -} arg_t; - -typedef void (*emitfunc)(const char* op, arg_t arg1, arg_t arg2, void* data); - -typedef struct { - char* mnemonic; - emitfunc func; - void* data; -} op_t; - -typedef struct { - u8 xmmprefix; - u8 subcode; // in modrm - u8 rmcode; // opcode for reg/mem, reg - u8 mrcode; // opcode for reg, reg/mem - u8 rcode8; // opcode for reg8/mem8 - u8 rcode; // opcode for reg/mem -} opparam_t; - -/* ************************* */ - -static unsigned hashkey(const char *string, unsigned len) { - unsigned register hash, i; - - hash = 0; - for (i = 0; i < len && string[i] != '\0'; ++i) { - hash += string[i] * (119 + i); - } - hash = (hash ^ (hash >> 10) ^ (hash >> 20)); - return hash; -} - -struct hashentry { - char* label; - unsigned address; - struct hashentry* next; -}; -static struct hashentry* labelhash[1021]; - -// no dup check! -static void hash_add_label(const char* label, unsigned address) -{ - struct hashentry* h; - unsigned i = hashkey(label, -1U); - i %= sizeof(labelhash)/sizeof(labelhash[0]); - h = malloc(sizeof(struct hashentry)); - h->label = strdup(label); - h->address = address; - h->next = labelhash[i]; - labelhash[i] = h; -} - -static unsigned lookup_label(const char* label) -{ - struct hashentry* h; - unsigned i = hashkey(label, -1U); - i %= sizeof(labelhash)/sizeof(labelhash[0]); - for(h = labelhash[i]; h; h = h->next ) - { - if(!strcmp(h->label, label)) - return h->address; - } - if(assembler_pass) - crap("label %s undefined", label); - return 0; -} - -static void labelhash_free(void) -{ - struct hashentry* h; - unsigned i; - unsigned z = 0, min = -1U, max = 0, t = 0; - for ( i = 0; i < sizeof(labelhash)/sizeof(labelhash[0]); ++i) - { - unsigned n = 0; - h = labelhash[i]; - while(h) - { - struct hashentry* next = h->next; - free(h->label); - free(h); - h = next; - ++n; - } - t+=n; - if(!n) ++z; - //else printf("%u\n", n); - min = MIN(min, n); - max = MAX(max, n); - } - printf("total %u, hsize %lu, zero %u, min %u, max %u\n", t, sizeof(labelhash)/sizeof(labelhash[0]), z, min, max); - memset(labelhash, 0, sizeof(labelhash)); -} - -/* ************************* */ - - -static const char* argtype2str(argtype_t t) -{ - switch(t) - { - case T_NONE: return "none"; - case T_REGISTER: return "register"; - case T_IMMEDIATE: return "immediate"; - case T_MEMORY: return "memory"; - case T_LABEL: return "label"; - default: crap("invalid type"); - } - /* not reached */ - return T_NONE; -} - -/* ************************* */ - -static inline int iss8(u64 v) -{ - return (labs(v) <= 0x80); -} - -static inline int isu8(u64 v) -{ - return (v <= 0xff); -} - -static inline int iss16(u64 v) -{ - return (labs(v) <= 0x8000); -} - -static inline int isu16(u64 v) -{ - return (v <= 0xffff); -} - -static inline int iss32(u64 v) -{ - return (labs(v) <= 0x80000000); -} - -static inline int isu32(u64 v) -{ - return (v <= 0xffffffff); -} - -static void emit_opsingle(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 op = (u8)((unsigned long) data); - - if(arg1.type != T_NONE || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - emit1(op); -} - -static void emit_opsingle16(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - emit1(0x66); - emit_opsingle(mnemonic, arg1, arg2, data); -} - -static void compute_rexmodrmsib(u8* rex_r, u8* modrm_r, u8* sib_r, arg_t* arg1, arg_t* arg2) -{ - u8 rex = 0; - u8 modrm = 0; - u8 sib = 0; - - if((arg1->type == T_REGISTER && arg2->type == T_REGISTER) - && ((arg1->v.reg & R_MSZ) != (arg2->v.reg & R_MSZ)) - && !((arg1->v.reg & R_XMM) || (arg2->v.reg & R_XMM))) - crap("both registers must be of same width"); - - if((arg1->type == T_REGISTER && arg1->v.reg & R_64) - || (arg2->type == T_REGISTER && arg2->v.reg & R_64)) - { - rex |= REX_W; - } - - if(arg1->type == T_REGISTER) - { - if((arg1->v.reg & R_MGP) > 0x07) - rex |= REX_R; - - modrm |= (arg1->v.reg & 0x07) << 3; - } - - if(arg2->type == T_REGISTER) - { - if((arg2->v.reg & R_MGP) > 0x07) - rex |= REX_B; - - modrm |= (arg2->v.reg & 0x07); - } - - if(arg2->type == T_MEMORY) - { - if((arg2->v.mem.basetype == T_REGISTER && !(arg2->v.mem.base.reg & R_64)) - || (arg2->v.mem.indextype == T_REGISTER && !(arg2->v.mem.index.reg & R_64))) - { - crap("only 64bit base/index registers are %x %x", arg2->v.mem.base.reg, arg2->v.mem.index.reg); - } - - if(arg2->v.mem.indextype == T_REGISTER) - { - modrm |= MODRM_RM_SIB; - if(!arg2->v.mem.disp) - { - modrm |= MODRM_MOD_00; - } - else if(iss8(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_01; - } - else if(isu32(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_10; - } - else - { - crap("invalid displacement"); - } - - if((arg2->v.mem.index.reg & R_MGP) > 0x07) - rex |= REX_X; - - if((arg2->v.mem.base.reg & R_MGP) > 0x07) - rex |= REX_B; - - if(arg2->v.mem.basetype != T_REGISTER) - crap("base must be register"); - switch(arg2->v.mem.scale) - { - case 1: break; - case 2: sib |= 1 << 6; break; - case 4: sib |= 2 << 6; break; - case 8: sib |= 3 << 6; break; - } - sib |= (arg2->v.mem.index.reg & 0x07) << 3; - sib |= (arg2->v.mem.base.reg & 0x07); - } - else if(arg2->v.mem.indextype == T_NONE) - { - if(!arg2->v.mem.disp) - { - modrm |= MODRM_MOD_00; - } - else if(iss8(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_01; - } - else if(isu32(arg2->v.mem.disp)) - { - modrm |= MODRM_MOD_10; - } - else - { - crap("invalid displacement"); - } - - if(arg2->v.mem.basetype != T_REGISTER) - crap("todo: base != register"); - - if((arg2->v.mem.base.reg & R_MGP) > 0x07) - rex |= REX_B; - - modrm |= arg2->v.mem.base.reg & 0x07; - } - else - { - crap("invalid indextype"); - } - } - else - { - modrm |= MODRM_MOD_11; - } - - if(rex) - rex |= 0x40; // XXX - - *rex_r = rex; - *modrm_r = modrm; - *sib_r = sib; -} - -static void maybe_emit_displacement(arg_t* arg) -{ - if(arg->type != T_MEMORY) - return; - - if(arg->v.mem.disp) - { - if(iss8(arg->v.mem.disp)) - { - emit1((u8)arg->v.mem.disp); - } - else if(isu32(arg->v.mem.disp)) - { - emit4(arg->v.mem.disp); - } - else - { - crap("invalid displacement"); - } - } -} - -/* one byte operator with register added to operator */ -static void emit_opreg(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 op = (u8)((unsigned long) data); - - if(arg1.type != T_REGISTER || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - if((arg1.v.reg & R_MGP) > 0x07) - emit1(0x40 | REX_B); - - op |= (arg1.v.reg & 0x07); - - emit1(op); -} - -/* operator which operates on reg/mem */ -static void emit_op_rm(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - opparam_t* params = data; - - if((arg1.type != T_REGISTER && arg1.type != T_MEMORY) || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - modrm |= params->subcode << 3; - - if(arg1.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg1.v.reg & R_8) - emit1(params->rcode8); // op reg8/mem8, - else - emit1(params->rcode); // op reg/mem, - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); -} - -/* operator which operates on reg/mem with cl */ -static void emit_op_rm_cl(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - opparam_t* params = data; - - if(arg2.type != T_REGISTER || arg1.type != T_REGISTER) - CRAP_INVALID_ARGS; - - if((arg1.v.reg & R_MGP) != R_ECX && !(arg1.v.reg & R_8)) - crap("only cl register is valid"); - - arg1.type = T_NONE; // don't complain, we know it's cl anyways - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - modrm |= params->subcode << 3; - - if(arg2.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg2.v.reg & R_8) - emit1(params->rcode8); // op reg8/mem8, - else - emit1(params->rcode); // op reg/mem, - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); -} - -static void emit_mov(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex = 0; - u8 modrm = 0; - u8 sib = 0; - - if(arg1.type == T_IMMEDIATE && arg2.type == T_REGISTER) - { - u8 op = 0xb8; - - if(arg2.v.reg & R_8) - { - if(!isu8(arg1.v.imm)) - crap("value too large for 8bit register"); - - op = 0xb0; - } - else if(arg2.v.reg & R_16) - { - if(!isu16(arg1.v.imm)) - crap("value too large for 16bit register"); - emit1(0x66); - } - else if(!arg2.v.reg & R_64) - { - if(!isu32(arg1.v.imm)) - crap("value too large for 32bit register"); - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(rex) emit1(rex); - - op |= (arg2.v.reg & 0x07); - - emit1(op); - - if(arg2.v.reg & R_8) emit1(arg1.v.imm); - else if(arg2.v.reg & R_16) emit2(arg1.v.imm); - else if(arg2.v.reg & R_64) emit8(arg1.v.imm); - else emit4(arg1.v.imm); - } - else if(arg1.type == T_IMMEDIATE && arg2.type == T_MEMORY) - { - if(!iss32(arg1.v.imm)) - { - crap("only 32bit immediates supported"); - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - if(rex) emit1(rex); - emit1(0xc7); // mov reg/mem, imm - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - emit4(arg1.v.imm); - } - else if(arg1.type == T_REGISTER && arg2.type == T_REGISTER) // XXX: same as next - { - if(arg1.type != T_REGISTER || arg2.type != T_REGISTER) - crap("both args must be registers"); - - if((arg1.v.reg & R_MSZ) != (arg2.v.reg & R_MSZ)) - crap("both registers must be same width"); - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(rex) emit1(rex); - emit1(0x89); // mov reg reg/mem, - emit1(modrm); - } - else if(arg1.type == T_REGISTER && arg2.type == T_MEMORY) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(arg1.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg1.v.reg & R_8) - emit1(0x88); // mov reg reg/mem, - else - emit1(0x89); // mov reg reg/mem, - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); - } - else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - if(arg2.v.reg & R_16) - emit1(0x66); - - if(rex) emit1(rex); - if(arg2.v.reg & R_8) - emit1(0x8a); // mov reg/mem, reg - else - emit1(0x8b); // mov reg/mem, reg - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); - } - else - CRAP_INVALID_ARGS; -} - -static void emit_subaddand(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex = 0; - u8 modrm = 0; - u8 sib = 0; - - opparam_t* params = data; - - if(arg1.type == T_IMMEDIATE && arg2.type == T_REGISTER) - { - if(!iss32(arg1.v.imm)) - { - crap("only 8 and 32 bit immediates supported"); - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - modrm |= params->subcode << 3; - - if(rex) emit1(rex); -#if 0 - if(isu8(arg1.v.imm)) - { - emit1(0x83); // sub reg/mem, imm8 - emit1(modrm); - emit1(arg1.v.imm&0xFF); - } - else -#endif - { - emit1(0x81); // sub reg/mem, imm32 - emit1(modrm); - emit4(arg1.v.imm); - } - } - else if(arg1.type == T_REGISTER && (arg2.type == T_MEMORY || arg2.type == T_REGISTER)) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(rex) emit1(rex); - emit1(params->rmcode); // sub reg/mem, reg - emit1(modrm); - if(arg2.type == T_MEMORY && (modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); - } - else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER && params->mrcode) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - if(rex) emit1(rex); - emit1(params->mrcode); // sub reg, reg/mem - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); - } - else - CRAP_INVALID_ARGS; -} - -static void emit_condjump(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - unsigned off; - int disp; - unsigned char opcode = (unsigned char)(((unsigned long)data)&0xFF); - - if(arg1.type != T_LABEL || arg2.type != T_NONE) - crap("%s: argument must be label", mnemonic); - - emit1(opcode); - - off = lookup_label(arg1.v.label); - disp = off-(compiledOfs+1); - if(assembler_pass && abs(disp) > 127) - crap("cannot jump that far (%x -> %x = %x)", compiledOfs, off, disp); - - emit1(disp); -} - -static void emit_jmp(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - if((arg1.type != T_LABEL && arg1.type != T_REGISTER && arg1.type != T_MEMORY) || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - if(arg1.type == T_LABEL) - { - unsigned off; - int disp; - - off = lookup_label(arg1.v.label); - disp = off-(compiledOfs+5); - emit1(0xe9); - emit4(disp); - } - else - { - u8 rex, modrm, sib; - - if(arg1.type == T_REGISTER) - { - if(!arg1.absolute) - crap("jmp must be absolute"); - - if((arg1.v.reg & R_64) != R_64) - crap("register must be 64bit"); - - arg1.v.reg ^= R_64; // no rex required for call - } - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - modrm |= 0x4 << 3; - - if(rex) emit1(rex); - emit1(0xff); - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - maybe_emit_displacement(&arg1); - } -} - -static void emit_call(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - - if(arg1.type != T_REGISTER || arg2.type != T_NONE) - CRAP_INVALID_ARGS; - - if(!arg1.absolute) - crap("call must be absolute"); - - if((arg1.v.reg & R_64) != R_64) - crap("register must be 64bit"); - - arg1.v.reg ^= R_64; // no rex required for call - - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - modrm |= 0x2 << 3; - - if(rex) emit1(rex); - emit1(0xff); - emit1(modrm); -} - - -static void emit_twobyte(const char* mnemonic, arg_t arg1, arg_t arg2, void* data) -{ - u8 rex, modrm, sib; - - opparam_t* params = data; - - if(arg1.type == T_REGISTER && (arg2.type == T_MEMORY || arg2.type == T_REGISTER)) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg1, &arg2); - - if(params->xmmprefix) emit1(params->xmmprefix); - if(rex) emit1(rex); - emit1(0x0f); - emit1(params->rmcode); // sub reg/mem, reg - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg2); - } - else if(arg1.type == T_MEMORY && arg2.type == T_REGISTER && params->mrcode) - { - compute_rexmodrmsib(&rex, &modrm, &sib, &arg2, &arg1); - - if(params->xmmprefix) emit1(params->xmmprefix); - if(rex) emit1(rex); - emit1(0x0f); - emit1(params->mrcode); // sub reg, reg/mem - emit1(modrm); - if((modrm & 0x07) == MODRM_RM_SIB) - emit1(sib); - - maybe_emit_displacement(&arg1); - } - else - CRAP_INVALID_ARGS; -} - -static opparam_t params_add = { subcode: 0, rmcode: 0x01, }; -static opparam_t params_or = { subcode: 1, rmcode: 0x09, }; -static opparam_t params_and = { subcode: 4, rmcode: 0x21, }; -static opparam_t params_sub = { subcode: 5, rmcode: 0x29, }; -static opparam_t params_xor = { subcode: 6, rmcode: 0x31, }; -static opparam_t params_cmp = { subcode: 6, rmcode: 0x39, mrcode: 0x3b, }; -static opparam_t params_dec = { subcode: 1, rcode: 0xff, rcode8: 0xfe, }; -static opparam_t params_sar = { subcode: 7, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_shl = { subcode: 4, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_shr = { subcode: 5, rcode: 0xd3, rcode8: 0xd2, }; -static opparam_t params_idiv = { subcode: 7, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_div = { subcode: 6, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_imul = { subcode: 5, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_mul = { subcode: 4, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_neg = { subcode: 3, rcode: 0xf7, rcode8: 0xf6, }; -static opparam_t params_not = { subcode: 2, rcode: 0xf7, rcode8: 0xf6, }; - -static opparam_t params_cvtsi2ss = { xmmprefix: 0xf3, rmcode: 0x2a }; -static opparam_t params_cvttss2si = { xmmprefix: 0xf3, rmcode: 0x2c }; -static opparam_t params_addss = { xmmprefix: 0xf3, mrcode: 0x58 }; -static opparam_t params_divss = { xmmprefix: 0xf3, mrcode: 0x5e }; -static opparam_t params_movss = { xmmprefix: 0xf3, mrcode: 0x10, rmcode: 0x11 }; -static opparam_t params_mulss = { xmmprefix: 0xf3, mrcode: 0x59 }; -static opparam_t params_subss = { xmmprefix: 0xf3, mrcode: 0x5c }; -static opparam_t params_ucomiss = { mrcode: 0x2e }; - -static int ops_sorted = 0; -static op_t ops[] = { - { "addl", emit_subaddand, ¶ms_add }, - { "addq", emit_subaddand, ¶ms_add }, - { "addss", emit_twobyte, ¶ms_addss }, - { "andl", emit_subaddand, ¶ms_and }, - { "andq", emit_subaddand, ¶ms_and }, - { "callq", emit_call, NULL }, - { "cbw", emit_opsingle16, (void*)0x98 }, - { "cdq", emit_opsingle, (void*)0x99 }, - { "cmpl", emit_subaddand, ¶ms_cmp }, - { "cmpq", emit_subaddand, ¶ms_cmp }, - { "cvtsi2ss", emit_twobyte, ¶ms_cvtsi2ss }, - { "cvttss2si", emit_twobyte, ¶ms_cvttss2si }, - { "cwde", emit_opsingle, (void*)0x98 }, - { "decl", emit_op_rm, ¶ms_dec }, - { "decq", emit_op_rm, ¶ms_dec }, - { "divl", emit_op_rm, ¶ms_div }, - { "divq", emit_op_rm, ¶ms_div }, - { "divss", emit_twobyte, ¶ms_divss }, - { "idivl", emit_op_rm, ¶ms_idiv }, - { "imull", emit_op_rm, ¶ms_imul }, - { "int3", emit_opsingle, (void*)0xcc }, - { "ja", emit_condjump, (void*)0x77 }, - { "jbe", emit_condjump, (void*)0x76 }, - { "jb", emit_condjump, (void*)0x72 }, - { "je", emit_condjump, (void*)0x74 }, - { "jl", emit_condjump, (void*)0x7c }, - { "jmp", emit_jmp, NULL }, - { "jmpq", emit_jmp, NULL }, - { "jnae", emit_condjump, (void*)0x72 }, - { "jna", emit_condjump, (void*)0x76 }, - { "jnbe", emit_condjump, (void*)0x77 }, - { "jnb", emit_condjump, (void*)0x73 }, - { "jnc", emit_condjump, (void*)0x73 }, - { "jne", emit_condjump, (void*)0x75 }, - { "jnge", emit_condjump, (void*)0x7c }, - { "jng", emit_condjump, (void*)0x7e }, - { "jnle", emit_condjump, (void*)0x7f }, - { "jnl", emit_condjump, (void*)0x7d }, - { "jnz", emit_condjump, (void*)0x75 }, - { "jp", emit_condjump, (void*)0x7a }, - { "jz", emit_condjump, (void*)0x74 }, - { "movb", emit_mov, NULL }, - { "movl", emit_mov, NULL }, - { "movq", emit_mov, NULL }, - { "movss", emit_twobyte, ¶ms_movss }, - { "movw", emit_mov, NULL }, - { "mull", emit_op_rm, ¶ms_mul }, - { "mulss", emit_twobyte, ¶ms_mulss }, - { "negl", emit_op_rm, ¶ms_neg }, - { "negq", emit_op_rm, ¶ms_neg }, - { "nop", emit_opsingle, (void*)0x90 }, - { "notl", emit_op_rm, ¶ms_not }, - { "notq", emit_op_rm, ¶ms_not }, - { "or", emit_subaddand, ¶ms_or }, - { "orl", emit_subaddand, ¶ms_or }, - { "pop", emit_opreg, (void*)0x58 }, - { "push", emit_opreg, (void*)0x50 }, - { "ret", emit_opsingle, (void*)0xc3 }, - { "sarl", emit_op_rm_cl, ¶ms_sar }, - { "shl", emit_op_rm_cl, ¶ms_shl }, - { "shrl", emit_op_rm_cl, ¶ms_shr }, - { "subl", emit_subaddand, ¶ms_sub }, - { "subq", emit_subaddand, ¶ms_sub }, - { "subss", emit_twobyte, ¶ms_subss }, - { "ucomiss", emit_twobyte, ¶ms_ucomiss }, - { "xorl", emit_subaddand, ¶ms_xor }, - { "xorq", emit_subaddand, ¶ms_xor }, - { NULL, NULL, NULL } -}; - -static int opsort(const void* A, const void* B) -{ - const op_t* a = A; - const op_t* b = B; - return strcmp(a->mnemonic, b->mnemonic); -} - -static op_t* getop(const char* n) -{ -#if 0 - op_t* o = ops; - while(o->mnemonic) - { - if(!strcmp(o->mnemonic, n)) - return o; - ++o; - } - -#else - unsigned m, t, b; - int r; - t = sizeof(ops)/sizeof(ops[0])-1; - b = 0; - - while(b <= t) - { - m = ((t-b)>>1) + b; - if((r = strcmp(ops[m].mnemonic, n)) == 0) - { - return &ops[m]; - } - else if(r < 0) - { - b = m + 1; - } - else - { - t = m - 1; - } - } -#endif - - return NULL; -} - -static reg_t parsereg(const char* str) -{ - const char* s = str; - if(*s == 'a' && s[1] == 'l' && !s[2]) - { - return R_AL; - } - else if(*s == 'a' && s[1] == 'x' && !s[2]) - { - return R_AX; - } - if(*s == 'c' && s[1] == 'l' && !s[2]) - { - return R_CL; - } - if(*s == 'x') - { - if(!strcmp(s, "xmm0")) - return R_XMM0; - } - else if(*s == 'r' && s[1]) - { - ++s; - if(s[1] == 'x') - { - switch(*s++) - { - case 'a': return R_RAX; - case 'b': return R_RBX; - case 'c': return R_RCX; - case 'd': return R_RDX; - } - } - else if(s[1] == 'i') - { - switch(*s++) - { - case 's': return R_RSI; - case 'd': return R_RDI; - } - } - else if(s[0] == 's' && s[1] == 'p' && !s[2]) - { - return R_RSP; - } - else if(*s == '8' && !s[1]) - return R_R8; - else if(*s == '9' && !s[1]) - return R_R9; - else if(*s == '1' && s[1] == '0') - return R_R10; - else if(*s == '1' && s[1] == '5') - return R_R15; - } - else if(*s == 'e' && s[1]) - { - ++s; - if(s[1] == 'x') - { - switch(*s++) - { - case 'a': return R_EAX; - case 'b': return R_EBX; - case 'c': return R_ECX; - case 'd': return R_EDX; - } - } - else if(s[1] == 'i') - { - switch(*s++) - { - case 's': return R_ESI; - case 'd': return R_EDI; - } - } - } - - crap("invalid register %s", str); - - return 0; -} - -typedef enum { - TOK_LABEL = 0x80, - TOK_INT = 0x81, - TOK_END = 0x82, - TOK_INVALID = 0x83, -} token_t; - -static unsigned char nexttok(const char** str, char* label, u64* val) -{ - const char* s = *str; - - if(label) *label = 0; - if(val) *val = 0; - - while(*s && *s == ' ') ++s; - - if(!*s) - { - return TOK_END; - } - else if(*s == '$' || *s == '*' || *s == '%' || *s == '-' || *s == ')' || *s == '(' || *s == ',') - { - *str = s+1; - return *s; - } - else if(*s >= 'a' && *s <= 'z') - { - size_t a = strspn(s+1, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); - if(a+1 >= LABELLEN) - crap("label %s too long", s); - if(label) - { - strncpy(label, s, a+1); - label[a+1] = 0; - } - *str = s+a+1; - return TOK_LABEL; - } - else if(*s >= '0' && *s <= '9') - { - char* endptr = NULL; - u64 v = strtol(s, &endptr, 0); - if(endptr && (endptr-s == 0)) - crap("invalid integer %s", s); - if(val) *val = v; - *str = endptr; - return TOK_INT; - } - crap("can't parse '%s'", *str); - return TOK_INVALID; -} - -static arg_t parsearg(const char** str) -{ - arg_t arg; - const char* s = *str; - char label[20]; - u64 val; - int negative = 1; - unsigned ttype; - - arg.type = T_NONE; - arg.absolute = 0; - - while(*s && *s == ' ') ++s; - - switch(nexttok(&s, label, &val)) - { - case '$' : - ttype = nexttok(&s, NULL, &val); - if(ttype == '-') - { - negative = -1; - ttype = nexttok(&s, NULL, &val); - } - if(ttype != TOK_INT) - crap("expected integer"); - arg.type = T_IMMEDIATE; - arg.v.imm = negative * val; - break; - case '*' : - if((ttype = nexttok(&s, NULL, NULL)) != '%') - { - if(ttype == '(') - goto tok_memory; - crap("expected '%%'"); - } - arg.absolute = 1; - /* fall through */ - case '%' : - if(nexttok(&s, label, &val) != TOK_LABEL) - crap("expected label"); - arg.type = T_REGISTER; - arg.v.reg = parsereg(label); - break; - case TOK_LABEL: - arg.type = T_LABEL; - strncpy(arg.v.label, label, LABELLEN); - break; - case '-': - negative = -1; - if(nexttok(&s, NULL, &val) != TOK_INT) - crap("expected integer"); - /* fall through */ - case TOK_INT: - if(nexttok(&s, label, NULL) != '(') - crap("expected '('"); // mov to/from fixed address not supported - /* fall through */ - case '(': -tok_memory: - arg.type = T_MEMORY; - arg.v.mem.indextype = T_NONE; - arg.v.mem.disp = negative * val; - ttype = nexttok(&s, label, &val); - if(ttype == '%' && nexttok(&s, label, &val) != TOK_LABEL) - { - crap("expected register"); - } - if (ttype == '%') - { - arg.v.mem.basetype = T_REGISTER; - arg.v.mem.base.reg = parsereg(label); - } - else if (ttype == TOK_INT) - { - arg.v.mem.basetype = T_IMMEDIATE; - arg.v.mem.base.imm = val; - } - if((ttype = nexttok(&s, NULL, NULL)) == ',') - { - ttype = nexttok(&s, label, &val); - if(ttype == '%' && nexttok(&s, label, &val) != TOK_LABEL) - { - crap("expected register"); - } - if (ttype == '%') - { - arg.v.mem.indextype = T_REGISTER; - arg.v.mem.index.reg = parsereg(label); - } - else if (ttype == TOK_INT) - { - crap("index must be register"); - arg.v.mem.indextype = T_IMMEDIATE; - arg.v.mem.index.imm = val; - } - if(nexttok(&s, NULL, NULL) != ',') - crap("expected ','"); - if(nexttok(&s, NULL, &val) != TOK_INT) - crap("expected integer"); - if(val != 1 && val != 2 && val != 4 && val != 8) - crap("scale must 1, 2, 4 or 8"); - arg.v.mem.scale = val; - - ttype = nexttok(&s, NULL, NULL); - } - if(ttype != ')') - { - crap("expected ')' or ','"); - } - break; - default: - crap("invalid token %hhu in %s", *(unsigned char*)s, *str); - break; - } - - *str = s; - - return arg; -} - -/* ************************* */ - -void assembler_init(int pass) -{ - compiledOfs = 0; - assembler_pass = pass; - if(!pass) - { - labelhash_free(); - cur_line = NULL; - } - if(!ops_sorted) - { - ops_sorted = 1; - qsort(ops, sizeof(ops)/sizeof(ops[0])-1, sizeof(ops[0]), opsort); - } -} - -size_t assembler_get_code_size(void) -{ - return compiledOfs; -} - -void assembler_set_output(char* buf) -{ - out = buf; -} - -void assemble_line(const char* input, size_t len) -{ - char line[4096]; - char* s; - op_t* o; - char* opn; - arg_t arg1, arg2; - - arg1.type = T_NONE; - arg2.type = T_NONE; - opn = NULL; - o = NULL; - - if(len < 1) - return; - - if(len >= sizeof(line)) - crap("line too long"); - - memcpy(line, input, sizeof(line)); - cur_line = input; - - if(line[len-1] == '\n') line[--len] = 0; - if(line[len-1] == ':') - { - line[--len] = 0; - if(assembler_pass) - debug("%s: 0x%x\n", line, compiledOfs); - else - hash_add_label(line, compiledOfs); - } - else - { - opn = line; - s = strchr(line, ' '); - if(s) - { - *s++ = 0; - arg1 = parsearg((const char**)&s); - if(*s) - { - if(*s != ',') - crap("expected ',', got '%c'", *s); - ++s; - arg2 = parsearg((const char**)&s); - } - } - - if(!opn) - { - crap("no operator in %s", line); - } - - o = getop(opn); - if(!o) - { - crap("cannot handle op %s", opn); - } - o->func(opn, arg1, arg2, o->data); - if(assembler_pass) - debug(" - %s%s", cur_line, cur_line[strlen(cur_line)-1]=='\n'?"":"\n"); - } -} - -#ifdef SA_STANDALONE -int main(int argc, char* argv[]) -{ - char line[4096]; - size_t len; - int pass; - FILE* file = NULL; - - if(argc < 2) - { - crap("specify file"); - } - - file = fopen(argv[1], "r"); - if(!file) - { - crap("can't open file"); - } - - if(argc > 2) - { - fout = fopen(argv[2], "w"); - if(!fout) - { - crap("can't open %s for writing", argv[2]); - } - } - - for(pass = 0; pass < 2; ++pass) - { - if(fseek(file, 0, SEEK_SET)) - crap("can't rewind file"); - - if(pass) - { - char* b = malloc(assembler_get_code_size()); - if(!b) - crap("cannot allocate memory"); - assembler_set_output(b); - } - - assembler_init(pass); - - while(fgets(line, sizeof(line), file)) - { - len = strlen(line); - if(!len) continue; - - assemble_line(line, len); - } - } - - assembler_init(0); - - fclose(file); - - return 0; -} -#endif diff --git a/code/globalcpp/scriptexception.cpp b/code/script/scriptexception.cpp similarity index 95% rename from code/globalcpp/scriptexception.cpp rename to code/script/scriptexception.cpp index 9e19a44e..4af18833 100644 --- a/code/globalcpp/scriptexception.cpp +++ b/code/script/scriptexception.cpp @@ -22,9 +22,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // scriptexception.cpp : Script Exception -#include "glb_local.h" #include "scriptexception.h" +#include + int ScriptException::next_abort = 0; int ScriptException::next_bIsForAnim = 0; @@ -69,5 +70,5 @@ void Error( const char * format, ... ) vsprintf( data, format, va); va_end( va ); - throw new ScriptException( ( const char * )data ); + throw ScriptException( ( const char * )data ); } diff --git a/code/globalcpp/scriptexception.h b/code/script/scriptexception.h similarity index 100% rename from code/globalcpp/scriptexception.h rename to code/script/scriptexception.h diff --git a/code/globalcpp/scriptvariable.cpp b/code/script/scriptvariable.cpp similarity index 88% rename from code/globalcpp/scriptvariable.cpp rename to code/script/scriptvariable.cpp index 62f9a0c7..bec3082b 100644 --- a/code/globalcpp/scriptvariable.cpp +++ b/code/script/scriptvariable.cpp @@ -22,16 +22,17 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // scriptvariable.cpp : Dynamic variables for scripts -#include "glb_local.h" #include "scriptvariable.h" +#include "scriptexception.h" #include "str.h" -#include "archive.h" #ifdef CGAME_DLL #include "../cgame_hook/script/centity.h" #endif #ifdef GAME_DLL +#include "archive.h" +#include "g_local.h" #include "../game/navigate.h" #endif @@ -68,10 +69,11 @@ int HashCode< ScriptVariable >( const ScriptVariable& key ) #endif default: - ScriptError( "Bad hash code value: %s", key.stringValue().c_str() ); + throw ScriptException( "Bad hash code value: %s", key.stringValue().c_str() ); } } +#if defined(ARCHIVE_SUPPORTED) template<> void Entry< ScriptVariable, ScriptVariable >::Archive ( @@ -188,43 +190,6 @@ void ScriptConstArrayHolder::Archive( Archiver& arc, ScriptConstArrayHolder *& c } } -ScriptConstArrayHolder::ScriptConstArrayHolder( ScriptVariable *pVar, unsigned int size ) -{ - refCount = 0; - this->size = size; - - constArrayValue = new ScriptVariable[ size + 1 ] - 1; - - for( int i = 1; i <= size; i++ ) - { - constArrayValue[ i ] = pVar[ i ]; - } -} - -ScriptConstArrayHolder::ScriptConstArrayHolder( unsigned int size ) -{ - refCount = 0; - this->size = size; - - constArrayValue = new ScriptVariable[ size + 1 ] - 1; -} - -ScriptConstArrayHolder::ScriptConstArrayHolder() -{ - refCount = 0; - size = 0; - constArrayValue = NULL; -} - -ScriptConstArrayHolder::~ScriptConstArrayHolder() -{ - if( constArrayValue ) - { - delete[]( constArrayValue + 1 ); - } -} - - void ScriptPointer::Archive( Archiver& arc ) { list.Archive( arc, ScriptVariable::Archive ); @@ -261,6 +226,161 @@ void ScriptPointer::Archive( Archiver& arc, ScriptPointer *& pointerValue ) } } +void ScriptVariable::Archive(Archiver& arc) +{ +#ifndef NO_SCRIPTENGINE + const_str s; + + if (arc.Loading()) + { + Director.ArchiveString(arc, s); + key = s; + } + else + { + s = key; + Director.ArchiveString(arc, s); + } +#endif + + ArchiveInternal(arc); +} + +void ScriptVariable::Archive(Archiver& arc, ScriptVariable** obj) +{ + arc.ArchiveObjectPointer((Class**)obj); +} + +void ScriptVariable::ArchiveInternal(Archiver& arc) +{ + arc.ArchiveObjectPosition(this); + + arc.ArchiveByte(&type); + switch (type) + { + case VARIABLE_STRING: + if (arc.Loading()) + { + m_data.stringValue = new str(4); + } + + arc.ArchiveString(m_data.stringValue); + break; + + case VARIABLE_INTEGER: + arc.ArchiveInteger(&m_data.intValue); + break; + + case VARIABLE_FLOAT: + arc.ArchiveFloat(&m_data.floatValue); + break; + + case VARIABLE_CHAR: + arc.ArchiveChar(&m_data.charValue); + break; + +#ifndef NO_SCRIPTENGINE + case VARIABLE_CONSTSTRING: + if (arc.Loading()) + { + str s; + arc.ArchiveString(&s); + m_data.intValue = Director.AddString(s); + } + else + { + str s = Director.GetString(m_data.intValue); + arc.ArchiveString(&s); + } + break; +#endif + + case VARIABLE_LISTENER: + if (arc.Loading()) + { + m_data.listenerValue = new SafePtr < Listener >; + } + + arc.ArchiveSafePointer(m_data.listenerValue); + break; + + case VARIABLE_ARRAY: + ScriptArrayHolder::Archive(arc, m_data.arrayValue); + break; + + case VARIABLE_CONSTARRAY: + ScriptConstArrayHolder::Archive(arc, m_data.constArrayValue); + break; + + case VARIABLE_REF: + case VARIABLE_CONTAINER: + arc.ArchiveObjectPointer((Class**)&m_data.refValue); + break; + + case VARIABLE_SAFECONTAINER: + if (arc.Loading()) + { + m_data.safeContainerValue = new SafePtr < ConList >; + } + + arc.ArchiveSafePointer(m_data.safeContainerValue); + break; + + case VARIABLE_POINTER: + ScriptPointer::Archive(arc, m_data.pointerValue); + break; + + case VARIABLE_VECTOR: + if (arc.Loading()) + { + m_data.vectorValue = new float[3]; + } + + arc.ArchiveVec3(m_data.vectorValue); + break; + + default: + break; + } +} +#endif + +ScriptConstArrayHolder::ScriptConstArrayHolder(ScriptVariable* pVar, unsigned int size) +{ + refCount = 0; + this->size = size; + + constArrayValue = new ScriptVariable[size + 1] - 1; + + for (int i = 1; i <= size; i++) + { + constArrayValue[i] = pVar[i]; + } +} + +ScriptConstArrayHolder::ScriptConstArrayHolder(unsigned int size) +{ + refCount = 0; + this->size = size; + + constArrayValue = new ScriptVariable[size + 1] - 1; +} + +ScriptConstArrayHolder::ScriptConstArrayHolder() +{ + refCount = 0; + size = 0; + constArrayValue = NULL; +} + +ScriptConstArrayHolder::~ScriptConstArrayHolder() +{ + if (constArrayValue) + { + delete[](constArrayValue + 1); + } +} + void ScriptPointer::Clear() { for( int i = 0; i < list.NumObjects(); i++ ) @@ -305,7 +425,9 @@ void ScriptPointer::setValue( const ScriptVariable& var ) ScriptVariable::ScriptVariable() { +#if defined(GAME_DLL) key = 0; +#endif type = 0; m_data.pointerValue = NULL; } @@ -323,124 +445,6 @@ ScriptVariable::~ScriptVariable() ClearInternal(); } -void ScriptVariable::Archive( Archiver& arc ) -{ -#ifndef NO_SCRIPTENGINE - const_str s; - - if( arc.Loading() ) - { - Director.ArchiveString( arc, s ); - key = s; - } - else - { - s = key; - Director.ArchiveString( arc, s ); - } -#endif - - ArchiveInternal( arc ); -} - -void ScriptVariable::Archive( Archiver& arc, ScriptVariable **obj ) -{ - arc.ArchiveObjectPointer( ( Class ** )obj ); -} - -void ScriptVariable::ArchiveInternal( Archiver& arc ) -{ - arc.ArchiveObjectPosition( this ); - - arc.ArchiveByte( &type ); - switch( type ) - { - case VARIABLE_STRING: - if( arc.Loading() ) - { - m_data.stringValue = new str( 4 ); - } - - arc.ArchiveString( m_data.stringValue ); - break; - - case VARIABLE_INTEGER: - arc.ArchiveInteger( &m_data.intValue ); - break; - - case VARIABLE_FLOAT: - arc.ArchiveFloat( &m_data.floatValue ); - break; - - case VARIABLE_CHAR: - arc.ArchiveChar( &m_data.charValue ); - break; - -#ifndef NO_SCRIPTENGINE - case VARIABLE_CONSTSTRING: - if( arc.Loading() ) - { - str s; - arc.ArchiveString( &s ); - m_data.intValue = Director.AddString( s ); - } - else - { - str s = Director.GetString( m_data.intValue ); - arc.ArchiveString( &s ); - } - break; -#endif - - case VARIABLE_LISTENER: - if( arc.Loading() ) - { - m_data.listenerValue = new SafePtr < Listener >; - } - - arc.ArchiveSafePointer( m_data.listenerValue ); - break; - - case VARIABLE_ARRAY: - ScriptArrayHolder::Archive( arc, m_data.arrayValue ); - break; - - case VARIABLE_CONSTARRAY: - ScriptConstArrayHolder::Archive( arc, m_data.constArrayValue ); - break; - - case VARIABLE_REF: - case VARIABLE_CONTAINER: - arc.ArchiveObjectPointer( ( Class ** )&m_data.refValue ); - break; - - case VARIABLE_SAFECONTAINER: - if( arc.Loading() ) - { - m_data.safeContainerValue = new SafePtr < ConList >; - } - - arc.ArchiveSafePointer( m_data.safeContainerValue ); - break; - - case VARIABLE_POINTER: - ScriptPointer::Archive( arc, m_data.pointerValue ); - break; - - case VARIABLE_VECTOR: - if( arc.Loading() ) - { - m_data.vectorValue = new float[ 3 ]; - } - - arc.ArchiveVec3( m_data.vectorValue ); - break; - - default: - break; - } -} - void ScriptVariable::CastBoolean( void ) { int newvalue = booleanValue(); @@ -464,7 +468,7 @@ void ScriptVariable::CastConstArrayValue( void ) case VARIABLE_POINTER: ClearPointerInternal(); case VARIABLE_NONE: - ScriptError( "cannot cast NIL to an array" ); + throw ScriptException( "cannot cast NIL to an array" ); case VARIABLE_CONSTARRAY: return; @@ -859,7 +863,7 @@ bool ScriptVariable::booleanNumericValue( void ) return ( *m_data.listenerValue ) != NULL; default: - ScriptError( "Cannot cast '%s' to boolean numeric", GetTypeName() ); + throw ScriptException( "Cannot cast '%s' to boolean numeric", GetTypeName() ); } return true; @@ -912,13 +916,13 @@ char ScriptVariable::charValue( void ) const if( value.length() != 1 ) { - ScriptError( "Cannot cast string not of length 1 to char" ); + throw ScriptException( "Cannot cast string not of length 1 to char" ); } return *value; default: - ScriptError( "Cannot cast '%s' to char", GetTypeName() ); + throw ScriptException( "Cannot cast '%s' to char", GetTypeName() ); } return 0; @@ -973,7 +977,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) if( index > 2 ) { Clear(); - ScriptError( "Vector index '%d' out of range", index ); + throw ScriptException( "Vector index '%d' out of range", index ); } return setFloatValue( m_data.vectorValue[ index ] ); @@ -989,7 +993,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) if( index >= string.length() ) { Clear(); - ScriptError( "String index %d out of range", index ); + throw ScriptException( "String index %d out of range", index ); } return setCharValue( string[ index ] ); @@ -1000,7 +1004,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) if( index != 1 ) { Clear(); - ScriptError( "array index %d out of range", index ); + throw ScriptException( "array index %d out of range", index ); } break; @@ -1024,7 +1028,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) if( !index || index > m_data.constArrayValue->size ) { - ScriptError( "array index %d out of range", index ); + throw ScriptException( "array index %d out of range", index ); } *this = m_data.constArrayValue->constArrayValue[ index ]; @@ -1035,7 +1039,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) if( !index || index > m_data.constArrayValue->size ) { - ScriptError( "array index %d out of range", index ); + throw ScriptException( "array index %d out of range", index ); } setListenerValue( m_data.containerValue->ObjectAt( index ) ); @@ -1046,7 +1050,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) if( !*m_data.safeContainerValue || !index || index > m_data.constArrayValue->size ) { - ScriptError( "array index %d out of range", index ); + throw ScriptException( "array index %d out of range", index ); } setListenerValue( ( *m_data.safeContainerValue )->ObjectAt( index ) ); @@ -1054,7 +1058,7 @@ void ScriptVariable::evalArrayAt( ScriptVariable &var ) default: Clear(); - ScriptError( "[] applied to invalid type '%s'", typenames[ GetType() ] ); + throw ScriptException( "[] applied to invalid type '%s'", typenames[ GetType() ] ); break; } } @@ -1081,7 +1085,7 @@ float ScriptVariable::floatValue( void ) const return val; default: - ScriptError( "Cannot cast '%s' to float", typenames[ type ] ); + throw ScriptException( "Cannot cast '%s' to float", typenames[ type ] ); } } @@ -1106,7 +1110,7 @@ int ScriptVariable::intValue( void ) const return val; default: - ScriptError( "Cannot cast '%s' to int", typenames[ type ] ); + throw ScriptException( "Cannot cast '%s' to int", typenames[ type ] ); } } @@ -1126,7 +1130,7 @@ Listener *ScriptVariable::listenerValue( void ) const return ( Listener * )m_data.listenerValue->Pointer(); default: - ScriptError( "Cannot cast '%s' to listener", typenames[ type ] ); + throw ScriptException( "Cannot cast '%s' to listener", typenames[ type ] ); } return NULL; @@ -1203,7 +1207,7 @@ str ScriptVariable::stringValue() const return str( "( " ) + str( m_data.vectorValue[ 0 ] ) + str( " " ) + str( m_data.vectorValue[ 1 ] ) + str( " " ) + str( m_data.vectorValue[ 2 ] + str( " )" ) ); default: - ScriptError( "Cannot cast '%s' to string", typenames[ GetType() ] ); + throw ScriptException( "Cannot cast '%s' to string", typenames[ GetType() ] ); break; } @@ -1225,7 +1229,7 @@ Vector ScriptVariable::vectorValue( void ) const string = stringValue(); if( strcmp( string, "" ) == 0 ) { - ScriptError( "cannot cast empty string to vector" ); + throw ScriptException( "cannot cast empty string to vector" ); } if( *string == '(' ) @@ -1233,7 +1237,7 @@ Vector ScriptVariable::vectorValue( void ) const if( sscanf( string, "(%f %f %f)", &x, &y, &z ) != 3 ) { if( sscanf( string, "(%f, %f, %f)", &x, &y, &z ) != 3 ) { - ScriptError( "Couldn't convert string to vector - malformed string '%s'", string ); + throw ScriptException( "Couldn't convert string to vector - malformed string '%s'", string ); } } } @@ -1242,7 +1246,7 @@ Vector ScriptVariable::vectorValue( void ) const if( sscanf( string, "%f %f %f", &x, &y, &z ) != 3 ) { if( sscanf( string, "%f, %f, %f", &x, &y, &z ) != 3 ) { - ScriptError( "Couldn't convert string to vector - malformed string '%s'", string ); + throw ScriptException( "Couldn't convert string to vector - malformed string '%s'", string ); } } } @@ -1251,25 +1255,25 @@ Vector ScriptVariable::vectorValue( void ) const case VARIABLE_LISTENER: { if( !m_data.listenerValue->Pointer() ) { - ScriptError( "Cannot cast NULL to vector" ); + throw ScriptException( "Cannot cast NULL to vector" ); } #ifndef NO_SCRIPTENGINE if( !checkInheritance( &SimpleEntity::ClassInfo, m_data.listenerValue->Pointer()->classinfo() ) ) { - ScriptError( "Cannot cast '%s' to vector", GetTypeName() ); + throw ScriptException( "Cannot cast '%s' to vector", GetTypeName() ); } SimpleEntity *ent = ( SimpleEntity * )m_data.listenerValue->Pointer(); return Vector( ent->origin[ 0 ], ent->origin[ 1 ], ent->origin[ 2 ] ); #else - ScriptError( "Cannot cast '%s' to vector", GetTypeName() ); + throw ScriptException( "Cannot cast '%s' to vector", GetTypeName() ); #endif } default: - ScriptError( "Cannot cast '%s' to vector", GetTypeName() ); + throw ScriptException( "Cannot cast '%s' to vector", GetTypeName() ); } } @@ -1281,12 +1285,12 @@ PathNode *ScriptVariable::pathNodeValue( void ) const if( !node ) { - ScriptError( "listener is NULL" ); + throw ScriptException( "listener is NULL" ); } if( !node->isSubclassOf( PathNode ) ) { - ScriptError( "listener is not a path node" ); + throw ScriptException( "listener is not a path node" ); } return ( PathNode * )node; @@ -1298,12 +1302,12 @@ Waypoint *ScriptVariable::waypointValue( void ) const if( !node ) { - ScriptError( "listener is NULL" ); + throw ScriptException( "listener is NULL" ); } if( !node->isSubclassOf( Waypoint ) ) { - ScriptError( "listener is not a way point" ); + throw ScriptException( "listener is not a way point" ); } return ( Waypoint * )node; @@ -1327,7 +1331,7 @@ void ScriptVariable::setArrayAtRef( ScriptVariable& index, ScriptVariable& value intValue = index.intValue(); if( intValue > 2 ) { - ScriptError( "Vector index '%d' out of range", intValue ); + throw ScriptException( "Vector index '%d' out of range", intValue ); } m_data.vectorValue[ intValue ] = value.floatValue(); @@ -1365,7 +1369,7 @@ void ScriptVariable::setArrayAtRef( ScriptVariable& index, ScriptVariable& value string = stringValue(); if( intValue >= strlen( string ) ) { - ScriptError( "String index '%d' out of range", intValue ); + throw ScriptException( "String index '%d' out of range", intValue ); } string[ intValue ] = value.charValue(); @@ -1378,7 +1382,7 @@ void ScriptVariable::setArrayAtRef( ScriptVariable& index, ScriptVariable& value intValue = index.intValue(); if( !intValue || intValue > m_data.constArrayValue->size ) { - ScriptError( "array index %d out of range", intValue ); + throw ScriptException( "array index %d out of range", intValue ); } if( value.GetType() ) @@ -1391,7 +1395,7 @@ void ScriptVariable::setArrayAtRef( ScriptVariable& index, ScriptVariable& value break; default: - ScriptError( "[] applied to invalid type '%s'\n", typenames[ GetType() ] ); + throw ScriptException( "[] applied to invalid type '%s'\n", typenames[ GetType() ] ); break; } } @@ -1533,7 +1537,7 @@ void ScriptVariable::operator+=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '+' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '+' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); break; @@ -1593,7 +1597,7 @@ void ScriptVariable::operator-=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '-' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '-' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); break; @@ -1626,7 +1630,7 @@ void ScriptVariable::operator*=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '*' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '*' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); break; @@ -1675,13 +1679,13 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '/' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '/' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); break; case VARIABLE_INTEGER + VARIABLE_INTEGER * VARIABLE_MAX: // ( int ) / ( int ) if( value.m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.intValue = m_data.intValue / value.m_data.intValue; @@ -1689,7 +1693,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_VECTOR + VARIABLE_INTEGER * VARIABLE_MAX: // ( vector ) / ( int ) if( value.m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } ( Vector )m_data.vectorValue = ( Vector )m_data.vectorValue / ( float )value.m_data.intValue; @@ -1697,7 +1701,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_VECTOR + VARIABLE_FLOAT * VARIABLE_MAX: // ( vector ) / ( float ) if( value.m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.vectorValue[ 0 ] = m_data.vectorValue[ 0 ] / value.m_data.floatValue; @@ -1707,7 +1711,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_INTEGER + VARIABLE_FLOAT * VARIABLE_MAX: // ( int ) / ( float ) if( value.m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } setFloatValue( ( float )m_data.intValue / value.m_data.floatValue ); @@ -1715,7 +1719,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_FLOAT + VARIABLE_FLOAT * VARIABLE_MAX: // ( float ) / ( float ) if( value.m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.floatValue = m_data.floatValue / value.m_data.floatValue; @@ -1723,7 +1727,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_FLOAT + VARIABLE_INTEGER * VARIABLE_MAX: // ( float ) / ( int ) if( value.m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.floatValue = m_data.floatValue / value.m_data.intValue; @@ -1731,7 +1735,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_INTEGER + VARIABLE_VECTOR * VARIABLE_MAX: // ( int ) / ( vector ) if( m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } setVectorValue( ( float )m_data.intValue / Vector( value.m_data.vectorValue ) ); @@ -1739,7 +1743,7 @@ void ScriptVariable::operator/=( const ScriptVariable& value ) case VARIABLE_FLOAT + VARIABLE_VECTOR * VARIABLE_MAX: // ( float ) / ( vector ) if( m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } setVectorValue( m_data.floatValue / Vector( value.m_data.vectorValue ) ); @@ -1772,13 +1776,13 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '%' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '%' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ value.GetType() ] ); break; case VARIABLE_INTEGER + VARIABLE_INTEGER * VARIABLE_MAX: // ( int ) % ( int ) if( value.m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.intValue = m_data.intValue % value.m_data.intValue; @@ -1786,7 +1790,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) case VARIABLE_VECTOR + VARIABLE_INTEGER * VARIABLE_MAX: // ( vector ) % ( int ) if( value.m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.vectorValue[ 0 ] = fmod( m_data.vectorValue[ 0 ], value.m_data.intValue ); @@ -1796,7 +1800,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) case VARIABLE_VECTOR + VARIABLE_FLOAT * VARIABLE_MAX: // ( vector ) % ( float ) if( value.m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.vectorValue[ 0 ] = fmod( m_data.vectorValue[ 0 ], value.m_data.floatValue ); @@ -1806,7 +1810,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) case VARIABLE_INTEGER + VARIABLE_FLOAT * VARIABLE_MAX: // ( int ) % ( float ) if( value.m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } setFloatValue( fmod( ( float )m_data.intValue, value.m_data.floatValue ) ); @@ -1814,7 +1818,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) case VARIABLE_FLOAT + VARIABLE_FLOAT * VARIABLE_MAX: // ( float ) % ( float ) if( value.m_data.floatValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.floatValue = fmod( m_data.floatValue, value.m_data.floatValue ); @@ -1822,7 +1826,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) case VARIABLE_FLOAT + VARIABLE_INTEGER * VARIABLE_MAX: // ( float ) % ( int ) if( value.m_data.intValue == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } m_data.floatValue = fmod( m_data.floatValue, ( float )value.m_data.intValue ); @@ -1832,7 +1836,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) mult = ( float )m_data.intValue; if( mult == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } setVectorValue( vec_zero ); @@ -1846,7 +1850,7 @@ void ScriptVariable::operator%=( const ScriptVariable& value ) mult = m_data.floatValue; if( mult == 0 ) { - ScriptError( "Division by zero error\n" ); + throw ScriptException( "Division by zero error\n" ); } setVectorValue( vec_zero ); @@ -1884,7 +1888,7 @@ void ScriptVariable::operator&=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '&' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '&' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); break; @@ -1903,7 +1907,7 @@ void ScriptVariable::operator^=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '^' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '^' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); break; @@ -1922,7 +1926,7 @@ void ScriptVariable::operator|=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '|' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '|' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); break; @@ -1941,7 +1945,7 @@ void ScriptVariable::operator<<=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '<<' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '<<' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); break; @@ -1960,7 +1964,7 @@ void ScriptVariable::operator>>=( const ScriptVariable& value ) default: Clear(); - ScriptError( "binary '>>' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); + throw ScriptException( "binary '>>' applied to incompatible types '%s' and '%s'", typenames[ type ], typenames[ value.GetType() ] ); break; @@ -2144,13 +2148,13 @@ ScriptVariable &ScriptVariable::operator[]( ScriptVariable& index ) if( i == 0 || i > m_data.constArrayValue->size ) { - ScriptError( "array index %d out of range", i ); + throw ScriptException( "array index %d out of range", i ); } return m_data.constArrayValue->constArrayValue[ i ]; default: - ScriptError( "[] applied to invalid type '%s'", typenames[ GetType() ] ); + throw ScriptException( "[] applied to invalid type '%s'", typenames[ GetType() ] ); } } @@ -2186,7 +2190,7 @@ void ScriptVariable::greaterthan( ScriptVariable &variable ) default: Clear(); - ScriptError( "binary '>' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); + throw ScriptException( "binary '>' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); break; @@ -2217,7 +2221,7 @@ void ScriptVariable::greaterthanorequal( ScriptVariable &variable ) default: Clear(); - ScriptError( "binary '>=' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); + throw ScriptException( "binary '>=' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); break; @@ -2248,7 +2252,7 @@ void ScriptVariable::lessthan( ScriptVariable &variable ) default: Clear(); - ScriptError( "binary '<' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); + throw ScriptException( "binary '<' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); break; @@ -2279,7 +2283,7 @@ void ScriptVariable::lessthanorequal( ScriptVariable &variable ) default: Clear(); - ScriptError( "binary '<=' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); + throw ScriptException( "binary '<=' applied to incompatible types '%s' and '%s'", typenames[ GetType() ], typenames[ variable.GetType() ] ); break; diff --git a/code/globalcpp/scriptvariable.h b/code/script/scriptvariable.h similarity index 99% rename from code/globalcpp/scriptvariable.h rename to code/script/scriptvariable.h index a4479e7d..9c8e8047 100644 --- a/code/globalcpp/scriptvariable.h +++ b/code/script/scriptvariable.h @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define __SCRIPTVARIABLE_H__ #include "listener.h" +#include "short3.h" #ifdef GAME_DLL #include "misc.h" @@ -112,7 +113,9 @@ public: class ScriptVariable { public: +#ifdef GAME_DLL short3 key; // variable name +#endif unsigned char type; // variable type union anon393 { public: diff --git a/code/server/sv_bot.c b/code/server/sv_bot.c deleted file mode 100644 index 0c436301..00000000 --- a/code/server/sv_bot.c +++ /dev/null @@ -1,632 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// sv_bot.c - -#include "server.h" -#include "../botlib/botlib.h" - -typedef struct bot_debugpoly_s -{ - int inuse; - int color; - int numPoints; - vec3_t points[128]; -} bot_debugpoly_t; - -static bot_debugpoly_t *debugpolygons; -int bot_maxdebugpolys; - -extern botlib_export_t *botlib_export; -int bot_enable; - - -/* -================== -SV_BotAllocateClient -================== -*/ -int SV_BotAllocateClient(void) { - int i; - client_t *cl; - - // find a client slot - for ( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { - if ( cl->state == CS_FREE ) { - break; - } - } - - if ( i == sv_maxclients->integer ) { - return -1; - } - - cl->gentity = SV_GentityNum( i ); - cl->gentity->s.number = i; - cl->state = CS_ACTIVE; - cl->lastPacketTime = svs.time; - cl->netchan.remoteAddress.type = NA_BOT; - cl->rate = 16384; - - return i; -} - -/* -================== -SV_BotFreeClient -================== -*/ -void SV_BotFreeClient( int clientNum ) { - client_t *cl; - - if ( clientNum < 0 || clientNum >= sv_maxclients->integer ) { - Com_Error( ERR_DROP, "SV_BotFreeClient: bad clientNum: %i", clientNum ); - } - cl = &svs.clients[clientNum]; - cl->state = CS_FREE; - cl->name[0] = 0; - if ( cl->gentity ) { - cl->gentity->r.svFlags &= ~SVF_BOT; - } -} - -/* -================== -BotDrawDebugPolygons -================== -*/ -void BotDrawDebugPolygons(void (*drawPoly)(int color, int numPoints, float *points), int value) { - static cvar_t *bot_debug, *bot_groundonly, *bot_reachability, *bot_highlightarea; - bot_debugpoly_t *poly; - int i, parm0; - - if (!debugpolygons) - return; - //bot debugging - if (!bot_debug) bot_debug = Cvar_Get("bot_debug", "0", 0); - // - if (bot_enable && bot_debug->integer) { - //show reachabilities - if (!bot_reachability) bot_reachability = Cvar_Get("bot_reachability", "0", 0); - //show ground faces only - if (!bot_groundonly) bot_groundonly = Cvar_Get("bot_groundonly", "1", 0); - //get the hightlight area - if (!bot_highlightarea) bot_highlightarea = Cvar_Get("bot_highlightarea", "0", 0); - // - parm0 = 0; - if (svs.clients[0].lastUsercmd.buttons & BUTTON_ATTACK) parm0 |= 1; - if (bot_reachability->integer) parm0 |= 2; - if (bot_groundonly->integer) parm0 |= 4; - botlib_export->BotLibVarSet("bot_highlightarea", bot_highlightarea->string); - botlib_export->Test(parm0, NULL, svs.clients[0].gentity->r.currentOrigin, - svs.clients[0].gentity->r.currentAngles); - } //end if - //draw all debug polys - for (i = 0; i < bot_maxdebugpolys; i++) { - poly = &debugpolygons[i]; - if (!poly->inuse) continue; - drawPoly(poly->color, poly->numPoints, (float *) poly->points); - //Com_Printf("poly %i, numpoints = %d\n", i, poly->numPoints); - } -} - -/* -================== -BotImport_Print -================== -*/ -void QDECL BotImport_Print(int type, char *fmt, ...) -{ - char str[2048]; - va_list ap; - - va_start(ap, fmt); - vsprintf(str, fmt, ap); - va_end(ap); - - switch(type) { - case PRT_MESSAGE: { - Com_Printf("%s", str); - break; - } - case PRT_WARNING: { - Com_Printf(S_COLOR_YELLOW "Warning: %s", str); - break; - } - case PRT_ERROR: { - Com_Printf(S_COLOR_RED "Error: %s", str); - break; - } - case PRT_FATAL: { - Com_Printf(S_COLOR_RED "Fatal: %s", str); - break; - } - case PRT_EXIT: { - Com_Error(ERR_DROP, S_COLOR_RED "Exit: %s", str); - break; - } - default: { - Com_Printf("unknown print type\n"); - break; - } - } -} - -/* -================== -BotImport_Trace -================== -*/ -void BotImport_Trace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask) { - trace_t trace; - - SV_Trace(&trace, start, mins, maxs, end, passent, contentmask, qfalse,qfalse); - //copy the trace information - bsptrace->allsolid = trace.allsolid; - bsptrace->startsolid = trace.startsolid; - bsptrace->fraction = trace.fraction; - VectorCopy(trace.endpos, bsptrace->endpos); - bsptrace->plane.dist = trace.plane.dist; - VectorCopy(trace.plane.normal, bsptrace->plane.normal); - bsptrace->plane.signbits = trace.plane.signbits; - bsptrace->plane.type = trace.plane.type; - bsptrace->surface.value = trace.surfaceFlags; - bsptrace->ent = trace.entityNum; - bsptrace->exp_dist = 0; - bsptrace->sidenum = 0; - bsptrace->contents = 0; -} - -/* -================== -BotImport_EntityTrace -================== -*/ -void BotImport_EntityTrace(bsp_trace_t *bsptrace, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int entnum, int contentmask) { - trace_t trace; - - SV_ClipToEntity(&trace, start, mins, maxs, end, entnum, contentmask); - //copy the trace information - bsptrace->allsolid = trace.allsolid; - bsptrace->startsolid = trace.startsolid; - bsptrace->fraction = trace.fraction; - VectorCopy(trace.endpos, bsptrace->endpos); - bsptrace->plane.dist = trace.plane.dist; - VectorCopy(trace.plane.normal, bsptrace->plane.normal); - bsptrace->plane.signbits = trace.plane.signbits; - bsptrace->plane.type = trace.plane.type; - bsptrace->surface.value = trace.surfaceFlags; - bsptrace->ent = trace.entityNum; - bsptrace->exp_dist = 0; - bsptrace->sidenum = 0; - bsptrace->contents = 0; -} - - -/* -================== -BotImport_PointContents -================== -*/ -int BotImport_PointContents(vec3_t point) { - return SV_PointContents(point, -1); -} - -/* -================== -BotImport_inPVS -================== -*/ -int BotImport_inPVS(vec3_t p1, vec3_t p2) { - return SV_inPVS (p1, p2); -} - -/* -================== -BotImport_BSPEntityData -================== -*/ -char *BotImport_BSPEntityData(void) { - return CM_EntityString(); -} - -/* -================== -BotImport_BSPModelMinsMaxsOrigin -================== -*/ -void BotImport_BSPModelMinsMaxsOrigin(int modelnum, vec3_t angles, vec3_t outmins, vec3_t outmaxs, vec3_t origin) { - clipHandle_t h; - vec3_t mins, maxs; - float max; - int i; - - h = CM_InlineModel(modelnum); - CM_ModelBounds(h, mins, maxs); - //if the model is rotated - if ((angles[0] || angles[1] || angles[2])) { - // expand for rotation - - max = RadiusFromBounds(mins, maxs); - for (i = 0; i < 3; i++) { - mins[i] = -max; - maxs[i] = max; - } - } - if (outmins) VectorCopy(mins, outmins); - if (outmaxs) VectorCopy(maxs, outmaxs); - if (origin) VectorClear(origin); -} - -/* -================== -BotImport_GetMemory -================== -*/ -void *BotImport_GetMemory(int size) { - void *ptr; - - ptr = Z_TagMalloc( size, TAG_BOTLIB ); - return ptr; -} - -/* -================== -BotImport_FreeMemory -================== -*/ -void BotImport_FreeMemory(void *ptr) { - Z_Free(ptr); -} - -/* -================= -BotImport_HunkAlloc -================= -*/ -void *BotImport_HunkAlloc( int size ) { - if( Hunk_CheckMark() ) { - Com_Error( ERR_DROP, "SV_Bot_HunkAlloc: Alloc with marks already set\n" ); - } - return Hunk_Alloc( size, h_high ); -} - -/* -================== -BotImport_DebugPolygonCreate -================== -*/ -int BotImport_DebugPolygonCreate(int color, int numPoints, vec3_t *points) { - bot_debugpoly_t *poly; - int i; - - if (!debugpolygons) - return 0; - - for (i = 1; i < bot_maxdebugpolys; i++) { - if (!debugpolygons[i].inuse) - break; - } - if (i >= bot_maxdebugpolys) - return 0; - poly = &debugpolygons[i]; - poly->inuse = qtrue; - poly->color = color; - poly->numPoints = numPoints; - Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); - // - return i; -} - -/* -================== -BotImport_DebugPolygonShow -================== -*/ -void BotImport_DebugPolygonShow(int id, int color, int numPoints, vec3_t *points) { - bot_debugpoly_t *poly; - - if (!debugpolygons) return; - poly = &debugpolygons[id]; - poly->inuse = qtrue; - poly->color = color; - poly->numPoints = numPoints; - Com_Memcpy(poly->points, points, numPoints * sizeof(vec3_t)); -} - -/* -================== -BotImport_DebugPolygonDelete -================== -*/ -void BotImport_DebugPolygonDelete(int id) -{ - if (!debugpolygons) return; - debugpolygons[id].inuse = qfalse; -} - -/* -================== -BotImport_DebugLineCreate -================== -*/ -int BotImport_DebugLineCreate(void) { - vec3_t points[1]; - return BotImport_DebugPolygonCreate(0, 0, points); -} - -/* -================== -BotImport_DebugLineDelete -================== -*/ -void BotImport_DebugLineDelete(int line) { - BotImport_DebugPolygonDelete(line); -} - -/* -================== -BotImport_DebugLineShow -================== -*/ -void BotImport_DebugLineShow(int line, vec3_t start, vec3_t end, int color) { - vec3_t points[4], dir, cross, up = {0, 0, 1}; - float dot; - - VectorCopy(start, points[0]); - VectorCopy(start, points[1]); - //points[1][2] -= 2; - VectorCopy(end, points[2]); - //points[2][2] -= 2; - VectorCopy(end, points[3]); - - - VectorSubtract(end, start, dir); - VectorNormalize(dir); - dot = DotProduct(dir, up); - if (dot > 0.99 || dot < -0.99) VectorSet(cross, 1, 0, 0); - else CrossProduct(dir, up, cross); - - VectorNormalize(cross); - - VectorMA(points[0], 2, cross, points[0]); - VectorMA(points[1], -2, cross, points[1]); - VectorMA(points[2], -2, cross, points[2]); - VectorMA(points[3], 2, cross, points[3]); - - BotImport_DebugPolygonShow(line, color, 4, points); -} - -/* -================== -SV_BotClientCommand -================== -*/ -void BotClientCommand( int client, char *command ) { - SV_ExecuteClientCommand( &svs.clients[client], command, qtrue ); -} - -/* -================== -SV_BotFrame -================== -*/ -void SV_BotFrame( int time ) { - if (!bot_enable) return; - //NOTE: maybe the game is already shutdown - if (!ge) return; - - //VM_Call( gvm, BOTAI_START_FRAME, time ); -} - -/* -=============== -SV_BotLibSetup -=============== -*/ -int SV_BotLibSetup( void ) { - if (!bot_enable) { - return 0; - } - - if ( !botlib_export ) { - Com_Printf( S_COLOR_RED "Error: SV_BotLibSetup without SV_BotInitBotLib\n" ); - return -1; - } - - return botlib_export->BotLibSetup(); -} - -/* -=============== -SV_ShutdownBotLib - -Called when either the entire server is being killed, or -it is changing to a different game directory. -=============== -*/ -int SV_BotLibShutdown( void ) { - - if ( !botlib_export ) { - return -1; - } - - return botlib_export->BotLibShutdown(); -} - -/* -================== -SV_BotInitCvars -================== -*/ -void SV_BotInitCvars(void) { - - Cvar_Get("bot_enable", "1", 0); //enable the bot //wombat: disabled for now - Cvar_Get("bot_developer", "0", CVAR_CHEAT); //bot developer mode - Cvar_Get("bot_debug", "0", CVAR_CHEAT); //enable bot debugging - Cvar_Get("bot_maxdebugpolys", "2", 0); //maximum number of debug polys - Cvar_Get("bot_groundonly", "1", 0); //only show ground faces of areas - Cvar_Get("bot_reachability", "0", 0); //show all reachabilities to other areas - Cvar_Get("bot_visualizejumppads", "0", CVAR_CHEAT); //show jumppads - Cvar_Get("bot_forceclustering", "0", 0); //force cluster calculations - Cvar_Get("bot_forcereachability", "0", 0); //force reachability calculations - Cvar_Get("bot_forcewrite", "0", 0); //force writing aas file - Cvar_Get("bot_aasoptimize", "0", 0); //no aas file optimisation - Cvar_Get("bot_saveroutingcache", "0", 0); //save routing cache - Cvar_Get("bot_thinktime", "100", CVAR_CHEAT); //msec the bots thinks - Cvar_Get("bot_reloadcharacters", "0", 0); //reload the bot characters each time - Cvar_Get("bot_testichat", "0", 0); //test ichats - Cvar_Get("bot_testrchat", "0", 0); //test rchats - Cvar_Get("bot_testsolid", "0", CVAR_CHEAT); //test for solid areas - Cvar_Get("bot_testclusters", "0", CVAR_CHEAT); //test the AAS clusters - Cvar_Get("bot_fastchat", "0", 0); //fast chatting bots - Cvar_Get("bot_nochat", "0", 0); //disable chats - Cvar_Get("bot_pause", "0", CVAR_CHEAT); //pause the bots thinking - Cvar_Get("bot_report", "0", CVAR_CHEAT); //get a full report in ctf - Cvar_Get("bot_grapple", "0", 0); //enable grapple - Cvar_Get("bot_rocketjump", "1", 0); //enable rocket jumping - Cvar_Get("bot_challenge", "0", 0); //challenging bot - Cvar_Get("bot_minplayers", "0", 0); //minimum players in a team or the game - Cvar_Get("bot_interbreedchar", "", CVAR_CHEAT); //bot character used for interbreeding - Cvar_Get("bot_interbreedbots", "10", CVAR_CHEAT); //number of bots used for interbreeding - Cvar_Get("bot_interbreedcycle", "20", CVAR_CHEAT); //bot interbreeding cycle - Cvar_Get("bot_interbreedwrite", "", CVAR_CHEAT); //write interbreeded bots to this file -} - -/* -================== -SV_BotInitBotLib -================== -*/ -void SV_BotInitBotLib(void) { - botlib_import_t botlib_import; - - if (debugpolygons) Z_Free(debugpolygons); - bot_maxdebugpolys = Cvar_VariableIntegerValue("bot_maxdebugpolys"); - debugpolygons = Z_Malloc(sizeof(bot_debugpoly_t) * bot_maxdebugpolys); - - botlib_import.Print = BotImport_Print; - botlib_import.Trace = BotImport_Trace; - botlib_import.EntityTrace = BotImport_EntityTrace; - botlib_import.PointContents = BotImport_PointContents; - botlib_import.inPVS = BotImport_inPVS; - botlib_import.BSPEntityData = BotImport_BSPEntityData; - botlib_import.BSPModelMinsMaxsOrigin = BotImport_BSPModelMinsMaxsOrigin; - botlib_import.BotClientCommand = BotClientCommand; - - //memory management - botlib_import.GetMemory = BotImport_GetMemory; - botlib_import.FreeMemory = BotImport_FreeMemory; - botlib_import.AvailableMemory = Z_AvailableMemory; - botlib_import.HunkAlloc = BotImport_HunkAlloc; - - // file system access - botlib_import.FS_FOpenFile = FS_FOpenFileByMode; - botlib_import.FS_Read = FS_Read2; - botlib_import.FS_Write = FS_Write; - botlib_import.FS_FCloseFile = FS_FCloseFile; - botlib_import.FS_Seek = FS_Seek; - - //debug lines - botlib_import.DebugLineCreate = BotImport_DebugLineCreate; - botlib_import.DebugLineDelete = BotImport_DebugLineDelete; - botlib_import.DebugLineShow = BotImport_DebugLineShow; - - //debug polygons - botlib_import.DebugPolygonCreate = BotImport_DebugPolygonCreate; - botlib_import.DebugPolygonDelete = BotImport_DebugPolygonDelete; - - botlib_export = (botlib_export_t *)GetBotLibAPI( BOTLIB_API_VERSION, &botlib_import ); - assert(botlib_export); // somehow we end up with a zero import. -} - - -// -// * * * BOT AI CODE IS BELOW THIS POINT * * * -// - -/* -================== -SV_BotGetConsoleMessage -================== -*/ -int SV_BotGetConsoleMessage( int client, char *buf, int size ) -{ - client_t *cl; - int index; - - cl = &svs.clients[client]; - cl->lastPacketTime = svs.time; - - if ( cl->reliableAcknowledge == cl->reliableSequence ) { - return qfalse; - } - - cl->reliableAcknowledge++; - index = cl->reliableAcknowledge & ( MAX_RELIABLE_COMMANDS - 1 ); - - if ( !cl->reliableCommands[index][0] ) { - return qfalse; - } - - Q_strncpyz( buf, cl->reliableCommands[index], size ); - return qtrue; -} - -#if 0 -/* -================== -EntityInPVS -================== -*/ -int EntityInPVS( int client, int entityNum ) { - client_t *cl; - clientSnapshot_t *frame; - int i; - - cl = &svs.clients[client]; - frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; - for ( i = 0; i < frame->num_entities; i++ ) { - if ( svs.snapshotEntities[(frame->first_entity + i) % svs.numSnapshotEntities].number == entityNum ) { - return qtrue; - } - } - return qfalse; -} -#endif - -/* -================== -SV_BotGetSnapshotEntity -================== -*/ -int SV_BotGetSnapshotEntity( int client, int sequence ) { - client_t *cl; - clientSnapshot_t *frame; - - cl = &svs.clients[client]; - frame = &cl->frames[cl->netchan.outgoingSequence & PACKET_MASK]; - if (sequence < 0 || sequence >= frame->num_entities) { - return -1; - } - return svs.snapshotEntities[(frame->first_entity + sequence) % svs.numSnapshotEntities].number; -} - diff --git a/code/server/sv_rankings.c b/code/server/sv_rankings.c deleted file mode 100644 index 844447be..00000000 --- a/code/server/sv_rankings.c +++ /dev/null @@ -1,1537 +0,0 @@ -/* -=========================================================================== -Copyright (C) 1999-2005 Id Software, Inc. - -This file is part of Quake III Arena source code. - -Quake III Arena source code 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. - -Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ -// sv_rankings.c -- global rankings interface - -#include "server.h" -#include "..\rankings\1.0\gr\grapi.h" -#include "..\rankings\1.0\gr\grlog.h" - -typedef struct -{ - GR_CONTEXT context; - uint64_t game_id; - uint64_t match; - uint64_t player_id; - GR_PLAYER_TOKEN token; - grank_status_t grank_status; - grank_status_t final_status; // status to set after cleanup - uint32_t grank; // global rank - char name[32]; -} ranked_player_t; - -static int s_rankings_contexts = 0; -static qboolean s_rankings_active = qfalse; -static GR_CONTEXT s_server_context = 0; -static uint64_t s_server_match = 0; -static char* s_rankings_game_key = NULL; -static uint64_t s_rankings_game_id = 0; -static ranked_player_t* s_ranked_players = NULL; -static qboolean s_server_quitting = qfalse; -static const char s_ascii_encoding[] = - "0123456789abcdef" - "ghijklmnopqrstuv" - "wxyzABCDEFGHIJKL" - "MNOPQRSTUVWXYZ[]"; - -// private functions -static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg ); -static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg ); -static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg ); -static void SV_RankSendReportsCBF( GR_STATUS* gr_status, void* cbf_arg ); -static void SV_RankCleanupCBF( GR_STATUS* gr_status, void* cbf_arg ); -static void SV_RankCloseContext( ranked_player_t* ranked_player ); -static int SV_RankAsciiEncode( char* dest, const unsigned char* src, - int src_len ); -static int SV_RankAsciiDecode( unsigned char* dest, const char* src, - int src_len ); -static void SV_RankEncodeGameID( uint64_t game_id, char* result, - int len ); -static uint64_t SV_RankDecodePlayerID( const char* string ); -static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key ); -static char* SV_RankStatusString( GR_STATUS status ); -static void SV_RankError( const char* fmt, ... ); -static char SV_RankGameKey[64]; - -/* -================ -SV_RankBegin -================ -*/ -void SV_RankBegin( char *gamekey ) -{ - GR_INIT init; - GR_STATUS status; - - assert( s_rankings_contexts == 0 ); - assert( !s_rankings_active ); - assert( s_ranked_players == NULL ); - - if( sv_enableRankings->integer == 0 || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) - { - s_rankings_active = qfalse; - if( sv_rankingsActive->integer == 1 ) - { - Cvar_Set( "sv_rankingsActive", "0" ); - } - return; - } - - // only allow official game key on pure servers - if( strcmp(gamekey, GR_GAMEKEY) == 0 ) - { -/* - if( Cvar_VariableValue("sv_pure") != 1 ) - { - Cvar_Set( "sv_enableRankings", "0" ); - return; - } -*/ - - // substitute game-specific game key - switch( (int)Cvar_VariableValue("g_gametype") ) - { - case GT_FFA: - gamekey = "Q3 Free For All"; - break; - case GT_TOURNAMENT: - gamekey = "Q3 Tournament"; - break; - case GT_TEAM: - gamekey = "Q3 Team Deathmatch"; - break; - case GT_CTF: - gamekey = "Q3 Capture the Flag"; - break; - case GT_1FCTF: - gamekey = "Q3 One Flag CTF"; - break; - case GT_OBELISK: - gamekey = "Q3 Overload"; - break; - case GT_HARVESTER: - gamekey = "Q3 Harvester"; - break; - default: - break; - } - } - s_rankings_game_key = gamekey; - - // initialize rankings - GRankLogLevel( GRLOG_OFF ); - memset(SV_RankGameKey,0,sizeof(SV_RankGameKey)); - strncpy(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)-1); - init = GRankInit( 1, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); - s_server_context = init.context; - s_rankings_contexts++; - Com_DPrintf( "SV_RankBegin(); GR_GAMEKEY is %s\n", gamekey ); - Com_DPrintf( "SV_RankBegin(); s_rankings_contexts=%d\n",s_rankings_contexts ); - Com_DPrintf( "SV_RankBegin(); s_server_context=%d\n",init.context ); - - // new game - if(!strlen(Cvar_VariableString( "sv_leagueName" ))) - { - status = GRankNewGameAsync - ( - s_server_context, - SV_RankNewGameCBF, - NULL, - GR_OPT_LEAGUENAME, - (void*)(Cvar_VariableString( "sv_leagueName" )), - GR_OPT_END - ); - } - else - { - status = GRankNewGameAsync - ( - s_server_context, - SV_RankNewGameCBF, - NULL, - GR_OPT_END - ); - } - - if( status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankBegin: Expected GR_STATUS_PENDING, got %s", - SV_RankStatusString( status ) ); - return; - } - - // logging - if( com_developer->value ) - { - GRankLogLevel( GRLOG_TRACE ); - } - - // allocate rankings info for each player - s_ranked_players = Z_Malloc( sv_maxclients->value * - sizeof(ranked_player_t) ); - memset( (void*)s_ranked_players, 0 ,sv_maxclients->value - * sizeof(ranked_player_t)); -} - -/* -================ -SV_RankEnd -================ -*/ -void SV_RankEnd( void ) -{ - GR_STATUS status; - int i; - - Com_DPrintf( "SV_RankEnd();\n" ); - - if( !s_rankings_active ) - { - // cleanup after error during game - if( s_ranked_players != NULL ) - { - for( i = 0; i < sv_maxclients->value; i++ ) - { - if( s_ranked_players[i].context != 0 ) - { - SV_RankCloseContext( &(s_ranked_players[i]) ); - } - } - } - if( s_server_context != 0 ) - { - SV_RankCloseContext( NULL ); - } - - return; - } - - for( i = 0; i < sv_maxclients->value; i++ ) - { - if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE ) - { - SV_RankUserLogout( i ); - Com_DPrintf( "SV_RankEnd: SV_RankUserLogout %d\n",i ); - } - } - - assert( s_server_context != 0 ); - - // send match reports, proceed to SV_RankSendReportsCBF - status = GRankSendReportsAsync - ( - s_server_context, - 0, - SV_RankSendReportsCBF, - NULL, - GR_OPT_END - ); - - if( status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankEnd: Expected GR_STATUS_PENDING, got %s", - SV_RankStatusString( status ) ); - } - - s_rankings_active = qfalse; - Cvar_Set( "sv_rankingsActive", "0" ); -} - -/* -================ -SV_RankPoll -================ -*/ -void SV_RankPoll( void ) -{ - GRankPoll(); -} - -/* -================ -SV_RankCheckInit -================ -*/ -qboolean SV_RankCheckInit( void ) -{ - return (s_rankings_contexts > 0); -} - -/* -================ -SV_RankActive -================ -*/ -qboolean SV_RankActive( void ) -{ - return s_rankings_active; -} - -/* -================= -SV_RankUserStatus -================= -*/ -grank_status_t SV_RankUserStatus( int index ) -{ - if( !s_rankings_active ) - { - return GR_STATUS_ERROR; - } - - assert( s_ranked_players != NULL ); - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - - return s_ranked_players[index].grank_status; -} - -/* -================ -SV_RankUserGRank -================ -*/ -int SV_RankUserGrank( int index ) -{ - if( !s_rankings_active ) - { - return 0; - } - - assert( s_ranked_players != NULL ); - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - - return s_ranked_players[index].grank; -} - -/* -================ -SV_RankUserReset -================ -*/ -void SV_RankUserReset( int index ) -{ - if( !s_rankings_active ) - { - return; - } - - assert( s_ranked_players != NULL ); - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - - switch( s_ranked_players[index].grank_status ) - { - case QGR_STATUS_SPECTATOR: - case QGR_STATUS_NO_USER: - case QGR_STATUS_BAD_PASSWORD: - case QGR_STATUS_USER_EXISTS: - case QGR_STATUS_NO_MEMBERSHIP: - case QGR_STATUS_TIMEOUT: - case QGR_STATUS_ERROR: - s_ranked_players[index].grank_status = QGR_STATUS_NEW; - break; - default: - break; - } -} - -/* -================ -SV_RankUserSpectate -================ -*/ -void SV_RankUserSpectate( int index ) -{ - if( !s_rankings_active ) - { - return; - } - - assert( s_ranked_players != NULL ); - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - - // GRANK_FIXME - check current status? - s_ranked_players[index].grank_status = QGR_STATUS_SPECTATOR; -} - -/* -================ -SV_RankUserCreate -================ -*/ -void SV_RankUserCreate( int index, char* username, char* password, - char* email ) -{ - GR_INIT init; - GR_STATUS status; - - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - assert( username != NULL ); - assert( password != NULL ); - assert( email != NULL ); - assert( s_ranked_players ); - assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE ); - - Com_DPrintf( "SV_RankUserCreate( %d, %s, \"****\", %s );\n", index, - username, email ); - - if( !s_rankings_active ) - { - Com_DPrintf( "SV_RankUserCreate: Not ready to create\n" ); - s_ranked_players[index].grank_status = QGR_STATUS_ERROR; - return; - } - - if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE ) - { - Com_DPrintf( "SV_RankUserCreate: Got Create from active player\n" ); - return; - } - - // get a separate context for the new user - init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); - s_ranked_players[index].context = init.context; - s_rankings_contexts++; - Com_DPrintf( "SV_RankUserCreate(); s_rankings_contexts=%d\n",s_rankings_contexts ); - Com_DPrintf( "SV_RankUserCreate(); s_ranked_players[%d].context=%d\n",index,init.context ); - - // attempt to create a new account, proceed to SV_RankUserCBF - status = GRankUserCreateAsync - ( - s_ranked_players[index].context, - username, - password, - email, - SV_RankUserCBF, - (void*)&s_ranked_players[index], - GR_OPT_END - ); - - if( status == GR_STATUS_PENDING ) - { - s_ranked_players[index].grank_status = QGR_STATUS_PENDING; - s_ranked_players[index].final_status = QGR_STATUS_NEW; - } - else - { - SV_RankError( "SV_RankUserCreate: Expected GR_STATUS_PENDING, got %s", - SV_RankStatusString( status ) ); - } -} - -/* -================ -SV_RankUserLogin -================ -*/ -void SV_RankUserLogin( int index, char* username, char* password ) -{ - GR_INIT init; - GR_STATUS status; - - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - assert( username != NULL ); - assert( password != NULL ); - assert( s_ranked_players ); - assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE ); - - Com_DPrintf( "SV_RankUserLogin( %d, %s, \"****\" );\n", index, username ); - - if( !s_rankings_active ) - { - Com_DPrintf( "SV_RankUserLogin: Not ready for login\n" ); - s_ranked_players[index].grank_status = QGR_STATUS_ERROR; - return; - } - - if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE ) - { - Com_DPrintf( "SV_RankUserLogin: Got Login from active player\n" ); - return; - } - - // get a separate context for the new user - init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); - s_ranked_players[index].context = init.context; - s_rankings_contexts++; - Com_DPrintf( "SV_RankUserLogin(); s_rankings_contexts=%d\n",s_rankings_contexts ); - Com_DPrintf( "SV_RankUserLogin(); s_ranked_players[%d].context=%d\n",index,init.context ); - - // login user, proceed to SV_RankUserCBF - status = GRankUserLoginAsync - ( - s_ranked_players[index].context, - username, - password, - SV_RankUserCBF, - (void*)&s_ranked_players[index], - GR_OPT_END - ); - - if( status == GR_STATUS_PENDING ) - { - s_ranked_players[index].grank_status = QGR_STATUS_PENDING; - s_ranked_players[index].final_status = QGR_STATUS_NEW; - } - else - { - SV_RankError( "SV_RankUserLogin: Expected GR_STATUS_PENDING, got %s", - SV_RankStatusString( status ) ); - } -} - -/* -=================== -SV_RankUserValidate -=================== -*/ -qboolean SV_RankUserValidate( int index, const char* player_id, const char* key, int token_len, int rank, char* name ) -{ - GR_INIT init; - GR_STATUS status; - qboolean rVal; - ranked_player_t* ranked_player; - int i; - - assert( s_ranked_players ); - assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE ); - - rVal = qfalse; - - if( !s_rankings_active ) - { - Com_DPrintf( "SV_RankUserValidate: Not ready to validate\n" ); - s_ranked_players[index].grank_status = QGR_STATUS_ERROR; - return rVal; - } - - ranked_player = &(s_ranked_players[index]); - - if ( (player_id != NULL) && (key != NULL)) - { - // the real player_id and key is set when SV_RankJoinGameCBF - // is called we do this so that SV_RankUserValidate - // can be shared by both server side login and client side login - - // for client side logined in players - // server is creating GR_OPT_PLAYERCONTEXT - init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END ); - ranked_player->context = init.context; - s_rankings_contexts++; - Com_DPrintf( "SV_RankUserValidate(); s_rankings_contexts=%d\n",s_rankings_contexts ); - Com_DPrintf( "SV_RankUserValidate(); s_ranked_players[%d].context=%d\n",index,init.context ); - - // uudecode player id and player token - ranked_player->player_id = SV_RankDecodePlayerID(player_id); - Com_DPrintf( "SV_RankUserValidate(); ranked_player->player_id =%u\n", (uint32_t)ranked_player->player_id ); - SV_RankDecodePlayerKey(key, ranked_player->token); - - // save name and check for duplicates - Q_strncpyz( ranked_player->name, name, sizeof(ranked_player->name) ); - for( i = 0; i < sv_maxclients->value; i++ ) - { - if( (i != index) && (s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE) && - (strcmp( s_ranked_players[i].name, name ) == 0) ) - { - Com_DPrintf( "SV_RankUserValidate: Duplicate login\n" ); - ranked_player->grank_status = QGR_STATUS_NO_USER; - ranked_player->final_status = QGR_STATUS_NEW; - ranked_player->grank = 0; - return qfalse; - } - } - - // then validate - status = GRankPlayerValidate( - s_server_context, - ranked_player->player_id, - ranked_player->token, - token_len, - GR_OPT_PLAYERCONTEXT, - ranked_player->context, - GR_OPT_END); - } - else - { - // make server side login (bots) happy - status = GR_STATUS_OK; - } - - if (status == GR_STATUS_OK) - { - ranked_player->grank_status = QGR_STATUS_ACTIVE; - ranked_player->final_status = QGR_STATUS_NEW; - ranked_player->grank = rank; - rVal = qtrue; - } - else if (status == GR_STATUS_INVALIDUSER) - { - ranked_player->grank_status = QGR_STATUS_INVALIDUSER; - ranked_player->final_status = QGR_STATUS_NEW; - ranked_player->grank = 0; - rVal = qfalse; - } - else - { - SV_RankError( "SV_RankUserValidate: Unexpected status %s", - SV_RankStatusString( status ) ); - s_ranked_players[index].grank_status = QGR_STATUS_ERROR; - ranked_player->grank = 0; - } - - return rVal; -} - -/* -================ -SV_RankUserLogout -================ -*/ -void SV_RankUserLogout( int index ) -{ - GR_STATUS status; - GR_STATUS cleanup_status; - - if( !s_rankings_active ) - { - return; - } - - assert( index >= 0 ); - assert( index < sv_maxclients->value ); - assert( s_ranked_players ); - - if( s_ranked_players[index].context == 0 ) { - return; - } - - Com_DPrintf( "SV_RankUserLogout( %d );\n", index ); - - // masqueraded player may not be active yet, if they fail validation, - // but still they have a context needs to be cleaned - // what matters is the s_ranked_players[index].context - - // send reports, proceed to SV_RankSendReportsCBF - status = GRankSendReportsAsync - ( - s_ranked_players[index].context, - 0, - SV_RankSendReportsCBF, - (void*)&s_ranked_players[index], - GR_OPT_END - ); - - if( status == GR_STATUS_PENDING ) - { - s_ranked_players[index].grank_status = QGR_STATUS_PENDING; - s_ranked_players[index].final_status = QGR_STATUS_NEW; - } - else - { - SV_RankError( "SV_RankUserLogout: Expected GR_STATUS_PENDING, got %s", - SV_RankStatusString( status ) ); - - cleanup_status = GRankCleanupAsync - ( - s_ranked_players[index].context, - 0, - SV_RankCleanupCBF, - (void*)&s_ranked_players[index], - GR_OPT_END - ); - - if( cleanup_status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankUserLogout: Expected " - "GR_STATUS_PENDING from GRankCleanupAsync, got %s", - SV_RankStatusString( cleanup_status ) ); - SV_RankCloseContext( &(s_ranked_players[index]) ); - } - } -} - -/* -================ -SV_RankReportInt -================ -*/ -void SV_RankReportInt( int index1, int index2, int key, int value, - qboolean accum ) -{ - GR_STATUS status; - GR_CONTEXT context; - uint64_t match; - uint64_t user1; - uint64_t user2; - int opt_accum; - - if( !s_rankings_active ) - { - return; - } - - assert( index1 >= -1 ); - assert( index1 < sv_maxclients->value ); - assert( index2 >= -1 ); - assert( index2 < sv_maxclients->value ); - assert( s_ranked_players ); - -// Com_DPrintf( "SV_RankReportInt( %d, %d, %d, %d, %d );\n", index1, index2, -// key, value, accum ); - - // get context, match, and player_id for player index1 - if( index1 == -1 ) - { - context = s_server_context; - match = s_server_match; - user1 = 0; - } - else - { - if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE ) - { - Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE" - " Got Unexpected status %d for player %d\n", - s_ranked_players[index1].grank_status, index1 ); - return; - } - - context = s_ranked_players[index1].context; - match = s_ranked_players[index1].match; - user1 = s_ranked_players[index1].player_id; - } - - // get player_id for player index2 - if( index2 == -1 ) - { - user2 = 0; - } - else - { - if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE ) - { - Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE" - " Got Unexpected status %d for player %d\n", - s_ranked_players[index2].grank_status, index2 ); - return; - } - - user2 = s_ranked_players[index2].player_id; - } - - opt_accum = accum ? GR_OPT_ACCUM : GR_OPT_END; - - status = GRankReportInt - ( - context, - match, - user1, - user2, - key, - value, - opt_accum, - GR_OPT_END - ); - - if( status != GR_STATUS_OK ) - { - SV_RankError( "SV_RankReportInt: Unexpected status %s", - SV_RankStatusString( status ) ); - } - - if( user2 != 0 ) - { - context = s_ranked_players[index2].context; - match = s_ranked_players[index2].match; - - status = GRankReportInt - ( - context, - match, - user1, - user2, - key, - value, - opt_accum, - GR_OPT_END - ); - - if( status != GR_STATUS_OK ) - { - SV_RankError( "SV_RankReportInt: Unexpected status %s", - SV_RankStatusString( status ) ); - } - } -} - -/* -================ -SV_RankReportStr -================ -*/ -void SV_RankReportStr( int index1, int index2, int key, char* value ) -{ - GR_STATUS status; - GR_CONTEXT context; - uint64_t match; - uint64_t user1; - uint64_t user2; - - if( !s_rankings_active ) - { - return; - } - - assert( index1 >= -1 ); - assert( index1 < sv_maxclients->value ); - assert( index2 >= -1 ); - assert( index2 < sv_maxclients->value ); - assert( s_ranked_players ); - -// Com_DPrintf( "SV_RankReportStr( %d, %d, %d, \"%s\" );\n", index1, index2, -// key, value ); - - // get context, match, and player_id for player index1 - if( index1 == -1 ) - { - context = s_server_context; - match = s_server_match; - user1 = 0; - } - else - { - if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE ) - { - Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n", - s_ranked_players[index1].grank_status ); - return; - } - - context = s_ranked_players[index1].context; - match = s_ranked_players[index1].match; - user1 = s_ranked_players[index1].player_id; - } - - // get player_id for player index2 - if( index2 == -1 ) - { - user2 = 0; - } - else - { - if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE ) - { - Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n", - s_ranked_players[index2].grank_status ); - return; - } - - user2 = s_ranked_players[index2].player_id; - } - - status = GRankReportStr - ( - context, - match, - user1, - user2, - key, - value, - GR_OPT_END - ); - - if( status != GR_STATUS_OK ) - { - SV_RankError( "SV_RankReportStr: Unexpected status %s", - SV_RankStatusString( status ) ); - } - - if( user2 != 0 ) - { - context = s_ranked_players[index2].context; - match = s_ranked_players[index2].match; - - status = GRankReportStr - ( - context, - match, - user1, - user2, - key, - value, - GR_OPT_END - ); - - if( status != GR_STATUS_OK ) - { - SV_RankError( "SV_RankReportInt: Unexpected status %s", - SV_RankStatusString( status ) ); - } - } -} - -/* -================ -SV_RankQuit -================ -*/ -void SV_RankQuit( void ) -{ - int i; - int j = 0; - // yuck - - while( s_rankings_contexts > 1 ) - { - assert(s_ranked_players); - if( s_ranked_players != NULL ) - { - for( i = 0; i < sv_maxclients->value; i++ ) - { - // check for players that weren't yet active in SV_RankEnd - if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE ) - { - SV_RankUserLogout( i ); - Com_DPrintf( "SV_RankQuit: SV_RankUserLogout %d\n",i ); - } - else - { - if( s_ranked_players[i].context ) - { - GR_STATUS cleanup_status; - cleanup_status = GRankCleanupAsync - ( - s_ranked_players[i].context, - 0, - SV_RankCleanupCBF, - (void*)&(s_ranked_players[i]), - GR_OPT_END - ); - - if( cleanup_status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankQuit: Expected " - "GR_STATUS_PENDING from GRankCleanupAsync, got %s", - SV_RankStatusString( cleanup_status ) ); - } - } - } - } - } - SV_RankPoll(); - - // should've finished by now - assert( (j++) < 68 ); - } -} - -/* -============================================================================== - -Private Functions - -============================================================================== -*/ - -/* -================= -SV_RankNewGameCBF -================= -*/ -static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg ) -{ - GR_MATCH match; - int i; - - assert( gr_newgame != NULL ); - assert( cbf_arg == NULL ); - - Com_DPrintf( "SV_RankNewGameCBF( %08X, %08X );\n", gr_newgame, cbf_arg ); - - if( gr_newgame->status == GR_STATUS_OK ) - { - char info[MAX_INFO_STRING]; - char gameid[sizeof(s_ranked_players[i].game_id) * 4 / 3 + 2]; - - // save game id - s_rankings_game_id = gr_newgame->game_id; - - // encode gameid - memset(gameid,0,sizeof(gameid)); - SV_RankEncodeGameID(s_rankings_game_id,gameid,sizeof(gameid)); - - // set CS_GRANK rankingsGameID to pass to client - memset(info,0,sizeof(info)); - Info_SetValueForKey( info, "rankingsGameKey", s_rankings_game_key ); - Info_SetValueForKey( info, "rankingsGameID", gameid ); - SV_SetConfigstring( CS_GRANK, info ); - - // initialize client status - for( i = 0; i < sv_maxclients->value; i++ ) - s_ranked_players[i].grank_status = QGR_STATUS_NEW; - - // start new match - match = GRankStartMatch( s_server_context ); - s_server_match = match.match; - - // ready to go - s_rankings_active = qtrue; - Cvar_Set( "sv_rankingsActive", "1" ); - - } - else if( gr_newgame->status == GR_STATUS_BADLEAGUE ) - { - SV_RankError( "SV_RankNewGameCBF: Invalid League name\n" ); - } - else - { - //GRank handle new game failure - // force SV_RankEnd() to run - //SV_RankEnd(); - SV_RankError( "SV_RankNewGameCBF: Unexpected status %s", - SV_RankStatusString( gr_newgame->status ) ); - } -} - -/* -================ -SV_RankUserCBF -================ -*/ -static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg ) -{ - ranked_player_t* ranked_player; - GR_STATUS join_status; - GR_STATUS cleanup_status; - - assert( gr_login != NULL ); - assert( cbf_arg != NULL ); - - Com_DPrintf( "SV_RankUserCBF( %08X, %08X );\n", gr_login, cbf_arg ); - - ranked_player = (ranked_player_t*)cbf_arg; - assert(ranked_player); - assert( ranked_player->context ); - - switch( gr_login->status ) - { - case GR_STATUS_OK: - // attempt to join the game, proceed to SV_RankJoinGameCBF - join_status = GRankJoinGameAsync - ( - ranked_player->context, - s_rankings_game_id, - SV_RankJoinGameCBF, - cbf_arg, - GR_OPT_END - ); - - if( join_status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING " - "from GRankJoinGameAsync, got %s", - SV_RankStatusString( join_status ) ); - } - break; - case GR_STATUS_NOUSER: - Com_DPrintf( "SV_RankUserCBF: Got status %s\n", - SV_RankStatusString( gr_login->status ) ); - ranked_player->final_status = QGR_STATUS_NO_USER; - break; - case GR_STATUS_BADPASSWORD: - Com_DPrintf( "SV_RankUserCBF: Got status %s\n", - SV_RankStatusString( gr_login->status ) ); - ranked_player->final_status = QGR_STATUS_BAD_PASSWORD; - break; - case GR_STATUS_TIMEOUT: - Com_DPrintf( "SV_RankUserCBF: Got status %s\n", - SV_RankStatusString( gr_login->status ) ); - ranked_player->final_status = QGR_STATUS_TIMEOUT; - break; - default: - Com_DPrintf( "SV_RankUserCBF: Unexpected status %s\n", - SV_RankStatusString( gr_login->status ) ); - ranked_player->final_status = QGR_STATUS_ERROR; - break; - } - - if( ranked_player->final_status != QGR_STATUS_NEW ) - { - // login or create failed, so clean up before the next attempt - cleanup_status = GRankCleanupAsync - ( - ranked_player->context, - 0, - SV_RankCleanupCBF, - (void*)ranked_player, - GR_OPT_END - ); - - if( cleanup_status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING " - "from GRankCleanupAsync, got %s", - SV_RankStatusString( cleanup_status ) ); - SV_RankCloseContext( ranked_player ); - } - } -} - -/* -================ -SV_RankJoinGameCBF -================ -*/ -static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg ) -{ - ranked_player_t* ranked_player; - GR_MATCH match; - GR_STATUS cleanup_status; - - assert( gr_joingame != NULL ); - assert( cbf_arg != NULL ); - - Com_DPrintf( "SV_RankJoinGameCBF( %08X, %08X );\n", gr_joingame, cbf_arg ); - - ranked_player = (ranked_player_t*)cbf_arg; - - assert( ranked_player ); - assert( ranked_player->context != 0 ); - - if( gr_joingame->status == GR_STATUS_OK ) - { - int i; - // save user id - ranked_player->player_id = gr_joingame->player_id; - memcpy(ranked_player->token,gr_joingame->token, - sizeof(GR_PLAYER_TOKEN)) ; - match = GRankStartMatch( ranked_player->context ); - ranked_player->match = match.match; - ranked_player->grank = gr_joingame->rank; - - // find the index and call SV_RankUserValidate - for (i=0;ivalue;i++) - if ( ranked_player == &s_ranked_players[i] ) - SV_RankUserValidate(i,NULL,NULL,0, gr_joingame->rank,ranked_player->name); - } - else - { - //GRand handle join game failure - SV_RankError( "SV_RankJoinGameCBF: Unexpected status %s", - SV_RankStatusString( gr_joingame->status ) ); - - cleanup_status = GRankCleanupAsync - ( - ranked_player->context, - 0, - SV_RankCleanupCBF, - cbf_arg, - GR_OPT_END - ); - - if( cleanup_status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankJoinGameCBF: Expected " - "GR_STATUS_PENDING from GRankCleanupAsync, got %s", - SV_RankStatusString( cleanup_status ) ); - SV_RankCloseContext( ranked_player ); - } - } -} - -/* -================ -SV_RankSendReportsCBF -================ -*/ -static void SV_RankSendReportsCBF( GR_STATUS* status, void* cbf_arg ) -{ - ranked_player_t* ranked_player; - GR_CONTEXT context; - GR_STATUS cleanup_status; - - assert( status != NULL ); - // NULL cbf_arg means server is sending match reports - - Com_DPrintf( "SV_RankSendReportsCBF( %08X, %08X );\n", status, cbf_arg ); - - ranked_player = (ranked_player_t*)cbf_arg; - if( ranked_player == NULL ) - { - Com_DPrintf( "SV_RankSendReportsCBF: server\n" ); - context = s_server_context; - } - else - { - Com_DPrintf( "SV_RankSendReportsCBF: player\n" ); - context = ranked_player->context; - } - - //assert( context != 0 ); - if( *status != GR_STATUS_OK ) - { - SV_RankError( "SV_RankSendReportsCBF: Unexpected status %s", - SV_RankStatusString( *status ) ); - } - - if( context == 0 ) - { - Com_DPrintf( "SV_RankSendReportsCBF: WARNING: context == 0" ); - SV_RankCloseContext( ranked_player ); - } - else - { - cleanup_status = GRankCleanupAsync - ( - context, - 0, - SV_RankCleanupCBF, - cbf_arg, - GR_OPT_END - ); - - if( cleanup_status != GR_STATUS_PENDING ) - { - SV_RankError( "SV_RankSendReportsCBF: Expected " - "GR_STATUS_PENDING from GRankCleanupAsync, got %s", - SV_RankStatusString( cleanup_status ) ); - SV_RankCloseContext( ranked_player ); - } - } -} - -/* -================ -SV_RankCleanupCBF -================ -*/ -static void SV_RankCleanupCBF( GR_STATUS* status, void* cbf_arg ) -{ - ranked_player_t* ranked_player; - ranked_player = (ranked_player_t*)cbf_arg; - - assert( status != NULL ); - // NULL cbf_arg means server is cleaning up - - Com_DPrintf( "SV_RankCleanupCBF( %08X, %08X );\n", status, cbf_arg ); - - if( *status != GR_STATUS_OK ) - { - SV_RankError( "SV_RankCleanupCBF: Unexpected status %s", - SV_RankStatusString( *status ) ); - } - - SV_RankCloseContext( ranked_player ); -} - -/* -================ -SV_RankCloseContext -================ -*/ -static void SV_RankCloseContext( ranked_player_t* ranked_player ) -{ - if( ranked_player == NULL ) - { - // server cleanup - if( s_server_context == 0 ) - { - return; - } - s_server_context = 0; - s_server_match = 0; - } - else - { - // player cleanup - if( s_ranked_players == NULL ) - { - return; - } - if( ranked_player->context == 0 ) - { - return; - } - ranked_player->context = 0; - ranked_player->match = 0; - ranked_player->player_id = 0; - memset( ranked_player->token, 0, sizeof(GR_PLAYER_TOKEN) ); - ranked_player->grank_status = ranked_player->final_status; - ranked_player->final_status = QGR_STATUS_NEW; - ranked_player->name[0] = '\0'; - } - - assert( s_rankings_contexts > 0 ); - s_rankings_contexts--; - Com_DPrintf( "SV_RankCloseContext: s_rankings_contexts = %d\n", - s_rankings_contexts ); - - if( s_rankings_contexts == 0 ) - { - GRankLogLevel( GRLOG_OFF ); - - if( s_ranked_players != NULL ) - { - Z_Free( s_ranked_players ); - s_ranked_players = NULL; - } - - s_rankings_active = qfalse; - Cvar_Set( "sv_rankingsActive", "0" ); - } -} - -/* -================ -SV_RankAsciiEncode - -Encodes src_len bytes of binary data from the src buffer as ASCII text, -using 6 bits per character. The result string is null-terminated and -stored in the dest buffer. - -The dest buffer must be at least (src_len * 4) / 3 + 2 bytes in length. - -Returns the length of the result string, not including the null. -================ -*/ -static int SV_RankAsciiEncode( char* dest, const unsigned char* src, - int src_len ) -{ - unsigned char bin[3]; - unsigned char txt[4]; - int dest_len = 0; - int i; - int j; - int num_chars; - - assert( dest != NULL ); - assert( src != NULL ); - - for( i = 0; i < src_len; i += 3 ) - { - // read three bytes of input - for( j = 0; j < 3; j++ ) - { - bin[j] = (i + j < src_len) ? src[i + j] : 0; - } - - // get four 6-bit values from three bytes - txt[0] = bin[0] >> 2; - txt[1] = ((bin[0] << 4) | (bin[1] >> 4)) & 63; - txt[2] = ((bin[1] << 2) | (bin[2] >> 6)) & 63; - txt[3] = bin[2] & 63; - - // store ASCII encoding of 6-bit values - num_chars = (i + 2 < src_len) ? 4 : ((src_len - i) * 4) / 3 + 1; - for( j = 0; j < num_chars; j++ ) - { - dest[dest_len++] = s_ascii_encoding[txt[j]]; - } - } - - dest[dest_len] = '\0'; - - return dest_len; -} - -/* -================ -SV_RankAsciiDecode - -Decodes src_len characters of ASCII text from the src buffer, stores -the binary result in the dest buffer. - -The dest buffer must be at least (src_len * 3) / 4 bytes in length. - -Returns the length of the binary result, or zero for invalid input. -================ -*/ -static int SV_RankAsciiDecode( unsigned char* dest, const char* src, - int src_len ) -{ - static unsigned char s_inverse_encoding[256]; - static char s_init = 0; - - unsigned char bin[3]; - unsigned char txt[4]; - int dest_len = 0; - int i; - int j; - int num_bytes; - - assert( dest != NULL ); - assert( src != NULL ); - - if( !s_init ) - { - // initialize lookup table for decoding - memset( s_inverse_encoding, 255, sizeof(s_inverse_encoding) ); - for( i = 0; i < 64; i++ ) - { - s_inverse_encoding[s_ascii_encoding[i]] = i; - } - s_init = 1; - } - - for( i = 0; i < src_len; i += 4 ) - { - // read four characters of input, decode them to 6-bit values - for( j = 0; j < 4; j++ ) - { - txt[j] = (i + j < src_len) ? s_inverse_encoding[src[i + j]] : 0; - if (txt[j] == 255) - { - return 0; // invalid input character - } - } - - // get three bytes from four 6-bit values - bin[0] = (txt[0] << 2) | (txt[1] >> 4); - bin[1] = (txt[1] << 4) | (txt[2] >> 2); - bin[2] = (txt[2] << 6) | txt[3]; - - // store binary data - num_bytes = (i + 3 < src_len) ? 3 : ((src_len - i) * 3) / 4; - for( j = 0; j < num_bytes; j++ ) - { - dest[dest_len++] = bin[j]; - } - } - - return dest_len; -} - -/* -================ -SV_RankEncodeGameID -================ -*/ -static void SV_RankEncodeGameID( uint64_t game_id, char* result, - int len ) -{ - assert( result != NULL ); - - if( len < ( ( sizeof(game_id) * 4) / 3 + 2) ) - { - Com_DPrintf( "SV_RankEncodeGameID: result buffer too small\n" ); - result[0] = '\0'; - } - else - { - qint64 gameid = LittleLong64(*(qint64*)&game_id); - SV_RankAsciiEncode( result, (unsigned char*)&gameid, - sizeof(qint64) ); - } -} - -/* -================ -SV_RankDecodePlayerID -================ -*/ -static uint64_t SV_RankDecodePlayerID( const char* string ) -{ - unsigned char buffer[9]; - int len; - qint64 player_id; - - assert( string != NULL ); - - len = strlen (string) ; - Com_DPrintf( "SV_RankDecodePlayerID: string length %d\n",len ); - SV_RankAsciiDecode( buffer, string, len ); - player_id = LittleLong64(*(qint64*)buffer); - return *(uint64_t*)&player_id; -} - -/* -================ -SV_RankDecodePlayerKey -================ -*/ -static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key ) -{ - unsigned char buffer[1400]; - int len; - assert( string != NULL ); - - len = strlen (string) ; - Com_DPrintf( "SV_RankDecodePlayerKey: string length %d\n",len ); - - memset(key,0,sizeof(GR_PLAYER_TOKEN)); - memset(buffer,0,sizeof(buffer)); - memcpy( key, buffer, SV_RankAsciiDecode( buffer, string, len ) ); -} - -/* -================ -SV_RankStatusString -================ -*/ -static char* SV_RankStatusString( GR_STATUS status ) -{ - switch( status ) - { - case GR_STATUS_OK: return "GR_STATUS_OK"; - case GR_STATUS_ERROR: return "GR_STATUS_ERROR"; - case GR_STATUS_BADPARAMS: return "GR_STATUS_BADPARAMS"; - case GR_STATUS_NETWORK: return "GR_STATUS_NETWORK"; - case GR_STATUS_NOUSER: return "GR_STATUS_NOUSER"; - case GR_STATUS_BADPASSWORD: return "GR_STATUS_BADPASSWORD"; - case GR_STATUS_BADGAME: return "GR_STATUS_BADGAME"; - case GR_STATUS_PENDING: return "GR_STATUS_PENDING"; - case GR_STATUS_BADDOMAIN: return "GR_STATUS_BADDOMAIN"; - case GR_STATUS_DOMAINLOCK: return "GR_STATUS_DOMAINLOCK"; - case GR_STATUS_TIMEOUT: return "GR_STATUS_TIMEOUT"; - case GR_STATUS_INVALIDUSER: return "GR_STATUS_INVALIDUSER"; - case GR_STATUS_INVALIDCONTEXT: return "GR_STATUS_INVALIDCONTEXT"; - default: return "(UNKNOWN)"; - } -} - -/* -================ -SV_RankError -================ -*/ -static void SV_RankError( const char* fmt, ... ) -{ - va_list arg_ptr; - char text[1024]; - - va_start( arg_ptr, fmt ); - vsprintf( text, fmt, arg_ptr ); - va_end( arg_ptr ); - - Com_DPrintf( "****************************************\n" ); - Com_DPrintf( "SV_RankError: %s\n", text ); - Com_DPrintf( "****************************************\n" ); - - s_rankings_active = qfalse; - Cvar_Set( "sv_rankingsActive", "0" ); - // FIXME - attempt clean shutdown? -} - diff --git a/code/skeletor/bonetable.cpp b/code/skeletor/bonetable.cpp index d3e252d4..ba8a8919 100644 --- a/code/skeletor/bonetable.cpp +++ b/code/skeletor/bonetable.cpp @@ -24,7 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include -#include "dbgheap.h" void ChannelNameTable::CopyChannel( ChannelName_t *dest, const ChannelName_t *source ) { diff --git a/code/skeletor/skeletor.cpp b/code/skeletor/skeletor.cpp index 40aa5a7e..2df3065e 100644 --- a/code/skeletor/skeletor.cpp +++ b/code/skeletor/skeletor.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include "skeletor.h" -#include "dbgheap.h" #define EPSILON 0.000000000001f diff --git a/code/skeletor/skeletor_loadanimation.cpp b/code/skeletor/skeletor_loadanimation.cpp index b9600876..1fd780b5 100644 --- a/code/skeletor/skeletor_loadanimation.cpp +++ b/code/skeletor/skeletor_loadanimation.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include "skeletor.h" -#include "dbgheap.h" qboolean Compress( skelAnimGameFrame_t *current, skelAnimGameFrame_t *last, int channelIndex, skelChannelList_c *channelList, ChannelNameTable *channelNames ) { diff --git a/code/skeletor/skeletor_model_files.cpp b/code/skeletor/skeletor_model_files.cpp index a579273c..e3659664 100644 --- a/code/skeletor/skeletor_model_files.cpp +++ b/code/skeletor/skeletor_model_files.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include "skeletor.h" -#include "dbgheap.h" int CreateRotationBoneFileData( const char *newBoneName, const char *newBoneParentName, SkelVec3 basePos, boneFileData_t *fileData ) { diff --git a/code/skeletor/skeletor_utilities.cpp b/code/skeletor/skeletor_utilities.cpp index c416d8fd..dd791261 100644 --- a/code/skeletor/skeletor_utilities.cpp +++ b/code/skeletor/skeletor_utilities.cpp @@ -24,7 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "skeletor.h" -#include "dbgheap.h" void SKEL_Message( const char *fmt, ... ) { diff --git a/code/skeletor/skeletorbones.cpp b/code/skeletor/skeletorbones.cpp index 6fb35810..5f1368c9 100644 --- a/code/skeletor/skeletorbones.cpp +++ b/code/skeletor/skeletorbones.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include "skeletor.h" -#include "dbgheap.h" char *skelBone_Names[ 8 ]; ChannelNameTable skeletor_c::m_channelNames; diff --git a/code/tiki/tiki_anim.cpp b/code/tiki/tiki_anim.cpp index 0d37c8d1..1d2de5c8 100644 --- a/code/tiki/tiki_anim.cpp +++ b/code/tiki/tiki_anim.cpp @@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include #include "tiki_files.h" -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_cache.cpp b/code/tiki/tiki_cache.cpp index 4a775a1d..3f7b629d 100644 --- a/code/tiki/tiki_cache.cpp +++ b/code/tiki/tiki_cache.cpp @@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include #include "tiki_files.h" #include "tiki_skel.h" -#include "dbgheap.h" struct pchar { const char *m_Value; diff --git a/code/tiki/tiki_commands.cpp b/code/tiki/tiki_commands.cpp index a4308349..3f4f1f62 100644 --- a/code/tiki/tiki_commands.cpp +++ b/code/tiki/tiki_commands.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include "../skeletor/skeletor.h" -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_files.cpp b/code/tiki/tiki_files.cpp index 11f97052..355d40f8 100644 --- a/code/tiki/tiki_files.cpp +++ b/code/tiki/tiki_files.cpp @@ -29,7 +29,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../client/client.h" #include #include -#include "dbgheap.h" qboolean tiki_loading; cvar_t *dumploadedanims; diff --git a/code/tiki/tiki_frame.cpp b/code/tiki/tiki_frame.cpp index 6db2369f..205d32f3 100644 --- a/code/tiki/tiki_frame.cpp +++ b/code/tiki/tiki_frame.cpp @@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../skeletor/tokenizer.h" #include "../client/client.h" #include -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_imports.cpp b/code/tiki/tiki_imports.cpp index c2ccb750..6a142243 100644 --- a/code/tiki/tiki_imports.cpp +++ b/code/tiki/tiki_imports.cpp @@ -24,7 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -#include "dbgheap.h" void TIKI_DPrintf( const char *fmt, ... ) { diff --git a/code/tiki/tiki_parse.cpp b/code/tiki/tiki_parse.cpp index 07454d71..39822f7f 100644 --- a/code/tiki/tiki_parse.cpp +++ b/code/tiki/tiki_parse.cpp @@ -27,7 +27,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../server/server.h" #include "../skeletor/skeletor.h" #include -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_skel.cpp b/code/tiki/tiki_skel.cpp index e6582a26..fd3725d1 100644 --- a/code/tiki/tiki_skel.cpp +++ b/code/tiki/tiki_skel.cpp @@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "qcommon.h" #include "../skeletor/skeletor.h" #include "../client/client.h" -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_surface.cpp b/code/tiki/tiki_surface.cpp index d9aca4d6..a0d84352 100644 --- a/code/tiki/tiki_surface.cpp +++ b/code/tiki/tiki_surface.cpp @@ -24,7 +24,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_tag.cpp b/code/tiki/tiki_tag.cpp index 9c4489c3..fc637970 100644 --- a/code/tiki/tiki_tag.cpp +++ b/code/tiki/tiki_tag.cpp @@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "qcommon.h" #include "../skeletor/skeletor.h" #include "tiki_cache.h" -#include "dbgheap.h" /* =============== diff --git a/code/tiki/tiki_utility.cpp b/code/tiki/tiki_utility.cpp index caac4a44..c868bdd7 100644 --- a/code/tiki/tiki_utility.cpp +++ b/code/tiki/tiki_utility.cpp @@ -25,7 +25,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "q_shared.h" #include "qcommon.h" #include "tiki_shared.h" -#include "dbgheap.h" /* ===============