📄 g_main.cpp
字号:
#include <setjmp.h>
#include "g_local.h"
#include "g_utils.h"
#include "Entity.h"
#include "vector.h"
#include "scriptmaster.h"
#include "navigate.h"
#include "viewthing.h"
#include "console.h"
#include "player.h"
#include "surface.h"
#include "gravpath.h"
#include "deadbody.h"
Vector vec_origin = "0 0 0";
Vector vec_zero = "0 0 0";
qboolean LoadingSavegame = false;
qboolean LoadingServer = false;
game_locals_t game;
level_locals_t level;
game_import_t gi;
game_export_t globals;
edict_t *g_edicts = NULL;
edict_t active_edicts;
edict_t free_edicts;
netconsole_t *g_consoles;
netconbuffer_t *g_conbuffers;
netsurface_t *g_surfaces;
cvar_t *developer;
cvar_t *deathmatch;
cvar_t *coop;
cvar_t *dmflags;
cvar_t *skill;
cvar_t *fraglimit;
cvar_t *timelimit;
cvar_t *password;
cvar_t *filterban;
cvar_t *flood_msgs;
cvar_t *flood_persecond;
cvar_t *flood_waitdelay;
cvar_t *maxclients;
cvar_t *maxentities;
cvar_t *maxconsoles;
cvar_t *maxsurfaces;
cvar_t *g_select_empty;
cvar_t *g_unlimited_ammo;
cvar_t *nomonsters;
cvar_t *dm_respawn;
cvar_t *dialog;
cvar_t *precache;
cvar_t *g_showmem;
cvar_t *g_timeents;
cvar_t *sv_maxvelocity;
cvar_t *sv_gravity;
cvar_t *dedicated;
cvar_t *sv_rollspeed;
cvar_t *sv_rollangle;
cvar_t *gun_x;
cvar_t *gun_y;
cvar_t *gun_z;
cvar_t *run_pitch;
cvar_t *run_roll;
cvar_t *bob_up;
cvar_t *bob_pitch;
cvar_t *bob_roll;
cvar_t *sv_cheats;
cvar_t *sv_showbboxes;
cvar_t *sv_showentnums;
cvar_t *sv_rocketspeed;
cvar_t *sv_rocketrate;
cvar_t *sv_stopspeed;
cvar_t *sv_friction;
cvar_t *sv_waterfriction;
cvar_t *sv_waterspeed;
cvar_t *sv_maxbulletholes;
cvar_t *sv_maxbloodsplats;
cvar_t *sv_gore;
cvar_t *sv_gibs;
cvar_t *sv_showdamage;
cvar_t *sv_showdamagelocation;
cvar_t *sv_traceinfo;
cvar_t *sv_drawtrace;
cvar_t *sv_maplist;
cvar_t *sv_footsteps;
cvar_t *sv_fatrockets;
cvar_t *csys_posx;
cvar_t *csys_posy;
cvar_t *csys_posz;
cvar_t *csys_x;
cvar_t *csys_y;
cvar_t *csys_z;
cvar_t *csys_draw;
cvar_t *parentmode;
int sv_numtraces;
usercmd_t *current_ucmd;
void G_AllocDebugLines( void );
void G_ClientDrawBoundingBoxes( void );
void ( *ServerError )( const char *fmt, ... );
char G_ErrorMessage[ 1024 ];
jmp_buf G_AbortGame;
/*
===============
G_Error
Abort the server with a game error
===============
*/
void G_Error
(
const char *fmt,
...
)
{
va_list argptr;
va_start( argptr, fmt );
vsprintf( G_ErrorMessage, fmt, argptr );
va_end( argptr );
assert( 0 );
longjmp( G_AbortGame, -1 );
}
/*
===============
G_ExitWithError
Calls the server's error function with the last error that occurred.
Should only be called after a setjmp( G_AbortGame ) call
===============
*/
void G_ExitWithError
(
void
)
{
ServerError( G_ErrorMessage );
}
/*
=================
G_ShutdownGame
Frees up any resources
=================
*/
void G_ShutdownGame
(
void
)
{
gi.dprintf ("==== ShutdownGame ====\n");
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
G_LevelShutdown();
gi.FreeTags (TAG_GAME);
}
/*
============
G_InitGame
This will be called when the dll is first loaded, which
only happens when a new game is begun
============
*/
void G_InitGame
(
void
)
{
gi.dprintf ("==== InitGame ====\n");
// Install our own error handler, since we can't
// call the EXE's handler from within a C++ class
ServerError = gi.error;
gi.error = G_Error;
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
// initialize the game variables
gameVars.ClearList();
gun_x = gi.cvar ("gun_x", "0", 0);
gun_y = gi.cvar ("gun_y", "0", 0);
gun_z = gi.cvar ("gun_z", "0", 0);
developer = gi.cvar( "developer", "0", 0 );
precache = gi.cvar( "sv_precache", "1", 0 );
//FIXME: sv_ prefix is wrong for these
sv_rollspeed = gi.cvar ("sv_rollspeed", "200", 0);
sv_rollangle = gi.cvar ("sv_rollangle", "2", 0);
sv_maxvelocity = gi.cvar ("sv_maxvelocity", "2000", 0);
sv_gravity = gi.cvar ("sv_gravity", "800", 0);
sv_maxbulletholes = gi.cvar ("sv_maxbulletholes", "32", 0);
sv_maxbloodsplats = gi.cvar ("sv_maxbloodspats", "5", 0);
sv_gore = gi.cvar ("sv_gore", "1", 0);
sv_gibs = gi.cvar ("sv_gibs", "1", 0);
sv_showdamage = gi.cvar ("sv_showdetaildamage", "0", 0);
sv_showdamagelocation = gi.cvar ("sv_showdamagelocation", "0", 0);
// noset vars
dedicated = gi.cvar ("dedicated", "0", CVAR_NOSET);
// latched vars
sv_cheats = gi.cvar ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH);
deathmatch = gi.cvar ("deathmatch", "0", CVAR_SERVERINFO|CVAR_LATCH);
coop = gi.cvar ("coop", "0", CVAR_SERVERINFO|CVAR_LATCH);
skill = gi.cvar ("skill", "1", CVAR_SERVERINFO|CVAR_LATCH);
#ifdef SIN
maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH | CVAR_ARCHIVE );
#else
maxclients = gi.cvar ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH);
#endif
maxentities = gi.cvar ("maxentities", "1024", CVAR_LATCH);
maxconsoles = gi.cvar ("maxconsoles", "32", CVAR_LATCH);
maxsurfaces = gi.cvar ("maxsurfaces", "1024", CVAR_LATCH);
// flood control
flood_msgs = gi.cvar ("flood_msgs", "4", 0);
flood_persecond = gi.cvar ("flood_persecond", "4", 0);
flood_waitdelay = gi.cvar ("flood_waitdelay", "10", 0);
// change anytime vars
password = gi.cvar ("password", "", CVAR_USERINFO);
filterban = gi.cvar ("filterban", "1", 0);
#ifdef SIN_ARCADE
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO|CVAR_ARCHIVE);
fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO|CVAR_ARCHIVE);
timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO|CVAR_ARCHIVE);
#else
dmflags = gi.cvar ("dmflags", "0", CVAR_SERVERINFO);
fraglimit = gi.cvar ("fraglimit", "0", CVAR_SERVERINFO);
timelimit = gi.cvar ("timelimit", "0", CVAR_SERVERINFO);
#endif
g_select_empty = gi.cvar ("g_select_empty", "0", CVAR_ARCHIVE);
g_unlimited_ammo = gi.cvar ("g_unlimited_ammo", "0", CVAR_SERVERINFO);
g_showmem = gi.cvar ("g_showmem", "0", 0 );
g_timeents = gi.cvar ("g_timeents", "0", 0 );
dm_respawn = gi.cvar ("dm_respawn", "2", CVAR_SERVERINFO);
nomonsters = gi.cvar ("nomonsters", "0", CVAR_SERVERINFO);
dialog = gi.cvar ("dialog", "2", CVAR_SERVERINFO | CVAR_ARCHIVE );
run_pitch = gi.cvar ("run_pitch", "0.002", 0);
run_roll = gi.cvar ("run_roll", "0.005", 0);
bob_up = gi.cvar ("bob_up", "0.005", 0);
bob_pitch = gi.cvar ("bob_pitch", "0.002", 0);
bob_roll = gi.cvar ("bob_roll", "0.002", 0);
bob_roll = gi.cvar ("bob_roll", "0.002", 0);
csys_posx = gi.cvar ("csys_posx", "0", 0);
csys_posy = gi.cvar ("csys_posy", "0", 0);
csys_posz = gi.cvar ("csys_posz", "0", 0);
csys_x = gi.cvar ("csys_x", "0", 0);
csys_y = gi.cvar ("csys_y", "0", 0);
csys_z = gi.cvar ("csys_z", "0", 0);
csys_draw = gi.cvar ("csys_draw", "0", 0);
sv_traceinfo = gi.cvar ("sv_traceinfo", "0", 0);
sv_drawtrace = gi.cvar ("sv_drawtrace", "0", 0);
// debug stuff
sv_showbboxes = gi.cvar ("sv_showbboxes", "0", 0);
sv_showentnums = gi.cvar ("sv_showentnums", "0", 0);
sv_rocketspeed = gi.cvar ("sv_rocketspeed", "300", 0);
sv_rocketrate = gi.cvar ("sv_rocketrate", "1.2", 0);
sv_friction = gi.cvar ("sv_friction", "4", CVAR_SERVERINFO);
sv_stopspeed = gi.cvar ("sv_stopspeed", "100", CVAR_SERVERINFO);
sv_waterfriction = gi.cvar ("sv_waterfriction", "1", CVAR_SERVERINFO);
sv_waterspeed = gi.cvar ("sv_waterspeed", "400", CVAR_SERVERINFO);
sv_maplist = gi.cvar ("sv_maplist", "", CVAR_SERVERINFO|CVAR_ARCHIVE);
sv_footsteps = gi.cvar ("sv_footsteps", "1", CVAR_SERVERINFO|CVAR_ARCHIVE);
if ( deathmatch->value )
{
sv_fatrockets = gi.cvar ("sv_fatrockets", "1", CVAR_SERVERINFO);
}
else
{
sv_fatrockets = gi.cvar ("sv_fatrockets", "1", CVAR_SERVERINFO);
}
parentmode = gi.cvar ("parentmode", "0", CVAR_USERINFO|CVAR_SERVERINFO|CVAR_ARCHIVE);
G_InitEvents();
sv_numtraces = 0;
game.maxentities = maxentities->value;
if (maxclients->value * 8 > game.maxentities)
{
game.maxentities = maxclients->value * 8;
}
game.maxclients = maxclients->value;
game.maxconsoles = maxconsoles->value;
game.maxsurfaces = maxsurfaces->value;
G_AllocGameData();
}
void G_AllocGameData
(
void
)
{
int i;
gi.FreeTags( TAG_GAME );
// Initialize debug lines
G_AllocDebugLines();
// initialize all entities for this game
g_edicts = ( edict_t * )gi.TagMalloc (game.maxentities * sizeof(g_edicts[0]), TAG_GAME);
globals.edicts = g_edicts;
globals.max_edicts = game.maxentities;
// Add all the edicts to the free list
LL_Reset( &free_edicts, next, prev );
LL_Reset( &active_edicts, next, prev );
for( i = 0; i < game.maxentities; i++ )
{
LL_Add( &free_edicts, &g_edicts[ i ], next, prev );
}
// initialize all clients for this game
game.clients = ( gclient_t * )gi.TagMalloc (game.maxclients * sizeof(game.clients[0]), TAG_GAME);
memset( game.clients, 0, game.maxclients * sizeof( game.clients[ 0 ] ) );
for (i=0 ; i<game.maxclients ; i++)
{
// set client fields on player ents
g_edicts[ i + 1 ].client = game.clients + i;
G_InitClientPersistant (&game.clients[i]);
G_InitClientResp (&game.clients[i]);
}
globals.num_edicts = game.maxclients+1;
// initialize all the consoles
g_consoles = (netconsole_t *)gi.TagMalloc (game.maxconsoles * sizeof(g_consoles[0]), TAG_GAME);
globals.consoles = g_consoles;
globals.max_consoles = game.maxconsoles;
globals.num_consoles = 0;
g_conbuffers = (netconbuffer_t *)gi.TagMalloc (game.maxconsoles * sizeof(g_conbuffers[0]), TAG_GAME);
globals.conbuffers = g_conbuffers;
// initialize the surfaces
g_surfaces = (netsurface_t *)gi.TagMalloc (game.maxsurfaces * sizeof(g_surfaces[0]), TAG_GAME);
globals.surfaces = g_surfaces;
globals.max_surfaces = game.maxsurfaces;
globals.num_surfaces = 0;
}
void ReadGame
(
const char *name
)
{
str mapname;
str spawnpoint;
Archiver arc;
int version;
int savegame_version;
LoadingServer = true;
// Get rid of anything left over from the last level
G_LevelShutdown();
arc.Read( name );
arc.ReadInteger( &version );
if ( version < GAME_API_VERSION )
{
gi.error( "Savegame from an older version (%d) of Sin.\n", version );
}
else if ( version > GAME_API_VERSION )
{
gi.error( "Savegame from version %d of Sin.\n", version );
}
arc.ReadInteger( &savegame_version );
if ( savegame_version < SAVEGAME_VERSION )
{
gi.error( "Savegame from an older version (%d) of Sin.\n", version );
}
else if ( savegame_version > SAVEGAME_VERSION )
{
gi.error( "Savegame from version %d of Sin.\n", version );
}
// Read the map name (needed by G_MapInit)
arc.ReadString( &mapname );
// Set up for a new map
G_MapInit( mapname.c_str() );
arc.ReadObject( &PersistantData );
arc.ReadObject( &game );
arc.ReadObject( &gameVars );
arc.Close();
}
void G_ReadGame
(
const char *name
)
{
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
ReadGame( name );
}
/*
============
WriteGame
This will be called whenever the game goes to a new level,
and when the user explicitly saves the game.
Game information include cross level data, like multi level
triggers, help computer info, and all client states.
A single player death will automatically restore from the
last save position.
============
*/
void WriteGame
(
const char *name,
qboolean autosave
)
{
Archiver arc;
game.autosaved = autosave;
arc.Create( name );
arc.WriteInteger( GAME_API_VERSION );
arc.WriteInteger( SAVEGAME_VERSION );
arc.WriteString( level.mapname );
arc.WriteObject( &PersistantData );
arc.WriteObject( &game );
arc.WriteObject( &gameVars );
arc.Close();
game.autosaved = false;
}
void G_WriteGame
(
const char *name,
qboolean autosave
)
{
// If we get an error, call the server's error function
if ( setjmp( G_AbortGame ) )
{
G_ExitWithError();
}
WriteGame( name, autosave );
}
/*
==============
G_WriteClient
==============
*/
void G_WriteClient
(
Archiver &arc,
gclient_t *client
)
{
arc.WriteRaw( client, sizeof( gclient_t ) );
}
/*
==============
G_ReadClient
==============
*/
void G_ReadClient
(
Archiver &arc,
gclient_t *client
)
{
arc.ReadRaw( client, sizeof( gclient_t ) );
}
/*
==================
G_SaveClientData
Some information that should be persistant, like health,
is stored in the Entity structure, so it needs to be mirrored
out to the client structure before all the edicts are wiped.
==================
*/
void G_SaveClientData
(
void
)
{
int i;
edict_t *ent;
PersistantData.Reset();
if ( deathmatch->value )
{
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -