mikeBot client - server communication code | version 0.1 |
© copyright 1997 mike warren | contact info |
WARNING : heavy construction
download |
Before downloading, it is important to note that this code is not freeware, nor is it GNU; to use it, you must: If these terms are unsuitable, don't download anything.
- Notify me before you release any project using this code (wheather with or without source)
- Give me credit in the documentation.
- Include all the files (with the possible exception of the source code) contained in the distributions below in your distribution.
- and, give me 5% of gross revenue if you plan on selling the product, shareware or commercial.
- nothing to download, yet. Soon though...
documentation |
Please, mail me at mbwarren@acs.ucalgary.ca with any questions you may have and I will answer them here.
classes/relationships |
mbnav is derived from mbfire so navigation can follow fire's target, and because in the very distant future, nav will need to override fire to hit things like switches.
class descriptions |
qsocket |
overview
qsocket handles all the outgoing/incomming socket calls, be it though the windows WinSock interface, or the unix one (just file descriptors, thankfully). It will also look up addresses such as quake.mike.com into #.#.#.# form. qsocket throws char * exceptions iff QTHROW is #define'd as non-zero.Note that if you are using these classes as intended, you should never interract with qsocket
development status : stable, except for proxy issues.
member functions
- private:
- struct in_addr * atoaddr( char * address );
- Returns an internet address structure from the address passed. The address can be in either www.foo.com or 127.0.0.1 form. NULL is returned on error.
- public:
- qsocket( char * addr=QCS_DEFAULT_SERVER, int port=QCS_DEFAULT_PORT );
- The constructor. Obtains a file descriptor for the socket, at the specified address and port, and binds the local address. If QTHROW was defined, then char * exceptions are thrown upon error, otherwise perror() and exit() are used to deal with errors. It may also interest you no know that the socket option O_NDELAY or O_NONBLOCK (depending on OS) is set; this means that calling receive() with no data to be read will cause an error, with errno set to EWOULDBLOCK.
- ~qsocket();
- Destructor; closes socket.
- int send( char * buff, int size );
- Sends the buffer pointed to by buff, which is of size size, and can be bigger, but better not be smaller. The number of bytes sent is returned, or < 0 on error, at which point errno is set appropriatly.
- int receive( char * buff, int maxSize );
- Simmilar to send; receives data (if any) from the socket. Returns bytes read, or < 0 on error. Note that a return value of 0 indicates EOF (i.e. the socket shutdown). maxSize is the maximum number of bytes buff can hold.
- void changePort( int p )
- Changes both the send and receive ports to p.
- int getLocalPort();
- Returns the current port the socket is receiving on.
- int getRemotePort();
- The port to which data will be sent.
- int getFD();
- Returns the file descriptor of the socket. Useful for select()ing in the "main" loop.
member variables
private:public:
- struct sockaddr_in remote
- The internet address structure for the remote system.
- struct sockaddr_in local
- Address of the local system (assigned by OS).
- int fd
- The file descriptor for the socket.
- none.
qpacket |
overview
qpacket handles construction and deconstruction of quake packets, both client-server and vice versa. It is more efficient to not create and destroy the actual qpacket objects for each packet, hence the reset() function. qpacket also handles endianess convertion.development statas : pretty stable, save the ::write() function.
member functions
private:
- none.
public:
- qpacket( int x=QP_MAX_PACKET_DATA )
- Constructor; only allocates data to size specified by x and initializes variables.
- void copy( qpacket & )
- Copy constructor. Not defined as qpacket( qpacket & ) because, i think, CC wasn't using it; anyone know why?
- ~qpacket()
- deletes data
- void reset ()
- Readies the packet for writeing. (no need to call this if the qpacket was just constructed).
- int write( FILE * f, int x, vector & v )
- Writes the packet out to f in valid .DEM format; the vector v is used for the facing info. in the .DEM headers, so send the bot's current facing. TODO: use mFile instead of FILE *(maybe...:) )
- int init()
- Updates pType and size based on the data in the data buffer. Only call this after filling data from, say, the socket
- int update()
- Makes the packet ready to send; adds header info. based on the current values of size and pType, so call changeType() before calling this when constructing packets. If you are using qpacket::send(), there is no need, since it calls update() for you.
- type getType()
- Returns the current packets type (i.e. qpacket::control, etc.)
- void dumpHex()
- void dumpChar()
- If DEBUG has the DQP bit set, then these funcions dump the contents of data (including header) in hexadecimal or character format, respectivly. If not, they do nothing.
- void changeType( type x )
- Changes the packets type. Only use when constructing packets, when you must use it :)
- void setReadPos( int x )
- Used to move through the packet. Negative x's are bad; if x > size, nothing is done. You shouldn't find a need for this.
- void ffwd()
- Zooms you to the end of the packet. Useful when, say, adding things like center-printed messages to received packets before writing them to a .DEM file ;)
- int send( qsocket * sock )
- Sends the packet through the socket pointed to by sock, which better not be NULL. update() is called in this function, so no need to call it yourself before-hand. TRUE or FALSE is returned, depending on the success of the qsocket::send().
- int getSize()
- Returns the size of the data portion of the packet only.
- int getReadPos()
- int getWritePos()
- int getMaxSize()
- Self-explanatory.
- char * getBuffer()
- Use this with extreme caution, if at all; this gives you basically public access to the data.
- int getNumber()
- Returns the number, as defined in the header. Only valid for qpacket::reliableEnd, qpacket::reliableFragment and qpacket::unreliable.
- int changeNumber( int x )
- Changes the 4 bytes between data[4] and data[8] to the number specified. Same restrictions as getNumber(). This is only used for debugging by me, so it may dissappear in a later release; try not to depend on it. Tell me if you do.
- int readLEint()
- int readBEint()
- short readLEshort()
- short readBEshort()
- float readLEfloat()
- float readBEfloat()
- unsigned char readByte()
- All these functions are basically the same, except for the amount of data they read. All functions (besides readByte, obvioulsy) use readByte() to obtain their data. readBE<type> functions read some bytes out of data and return a <type>, assuming the <type> was in big-endian form in data. Similar for readLE<type> functions.
- float readAngle()
- This reads a byte, then multiples it by 360.0 / 256.0, then returns a float.
- float readCoord()
- Reads a short, and multiplies it by 0.125 before returning it.
- char * readString()
- Reads bytes from data until a 0-byte is read, at which point the string is returned. It will not exceed Q_MAX_STRING bytes in size. (1024, currently) You must delete the string returned, eventually, or you will be leaking memory
- void addLEint( int )
- void addBEint( int )
- void addLEshort( short )
- void addBEshort( short )
- void addLEfloat( float )
- void addBEfloat( float )
- void addByte( char x )
- void addData( char * x, int s )
- void addAngle( float )
- void addCoord( float )
- void addString( char * )
- These work very similarily to the read functions; addBE<type> will put the type into big-endian order in data.
- qpacket & operator += ( qpacket & )
- Adds two packets together. Adds to the end of the current packet, but copies from data[8] of the second, thus skipping the header and packet number. Used only for qpacket::reliableFragments by me. The header of the first is not adjusted, but size is.
member variables
private:
- int size
- Size of the data portion of the packet only. i.e. the 8 bytes for the header are not included in this number.
- int maxSize
- Size of data allocated.
- int readPos
- How far through the data the read calls are. This does not include the header (well, it does, but you don't have to read the header off)
- int writePos
- Same as readPos, but for write calls. Don't try to write the header on; use update()
- char * data
- Allocated in the constructor, deleted in the descructor.
- type pType
- The type of packet this is; uses the "nice" enum type defined below (in member variables).
- char t1[ 4 ]
- char t2[ 4 ]
- Temporary storage for endianess convertion.
public:
- enum type { control, reliableFragment, reliableEnd, acknowledge, unreliable, unknown }
- The "nice" packet types. Self-explanatory.
qcs |
overview
qcs handles all communications between the client (the bot) and the server. As much as possible, virtual functions are used to change things; this allows derived classes like mbotbase to override them and keep as much code as possible out of this already huge class.Please tell me if you find any bugs in the decoding of messages. I would also welcome your suggestions for the class. Mail me or use the handy feedback form.
member functions
private:protected:
- qcs( qcs & ){}
- NULL copy ctor, 'cause copying qcs is a Bad Thing.
public:
- int decodeControl( qpacket & )
- int decodeReliable( qpacket & )
- int decodeUnreliable( qpacket & )
- int decodeAcknowledge( qpacket & )
- int decodeQPacket( qpacket & )
- int decodeMessages( qpacket & )
- These decode various types of qpacket's. decodeMessages is for the unreliable game updates and is therefore huge :)
- int send( qpacket & )
- Sends a packet. Correctly handels waiting for acknowledges from reliable packets on the ack queue.
- void initTables()
- initialized each entry in modeltable and soundtable to NULL.
- void deleteTables()
- deletes any non-NULL entries in modeltable and soundtable.
- void updateTableTypes()
- This [will] update the modeltypes and soundtypes. unimplemented
- qcs()
- constructor. Doens't allocate a qsocket; that is done by qcs::server(), which must be called.
- virtual ~qcs()
- desctructor. Sends a disconnect packet if connected.
- int sendKeepalive()
- int sendDisconnect()
- virtual int sendMovement()
- int sendConsole( char * )
- Send various packets. You should only find a use for sendConsole().
- int getSignonLevel()
- int update()
- Only call this if data is waiting on the socket! Use select() to determine this.
- int getFD()
- Gets the file descriptor used by the socket. Returns 0 if there is no valid socket. This is then used by select(). See above.
- char * connect()
- Sends a connection request to the server. Returns NULL if connection was accepted or a pointer to the rejection message if not.
- void disconnect()
- Hmmm
- int recordDemo( char *)
- Returns TRUE if the filename passed was opened succesfully and demo recording can now commence. Note that you can not [yet] start recording demos partway through levels.
- int stopDemo()
- int waitForPacket()
- This waits for a packet to be received by the socket. It does block and is intended to wait for qpacket::control packets (only). (i.e. when connecting).
- int server( char * ip, int port = 26000 )
- If currently connected, disconnects, destroys sock and tries to reconstruct it with the ip passed. It will not attempt to connect and returns TRUE or FALSE.
- int connected()
- int recording()
- Self-explanatory
- void printInfo()
- Queries server for its info and then prints it. Won't work if already connected.
- void printPlayerInfo( int )
- Queries the server for info on the specified player and prints it. Not valid when connected.
- void printLevel()
- Will only work if connected.
- int isProxyConnected()
- void waitForProxy()
- Proxy stuff; unimplemented
- virtual void changedLevel( char * x )
- Passes the file name for the new level.
- void rankings() prints out players and frags (and colors).
- virtual void entityUpdated( int x )
This is called if something major happeded to the entity (i.e. it got a new modeltable index)- virtual void entityChanged( int x )
- virtual void timestampChanged( float x )
i is the index (0 <= i < 32) and v is the new value- virtual void playerstateUpdate( int i,int v )
- virtual void gotSayMessage( char * x )
The vector is a position on where the damage came from.- virtual void receivedDamage( int amt, vector & v )
- virtual void centerPrint( char * x )
- virtual void updateHealth( int x )
- virtual void updateArmour( int x )
- virtual void updateCells( int x )
- virtual void updateShells( int x )
- virtual void updateRockets( int x )
- virtual void updateNails( int x )
- virtual void updateWeapon( int x )
- These are fairly self-explanatory, but should be over-ridden by a derived class like mbotbase. They are called whenever the event they describe happens. There will (maybe) be more added to this list, but these won't change.
member variables
private:protected:
- qsocket * sock
- Current socket, bound to current server. All communications go through here.
- qproxy * proxy
- unimplemented; for proxy-server, when it's ready.
- char currentServerIP[ Q_MAX_STRING ]
- String of the current server's address, either #.#.#.# or quake.spode.com mode.
- FILE * demoFP
- If a demo is being recorded, this is a valid file pointer. If no demo recording, this [must] be NULL. warning : this will likely be made private.
- char qcs_message[ Q_MAX_STRING ]
- This will be written at the back of all .DEM packets written (if any)
- vector facing
- Used to write .DEM packets; the facing for the camera (the bot's facing)
- int fireTarget, navTarget
- For adding particles in the .DEM packets; these are indexs into entities.
- qpacket inPacket
- qpacket outPacket
- qpacket * fragments
- Used for incoming, outgoing and reliable packets, respectivly. reliableFragments are copied into *fragments, then decoded when a reliableEnd packet arrives.
- int outgoingUnreliable
- int outgoingReliable
- int incomingReliable
- int incomingUnreliable
- Packet counts. Don't reset on level changes. If a packet with a lower number than the "current" one, it is rejected (not decoded).
- int haveConnection
- TRUE iff the server is talking to me. (i.e. accepted connection request)
- qack ackQueue
- The queue of reliable packets to send
- serverInfo info
- Contains nifty info like maxPlayers; both qcs::printServerInfo() and qcs::decodeMessges() mess with this.
- char * result
- The reject messge from last connect request. NULL iff the connection was accepted.
- float newTimestamp
- float oldTimestamp
- The timestamps sent by the server. They increment by 0.1 second, by default. (Each unreliable update packet contains one of these; if they go up by about 0.1, the server is sending updates every 0.1 second...this can be changed by the serverop)
- int signonLevel
- Signon level for level changes; if signonLevel >= 3, then the game has begun. Go kill stuff.
- int myEntityNumber
- An index into entities. Note that the index into players will be myEntityNumber-1 (this is true for all players; if they are playerNumber 3, their entity will be 3+1=4. Conversly, an entity ( <= info.maxPlayers +1 ) has playerNumber entityNumber-1) Watch out for illegal array indexs (i.e. < 0)
- char * modeltable[ QCS_MAX_MODELS ]
- char * soundtable[ QCS_MAX_SOUNDS ]
- These contain the filenames of the prechached models and sounds.
- int modeltypes[ QCS_MAX_MODELS ]
- int soundtypes[ QCS_MAX_SOUNDS ]
- These are "nice" model/sound types. unimplemented
- qentity entities[ QCS_MAX_ENTITIES ]
- Entity info.
- qplayer players[ QCS_MAX_PLAYERS ]
- Contains frags, hate, etc. for each player. QCS_MAX_PLAYERS is the theoretical limit, not the number the actual server allows. Use qcs::info.maxPlayers.
mbotbase |
overview
member functions
member variables
qack |
overview
qack handles remembering and resending (if not acknowleded) any client to server reliable packets (like console commands, through qcs::sendConsole()). Up to QACK_MAX_PACKETS packets can be in the queue at once, and packets are resent approx. every .3 seconds if not acknowledged (every three calls to qack::update(), which will be approximatly every third timestamp (server-client update) which occur every tenth of a second)member functions
private:public:
- int deletePacket()
- Removes a packet from the queue
- qack()
- ~qack()
- Ctor, dtor.
- int addPacket( qpacket &, qsocket * )
- Inserts (if possible) a packet into the queue, and sends it to the socket if the queue is empty already. TRUE/FALSE returned.
- int gotAck( int, qsocket * )
- Should be called when an acknowledge is received (duh); deletes the appropriate packet, if any.
- int resend( qsocket * )
- Call this whenever qcs::update() is called; only actually resends packets after QACK_MAX_WAIT calls.
- void clear()
- Forces the queue to be emptied. This does not mean the packets are send; any unsent (unacknowledged) packets will never be delivered
member variables
private:qpacket packets[ QACK_MAX ] int packetNumbers[ QACK_MAX ] These are the actual elements in the queue.
int size Number of elements in queue.
int tail Index of the tail of the queue. (insertion point)
int head Index of head of queue. (deletion point)
int lastSend int current Info so resend knows when to actually resend the next packet. public:
- none.
structures/auxillary classes |
qplayer |
- int index
- Index into qcs::entities
- int frame
- Frame can be used to determine if the (player) is living or dead.
- int skin
- Helpfull in determining armour type
- vector origin
- Where it is.
- vector facing
- Where it's looking.
- vector velocity
- How fast (and which direction) it's moving.
- float lastTime
- Last timestamp this entity was updated during.
- qentity()
- Ctor
- void updateOrigin( vector & v, float t1, float t2 )
- this will change. Currently send the (new) position, and new and old timestamps.
qentity |
- int index
- into qcs::modeltable array.
- int frags
- char * name
- int hate
- int shirt
- 0 <= shirt < 13
- int pants
- 0 <= pants < 13
- qplayer()
- ~qplayer()
preprocessor definitions |
- QTHROW
- When TRUE, classes which potentially throw exceptions do. When FALSE, errors simply print a message and exit()
- UNIX
- When TRUE, unix code is uncluded. Mutually exclusive with WIN
- AIX
- When TRUE, AIX-specific code is included. Should not be TRUE if UNIX is FALSE.
- WIN
- When TRUE, windows95 code is used; currently not implemented.