Ubisim Mod for Quake III Arena

Ubisim is a Quake III Arena (monster-shooting computer game) modification designed to aid the development of systems that integrate the physical and virtual worlds by simulating the physical world of people, the things they interact with, and the places they work, play, and live in. These systems are emerging from the new field of "ubiquitious" or "pervasive" computing. Ubisim works in tandem with WISE, a Java UI and protocol development tool. The entire package is called "ubiwise".

Ubisim Documentation.

If you want to work on the ubisim code, please just ask questions on the ubiwise-discuss mailing list.

Comparing Q3A and Ubisim

To understand how Q3A works as a tool for ubiquitous computing we need to translate from the world of 3D computer games into the world of ubicomp:

Quake III Arena Game
Ubisim Simulator
weapons handheld devices (handy)
entities people and things
baseq3/scripts/entities.def ... all possible entities for levels ubisim/scripts/ubients.def ... all possible entities for scenarios
levels scenarios
8 (eight) Game units (grid) one foot (12 inches,30.5 cm)
level editor, eg GtkRadiant scenario editor, when used with ubisim/scripts/ubients.def and fsgame="ubisim"
models 3D presentation of people or things for simulator
model editor, eg Milkshape model editor
brush 3D polygon-faced shape

File Overview

Ubisim, like Quake III Arena, has three parts:

  1. the rendering engine, Quake.exe. Copied from the Q3A CDROM to e.g. G:\ubisim\quake3\quake3.exe when Q3A is installed
  2. media files, ubisim.zip. Downloaded from the distribution and installed in eg. G:\ubisim\quake3\ubisim.
  3. Dynamic Link Libraries (dll-s). Built from ubisrc.zip and stored at the top of the ubisim tree, e.g G:\ubisim\quake3\ubisim.

The rendering engine is run with the command line option "+set fsgame ubisim". This causes the rendering engine to look into the subdirectory under quake3 for the dlls and media.

Media Files

The subdirectories of quake3/ubisim include files loaded into ubisim to create the 3D environment. They are organized along the lines of Q3A:

3D shapes for objects that can be added into scenarios. In the leaf subdirectories, each 3D object will (typically) have a binary file for the model editor (e.g. .md3d for Milkshape3d editor), a binary file output by the editor for input to the simulator (.md3), and one or more image files. Milkshape also requires a .qc file that associates the model with image files. Generally each object is in a subdirectory.
images to cover models. Textures specific to objects are put in the models subtree in ubisim (Q3A puts them in the textures tree, probably because different designers work on textures and models). So the textures subtree is for shared textures and ones independent of models. For examples, textures/sfx/logo512.jpg is the background screen for the main setup menu. These files are .jpg or .tga for Targa (use 32 bit Targa with alpha channel). Textures should be sized to a power of 2 in number of pixels in each dimension, eg 256x128.
3D models of places and the objects therein. The files contain 3D shapes for floors,walls, doors, ceilings and so forth as well as references to the textures and models files for decorating the places and filling them with objects. Files types used here are .map for text versions and .bsp for compiled binary files. These are created by a level editor like GtkRadiant. If you are careful with matching braces and quotes, then the .map files can be edited with a text editor then compiled in to .bsps. This approach is prefered when models or textures are moved to new file names for example.
various text files for driving the rendering engine. Most of these are texture scripts (.shader files). Whereever a texture is used to cover a model, a shader script can replace it. These scripts are commands to a texture pipeline that allows rapid subframe animation with various timebases. This is how visual effects like flames are created. Also in the scripts directory is the important file ubients.def file that specifies the entites that can be placed into maps.
A list of the classes of objects that can be placed in a scenario. The format is a bit funny: it looks like it was extracted from code comments. This file is read by GtkRadiant, not the runtime engine.
special effect sound files. These are .wav files.
background images for a scenario (aka level in Q3A). These are used fill-size in the background as a level loads and as a large thumbnail in the scenario picker.
for handheld entites (handy entities or weapons in Q3A. These are 32 bit Targa files with the shape of the handheld device drawn in the alpha channel. The other 3 channels combine into one solid color, giving an icon effect.
run the simulator on autopilot. These are created pulling down the console (using ~), then typing in /+set g_synchronousClients 1; record "file_name", running the simulator in a way you want recorded, then /+set g_synchronousClients 1; stoprecord. You can play back the demo with the command /demo "file_name". The files are type DM_66.
Win32 scripts (not used in Q3A)
files like this one. (not used in Q3A)

Dynamic Link Libraries

Ubisim has three dlls built from three Microsoft Visual C++ projects contained in matching subdirectories of the source tree:

server-side logic, builds qagamex86.dll. This code deals with simulation of the physical world.
client-side logic, builds cgamex86.dll. This code presents the physical world to the user.
menu logic, builds uix86.dll. This code supports a simple cascaded menu user-interface on a 640x480 canvas. Note that the original Q3A source code file has a directory called "ui" (rather than q3_ui). It is the menu code for a modified Q3A game called Team Arena. I have removed it from the source tree for ubisim.

Some source files are shared between the dlls. When they are changed, all dlls have to be rebuilt. Usually if you are changing pure physics in game you can just compile it, or if you are changing pure presentation logic in cgame you can just compile that dll. Generally if the simulator crashes or acts wierd, try rebuilding all three dlls (eg MSVC++->Build->BatchBuild) before you panic.

The three DLLs communicate with the rendering engine (in quake3.exe) through functions prefixed with trap_. These trap functions each wrap another function called syscall. For example

void trap_Cmd_ExecuteText( int exec_when, const char *text ) {
syscall( UI_CMD_EXECUTETEXT, exec_when, text );

Here is more from AnthonyJ as posted on PlanetQuake Forum for Q3 Mod Making:

As for how they're actually implemented...

When Q3 loads a dll, it calls "dllEntry()" and passes a pointer to the function "syscall" which is then stored with the dll. This function is a variable parameter function (like printf) which calls the appropriate things within the engine to do whatever is needed. The first parameter tells it which trap function it should do (the numerical constant you found), and then any further parameters are additional params for the syscalls.

id have bundled an asm file that hooks into the qvm interface to specify the system calls by passing in the correct ids.

Basically, dont worry about these files (and dont fiddle), since you cant make meaningful changes.

The Microsoft Visual C++ workspace file for ubisim is in source/ubisim.dsw. It has the three projects outlined above: game, cgame and q3_ui.


The server-side or physics part of the simulator is in the game project. Here are some of the important files:

A new file for ubisim, not found in Q3A. Opens sockets and sends data (XML) to WISE for the user interface to handheld devices. Also opens a socket for reading data from WISE. This file is has some Win32-specific socket code that would have to be ported for the simulator to run elsewhere, eg linux (not hard to do).
"Spawn" is Q3A-speak for create or instantiate. Most of the functions in this file parse elements of a .bsp file. If you look at one of these files you can see that the entities are stored as text mixed in with binary coordinates for the level.
field_t fields[]
lists the names of properties that can be set on entities, the corresponding fields in structs, and the type of the field.
spawn_t spawns[]
a dictionary of entity names to spawn functions.
G_SpawnGEntityFromSpawnVars(); G_CallSpawn(); etc
Functions that call the spawn functions for each named entity
Spawn functions. They act like constructors (C++) or initializers. They can call the G_Parse* functions for each type of property they expect in the .bsp. Usually the function is named SP_entityname().
entities that can be pushed around by players or that move themselves (e.g. trains). Also tends to be the place where entity methods are defined.
server commands. These are entered on the console (type ~ while playing) following a forward slash.
weapon physics. Things like launching rockets and assessing their damage are here. Many weapons create dynamic entities that are moved through the world during the game loop (see control flow). It provides mechanism for a player's handheld device to sample the world in a detailed way.



Control flow and time

As far as developers can tell, two loops control activity: one for game (server side) and one for cgame (client side). The quake.exe engine has the loop start and end, it calls vmMain() for the loop body. For game, the loop body is in G_RunFrame(); for cgame it is in ClientThink_real() (I think ;-)

Both the client and server are in loops, but these loops are not synchronous. Q3A has physical prediction code to smooth over the frame-rate mismatches caused by network connections and different resources available to client and server. The time-base for the physics is therefore not the frame cycle, but rather it is a seperate clock maintained by the server. This clock value is held in level.time and it is measured in milliseconds since the level (aka map aka scenario) started.

Entities, Items, Weapons, Players

There are four kinds of objects in ubisim as inherited from the Q3A code:

Unfortunately "entity" in Q3A means both the class of objects and the instance of an object. The instances are held in an array g_entities. The first part of the array is reserved for player entities. Other entities are loaded when the level is spawned or later when, e.g. a rocket entity is launched into the world. Every entity gets control-flow once per "frame", the main loop in game. The other meaning of "entity" is as a class of entities. These are listed in ubients.def, the ubisim version of entities.def. These entities can be placed in the scenario with the GtkRadiant editor and they can have code attached to them when they are spawned.
Items are another class of entities. Items can be "picked up" by players but they don't appear in the players hands. Rather they act as if the item was instantly loaded into the player's backpack. Items are defined in g_items.c, both code and media. The media is given in bg_misc.c, bg_itemlist[]. Usually items are set to "respawn", meaning that they disappear when picked up by one player, then reappear a bit later. Item instances can be placed in a scenario by the editor.
Weapons (handys)
Handys (Weapons) are special items in that when they are picked up they can go in player's hands. These instances may not listed in g_entities. Handy instances can be placed in the level with the editor. Each player can hold up to 10 handy objects. Ubisim has no weapons in hand by default; if you want players to start with an object in their hand, place that object directly above the player start position (info_player_start). The highest object will be the one the player starts with an others will be in their pocket.
Players are special entities whose instances are listed in g_entities[], but they cannot be dropped into the level directly with the level editor. Instead a special entity called info_player_start is dropped in the level. Players (users) pick how they will look in the game (model/skin), then join. At that point a player entity is placed into one of the reserved slots in g_entities[].

For Ubisim purposes the object system is not ideal. Generally I would like to take all of the media names out of the code and treat everything via ubients.def. I don't want entities to magically appear so respawning is disabled. Eventually then I would like to remove the "items" subsystem and make weapons be entities that are marked as "handy" meaning they can be held.

Ubisim Entities (not found in Q3A)

Digital Camera

A "weapon" or "handy" entity that looks like HP's 618 digital camera:

Milkshape 3D binary data for camera model. Drawn by John Barton from an image of the HP 618 (aka Durango) digital camera from Amy Battles, HP.
Model file ready for input to Q3A, exported from the .ms3d file. Beware the .qc file also has to be updated if you change the textures.
Weapon index used for Camera.
When the camera is fired, a "ray", patterned after the Q3A rocket, is sent from the camera. The ray is real fast compared with rockets. When the ray collides with an entity or a wall, the appropriate action can be triggered. (This approach isn't essential: the camera effects could be instantantious.) It calls G_ExplodeRay() if the ray hits a wall; this in turn sends an event, EV_RAY_MISS, to cgame. In the normal entity loop, G_RunMissileOrRay() will be called and it will test the trace ahead of the ray over the next frame. Any collision will trigger an event for cgame, EV_RAY_HIT. TODO: make the camera render a frame an store it when fired.

How To

How to add a new entity:
  1. write a new spawn function,
  2. put it and the entity name in spawns[],
  3. add an entry in the ubients.def file for this entity,
  4. then drop the new entity into a scenario file using a level editor.
How to find the distance from the ground (un tested):
Here is a guess. From g_items.c, you can see how to
get a vector (dest) for a point infinitely below an
VectorSet( dest, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2] - 4096 );

Then you can ask the engine to trace along the line from
your entity at ent->s.origin to "dest" and give back
any collisions with a bounding box given by ent->r.mins
and ent->r.maxs:
trap_Trace( &tr, ent->s.origin, ent->r.mins, ent->r.maxs, dest, ent->s.number, MASK_SOLID );

Now you just need to decide of the trace hit the ground
or another entity (eg a train). Hopefully you don't
care, you only care if something is below by 20 units
if( (ent->s.origin[2] - tr.endpos[2]) < 20 ) ...
----------------------------------^ z axis, up and down

How to Debug with MSVC++
Key hint from http://www.abl.com/at/city/code/helloCity.html. You need to build the dll directly into the mod directory so that the debug version written by MSVC++ is picked up by quake3.exe. In MSVC++ with Project-->Settings-->Link, drop the .dll into ubisim subdir. Then in Project-->Settings-->Debug set the executable to quake3.exe. All three .dll files need to be built and I had to have the command line args in Project-->Settings-->Debug

+set fs_game "ubisim" +set vm_game 0 +set vm_cgame 0 +set vm_ui 0 +set sv_pure 0

to get the dlls to load. The sv_pure setting allows non-idSoftware dlls I guess. You can use the last panel of the q3a ui for multiplayer mode to set it.

How to send commands to the engine.
It seems that the three functions:
	g_syscalls.c: void trap_SendConsoleCommand(int exec_when, const char *text );
    cg_syscalls.c void trap_SendConsoleCommand( const char *text );
    ui_syscalls.c: void trap_Cmd_ExecuteText( int exec_when, const char *text );
are all the same function with exec_when==EXEC_APPEND. They all send a text string from their respective DLL to the Q3A engine. Inside there must be some sort of table of commands that can be built-in to the engine (like "screenshot") or directed to one of the DLLs (like "centerview"). For the UI DLL at least the internal table seems to configurable from a mod via the binding mechanism in ui_controls2.c. But I am guessing. See also the console part of Cvars, commands, and VM Communication
by HypoThermia.





Links to Q3A related info that may be helpful

Weapons (handhelds)

Level editing



These are random older notes as I tried to learn about Q3A modification.

(c) 2002 Hewlett Packard

John J. Barton http://www.johnjbarton.com/index.htm