Yet about parsing: may I suggest JSON ? widely used, a de facto industry standard, very similar (but more complete) to the key/value approach you guys are aiming without the XML verbosity/complexity, supported among a great number of languages (including but not limited to C, C++, C#, Java, JavaScript - this one natively-, Perl, Python, etc.), with code to write and parse the format ready to use.taniwha wrote:QF's completion isn't very smart yet. It certainly doesn't complete parameters, and I'm pretty sure it doesn't work after semicolons. It does, however, provide a list of all possible cvars and commands (including aliases?) that match the current "head". Certainly less annoying that id's very basic version.
Re parsing: may I suggest QF's plist code? It's actually quite self-contained (only dependencies are dstrings and hash tables, and all three modules are documented). There are some dependencies on sys (Sys_Printf etc) and mathlib/compat (min/max and strequal), but they're trivial to replace.
Property lists (include/QF/qfplist.h and libs/util/qfplist.c) (format docs)
Hash tables (include/QF/hash.h and libs/util/hash.c)
Dynamic Strings (include/QF/dstring.h and libs/util/dstring.c)
Describing the Quake Command System
-
- Posts: 2126
- Joined: Sat Nov 25, 2006 1:49 pm
Re: Describing the Quake Command System
I know FrikaC made a cgi-bin version of the quakec interpreter once and wrote part of his website in QuakeC (LordHavoc)
Re: Describing the Quake Command System
Threading would work OK in the menus where it would show up as some latency in the info becoming visible rather than causing a hitch, but I suspect that it would be equally as annoying in the console. Press TAB and nothing happens for a short while. Unfortunately the console is the place where autocompletion is really needed, and equally as unfortunately I think that filtering out ammo box/etc models from the maps list is sufficiently important that maps do need to be opened and validated (the fact that the "map" command is the one where autocompletion is of most benefit just makes this suck even more).
So much for on-demand parsing; threading the scan at game change time may be of benefit but disk IO does remain the major bottleneck.
So much for on-demand parsing; threading the scan at game change time may be of benefit but disk IO does remain the major bottleneck.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
Re: Describing the Quake Command System
I know you are in to perfect solutions. What about the opposite of your solution?mh wrote:Threading would work OK in the menus where it would show up as some latency in the info becoming visible rather than causing a hitch, but I suspect that it would be equally as annoying in the console. Press TAB and nothing happens for a short while. Unfortunately the console is the place where autocompletion is really needed, and equally as unfortunately I think that filtering out ammo box/etc models from the maps list is sufficiently important that maps do need to be opened and validated (the fact that the "map" command is the one where autocompletion is of most benefit just makes this suck even more).
So much for on-demand parsing; threading the scan at game change time may be of benefit but disk IO does remain the major bottleneck.
Don't scan the maps. Scan the progs.dat. If the .bsp is in the progs.dat, it isn't really a map. That would scan just 1 file.
Asses kicked, gum chewed ... and be living the good life in problems-minus-one-ville. And if I'm making a mod so I have miscellaneous .bsp models sitting around and I'm being stupid and think I can really get a quality game from playing chair.bsp or healthbox.bsp, that's just a case of the tough-shits since that isn't really an end-user problem ... ya know.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Describing the Quake Command System
Won't work with multiplayer though, where there may be a different progs on a different machine.
Not really bothered about it being a perfect solution; sensible with some imperfections is OK.
Not really bothered about it being a perfect solution; sensible with some imperfections is OK.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
Re: Describing the Quake Command System
The .bsp model problem sucks.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Describing the Quake Command System
if it has a leading b_ then ignore it?
scanning the progs won't work. most list the maps/foo.bsp files within the 'main' function. and those that don't still have the map names hardcoded in the intermission/finale code.
scanning the progs won't work. most list the maps/foo.bsp files within the 'main' function. and those that don't still have the map names hardcoded in the intermission/finale code.
Re: Describing the Quake Command System
A bit of a tangent, but on looking at QF's command and cvar code (with a mind to do some more work on completion), it turns out QF still maintains the alpha-sorted linked lists (however, hash tables most definitely are used for lookup by name).
Leave others their otherness.
http://quakeforge.net/
http://quakeforge.net/
Re: Describing the Quake Command System
Command parser
Code: Select all
/*
////////////////////////////////////////////////////////////////////////////////
Parser
////////////////////////////////////////////////////////////////////////////////
*/
#define MAX_LINE_LEN_1024 1024
#define MAX_NUM_ARGS_128 128
#define MAX_ARG_LEN_64 64
typedef struct
{
text64 args[MAX_NUM_ARGS_128];
int count;
} line_parse_t;
line_parse_t commandargs;
typedef struct
{
int start;
int end;
int len;
} arg_t;
int Interpreter_Parse (line_parse_t* lineParse, const char* text)
{
static const int maxlen63 = MAX_ARG_LEN_64 - 1;
arg_t argz[MAX_NUM_ARGS_128];
arg_t* arg = NULL;
const char* cursor = text;
int i, count = 0, len = strlen(text);
fbool in_quote = False;
memset (lineParse, 0, sizeof(*lineParse));
// Locate split points
for (i = 0; i < len; i ++, cursor++)
{
// Whitespace inside arg delimits, except if quoted
if (*cursor <= ' ' && arg && in_quote == False )
arg = NULL;
// Whitespace outside arg = ignore
else if (*cursor <= ' ' && arg == NULL)
continue;
// Comment terminates line
else if (*cursor == '/' && cursor[1] == '/')
break;
// Quote toggles in_quote, then ignored
else if (*cursor == '\"')
in_quote = !in_quote;
else if (arg) // Data .. if in_arg extend it
{
if (len == maxlen63)
continue; // At limit, no room left
arg->end ++;
arg->len ++;
}
else // Data, wasn't in an arg so start one
{
if (count == MAX_NUM_ARGS_128)
break; // Can't add more
arg = &argz[count];
count ++;
arg->start = arg->end = i;
arg->len = 1;
}
}
for (i = 0; i < count; i ++)
strncpyz (lineParse->args[i], &text[argz[i].start], argz[i].len + 1); // +1 = room for null term
return (lineParse->count = count);
}
databuffer_t command_buffer;
void Interpreter_AddText (const char* text)
{
size_t numbytes = strlen (text);
Databuffer_AddBytes (&command_buffer, text, numbytes);
Databuffer_AddBytes (&command_buffer, "\n", 1); // Command buffer needs newline terminated text
}
// Issue commands for everything we have until there is nothing left to process
void Interpreter_Run (void)
{
char current_line[MAX_LINE_LEN_1024];
static size_t maxbytes = sizeof(current_line);
if (command_buffer.maxsize == 0)
Host_FatalError ("Interpreter_Run: No command buffer. Not initialized");
// Run until nothing left ...
while (DataBuffer_GetTextLine_And_Remove (&command_buffer, current_line, maxbytes))
{
// Parse the line.
if (Interpreter_Parse (&commandargs, current_line))
{
// Run the command
Command_Execute (commandargs.args[0]);
}
}
}
fbool Interpreter_Init (void)
{
#define COMMAND_BUFFER_SIZE_65535 65535 // The buffer will add 1 byte of padding to get nice 65536.
Databuffer_Alloc (&command_buffer, COMMAND_BUFFER_SIZE_65535);
return True;
}
void Interpreter_Shutdown (void)
{
Databuffer_Dealloc (&command_buffer);
}
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Describing the Quake Command System
They should have done the folders differently in the Quake paks + progs.dat. And the health boxes should have been in thrown in progs folder. Looking back ...mh wrote: (the fact that the "map" command is the one where autocompletion is of most benefit just makes this suck even more).
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Describing the Quake Command System
they should have put sounds in the progs directory too, it makes about as much sense. and yes, separate complaint.
Re: Describing the Quake Command System
Lotsa things only come through with hindsight. That's part of what makes Q2 and Q3A better platforms than Q1.
We had the power, we had the space, we had a sense of time and place
We knew the words, we knew the score, we knew what we were fighting for
We knew the words, we knew the score, we knew what we were fighting for
Re: Describing the Quake Command System
I think I'm going to drift into that general direction, especially since the format is ok.frag.machine wrote:Yet about parsing: may I suggest JSON ? widely used, a de facto industry standard, very similar (but more complete) to the key/value approach you guys are aiming without the XML verbosity/complexity, supported among a great number of languages (including but not limited to C, C++, C#, Java, JavaScript - this one natively-, Perl, Python, etc.), with code to write and parse the format ready to use.
I've modified the parser I'm playing with as such
Code: Select all
#ifdef REPEAT_FUNCTIONALITY
// Check for repeat command. An unquoted trailing "{" starts it, a singular unquoted "}" ends it.
if (count >= 2 && arg->quoted == False && text[arg->start] == '{' && arg->len == 1)
{
count --; // Strip the trailing "{"
memset (&repeatCommand, 0, sizeof(repeatCommand));
for (i = 0; i < count; i ++)
strncpyz (repeatCommand.args[repeatCommand.count++], &text[argz[i].start], argz[i].len + 1); // +1 = room for null term
in_repeat_command = &repeatCommand;
return 0;
}
if (count == 1 && argz[0].quoted == False && text[argz[0].start] == '}' && argz[0].len == 1)
{
in_repeat_command = NULL;
return 0;
}
if (in_repeat_command && count /* <--- don't act on blank lines */ )
{
memcpy (lineParse, &repeatCommand, sizeof(*lineParse) );
// If we would overflow, cap the args
if (lineParse->count + count > MAX_NUM_ARGS_128 - 1)
count = (MAX_NUM_ARGS_128 - 1) - lineParse->count;
}
#endif
Code: Select all
msgbox {
"red"
"green"
"blue"
}
Code: Select all
entities add {
// name origin angles
"box1", {0, 15, 0}, {0, 0, 0}
"box2", {0, 15, 0}, {0, 0, 0}
"box3", {0, 15, 0}, {0, 0, 0}
}
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Describing the Quake Command System
Holy hell ...
The amount of fun you can start having playing around with building a "command line interpreter" is almost beyond description, after you get a few pain in the arse functions written.
I used to wonder what could possibly motivate someone to, say, work on QuakeC compilers. Or scripting. Which seems boring as hell. I get that now. The possibilities are endless ...
/ My initial interest in this really was some "robust" 3D menus and doing it in a flexible way, so I can't do that within the Quake entity system. Using parsing, not only can I largely define this stuff in a text file, but defining 2D interfaces with hotspots on the fly seems within range.
The amount of fun you can start having playing around with building a "command line interpreter" is almost beyond description, after you get a few pain in the arse functions written.
I used to wonder what could possibly motivate someone to, say, work on QuakeC compilers. Or scripting. Which seems boring as hell. I get that now. The possibilities are endless ...
/ My initial interest in this really was some "robust" 3D menus and doing it in a flexible way, so I can't do that within the Quake entity system. Using parsing, not only can I largely define this stuff in a text file, but defining 2D interfaces with hotspots on the fly seems within range.
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
Re: Describing the Quake Command System
much of the joy of writing a compiler is writing code that writes code. good luck testing every single possible combination though.
Re: Describing the Quake Command System
Tangents like these are often my achilles heel in a distraction sense, and I risk getting lost in this little (but awesome) world of the command line interpreter ...Spike wrote:much of the joy of writing a compiler is writing code that writes code. good luck testing every single possible combination though.
That being said, I think this particular side-quest might be the most worthy one I've gotten lost on ... provided I'm fast, work quickly, stay within "limits" and don't get infinitely bogged down ...
Code: Select all
//
// Entities defintion
//
entities_fields name texture origin
entities_add {
// name, texture, origin
"cube1" "bars.tga" (25, 10, 11)
"cube2" "bars.tga" (25, 15, 11)
"cube3" "globe.tga" (20, 15, 11)
}
The night is young. How else can I annoy the world before sunsrise? Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..