mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-10 11:59:58 -05:00
Quack 3
This commit is contained in:
committed by
GitHub
parent
e8bd66b89c
commit
0bf99969fd
892
qcommon/cmd.c
Normal file
892
qcommon/cmd.c
Normal file
@ -0,0 +1,892 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cmd.c -- Quake script command processing module
|
||||
|
||||
#include "qcommon.h"
|
||||
|
||||
void Cmd_ForwardToServer (void);
|
||||
|
||||
#define MAX_ALIAS_NAME 32
|
||||
|
||||
typedef struct cmdalias_s
|
||||
{
|
||||
struct cmdalias_s *next;
|
||||
char name[MAX_ALIAS_NAME];
|
||||
char *value;
|
||||
} cmdalias_t;
|
||||
|
||||
cmdalias_t *cmd_alias;
|
||||
|
||||
qboolean cmd_wait;
|
||||
|
||||
#define ALIAS_LOOP_COUNT 16
|
||||
int alias_count; // for detecting runaway loops
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Wait_f
|
||||
|
||||
Causes execution of the remainder of the command buffer to be delayed until
|
||||
next frame. This allows commands like:
|
||||
bind g "impulse 5 ; +attack ; wait ; -attack ; impulse 2"
|
||||
============
|
||||
*/
|
||||
void Cmd_Wait_f (void)
|
||||
{
|
||||
cmd_wait = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
COMMAND BUFFER
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
sizebuf_t cmd_text;
|
||||
byte cmd_text_buf[8192];
|
||||
|
||||
byte defer_text_buf[8192];
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_Init
|
||||
============
|
||||
*/
|
||||
void Cbuf_Init (void)
|
||||
{
|
||||
SZ_Init (&cmd_text, cmd_text_buf, sizeof(cmd_text_buf));
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_AddText
|
||||
|
||||
Adds command text at the end of the buffer
|
||||
============
|
||||
*/
|
||||
void Cbuf_AddText (char *text)
|
||||
{
|
||||
int l;
|
||||
|
||||
l = strlen (text);
|
||||
|
||||
if (cmd_text.cursize + l >= cmd_text.maxsize)
|
||||
{
|
||||
Com_Printf ("Cbuf_AddText: overflow\n");
|
||||
return;
|
||||
}
|
||||
SZ_Write (&cmd_text, text, strlen (text));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_InsertText
|
||||
|
||||
Adds command text immediately after the current command
|
||||
Adds a \n to the text
|
||||
FIXME: actually change the command buffer to do less copying
|
||||
============
|
||||
*/
|
||||
void Cbuf_InsertText (char *text)
|
||||
{
|
||||
char *temp;
|
||||
int templen;
|
||||
|
||||
// copy off any commands still remaining in the exec buffer
|
||||
templen = cmd_text.cursize;
|
||||
if (templen)
|
||||
{
|
||||
temp = Z_Malloc (templen);
|
||||
memcpy (temp, cmd_text.data, templen);
|
||||
SZ_Clear (&cmd_text);
|
||||
}
|
||||
else
|
||||
temp = NULL; // shut up compiler
|
||||
|
||||
// add the entire text of the file
|
||||
Cbuf_AddText (text);
|
||||
|
||||
// add the copied off data
|
||||
if (templen)
|
||||
{
|
||||
SZ_Write (&cmd_text, temp, templen);
|
||||
Z_Free (temp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_CopyToDefer
|
||||
============
|
||||
*/
|
||||
void Cbuf_CopyToDefer (void)
|
||||
{
|
||||
memcpy(defer_text_buf, cmd_text_buf, cmd_text.cursize);
|
||||
defer_text_buf[cmd_text.cursize] = 0;
|
||||
cmd_text.cursize = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_InsertFromDefer
|
||||
============
|
||||
*/
|
||||
void Cbuf_InsertFromDefer (void)
|
||||
{
|
||||
Cbuf_InsertText (defer_text_buf);
|
||||
defer_text_buf[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_ExecuteText
|
||||
============
|
||||
*/
|
||||
void Cbuf_ExecuteText (int exec_when, char *text)
|
||||
{
|
||||
switch (exec_when)
|
||||
{
|
||||
case EXEC_NOW:
|
||||
Cmd_ExecuteString (text);
|
||||
break;
|
||||
case EXEC_INSERT:
|
||||
Cbuf_InsertText (text);
|
||||
break;
|
||||
case EXEC_APPEND:
|
||||
Cbuf_AddText (text);
|
||||
break;
|
||||
default:
|
||||
Com_Error (ERR_FATAL, "Cbuf_ExecuteText: bad exec_when");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_Execute
|
||||
============
|
||||
*/
|
||||
void Cbuf_Execute (void)
|
||||
{
|
||||
int i;
|
||||
char *text;
|
||||
char line[1024];
|
||||
int quotes;
|
||||
|
||||
alias_count = 0; // don't allow infinite alias loops
|
||||
|
||||
while (cmd_text.cursize)
|
||||
{
|
||||
// find a \n or ; line break
|
||||
text = (char *)cmd_text.data;
|
||||
|
||||
quotes = 0;
|
||||
for (i=0 ; i< cmd_text.cursize ; i++)
|
||||
{
|
||||
if (text[i] == '"')
|
||||
quotes++;
|
||||
if ( !(quotes&1) && text[i] == ';')
|
||||
break; // don't break if inside a quoted string
|
||||
if (text[i] == '\n')
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
memcpy (line, text, i);
|
||||
line[i] = 0;
|
||||
|
||||
// delete the text from the command buffer and move remaining commands down
|
||||
// this is necessary because commands (exec, alias) can insert data at the
|
||||
// beginning of the text buffer
|
||||
|
||||
if (i == cmd_text.cursize)
|
||||
cmd_text.cursize = 0;
|
||||
else
|
||||
{
|
||||
i++;
|
||||
cmd_text.cursize -= i;
|
||||
memmove (text, text+i, cmd_text.cursize);
|
||||
}
|
||||
|
||||
// execute the command line
|
||||
Cmd_ExecuteString (line);
|
||||
|
||||
if (cmd_wait)
|
||||
{
|
||||
// skip out while text still remains in buffer, leaving it
|
||||
// for next frame
|
||||
cmd_wait = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cbuf_AddEarlyCommands
|
||||
|
||||
Adds command line parameters as script statements
|
||||
Commands lead with a +, and continue until another +
|
||||
|
||||
Set commands are added early, so they are guaranteed to be set before
|
||||
the client and server initialize for the first time.
|
||||
|
||||
Other commands are added late, after all initialization is complete.
|
||||
===============
|
||||
*/
|
||||
void Cbuf_AddEarlyCommands (qboolean clear)
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
|
||||
for (i=0 ; i<COM_Argc() ; i++)
|
||||
{
|
||||
s = COM_Argv(i);
|
||||
if (strcmp (s, "+set"))
|
||||
continue;
|
||||
Cbuf_AddText (va("set %s %s\n", COM_Argv(i+1), COM_Argv(i+2)));
|
||||
if (clear)
|
||||
{
|
||||
COM_ClearArgv(i);
|
||||
COM_ClearArgv(i+1);
|
||||
COM_ClearArgv(i+2);
|
||||
}
|
||||
i+=2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Cbuf_AddLateCommands
|
||||
|
||||
Adds command line parameters as script statements
|
||||
Commands lead with a + and continue until another + or -
|
||||
quake +vid_ref gl +map amlev1
|
||||
|
||||
Returns true if any late commands were added, which
|
||||
will keep the demoloop from immediately starting
|
||||
=================
|
||||
*/
|
||||
qboolean Cbuf_AddLateCommands (void)
|
||||
{
|
||||
int i, j;
|
||||
int s;
|
||||
char *text, *build, c;
|
||||
int argc;
|
||||
qboolean ret;
|
||||
|
||||
// build the combined string to parse from
|
||||
s = 0;
|
||||
argc = COM_Argc();
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
s += strlen (COM_Argv(i)) + 1;
|
||||
}
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
text = Z_Malloc (s+1);
|
||||
text[0] = 0;
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
strcat (text,COM_Argv(i));
|
||||
if (i != argc-1)
|
||||
strcat (text, " ");
|
||||
}
|
||||
|
||||
// pull out the commands
|
||||
build = Z_Malloc (s+1);
|
||||
build[0] = 0;
|
||||
|
||||
for (i=0 ; i<s-1 ; i++)
|
||||
{
|
||||
if (text[i] == '+')
|
||||
{
|
||||
i++;
|
||||
|
||||
for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
|
||||
;
|
||||
|
||||
c = text[j];
|
||||
text[j] = 0;
|
||||
|
||||
strcat (build, text+i);
|
||||
strcat (build, "\n");
|
||||
text[j] = c;
|
||||
i = j-1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = (build[0] != 0);
|
||||
if (ret)
|
||||
Cbuf_AddText (build);
|
||||
|
||||
Z_Free (text);
|
||||
Z_Free (build);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
SCRIPT COMMANDS
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Exec_f
|
||||
===============
|
||||
*/
|
||||
void Cmd_Exec_f (void)
|
||||
{
|
||||
char *f, *f2;
|
||||
int len;
|
||||
|
||||
if (Cmd_Argc () != 2)
|
||||
{
|
||||
Com_Printf ("exec <filename> : execute a script file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len = FS_LoadFile (Cmd_Argv(1), (void **)&f);
|
||||
if (!f)
|
||||
{
|
||||
Com_Printf ("couldn't exec %s\n",Cmd_Argv(1));
|
||||
return;
|
||||
}
|
||||
Com_Printf ("execing %s\n",Cmd_Argv(1));
|
||||
|
||||
// the file doesn't have a trailing 0, so we need to copy it off
|
||||
f2 = Z_Malloc(len+1);
|
||||
memcpy (f2, f, len);
|
||||
f2[len] = 0;
|
||||
|
||||
Cbuf_InsertText (f2);
|
||||
|
||||
Z_Free (f2);
|
||||
FS_FreeFile (f);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Echo_f
|
||||
|
||||
Just prints the rest of the line to the console
|
||||
===============
|
||||
*/
|
||||
void Cmd_Echo_f (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=1 ; i<Cmd_Argc() ; i++)
|
||||
Com_Printf ("%s ",Cmd_Argv(i));
|
||||
Com_Printf ("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Cmd_Alias_f
|
||||
|
||||
Creates a new command that executes a command string (possibly ; seperated)
|
||||
===============
|
||||
*/
|
||||
void Cmd_Alias_f (void)
|
||||
{
|
||||
cmdalias_t *a;
|
||||
char cmd[1024];
|
||||
int i, c;
|
||||
char *s;
|
||||
|
||||
if (Cmd_Argc() == 1)
|
||||
{
|
||||
Com_Printf ("Current alias commands:\n");
|
||||
for (a = cmd_alias ; a ; a=a->next)
|
||||
Com_Printf ("%s : %s\n", a->name, a->value);
|
||||
return;
|
||||
}
|
||||
|
||||
s = Cmd_Argv(1);
|
||||
if (strlen(s) >= MAX_ALIAS_NAME)
|
||||
{
|
||||
Com_Printf ("Alias name is too long\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// if the alias already exists, reuse it
|
||||
for (a = cmd_alias ; a ; a=a->next)
|
||||
{
|
||||
if (!strcmp(s, a->name))
|
||||
{
|
||||
Z_Free (a->value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!a)
|
||||
{
|
||||
a = Z_Malloc (sizeof(cmdalias_t));
|
||||
a->next = cmd_alias;
|
||||
cmd_alias = a;
|
||||
}
|
||||
strcpy (a->name, s);
|
||||
|
||||
// copy the rest of the command line
|
||||
cmd[0] = 0; // start out with a null string
|
||||
c = Cmd_Argc();
|
||||
for (i=2 ; i< c ; i++)
|
||||
{
|
||||
strcat (cmd, Cmd_Argv(i));
|
||||
if (i != (c - 1))
|
||||
strcat (cmd, " ");
|
||||
}
|
||||
strcat (cmd, "\n");
|
||||
|
||||
a->value = CopyString (cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
COMMAND EXECUTION
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
typedef struct cmd_function_s
|
||||
{
|
||||
struct cmd_function_s *next;
|
||||
char *name;
|
||||
xcommand_t function;
|
||||
} cmd_function_t;
|
||||
|
||||
|
||||
static int cmd_argc;
|
||||
static char *cmd_argv[MAX_STRING_TOKENS];
|
||||
static char *cmd_null_string = "";
|
||||
static char cmd_args[MAX_STRING_CHARS];
|
||||
|
||||
static cmd_function_t *cmd_functions; // possible commands to execute
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Argc
|
||||
============
|
||||
*/
|
||||
int Cmd_Argc (void)
|
||||
{
|
||||
return cmd_argc;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Argv
|
||||
============
|
||||
*/
|
||||
char *Cmd_Argv (int arg)
|
||||
{
|
||||
if ( (unsigned)arg >= cmd_argc )
|
||||
return cmd_null_string;
|
||||
return cmd_argv[arg];
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Args
|
||||
|
||||
Returns a single string containing argv(1) to argv(argc()-1)
|
||||
============
|
||||
*/
|
||||
char *Cmd_Args (void)
|
||||
{
|
||||
return cmd_args;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
======================
|
||||
Cmd_MacroExpandString
|
||||
======================
|
||||
*/
|
||||
char *Cmd_MacroExpandString (char *text)
|
||||
{
|
||||
int i, j, count, len;
|
||||
qboolean inquote;
|
||||
char *scan;
|
||||
static char expanded[MAX_STRING_CHARS];
|
||||
char temporary[MAX_STRING_CHARS];
|
||||
char *token, *start;
|
||||
|
||||
inquote = false;
|
||||
scan = text;
|
||||
|
||||
len = strlen (scan);
|
||||
if (len >= MAX_STRING_CHARS)
|
||||
{
|
||||
Com_Printf ("Line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for (i=0 ; i<len ; i++)
|
||||
{
|
||||
if (scan[i] == '"')
|
||||
inquote ^= 1;
|
||||
if (inquote)
|
||||
continue; // don't expand inside quotes
|
||||
if (scan[i] != '$')
|
||||
continue;
|
||||
// scan out the complete macro
|
||||
start = scan+i+1;
|
||||
token = COM_Parse (&start);
|
||||
if (!start)
|
||||
continue;
|
||||
|
||||
token = Cvar_VariableString (token);
|
||||
|
||||
j = strlen(token);
|
||||
len += j;
|
||||
if (len >= MAX_STRING_CHARS)
|
||||
{
|
||||
Com_Printf ("Expanded line exceeded %i chars, discarded.\n", MAX_STRING_CHARS);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strncpy (temporary, scan, i);
|
||||
strcpy (temporary+i, token);
|
||||
strcpy (temporary+i+j, start);
|
||||
|
||||
strcpy (expanded, temporary);
|
||||
scan = expanded;
|
||||
i--;
|
||||
|
||||
if (++count == 100)
|
||||
{
|
||||
Com_Printf ("Macro expansion loop, discarded.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (inquote)
|
||||
{
|
||||
Com_Printf ("Line has unmatched quote, discarded.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return scan;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_TokenizeString
|
||||
|
||||
Parses the given string into command line tokens.
|
||||
$Cvars will be expanded unless they are in a quoted token
|
||||
============
|
||||
*/
|
||||
void Cmd_TokenizeString (char *text, qboolean macroExpand)
|
||||
{
|
||||
int i;
|
||||
char *com_token;
|
||||
|
||||
// clear the args from the last string
|
||||
for (i=0 ; i<cmd_argc ; i++)
|
||||
Z_Free (cmd_argv[i]);
|
||||
|
||||
cmd_argc = 0;
|
||||
cmd_args[0] = 0;
|
||||
|
||||
// macro expand the text
|
||||
if (macroExpand)
|
||||
text = Cmd_MacroExpandString (text);
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// skip whitespace up to a /n
|
||||
while (*text && *text <= ' ' && *text != '\n')
|
||||
{
|
||||
text++;
|
||||
}
|
||||
|
||||
if (*text == '\n')
|
||||
{ // a newline seperates commands in the buffer
|
||||
text++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!*text)
|
||||
return;
|
||||
|
||||
// set cmd_args to everything after the first arg
|
||||
if (cmd_argc == 1)
|
||||
{
|
||||
int l;
|
||||
|
||||
strcpy (cmd_args, text);
|
||||
|
||||
// strip off any trailing whitespace
|
||||
l = strlen(cmd_args) - 1;
|
||||
for ( ; l >= 0 ; l--)
|
||||
if (cmd_args[l] <= ' ')
|
||||
cmd_args[l] = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
com_token = COM_Parse (&text);
|
||||
if (!text)
|
||||
return;
|
||||
|
||||
if (cmd_argc < MAX_STRING_TOKENS)
|
||||
{
|
||||
cmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1);
|
||||
strcpy (cmd_argv[cmd_argc], com_token);
|
||||
cmd_argc++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddCommand
|
||||
============
|
||||
*/
|
||||
void Cmd_AddCommand (char *cmd_name, xcommand_t function)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
|
||||
// fail if the command is a variable name
|
||||
if (Cvar_VariableString(cmd_name)[0])
|
||||
{
|
||||
Com_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
|
||||
return;
|
||||
}
|
||||
|
||||
// fail if the command already exists
|
||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||
{
|
||||
if (!strcmp (cmd_name, cmd->name))
|
||||
{
|
||||
Com_Printf ("Cmd_AddCommand: %s already defined\n", cmd_name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = Z_Malloc (sizeof(cmd_function_t));
|
||||
cmd->name = cmd_name;
|
||||
cmd->function = function;
|
||||
cmd->next = cmd_functions;
|
||||
cmd_functions = cmd;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_RemoveCommand
|
||||
============
|
||||
*/
|
||||
void Cmd_RemoveCommand (char *cmd_name)
|
||||
{
|
||||
cmd_function_t *cmd, **back;
|
||||
|
||||
back = &cmd_functions;
|
||||
while (1)
|
||||
{
|
||||
cmd = *back;
|
||||
if (!cmd)
|
||||
{
|
||||
Com_Printf ("Cmd_RemoveCommand: %s not added\n", cmd_name);
|
||||
return;
|
||||
}
|
||||
if (!strcmp (cmd_name, cmd->name))
|
||||
{
|
||||
*back = cmd->next;
|
||||
Z_Free (cmd);
|
||||
return;
|
||||
}
|
||||
back = &cmd->next;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Exists
|
||||
============
|
||||
*/
|
||||
qboolean Cmd_Exists (char *cmd_name)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
|
||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||
{
|
||||
if (!strcmp (cmd_name,cmd->name))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_CompleteCommand
|
||||
============
|
||||
*/
|
||||
char *Cmd_CompleteCommand (char *partial)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
int len;
|
||||
cmdalias_t *a;
|
||||
|
||||
len = strlen(partial);
|
||||
|
||||
if (!len)
|
||||
return NULL;
|
||||
|
||||
// check for exact match
|
||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||
if (!strcmp (partial,cmd->name))
|
||||
return cmd->name;
|
||||
for (a=cmd_alias ; a ; a=a->next)
|
||||
if (!strcmp (partial, a->name))
|
||||
return a->name;
|
||||
|
||||
// check for partial match
|
||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||
if (!strncmp (partial,cmd->name, len))
|
||||
return cmd->name;
|
||||
for (a=cmd_alias ; a ; a=a->next)
|
||||
if (!strncmp (partial, a->name, len))
|
||||
return a->name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_ExecuteString
|
||||
|
||||
A complete command line has been parsed, so try to execute it
|
||||
FIXME: lookupnoadd the token to speed search?
|
||||
============
|
||||
*/
|
||||
void Cmd_ExecuteString (char *text)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
cmdalias_t *a;
|
||||
|
||||
Cmd_TokenizeString (text, true);
|
||||
|
||||
// execute the command line
|
||||
if (!Cmd_Argc())
|
||||
return; // no tokens
|
||||
|
||||
// check functions
|
||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
|
||||
{
|
||||
if (!Q_strcasecmp (cmd_argv[0],cmd->name))
|
||||
{
|
||||
if (!cmd->function)
|
||||
{ // forward to server command
|
||||
Cmd_ExecuteString (va("cmd %s", text));
|
||||
}
|
||||
else
|
||||
cmd->function ();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check alias
|
||||
for (a=cmd_alias ; a ; a=a->next)
|
||||
{
|
||||
if (!Q_strcasecmp (cmd_argv[0], a->name))
|
||||
{
|
||||
if (++alias_count == ALIAS_LOOP_COUNT)
|
||||
{
|
||||
Com_Printf ("ALIAS_LOOP_COUNT\n");
|
||||
return;
|
||||
}
|
||||
Cbuf_InsertText (a->value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// check cvars
|
||||
if (Cvar_Command ())
|
||||
return;
|
||||
|
||||
// send it as a server command if we are connected
|
||||
Cmd_ForwardToServer ();
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_List_f
|
||||
============
|
||||
*/
|
||||
void Cmd_List_f (void)
|
||||
{
|
||||
cmd_function_t *cmd;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
for (cmd=cmd_functions ; cmd ; cmd=cmd->next, i++)
|
||||
Com_Printf ("%s\n", cmd->name);
|
||||
Com_Printf ("%i commands\n", i);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_Init
|
||||
============
|
||||
*/
|
||||
void Cmd_Init (void)
|
||||
{
|
||||
//
|
||||
// register our commands
|
||||
//
|
||||
Cmd_AddCommand ("cmdlist",Cmd_List_f);
|
||||
Cmd_AddCommand ("exec",Cmd_Exec_f);
|
||||
Cmd_AddCommand ("echo",Cmd_Echo_f);
|
||||
Cmd_AddCommand ("alias",Cmd_Alias_f);
|
||||
Cmd_AddCommand ("wait", Cmd_Wait_f);
|
||||
}
|
||||
|
1770
qcommon/cmodel.c
Normal file
1770
qcommon/cmodel.c
Normal file
File diff suppressed because it is too large
Load Diff
1588
qcommon/common.c
Normal file
1588
qcommon/common.c
Normal file
File diff suppressed because it is too large
Load Diff
92
qcommon/crc.c
Normal file
92
qcommon/crc.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
/* crc.c */
|
||||
|
||||
#include "qcommon.h"
|
||||
|
||||
// this is a 16 bit, non-reflected CRC using the polynomial 0x1021
|
||||
// and the initial and final xor values shown below... in other words, the
|
||||
// CCITT standard CRC used by XMODEM
|
||||
|
||||
#define CRC_INIT_VALUE 0xffff
|
||||
#define CRC_XOR_VALUE 0x0000
|
||||
|
||||
static unsigned short crctable[256] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||
};
|
||||
|
||||
void CRC_Init(unsigned short *crcvalue)
|
||||
{
|
||||
*crcvalue = CRC_INIT_VALUE;
|
||||
}
|
||||
|
||||
void CRC_ProcessByte(unsigned short *crcvalue, byte data)
|
||||
{
|
||||
*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];
|
||||
}
|
||||
|
||||
unsigned short CRC_Value(unsigned short crcvalue)
|
||||
{
|
||||
return crcvalue ^ CRC_XOR_VALUE;
|
||||
}
|
||||
|
||||
unsigned short CRC_Block (byte *start, int count)
|
||||
{
|
||||
unsigned short crc;
|
||||
|
||||
CRC_Init (&crc);
|
||||
while (count--)
|
||||
crc = (crc << 8) ^ crctable[(crc >> 8) ^ *start++];
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
6
qcommon/crc.h
Normal file
6
qcommon/crc.h
Normal file
@ -0,0 +1,6 @@
|
||||
/* crc.h */
|
||||
|
||||
void CRC_Init(unsigned short *crcvalue);
|
||||
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
|
||||
unsigned short CRC_Value(unsigned short crcvalue);
|
||||
unsigned short CRC_Block (byte *start, int count);
|
527
qcommon/cvar.c
Normal file
527
qcommon/cvar.c
Normal file
@ -0,0 +1,527 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
// cvar.c -- dynamic variable tracking
|
||||
|
||||
#include "qcommon.h"
|
||||
|
||||
cvar_t *cvar_vars;
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_InfoValidate
|
||||
============
|
||||
*/
|
||||
static qboolean Cvar_InfoValidate (char *s)
|
||||
{
|
||||
if (strstr (s, "\\"))
|
||||
return false;
|
||||
if (strstr (s, "\""))
|
||||
return false;
|
||||
if (strstr (s, ";"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_FindVar
|
||||
============
|
||||
*/
|
||||
static cvar_t *Cvar_FindVar (char *var_name)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
for (var=cvar_vars ; var ; var=var->next)
|
||||
if (!strcmp (var_name, var->name))
|
||||
return var;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_VariableValue
|
||||
============
|
||||
*/
|
||||
float Cvar_VariableValue (char *var_name)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
var = Cvar_FindVar (var_name);
|
||||
if (!var)
|
||||
return 0;
|
||||
return atof (var->string);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_VariableString
|
||||
============
|
||||
*/
|
||||
char *Cvar_VariableString (char *var_name)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
var = Cvar_FindVar (var_name);
|
||||
if (!var)
|
||||
return "";
|
||||
return var->string;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_CompleteVariable
|
||||
============
|
||||
*/
|
||||
char *Cvar_CompleteVariable (char *partial)
|
||||
{
|
||||
cvar_t *cvar;
|
||||
int len;
|
||||
|
||||
len = strlen(partial);
|
||||
|
||||
if (!len)
|
||||
return NULL;
|
||||
|
||||
// check exact match
|
||||
for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
|
||||
if (!strcmp (partial,cvar->name))
|
||||
return cvar->name;
|
||||
|
||||
// check partial match
|
||||
for (cvar=cvar_vars ; cvar ; cvar=cvar->next)
|
||||
if (!strncmp (partial,cvar->name, len))
|
||||
return cvar->name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Get
|
||||
|
||||
If the variable already exists, the value will not be set
|
||||
The flags will be or'ed in if the variable exists.
|
||||
============
|
||||
*/
|
||||
cvar_t *Cvar_Get (char *var_name, char *var_value, int flags)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
|
||||
{
|
||||
if (!Cvar_InfoValidate (var_name))
|
||||
{
|
||||
Com_Printf("invalid info cvar name\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
var = Cvar_FindVar (var_name);
|
||||
if (var)
|
||||
{
|
||||
var->flags |= flags;
|
||||
return var;
|
||||
}
|
||||
|
||||
if (!var_value)
|
||||
return NULL;
|
||||
|
||||
if (flags & (CVAR_USERINFO | CVAR_SERVERINFO))
|
||||
{
|
||||
if (!Cvar_InfoValidate (var_value))
|
||||
{
|
||||
Com_Printf("invalid info cvar value\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
var = Z_Malloc (sizeof(*var));
|
||||
var->name = CopyString (var_name);
|
||||
var->string = CopyString (var_value);
|
||||
var->modified = true;
|
||||
var->value = atof (var->string);
|
||||
|
||||
// link the variable in
|
||||
var->next = cvar_vars;
|
||||
cvar_vars = var;
|
||||
|
||||
var->flags = flags;
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Set2
|
||||
============
|
||||
*/
|
||||
cvar_t *Cvar_Set2 (char *var_name, char *value, qboolean force)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
var = Cvar_FindVar (var_name);
|
||||
if (!var)
|
||||
{ // create it
|
||||
return Cvar_Get (var_name, value, 0);
|
||||
}
|
||||
|
||||
if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO))
|
||||
{
|
||||
if (!Cvar_InfoValidate (value))
|
||||
{
|
||||
Com_Printf("invalid info cvar value\n");
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if (var->flags & CVAR_NOSET)
|
||||
{
|
||||
Com_Printf ("%s is write protected.\n", var_name);
|
||||
return var;
|
||||
}
|
||||
|
||||
if (var->flags & CVAR_LATCH)
|
||||
{
|
||||
if (var->latched_string)
|
||||
{
|
||||
if (strcmp(value, var->latched_string) == 0)
|
||||
return var;
|
||||
Z_Free (var->latched_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(value, var->string) == 0)
|
||||
return var;
|
||||
}
|
||||
|
||||
if (Com_ServerState())
|
||||
{
|
||||
Com_Printf ("%s will be changed for next game.\n", var_name);
|
||||
var->latched_string = CopyString(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
var->string = CopyString(value);
|
||||
var->value = atof (var->string);
|
||||
if (!strcmp(var->name, "game"))
|
||||
{
|
||||
FS_SetGamedir (var->string);
|
||||
FS_ExecAutoexec ();
|
||||
}
|
||||
}
|
||||
return var;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (var->latched_string)
|
||||
{
|
||||
Z_Free (var->latched_string);
|
||||
var->latched_string = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp(value, var->string))
|
||||
return var; // not changed
|
||||
|
||||
var->modified = true;
|
||||
|
||||
if (var->flags & CVAR_USERINFO)
|
||||
userinfo_modified = true; // transmit at next oportunity
|
||||
|
||||
Z_Free (var->string); // free the old value string
|
||||
|
||||
var->string = CopyString(value);
|
||||
var->value = atof (var->string);
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_ForceSet
|
||||
============
|
||||
*/
|
||||
cvar_t *Cvar_ForceSet (char *var_name, char *value)
|
||||
{
|
||||
return Cvar_Set2 (var_name, value, true);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Set
|
||||
============
|
||||
*/
|
||||
cvar_t *Cvar_Set (char *var_name, char *value)
|
||||
{
|
||||
return Cvar_Set2 (var_name, value, false);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_FullSet
|
||||
============
|
||||
*/
|
||||
cvar_t *Cvar_FullSet (char *var_name, char *value, int flags)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
var = Cvar_FindVar (var_name);
|
||||
if (!var)
|
||||
{ // create it
|
||||
return Cvar_Get (var_name, value, flags);
|
||||
}
|
||||
|
||||
var->modified = true;
|
||||
|
||||
if (var->flags & CVAR_USERINFO)
|
||||
userinfo_modified = true; // transmit at next oportunity
|
||||
|
||||
Z_Free (var->string); // free the old value string
|
||||
|
||||
var->string = CopyString(value);
|
||||
var->value = atof (var->string);
|
||||
var->flags = flags;
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_SetValue
|
||||
============
|
||||
*/
|
||||
void Cvar_SetValue (char *var_name, float value)
|
||||
{
|
||||
char val[32];
|
||||
|
||||
if (value == (int)value)
|
||||
Com_sprintf (val, sizeof(val), "%i",(int)value);
|
||||
else
|
||||
Com_sprintf (val, sizeof(val), "%f",value);
|
||||
Cvar_Set (var_name, val);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_GetLatchedVars
|
||||
|
||||
Any variables with latched values will now be updated
|
||||
============
|
||||
*/
|
||||
void Cvar_GetLatchedVars (void)
|
||||
{
|
||||
cvar_t *var;
|
||||
|
||||
for (var = cvar_vars ; var ; var = var->next)
|
||||
{
|
||||
if (!var->latched_string)
|
||||
continue;
|
||||
Z_Free (var->string);
|
||||
var->string = var->latched_string;
|
||||
var->latched_string = NULL;
|
||||
var->value = atof(var->string);
|
||||
if (!strcmp(var->name, "game"))
|
||||
{
|
||||
FS_SetGamedir (var->string);
|
||||
FS_ExecAutoexec ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Command
|
||||
|
||||
Handles variable inspection and changing from the console
|
||||
============
|
||||
*/
|
||||
qboolean Cvar_Command (void)
|
||||
{
|
||||
cvar_t *v;
|
||||
|
||||
// check variables
|
||||
v = Cvar_FindVar (Cmd_Argv(0));
|
||||
if (!v)
|
||||
return false;
|
||||
|
||||
// perform a variable print or set
|
||||
if (Cmd_Argc() == 1)
|
||||
{
|
||||
Com_Printf ("\"%s\" is \"%s\"\n", v->name, v->string);
|
||||
return true;
|
||||
}
|
||||
|
||||
Cvar_Set (v->name, Cmd_Argv(1));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Set_f
|
||||
|
||||
Allows setting and defining of arbitrary cvars from console
|
||||
============
|
||||
*/
|
||||
void Cvar_Set_f (void)
|
||||
{
|
||||
int c;
|
||||
int flags;
|
||||
|
||||
c = Cmd_Argc();
|
||||
if (c != 3 && c != 4)
|
||||
{
|
||||
Com_Printf ("usage: set <variable> <value> [u / s]\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (c == 4)
|
||||
{
|
||||
if (!strcmp(Cmd_Argv(3), "u"))
|
||||
flags = CVAR_USERINFO;
|
||||
else if (!strcmp(Cmd_Argv(3), "s"))
|
||||
flags = CVAR_SERVERINFO;
|
||||
else
|
||||
{
|
||||
Com_Printf ("flags can only be 'u' or 's'\n");
|
||||
return;
|
||||
}
|
||||
Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags);
|
||||
}
|
||||
else
|
||||
Cvar_Set (Cmd_Argv(1), Cmd_Argv(2));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_WriteVariables
|
||||
|
||||
Appends lines containing "set variable value" for all variables
|
||||
with the archive flag set to true.
|
||||
============
|
||||
*/
|
||||
void Cvar_WriteVariables (char *path)
|
||||
{
|
||||
cvar_t *var;
|
||||
char buffer[1024];
|
||||
FILE *f;
|
||||
|
||||
f = fopen (path, "a");
|
||||
for (var = cvar_vars ; var ; var = var->next)
|
||||
{
|
||||
if (var->flags & CVAR_ARCHIVE)
|
||||
{
|
||||
Com_sprintf (buffer, sizeof(buffer), "set %s \"%s\"\n", var->name, var->string);
|
||||
fprintf (f, "%s", buffer);
|
||||
}
|
||||
}
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_List_f
|
||||
|
||||
============
|
||||
*/
|
||||
void Cvar_List_f (void)
|
||||
{
|
||||
cvar_t *var;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
for (var = cvar_vars ; var ; var = var->next, i++)
|
||||
{
|
||||
if (var->flags & CVAR_ARCHIVE)
|
||||
Com_Printf ("*");
|
||||
else
|
||||
Com_Printf (" ");
|
||||
if (var->flags & CVAR_USERINFO)
|
||||
Com_Printf ("U");
|
||||
else
|
||||
Com_Printf (" ");
|
||||
if (var->flags & CVAR_SERVERINFO)
|
||||
Com_Printf ("S");
|
||||
else
|
||||
Com_Printf (" ");
|
||||
if (var->flags & CVAR_NOSET)
|
||||
Com_Printf ("-");
|
||||
else if (var->flags & CVAR_LATCH)
|
||||
Com_Printf ("L");
|
||||
else
|
||||
Com_Printf (" ");
|
||||
Com_Printf (" %s \"%s\"\n", var->name, var->string);
|
||||
}
|
||||
Com_Printf ("%i cvars\n", i);
|
||||
}
|
||||
|
||||
|
||||
qboolean userinfo_modified;
|
||||
|
||||
|
||||
char *Cvar_BitInfo (int bit)
|
||||
{
|
||||
static char info[MAX_INFO_STRING];
|
||||
cvar_t *var;
|
||||
|
||||
info[0] = 0;
|
||||
|
||||
for (var = cvar_vars ; var ; var = var->next)
|
||||
{
|
||||
if (var->flags & bit)
|
||||
Info_SetValueForKey (info, var->name, var->string);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// returns an info string containing all the CVAR_USERINFO cvars
|
||||
char *Cvar_Userinfo (void)
|
||||
{
|
||||
return Cvar_BitInfo (CVAR_USERINFO);
|
||||
}
|
||||
|
||||
// returns an info string containing all the CVAR_SERVERINFO cvars
|
||||
char *Cvar_Serverinfo (void)
|
||||
{
|
||||
return Cvar_BitInfo (CVAR_SERVERINFO);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_Init
|
||||
|
||||
Reads in all archived cvars
|
||||
============
|
||||
*/
|
||||
void Cvar_Init (void)
|
||||
{
|
||||
Cmd_AddCommand ("set", Cvar_Set_f);
|
||||
Cmd_AddCommand ("cvarlist", Cvar_List_f);
|
||||
|
||||
}
|
877
qcommon/files.c
Normal file
877
qcommon/files.c
Normal file
@ -0,0 +1,877 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "qcommon.h"
|
||||
|
||||
// define this to dissalow any data but the demo pak file
|
||||
//#define NO_ADDONS
|
||||
|
||||
// if a packfile directory differs from this, it is assumed to be hacked
|
||||
// Full version
|
||||
#define PAK0_CHECKSUM 0x40e614e0
|
||||
// Demo
|
||||
//#define PAK0_CHECKSUM 0xb2c6d7ea
|
||||
// OEM
|
||||
//#define PAK0_CHECKSUM 0x78e135c
|
||||
|
||||
/*
|
||||
=============================================================================
|
||||
|
||||
QUAKE FILESYSTEM
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
|
||||
|
||||
//
|
||||
// in memory
|
||||
//
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
int filepos, filelen;
|
||||
} packfile_t;
|
||||
|
||||
typedef struct pack_s
|
||||
{
|
||||
char filename[MAX_OSPATH];
|
||||
FILE *handle;
|
||||
int numfiles;
|
||||
packfile_t *files;
|
||||
} pack_t;
|
||||
|
||||
char fs_gamedir[MAX_OSPATH];
|
||||
cvar_t *fs_basedir;
|
||||
cvar_t *fs_cddir;
|
||||
cvar_t *fs_gamedirvar;
|
||||
|
||||
typedef struct filelink_s
|
||||
{
|
||||
struct filelink_s *next;
|
||||
char *from;
|
||||
int fromlength;
|
||||
char *to;
|
||||
} filelink_t;
|
||||
|
||||
filelink_t *fs_links;
|
||||
|
||||
typedef struct searchpath_s
|
||||
{
|
||||
char filename[MAX_OSPATH];
|
||||
pack_t *pack; // only one of filename / pack will be used
|
||||
struct searchpath_s *next;
|
||||
} searchpath_t;
|
||||
|
||||
searchpath_t *fs_searchpaths;
|
||||
searchpath_t *fs_base_searchpaths; // without gamedirs
|
||||
|
||||
|
||||
/*
|
||||
|
||||
All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
|
||||
|
||||
The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is
|
||||
only used during filesystem initialization.
|
||||
|
||||
The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FS_filelength
|
||||
================
|
||||
*/
|
||||
int FS_filelength (FILE *f)
|
||||
{
|
||||
int pos;
|
||||
int end;
|
||||
|
||||
pos = ftell (f);
|
||||
fseek (f, 0, SEEK_END);
|
||||
end = ftell (f);
|
||||
fseek (f, pos, SEEK_SET);
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
FS_CreatePath
|
||||
|
||||
Creates any directories needed to store the given filename
|
||||
============
|
||||
*/
|
||||
void FS_CreatePath (char *path)
|
||||
{
|
||||
char *ofs;
|
||||
|
||||
for (ofs = path+1 ; *ofs ; ofs++)
|
||||
{
|
||||
if (*ofs == '/')
|
||||
{ // create the directory
|
||||
*ofs = 0;
|
||||
Sys_Mkdir (path);
|
||||
*ofs = '/';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
FS_FCloseFile
|
||||
|
||||
For some reason, other dll's can't just cal fclose()
|
||||
on files returned by FS_FOpenFile...
|
||||
==============
|
||||
*/
|
||||
void FS_FCloseFile (FILE *f)
|
||||
{
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
// RAFAEL
|
||||
/*
|
||||
Developer_searchpath
|
||||
*/
|
||||
int Developer_searchpath (int who)
|
||||
{
|
||||
|
||||
int ch;
|
||||
// PMM - warning removal
|
||||
// char *start;
|
||||
searchpath_t *search;
|
||||
|
||||
if (who == 1) // xatrix
|
||||
ch = 'x';
|
||||
else if (who == 2)
|
||||
ch = 'r';
|
||||
|
||||
for (search = fs_searchpaths ; search ; search = search->next)
|
||||
{
|
||||
if (strstr (search->filename, "xatrix"))
|
||||
return 1;
|
||||
|
||||
if (strstr (search->filename, "rogue"))
|
||||
return 2;
|
||||
/*
|
||||
start = strchr (search->filename, ch);
|
||||
|
||||
if (start == NULL)
|
||||
continue;
|
||||
|
||||
if (strcmp (start ,"xatrix") == 0)
|
||||
return (1);
|
||||
*/
|
||||
}
|
||||
return (0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===========
|
||||
FS_FOpenFile
|
||||
|
||||
Finds the file in the search path.
|
||||
returns filesize and an open FILE *
|
||||
Used for streaming data out of either a pak file or
|
||||
a seperate file.
|
||||
===========
|
||||
*/
|
||||
int file_from_pak = 0;
|
||||
#ifndef NO_ADDONS
|
||||
int FS_FOpenFile (char *filename, FILE **file)
|
||||
{
|
||||
searchpath_t *search;
|
||||
char netpath[MAX_OSPATH];
|
||||
pack_t *pak;
|
||||
int i;
|
||||
filelink_t *link;
|
||||
|
||||
file_from_pak = 0;
|
||||
|
||||
// check for links first
|
||||
for (link = fs_links ; link ; link=link->next)
|
||||
{
|
||||
if (!strncmp (filename, link->from, link->fromlength))
|
||||
{
|
||||
Com_sprintf (netpath, sizeof(netpath), "%s%s",link->to, filename+link->fromlength);
|
||||
*file = fopen (netpath, "rb");
|
||||
if (*file)
|
||||
{
|
||||
Com_DPrintf ("link file: %s\n",netpath);
|
||||
return FS_filelength (*file);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// search through the path, one element at a time
|
||||
//
|
||||
for (search = fs_searchpaths ; search ; search = search->next)
|
||||
{
|
||||
// is the element a pak file?
|
||||
if (search->pack)
|
||||
{
|
||||
// look through all the pak file elements
|
||||
pak = search->pack;
|
||||
for (i=0 ; i<pak->numfiles ; i++)
|
||||
if (!Q_strcasecmp (pak->files[i].name, filename))
|
||||
{ // found it!
|
||||
file_from_pak = 1;
|
||||
Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
|
||||
// open a new file on the pakfile
|
||||
*file = fopen (pak->filename, "rb");
|
||||
if (!*file)
|
||||
Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
|
||||
fseek (*file, pak->files[i].filepos, SEEK_SET);
|
||||
return pak->files[i].filelen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// check a file in the directory tree
|
||||
|
||||
Com_sprintf (netpath, sizeof(netpath), "%s/%s",search->filename, filename);
|
||||
|
||||
*file = fopen (netpath, "rb");
|
||||
if (!*file)
|
||||
continue;
|
||||
|
||||
Com_DPrintf ("FindFile: %s\n",netpath);
|
||||
|
||||
return FS_filelength (*file);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Com_DPrintf ("FindFile: can't find %s\n", filename);
|
||||
|
||||
*file = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// this is just for demos to prevent add on hacking
|
||||
|
||||
int FS_FOpenFile (char *filename, FILE **file)
|
||||
{
|
||||
searchpath_t *search;
|
||||
char netpath[MAX_OSPATH];
|
||||
pack_t *pak;
|
||||
int i;
|
||||
|
||||
file_from_pak = 0;
|
||||
|
||||
// get config from directory, everything else from pak
|
||||
if (!strcmp(filename, "config.cfg") || !strncmp(filename, "players/", 8))
|
||||
{
|
||||
Com_sprintf (netpath, sizeof(netpath), "%s/%s",FS_Gamedir(), filename);
|
||||
|
||||
*file = fopen (netpath, "rb");
|
||||
if (!*file)
|
||||
return -1;
|
||||
|
||||
Com_DPrintf ("FindFile: %s\n",netpath);
|
||||
|
||||
return FS_filelength (*file);
|
||||
}
|
||||
|
||||
for (search = fs_searchpaths ; search ; search = search->next)
|
||||
if (search->pack)
|
||||
break;
|
||||
if (!search)
|
||||
{
|
||||
*file = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
pak = search->pack;
|
||||
for (i=0 ; i<pak->numfiles ; i++)
|
||||
if (!Q_strcasecmp (pak->files[i].name, filename))
|
||||
{ // found it!
|
||||
file_from_pak = 1;
|
||||
Com_DPrintf ("PackFile: %s : %s\n",pak->filename, filename);
|
||||
// open a new file on the pakfile
|
||||
*file = fopen (pak->filename, "rb");
|
||||
if (!*file)
|
||||
Com_Error (ERR_FATAL, "Couldn't reopen %s", pak->filename);
|
||||
fseek (*file, pak->files[i].filepos, SEEK_SET);
|
||||
return pak->files[i].filelen;
|
||||
}
|
||||
|
||||
Com_DPrintf ("FindFile: can't find %s\n", filename);
|
||||
|
||||
*file = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
FS_ReadFile
|
||||
|
||||
Properly handles partial reads
|
||||
=================
|
||||
*/
|
||||
void CDAudio_Stop(void);
|
||||
#define MAX_READ 0x10000 // read in blocks of 64k
|
||||
void FS_Read (void *buffer, int len, FILE *f)
|
||||
{
|
||||
int block, remaining;
|
||||
int read;
|
||||
byte *buf;
|
||||
int tries;
|
||||
|
||||
buf = (byte *)buffer;
|
||||
|
||||
// read in chunks for progress bar
|
||||
remaining = len;
|
||||
tries = 0;
|
||||
while (remaining)
|
||||
{
|
||||
block = remaining;
|
||||
if (block > MAX_READ)
|
||||
block = MAX_READ;
|
||||
read = fread (buf, 1, block, f);
|
||||
if (read == 0)
|
||||
{
|
||||
// we might have been trying to read from a CD
|
||||
if (!tries)
|
||||
{
|
||||
tries = 1;
|
||||
CDAudio_Stop();
|
||||
}
|
||||
else
|
||||
Com_Error (ERR_FATAL, "FS_Read: 0 bytes read");
|
||||
}
|
||||
|
||||
if (read == -1)
|
||||
Com_Error (ERR_FATAL, "FS_Read: -1 bytes read");
|
||||
|
||||
// do some progress bar thing here...
|
||||
|
||||
remaining -= read;
|
||||
buf += read;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FS_LoadFile
|
||||
|
||||
Filename are reletive to the quake search path
|
||||
a null buffer will just return the file length without loading
|
||||
============
|
||||
*/
|
||||
int FS_LoadFile (char *path, void **buffer)
|
||||
{
|
||||
FILE *h;
|
||||
byte *buf;
|
||||
int len;
|
||||
|
||||
buf = NULL; // quiet compiler warning
|
||||
|
||||
// look for it in the filesystem or pack files
|
||||
len = FS_FOpenFile (path, &h);
|
||||
if (!h)
|
||||
{
|
||||
if (buffer)
|
||||
*buffer = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
fclose (h);
|
||||
return len;
|
||||
}
|
||||
|
||||
buf = Z_Malloc(len);
|
||||
*buffer = buf;
|
||||
|
||||
FS_Read (buf, len, h);
|
||||
|
||||
fclose (h);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FS_FreeFile
|
||||
=============
|
||||
*/
|
||||
void FS_FreeFile (void *buffer)
|
||||
{
|
||||
Z_Free (buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
FS_LoadPackFile
|
||||
|
||||
Takes an explicit (not game tree related) path to a pak file.
|
||||
|
||||
Loads the header and directory, adding the files at the beginning
|
||||
of the list so they override previous pack files.
|
||||
=================
|
||||
*/
|
||||
pack_t *FS_LoadPackFile (char *packfile)
|
||||
{
|
||||
dpackheader_t header;
|
||||
int i;
|
||||
packfile_t *newfiles;
|
||||
int numpackfiles;
|
||||
pack_t *pack;
|
||||
FILE *packhandle;
|
||||
dpackfile_t info[MAX_FILES_IN_PACK];
|
||||
unsigned checksum;
|
||||
|
||||
packhandle = fopen(packfile, "rb");
|
||||
if (!packhandle)
|
||||
return NULL;
|
||||
|
||||
fread (&header, 1, sizeof(header), packhandle);
|
||||
if (LittleLong(header.ident) != IDPAKHEADER)
|
||||
Com_Error (ERR_FATAL, "%s is not a packfile", packfile);
|
||||
header.dirofs = LittleLong (header.dirofs);
|
||||
header.dirlen = LittleLong (header.dirlen);
|
||||
|
||||
numpackfiles = header.dirlen / sizeof(dpackfile_t);
|
||||
|
||||
if (numpackfiles > MAX_FILES_IN_PACK)
|
||||
Com_Error (ERR_FATAL, "%s has %i files", packfile, numpackfiles);
|
||||
|
||||
newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
|
||||
|
||||
fseek (packhandle, header.dirofs, SEEK_SET);
|
||||
fread (info, 1, header.dirlen, packhandle);
|
||||
|
||||
// crc the directory to check for modifications
|
||||
checksum = Com_BlockChecksum ((void *)info, header.dirlen);
|
||||
|
||||
#ifdef NO_ADDONS
|
||||
if (checksum != PAK0_CHECKSUM)
|
||||
return NULL;
|
||||
#endif
|
||||
// parse the directory
|
||||
for (i=0 ; i<numpackfiles ; i++)
|
||||
{
|
||||
strcpy (newfiles[i].name, info[i].name);
|
||||
newfiles[i].filepos = LittleLong(info[i].filepos);
|
||||
newfiles[i].filelen = LittleLong(info[i].filelen);
|
||||
}
|
||||
|
||||
pack = Z_Malloc (sizeof (pack_t));
|
||||
strcpy (pack->filename, packfile);
|
||||
pack->handle = packhandle;
|
||||
pack->numfiles = numpackfiles;
|
||||
pack->files = newfiles;
|
||||
|
||||
Com_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
|
||||
return pack;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FS_AddGameDirectory
|
||||
|
||||
Sets fs_gamedir, adds the directory to the head of the path,
|
||||
then loads and adds pak1.pak pak2.pak ...
|
||||
================
|
||||
*/
|
||||
void FS_AddGameDirectory (char *dir)
|
||||
{
|
||||
int i;
|
||||
searchpath_t *search;
|
||||
pack_t *pak;
|
||||
char pakfile[MAX_OSPATH];
|
||||
|
||||
strcpy (fs_gamedir, dir);
|
||||
|
||||
//
|
||||
// add the directory to the search path
|
||||
//
|
||||
search = Z_Malloc (sizeof(searchpath_t));
|
||||
strcpy (search->filename, dir);
|
||||
search->next = fs_searchpaths;
|
||||
fs_searchpaths = search;
|
||||
|
||||
//
|
||||
// add any pak files in the format pak0.pak pak1.pak, ...
|
||||
//
|
||||
for (i=0; i<10; i++)
|
||||
{
|
||||
Com_sprintf (pakfile, sizeof(pakfile), "%s/pak%i.pak", dir, i);
|
||||
pak = FS_LoadPackFile (pakfile);
|
||||
if (!pak)
|
||||
continue;
|
||||
search = Z_Malloc (sizeof(searchpath_t));
|
||||
search->pack = pak;
|
||||
search->next = fs_searchpaths;
|
||||
fs_searchpaths = search;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FS_Gamedir
|
||||
|
||||
Called to find where to write a file (demos, savegames, etc)
|
||||
============
|
||||
*/
|
||||
char *FS_Gamedir (void)
|
||||
{
|
||||
return fs_gamedir;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
FS_ExecAutoexec
|
||||
=============
|
||||
*/
|
||||
void FS_ExecAutoexec (void)
|
||||
{
|
||||
char *dir;
|
||||
char name [MAX_QPATH];
|
||||
|
||||
dir = Cvar_VariableString("gamedir");
|
||||
if (*dir)
|
||||
Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, dir);
|
||||
else
|
||||
Com_sprintf(name, sizeof(name), "%s/%s/autoexec.cfg", fs_basedir->string, BASEDIRNAME);
|
||||
if (Sys_FindFirst(name, 0, SFF_SUBDIR | SFF_HIDDEN | SFF_SYSTEM))
|
||||
Cbuf_AddText ("exec autoexec.cfg\n");
|
||||
Sys_FindClose();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FS_SetGamedir
|
||||
|
||||
Sets the gamedir and path to a different directory.
|
||||
================
|
||||
*/
|
||||
void FS_SetGamedir (char *dir)
|
||||
{
|
||||
searchpath_t *next;
|
||||
|
||||
if (strstr(dir, "..") || strstr(dir, "/")
|
||||
|| strstr(dir, "\\") || strstr(dir, ":") )
|
||||
{
|
||||
Com_Printf ("Gamedir should be a single filename, not a path\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// free up any current game dir info
|
||||
//
|
||||
while (fs_searchpaths != fs_base_searchpaths)
|
||||
{
|
||||
if (fs_searchpaths->pack)
|
||||
{
|
||||
fclose (fs_searchpaths->pack->handle);
|
||||
Z_Free (fs_searchpaths->pack->files);
|
||||
Z_Free (fs_searchpaths->pack);
|
||||
}
|
||||
next = fs_searchpaths->next;
|
||||
Z_Free (fs_searchpaths);
|
||||
fs_searchpaths = next;
|
||||
}
|
||||
|
||||
//
|
||||
// flush all data, so it will be forced to reload
|
||||
//
|
||||
if (dedicated && !dedicated->value)
|
||||
Cbuf_AddText ("vid_restart\nsnd_restart\n");
|
||||
|
||||
Com_sprintf (fs_gamedir, sizeof(fs_gamedir), "%s/%s", fs_basedir->string, dir);
|
||||
|
||||
if (!strcmp(dir,BASEDIRNAME) || (*dir == 0))
|
||||
{
|
||||
Cvar_FullSet ("gamedir", "", CVAR_SERVERINFO|CVAR_NOSET);
|
||||
Cvar_FullSet ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_FullSet ("gamedir", dir, CVAR_SERVERINFO|CVAR_NOSET);
|
||||
if (fs_cddir->string[0])
|
||||
FS_AddGameDirectory (va("%s/%s", fs_cddir->string, dir) );
|
||||
FS_AddGameDirectory (va("%s/%s", fs_basedir->string, dir) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FS_Link_f
|
||||
|
||||
Creates a filelink_t
|
||||
================
|
||||
*/
|
||||
void FS_Link_f (void)
|
||||
{
|
||||
filelink_t *l, **prev;
|
||||
|
||||
if (Cmd_Argc() != 3)
|
||||
{
|
||||
Com_Printf ("USAGE: link <from> <to>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// see if the link already exists
|
||||
prev = &fs_links;
|
||||
for (l=fs_links ; l ; l=l->next)
|
||||
{
|
||||
if (!strcmp (l->from, Cmd_Argv(1)))
|
||||
{
|
||||
Z_Free (l->to);
|
||||
if (!strlen(Cmd_Argv(2)))
|
||||
{ // delete it
|
||||
*prev = l->next;
|
||||
Z_Free (l->from);
|
||||
Z_Free (l);
|
||||
return;
|
||||
}
|
||||
l->to = CopyString (Cmd_Argv(2));
|
||||
return;
|
||||
}
|
||||
prev = &l->next;
|
||||
}
|
||||
|
||||
// create a new link
|
||||
l = Z_Malloc(sizeof(*l));
|
||||
l->next = fs_links;
|
||||
fs_links = l;
|
||||
l->from = CopyString(Cmd_Argv(1));
|
||||
l->fromlength = strlen(l->from);
|
||||
l->to = CopyString(Cmd_Argv(2));
|
||||
}
|
||||
|
||||
/*
|
||||
** FS_ListFiles
|
||||
*/
|
||||
char **FS_ListFiles( char *findname, int *numfiles, unsigned musthave, unsigned canthave )
|
||||
{
|
||||
char *s;
|
||||
int nfiles = 0;
|
||||
char **list = 0;
|
||||
|
||||
s = Sys_FindFirst( findname, musthave, canthave );
|
||||
while ( s )
|
||||
{
|
||||
if ( s[strlen(s)-1] != '.' )
|
||||
nfiles++;
|
||||
s = Sys_FindNext( musthave, canthave );
|
||||
}
|
||||
Sys_FindClose ();
|
||||
|
||||
if ( !nfiles )
|
||||
return NULL;
|
||||
|
||||
nfiles++; // add space for a guard
|
||||
*numfiles = nfiles;
|
||||
|
||||
list = malloc( sizeof( char * ) * nfiles );
|
||||
memset( list, 0, sizeof( char * ) * nfiles );
|
||||
|
||||
s = Sys_FindFirst( findname, musthave, canthave );
|
||||
nfiles = 0;
|
||||
while ( s )
|
||||
{
|
||||
if ( s[strlen(s)-1] != '.' )
|
||||
{
|
||||
list[nfiles] = strdup( s );
|
||||
#ifdef _WIN32
|
||||
strlwr( list[nfiles] );
|
||||
#endif
|
||||
nfiles++;
|
||||
}
|
||||
s = Sys_FindNext( musthave, canthave );
|
||||
}
|
||||
Sys_FindClose ();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*
|
||||
** FS_Dir_f
|
||||
*/
|
||||
void FS_Dir_f( void )
|
||||
{
|
||||
char *path = NULL;
|
||||
char findname[1024];
|
||||
char wildcard[1024] = "*.*";
|
||||
char **dirnames;
|
||||
int ndirs;
|
||||
|
||||
if ( Cmd_Argc() != 1 )
|
||||
{
|
||||
strcpy( wildcard, Cmd_Argv( 1 ) );
|
||||
}
|
||||
|
||||
while ( ( path = FS_NextPath( path ) ) != NULL )
|
||||
{
|
||||
char *tmp = findname;
|
||||
|
||||
Com_sprintf( findname, sizeof(findname), "%s/%s", path, wildcard );
|
||||
|
||||
while ( *tmp != 0 )
|
||||
{
|
||||
if ( *tmp == '\\' )
|
||||
*tmp = '/';
|
||||
tmp++;
|
||||
}
|
||||
Com_Printf( "Directory of %s\n", findname );
|
||||
Com_Printf( "----\n" );
|
||||
|
||||
if ( ( dirnames = FS_ListFiles( findname, &ndirs, 0, 0 ) ) != 0 )
|
||||
{
|
||||
int i;
|
||||
|
||||
for ( i = 0; i < ndirs-1; i++ )
|
||||
{
|
||||
if ( strrchr( dirnames[i], '/' ) )
|
||||
Com_Printf( "%s\n", strrchr( dirnames[i], '/' ) + 1 );
|
||||
else
|
||||
Com_Printf( "%s\n", dirnames[i] );
|
||||
|
||||
free( dirnames[i] );
|
||||
}
|
||||
free( dirnames );
|
||||
}
|
||||
Com_Printf( "\n" );
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FS_Path_f
|
||||
|
||||
============
|
||||
*/
|
||||
void FS_Path_f (void)
|
||||
{
|
||||
searchpath_t *s;
|
||||
filelink_t *l;
|
||||
|
||||
Com_Printf ("Current search path:\n");
|
||||
for (s=fs_searchpaths ; s ; s=s->next)
|
||||
{
|
||||
if (s == fs_base_searchpaths)
|
||||
Com_Printf ("----------\n");
|
||||
if (s->pack)
|
||||
Com_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
|
||||
else
|
||||
Com_Printf ("%s\n", s->filename);
|
||||
}
|
||||
|
||||
Com_Printf ("\nLinks:\n");
|
||||
for (l=fs_links ; l ; l=l->next)
|
||||
Com_Printf ("%s : %s\n", l->from, l->to);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_NextPath
|
||||
|
||||
Allows enumerating all of the directories in the search path
|
||||
================
|
||||
*/
|
||||
char *FS_NextPath (char *prevpath)
|
||||
{
|
||||
searchpath_t *s;
|
||||
char *prev;
|
||||
|
||||
if (!prevpath)
|
||||
return fs_gamedir;
|
||||
|
||||
prev = fs_gamedir;
|
||||
for (s=fs_searchpaths ; s ; s=s->next)
|
||||
{
|
||||
if (s->pack)
|
||||
continue;
|
||||
if (prevpath == prev)
|
||||
return s->filename;
|
||||
prev = s->filename;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
FS_InitFilesystem
|
||||
================
|
||||
*/
|
||||
void FS_InitFilesystem (void)
|
||||
{
|
||||
Cmd_AddCommand ("path", FS_Path_f);
|
||||
Cmd_AddCommand ("link", FS_Link_f);
|
||||
Cmd_AddCommand ("dir", FS_Dir_f );
|
||||
|
||||
//
|
||||
// basedir <path>
|
||||
// allows the game to run from outside the data tree
|
||||
//
|
||||
fs_basedir = Cvar_Get ("basedir", ".", CVAR_NOSET);
|
||||
|
||||
//
|
||||
// cddir <path>
|
||||
// Logically concatenates the cddir after the basedir for
|
||||
// allows the game to run from outside the data tree
|
||||
//
|
||||
fs_cddir = Cvar_Get ("cddir", "", CVAR_NOSET);
|
||||
if (fs_cddir->string[0])
|
||||
FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_cddir->string) );
|
||||
|
||||
//
|
||||
// start up with baseq2 by default
|
||||
//
|
||||
FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) );
|
||||
|
||||
// any set gamedirs will be freed up to here
|
||||
fs_base_searchpaths = fs_searchpaths;
|
||||
|
||||
// check for game override
|
||||
fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO);
|
||||
if (fs_gamedirvar->string[0])
|
||||
FS_SetGamedir (fs_gamedirvar->string);
|
||||
}
|
||||
|
||||
|
||||
|
278
qcommon/md4.c
Normal file
278
qcommon/md4.c
Normal file
@ -0,0 +1,278 @@
|
||||
/* GLOBAL.H - RSAREF types and constants */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* POINTER defines a generic pointer type */
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
/* UINT2 defines a two byte word */
|
||||
typedef unsigned short int UINT2;
|
||||
|
||||
/* UINT4 defines a four byte word */
|
||||
#ifdef __alpha__
|
||||
typedef unsigned int UINT4;
|
||||
#else
|
||||
typedef unsigned long int UINT4;
|
||||
#endif
|
||||
|
||||
|
||||
/* MD4.H - header file for MD4C.C */
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it is identified as the <20>RSA Data Security, Inc. MD4 Message-Digest Algorithm<68> in all material mentioning or referencing this software or this function.
|
||||
License is also granted to make and use derivative works provided that such works are identified as <20>derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm<68> in all material mentioning or referencing the derived work.
|
||||
RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided <20>as is<69> without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this documentation and/or software. */
|
||||
|
||||
/* MD4 context. */
|
||||
typedef struct {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD4_CTX;
|
||||
|
||||
void MD4Init (MD4_CTX *);
|
||||
void MD4Update (MD4_CTX *, unsigned char *, unsigned int);
|
||||
void MD4Final (unsigned char [16], MD4_CTX *);
|
||||
|
||||
|
||||
|
||||
/* MD4C.C - RSA Data Security, Inc., MD4 message-digest algorithm */
|
||||
/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it is identified as the
|
||||
RSA Data Security, Inc. MD4 Message-Digest Algorithm
|
||||
in all material mentioning or referencing this software or this function.
|
||||
License is also granted to make and use derivative works provided that such works are identified as
|
||||
derived from the RSA Data Security, Inc. MD4 Message-Digest Algorithm
|
||||
in all material mentioning or referencing the derived work.
|
||||
RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided
|
||||
as is without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this documentation and/or software. */
|
||||
|
||||
/* Constants for MD4Transform routine. */
|
||||
#define S11 3
|
||||
#define S12 7
|
||||
#define S13 11
|
||||
#define S14 19
|
||||
#define S21 3
|
||||
#define S22 5
|
||||
#define S23 9
|
||||
#define S24 13
|
||||
#define S31 3
|
||||
#define S32 9
|
||||
#define S33 11
|
||||
#define S34 15
|
||||
|
||||
static void MD4Transform (UINT4 [4], unsigned char [64]);
|
||||
static void Encode (unsigned char *, UINT4 *, unsigned int);
|
||||
static void Decode (UINT4 *, unsigned char *, unsigned int);
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* F, G and H are basic MD4 functions. */
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits. */
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
|
||||
/* Rotation is separate from addition to prevent recomputation */
|
||||
#define FF(a, b, c, d, x, s) {(a) += F ((b), (c), (d)) + (x); (a) = ROTATE_LEFT ((a), (s));}
|
||||
|
||||
#define GG(a, b, c, d, x, s) {(a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; (a) = ROTATE_LEFT ((a), (s));}
|
||||
|
||||
#define HH(a, b, c, d, x, s) {(a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; (a) = ROTATE_LEFT ((a), (s));}
|
||||
|
||||
|
||||
/* MD4 initialization. Begins an MD4 operation, writing a new context. */
|
||||
void MD4Init (MD4_CTX *context)
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
|
||||
/* Load magic initialization constants.*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/* MD4 block update operation. Continues an MD4 message-digest operation, processing another message block, and updating the context. */
|
||||
void MD4Update (MD4_CTX *context, unsigned char *input, unsigned int inputLen)
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((UINT4)inputLen << 3))< ((UINT4)inputLen << 3))
|
||||
context->count[1]++;
|
||||
|
||||
context->count[1] += ((UINT4)inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible.*/
|
||||
if (inputLen >= partLen)
|
||||
{
|
||||
memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
|
||||
MD4Transform (context->state, context->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD4Transform (context->state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
memcpy ((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
|
||||
}
|
||||
|
||||
|
||||
/* MD4 finalization. Ends an MD4 message-digest operation, writing the the message digest and zeroizing the context. */
|
||||
void MD4Final (unsigned char digest[16], MD4_CTX *context)
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, context->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.*/
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD4Update (context, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD4Update (context, bits, 8);
|
||||
|
||||
/* Store state in digest */
|
||||
Encode (digest, context->state, 16);
|
||||
|
||||
/* Zeroize sensitive information.*/
|
||||
memset ((POINTER)context, 0, sizeof (*context));
|
||||
}
|
||||
|
||||
|
||||
/* MD4 basic transformation. Transforms state based on block. */
|
||||
static void MD4Transform (UINT4 state[4], unsigned char block[64])
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 0], S21); /* 17 */
|
||||
GG (d, a, b, c, x[ 4], S22); /* 18 */
|
||||
GG (c, d, a, b, x[ 8], S23); /* 19 */
|
||||
GG (b, c, d, a, x[12], S24); /* 20 */
|
||||
GG (a, b, c, d, x[ 1], S21); /* 21 */
|
||||
GG (d, a, b, c, x[ 5], S22); /* 22 */
|
||||
GG (c, d, a, b, x[ 9], S23); /* 23 */
|
||||
GG (b, c, d, a, x[13], S24); /* 24 */
|
||||
GG (a, b, c, d, x[ 2], S21); /* 25 */
|
||||
GG (d, a, b, c, x[ 6], S22); /* 26 */
|
||||
GG (c, d, a, b, x[10], S23); /* 27 */
|
||||
GG (b, c, d, a, x[14], S24); /* 28 */
|
||||
GG (a, b, c, d, x[ 3], S21); /* 29 */
|
||||
GG (d, a, b, c, x[ 7], S22); /* 30 */
|
||||
GG (c, d, a, b, x[11], S23); /* 31 */
|
||||
GG (b, c, d, a, x[15], S24); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 0], S31); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32); /* 34 */
|
||||
HH (c, d, a, b, x[ 4], S33); /* 35 */
|
||||
HH (b, c, d, a, x[12], S34); /* 36 */
|
||||
HH (a, b, c, d, x[ 2], S31); /* 37 */
|
||||
HH (d, a, b, c, x[10], S32); /* 38 */
|
||||
HH (c, d, a, b, x[ 6], S33); /* 39 */
|
||||
HH (b, c, d, a, x[14], S34); /* 40 */
|
||||
HH (a, b, c, d, x[ 1], S31); /* 41 */
|
||||
HH (d, a, b, c, x[ 9], S32); /* 42 */
|
||||
HH (c, d, a, b, x[ 5], S33); /* 43 */
|
||||
HH (b, c, d, a, x[13], S34); /* 44 */
|
||||
HH (a, b, c, d, x[ 3], S31); /* 45 */
|
||||
HH (d, a, b, c, x[11], S32); /* 46 */
|
||||
HH (c, d, a, b, x[ 7], S33); /* 47 */
|
||||
HH (b, c, d, a, x[15], S34); /* 48 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/* Zeroize sensitive information.*/
|
||||
memset ((POINTER)x, 0, sizeof (x));
|
||||
}
|
||||
|
||||
|
||||
/* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */
|
||||
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */
|
||||
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
|
||||
unsigned Com_BlockChecksum (void *buffer, int length)
|
||||
{
|
||||
int digest[4];
|
||||
unsigned val;
|
||||
MD4_CTX ctx;
|
||||
|
||||
MD4Init (&ctx);
|
||||
MD4Update (&ctx, (unsigned char *)buffer, length);
|
||||
MD4Final ( (unsigned char *)digest, &ctx);
|
||||
|
||||
val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
|
||||
|
||||
return val;
|
||||
}
|
387
qcommon/net_chan.c
Normal file
387
qcommon/net_chan.c
Normal file
@ -0,0 +1,387 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "qcommon.h"
|
||||
|
||||
/*
|
||||
|
||||
packet header
|
||||
-------------
|
||||
31 sequence
|
||||
1 does this message contain a reliable payload
|
||||
31 acknowledge sequence
|
||||
1 acknowledge receipt of even/odd message
|
||||
16 qport
|
||||
|
||||
The remote connection never knows if it missed a reliable message, the
|
||||
local side detects that it has been dropped by seeing a sequence acknowledge
|
||||
higher thatn the last reliable sequence, but without the correct evon/odd
|
||||
bit for the reliable set.
|
||||
|
||||
If the sender notices that a reliable message has been dropped, it will be
|
||||
retransmitted. It will not be retransmitted again until a message after
|
||||
the retransmit has been acknowledged and the reliable still failed to get there.
|
||||
|
||||
if the sequence number is -1, the packet should be handled without a netcon
|
||||
|
||||
The reliable message can be added to at any time by doing
|
||||
MSG_Write* (&netchan->message, <data>).
|
||||
|
||||
If the message buffer is overflowed, either by a single message, or by
|
||||
multiple frames worth piling up while the last reliable transmit goes
|
||||
unacknowledged, the netchan signals a fatal error.
|
||||
|
||||
Reliable messages are always placed first in a packet, then the unreliable
|
||||
message is included if there is sufficient room.
|
||||
|
||||
To the receiver, there is no distinction between the reliable and unreliable
|
||||
parts of the message, they are just processed out as a single larger message.
|
||||
|
||||
Illogical packet sequence numbers cause the packet to be dropped, but do
|
||||
not kill the connection. This, combined with the tight window of valid
|
||||
reliable acknowledgement numbers provides protection against malicious
|
||||
address spoofing.
|
||||
|
||||
|
||||
The qport field is a workaround for bad address translating routers that
|
||||
sometimes remap the client's source port on a packet during gameplay.
|
||||
|
||||
If the base part of the net address matches and the qport matches, then the
|
||||
channel matches even if the IP port differs. The IP port should be updated
|
||||
to the new value before sending out any replies.
|
||||
|
||||
|
||||
If there is no information that needs to be transfered on a given frame,
|
||||
such as during the connection stage while waiting for the client to load,
|
||||
then a packet only needs to be delivered if there is something in the
|
||||
unacknowledged reliable
|
||||
*/
|
||||
|
||||
cvar_t *showpackets;
|
||||
cvar_t *showdrop;
|
||||
cvar_t *qport;
|
||||
|
||||
netadr_t net_from;
|
||||
sizebuf_t net_message;
|
||||
byte net_message_buffer[MAX_MSGLEN];
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_Init
|
||||
|
||||
===============
|
||||
*/
|
||||
void Netchan_Init (void)
|
||||
{
|
||||
int port;
|
||||
|
||||
// pick a port value that should be nice and random
|
||||
port = Sys_Milliseconds() & 0xffff;
|
||||
|
||||
showpackets = Cvar_Get ("showpackets", "0", 0);
|
||||
showdrop = Cvar_Get ("showdrop", "0", 0);
|
||||
qport = Cvar_Get ("qport", va("%i", port), CVAR_NOSET);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_OutOfBand
|
||||
|
||||
Sends an out-of-band datagram
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data)
|
||||
{
|
||||
sizebuf_t send;
|
||||
byte send_buf[MAX_MSGLEN];
|
||||
|
||||
// write the packet header
|
||||
SZ_Init (&send, send_buf, sizeof(send_buf));
|
||||
|
||||
MSG_WriteLong (&send, -1); // -1 sequence means out of band
|
||||
SZ_Write (&send, data, length);
|
||||
|
||||
// send the datagram
|
||||
NET_SendPacket (net_socket, send.cursize, send.data, adr);
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_OutOfBandPrint
|
||||
|
||||
Sends a text message in an out-of-band datagram
|
||||
================
|
||||
*/
|
||||
void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
static char string[MAX_MSGLEN - 4];
|
||||
|
||||
va_start (argptr, format);
|
||||
vsprintf (string, format,argptr);
|
||||
va_end (argptr);
|
||||
|
||||
Netchan_OutOfBand (net_socket, adr, strlen(string), (byte *)string);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
Netchan_Setup
|
||||
|
||||
called to open a channel to a remote system
|
||||
==============
|
||||
*/
|
||||
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport)
|
||||
{
|
||||
memset (chan, 0, sizeof(*chan));
|
||||
|
||||
chan->sock = sock;
|
||||
chan->remote_address = adr;
|
||||
chan->qport = qport;
|
||||
chan->last_received = curtime;
|
||||
chan->incoming_sequence = 0;
|
||||
chan->outgoing_sequence = 1;
|
||||
|
||||
SZ_Init (&chan->message, chan->message_buf, sizeof(chan->message_buf));
|
||||
chan->message.allowoverflow = true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_CanReliable
|
||||
|
||||
Returns true if the last reliable message has acked
|
||||
================
|
||||
*/
|
||||
qboolean Netchan_CanReliable (netchan_t *chan)
|
||||
{
|
||||
if (chan->reliable_length)
|
||||
return false; // waiting for ack
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
qboolean Netchan_NeedReliable (netchan_t *chan)
|
||||
{
|
||||
qboolean send_reliable;
|
||||
|
||||
// if the remote side dropped the last reliable message, resend it
|
||||
send_reliable = false;
|
||||
|
||||
if (chan->incoming_acknowledged > chan->last_reliable_sequence
|
||||
&& chan->incoming_reliable_acknowledged != chan->reliable_sequence)
|
||||
send_reliable = true;
|
||||
|
||||
// if the reliable transmit buffer is empty, copy the current message out
|
||||
if (!chan->reliable_length && chan->message.cursize)
|
||||
{
|
||||
send_reliable = true;
|
||||
}
|
||||
|
||||
return send_reliable;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
Netchan_Transmit
|
||||
|
||||
tries to send an unreliable message to a connection, and handles the
|
||||
transmition / retransmition of the reliable messages.
|
||||
|
||||
A 0 length will still generate a packet and deal with the reliable messages.
|
||||
================
|
||||
*/
|
||||
void Netchan_Transmit (netchan_t *chan, int length, byte *data)
|
||||
{
|
||||
sizebuf_t send;
|
||||
byte send_buf[MAX_MSGLEN];
|
||||
qboolean send_reliable;
|
||||
unsigned w1, w2;
|
||||
|
||||
// check for message overflow
|
||||
if (chan->message.overflowed)
|
||||
{
|
||||
chan->fatal_error = true;
|
||||
Com_Printf ("%s:Outgoing message overflow\n"
|
||||
, NET_AdrToString (chan->remote_address));
|
||||
return;
|
||||
}
|
||||
|
||||
send_reliable = Netchan_NeedReliable (chan);
|
||||
|
||||
if (!chan->reliable_length && chan->message.cursize)
|
||||
{
|
||||
memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize);
|
||||
chan->reliable_length = chan->message.cursize;
|
||||
chan->message.cursize = 0;
|
||||
chan->reliable_sequence ^= 1;
|
||||
}
|
||||
|
||||
|
||||
// write the packet header
|
||||
SZ_Init (&send, send_buf, sizeof(send_buf));
|
||||
|
||||
w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31);
|
||||
w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31);
|
||||
|
||||
chan->outgoing_sequence++;
|
||||
chan->last_sent = curtime;
|
||||
|
||||
MSG_WriteLong (&send, w1);
|
||||
MSG_WriteLong (&send, w2);
|
||||
|
||||
// send the qport if we are a client
|
||||
if (chan->sock == NS_CLIENT)
|
||||
MSG_WriteShort (&send, qport->value);
|
||||
|
||||
// copy the reliable message to the packet first
|
||||
if (send_reliable)
|
||||
{
|
||||
SZ_Write (&send, chan->reliable_buf, chan->reliable_length);
|
||||
chan->last_reliable_sequence = chan->outgoing_sequence;
|
||||
}
|
||||
|
||||
// add the unreliable part if space is available
|
||||
if (send.maxsize - send.cursize >= length)
|
||||
SZ_Write (&send, data, length);
|
||||
else
|
||||
Com_Printf ("Netchan_Transmit: dumped unreliable\n");
|
||||
|
||||
// send the datagram
|
||||
NET_SendPacket (chan->sock, send.cursize, send.data, chan->remote_address);
|
||||
|
||||
if (showpackets->value)
|
||||
{
|
||||
if (send_reliable)
|
||||
Com_Printf ("send %4i : s=%i reliable=%i ack=%i rack=%i\n"
|
||||
, send.cursize
|
||||
, chan->outgoing_sequence - 1
|
||||
, chan->reliable_sequence
|
||||
, chan->incoming_sequence
|
||||
, chan->incoming_reliable_sequence);
|
||||
else
|
||||
Com_Printf ("send %4i : s=%i ack=%i rack=%i\n"
|
||||
, send.cursize
|
||||
, chan->outgoing_sequence - 1
|
||||
, chan->incoming_sequence
|
||||
, chan->incoming_reliable_sequence);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Netchan_Process
|
||||
|
||||
called when the current net_message is from remote_address
|
||||
modifies net_message so that it points to the packet payload
|
||||
=================
|
||||
*/
|
||||
qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg)
|
||||
{
|
||||
unsigned sequence, sequence_ack;
|
||||
unsigned reliable_ack, reliable_message;
|
||||
int qport;
|
||||
|
||||
// get sequence numbers
|
||||
MSG_BeginReading (msg);
|
||||
sequence = MSG_ReadLong (msg);
|
||||
sequence_ack = MSG_ReadLong (msg);
|
||||
|
||||
// read the qport if we are a server
|
||||
if (chan->sock == NS_SERVER)
|
||||
qport = MSG_ReadShort (msg);
|
||||
|
||||
reliable_message = sequence >> 31;
|
||||
reliable_ack = sequence_ack >> 31;
|
||||
|
||||
sequence &= ~(1<<31);
|
||||
sequence_ack &= ~(1<<31);
|
||||
|
||||
if (showpackets->value)
|
||||
{
|
||||
if (reliable_message)
|
||||
Com_Printf ("recv %4i : s=%i reliable=%i ack=%i rack=%i\n"
|
||||
, msg->cursize
|
||||
, sequence
|
||||
, chan->incoming_reliable_sequence ^ 1
|
||||
, sequence_ack
|
||||
, reliable_ack);
|
||||
else
|
||||
Com_Printf ("recv %4i : s=%i ack=%i rack=%i\n"
|
||||
, msg->cursize
|
||||
, sequence
|
||||
, sequence_ack
|
||||
, reliable_ack);
|
||||
}
|
||||
|
||||
//
|
||||
// discard stale or duplicated packets
|
||||
//
|
||||
if (sequence <= chan->incoming_sequence)
|
||||
{
|
||||
if (showdrop->value)
|
||||
Com_Printf ("%s:Out of order packet %i at %i\n"
|
||||
, NET_AdrToString (chan->remote_address)
|
||||
, sequence
|
||||
, chan->incoming_sequence);
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// dropped packets don't keep the message from being used
|
||||
//
|
||||
chan->dropped = sequence - (chan->incoming_sequence+1);
|
||||
if (chan->dropped > 0)
|
||||
{
|
||||
if (showdrop->value)
|
||||
Com_Printf ("%s:Dropped %i packets at %i\n"
|
||||
, NET_AdrToString (chan->remote_address)
|
||||
, chan->dropped
|
||||
, sequence);
|
||||
}
|
||||
|
||||
//
|
||||
// if the current outgoing reliable message has been acknowledged
|
||||
// clear the buffer to make way for the next
|
||||
//
|
||||
if (reliable_ack == chan->reliable_sequence)
|
||||
chan->reliable_length = 0; // it has been received
|
||||
|
||||
//
|
||||
// if this message contains a reliable message, bump incoming_reliable_sequence
|
||||
//
|
||||
chan->incoming_sequence = sequence;
|
||||
chan->incoming_acknowledged = sequence_ack;
|
||||
chan->incoming_reliable_acknowledged = reliable_ack;
|
||||
if (reliable_message)
|
||||
{
|
||||
chan->incoming_reliable_sequence ^= 1;
|
||||
}
|
||||
|
||||
//
|
||||
// the message can now be read from the current message pointer
|
||||
//
|
||||
chan->last_received = curtime;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
1360
qcommon/pmove.c
Normal file
1360
qcommon/pmove.c
Normal file
File diff suppressed because it is too large
Load Diff
826
qcommon/qcommon.h
Normal file
826
qcommon/qcommon.h
Normal file
@ -0,0 +1,826 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// qcommon.h -- definitions common between client and server, but not game.dll
|
||||
|
||||
#include "../game/q_shared.h"
|
||||
|
||||
|
||||
#define VERSION 3.19
|
||||
|
||||
#define BASEDIRNAME "baseq2"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define BUILDSTRING "Win32 RELEASE"
|
||||
#else
|
||||
#define BUILDSTRING "Win32 DEBUG"
|
||||
#endif
|
||||
|
||||
#ifdef _M_IX86
|
||||
#define CPUSTRING "x86"
|
||||
#elif defined _M_ALPHA
|
||||
#define CPUSTRING "AXP"
|
||||
#endif
|
||||
|
||||
#elif defined __linux__
|
||||
|
||||
#define BUILDSTRING "Linux"
|
||||
|
||||
#ifdef __i386__
|
||||
#define CPUSTRING "i386"
|
||||
#elif defined __alpha__
|
||||
#define CPUSTRING "axp"
|
||||
#else
|
||||
#define CPUSTRING "Unknown"
|
||||
#endif
|
||||
|
||||
#elif defined __sun__
|
||||
|
||||
#define BUILDSTRING "Solaris"
|
||||
|
||||
#ifdef __i386__
|
||||
#define CPUSTRING "i386"
|
||||
#else
|
||||
#define CPUSTRING "sparc"
|
||||
#endif
|
||||
|
||||
#else // !WIN32
|
||||
|
||||
#define BUILDSTRING "NON-WIN32"
|
||||
#define CPUSTRING "NON-WIN32"
|
||||
|
||||
#endif
|
||||
|
||||
//============================================================================
|
||||
|
||||
typedef struct sizebuf_s
|
||||
{
|
||||
qboolean allowoverflow; // if false, do a Com_Error
|
||||
qboolean overflowed; // set to true if the buffer size failed
|
||||
byte *data;
|
||||
int maxsize;
|
||||
int cursize;
|
||||
int readcount;
|
||||
} sizebuf_t;
|
||||
|
||||
void SZ_Init (sizebuf_t *buf, byte *data, int length);
|
||||
void SZ_Clear (sizebuf_t *buf);
|
||||
void *SZ_GetSpace (sizebuf_t *buf, int length);
|
||||
void SZ_Write (sizebuf_t *buf, void *data, int length);
|
||||
void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf
|
||||
|
||||
//============================================================================
|
||||
|
||||
struct usercmd_s;
|
||||
struct entity_state_s;
|
||||
|
||||
void MSG_WriteChar (sizebuf_t *sb, int c);
|
||||
void MSG_WriteByte (sizebuf_t *sb, int c);
|
||||
void MSG_WriteShort (sizebuf_t *sb, int c);
|
||||
void MSG_WriteLong (sizebuf_t *sb, int c);
|
||||
void MSG_WriteFloat (sizebuf_t *sb, float f);
|
||||
void MSG_WriteString (sizebuf_t *sb, char *s);
|
||||
void MSG_WriteCoord (sizebuf_t *sb, float f);
|
||||
void MSG_WritePos (sizebuf_t *sb, vec3_t pos);
|
||||
void MSG_WriteAngle (sizebuf_t *sb, float f);
|
||||
void MSG_WriteAngle16 (sizebuf_t *sb, float f);
|
||||
void MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
|
||||
void MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, qboolean force, qboolean newentity);
|
||||
void MSG_WriteDir (sizebuf_t *sb, vec3_t vector);
|
||||
|
||||
|
||||
void MSG_BeginReading (sizebuf_t *sb);
|
||||
|
||||
int MSG_ReadChar (sizebuf_t *sb);
|
||||
int MSG_ReadByte (sizebuf_t *sb);
|
||||
int MSG_ReadShort (sizebuf_t *sb);
|
||||
int MSG_ReadLong (sizebuf_t *sb);
|
||||
float MSG_ReadFloat (sizebuf_t *sb);
|
||||
char *MSG_ReadString (sizebuf_t *sb);
|
||||
char *MSG_ReadStringLine (sizebuf_t *sb);
|
||||
|
||||
float MSG_ReadCoord (sizebuf_t *sb);
|
||||
void MSG_ReadPos (sizebuf_t *sb, vec3_t pos);
|
||||
float MSG_ReadAngle (sizebuf_t *sb);
|
||||
float MSG_ReadAngle16 (sizebuf_t *sb);
|
||||
void MSG_ReadDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct usercmd_s *cmd);
|
||||
|
||||
void MSG_ReadDir (sizebuf_t *sb, vec3_t vector);
|
||||
|
||||
void MSG_ReadData (sizebuf_t *sb, void *buffer, int size);
|
||||
|
||||
//============================================================================
|
||||
|
||||
extern qboolean bigendien;
|
||||
|
||||
extern short BigShort (short l);
|
||||
extern short LittleShort (short l);
|
||||
extern int BigLong (int l);
|
||||
extern int LittleLong (int l);
|
||||
extern float BigFloat (float l);
|
||||
extern float LittleFloat (float l);
|
||||
|
||||
//============================================================================
|
||||
|
||||
|
||||
int COM_Argc (void);
|
||||
char *COM_Argv (int arg); // range and null checked
|
||||
void COM_ClearArgv (int arg);
|
||||
int COM_CheckParm (char *parm);
|
||||
void COM_AddParm (char *parm);
|
||||
|
||||
void COM_Init (void);
|
||||
void COM_InitArgv (int argc, char **argv);
|
||||
|
||||
char *CopyString (char *in);
|
||||
|
||||
//============================================================================
|
||||
|
||||
void Info_Print (char *s);
|
||||
|
||||
|
||||
/* crc.h */
|
||||
|
||||
void CRC_Init(unsigned short *crcvalue);
|
||||
void CRC_ProcessByte(unsigned short *crcvalue, byte data);
|
||||
unsigned short CRC_Value(unsigned short crcvalue);
|
||||
unsigned short CRC_Block (byte *start, int count);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
PROTOCOL
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
// protocol.h -- communications protocols
|
||||
|
||||
#define PROTOCOL_VERSION 34
|
||||
|
||||
//=========================================
|
||||
|
||||
#define PORT_MASTER 27900
|
||||
#define PORT_CLIENT 27901
|
||||
#define PORT_SERVER 27910
|
||||
|
||||
//=========================================
|
||||
|
||||
#define UPDATE_BACKUP 16 // copies of entity_state_t to keep buffered
|
||||
// must be power of two
|
||||
#define UPDATE_MASK (UPDATE_BACKUP-1)
|
||||
|
||||
|
||||
|
||||
//==================
|
||||
// the svc_strings[] array in cl_parse.c should mirror this
|
||||
//==================
|
||||
|
||||
//
|
||||
// server to client
|
||||
//
|
||||
enum svc_ops_e
|
||||
{
|
||||
svc_bad,
|
||||
|
||||
// these ops are known to the game dll
|
||||
svc_muzzleflash,
|
||||
svc_muzzleflash2,
|
||||
svc_temp_entity,
|
||||
svc_layout,
|
||||
svc_inventory,
|
||||
|
||||
// the rest are private to the client and server
|
||||
svc_nop,
|
||||
svc_disconnect,
|
||||
svc_reconnect,
|
||||
svc_sound, // <see code>
|
||||
svc_print, // [byte] id [string] null terminated string
|
||||
svc_stufftext, // [string] stuffed into client's console buffer, should be \n terminated
|
||||
svc_serverdata, // [long] protocol ...
|
||||
svc_configstring, // [short] [string]
|
||||
svc_spawnbaseline,
|
||||
svc_centerprint, // [string] to put in center of the screen
|
||||
svc_download, // [short] size [size bytes]
|
||||
svc_playerinfo, // variable
|
||||
svc_packetentities, // [...]
|
||||
svc_deltapacketentities, // [...]
|
||||
svc_frame
|
||||
};
|
||||
|
||||
//==============================================
|
||||
|
||||
//
|
||||
// client to server
|
||||
//
|
||||
enum clc_ops_e
|
||||
{
|
||||
clc_bad,
|
||||
clc_nop,
|
||||
clc_move, // [[usercmd_t]
|
||||
clc_userinfo, // [[userinfo string]
|
||||
clc_stringcmd // [string] message
|
||||
};
|
||||
|
||||
//==============================================
|
||||
|
||||
// plyer_state_t communication
|
||||
|
||||
#define PS_M_TYPE (1<<0)
|
||||
#define PS_M_ORIGIN (1<<1)
|
||||
#define PS_M_VELOCITY (1<<2)
|
||||
#define PS_M_TIME (1<<3)
|
||||
#define PS_M_FLAGS (1<<4)
|
||||
#define PS_M_GRAVITY (1<<5)
|
||||
#define PS_M_DELTA_ANGLES (1<<6)
|
||||
|
||||
#define PS_VIEWOFFSET (1<<7)
|
||||
#define PS_VIEWANGLES (1<<8)
|
||||
#define PS_KICKANGLES (1<<9)
|
||||
#define PS_BLEND (1<<10)
|
||||
#define PS_FOV (1<<11)
|
||||
#define PS_WEAPONINDEX (1<<12)
|
||||
#define PS_WEAPONFRAME (1<<13)
|
||||
#define PS_RDFLAGS (1<<14)
|
||||
|
||||
//==============================================
|
||||
|
||||
// user_cmd_t communication
|
||||
|
||||
// ms and light always sent, the others are optional
|
||||
#define CM_ANGLE1 (1<<0)
|
||||
#define CM_ANGLE2 (1<<1)
|
||||
#define CM_ANGLE3 (1<<2)
|
||||
#define CM_FORWARD (1<<3)
|
||||
#define CM_SIDE (1<<4)
|
||||
#define CM_UP (1<<5)
|
||||
#define CM_BUTTONS (1<<6)
|
||||
#define CM_IMPULSE (1<<7)
|
||||
|
||||
//==============================================
|
||||
|
||||
// a sound without an ent or pos will be a local only sound
|
||||
#define SND_VOLUME (1<<0) // a byte
|
||||
#define SND_ATTENUATION (1<<1) // a byte
|
||||
#define SND_POS (1<<2) // three coordinates
|
||||
#define SND_ENT (1<<3) // a short 0-2: channel, 3-12: entity
|
||||
#define SND_OFFSET (1<<4) // a byte, msec offset from frame start
|
||||
|
||||
#define DEFAULT_SOUND_PACKET_VOLUME 1.0
|
||||
#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0
|
||||
|
||||
//==============================================
|
||||
|
||||
// entity_state_t communication
|
||||
|
||||
// try to pack the common update flags into the first byte
|
||||
#define U_ORIGIN1 (1<<0)
|
||||
#define U_ORIGIN2 (1<<1)
|
||||
#define U_ANGLE2 (1<<2)
|
||||
#define U_ANGLE3 (1<<3)
|
||||
#define U_FRAME8 (1<<4) // frame is a byte
|
||||
#define U_EVENT (1<<5)
|
||||
#define U_REMOVE (1<<6) // REMOVE this entity, don't add it
|
||||
#define U_MOREBITS1 (1<<7) // read one additional byte
|
||||
|
||||
// second byte
|
||||
#define U_NUMBER16 (1<<8) // NUMBER8 is implicit if not set
|
||||
#define U_ORIGIN3 (1<<9)
|
||||
#define U_ANGLE1 (1<<10)
|
||||
#define U_MODEL (1<<11)
|
||||
#define U_RENDERFX8 (1<<12) // fullbright, etc
|
||||
#define U_EFFECTS8 (1<<14) // autorotate, trails, etc
|
||||
#define U_MOREBITS2 (1<<15) // read one additional byte
|
||||
|
||||
// third byte
|
||||
#define U_SKIN8 (1<<16)
|
||||
#define U_FRAME16 (1<<17) // frame is a short
|
||||
#define U_RENDERFX16 (1<<18) // 8 + 16 = 32
|
||||
#define U_EFFECTS16 (1<<19) // 8 + 16 = 32
|
||||
#define U_MODEL2 (1<<20) // weapons, flags, etc
|
||||
#define U_MODEL3 (1<<21)
|
||||
#define U_MODEL4 (1<<22)
|
||||
#define U_MOREBITS3 (1<<23) // read one additional byte
|
||||
|
||||
// fourth byte
|
||||
#define U_OLDORIGIN (1<<24) // FIXME: get rid of this
|
||||
#define U_SKIN16 (1<<25)
|
||||
#define U_SOUND (1<<26)
|
||||
#define U_SOLID (1<<27)
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
CMD
|
||||
|
||||
Command text buffering and command execution
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Any number of commands can be added in a frame, from several different sources.
|
||||
Most commands come from either keybindings or console line input, but remote
|
||||
servers can also send across commands and entire text files can be execed.
|
||||
|
||||
The + command line options are also added to the command buffer.
|
||||
|
||||
The game starts with a Cbuf_AddText ("exec quake.rc\n"); Cbuf_Execute ();
|
||||
|
||||
*/
|
||||
|
||||
#define EXEC_NOW 0 // don't return until completed
|
||||
#define EXEC_INSERT 1 // insert at current position, but don't run yet
|
||||
#define EXEC_APPEND 2 // add to end of the command buffer
|
||||
|
||||
void Cbuf_Init (void);
|
||||
// allocates an initial text buffer that will grow as needed
|
||||
|
||||
void Cbuf_AddText (char *text);
|
||||
// as new commands are generated from the console or keybindings,
|
||||
// the text is added to the end of the command buffer.
|
||||
|
||||
void Cbuf_InsertText (char *text);
|
||||
// when a command wants to issue other commands immediately, the text is
|
||||
// inserted at the beginning of the buffer, before any remaining unexecuted
|
||||
// commands.
|
||||
|
||||
void Cbuf_ExecuteText (int exec_when, char *text);
|
||||
// this can be used in place of either Cbuf_AddText or Cbuf_InsertText
|
||||
|
||||
void Cbuf_AddEarlyCommands (qboolean clear);
|
||||
// adds all the +set commands from the command line
|
||||
|
||||
qboolean Cbuf_AddLateCommands (void);
|
||||
// adds all the remaining + commands from the command line
|
||||
// Returns true if any late commands were added, which
|
||||
// will keep the demoloop from immediately starting
|
||||
|
||||
void Cbuf_Execute (void);
|
||||
// Pulls off \n terminated lines of text from the command buffer and sends
|
||||
// them through Cmd_ExecuteString. Stops when the buffer is empty.
|
||||
// Normally called once per frame, but may be explicitly invoked.
|
||||
// Do not call inside a command function!
|
||||
|
||||
void Cbuf_CopyToDefer (void);
|
||||
void Cbuf_InsertFromDefer (void);
|
||||
// These two functions are used to defer any pending commands while a map
|
||||
// is being loaded
|
||||
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
|
||||
Command execution takes a null terminated string, breaks it into tokens,
|
||||
then searches for a command or variable that matches the first token.
|
||||
|
||||
*/
|
||||
|
||||
typedef void (*xcommand_t) (void);
|
||||
|
||||
void Cmd_Init (void);
|
||||
|
||||
void Cmd_AddCommand (char *cmd_name, xcommand_t function);
|
||||
// called by the init functions of other parts of the program to
|
||||
// register commands and functions to call for them.
|
||||
// The cmd_name is referenced later, so it should not be in temp memory
|
||||
// if function is NULL, the command will be forwarded to the server
|
||||
// as a clc_stringcmd instead of executed locally
|
||||
void Cmd_RemoveCommand (char *cmd_name);
|
||||
|
||||
qboolean Cmd_Exists (char *cmd_name);
|
||||
// used by the cvar code to check for cvar / command name overlap
|
||||
|
||||
char *Cmd_CompleteCommand (char *partial);
|
||||
// attempts to match a partial command for automatic command line completion
|
||||
// returns NULL if nothing fits
|
||||
|
||||
int Cmd_Argc (void);
|
||||
char *Cmd_Argv (int arg);
|
||||
char *Cmd_Args (void);
|
||||
// The functions that execute commands get their parameters with these
|
||||
// functions. Cmd_Argv () will return an empty string, not a NULL
|
||||
// if arg > argc, so string operations are always safe.
|
||||
|
||||
void Cmd_TokenizeString (char *text, qboolean macroExpand);
|
||||
// Takes a null terminated string. Does not need to be /n terminated.
|
||||
// breaks the string up into arg tokens.
|
||||
|
||||
void Cmd_ExecuteString (char *text);
|
||||
// Parses a single line of text into arguments and tries to execute it
|
||||
// as if it was typed at the console
|
||||
|
||||
void Cmd_ForwardToServer (void);
|
||||
// adds the current command line as a clc_stringcmd to the client message.
|
||||
// things like godmode, noclip, etc, are commands directed to the server,
|
||||
// so when they are typed in at the console, they will need to be forwarded.
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
CVAR
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
cvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly
|
||||
in C code.
|
||||
|
||||
The user can access cvars from the console in three ways:
|
||||
r_draworder prints the current value
|
||||
r_draworder 0 sets the current value to 0
|
||||
set r_draworder 0 as above, but creates the cvar if not present
|
||||
Cvars are restricted from having the same names as commands to keep this
|
||||
interface from being ambiguous.
|
||||
*/
|
||||
|
||||
extern cvar_t *cvar_vars;
|
||||
|
||||
cvar_t *Cvar_Get (char *var_name, char *value, int flags);
|
||||
// creates the variable if it doesn't exist, or returns the existing one
|
||||
// if it exists, the value will not be changed, but flags will be ORed in
|
||||
// that allows variables to be unarchived without needing bitflags
|
||||
|
||||
cvar_t *Cvar_Set (char *var_name, char *value);
|
||||
// will create the variable if it doesn't exist
|
||||
|
||||
cvar_t *Cvar_ForceSet (char *var_name, char *value);
|
||||
// will set the variable even if NOSET or LATCH
|
||||
|
||||
cvar_t *Cvar_FullSet (char *var_name, char *value, int flags);
|
||||
|
||||
void Cvar_SetValue (char *var_name, float value);
|
||||
// expands value to a string and calls Cvar_Set
|
||||
|
||||
float Cvar_VariableValue (char *var_name);
|
||||
// returns 0 if not defined or non numeric
|
||||
|
||||
char *Cvar_VariableString (char *var_name);
|
||||
// returns an empty string if not defined
|
||||
|
||||
char *Cvar_CompleteVariable (char *partial);
|
||||
// attempts to match a partial variable name for command line completion
|
||||
// returns NULL if nothing fits
|
||||
|
||||
void Cvar_GetLatchedVars (void);
|
||||
// any CVAR_LATCHED variables that have been set will now take effect
|
||||
|
||||
qboolean Cvar_Command (void);
|
||||
// called by Cmd_ExecuteString when Cmd_Argv(0) doesn't match a known
|
||||
// command. Returns true if the command was a variable reference that
|
||||
// was handled. (print or change)
|
||||
|
||||
void Cvar_WriteVariables (char *path);
|
||||
// appends lines containing "set variable value" for all variables
|
||||
// with the archive flag set to true.
|
||||
|
||||
void Cvar_Init (void);
|
||||
|
||||
char *Cvar_Userinfo (void);
|
||||
// returns an info string containing all the CVAR_USERINFO cvars
|
||||
|
||||
char *Cvar_Serverinfo (void);
|
||||
// returns an info string containing all the CVAR_SERVERINFO cvars
|
||||
|
||||
extern qboolean userinfo_modified;
|
||||
// this is set each time a CVAR_USERINFO variable is changed
|
||||
// so that the client knows to send it to the server
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
NET
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
// net.h -- quake's interface to the networking layer
|
||||
|
||||
#define PORT_ANY -1
|
||||
|
||||
#define MAX_MSGLEN 1400 // max length of a message
|
||||
#define PACKET_HEADER 10 // two ints and a short
|
||||
|
||||
typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t;
|
||||
|
||||
typedef enum {NS_CLIENT, NS_SERVER} netsrc_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
netadrtype_t type;
|
||||
|
||||
byte ip[4];
|
||||
byte ipx[10];
|
||||
|
||||
unsigned short port;
|
||||
} netadr_t;
|
||||
|
||||
void NET_Init (void);
|
||||
void NET_Shutdown (void);
|
||||
|
||||
void NET_Config (qboolean multiplayer);
|
||||
|
||||
qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message);
|
||||
void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to);
|
||||
|
||||
qboolean NET_CompareAdr (netadr_t a, netadr_t b);
|
||||
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b);
|
||||
qboolean NET_IsLocalAddress (netadr_t adr);
|
||||
char *NET_AdrToString (netadr_t a);
|
||||
qboolean NET_StringToAdr (char *s, netadr_t *a);
|
||||
void NET_Sleep(int msec);
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define OLD_AVG 0.99 // total = oldtotal*OLD_AVG + new*(1-OLD_AVG)
|
||||
|
||||
#define MAX_LATENT 32
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean fatal_error;
|
||||
|
||||
netsrc_t sock;
|
||||
|
||||
int dropped; // between last packet and previous
|
||||
|
||||
int last_received; // for timeouts
|
||||
int last_sent; // for retransmits
|
||||
|
||||
netadr_t remote_address;
|
||||
int qport; // qport value to write when transmitting
|
||||
|
||||
// sequencing variables
|
||||
int incoming_sequence;
|
||||
int incoming_acknowledged;
|
||||
int incoming_reliable_acknowledged; // single bit
|
||||
|
||||
int incoming_reliable_sequence; // single bit, maintained local
|
||||
|
||||
int outgoing_sequence;
|
||||
int reliable_sequence; // single bit
|
||||
int last_reliable_sequence; // sequence number of last send
|
||||
|
||||
// reliable staging and holding areas
|
||||
sizebuf_t message; // writing buffer to send to server
|
||||
byte message_buf[MAX_MSGLEN-16]; // leave space for header
|
||||
|
||||
// message is copied to this buffer when it is first transfered
|
||||
int reliable_length;
|
||||
byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message
|
||||
} netchan_t;
|
||||
|
||||
extern netadr_t net_from;
|
||||
extern sizebuf_t net_message;
|
||||
extern byte net_message_buffer[MAX_MSGLEN];
|
||||
|
||||
|
||||
void Netchan_Init (void);
|
||||
void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport);
|
||||
|
||||
qboolean Netchan_NeedReliable (netchan_t *chan);
|
||||
void Netchan_Transmit (netchan_t *chan, int length, byte *data);
|
||||
void Netchan_OutOfBand (int net_socket, netadr_t adr, int length, byte *data);
|
||||
void Netchan_OutOfBandPrint (int net_socket, netadr_t adr, char *format, ...);
|
||||
qboolean Netchan_Process (netchan_t *chan, sizebuf_t *msg);
|
||||
|
||||
qboolean Netchan_CanReliable (netchan_t *chan);
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
CMODEL
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
|
||||
#include "../qcommon/qfiles.h"
|
||||
|
||||
cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum);
|
||||
cmodel_t *CM_InlineModel (char *name); // *1, *2, etc
|
||||
|
||||
int CM_NumClusters (void);
|
||||
int CM_NumInlineModels (void);
|
||||
char *CM_EntityString (void);
|
||||
|
||||
// creates a clipping hull for an arbitrary box
|
||||
int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs);
|
||||
|
||||
|
||||
// returns an ORed contents mask
|
||||
int CM_PointContents (vec3_t p, int headnode);
|
||||
int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles);
|
||||
|
||||
trace_t CM_BoxTrace (vec3_t start, vec3_t end,
|
||||
vec3_t mins, vec3_t maxs,
|
||||
int headnode, int brushmask);
|
||||
trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end,
|
||||
vec3_t mins, vec3_t maxs,
|
||||
int headnode, int brushmask,
|
||||
vec3_t origin, vec3_t angles);
|
||||
|
||||
byte *CM_ClusterPVS (int cluster);
|
||||
byte *CM_ClusterPHS (int cluster);
|
||||
|
||||
int CM_PointLeafnum (vec3_t p);
|
||||
|
||||
// call with topnode set to the headnode, returns with topnode
|
||||
// set to the first node that splits the box
|
||||
int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list,
|
||||
int listsize, int *topnode);
|
||||
|
||||
int CM_LeafContents (int leafnum);
|
||||
int CM_LeafCluster (int leafnum);
|
||||
int CM_LeafArea (int leafnum);
|
||||
|
||||
void CM_SetAreaPortalState (int portalnum, qboolean open);
|
||||
qboolean CM_AreasConnected (int area1, int area2);
|
||||
|
||||
int CM_WriteAreaBits (byte *buffer, int area);
|
||||
qboolean CM_HeadnodeVisible (int headnode, byte *visbits);
|
||||
|
||||
void CM_WritePortalState (FILE *f);
|
||||
void CM_ReadPortalState (FILE *f);
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
PLAYER MOVEMENT CODE
|
||||
|
||||
Common between server and client so prediction matches
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
extern float pm_airaccelerate;
|
||||
|
||||
void Pmove (pmove_t *pmove);
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
FILESYSTEM
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
void FS_InitFilesystem (void);
|
||||
void FS_SetGamedir (char *dir);
|
||||
char *FS_Gamedir (void);
|
||||
char *FS_NextPath (char *prevpath);
|
||||
void FS_ExecAutoexec (void);
|
||||
|
||||
int FS_FOpenFile (char *filename, FILE **file);
|
||||
void FS_FCloseFile (FILE *f);
|
||||
// note: this can't be called from another DLL, due to MS libc issues
|
||||
|
||||
int FS_LoadFile (char *path, void **buffer);
|
||||
// a null buffer will just return the file length without loading
|
||||
// a -1 length is not present
|
||||
|
||||
void FS_Read (void *buffer, int len, FILE *f);
|
||||
// properly handles partial reads
|
||||
|
||||
void FS_FreeFile (void *buffer);
|
||||
|
||||
void FS_CreatePath (char *path);
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
MISC
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
|
||||
#define ERR_FATAL 0 // exit the entire game with a popup window
|
||||
#define ERR_DROP 1 // print to console and disconnect from game
|
||||
#define ERR_QUIT 2 // not an error, just a normal exit
|
||||
|
||||
#define EXEC_NOW 0 // don't return until completed
|
||||
#define EXEC_INSERT 1 // insert at current position, but don't run yet
|
||||
#define EXEC_APPEND 2 // add to end of the command buffer
|
||||
|
||||
#define PRINT_ALL 0
|
||||
#define PRINT_DEVELOPER 1 // only print when "developer 1"
|
||||
|
||||
void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush));
|
||||
void Com_EndRedirect (void);
|
||||
void Com_Printf (char *fmt, ...);
|
||||
void Com_DPrintf (char *fmt, ...);
|
||||
void Com_Error (int code, char *fmt, ...);
|
||||
void Com_Quit (void);
|
||||
|
||||
int Com_ServerState (void); // this should have just been a cvar...
|
||||
void Com_SetServerState (int state);
|
||||
|
||||
unsigned Com_BlockChecksum (void *buffer, int length);
|
||||
byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence);
|
||||
|
||||
float frand(void); // 0 ti 1
|
||||
float crand(void); // -1 to 1
|
||||
|
||||
extern cvar_t *developer;
|
||||
extern cvar_t *dedicated;
|
||||
extern cvar_t *host_speeds;
|
||||
extern cvar_t *log_stats;
|
||||
|
||||
extern FILE *log_stats_file;
|
||||
|
||||
// host_speeds times
|
||||
extern int time_before_game;
|
||||
extern int time_after_game;
|
||||
extern int time_before_ref;
|
||||
extern int time_after_ref;
|
||||
|
||||
void Z_Free (void *ptr);
|
||||
void *Z_Malloc (int size); // returns 0 filled memory
|
||||
void *Z_TagMalloc (int size, int tag);
|
||||
void Z_FreeTags (int tag);
|
||||
|
||||
void Qcommon_Init (int argc, char **argv);
|
||||
void Qcommon_Frame (int msec);
|
||||
void Qcommon_Shutdown (void);
|
||||
|
||||
#define NUMVERTEXNORMALS 162
|
||||
extern vec3_t bytedirs[NUMVERTEXNORMALS];
|
||||
|
||||
// this is in the client code, but can be used for debugging from server
|
||||
void SCR_DebugGraph (float value, int color);
|
||||
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
NON-PORTABLE SYSTEM SERVICES
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
void Sys_Init (void);
|
||||
|
||||
void Sys_AppActivate (void);
|
||||
|
||||
void Sys_UnloadGame (void);
|
||||
void *Sys_GetGameAPI (void *parms);
|
||||
// loads the game dll and calls the api init function
|
||||
|
||||
char *Sys_ConsoleInput (void);
|
||||
void Sys_ConsoleOutput (char *string);
|
||||
void Sys_SendKeyEvents (void);
|
||||
void Sys_Error (char *error, ...);
|
||||
void Sys_Quit (void);
|
||||
char *Sys_GetClipboardData( void );
|
||||
void Sys_CopyProtect (void);
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
CLIENT / SERVER SYSTEMS
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
|
||||
void CL_Init (void);
|
||||
void CL_Drop (void);
|
||||
void CL_Shutdown (void);
|
||||
void CL_Frame (int msec);
|
||||
void Con_Print (char *text);
|
||||
void SCR_BeginLoadingPlaque (void);
|
||||
|
||||
void SV_Init (void);
|
||||
void SV_Shutdown (char *finalmsg, qboolean reconnect);
|
||||
void SV_Frame (int msec);
|
||||
|
||||
|
||||
|
482
qcommon/qfiles.h
Normal file
482
qcommon/qfiles.h
Normal file
@ -0,0 +1,482 @@
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
//
|
||||
// qfiles.h: quake file formats
|
||||
// This file must be identical in the quake and utils directories
|
||||
//
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
The .pak files are just a linear collapse of a directory tree
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P')
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[56];
|
||||
int filepos, filelen;
|
||||
} dpackfile_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident; // == IDPAKHEADER
|
||||
int dirofs;
|
||||
int dirlen;
|
||||
} dpackheader_t;
|
||||
|
||||
#define MAX_FILES_IN_PACK 4096
|
||||
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
PCX files are used for as many images as possible
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char manufacturer;
|
||||
char version;
|
||||
char encoding;
|
||||
char bits_per_pixel;
|
||||
unsigned short xmin,ymin,xmax,ymax;
|
||||
unsigned short hres,vres;
|
||||
unsigned char palette[48];
|
||||
char reserved;
|
||||
char color_planes;
|
||||
unsigned short bytes_per_line;
|
||||
unsigned short palette_type;
|
||||
char filler[58];
|
||||
unsigned char data; // unbounded
|
||||
} pcx_t;
|
||||
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
.MD2 triangle model file format
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I')
|
||||
#define ALIAS_VERSION 8
|
||||
|
||||
#define MAX_TRIANGLES 4096
|
||||
#define MAX_VERTS 2048
|
||||
#define MAX_FRAMES 512
|
||||
#define MAX_MD2SKINS 32
|
||||
#define MAX_SKINNAME 64
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short s;
|
||||
short t;
|
||||
} dstvert_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
short index_xyz[3];
|
||||
short index_st[3];
|
||||
} dtriangle_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
byte v[3]; // scaled byte to fit in frame mins/maxs
|
||||
byte lightnormalindex;
|
||||
} dtrivertx_t;
|
||||
|
||||
#define DTRIVERTX_V0 0
|
||||
#define DTRIVERTX_V1 1
|
||||
#define DTRIVERTX_V2 2
|
||||
#define DTRIVERTX_LNI 3
|
||||
#define DTRIVERTX_SIZE 4
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float scale[3]; // multiply byte verts by this
|
||||
float translate[3]; // then add this
|
||||
char name[16]; // frame name from grabbing
|
||||
dtrivertx_t verts[1]; // variable sized
|
||||
} daliasframe_t;
|
||||
|
||||
|
||||
// the glcmd format:
|
||||
// a positive integer starts a tristrip command, followed by that many
|
||||
// vertex structures.
|
||||
// a negative integer starts a trifan command, followed by -x vertexes
|
||||
// a zero indicates the end of the command list.
|
||||
// a vertex consists of a floating point s, a floating point t,
|
||||
// and an integer vertex index.
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident;
|
||||
int version;
|
||||
|
||||
int skinwidth;
|
||||
int skinheight;
|
||||
int framesize; // byte size of each frame
|
||||
|
||||
int num_skins;
|
||||
int num_xyz;
|
||||
int num_st; // greater than num_xyz for seams
|
||||
int num_tris;
|
||||
int num_glcmds; // dwords in strip/fan command list
|
||||
int num_frames;
|
||||
|
||||
int ofs_skins; // each skin is a MAX_SKINNAME string
|
||||
int ofs_st; // byte offset from start for stverts
|
||||
int ofs_tris; // offset for dtriangles
|
||||
int ofs_frames; // offset for first frame
|
||||
int ofs_glcmds;
|
||||
int ofs_end; // end of file
|
||||
|
||||
} dmdl_t;
|
||||
|
||||
/*
|
||||
========================================================================
|
||||
|
||||
.SP2 sprite file format
|
||||
|
||||
========================================================================
|
||||
*/
|
||||
|
||||
#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I')
|
||||
// little-endian "IDS2"
|
||||
#define SPRITE_VERSION 2
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int width, height;
|
||||
int origin_x, origin_y; // raster coordinates inside pic
|
||||
char name[MAX_SKINNAME]; // name of pcx file
|
||||
} dsprframe_t;
|
||||
|
||||
typedef struct {
|
||||
int ident;
|
||||
int version;
|
||||
int numframes;
|
||||
dsprframe_t frames[1]; // variable sized
|
||||
} dsprite_t;
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
.WAL texture file format
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
|
||||
#define MIPLEVELS 4
|
||||
typedef struct miptex_s
|
||||
{
|
||||
char name[32];
|
||||
unsigned width, height;
|
||||
unsigned offsets[MIPLEVELS]; // four mip maps stored
|
||||
char animname[32]; // next frame in animation chain
|
||||
int flags;
|
||||
int contents;
|
||||
int value;
|
||||
} miptex_t;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
.BSP file format
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I')
|
||||
// little-endian "IBSP"
|
||||
|
||||
#define BSPVERSION 38
|
||||
|
||||
|
||||
// upper design bounds
|
||||
// leaffaces, leafbrushes, planes, and verts are still bounded by
|
||||
// 16 bit short limits
|
||||
#define MAX_MAP_MODELS 1024
|
||||
#define MAX_MAP_BRUSHES 8192
|
||||
#define MAX_MAP_ENTITIES 2048
|
||||
#define MAX_MAP_ENTSTRING 0x40000
|
||||
#define MAX_MAP_TEXINFO 8192
|
||||
|
||||
#define MAX_MAP_AREAS 256
|
||||
#define MAX_MAP_AREAPORTALS 1024
|
||||
#define MAX_MAP_PLANES 65536
|
||||
#define MAX_MAP_NODES 65536
|
||||
#define MAX_MAP_BRUSHSIDES 65536
|
||||
#define MAX_MAP_LEAFS 65536
|
||||
#define MAX_MAP_VERTS 65536
|
||||
#define MAX_MAP_FACES 65536
|
||||
#define MAX_MAP_LEAFFACES 65536
|
||||
#define MAX_MAP_LEAFBRUSHES 65536
|
||||
#define MAX_MAP_PORTALS 65536
|
||||
#define MAX_MAP_EDGES 128000
|
||||
#define MAX_MAP_SURFEDGES 256000
|
||||
#define MAX_MAP_LIGHTING 0x200000
|
||||
#define MAX_MAP_VISIBILITY 0x100000
|
||||
|
||||
// key / value pair sizes
|
||||
|
||||
#define MAX_KEY 32
|
||||
#define MAX_VALUE 1024
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int fileofs, filelen;
|
||||
} lump_t;
|
||||
|
||||
#define LUMP_ENTITIES 0
|
||||
#define LUMP_PLANES 1
|
||||
#define LUMP_VERTEXES 2
|
||||
#define LUMP_VISIBILITY 3
|
||||
#define LUMP_NODES 4
|
||||
#define LUMP_TEXINFO 5
|
||||
#define LUMP_FACES 6
|
||||
#define LUMP_LIGHTING 7
|
||||
#define LUMP_LEAFS 8
|
||||
#define LUMP_LEAFFACES 9
|
||||
#define LUMP_LEAFBRUSHES 10
|
||||
#define LUMP_EDGES 11
|
||||
#define LUMP_SURFEDGES 12
|
||||
#define LUMP_MODELS 13
|
||||
#define LUMP_BRUSHES 14
|
||||
#define LUMP_BRUSHSIDES 15
|
||||
#define LUMP_POP 16
|
||||
#define LUMP_AREAS 17
|
||||
#define LUMP_AREAPORTALS 18
|
||||
#define HEADER_LUMPS 19
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int ident;
|
||||
int version;
|
||||
lump_t lumps[HEADER_LUMPS];
|
||||
} dheader_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float mins[3], maxs[3];
|
||||
float origin[3]; // for sounds or lights
|
||||
int headnode;
|
||||
int firstface, numfaces; // submodels just draw faces
|
||||
// without walking the bsp tree
|
||||
} dmodel_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float point[3];
|
||||
} dvertex_t;
|
||||
|
||||
|
||||
// 0-2 are axial planes
|
||||
#define PLANE_X 0
|
||||
#define PLANE_Y 1
|
||||
#define PLANE_Z 2
|
||||
|
||||
// 3-5 are non-axial planes snapped to the nearest
|
||||
#define PLANE_ANYX 3
|
||||
#define PLANE_ANYY 4
|
||||
#define PLANE_ANYZ 5
|
||||
|
||||
// planes (x&~1) and (x&~1)+1 are always opposites
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float normal[3];
|
||||
float dist;
|
||||
int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate
|
||||
} dplane_t;
|
||||
|
||||
|
||||
// contents flags are seperate bits
|
||||
// a given brush can contribute multiple content bits
|
||||
// multiple brushes can be in a single leaf
|
||||
|
||||
// these definitions also need to be in q_shared.h!
|
||||
|
||||
// lower bits are stronger, and will eat weaker brushes completely
|
||||
#define CONTENTS_SOLID 1 // an eye is never valid in a solid
|
||||
#define CONTENTS_WINDOW 2 // translucent, but not watery
|
||||
#define CONTENTS_AUX 4
|
||||
#define CONTENTS_LAVA 8
|
||||
#define CONTENTS_SLIME 16
|
||||
#define CONTENTS_WATER 32
|
||||
#define CONTENTS_MIST 64
|
||||
#define LAST_VISIBLE_CONTENTS 64
|
||||
|
||||
// remaining contents are non-visible, and don't eat brushes
|
||||
|
||||
#define CONTENTS_AREAPORTAL 0x8000
|
||||
|
||||
#define CONTENTS_PLAYERCLIP 0x10000
|
||||
#define CONTENTS_MONSTERCLIP 0x20000
|
||||
|
||||
// currents can be added to any other contents, and may be mixed
|
||||
#define CONTENTS_CURRENT_0 0x40000
|
||||
#define CONTENTS_CURRENT_90 0x80000
|
||||
#define CONTENTS_CURRENT_180 0x100000
|
||||
#define CONTENTS_CURRENT_270 0x200000
|
||||
#define CONTENTS_CURRENT_UP 0x400000
|
||||
#define CONTENTS_CURRENT_DOWN 0x800000
|
||||
|
||||
#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity
|
||||
|
||||
#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game
|
||||
#define CONTENTS_DEADMONSTER 0x4000000
|
||||
#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs
|
||||
#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans
|
||||
#define CONTENTS_LADDER 0x20000000
|
||||
|
||||
|
||||
|
||||
#define SURF_LIGHT 0x1 // value will hold the light strength
|
||||
|
||||
#define SURF_SLICK 0x2 // effects game physics
|
||||
|
||||
#define SURF_SKY 0x4 // don't draw, but add to skybox
|
||||
#define SURF_WARP 0x8 // turbulent water warp
|
||||
#define SURF_TRANS33 0x10
|
||||
#define SURF_TRANS66 0x20
|
||||
#define SURF_FLOWING 0x40 // scroll towards angle
|
||||
#define SURF_NODRAW 0x80 // don't bother referencing the texture
|
||||
|
||||
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int planenum;
|
||||
int children[2]; // negative numbers are -(leafs+1), not nodes
|
||||
short mins[3]; // for frustom culling
|
||||
short maxs[3];
|
||||
unsigned short firstface;
|
||||
unsigned short numfaces; // counting both sides
|
||||
} dnode_t;
|
||||
|
||||
|
||||
typedef struct texinfo_s
|
||||
{
|
||||
float vecs[2][4]; // [s/t][xyz offset]
|
||||
int flags; // miptex flags + overrides
|
||||
int value; // light emission, etc
|
||||
char texture[32]; // texture name (textures/*.wal)
|
||||
int nexttexinfo; // for animations, -1 = end of chain
|
||||
} texinfo_t;
|
||||
|
||||
|
||||
// note that edge 0 is never used, because negative edge nums are used for
|
||||
// counterclockwise use of the edge in a face
|
||||
typedef struct
|
||||
{
|
||||
unsigned short v[2]; // vertex numbers
|
||||
} dedge_t;
|
||||
|
||||
#define MAXLIGHTMAPS 4
|
||||
typedef struct
|
||||
{
|
||||
unsigned short planenum;
|
||||
short side;
|
||||
|
||||
int firstedge; // we must support > 64k edges
|
||||
short numedges;
|
||||
short texinfo;
|
||||
|
||||
// lighting info
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
int lightofs; // start of [numstyles*surfsize] samples
|
||||
} dface_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int contents; // OR of all brushes (not needed?)
|
||||
|
||||
short cluster;
|
||||
short area;
|
||||
|
||||
short mins[3]; // for frustum culling
|
||||
short maxs[3];
|
||||
|
||||
unsigned short firstleafface;
|
||||
unsigned short numleaffaces;
|
||||
|
||||
unsigned short firstleafbrush;
|
||||
unsigned short numleafbrushes;
|
||||
} dleaf_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short planenum; // facing out of the leaf
|
||||
short texinfo;
|
||||
} dbrushside_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int firstside;
|
||||
int numsides;
|
||||
int contents;
|
||||
} dbrush_t;
|
||||
|
||||
#define ANGLE_UP -1
|
||||
#define ANGLE_DOWN -2
|
||||
|
||||
|
||||
// the visibility lump consists of a header with a count, then
|
||||
// byte offsets for the PVS and PHS of each cluster, then the raw
|
||||
// compressed bit vectors
|
||||
#define DVIS_PVS 0
|
||||
#define DVIS_PHS 1
|
||||
typedef struct
|
||||
{
|
||||
int numclusters;
|
||||
int bitofs[8][2]; // bitofs[numclusters][2]
|
||||
} dvis_t;
|
||||
|
||||
// each area has a list of portals that lead into other areas
|
||||
// when portals are closed, other areas may not be visible or
|
||||
// hearable even if the vis info says that it should be
|
||||
typedef struct
|
||||
{
|
||||
int portalnum;
|
||||
int otherarea;
|
||||
} dareaportal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numareaportals;
|
||||
int firstareaportal;
|
||||
} darea_t;
|
Reference in New Issue
Block a user