ebfs.txt

来自「quake1 dos源代码最新版本」· 文本 代码 · 共 895 行 · 第 1/3 页

TXT
895
字号
================================================================
Title         : Tutorial: Implementing the Enhanced BuiltIn Function System into the Quake engine
                (including new builtin functions: cmd_find, cvar_find and cvar_string)
Date          : 2001-10-05
Filename      : EBFS.TXT
Author        : Matthias "Maddes" Buecher
Email Address : maddes@go.to
Homepage      : Quake Info Pool
                http://www.quake-info-pool.net/
                Quake Standards Group (short QSG)
                http://www.quakesrc.org/
Complexity    : Moderate
================================================================



Index
=====
Part I   - Purpose and system explanation
Part II  - Implementing EBFS into the Quake engine
Part III - Rules for registering new builtin functions to the QSG list
Part IV  - Four examples of implementing new builtin functions with EBFS
           (builtin functions: cmd_find, cvar_find, cvar_string, WriteFloat)
Part V   - Activating some useful builtin functions of the preliminary Quake 2 code
           (builtin functions: sin, cos, sqrt, etos)



Part I - Purpose and system explanation
=======================================
All QuakeC coders want to have new builtin functions to use in their addons.
The problem is to keep a standard among all the different engine ports.
That is where the Quake Standards Group came in. The QSG keeps a list of all
additional builtin functions, so that every engine uses the same function
numbers.

But how can the QuakeC coder determine during run-time if the engine supports
all the needed new builtin functions?
That's what the Enhanced BuiltIn Function System (short EBFS) is for.

With EBFS the new builtin function "builtin_find" is added to the engine. It
returns the function number of a given function name. The result is zero when
the function does not exist.

As the EBFS function "builtin_find" is a new builtin function too, the above
system doesn't work for it. Hence there is also a new cvar called
"pr_builtin_find" needed which contains the function number of "builtin_find".

Some days after I send the first version of this tutorial to the QSG for
approval, Sander "FireStorm" van Rossen <mv_firestorm@hotmail.com> did a posting
on the QSG forum about remapping builtin functions to the data stored in the
PROGS.DAT.
Testing showed that there can be problems with QuakeC addons which replace
builtin functions with QuakeC functions and redefines the builtin functions
under a different name as the engine can not assign this unknown function. A
good workaround is to assign all unassigned functions to their default number if
possible.
So this "BuiltIn Function Remapping" is an option which is controlled by the
cvar "pr_builtin_remap". It defaults to zero ("off") as QuakeC coders should be
as thoroughly with there code as engine coders (means following the QSG
standards), otherwise they will never notice their mistakes.
When a host error occurs the user is pointed to the "BuiltIn Function
Remapping", so they may be able to play the QuakeC addon.

With EBFS the old builtin array is no more static, it is created from a new
array on the fly when a PROGS.DAT is loaded. The run-time execution of the
PROGS.DAT stays the same, so there are no performance penalties because of the
dynamic way of using the builtin numbers.

You can download this tutorial including "How_to_use_EBFS_in_QuakeC.txt" here. (Bram: place download link here)

Some may point out that Lord Havoc already introduced a similar system to check
for new engine extensions.
The EBFS does not replace his system as it is still useful for various other
engine extensions, but the EBFS simplifies adding new builtin functions to the
engine (no more padding with PF_FixMe), allows to check the actual function
numbers for QuakeC coders and provides a remapping functionality for the user.



Part II  - Implementing EBFS into the Quake engine
==================================================
Adding EBFS to your engine is very easy, even if you did lots of changes to your
own engine.

The new builtin function "builtin_find" and the dynamic number assignment need
additional data, so we need to define a new structure for it.
Go into PROGS.H and after...

typedef void (*builtin_t) (void);
extern builtin_t	*pr_builtins;
extern int			pr_numbuiltins;

... add ...

// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start
typedef struct ebfs_builtin_s
{
	int			default_funcno;
	char		*funcname;
	builtin_t	function;
	int			funcno;
} ebfs_builtin_t;

extern ebfs_builtin_t	pr_ebfs_builtins[];
extern int				pr_ebfs_numbuiltins;

#define PR_DEFAULT_FUNCNO_BUILTIN_FIND	100

extern cvar_t	pr_builtin_find;
extern cvar_t	pr_builtin_remap;

#define PR_DEFAULT_FUNCNO_EXTENSION_FIND	99	// 2001-10-20 Extension System by Lord Havoc/Maddes
// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end

This added the default function number, its name and the assigned number to the
data. The assigned number will be used to build the run-time builtin array for
QuakeC execution, and it is also needed for the return value of "builtin_find".
The name will be used to find a function when searched with "builtin_find" or
when remapping the functions from the PROGS.DAT data.


Now you have to add the EBFS data to PR_CMDS.C. But first completely disable the
pr_builtin[] array at the end of PR_CMDS.C and also remove the assignment of the
two builtin variables. The result looks like this...

// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start
/*
builtin_t pr_builtin[] =
{
PF_Fixme,
PF_makevectors,	// void(entity e)	makevectors 		= #1;
.
.
.
PF_setspawnparms
};
*/
builtin_t *pr_builtins;
int pr_numbuiltins;
// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end

... after this add the new EBFS data...

// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start
// for builtin function definitions see Quake Standards Group at http://www.quakesrc.org/
ebfs_builtin_t pr_ebfs_builtins[] =
{
	{   0, NULL, PF_Fixme },				// has to be first entry as it is needed for initialization in PR_LoadProgs()
	{   1, "makevectors", PF_makevectors },	// void(entity e)	makevectors 		= #1;
	{   2, "setorigin", PF_setorigin },		// void(entity e, vector o) setorigin	= #2;
	{   3, "setmodel", PF_setmodel },		// void(entity e, string m) setmodel	= #3;
	{   4, "setsize", PF_setsize },			// void(entity e, vector min, vector max) setsize = #4;
//	{   5, "fixme", PF_Fixme },				// void(entity e, vector min, vector max) setabssize = #5;
	{   6, "break", PF_break },				// void() break						= #6;
	{   7, "random", PF_random },			// float() random						= #7;
	{   8, "sound", PF_sound },				// void(entity e, float chan, string samp) sound = #8;
	{   9, "normalize", PF_normalize },		// vector(vector v) normalize			= #9;
	{  10, "error", PF_error },				// void(string e) error				= #10;
	{  11, "objerror", PF_objerror },		// void(string e) objerror				= #11;
	{  12, "vlen", PF_vlen },				// float(vector v) vlen				= #12;
	{  13, "vectoyaw", PF_vectoyaw },		// float(vector v) vectoyaw		= #13;
	{  14, "spawn", PF_Spawn },				// entity() spawn						= #14;
	{  15, "remove", PF_Remove },			// void(entity e) remove				= #15;
	{  16, "traceline", PF_traceline },		// float(vector v1, vector v2, float tryents) traceline = #16;
	{  17, "checkclient", PF_checkclient },	// entity() clientlist					= #17;
	{  18, "find", PF_Find },				// entity(entity start, .string fld, string match) find = #18;
	{  19, "precache_sound", PF_precache_sound },	// void(string s) precache_sound		= #19;
	{  20, "precache_model", PF_precache_model },	// void(string s) precache_model		= #20;
	{  21, "stuffcmd", PF_stuffcmd },		// void(entity client, string s)stuffcmd = #21;
	{  22, "findradius", PF_findradius },	// entity(vector org, float rad) findradius = #22;
	{  23, "bprint", PF_bprint },			// void(string s) bprint				= #23;
	{  24, "sprint", PF_sprint },			// void(entity client, string s) sprint = #24;
	{  25, "dprint", PF_dprint },			// void(string s) dprint				= #25;
	{  26, "ftos", PF_ftos },				// void(string s) ftos				= #26;
	{  27, "vtos", PF_vtos },				// void(string s) vtos				= #27;
	{  28, "coredump", PF_coredump },
	{  29, "traceon", PF_traceon },
	{  30, "traceoff", PF_traceoff },
	{  31, "eprint", PF_eprint },			// void(entity e) debug print an entire entity
	{  32, "walkmove", PF_walkmove },		// float(float yaw, float dist) walkmove
//	{  33, "fixme", PF_Fixme },				// float(float yaw, float dist) walkmove
	{  34, "droptofloor", PF_droptofloor },
	{  35, "lightstyle", PF_lightstyle },
	{  36, "rint", PF_rint },
	{  37, "floor", PF_floor },
	{  38, "ceil", PF_ceil },
//	{  39, "fixme", PF_Fixme },
	{  40, "checkbottom", PF_checkbottom },
	{  41, "pointcontents", PF_pointcontents },
//	{  42, "fixme", PF_Fixme },
	{  43, "fabs", PF_fabs },
	{  44, "aim", PF_aim },
	{  45, "cvar", PF_cvar },
	{  46, "localcmd", PF_localcmd },
	{  47, "nextent", PF_nextent },
	{  48, "particle", PF_particle },
	{  49, "ChangeYaw", PF_changeyaw },
//	{  50, "fixme", PF_Fixme },
	{  51, "vectoangles", PF_vectoangles },

	{  52, "WriteByte", PF_WriteByte },
	{  53, "WriteChar", PF_WriteChar },
	{  54, "WriteShort", PF_WriteShort },
	{  55, "WriteLong", PF_WriteLong },
	{  56, "WriteCoord", PF_WriteCoord },
	{  57, "WriteAngle", PF_WriteAngle },
	{  58, "WriteString", PF_WriteString },
	{  59, "WriteEntity", PF_WriteEntity },

#ifdef QUAKE2
	{  60, "sin", PF_sin },
	{  61, "cos", PF_cos },
	{  62, "sqrt", PF_sqrt },
	{  63, "changepitch", PF_changepitch },
	{  64, "TraceToss", PF_TraceToss },
	{  65, "etos", PF_etos },
	{  66, "WaterMove", PF_WaterMove },
#endif

	{  67, "movetogoal", SV_MoveToGoal },
	{  68, "precache_file", PF_precache_file },
	{  69, "makestatic", PF_makestatic },

	{  70, "changelevel", PF_changelevel },
//	{  71, "fixme", PF_Fixme },

	{  72, "cvar_set", PF_cvar_set },
	{  73, "centerprint", PF_centerprint },

	{  74, "ambientsound", PF_ambientsound },

	{  75, "precache_model2", PF_precache_model },
	{  76, "precache_sound2", PF_precache_sound },	// precache_sound2 is different only for qcc
	{  77, "precache_file2", PF_precache_file },

	{  78, "setspawnparms", PF_setspawnparms },

//	{  81, "stof", PF_stof },	// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes

// 2001-11-15 DarkPlaces general builtin functions by Lord Havoc  start
// not implemented yet
/*
	{  90, "tracebox", PF_tracebox },
	{  91, "randomvec", PF_randomvec },
	{  92, "getlight", PF_GetLight },	// not implemented yet
	{  93, "cvar_create", PF_cvar_create },		// 2001-09-18 New BuiltIn Function: cvar_create() by Maddes
	{  94, "fmin", PF_fmin },
	{  95, "fmax", PF_fmax },
	{  96, "fbound", PF_fbound },
	{  97, "fpow", PF_fpow },
	{  98, "findfloat", PF_FindFloat },
	{ PR_DEFAULT_FUNCNO_EXTENSION_FIND, "extension_find", PF_extension_find },	// 2001-10-20 Extension System by Lord Havoc/Maddes
	{   0, "registercvar", PF_cvar_create },		// 0 indicates that this entry is just for remapping (because of name change)
	{   0, "checkextension", PF_extension_find },
*/
// 2001-11-15 DarkPlaces general builtin functions by Lord Havoc  end

	{ PR_DEFAULT_FUNCNO_BUILTIN_FIND, "builtin_find", PF_builtin_find },		// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes

// not implemented yet
/*
	{ 101, "cmd_find", PF_cmd_find },		// 2001-09-16 New BuiltIn Function: cmd_find() by Maddes

	{ 102, "cvar_find", PF_cvar_find },		// 2001-09-16 New BuiltIn Function: cvar_find() by Maddes

	{ 103, "cvar_string", PF_cvar_string },	// 2001-09-16 New BuiltIn Function: cvar_string() by Maddes

	{ 105, "cvar_free", PF_cvar_free },		// 2001-09-18 New BuiltIn Function: cvar_free() by Maddes

	{ 106, "NVS_InitSVCMsg", PF_NVS_InitSVCMsg },	// 2000-05-02 NVS SVC by Maddes

	{ 107, "WriteFloat", PF_WriteFloat },	// 2001-09-16 New BuiltIn Function: WriteFloat() by Maddes

	{ 108, "etof", PF_etof },	// 2001-09-25 New BuiltIn Function: etof() by Maddes

	{ 109, "ftoe", PF_ftoe },	// 2001-09-25 New BuiltIn Function: ftoe() by Maddes
*/

// 2001-09-20 QuakeC file access by FrikaC/Maddes  start
// not implemented yet
/*
	{ 110, "fopen", PF_fopen },
	{ 111, "fclose", PF_fclose },
	{ 112, "fgets", PF_fgets },
	{ 113, "fputs", PF_fputs },
	{   0, "open", PF_fopen },		// 0 indicates that this entry is just for remapping (because of name and number change)
	{   0, "close", PF_fclose },
	{   0, "read", PF_fgets },
	{   0, "write", PF_fputs },
*/
// 2001-09-20 QuakeC file access by FrikaC/Maddes  end

// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes  start
// not implemented yet
/*
	{ 114, "strlen", PF_strlen },
	{ 115, "strcat", PF_strcat },
	{ 116, "substring", PF_substring },

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?