Changes between Version 5 and Version 6 of ioquake3
- Timestamp:
- Jun 24, 2011 10:44:00 AM (13 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
ioquake3
v5 v6 1 = IOQuake3 = 1 2 The following is what I've learned about the ioquake3 engine, which I hope will be helpful to you guys while I'm away. 3 4 FIXME: Currently, I'm using this page as more of a "hey guys, here's the sit" rather than an actual public page. We can clean it up later. 2 5 3 6 == General Terms & Tips == … … 12 15 We call an iteration of a game-driving loop a "frame". Because the client and the server are on different machines, client frames and server frames may operate at completely different frequencies. Quagent AI is called every single server frame (unlike normal Quake bot AI). This is unlikely to cost much computationally on a modern machine, since they are far more powerful than machines made in the early 90s. 13 16 14 == Server, Client, Interface == 15 TODO: put text here. 17 == Server, Client == 18 Quake is a multiplayer game, so it runs on multiple machines and struggles to keep everything consistent. Clients do prediction and interpolation, while the server periodically gives authoritative snapshots of the game state. Honestly I don't know too much about this: I gave Xu a book that covers it a little. 19 20 This might be a problem for our model loading bug - since events that result in the loading of a new model occur on the server, but model loading takes place on the client, we'll have to find a clever way to realize a model is missing in the client (though for all I know, it calls "ModelMissing()" or something...) 16 21 17 22 == The Virtual Machine == 18 T ODO: put text here.23 To protect users from malicious mods, Quake has a virtual machine that runs large sections of its code. In fact, most of our modifications are to virtual machine code. On both the server and the client, there is some code running inside the VM, and some code running outside it. 19 24 20 25 Generally, code inside the following folders are available inside the VM: 21 26 * game 22 27 * cgame 23 * client 28 * client? 29 * ui? 24 30 while any code inside the following folders are strictly outside the VM: 25 31 * botlib 26 32 some code is shared: 27 * qcommon 28 * tools? 33 * qcommon (some of it?) 29 34 and the rest I don't know about. 30 35 31 36 === Getting In and Out of the VM === 32 TODO: put text here. 37 So say you want to call something inside the VM from a function outside it. I have no idea how to do that, but can point you at VM_Call in the qcommon/vm_* files. 38 39 Going the other way is easier, however. You need to add a "trap function" that when called, actually drops out of the VM, reinterprets any memory pointers, and does whatever you need it to. Adding a trap function is a bit of a pain, especially if you're doing it to botlib (if so you'll have to change the function export structure: just grep -i "Stupidly" and you'll find all the changes I made for one of our botlib traps: trap_BotMoveStupidlyInDirection). Adding traps like we did for reading/writing sockets is much easier, though: just follow the step-by-step instructions below and copy the style of the existing entries there. Typically our edits are at the bottom of the files, but if you search "quagents" (case-insensitive) you'll turn then up quickly. 33 40 34 41 ==== Adding a Trap Function ==== … … 47 54 48 55 All Quagent behavior runs through an AINode. An AINode is a function assigned to the bs->ainode pointer in bot_state_t, as you can see in the large switch statement. 56 57 Generally all our modifications to ai_main.c are at the bottom of that file. 58 59 === !CommandQueue === 60 As you know, the Quagents store their commands into a command queue that is actually an array 1024 commands long. There are two array indexes that are used to point into this array: bs->finalcommand and bs->currentcommand. If finalcommand is ever greater than currentcommand, there are no orders on the queue. When they are equal (pointing to the same command), that command is the only command. Otherwise, finalcommand points at the last command and currentcommand points at the next to be executed. Most commands are [[AtomicActions|atomic]], but some will take some duration of time. All manipulation of the queue itself is done in AIExit_Quagents and AIEnter_Quagents in game/ai_quagentsnodes.c. 61 62 The queue is an array of "quagent_command_t"s, which are a struct that contains command state information. Because it must be statically sized, it is as large as the state information of the largest command ([[rb|rb]]). It has generic spaces for information - by convention, these values are in the same order as ProtocolZero parameters. So for example, if I issue a "n ro 4 180 0", the command for that will have: 63 {{{ 64 command = QCMD_RO 65 id = 4 66 valf1 = 180 67 valf2 = 0 68 }}} 69 These values are assigned as part of BotAIQuagentsParseCommand's routine. After the command is executed in one frame, the Quagent has rotated a few degrees, and valf1 is updated to be however much is left to go (so, say, valf1 = 166). This way, if the user issues another command that interrupts the rotate, when the rotate eventually resumes it will only rotate the remaining amount. So typically the valf* track parameters, but in some cases they've been used as state machines. 49 70 50 71 === AINodes === … … 75 96 76 97 ==== Thread Safety ==== 77 Thread safety is not a concern because Quake is single-threaded. If a user sends a command while an AINode is midway through execution, it will not be read until the next AI frame. You are guaranteed that the state of the command queue is constant through the execution of an AINode. For this reason, it is safe to make multiple calls to trap_Com_QuagentsWriteStr, as the batch rangefinder does.98 Thread safety is not a concern because Quake is single-threaded. If a user sends a command while an AINode is midway through execution, it will not be read until the next AI frame. You are guaranteed that the state of the command queue is constant through the execution of an AINode. (That is, until you return, no function anywhere can interrupt you.) For this reason, it is safe to make multiple calls to trap_Com_QuagentsWriteStr, as the batch rangefinder does. 78 99 79 === ai_main.c === 80 TODO: put text here. 100 == The Director == 101 I should have all the framework we want in place for the GOD / Director functionality. Try connecting to Quagents on port 6002 and typing stuff. Currently, it'll just echo every command to stdout. I think pretty much anything we want a "configuration file" for, we should build through the director instead. Here's the points: 102 * Assuming we implement all the commands, anything a config file can do, we could do by piping it in command form into the director with an easy script (that we could even configure to run on startup or something). Example: 103 {{{ 104 cat config.txt | telnet localhost 6002 105 }}} 106 * If we put more general options here, we can do things a config file can't, such as change the configuration on the fly. Sure, it's not a huge feature, but it might be nice to add more items to the world as it ran, or something like that. 107 * The major drawback is that it's not blindingly obvious how to buffer commands the user issues as soon as Quake starts up (say, before the map is loaded). Then again, I'd be surprised if people choose not to just start Quake using the +map option. At least, that's what everyone I know did in the previous Quagents. Actually, I take this back, maybe. We just have it wait on the "hasn't had a read call yet" bit. 108 109 If you want to edit director effects, check out the !BotHandleDirectorCommand(char* cmdbuff) function in game/ai_main.c. Currently, it just echoes any director commands to stdout, but it gets called once per command with the command string in cmdbuff (see the comments). So you'll need to add stuff to parse out the commands from whatever format they are in and then evaluate them. I decided it might be nice to keep all the director command functions in ai_directorcommands.c and ai_directorcommands.h. Hopefully that won't be a problem.