From 0561ac207627815a8ae9c384a6367fdcbd67b48f Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 1 Jun 2018 21:28:25 +0300 Subject: [PATCH] Add basecmd from old engine. Add basecmd_stats command --- contib/a1batross/xash3d.files | 2 + engine/client/cl_main.c | 2 + engine/common/base_cmd.c | 229 ++++++++++++++++++++++++++++++++++ engine/common/base_cmd.h | 58 +++++++++ engine/common/cmd.c | 46 ++++++- engine/common/cvar.c | 10 +- engine/common/cvar.h | 2 +- engine/common/host.c | 3 + 8 files changed, 343 insertions(+), 9 deletions(-) create mode 100644 engine/common/base_cmd.c create mode 100644 engine/common/base_cmd.h diff --git a/contib/a1batross/xash3d.files b/contib/a1batross/xash3d.files index 17423cc6..97887702 100644 --- a/contib/a1batross/xash3d.files +++ b/contib/a1batross/xash3d.files @@ -108,6 +108,8 @@ engine/client/vgui/vgui_draw.h engine/client/vid_common.c engine/client/vid_common.h engine/client/vox.h +engine/common/base_cmd.c +engine/common/base_cmd.h engine/common/build.c engine/common/cfgscript.c engine/common/cmd.c diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index c3a60036..8aec7a72 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -83,6 +83,8 @@ client_t cl; client_static_t cls; clgame_static_t clgame; +void CL_InternetServers_f( void ); + //====================================================================== int CL_Active( void ) { diff --git a/engine/common/base_cmd.c b/engine/common/base_cmd.c new file mode 100644 index 00000000..3aae5093 --- /dev/null +++ b/engine/common/base_cmd.c @@ -0,0 +1,229 @@ +/* +base_cmd.c - command & cvar hashmap. Insipred by Doom III +Copyright (C) 2016 a1batross + +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 3 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. +*/ + +#include "common.h" +#include "base_cmd.h" + +// TODO: use another hash function, as COM_HashKey depends on string length +#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes +static base_command_hashmap_t *hashed_cmds[HASH_SIZE]; + +/* +============ +BaseCmd_FindInBucket + +Find base command in bucket +============ +*/ +base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name ) +{ + base_command_hashmap_t *i = bucket; + for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out + i = i->next ); + + return i; +} + +/* +============ +BaseCmd_GetBucket + +Get bucket which contain basecmd by given name +============ +*/ +base_command_hashmap_t *BaseCmd_GetBucket( const char *name ) +{ + return hashed_cmds[ COM_HashKey( name, HASH_SIZE ) ]; +} + +/* +============ +BaseCmd_Find + +Find base command in hashmap +============ +*/ +base_command_t *BaseCmd_Find( base_command_type_e type, const char *name ) +{ + base_command_hashmap_t *base = BaseCmd_GetBucket( name ); + base_command_hashmap_t *found = BaseCmd_FindInBucket( base, type, name ); + + if( found ) + return found->basecmd; + return NULL; +} + +/* +============ +BaseCmd_Find + +Find every type of base command and write into arguments +============ +*/ +void BaseCmd_FindAll(const char *name, base_command_t **cmd, base_command_t **alias, base_command_t **cvar) +{ + base_command_hashmap_t *base = BaseCmd_GetBucket( name ); + base_command_hashmap_t *i = base; + + ASSERT( cmd && alias && cvar ); + + *cmd = *alias = *cvar = NULL; + + for( ; i; i = i->next ) + { + if( !Q_stricmp( i->name, name ) ) + { + switch( i->type ) + { + case HM_CMD: + *cmd = i->basecmd; + break; + case HM_CMDALIAS: + *alias = i->basecmd; + break; + case HM_CVAR: + *cvar = i->basecmd; + break; + default: break; + } + } + } + +} + +/* +============ +BaseCmd_Insert + +Add new typed base command to hashmap +============ +*/ +void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const char *name ) +{ + uint hash = COM_HashKey( name, HASH_SIZE ); + base_command_hashmap_t *elem; + + elem = Z_Malloc( sizeof( base_command_hashmap_t ) ); + elem->basecmd = basecmd; + elem->type = type; + elem->name = name; + elem->next = hashed_cmds[hash]; + hashed_cmds[hash] = elem; +} + +/* +============ +BaseCmd_Replace + +Used in case, when basecmd has been registered, but gamedll wants to register it's own +============ +*/ +qboolean BaseCmd_Replace( base_command_type_e type, base_command_t *basecmd, const char *name ) +{ + base_command_hashmap_t *i = BaseCmd_GetBucket( name ); + + for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ) ; // filter out + i = i->next ); + + if( !i ) + { + MsgDev( D_ERROR, "BaseCmd_Replace: couldn't find %s\n", name); + return false; + } + + i->basecmd = basecmd; + i->name = name; // may be freed after + + return true; +} + +/* +============ +BaseCmd_Remove + +Remove base command from hashmap +============ +*/ +void BaseCmd_Remove( base_command_type_e type, const char *name ) +{ + uint hash = COM_HashKey( name, HASH_SIZE ); + base_command_hashmap_t *i, *prev; + + for( prev = NULL, i = hashed_cmds[hash]; i && + ( Q_strcmp( i->name, name ) || i->type != type); // filter out + prev = i, i = i->next ); + + if( !i ) + { + MsgDev( D_ERROR, "Couldn't find %s in buckets\n", name ); + return; + } + + if( prev ) + prev->next = i->next; + else + hashed_cmds[hash] = i->next; + + Z_Free( i ); +} + +/* +============ +BaseCmd_Init + +initialize base command hashmap system +============ +*/ +void BaseCmd_Init( void ) +{ + memset( hashed_cmds, 0, sizeof( hashed_cmds ) ); +} + +/* +============ +BaseCmd_Stats_f + +============ +*/ +void BaseCmd_Stats_f( void ) +{ + int i, minsize = 99999, maxsize = -1, empty = 0; + + for( i = 0; i < HASH_SIZE; i++ ) + { + base_command_hashmap_t *hm; + int len = 0; + + // count bucket length + for( hm = hashed_cmds[i]; hm; hm = hm->next, len++ ); + + if( len == 0 ) + { + empty++; + continue; + } + + if( len < minsize ) + minsize = len; + + if( len > maxsize ) + maxsize = len; + } + + Con_Printf( "Base command stats:\n"); + Con_Printf( "Bucket minimal length: %d\n", minsize ); + Con_Printf( "Bucket maximum length: %d\n", maxsize ); + Con_Printf( "Empty buckets: %d\n", empty ); +} diff --git a/engine/common/base_cmd.h b/engine/common/base_cmd.h new file mode 100644 index 00000000..9d07886c --- /dev/null +++ b/engine/common/base_cmd.h @@ -0,0 +1,58 @@ +/* +base_cmd.h - command & cvar hashmap. Insipred by Doom III +Copyright (C) 2016 a1batross + +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 3 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. +*/ + +#pragma once +#ifndef BASE_CMD_H +#define BASE_CMD_H + +// TODO: Find cases when command hashmap works incorrect +// and maybe disable it +#define XASH_HASHED_VARS + +#ifdef XASH_HASHED_VARS + +typedef enum base_command_type +{ + HM_DONTCARE = 0, + HM_CVAR, + HM_CMD, + HM_CMDALIAS +} base_command_type_e; + +typedef void base_command_t; + +typedef struct base_command_hashmap_s +{ + base_command_t *basecmd; // base command: cvar, alias or command + const char *name; // key for searching + base_command_type_e type; // type for faster searching + struct base_command_hashmap_s *next; +} base_command_hashmap_t; + + +void BaseCmd_Init( void ); +base_command_hashmap_t *BaseCmd_GetBucket( const char *name ); +base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name ); +base_command_t *BaseCmd_Find( base_command_type_e type, const char *name ); +void BaseCmd_FindAll( const char *name, + base_command_t **cmd, base_command_t **alias, base_command_t **cvar ); +void BaseCmd_Insert ( base_command_type_e type, base_command_t *basecmd, const char *name ); +qboolean BaseCmd_Replace( base_command_type_e type, base_command_t *basecmd, const char *name ); // only if same name +void BaseCmd_Remove ( base_command_type_e type, const char *name ); +void BaseCmd_Stats_f( void ); // to be registered later + +#endif // XASH_HASHED_VARS + +#endif // BASE_CMD_H diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 60cd99b1..f838fdf1 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -16,6 +16,7 @@ GNU General Public License for more details. #include "common.h" #include "client.h" #include "server.h" +#include "base_cmd.h" #define MAX_CMD_BUFFER 32768 #define MAX_CMD_LINE 2048 @@ -380,6 +381,10 @@ void Cmd_Alias_f( void ) if( prev ) prev->next = a; else cmd_alias = a; a->next = cur; + +#if defined( XASH_HASHED_VARS ) + BaseCmd_Insert( HM_CMDALIAS, a, a->name ); +#endif } // copy the rest of the command line @@ -425,6 +430,9 @@ static void Cmd_UnAlias_f ( void ) { if( !Q_strcmp( s, a->name )) { +#if defined( XASH_HASHED_VARS ) + BaseCmd_Remove( HM_CMDALIAS, a->name ); +#endif if( a == cmd_alias ) cmd_alias = a->next; if( p ) p->next = a->next; @@ -722,6 +730,10 @@ void Cmd_RemoveCommand( const char *cmd_name ) if( !Q_strcmp( cmd_name, cmd->name )) { +#if defined(XASH_HASHED_VARS) + BaseCmd_Remove( HM_CMD, cmd->name ); +#endif + *back = cmd->next; if( cmd->name ) @@ -768,6 +780,9 @@ Cmd_Exists */ qboolean Cmd_Exists( const char *cmd_name ) { +#if defined(XASH_HASHED_VARS) + return BaseCmd_Find( HM_CMD, cmd_name ) != NULL; +#else cmd_t *cmd; for( cmd = cmd_functions; cmd; cmd = cmd->next ) @@ -776,6 +791,7 @@ qboolean Cmd_Exists( const char *cmd_name ) return true; } return false; +#endif } /* @@ -860,8 +876,9 @@ A complete command line has been parsed, so try to execute it */ void Cmd_ExecuteString( char *text ) { - cmd_t *cmd; - cmdalias_t *a; + cmd_t *cmd = NULL; + cmdalias_t *a = NULL; + convar_t *cvar = NULL; char command[MAX_CMD_LINE]; char *pcmd = command; int len = 0; @@ -916,9 +933,22 @@ void Cmd_ExecuteString( char *text ) if( !Cmd_Argc( )) return; // no tokens +#if defined(XASH_HASHED_VARS) + BaseCmd_FindAll( cmd_argv[0], + (base_command_t**)&cmd, + (base_command_t**)&a, + (base_command_t**)&cvar ); +#endif + if( !host.apply_game_config ) { // check aliases + if( a ) // already found in basecmd + { + Cbuf_InsertText( a->value ); + return; + } + for( a = cmd_alias; a; a = a->next ) { if( !Q_stricmp( cmd_argv[0], a->name )) @@ -933,6 +963,12 @@ void Cmd_ExecuteString( char *text ) if( !host.apply_game_config || !Q_strcmp( cmd_argv[0], "exec" )) { // check functions + if( cmd && cmd->function ) // already found in basecmd + { + cmd->function(); + return; + } + for( cmd = cmd_functions; cmd; cmd = cmd->next ) { if( !Q_stricmp( cmd_argv[0], cmd->name ) && cmd->function ) @@ -944,7 +980,7 @@ void Cmd_ExecuteString( char *text ) } // check cvars - if( Cvar_Command( )) return; + if( Cvar_Command( cvar )) return; if( host.apply_game_config ) return; // don't send nothing to server: we is a server! @@ -1125,4 +1161,8 @@ void Cmd_Init( void ) Cmd_AddCommand( "unalias", Cmd_UnAlias_f, "remove a script function" ); Cmd_AddCommand( "if", Cmd_If_f, "compare and set condition bits" ); Cmd_AddCommand( "else", Cmd_Else_f, "invert condition bit" ); + +#if defined(XASH_HASHED_VARS) + Cmd_AddCommand( "basecmd_stats", BaseCmd_Stats_f, "print info about basecmd usage" ); +#endif } diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 55932406..15521c10 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -13,8 +13,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ +#include // fabs... #include "common.h" -#include "math.h" // fabs... +#include "base_cmd.h" convar_t *cvar_vars = NULL; // head of list convar_t *cmd_scripting; @@ -690,10 +691,8 @@ Cvar_Command Handles variable inspection and changing from the console ============ */ -qboolean Cvar_Command( void ) +qboolean Cvar_Command( convar_t *v ) { - convar_t *v; - // special case for setup opengl configuration if( host.apply_opengl_config ) { @@ -702,7 +701,8 @@ qboolean Cvar_Command( void ) } // check variables - v = Cvar_FindVar( Cmd_Argv( 0 )); + if( !v ) // already found in basecmd + v = Cvar_FindVar( Cmd_Argv( 0 )); if( !v ) return false; // perform a variable print or set diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 2ee7addf..5d5e5407 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -66,7 +66,7 @@ const char *Cvar_VariableString( const char *var_name ); void Cvar_WriteVariables( file_t *f, int group ); void Cvar_Reset( const char *var_name ); void Cvar_SetCheatState( void ); -qboolean Cvar_Command( void ); +qboolean Cvar_Command( convar_t *v ); void Cvar_Init( void ); void Cvar_Unlink( int group ); diff --git a/engine/common/host.c b/engine/common/host.c index 40987edb..0da0e0ad 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -822,6 +822,9 @@ void Host_InitCommon( int argc, char **argv, const char *progname, qboolean bCha // init host state machine COM_InitHostState(); + // init hashed commands + BaseCmd_Init(); + // startup cmds and cvars subsystem Cmd_Init(); Cvar_Init();