opentnl-cvs Mailing List for Torque Network Library (Page 28)
Brought to you by:
mark_frohnmayer,
s_alanet
You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(141) |
May
(232) |
Jun
(103) |
Jul
(36) |
Aug
(35) |
Sep
(19) |
Oct
(20) |
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
|
Feb
(26) |
Mar
(2) |
Apr
(84) |
May
(5) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
Update of /cvsroot/opentnl/tnl/tnl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/tnl Added Files: Makefile assert.cpp asymmetricKey.cpp bitStream.cpp byteBuffer.cpp certificate.cpp clientPuzzle.cpp connectionStringTable.cpp dataChunker.cpp eventConnection.cpp ghostConnection.cpp huffmanStringProcessor.cpp log.cpp netBase.cpp netConnection.cpp netInterface.cpp netObject.cpp netStringTable.cpp platform.cpp random.cpp rpc.cpp symmetricCipher.cpp tnl.changelog.txt tnl.dsp tnl.h tnl.overview.txt tnl.suo tnl.vcproj tnlAssert.h tnlAsymmetricKey.h tnlBitSet.h tnlBitStream.h tnlByteBuffer.h tnlCertificate.h tnlClientPuzzle.h tnlConnectionStringTable.h tnlDataChunker.h tnlEndian.h tnlEventConnection.h tnlGhostConnection.h tnlHuffmanStringProcessor.h tnlLog.h tnlNetBase.h tnlNetConnection.h tnlNetEvent.h tnlNetInterface.h tnlNetObject.h tnlNetStringTable.h tnlNonce.h tnlPlatform.h tnlRPC.h tnlRandom.h tnlSymmetricCipher.h tnlTypes.h tnlUDP.h tnlVector.h udp.cpp vector.cpp Log Message: Initial commit. --- NEW FILE: tnlBitSet.h --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _TNL_BITSET_H_ #define _TNL_BITSET_H_ //Includes #ifndef _TNL_TYPES_H_ #include "tnlTypes.h" #endif namespace TNL { /// Represents a word of bits. /// /// A helper class to perform operations on a set of 32 bits. class BitSet32 { private: U32 mBits; public: /// Default constructor initializes this bit set to all zeros. BitSet32() { mBits = 0; } /// Copy constructor. BitSet32(const BitSet32& in_rCopy) { mBits = in_rCopy.mBits; } /// Construct from an input U32. BitSet32(const U32 in_mask) { mBits = in_mask; } /// @name Accessors /// @{ /// Returns the U32 representation of the bit set. operator U32() const { return mBits; } /// Returns the U32 representation of the bit set. U32 getMask() const { return mBits; } /// @} /// @name Mutators /// /// Most of these methods take a word (ie, a BitSet32) of bits /// to operate with. /// @{ /// Sets all the bits in the bit set to 1 void set() { mBits = 0xFFFFFFFFUL; } /// Sets all the bits in the bit set that are set in m. void set(const U32 m) { mBits |= m; } /// For each bit set in s, sets or clears that bit in this, depending on whether b is true or false. void set(BitSet32 s, bool b) { mBits = (mBits&~(s.mBits))|(b?s.mBits:0); } /// Clears all the bits in the bit set to 0. void clear() { mBits = 0; } /// Clears all the bits in the bit set that are set in m. void clear(const U32 m) { mBits &= ~m; } /// Flips all the bits in the bit set that are set in m. void toggle(const U32 m) { mBits ^= m; } /// Test if the passed bits are set. bool test(const U32 m) const { return (mBits & m) != 0; } /// Test if the passed bits and only the passed bits are set. bool testStrict(const U32 m) const { return (mBits & m) == m; } BitSet32& operator =(const U32 m) { mBits = m; return *this; } BitSet32& operator|=(const U32 m) { mBits |= m; return *this; } BitSet32& operator&=(const U32 m) { mBits &= m; return *this; } BitSet32& operator^=(const U32 m) { mBits ^= m; return *this; } BitSet32 operator|(const U32 m) const { return BitSet32(mBits | m); } BitSet32 operator&(const U32 m) const { return BitSet32(mBits & m); } BitSet32 operator^(const U32 m) const { return BitSet32(mBits ^ m); } /// @} }; }; #endif //_TNL_BITSET_H_ --- NEW FILE: tnlClientPuzzle.h --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _TNL_CLIENTPUZZLE_H_ #define _TNL_CLIENTPUZZLE_H_ #include "tnlDataChunker.h" #include "tnlNonce.h" // JMQ: work around X.h header file #if defined(TNL_OS_LINUX) && defined(Success) #undef Success #endif namespace TNL { /// The ClientPuzzleManager class issues, solves and validates client /// puzzles for connection authentication. class ClientPuzzleManager { public: private: /// NonceTable manages the list of client nonces for which clients /// have constructed valid puzzle solutions for the current server /// nonce. There are 2 nonce tables in the ClientPuzzleManager - /// one for the current nonce and one for the previous nonce. class NonceTable { private: struct Entry { Nonce mNonce; Entry *mHashNext; }; enum { MinHashTableSize = 127, MaxHashTableSize = 387, }; Entry **mHashTable; U32 mHashTableSize; DataChunker mChunker; public: /// NonceTable constructor NonceTable() { reset(); } /// Resets and clears the nonce table void reset(); /// checks if the given nonce is already in the table and adds it /// if it is not. Returns true if the nonce was not in the table /// when the function was called. bool checkAdd(Nonce &theNonce); }; enum { PuzzleRefreshTime = 30000, ///< Refresh the server puzzle every 30 seconds }; U32 mCurrentDifficulty; U32 mLastUpdateTime; U32 mLastTickTime; Nonce mCurrentNonce; Nonce mLastNonce; NonceTable *mCurrentNonceTable; NonceTable *mLastNonceTable; static bool checkOneSolution(U32 solution, Nonce &clientNonce, Nonce &serverNonce, U32 puzzleDifficulty, U32 clientIdentity); public: ClientPuzzleManager(); ~ClientPuzzleManager(); /// Checks to see if a new nonce needs to be created, and if so /// generates one and tosses out the current list of accepted nonces void tick(U32 currentTime); /// Error codes that can be returned by checkSolution enum ErrorCode { Success, InvalidSolution, InvalidServerNonce, InvalidClientNonce, InvalidPuzzleDifficulty, ErrorCodeCount, }; /// Difficulty levels of puzzles enum { InitialPuzzleDifficulty = 17, ///< Initial puzzle difficulty is set so clients do approx 2-3x the shared secret generation of the server MaxPuzzleDifficulty = 26, ///< Maximum puzzle diffuclty is approx 1 minute to solve on ~2004 hardware. MaxSolutionComputeFragment = 30, ///< Number of milliseconds spent computing a solution per call to solvePuzzle. }; /// Checks a puzzle solution submitted by a client to see if it is a valid solution for the current or previous puzzle nonces ErrorCode checkSolution(U32 solution, Nonce &clientNonce, Nonce &serverNonce, U32 puzzleDifficulty, U32 clientIdentity); /// Computes a puzzle solution value for the given puzzle difficulty and server nonce. If the execution time of this function /// exceeds 30 milliseconds, it will return the current trail solution in the solution variable and a return value of false. static bool solvePuzzle(U32 *solution, Nonce &clientNonce, Nonce &serverNonce, U32 puzzleDifficulty, U32 clientIdentity); /// Returns the current server nonce Nonce getCurrentNonce() { return mCurrentNonce; } /// Returns the current client puzzle difficulty U32 getCurrentDifficulty() { return mCurrentDifficulty; } }; }; #endif --- NEW FILE: tnl.suo --- (This appears to be a binary file; contents omitted.) --- NEW FILE: tnlBitStream.h --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _TNL_BITSTREAM_H_ #define _TNL_BITSTREAM_H_ #ifndef _TNL_BYTEBUFFER_H_ #include "tnlByteBuffer.h" #endif namespace TNL { class SymmetricCipher; /// Point3F is used by BitStream for transmitting 3D points and vectors. /// /// Users of the TNL should provide conversion operators to and from /// this TNL-native type. struct Point3F { F32 x; ///< the X coordinate F32 y; ///< the Y coordinate F32 z; ///< the Z coordinate }; /// Helper macro used in BitStream declaration. /// /// @note DeclareTemplatizedReadWrite macro declares a read and write function /// for the specified type. This is a macro because MSVC6 has seriously /// broken template functionality. Thanks MS! #define DeclareTemplatizedReadWrite(T) \ inline bool write(T value) { T temp = convertHostToLEndian(value); return write(sizeof(T), &temp); } \ inline bool read(T *value) { T temp; bool success = read(sizeof(T), &temp); *value = convertLEndianToHost(temp); return success;} /// BitStream provides a bit-level stream interface to a data buffer. class BitStream : public ByteBuffer { protected: enum { ResizePad = 1500, }; U32 bitNum; ///< The current bit position for reading/writing in the bit stream. bool error; ///< Flag set if a user operation attempts to read or write past the max read/write sizes. bool mCompressRelative; ///< Flag set if the bit stream should compress points relative to a compression point. Point3F mCompressPoint; ///< Reference point for relative point compression. U32 maxReadBitNum; ///< Last valid read bit position. U32 maxWriteBitNum; ///< Last valid write bit position. /// String buffer holds the last string written into the stream for substring compression. char mStringBuffer[256]; bool resizeBits(U32 numBitsNeeded); public: /// @name Constructors /// /// Note that the BitStream essentially wraps an existing buffer, so to use a bitstream you must /// have an existing buffer for it to work with! /// /// @{ /// Default to maximum write size being the size of the buffer. BitStream(U8 *bufPtr, U32 bufSize) : ByteBuffer(bufPtr, bufSize) { setMaxSizes(bufSize, bufSize); reset(); } /// Optionally, specify a maximum write size. BitStream(U8 *bufPtr, U32 bufSize, U32 maxWriteSize) : ByteBuffer(bufPtr, bufSize) { setMaxSizes(bufSize, maxWriteSize); reset(); } /// Creates a resizable BitStream BitStream() : ByteBuffer() { setMaxSizes( getBufferSize(), getBufferSize() ); reset(); } /// @} /// Sets the maximum read and write sizes for the BitStream. void setMaxSizes(U32 maxReadSize, U32 maxWriteSize = 0); /// resets the read/write position to 0 and clears any error state. void reset(); /// Returns a pointer to the next byte in the BitStream from the current bit position U8* getBytePtr(); /// Returns the current position in the stream rounded up to the next byte. U32 getBytePosition() const; /// Returns the current bit position in the stream U32 getBitPosition() const; /// Sets the position in the stream to the first bit of byte newPosition. void setBytePosition(const U32 newPosition); /// Sets the position in the stream to newBitPosition. void setBitPosition(const U32 newBitPosition); /// Advances the position in the stream by numBits. void advanceBitPosition(const S32 numBits); /// Writes an unsigned integer value between 0 and 2^(bitCount - 1) into the stream. void writeInt(U32 value, U8 bitCount); /// Reads an unsigned integer value between 0 and 2^(bitCount - 1) from the stream. U32 readInt(U8 bitCount); /// Writes an unsigned integer value between 0 and 2^(bitCount -1) into the stream at the specified position, without changing the current write position. void writeIntAt(U32 value, U8 bitCount, U32 bitPosition); /// Writes a signed integer value between -2^(bitCount-1) and 2^(bitCount-1) - 1. void writeSignedInt(S32 value, U8 bitCount); /// Reads a signed integer value between -2^(bitCount-1) and 2^(bitCount-1) - 1. S32 readSignedInt(U8 bitCount); /// Writes an unsigned integer value in the range rangeStart to rangeEnd inclusive. void writeRangedU32(U32 value, U32 rangeStart, U32 rangeEnd); /// Reads an unsigned integer value in the range rangeStart to rangeEnd inclusive. U32 readRangedU32(U32 rangeStart, U32 rangeEnd); /// Writes a float from 0 to 1 inclusive, using bitCount bits of precision. void writeFloat(F32 f, U8 bitCount); /// Reads a float from 0 to 1 inclusive, using bitCount bits of precision. F32 readFloat(U8 bitCount); /// Writes a signed float from -1 to 1 inclusive, using bitCount bits of precision. void writeSignedFloat(F32 f, U8 bitCount); /// Reads a signed float from -1 to 1 inclusive, using bitCount bits of precision. F32 readSignedFloat(U8 bitCount); /// Writes an object's class ID, given its class type and class group. void writeClassId(U32 classId, U32 classType, U32 classGroup); /// Reads a class ID for an object, given a class type and class group. Returns -1 if the class type is out of range U32 readClassId(U32 classType, U32 classGroup); /// Writes a normalized vector into the stream, using bitCount bits for the precision of angles phi and theta. void writeNormalVector(const Point3F &vec, U8 bitCount); /// Reads a normalized vector from the stream, using bitCount bits for the precision of angles phi and theta. void readNormalVector(Point3F *vec, U8 bitCount); /// Uses the same method as in writeNormalVector to reduce the precision of a normal vector /// to determine what will be read from the stream. static Point3F dumbDownNormal(const Point3F& vec, U8 bitCount); /// Writes a normalized vector by writing a z value and theta angle. void writeNormalVector(const Point3F& vec, U8 angleBitCount, U8 zBitCount); /// Reads a normalized vector by reading a z value and theta angle. void readNormalVector(Point3F *vec, U8 angleBitCount, U8 zBitCount); /// Sets a reference point for subsequent compressed point writing. void setPointCompression(const Point3F &p); /// Disables compression of point. void clearPointCompression(); /// Writes a point into the stream, to a precision denoted by scale. void writePointCompressed(const Point3F &p, F32 scale); /// Reads a compressed point from the stream, to a precision denoted by scale. void readPointCompressed(Point3F *p, F32 scale); /// Writes bitCount bits into the stream from bitPtr. bool writeBits(U32 bitCount, const void *bitPtr); /// Reads bitCount bits from the stream into bitPtr. bool readBits(U32 bitCount, void *bitPtr); /// Writes a ByteBuffer into the stream. The ByteBuffer can be no larger than 1024 bytes in size. bool write(const ByteBuffer *theBuffer); /// Reads a ByteBuffer in from the stream. bool read(ByteBuffer *theBuffer); /// Writes a single boolean flag (bit) into the stream, and returns the boolean that was written. /// /// This is set up so you can do... /// /// @code /// if(stream->writeFlag(foo == bar)) /// { /// ... write other stuff ... /// } /// @endcode bool writeFlag(bool val); /// Reads a single bit from the stream. /// /// This is set up so you can do... /// /// @code /// if(stream->readFlag()) /// { /// ... read other stuff ... /// } /// @endcode bool readFlag(); /// Writes a huffman compressed string into the stream. void writeString(const char *stringBuf, U8 maxLen=255); /// Reads a huffman compressed string from the stream. void readString(char stringBuf[256]); /// Writes byte data into the stream. bool write(const U32 in_numBytes, const void* in_pBuffer); /// Reads byte data from the stream. bool read(const U32 in_numBytes, void* out_pBuffer); /// @name Various types that the BitStream can read and write... /// @{ /// DeclareTemplatizedReadWrite(U8); DeclareTemplatizedReadWrite(S8); DeclareTemplatizedReadWrite(U16); DeclareTemplatizedReadWrite(S16); DeclareTemplatizedReadWrite(U32); DeclareTemplatizedReadWrite(S32); DeclareTemplatizedReadWrite(F32); DeclareTemplatizedReadWrite(F64); /// @} /// Sets the bit at position bitCount to the value of set bool setBit(U32 bitCount, bool set); /// Tests the value of the bit at position bitCount. bool testBit(U32 bitCount); /// Returns whether the BitStream writing has exceeded the write target size. bool isFull() { return bitNum > (getBufferSize() << 3); } /// Returns whether the stream has generated an error condition due to reading or writing past the end of the buffer. bool isValid() { return !error; } /// Hashes the BitStream, writing the hash digest into the end of the buffer, and then encrypts with the given cipher void hashAndEncrypt(U32 hashDigestSize, U32 encryptStartOffset, SymmetricCipher *theCipher); /// Decrypts the BitStream, then checks the hash digest at the end of the buffer to validate the contents bool decryptAndCheckHash(U32 hashDigestSize, U32 decryptStartOffset, SymmetricCipher *theCipher); }; //------------------------------------------------------------------------------ /// PacketStream provides a network interface to the BitStream for easy construction of data packets. class PacketStream : public BitStream { U8 buffer[MaxPacketDataSize]; ///< internal buffer for packet data, sized to the maximum UDP packet size. public: /// Constructor assigns the internal buffer to the BitStream. PacketStream(U32 targetPacketSize = MaxPacketDataSize) : BitStream(buffer, targetPacketSize, MaxPacketDataSize) {} /// Sends this packet to the specified address through the specified socket. NetError sendto(Socket &outgoingSocket, const Address &theAddress); /// Reads a packet into the stream from the specified socket. NetError recvfrom(Socket &incomingSocket, Address *recvAddress); }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ inline U32 BitStream::getBytePosition() const { return (bitNum + 7) >> 3; } inline U32 BitStream::getBitPosition() const { return bitNum; } inline void BitStream::setBytePosition(const U32 newPosition) { bitNum = newPosition << 3; } inline void BitStream::setBitPosition(const U32 newBitPosition) { bitNum = newBitPosition; } inline void BitStream::advanceBitPosition(const S32 numBits) { setBitPosition(getBitPosition() + numBits); } inline bool BitStream::write(const U32 in_numBytes, const void* in_pBuffer) { return writeBits(in_numBytes << 3, in_pBuffer); } inline bool BitStream::read(const U32 in_numBytes, void* out_pBuffer) { return readBits(in_numBytes << 3, out_pBuffer); } inline bool BitStream::readFlag() { if(bitNum > maxReadBitNum) { error = true; TNLAssert(false, "Out of range read"); return false; } S32 mask = 1 << (bitNum & 0x7); bool ret = (*(getBuffer() + (bitNum >> 3)) & mask) != 0; bitNum++; return ret; } inline void BitStream::writeIntAt(U32 value, U8 bitCount, U32 bitPosition) { U32 curPos = getBitPosition(); setBitPosition(bitPosition); writeInt(value, bitCount); setBitPosition(curPos); } inline void BitStream::writeRangedU32(U32 value, U32 rangeStart, U32 rangeEnd) { TNLAssert(value >= rangeStart && value <= rangeEnd, "Out of bounds value!"); TNLAssert(rangeEnd >= rangeStart, "error, end of range less than start"); U32 rangeSize = rangeEnd - rangeStart + 1; U32 rangeBits = getNextBinLog2(rangeSize); writeInt(S32(value - rangeStart), S32(rangeBits)); } inline U32 BitStream::readRangedU32(U32 rangeStart, U32 rangeEnd) { TNLAssert(rangeEnd >= rangeStart, "error, end of range less than start"); U32 rangeSize = rangeEnd - rangeStart + 1; U32 rangeBits = getNextBinLog2(rangeSize); U32 val = U32(readInt(S32(rangeBits))); return val + rangeStart; } }; #endif //_TNL_BITSTREAM_H_ --- NEW FILE: Makefile --- # TNL Makefile # (c) 2003 GarageGames # # This makefile is for gcc-based projects, at the moment. # # Configuration # CC=gcc -g -DTNL_DEBUG -I../libtomcrypt # -O2 OBJECTS=\ assert.o\ asymmetricKey.o\ bitStream.o\ byteBuffer.o\ clientPuzzle.o\ connectionStringTable.o\ dataChunker.o\ eventConnection.o\ ghostConnection.o\ huffmanStringProcessor.o\ log.o\ netBase.o\ netConnection.o\ netInterface.o\ netObject.o\ netStringTable.o\ platform.o\ random.o\ rpc.o\ symmetricCipher.o\ udp.o\ vector.o\ CFLAGS= .cpp.o : $(CC) -c $(CFLAGS) $< default: $(OBJECTS) @echo Building libtnl.a ... ar rcv libtnl.a $(OBJECTS) clean: rm -f $(OBJECTS) libtnl.a --- NEW FILE: eventConnection.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "tnl.h" #include "tnlEventConnection.h" #include "tnlBitStream.h" #include "tnlLog.h" #include "tnlNetInterface.h" namespace TNL { ClassChunker<EventConnection::EventNote> EventConnection::mEventNoteChunker; EventConnection::EventConnection() { // event management data: mNotifyEventList = NULL; mSendEventQueueHead = NULL; mSendEventQueueTail = NULL; mUnorderedSendEventQueueHead = NULL; mUnorderedSendEventQueueTail = NULL; mWaitSeqEvents = NULL; mNextSendEventSeq = FirstValidSendEventSeq; mNextRecvEventSeq = FirstValidSendEventSeq; mLastAckedEventSeq = -1; mStringTable = NULL; mEventClassCount = 0; mEventClassBitSize = 0; } EventConnection::~EventConnection() { while(mNotifyEventList) { EventNote *temp = mNotifyEventList; mNotifyEventList = temp->mNextEvent; temp->mEvent->notifyDelivered(this, true); mEventNoteChunker.free(temp); } while(mUnorderedSendEventQueueHead) { EventNote *temp = mUnorderedSendEventQueueHead; mUnorderedSendEventQueueHead = temp->mNextEvent; temp->mEvent->notifyDelivered(this, true); mEventNoteChunker.free(temp); } while(mSendEventQueueHead) { EventNote *temp = mSendEventQueueHead; mSendEventQueueHead = temp->mNextEvent; temp->mEvent->notifyDelivered(this, true); mEventNoteChunker.free(temp); } delete mStringTable; } void EventConnection::writeConnectRequest(BitStream *stream) { Parent::writeConnectRequest(stream); stream->write(NetClassRep::getNetClassCount(getNetClassGroup(), NetClassTypeEvent)); } bool EventConnection::readConnectRequest(BitStream *stream, const char **errorString) { if(!Parent::readConnectRequest(stream, errorString)) return false; U32 classCount; stream->read(&classCount); U32 myCount = NetClassRep::getNetClassCount(getNetClassGroup(), NetClassTypeEvent); if(myCount <= classCount) mEventClassCount = myCount; else { mEventClassCount = classCount; if(!NetClassRep::isVersionBorderCount(getNetClassGroup(), NetClassTypeEvent, mEventClassCount)) return false; } mEventClassBitSize = getNextBinLog2(mEventClassCount); return true; } void EventConnection::writeConnectAccept(BitStream *stream) { Parent::writeConnectAccept(stream); stream->write(mEventClassCount); } bool EventConnection::readConnectAccept(BitStream *stream, const char **errorString) { if(!Parent::readConnectAccept(stream, errorString)) return false; stream->read(&mEventClassCount); if(!NetClassRep::isVersionBorderCount(getNetClassGroup(), NetClassTypeEvent, mEventClassCount)) return false; mEventClassBitSize = getNextBinLog2(mEventClassCount); return true; } void EventConnection::setTranslatesStrings() { if(!mStringTable) mStringTable = new ConnectionStringTable(this); } void EventConnection::packetDropped(PacketNotify *pnotify) { Parent::packetDropped(pnotify); EventPacketNotify *notify = static_cast<EventPacketNotify *>(pnotify); if(mStringTable) mStringTable->packetDropped(¬ify->stringList); EventNote *walk = notify->eventList; EventNote **insertList = &mSendEventQueueHead; EventNote *temp; while(walk) { switch(walk->mEvent->mGuaranteeType) { case NetEvent::GuaranteedOrdered: // It was a guaranteed ordered packet, reinsert it back into // mSendEventQueueHead in the right place (based on seq numbers) TNLLogMessageV(LogEventConnection, ("EventConnection %s: DroppedGuaranteed - %d", getNetAddressString(), walk->mSeqCount)); while(*insertList && (*insertList)->mSeqCount < walk->mSeqCount) insertList = &((*insertList)->mNextEvent); temp = walk->mNextEvent; walk->mNextEvent = *insertList; if(!walk->mNextEvent) mSendEventQueueTail = walk; *insertList = walk; insertList = &(walk->mNextEvent); walk = temp; break; case NetEvent::Guaranteed: // It was a guaranteed packet, put it at the top of // mUnorderedSendEventQueueHead. temp = walk->mNextEvent; walk->mNextEvent = mUnorderedSendEventQueueHead; mUnorderedSendEventQueueHead = walk; if(!walk->mNextEvent) mUnorderedSendEventQueueTail = walk; walk = temp; break; case NetEvent::Unguaranteed: // Or else it was an unguaranteed packet, notify that // it was _not_ delivered and blast it. walk->mEvent->notifyDelivered(this, false); temp = walk->mNextEvent; mEventNoteChunker.free(walk); walk = temp; } } } void EventConnection::packetReceived(PacketNotify *pnotify) { Parent::packetReceived(pnotify); EventPacketNotify *notify = static_cast<EventPacketNotify *>(pnotify); if(mStringTable) mStringTable->packetReceived(¬ify->stringList); EventNote *walk = notify->eventList; EventNote **noteList = &mNotifyEventList; while(walk) { EventNote *next = walk->mNextEvent; if(walk->mEvent->mGuaranteeType != NetEvent::GuaranteedOrdered) { walk->mEvent->notifyDelivered(this, true); mEventNoteChunker.free(walk); walk = next; } else { while(*noteList && (*noteList)->mSeqCount < walk->mSeqCount) noteList = &((*noteList)->mNextEvent); walk->mNextEvent = *noteList; *noteList = walk; noteList = &walk->mNextEvent; walk = next; } } while(mNotifyEventList && mNotifyEventList->mSeqCount == mLastAckedEventSeq + 1) { mLastAckedEventSeq++; EventNote *next = mNotifyEventList->mNextEvent; TNLLogMessageV(LogEventConnection, ("EventConnection %s: NotifyDelivered - %d", getNetAddressString(), mNotifyEventList->mSeqCount)); mNotifyEventList->mEvent->notifyDelivered(this, true); mEventNoteChunker.free(mNotifyEventList); mNotifyEventList = next; } } void EventConnection::writePacket(BitStream *bstream, PacketNotify *pnotify) { Parent::writePacket(bstream, pnotify); EventPacketNotify *notify = static_cast<EventPacketNotify *>(pnotify); if(mConnectionParameters.mDebugObjectSizes) bstream->writeInt(DebugChecksum, 32); EventNote *packQueueHead = NULL, *packQueueTail = NULL; while(mUnorderedSendEventQueueHead) { if(bstream->isFull()) break; // dequeue the first event EventNote *ev = mUnorderedSendEventQueueHead; mUnorderedSendEventQueueHead = ev->mNextEvent; bstream->writeFlag(true); S32 start = bstream->getBitPosition(); if(mConnectionParameters.mDebugObjectSizes) bstream->advanceBitPosition(BitStreamPosBitSize); S32 classId = ev->mEvent->getClassId(getNetClassGroup()); bstream->writeInt(classId, mEventClassBitSize); ev->mEvent->pack(this, bstream); TNLLogMessageV(LogEventConnection, ("EventConnection %s: WroteEvent %s - %d bits", getNetAddressString(), ev->mEvent->getDebugName(), bstream->getBitPosition() - start)); if(mConnectionParameters.mDebugObjectSizes) bstream->writeIntAt(bstream->getBitPosition(), BitStreamPosBitSize, start); // add this event onto the packet queue ev->mNextEvent = NULL; if(!packQueueHead) packQueueHead = ev; else packQueueTail->mNextEvent = ev; packQueueTail = ev; } bstream->writeFlag(false); S32 prevSeq = -2; while(mSendEventQueueHead) { if(bstream->isFull()) break; // if the event window is full, stop processing if(mSendEventQueueHead->mSeqCount > mLastAckedEventSeq + 126) break; // dequeue the first event EventNote *ev = mSendEventQueueHead; mSendEventQueueHead = ev->mNextEvent; //Con::printf("EVT %d: SEND - %d", getId(), ev->mSeqCount); bstream->writeFlag(true); ev->mNextEvent = NULL; if(!packQueueHead) packQueueHead = ev; else packQueueTail->mNextEvent = ev; packQueueTail = ev; if(!bstream->writeFlag(ev->mSeqCount == prevSeq + 1)) bstream->writeInt(ev->mSeqCount, 7); prevSeq = ev->mSeqCount; S32 start = bstream->getBitPosition(); if(mConnectionParameters.mDebugObjectSizes) bstream->advanceBitPosition(BitStreamPosBitSize); S32 classId = ev->mEvent->getClassId(getNetClassGroup()); bstream->writeInt(classId, mEventClassBitSize); ev->mEvent->pack(this, bstream); TNLLogMessageV(LogEventConnection, ("EventConnection %s: WroteEvent %s - %d bits", getNetAddressString(), ev->mEvent->getDebugName(), bstream->getBitPosition() - start)); if(mConnectionParameters.mDebugObjectSizes) bstream->writeIntAt(bstream->getBitPosition(), BitStreamPosBitSize, start); } for(EventNote *ev = packQueueHead; ev; ev = ev->mNextEvent) ev->mEvent->notifySent(this); notify->eventList = packQueueHead; bstream->writeFlag(0); } void EventConnection::readPacket(BitStream *bstream) { Parent::readPacket(bstream); if(mConnectionParameters.mDebugObjectSizes) { U32 sum = bstream->readInt(32); TNLAssert(sum == DebugChecksum, "Invalid checksum."); } S32 prevSeq = -2; EventNote **waitInsert = &mWaitSeqEvents; bool unguaranteedPhase = true; while(true) { bool bit = bstream->readFlag(); if(unguaranteedPhase && !bit) { unguaranteedPhase = false; bit = bstream->readFlag(); } if(!unguaranteedPhase && !bit) break; S32 seq = -1; if(!unguaranteedPhase) // get the sequence { if(bstream->readFlag()) seq = (prevSeq + 1) & 0x7f; else seq = bstream->readInt(7); prevSeq = seq; } U32 endingPosition; if(mConnectionParameters.mDebugObjectSizes) endingPosition = bstream->readInt(BitStreamPosBitSize); U32 classId = bstream->readInt(mEventClassBitSize); if(classId >= mEventClassCount) { setLastError("Invalid packet."); return; } NetEvent *evt = (NetEvent *) Object::create(getNetClassGroup(), NetClassTypeEvent, classId); if(!evt) { setLastError("Invalid packet."); return; } // check if the direction this event moves is a valid direction. if( (evt->getEventDirection() == NetEvent::DirUnset) || (evt->getEventDirection() == NetEvent::DirServerToClient && isConnectionToClient()) || (evt->getEventDirection() == NetEvent::DirClientToServer && isConnectionToServer()) ) { setLastError("Invalid Packet."); return; } evt->unpack(this, bstream); if(mErrorBuffer[0]) return; if(mConnectionParameters.mDebugObjectSizes) { TNLAssert(endingPosition == bstream->getBitPosition(), avar("unpack did not match pack for event of class %s.", evt->getClassName()) ); } if(unguaranteedPhase) { evt->process(this); delete evt; if(mErrorBuffer[0]) return; continue; } seq |= (mNextRecvEventSeq & ~0x7F); if(seq < mNextRecvEventSeq) seq += 128; EventNote *note = mEventNoteChunker.alloc(); note->mEvent = evt; note->mSeqCount = seq; TNLLogMessageV(LogEventConnection, ("EventConnection %s: RecvdGuaranteed %d", getNetAddressString(), seq)); while(*waitInsert && (*waitInsert)->mSeqCount < seq) waitInsert = &((*waitInsert)->mNextEvent); note->mNextEvent = *waitInsert; *waitInsert = note; waitInsert = &(note->mNextEvent); } while(mWaitSeqEvents && mWaitSeqEvents->mSeqCount == mNextRecvEventSeq) { mNextRecvEventSeq++; EventNote *temp = mWaitSeqEvents; mWaitSeqEvents = temp->mNextEvent; TNLLogMessageV(LogEventConnection, ("EventConnection %s: ProcessGuaranteed %d", getNetAddressString(), temp->mSeqCount)); temp->mEvent->process(this); mEventNoteChunker.free(temp); if(mErrorBuffer[0]) return; } } bool EventConnection::postNetEvent(NetEvent *theEvent) { theEvent->notifyPosted(this); EventNote *event = mEventNoteChunker.alloc(); event->mEvent = theEvent; event->mNextEvent = NULL; if(event->mEvent->mGuaranteeType == NetEvent::GuaranteedOrdered) { event->mSeqCount = mNextSendEventSeq++; if(!mSendEventQueueHead) mSendEventQueueHead = event; else mSendEventQueueTail->mNextEvent = event; mSendEventQueueTail = event; } else { event->mSeqCount = InvalidSendEventSeq; if(!mUnorderedSendEventQueueHead) mUnorderedSendEventQueueHead = event; else mUnorderedSendEventQueueTail->mNextEvent = event; mUnorderedSendEventQueueTail = event; } return true; } void EventConnection::packStringTableEntry(BitStream *stream, StringTableEntryRef h) { if(!mStringTable) stream->writeString(h.getString()); else mStringTable->writeStringTableEntry(stream, h, &((EventPacketNotify *) getCurrentWritePacketNotify())->stringList); } StringTableEntry EventConnection::unpackStringTableEntry(BitStream *stream) { if(!mStringTable) { char buf[256]; stream->readString(buf); return StringTableEntry(buf); } else return mStringTable->readStringTableEntry(stream); } bool EventConnection::isDataToTransmit() { return mUnorderedSendEventQueueHead || mSendEventQueueHead || Parent::isDataToTransmit(); } }; --- NEW FILE: tnlLog.h --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _TNL_LOG_H_ #define _TNL_LOG_H_ #include "tnlBitSet.h" #include "tnl.h" namespace TNL { /// Global interface to the TNL logging system. /// /// The TNL logging system is consumer based. This is just a /// global stub that routes the log string to all the consumers. /// /// You should <b>really</b> be using the TNLLogMessage() and /// TNLLogMessageV() macros instead of calling this. /// /// @see LogConsumer extern void logprintf(const char *format, ...); /// LogConsumer is the base class for the message logging system in TNL. /// /// TNL by default doesn't log messages anywhere, but users of the library /// can instantiate subclasses that override the logString method. /// Any instantiated subclass of LogConsumer will receive all general /// logprintf's, as well as any TNLLogMessages that are enabled via /// the TNLLogEnable macro. class LogConsumer { LogConsumer *mNextConsumer; ///< Next LogConsumer in the global linked list of log consumers. LogConsumer *mPrevConsumer; ///< Previous LogConsumer in the global linked list of log consumers. static LogConsumer *mLinkedList; ///< Head of the global linked list of log consumers. public: /// Constructor adds this LogConsumer to the global linked list. LogConsumer(); /// Destructor removes this LogConsumer from the global linked list, and updates the log flags. virtual ~LogConsumer(); /// Returns the head of the linked list of all log consumers. static LogConsumer *getLinkedList() { return mLinkedList; } /// Returns the next LogConsumer in the linked list. LogConsumer *getNext() { return mNextConsumer; } /// Writes a string to this instance of LogConsumer. /// /// By default the string is sent to the Platform::outputDebugString function. Subclasses /// might log to a file, a remote service, or even a message box. virtual void logString(const char *string); }; struct LogType { LogType *next; static LogType *linkedList; bool isEnabled; const char *typeName; static LogType *current; #ifdef TNL_ENABLE_LOGGING static void setCurrent(LogType *theType) { current = theType; } static LogType *find(const char *name); #endif }; #ifdef TNL_ENABLE_LOGGING struct LogTypeRef { LogType *theLogType; LogTypeRef(const char *name) { theLogType = LogType::find(name); } }; /// LogConnectionProtocol, /// LogNetConnection, /// LogEventConnection, /// LogGhostConnection, /// LogNetInterface, /// LogPlatform, /// Logs a message of the specified type to the currently active LogConsumers. #define TNLLogMessage(logType, message) { static TNL::LogTypeRef theType(#logType); if(theType.theLogType->isEnabled) { TNL::LogType::setCurrent(theType.theLogType); logprintf("%s", message); TNL::LogType::setCurrent(NULL); } } /// Logs a printf-style variable argument message of the specified type to the currently active LogConsumers. #define TNLLogMessageV(logType, message) { static TNL::LogTypeRef theType(#logType); if(theType.theLogType->isEnabled) { TNL::LogType::setCurrent(theType.theLogType); logprintf message; TNL::LogType::setCurrent(NULL); } } #define TNLLogEnable(logType, enabled) { static TNL::LogTypeRef theType(#logType); theType.theLogType->isEnabled = enabled; } #define TNLLogBlock(logType, code) { static TNL::LogTypeRef theType(#logType); if(theType.theLogType->isEnabled) { TNL::LogType::setCurrent(theType.theLogType); { code } TNL::LogType::setCurrent(NULL); } } #else #define TNLLogMessage(logType, message) { } #define TNLLogMessageV(logType, message) { } #define TNLLogEnable(logType, enabled) { } #define TNLLogBlock(logType, code) { } #endif }; #endif --- NEW FILE: netInterface.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. [...1223 lines suppressed...] if(nonce != theParams.mNonce || serverNonce != theParams.mServerNonce) return; U32 decryptPos = stream->getBytePosition(); stream->setBytePosition(decryptPos); if(theParams.mUsingCrypto) { SymmetricCipher theCipher(theParams.mSharedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, decryptPos, &theCipher)) return; } stream->readString(reason); conn->setConnectionState(NetConnection::Disconnected); conn->onDisconnect(reason); removeConnection(conn); } }; --- NEW FILE: clientPuzzle.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "tnl.h" #include "tnlClientPuzzle.h" #include "tnlRandom.h" #include <mycrypt.h> namespace TNL { void ClientPuzzleManager::NonceTable::reset() { mChunker.freeBlocks(); mHashTableSize = Random::readI(MinHashTableSize, MaxHashTableSize) * 2 + 1; mHashTable = (Entry **) mChunker.alloc(sizeof(Entry *) * mHashTableSize); for(U32 i = 0; i < mHashTableSize; i++) mHashTable[i] = NULL; } bool ClientPuzzleManager::NonceTable::checkAdd(Nonce &theNonce) { U32 nonce1 = readU32FromBuffer(theNonce.data); U32 nonce2 = readU32FromBuffer(theNonce.data + 4); U64 fullNonce = (U64(nonce1) << 32) | nonce2; U32 hashIndex = U32(fullNonce % mHashTableSize); for(Entry *walk = mHashTable[hashIndex]; walk; walk = walk->mHashNext) if(walk->mNonce == theNonce) return false; Entry *newEntry = (Entry *) mChunker.alloc(sizeof(Entry)); newEntry->mNonce = theNonce; newEntry->mHashNext = mHashTable[hashIndex]; mHashTable[hashIndex] = newEntry; return true; } ClientPuzzleManager::ClientPuzzleManager() { mCurrentDifficulty = InitialPuzzleDifficulty; mLastUpdateTime = 0; mLastTickTime = 0; Random::read(mCurrentNonce.data, Nonce::NonceSize); Random::read(mLastNonce.data, Nonce::NonceSize); mCurrentNonceTable = new NonceTable; mLastNonceTable = new NonceTable; } ClientPuzzleManager::~ClientPuzzleManager() { delete mCurrentNonceTable; delete mLastNonceTable; } void ClientPuzzleManager::tick(U32 currentTime) { if(!mLastTickTime) mLastTickTime = currentTime; // use delta of last tick time and current time to manage puzzle // difficulty. // not yet implemented. // see if it's time to refresh the current puzzle: U32 timeDelta = currentTime - mLastUpdateTime; if(timeDelta > PuzzleRefreshTime) { mLastUpdateTime = currentTime; mLastNonce = mCurrentNonce; NonceTable *tempTable = mLastNonceTable; mLastNonceTable = mCurrentNonceTable; mCurrentNonceTable = tempTable; mLastNonce = mCurrentNonce; mCurrentNonceTable->reset(); Random::read(mCurrentNonce.data, Nonce::NonceSize); } } bool ClientPuzzleManager::checkOneSolution(U32 solution, Nonce &clientNonce, Nonce &serverNonce, U32 puzzleDifficulty, U32 clientIdentity) { U8 buffer[8]; writeU32ToBuffer(solution, buffer); writeU32ToBuffer(clientIdentity, buffer + 4); hash_state hashState; U8 hash[32]; sha256_init(&hashState); sha256_process(&hashState, buffer, sizeof(buffer)); sha256_process(&hashState, clientNonce.data, Nonce::NonceSize); sha256_process(&hashState, serverNonce.data, Nonce::NonceSize); sha256_done(&hashState, hash); U32 index = 0; while(puzzleDifficulty > 8) { if(hash[index]) return false; index++; puzzleDifficulty -= 8; } U8 mask = 0xFF << (8 - puzzleDifficulty); return (mask & hash[index]) == 0; } ClientPuzzleManager::ErrorCode ClientPuzzleManager::checkSolution(U32 solution, Nonce &clientNonce, Nonce &serverNonce, U32 puzzleDifficulty, U32 clientIdentity) { if(puzzleDifficulty != mCurrentDifficulty) return InvalidPuzzleDifficulty; NonceTable *theTable = NULL; if(serverNonce == mCurrentNonce) theTable = mCurrentNonceTable; else if(serverNonce == mLastNonce) theTable = mLastNonceTable; if(!theTable) return InvalidServerNonce; if(!checkOneSolution(solution, clientNonce, serverNonce, puzzleDifficulty, clientIdentity)) return InvalidSolution; if(!theTable->checkAdd(clientNonce)) return InvalidClientNonce; return Success; } bool ClientPuzzleManager::solvePuzzle(U32 *solution, Nonce &clientNonce, Nonce &serverNonce, U32 puzzleDifficulty, U32 clientIdentity) { U32 startTime = Platform::getRealMilliseconds(); U32 startValue = *solution; // Until we're done... for(;;) { // We do 100,000 attempts... U32 nextValue = startValue + 100000; for(;startValue < nextValue; startValue++) { if(checkOneSolution(startValue, clientNonce, serverNonce, puzzleDifficulty, clientIdentity)) { *solution = startValue; return true; } } // Then we check to see if we're out of time... if(Platform::getRealMilliseconds() - startTime > MaxSolutionComputeFragment) { *solution = startValue; return false; } } } }; --- NEW FILE: tnlDataChunker.h --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _TNL_DATACHUNKER_H_ #define _TNL_DATACHUNKER_H_ //---------------------------------------------------------------------------- namespace TNL { //---------------------------------------------------------------------------- /// Implements a chunked data allocater. /// /// Calling new/malloc all the time is a time consuming operation. Therefore, /// we provide the DataChunker, which allocates memory in blocks of /// chunkSize (by default 16k, see ChunkSize, though it can be set in /// the constructor), then doles it out as requested, in chunks of up to /// chunkSize in size. /// /// It will assert if you try to get more than ChunkSize bytes at a time, /// and it deals with the logic of allocating new blocks and giving out /// word-aligned chunks. /// /// Note that new/free/realloc WILL NOT WORK on memory gotten from the /// DataChunker. This also only grows (you can call freeBlocks to deallocate /// and reset things). class DataChunker { public: enum { ChunkSize = 16376 ///< Default size of each DataBlock page in the DataChunker }; private: /// DataBlock representation for each page of the DataChunker struct DataBlock { DataBlock *next; ///< linked list pointer to the next DataBlock for this chunker U8 *data; ///< allocated pointer for the base of this page S32 curIndex; ///< current allocation point within this DataBlock DataBlock(S32 size); ~DataBlock(); }; DataBlock *curBlock; ///< current page we're allocating data from. If the ///< data size request is greater than the memory space currently ///< available in the current page, a new page will be allocated. S32 chunkSize; ///< The size allocated for each page in the DataChunker public: void *alloc(S32 size); ///< allocate a pointer to memory of size bytes from the DataChunker void freeBlocks(); ///< free all pages currently allocated in the DataChunker DataChunker(S32 size=ChunkSize); ///< Construct a DataChunker with a page size of size bytes. ~DataChunker(); /// Swaps the memory allocated in one data chunker for another. This can be used to implement /// packing of memory stored in a DataChunker. void swap(DataChunker &d) { DataBlock *temp = d.curBlock; d.curBlock = curBlock; curBlock = temp; } }; //---------------------------------------------------------------------------- /// Templatized data chunker class with proper construction and destruction of its elements. /// /// DataChunker just allocates space. This subclass actually constructs/destructs the /// elements. This class is appropriate for more complex classes. template<class T> class ClassChunker: private DataChunker { S32 numAllocated; ///< number of elements currently allocated through this ClassChunker S32 elementSize; ///< the size of each element, or the size of a pointer, whichever is greater T *freeListHead; ///< a pointer to a linked list of freed elements for reuse public: ClassChunker(S32 size = DataChunker::ChunkSize) : DataChunker(size) { numAllocated = 0; elementSize = getMax(U32(sizeof(T)), U32(sizeof(T *))); freeListHead = NULL; } /// Allocates and properly constructs in place a new element. T *alloc() { numAllocated++; if(freeListHead == NULL) return constructInPlace(reinterpret_cast<T*>(DataChunker::alloc(elementSize))); T* ret = freeListHead; freeListHead = *(reinterpret_cast<T**>(freeListHead)); return constructInPlace(ret); } /// Properly destructs and freesan element allocated with the alloc method. void free(T* elem) { destructInPlace(elem); numAllocated--; *(reinterpret_cast<T**>(elem)) = freeListHead; freeListHead = elem; } }; }; #endif --- NEW FILE: tnlPlatform.h --- //----------------------------------------------------------------------------------- // // Torque Network Library // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _TNL_PLATFORM_H_ #define _TNL_PLATFORM_H_ #ifndef _TNL_TYPES_H_ #include "tnlTypes.h" #endif namespace TNL { /// Platform specific functionality is gathered here to enable easier porting. /// /// If you are embedding TNL in a complex application, you may want to replace /// these with hooks to your own code - for instance the alerts really should /// bring up an actual message box; currently they just emit a log item. namespace Platform { /// Prints a string to the OS specific debug log. void outputDebugString(const char *string); /// Stops the program in the debugger, if it is being debugged. void debugBreak(); /// Forces the program to exit immediately. /// /// @note This is probably a bit strong for a networking library. -- BJG void forceQuit(); /// Brings up a dialog window with a message and an "OK" button void AlertOK(const char *windowTitle, const char *message); /// Brings up a dialog window with the message, and "OK" and "Cancel" buttons bool AlertOKCancel(const char *windowTitle, const char *message); /// Brings up a dialog window with the message, and "Retry" and "Cancel" buttons bool AlertRetry(const char *windowTitle, const char *message); /// Elapsed time in milliseconds. /// /// Usually since last reboot, but it varies from platform to platform. It is /// guaranteed to always increase, however, up to the limit of a U32 - about /// 7 weeks worth of time. If you are developing a server you want to run for longer /// than that, prepared to see wraparounds. U32 getRealMilliseconds(); /// Returns a high-precision time value, in a platform-specific time value S64 getHighPrecisionTimerValue(); /// Converts a high precision timer delta into milliseconds F64 getHighPrecisionMilliseconds(S64 timerDelta); /// Put the process to sleep for the specified millisecond interva. void sleep(U32 msCount); /// checks the status of the memory allocation heap bool checkHeap(); }; #define TIME_BLOCK(name,block) { S64 st = Platform::getHighPrecisionTimerValue(); {block} S64 delta = Platform::getHighPrecisionTimerValue() - st; F64 ms = Platform::getHighPrecisionMilliseconds(delta); logprintf("Timer: %s Elapsed: %g ms", #name, ms); } #if defined (TNL_SUPPORTS_VC_INLINE_X86_ASM) #define TNL_DEBUGBREAK() { __asm { int 3 }; } #elif defined(TNL_SUPPORTS_GCC_INLINE_X86_ASM) #define TNL_DEBUGBREAK() { asm ( "int $3"); } #else /// Macro to do in-line debug breaks, used for asserts. Does inline assembly where appropriate #define TNL_DEBUGBREAK() Platform::debugBreak(); #endif #define TNL_CHECK_HEAP() { bool status = TNL::Platform::checkHeap(); if(!status) TNL_DEBUGBREAK(); } extern bool atob(const char *str); ///< String to boolean conversion. /// Printf into string with a buffer size. /// /// This will print into the specified string until the buffer size is reached. extern int dSprintf(char *buffer, U32 bufferSize, const char *format, ...); /// Vsprintf with buffer size argument. /// /// This will print into the specified string until the ... [truncated message content] |
Update of /cvsroot/opentnl/tnl/zap In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/zap Added Files: CTFGame.cpp CTFGame.h Makefile SweptEllipsoid.cpp SweptEllipsoid.h UI.cpp UI.h UIGame.cpp UIGame.h UIMenus.cpp UIMenus.h UINameEntry.cpp UINameEntry.h UIQueryServers.cpp UIQueryServers.h ZAP.vcproj barrier.cpp barrier.h game.cpp game.h gameConnection.cpp gameConnection.h gameLoader.cpp gameLoader.h gameNetInterface.cpp gameNetInterface.h gameObject.cpp gameObject.h gameType.cpp gameType.h gridDB.cpp gridDB.h item.cpp item.h main.cpp masterConnection.cpp masterConnection.h moveObject.cpp moveObject.h point.h projectile.cpp projectile.h sfx.cpp sfx.h ship.cpp ship.h sparkManager.cpp sparkManager.h teleporter.cpp teleporter.h winmain.cpp zap.dsp Log Message: Initial commit. --- NEW FILE: main.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "../tnl/tnl.h" #include "../tnl/tnlRandom.h" #include "../tnl/tnlGhostConnection.h" #include "../tnl/tnlNetInterface.h" #include "glutInclude.h" #include <stdarg.h> using namespace TNL; #include "UI.h" #include "UIGame.h" #include "UINameEntry.h" #include "UIMenus.h" #include "game.h" #include "gameNetInterface.h" #include "masterConnection.h" #include "sfx.h" namespace Zap { bool gQuit = false; bool gIsServer = false; const char *gHostName = "ZAP Game"; U32 gMaxPlayers = 128; Address gMasterAddress("127.0.0.1:28999"); void reshape(int nw, int nh) { UserInterface::windowWidth = nw; UserInterface::windowHeight = nh; } void motion(int x, int y) { if(UserInterface::current) UserInterface::current->onMouseDragged(x, y); } void passivemotion(int x, int y) { if(UserInterface::current) UserInterface::current->onMouseMoved(x, y); } void key(unsigned char key, int x, int y) { if(UserInterface::current) UserInterface::current->onKeyDown(key); } void keyup(unsigned char key, int x, int y) { if(UserInterface::current) UserInterface::current->onKeyUp(key); } void mouse(int button, int state, int x, int y) { static int mouseState=0; logprintf("button=%d state=%d", button, state); if(UserInterface::current) if(state==1 && !mouseState) { UserInterface::current->onMouseUp(x, y); mouseState = 0; } else { mouseState = state; UserInterface::current->onMouseDown(x, y); } } void specialkey(int key, int x, int y) { if(UserInterface::current) UserInterface::current->onSpecialKeyDown(key); } void specialkeyup(int key, int x, int y) { if(UserInterface::current) UserInterface::current->onSpecialKeyUp(key); } void idle() { static S64 lastTimer = Platform::getHighPrecisionTimerValue(); static F64 unusedFraction = 0; S64 currentTimer = Platform::getHighPrecisionTimerValue(); F64 timeElapsed = Platform::getHighPrecisionMilliseconds(currentTimer - lastTimer) + unusedFraction; U32 integerTime = timeElapsed; if(integerTime >= 10) { lastTimer = currentTimer; unusedFraction = timeElapsed - integerTime; if(UserInterface::current) UserInterface::current->idle(integerTime); if(gClientGame) gClientGame->idle(integerTime); if(gServerGame) gServerGame->idle(integerTime); if(gClientGame) glutPostRedisplay(); } // Sleep a bit so we don't saturate the system. Platform::sleep(1); } void dedicatedServerLoop() { for(;;) idle(); } void display(void) { if(UserInterface::current) UserInterface::current->render(); glFlush(); glutSwapBuffers(); } #include <stdio.h> class StdoutLogConsumer : public LogConsumer { public: void logString(const char *string) { printf("%s\r\n", string); } } gStdoutLogConsumer; void hostGame(bool dedicated, Address bindAddress) { gServerGame = new ServerGame(bindAddress, gMaxPlayers, gHostName); if(!dedicated) joinGame(Address(), false, true); } void joinGame(Address remoteAddress, bool isFromMaster, bool local) { if(isFromMaster && gClientGame->getConnectionToMaster()) { gClientGame->getConnectionToMaster()->requestArrangedConnection(remoteAddress); gGameUserInterface.activate(); } else { GameConnection *theConnection = new GameConnection(gClientGame); gClientGame->setConnectionToServer(theConnection); const char *name = gNameEntryUserInterface.getText(); if(!name[0]) name = "Playa"; theConnection->setPlayerName(name); if(local) theConnection->connectLocal(gClientGame->getNetInterface(), gServerGame->getNetInterface()); else theConnection->connect(gClientGame->getNetInterface(), remoteAddress); gGameUserInterface.activate(); } } void endGame() { if(gClientGame && gClientGame->getConnectionToMaster()) gClientGame->getConnectionToMaster()->cancelArrangedConnectionAttempt(); if(gClientGame && gClientGame->getConnectionToServer()) gClientGame->getConnectionToServer()->disconnect(""); delete gServerGame; gServerGame = NULL; } void onExit() { endGame(); SFXObject::shutdown(); } }; using namespace Zap; int main(int argc, char **argv) { TNLLogEnable(LogNetInterface, true); bool hasClient = true; bool hasServer = false; bool connectLocal = false; bool connectRemote = false; bool nameSet = false; Address connectAddress; Address bindAddress(IPProtocol, Address::Any, 28000); U32 maxPlayers = 128; for(S32 i = 1; i < argc;i+=2) { bool hasAdditionalArg = (i != argc - 1); if(!stricmp(argv[i], "-server")) { hasServer = true; connectLocal = true; if(hasAdditionalArg) bindAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-connect")) { connectRemote = true; if(hasAdditionalArg) connectAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-master")) { if(hasAdditionalArg) gMasterAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-dedicated")) { hasClient = false; hasServer = true; if(hasAdditionalArg) bindAddress.set(argv[i+1]); } else if(!stricmp(argv[i], "-name")) { if(hasAdditionalArg) { nameSet = true; gNameEntryUserInterface.setText(argv[i+1]); } } else if(!stricmp(argv[i], "-hostname")) { if(hasAdditionalArg) gHostName = argv[i+1]; } else if(!stricmp(argv[i], "-maxplayers")) { if(hasAdditionalArg) gMaxPlayers = atoi(argv[i+1]); } } if(hasClient) gClientGame = new ClientGame(Address()); if(hasServer) hostGame(hasClient == false, bindAddress); else if(connectRemote) joinGame(connectAddress, false); if(!connectLocal && !connectRemote) { if(!nameSet) gNameEntryUserInterface.activate(); else gMainMenuUserInterface.activate(); } if(hasClient) { SFXObject::init(); glutInitWindowSize(800, 600); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB); glutCreateWindow("ZAP II - The Return"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutPassiveMotionFunc(passivemotion); glutMotionFunc(passivemotion); glutKeyboardFunc(key); glutKeyboardUpFunc(keyup); glutSpecialFunc(specialkey); glutSpecialUpFunc(specialkeyup); glutMouseFunc(mouse); glutIdleFunc(idle); glutSetCursor(GLUT_CURSOR_NONE); glMatrixMode(GL_PROJECTION); glOrtho(0, 800, 600, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(400, 300, 0); atexit(endGame); glutMainLoop(); } else { dedicatedServerLoop(); } return 0; } --- NEW FILE: gameType.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "gameType.h" #include "ship.h" #include "UIGame.h" #include "gameNetInterface.h" namespace Zap { TNL_IMPLEMENT_NETOBJECT(GameType); GameType::GameType() { mNetFlags.set(Ghostable); } void GameType::processArguments(S32 argc, const char **argv) { } void GameType::onAddedToGame(Game *theGame) { theGame->setGameType(this); setInterface(theGame->getNetInterface()); if(!isGhost()) setScopeAlways(); } bool GameType::processLevelItem(S32 argc, const char **argv) { if(!stricmp(argv[0], "Team")) { if(argc < 5) return false; Team t; t.numPlayers = 0; t.name.set(argv[1]); t.color.read(argv + 2); mTeams.push_back(t); } else if(!stricmp(argv[0], "Spawn")) { if(argc < 4) return false; S32 teamIndex = atoi(argv[1]); Point p; p.read(argv + 2); p *= getGame()->getGridSize(); if(teamIndex >= 0 && teamIndex < mTeams.size()) mTeams[teamIndex].spawnPoints.push_back(p); } else return false; return true; } S32 GameType::findClientIndexByConnection(GameConnection *theConnection) { for(S32 clientIndex = 0; clientIndex < mClientList.size(); clientIndex++) if(mClientList[clientIndex].clientConnection == theConnection) return clientIndex; return -1; } S32 GameType::findClientIndexById(U32 clientId) { for(S32 clientIndex = 0; clientIndex < mClientList.size(); clientIndex++) if(mClientList[clientIndex].clientId == clientId) return clientIndex; return -1; } void GameType::spawnShip(GameConnection *theClient) { S32 clientIndex = findClientIndexByConnection(theClient); S32 teamIndex = mClientList[clientIndex].teamId; Point spawnPoint; S32 spawnIndex = Random::readI() % mTeams[teamIndex].spawnPoints.size(); spawnPoint = mTeams[teamIndex].spawnPoints[spawnIndex]; Ship *newShip = new Ship(spawnPoint, mTeams[teamIndex].color); newShip->addToGame(getGame()); theClient->setControlObject(newShip); } void GameType::serverAddClient(GameConnection *theClient) { ClientRef cref; cref.clientId = theClient->mClientId; cref.name = theClient->playerName; cref.clientConnection = theClient; U32 minPlayers = mTeams[0].numPlayers; S32 minTeamIndex = 0; for(S32 i = 1; i < mTeams.size(); i++) { if(mTeams[i].numPlayers < minPlayers) { minTeamIndex = i; minPlayers = mTeams[i].numPlayers; } } cref.teamId = minTeamIndex; mClientList.push_back(cref); mTeams[cref.teamId].numPlayers++; s2cAddClient(cref.clientId, cref.name, false); s2cClientJoinedTeam(cref.clientId, cref.teamId); spawnShip(theClient); } void GameType::controlObjectForClientKilled(GameConnection *theClient) { spawnShip(theClient); } void GameType::addClientGameMenuOptions(Vector<const char *> &menuOptions) { if(mTeams.size() > 1) menuOptions.push_back("CHANGE TEAMS"); } void GameType::processClientGameMenuOption(U32 index) { if(index == 0) c2sChangeTeams(); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cAddClient, (U32 id, StringTableEntry name, bool isMyClient), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { ClientRef cref; cref.clientId = id; cref.name = name; cref.teamId = 0; mClientList.push_back(cref); if(isMyClient) mThisClientId = id; gGameUserInterface.displayMessage(Color(0.6f, 0.6f, 0.8f), "%s joined the game.", name.getString()); } void GameType::serverRemoveClient(GameConnection *theClient) { S32 clientIndex = findClientIndexByConnection(theClient); mTeams[mClientList[clientIndex].teamId].numPlayers--; mClientList.erase(clientIndex); GameObject *theControlObject = theClient->getControlObject(); if(theControlObject) delete theControlObject; s2cRemoveClient(theClient->mClientId); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cRemoveClient, (U32 id), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { S32 clientIndex = findClientIndexById(id); mClientList.erase(clientIndex); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cAddTeam, (StringTableEntry teamName, F32 r, F32 g, F32 b), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { Team team; team.name = teamName; team.color.r = r; team.color.g = g; team.color.b = b; mTeams.push_back(team); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cSetTeamScore, (U32 teamIndex, U32 score), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { mTeams[teamIndex].score = score; } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cClientJoinedTeam, (U32 clientId, U32 teamIndex), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { S32 clientIndex = findClientIndexById(clientId); mClientList[clientIndex].teamId = teamIndex; gGameUserInterface.displayMessage(Color(0.6f, 0.6f, 0.8f), "%s joined team %s.", mClientList[clientIndex].name.getString(), mTeams[teamIndex].name.getString()); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, c2sChangeTeams, (), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhostParent, 0) { if(mTeams.size() <= 1) return; GameConnection *source = (GameConnection *) NetObject::getRPCSourceConnection(); S32 clientIndex = findClientIndexByConnection(source); // destroy the old ship GameObject *co = source->getControlObject(); if(co) getGame()->deleteObject(co); U32 newTeamId = (mClientList[clientIndex].teamId + 1) % mTeams.size(); mClientList[clientIndex].teamId = newTeamId; s2cClientJoinedTeam(mClientList[clientIndex].clientId, newTeamId); spawnShip(source); } void GameType::onGhostAvailable(GhostConnection *theConnection) { NetObject::setRPCDestConnection(theConnection); for(S32 i = 0; i < mTeams.size(); i++) { s2cAddTeam(mTeams[i].name, mTeams[i].color.r, mTeams[i].color.g, mTeams[i].color.b); s2cSetTeamScore(i, mTeams[i].score); } // add all the client and team information for(S32 i = 0; i < mClientList.size(); i++) { s2cAddClient(mClientList[i].clientId, mClientList[i].name, mClientList[i].clientConnection == theConnection); s2cClientJoinedTeam(mClientList[i].clientId, mClientList[i].teamId); } NetObject::setRPCDestConnection(NULL); } TNL_IMPLEMENT_NETOBJECT_RPC(GameType, c2sSendChat, (bool global, const char *message), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhostParent, 0) { GameConnection *source = (GameConnection *) getRPCSourceConnection(); RefPtr<NetEvent> theEvent = TNL_RPC_CONSTRUCT_NETEVENT(this, s2cDisplayChatMessage, (global, source->playerName, message)); for(S32 i = 0; i < mClientList.size(); i++) mClientList[i].clientConnection->postNetEvent(theEvent); } extern Color gGlobalChatColor; extern Color gTeamChatColor; TNL_IMPLEMENT_NETOBJECT_RPC(GameType, s2cDisplayChatMessage, (bool global, StringTableEntry clientName, const char *message), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { Color theColor = global ? gGlobalChatColor : gTeamChatColor; gGameUserInterface.displayMessage(theColor, "%s: %s", clientName.getString(), message); } }; --- NEW FILE: gameLoader.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "gameLoader.h" #include "../tnl/tnlPlatform.h" #include <stdio.h> namespace Zap { enum { MaxArgc = 128, MaxArgLen = 100, }; static char *argv[MaxArgc]; static char argv_buffer[MaxArgc][MaxArgLen]; static int argc; static int argLen = 0; static const char *argString; inline char getNextChar() { while(*argString == '\r') argString++; return *argString++; } inline void addCharToArg(char c) { if(argc < MaxArgc && argLen < MaxArgLen-1) { argv[argc][argLen] = c; argLen++; } } inline void addArg() { if(argc < MaxArgc) { argv[argc][argLen] = 0; argc++; argLen = 0; } } int parseArgs(const char *string, ServerGame *g) { int numObjects = 0; argc = 0; argLen = 0; argString = string; char c; for(U32 i = 0; i < MaxArgc; i++) argv[i] = argv_buffer[i]; stateEatingWhitespace: c = getNextChar(); if(c == ' ' || c == '\t') goto stateEatingWhitespace; if(c == '\n' || !c) goto stateLineParseDone; if(c == '\"') goto stateReadString; if(c == '#') goto stateEatingComment; stateAddCharToIdent: addCharToArg(c); c = getNextChar(); if(c == ' ' || c == '\t') { addArg(); goto stateEatingWhitespace; } if(c == '\n' || !c) { addArg(); goto stateLineParseDone; } if(c == '\"') { addArg(); goto stateReadString; } goto stateAddCharToIdent; stateReadString: c = getNextChar(); if(c == '\"') { addArg(); goto stateEatingWhitespace; } if(c == '\n' || !c) { addArg(); goto stateLineParseDone; } if(c == '\\') { c = getNextChar(); if(c == 'n') { addCharToArg('\n'); goto stateReadString; } if(c == 't') { addCharToArg('\t'); goto stateReadString; } if(c == '\\') { addCharToArg('\\'); goto stateReadString; } if(c == '\n' || !c) { addArg(); goto stateLineParseDone; } } addCharToArg(c); goto stateReadString; stateEatingComment: c = getNextChar(); if(c != '\n' && c) goto stateEatingComment; stateLineParseDone: if(argc) g->processLevelLoadLine(argc, (const char **) argv); argc = 0; argLen = 0; if(c) goto stateEatingWhitespace; return numObjects; } void GameLoader::initGameFromFile(ServerGame *g, const char *file) { FILE *f = fopen(file, "r"); if(!f) return; char fileData[32768]; size_t bytesRead = fread(fileData, 1, sizeof(fileData), f); fileData[bytesRead] = 0; parseArgs(fileData, g); fclose(f); } }; --- NEW FILE: UI.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _UI_H_ #define _UI_H_ #include "../tnl/tnl.h" using namespace TNL; namespace Zap { class UserInterface { public: static UserInterface *current; static F32 windowWidth, windowHeight, canvasWidth, canvasHeight; virtual void render(); virtual void idle(U32 timeDelta); virtual void onActivate(); void activate(); virtual void onMouseDown(S32 x, S32 y); virtual void onMouseUp(S32 x, S32 y); virtual void onMouseMoved(S32 x, S32 y); virtual void onMouseDragged(S32 x, S32 y); virtual void onKeyDown(U32 key); virtual void onKeyUp(U32 key); virtual void onSpecialKeyDown(U32 key); virtual void onSpecialKeyUp(U32 key); static void drawString(S32 x, S32 y, S32 size, const char *string); static void drawCenteredString(S32 y, S32 size, const char *string); static void drawStringf(S32 x, S32 y, S32 size, const char *fmt, ...); static U32 getStringWidth(S32 size, const char *string, U32 len = 0); }; }; #endif --- NEW FILE: UIQueryServers.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "UIQueryServers.h" #include "UIMenus.h" #include "tnlRandom.h" #include "masterConnection.h" #include "gameNetInterface.h" #include "glutInclude.h" #include "game.h" namespace Zap { QueryServersUserInterface gQueryServersUserInterface; void QueryServersUserInterface::onActivate() { servers.clear(); sortColumn = 0; pendingPings = 0; pendingQueries = 0; sortAscending = true; mNonce.getRandom(); logprintf("pinging broadcast servers..."); Address broadcastAddress(IPProtocol, Address::Broadcast, 28000); broadcastPingSendTime = Platform::getRealMilliseconds(); gClientGame->getNetInterface()->sendPing(broadcastAddress, mNonce); if(gClientGame->getConnectionToMaster()) gClientGame->getConnectionToMaster()->startGameTypesQuery(); } void QueryServersUserInterface::addPingServers(const Vector<IPAddress> &ipList) { for(S32 i = 0; i < ipList.size(); i++) { ServerRef s; s.state = ServerRef::Start; s.id = ++lastUsedServerId; s.sendNonce.getRandom(); s.serverAddress.set(ipList[i]); s.sendCount = 0; s.pingTime = 9999; s.playerCount = s.maxPlayers = -1; s.isFromMaster = true; strcpy(s.serverName, "Internet Server"); servers.push_back(s); } } void QueryServersUserInterface::gotPingResponse(const Address &theAddress, const Nonce &theNonce, U32 clientIdentityToken) { // see if this ping is a server from the local broadcast ping: if(mNonce == theNonce) { for(S32 i = 0; i < servers.size(); i++) if(servers[i].sendNonce == theNonce && servers[i].serverAddress == theAddress) return; // it was from a local ping ServerRef s; s.pingTime = Platform::getRealMilliseconds() - broadcastPingSendTime; s.state = ServerRef::ReceivedPing; s.id = ++lastUsedServerId; s.sendNonce = theNonce; s.identityToken = clientIdentityToken; s.serverAddress = theAddress; s.sendCount = 0; s.playerCount = -1; s.maxPlayers = -1; s.isFromMaster = false; strcpy(s.serverName, "LAN Server"); servers.push_back(s); return; } // see if this ping is in the list: for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.sendNonce == theNonce && s.serverAddress == theAddress && s.state == ServerRef::SentPing) { s.pingTime = Platform::getRealMilliseconds() - s.lastSendTime; s.state = ServerRef::ReceivedPing; s.identityToken = clientIdentityToken; pendingPings--; break; } } shouldSort = true; } void QueryServersUserInterface::gotQueryResponse(const Address &theAddress, const Nonce &clientNonce, const char *serverName, U32 playerCount, U32 maxPlayers) { for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.sendNonce == clientNonce && s.serverAddress == theAddress && s.state == ServerRef::SentQuery) { s.playerCount = playerCount; s.maxPlayers = maxPlayers; dSprintf(s.serverName, sizeof(s.serverName), "%s", serverName); s.state = ServerRef::ReceivedQuery; pendingQueries--; } } shouldSort = true; // find this } void QueryServersUserInterface::idle(U32 t) { U32 time = Platform::getRealMilliseconds(); for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.state == ServerRef::SentPing && (time - s.lastSendTime) > PingQueryTimeout) { s.state = ServerRef::Start; pendingPings--; } else if(s.state == ServerRef::SentQuery && (time - s.lastSendTime) > PingQueryTimeout) { s.state = ServerRef::ReceivedPing; pendingQueries--; } } if(pendingPings < MaxPendingPings) { for(S32 i = 0; i < servers.size() ; i++) { ServerRef &s = servers[i]; if(s.state == ServerRef::Start) { s.sendCount++; if(s.sendCount > PingQueryRetryCount) { s.pingTime = 999; strcpy(s.serverName, "PingTimedOut"); s.playerCount = 0; s.maxPlayers = 0; s.state = ServerRef::ReceivedQuery; shouldSort = true; } else { s.state = ServerRef::SentPing; s.lastSendTime = time; s.sendNonce.getRandom(); gClientGame->getNetInterface()->sendPing(s.serverAddress, s.sendNonce); pendingPings++; if(pendingPings >= MaxPendingPings) break; } } } } if(pendingPings == 0 && (pendingQueries < MaxPendingQueries)) { for(S32 i = 0; i < servers.size(); i++) { ServerRef &s = servers[i]; if(s.state == ServerRef::ReceivedPing) { s.sendCount++; if(s.sendCount > PingQueryRetryCount) { strcpy(s.serverName, "QueryTimedOut"); s.playerCount = s.maxPlayers = 0; s.state = ServerRef::ReceivedQuery; shouldSort = true; } else { s.state = ServerRef::SentQuery; s.lastSendTime = time; gClientGame->getNetInterface()->sendQuery(s.serverAddress, s.sendNonce, s.identityToken); pendingQueries++; if(pendingQueries >= MaxPendingQueries) break; } } } } } QueryServersUserInterface::QueryServersUserInterface() { /* for(U32 i = 0;i < 512; i++) { ServerRef s; dSprintf(s.serverName, MaxServerNameLen, "Svr%8x", Random::readI()); s.id = i; s.pingTime = Random::readF() * 512; s.serverAddress.port = 28000; s.serverAddress.netNum[0] = Random::readI(); s.maxPlayers = Random::readF() * 16 + 8; s.playerCount = Random::readF() * s.maxPlayers; servers.push_back(s); }*/ lastUsedServerId = 0; sortColumn = 0; lastSortColumn = 0; sortAscending = true; columns.push_back(ColumnInfo("SERVER NAME", 3)); columns.push_back(ColumnInfo("PING", 300)); columns.push_back(ColumnInfo("PLAYERS", 420)); columns.push_back(ColumnInfo("ADDRESS", 550)); selectedId = 0xFFFFFF; sort(); shouldSort = false; } S32 QueryServersUserInterface::findSelectedIndex() { for(S32 i = 0; i < servers.size(); i++) if(servers[i].id == selectedId) return i; return -1; } void QueryServersUserInterface::render() { if(shouldSort) { shouldSort = false; sort(); } glViewport(0, 0, windowWidth, windowHeight); glClearColor(0, 0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1,1,1); drawCenteredString(0, 25, "CHOOSE A SERVER TO JOIN:"); drawCenteredString(560, 18, "UP, DOWN, PAGEUP, PAGEDOWN to select, ENTER to join."); drawCenteredString(580, 18, "LEFT, RIGHT select sort column, SPACE to sort. ESC exits."); for(S32 i = 0; i < columns.size(); i++) { drawString(columns[i].xStart, 35, 24, columns[i].name); } S32 x1 = columns[sortColumn].xStart - 2; S32 x2; if(sortColumn == columns.size() - 1) x2 = 799; else x2 = columns[sortColumn+1].xStart - 6; glBegin(GL_LINE_LOOP); glVertex2f(x1, 33); glVertex2f(x2, 33); glVertex2f(x2, 61); glVertex2f(x1, 61); glEnd(); if(servers.size()) { S32 selectedIndex = findSelectedIndex(); if(selectedIndex == -1) selectedIndex = 0; S32 firstServer = selectedIndex - ServersAboveBelow; S32 lastServer = selectedIndex + ServersAboveBelow; if(firstServer < 0) { lastServer -= firstServer; firstServer = 0; } if(lastServer >= servers.size()) { lastServer = servers.size() - 1; } for(S32 i = firstServer; i <= lastServer; i++) { U32 y = 65 + (i - firstServer) * 23; U32 fontSize = 20; if(i == selectedIndex) { glColor3f(0,0,0.4); glBegin(GL_POLYGON); glVertex2f(0, y); glVertex2f(799, y); glVertex2f(799, y + 22); glVertex2f(0, y + 22); glEnd(); glColor3f(0,0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(0, y); glVertex2f(799, y); glVertex2f(799, y + 22); glVertex2f(0, y + 22); glEnd(); } glColor3f(1,1,1); drawString(columns[0].xStart, y, fontSize, servers[i].serverName); if(servers[i].pingTime < 100) glColor3f(0,1,0); else if(servers[i].pingTime < 250) glColor3f(1,1,0); else glColor3f(1,0,0); drawStringf(columns[1].xStart, y, fontSize, "%d", servers[i].pingTime); if(servers[i].playerCount == servers[i].maxPlayers) glColor3f(1,0,0); else if(servers[i].playerCount == 0) glColor3f(1,1,0); else glColor3f(0,1,0); if(servers[i].playerCount < 0) drawString(columns[2].xStart, y, fontSize, "?? / ??"); else drawStringf(columns[2].xStart, y, fontSize, "%d / %d", servers[i].playerCount, servers[i].maxPlayers); glColor3f(1,1,1); drawString(columns[3].xStart, y, fontSize, servers[i].serverAddress.toString()); } } glColor3f(0.7, 0.7, 0.7); for(S32 i = 1; i < columns.size(); i++) { glBegin(GL_LINES); glVertex2f(columns[i].xStart - 4, 35); glVertex2f(columns[i].xStart - 4, 550); glEnd(); } glBegin(GL_LINES); glVertex2f(0, 62); glVertex2f(800, 62); glEnd(); } void QueryServersUserInterface::onKeyDown(U32 key) { switch(key) { case ' ': if(lastSortColumn == sortColumn) sortAscending = !sortAscending; else { lastSortColumn = sortColumn; sortAscending = true; } sort(); break; case '\r': { S32 currentIndex = findSelectedIndex(); if(currentIndex == -1) currentIndex = 0; if(servers.size() > currentIndex) { // join the selected game joinGame(servers[currentIndex].serverAddress, servers[currentIndex].isFromMaster, false); // and clear out the servers, so that we don't do any more pinging servers.clear(); } } break; case 27: gMainMenuUserInterface.activate(); break; } } void QueryServersUserInterface::onSpecialKeyDown(U32 key) { if(!servers.size()) return; S32 currentIndex = findSelectedIndex(); if(currentIndex == -1) currentIndex = 0; switch(key) { case GLUT_KEY_PAGE_UP: currentIndex -= ServersPerScreen - 1; break; case GLUT_KEY_PAGE_DOWN: currentIndex += ServersPerScreen - 1; break; case GLUT_KEY_UP: currentIndex--; break; case GLUT_KEY_DOWN: currentIndex++; break; case GLUT_KEY_LEFT: sortColumn--; if(sortColumn < 0) sortColumn = 0; break; case GLUT_KEY_RIGHT: sortColumn++; if(sortColumn >= columns.size()) sortColumn = columns.size() - 1; break; } if(currentIndex < 0) currentIndex = 0; if(currentIndex >= servers.size()) currentIndex = servers.size() - 1; selectedId = servers[currentIndex].id; } static S32 QSORT_CALLBACK compareFuncName(const void *a, const void *b) { return stricmp(((QueryServersUserInterface::ServerRef *) a)->serverName, ((QueryServersUserInterface::ServerRef *) b)->serverName); } static S32 QSORT_CALLBACK compareFuncPing(const void *a, const void *b) { return S32(((QueryServersUserInterface::ServerRef *) a)->pingTime - ((QueryServersUserInterface::ServerRef *) b)->pingTime); } static S32 QSORT_CALLBACK compareFuncPlayers(const void *a, const void *b) { S32 pc = S32(((QueryServersUserInterface::ServerRef *) a)->playerCount - ((QueryServersUserInterface::ServerRef *) b)->playerCount); if(pc) return pc; return S32(((QueryServersUserInterface::ServerRef *) a)->maxPlayers - ((QueryServersUserInterface::ServerRef *) b)->maxPlayers); } static S32 QSORT_CALLBACK compareFuncAddress(const void *a, const void *b) { return S32(((QueryServersUserInterface::ServerRef *) a)->serverAddress.netNum[0] - ((QueryServersUserInterface::ServerRef *) b)->serverAddress.netNum[0]); } void QueryServersUserInterface::sort() { switch(sortColumn) { case 0: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncName); break; case 1: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncPing); break; case 2: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncPlayers); break; case 3: qsort(servers.address(), servers.size(), sizeof(ServerRef), compareFuncAddress); break; } if(!sortAscending) { S32 size = servers.size() / 2; S32 totalSize = servers.size(); for(S32 i = 0; i < size; i++) { ServerRef temp = servers[i]; servers[i] = servers[totalSize - i - 1]; servers[totalSize - i - 1] = temp; } } } }; --- NEW FILE: UIGame.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "gameConnection.h" #include "game.h" #include "UIGame.h" #include "UIMenus.h" #include "gameType.h" #include <stdarg.h> #include "glutInclude.h" namespace Zap { GameUserInterface gGameUserInterface; Color gGlobalChatColor(0.9, 0.9, 0.9); Color gTeamChatColor(0, 1, 0); GameUserInterface::GameUserInterface() { mCurrentMode = PlayMode; mChatLastBlinkTime = 0; memset(mChatBuffer, 0, sizeof(mChatBuffer)); mChatBlink = false; for(U32 i = 0; i < 4; i++) mDisplayMessage[i][0] = 0; } void GameUserInterface::displayMessage(Color theColor, const char *format, ...) { for(S32 i = MessageDisplayCount - 1; i > 0; i--) { strcpy(mDisplayMessage[i], mDisplayMessage[i-1]); mDisplayMessageColor[i] = mDisplayMessageColor[i-1]; } va_list args; va_start(args, format); dVsprintf(mDisplayMessage[0], sizeof(mDisplayMessage[0]), format, args); mDisplayMessageColor[0] = theColor; mDisplayMessageTimer = DisplayMessageTimeout; } void GameUserInterface::idle(U32 timeDelta) { if(timeDelta > mDisplayMessageTimer) { mDisplayMessageTimer = DisplayMessageTimeout; for(S32 i = MessageDisplayCount - 1; i > 0; i--) { strcpy(mDisplayMessage[i], mDisplayMessage[i-1]); mDisplayMessageColor[i] = mDisplayMessageColor[i-1]; } mDisplayMessage[0][0] = 0; } else mDisplayMessageTimer -= timeDelta; if(mCurrentMode == ChatMode) { mChatLastBlinkTime += timeDelta; if(mChatLastBlinkTime > ChatBlinkTime) { mChatBlink = !mChatBlink; mChatLastBlinkTime = 0; } } } void GameUserInterface::render() { glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(0.0, 0.0, 0.0); glViewport(0, 0, windowWidth, windowHeight); glClearColor(0, 0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); if(!gClientGame->isConnectedToServer()) { glColor3f(1,1,1); drawCenteredString(290, 30, "Connecting to server..."); drawCenteredString(330, 20, "Press <ESC> to abort"); } glTranslatef(400, 300, 0); if(gClientGame) gClientGame->render(); // draw the reticle glPushMatrix(); glTranslatef(mMousePoint.x, mMousePoint.y, 0); glColor3f(1, 0, 0); glBegin(GL_LINE_LOOP); glVertex2f(-8, -6); glVertex2f(-6, -8); glVertex2f(-3, -3); glEnd(); glBegin(GL_LINE_LOOP); glVertex2f( 8, 6); glVertex2f( 6, 8); glVertex2f( 3, 3); glEnd(); glBegin(GL_LINE_LOOP); //glColor3f(1, 0, 0); glVertex2f(8, -6); glVertex2f(6, -8); glVertex2f(3, -3); glEnd(); glBegin(GL_LINE_LOOP); glVertex2f(-8, 6); glVertex2f(-6, 8); glVertex2f(-3, 3); glEnd(); glPopMatrix(); //glMatrixMode(GL_PROJECTION); //glOrtho(0, windowWidth, windowHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glColor3f(1,1,1); U32 y = 5; for(S32 i = 3; i >= 0; i--) { if(mDisplayMessage[i][0]) { glColor3f(mDisplayMessageColor[i].r, mDisplayMessageColor[i].g, mDisplayMessageColor[i].b); drawString(5, y, 20, mDisplayMessage[i]); y += 24; } } GameType *theGameType = gClientGame->getGameType(); if(theGameType) theGameType->renderInterfaceOverlay(); if(mCurrentMode == ChatMode) { const char *promptStr; if(mCurrentChatType == TeamChat) { glColor3f(gTeamChatColor.r, gTeamChatColor.g, gTeamChatColor.b); promptStr = "(Team): "; } else { glColor3f(gGlobalChatColor.r, gGlobalChatColor.g, gGlobalChatColor.b); promptStr = "(Global): "; } U32 width = getStringWidth(20, promptStr); drawString(5, 100, 20, promptStr); drawString(5 + width, 100, 20, mChatBuffer); if(mChatBlink) drawString(5 + width + getStringWidth(20, mChatBuffer, mChatCursorPos), 100, 20, "_"); } #if 0 // some code for outputting the RTT for the connection // useful for testing lag code GameConnection *con = gClientGame->getConnectionToServer(); if(con) { drawStringf(10, 550, 30, "%0.2g", con->getRoundTripTime()); } #endif } void GameUserInterface::onMouseDragged(S32 x, S32 y) { onMouseMoved(x, y); } void GameUserInterface::onMouseMoved(S32 x, S32 y) { mMousePoint = Point(x - windowWidth / 2, y - windowHeight / 2); mMousePoint.x *= canvasWidth / windowWidth; mMousePoint.y *= canvasHeight / windowHeight; mCurrentMove.angle = atan2(mMousePoint.x, mMousePoint.y); } void GameUserInterface::onMouseDown(S32 x, S32 y) { mCurrentMove.fire = true; } void GameUserInterface::onMouseUp(S32 x, S32 y) { mCurrentMove.fire = false; } void GameUserInterface::onKeyDown(U32 key) { if(mCurrentMode == PlayMode) { mCurrentChatType = GlobalChat; switch(key) { case 'w': case 'W': mCurrentMove.up = 1.0; break; case 'a': case 'A': mCurrentMove.left = 1.0; break; case 's': case 'S': mCurrentMove.down = 1.0; break; case 'd': case 'D': mCurrentMove.right = 1.0; break; case 27: if(!gClientGame->isConnectedToServer()) { endGame(); gMainMenuUserInterface.activate(); } else gGameMenuUserInterface.activate(); break; case 't': case 'T': mCurrentChatType = TeamChat; case 'g': case 'G': mChatLastBlinkTime = 0; mChatBlink = true; mCurrentMode = ChatMode; mCurrentMove.up = mCurrentMove.left = mCurrentMove.right = mCurrentMove.down = 0; break; } } else if(mCurrentMode == ChatMode) { if(key == '\r') issueChat(); else if(key == 8) { // backspace key if(mChatCursorPos > 0) { mChatCursorPos--; for(U32 i = mChatCursorPos; mChatBuffer[i]; i++) mChatBuffer[i] = mChatBuffer[i+1]; } } else if(key == 27) { cancelChat(); } else { for(U32 i = sizeof(mChatBuffer) - 2; i > mChatCursorPos; i--) mChatBuffer[i] = mChatBuffer[i-1]; if(mChatCursorPos < sizeof(mChatBuffer) - 2) { mChatBuffer[mChatCursorPos] = key; mChatCursorPos++; } } } } Move *GameUserInterface::getCurrentMove() { if(!OptionsMenuUserInterface::controlsRelative) return &mCurrentMove; else { mTransformedMove = mCurrentMove; Point moveDir(mCurrentMove.right - mCurrentMove.left, mCurrentMove.up - mCurrentMove.down); Point angleDir(sin(mCurrentMove.angle), cos(mCurrentMove.angle)); Point rightAngleDir(-angleDir.y, angleDir.x); Point newMoveDir = angleDir * moveDir.y + rightAngleDir * moveDir.x; if(newMoveDir.x > 0) { mTransformedMove.right = newMoveDir.x; mTransformedMove.left = 0; } else { mTransformedMove.right = 0; mTransformedMove.left = -newMoveDir.x; } if(newMoveDir.y > 0) { mTransformedMove.down = newMoveDir.y; mTransformedMove.up = 0; } else { mTransformedMove.down = 0; mTransformedMove.up = -newMoveDir.y; } if(mTransformedMove.right > 1) mTransformedMove.right = 1; if(mTransformedMove.left > 1) mTransformedMove.left = 1; if(mTransformedMove.up > 1) mTransformedMove.up = 1; if(mTransformedMove.down > 1) mTransformedMove.down = 1; return &mTransformedMove; } } void GameUserInterface::cancelChat() { memset(mChatBuffer, 0, sizeof(mChatBuffer)); mChatCursorPos = 0; mCurrentMode = PlayMode; } void GameUserInterface::issueChat() { if(mChatBuffer[0]) { GameType *gt = gClientGame->getGameType(); if(gt) gt->c2sSendChat(mCurrentChatType == GlobalChat, mChatBuffer); } cancelChat(); } void GameUserInterface::onKeyUp(U32 key) { if(mCurrentMode == PlayMode) { switch(key) { case 'w': case 'W': mCurrentMove.up = 0; break; case 'a': case 'A': mCurrentMove.left = 0; break; case 's': case 'S': mCurrentMove.down = 0; break; case 'd': case 'D': mCurrentMove.right = 0; break; } } else if(mCurrentMode == ChatMode) { } } }; --- NEW FILE: SweptEllipsoid.h --- // Example code for: Collision Detection with Swept Spheres and Ellipsoids // See: http://www.three14.demon.nl/sweptellipsoid/SweptEllipsoid.pdf // // Copyright (C) 2003 Jorrit Rouwe // // 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. // // This is free software, you can do with it what you want. // // This file contains the main swept sphere / ellipsoid intersection tests. // // Please have a look at the notes. They indicate obvious places for optimization // if you are using a swept ellipsoid against a large number of polygons. // this file has been modified by Mark Frohnmayer: // removed swept ellipsoid routine // removed swept sphere // removed references to vector2 and replaced with Point // added in prototypes for circle collisions #ifndef _SWEPT_ELLIPSOID_H_ #define _SWEPT_ELLIPSOID_H_ namespace Zap { //#include "Vector2.h" //#include "Plane.h" // Test between a polygon and a swept sphere with radius inRadius moving from inBegin to inBegin + inDelta // If there is an intersection the intersection position is returned in outPoint and the center of the // sphere is at inBegin + outFraction * inDelta when it collides //bool PolygonSweptSphereIntersect(const Plane &inPlane, const Vector2 *inVertices, int inNumVertices, const Vector3 &inBegin, const Vector3 &inDelta, float inRadius, Vector3 &outPoint, float &outFraction); // Test intersection with a swept ellipsoid with principal axis inAxis1, inAxis2, inAxis3 moving from inBegin to inBegin + inDelta // If there is an intersection the intersection position is returned in outPoint and the center of the // sphere is at inBegin + outFraction * inDelta when it collides //bool PolygonSweptEllipsoidIntersect(const Plane &inPlane, const Vector2 *inVertices, int inNumVertices, const Vector3 &inBegin, const Vector3 &inDelta, const Vector3 &inAxis1, const Vector3 &inAxis2, const Vector3 &inAxis3, Vector3 &outPoint, float &outFraction); bool PolygonSweptCircleIntersect(const Point *inVertices, int inNumVertices, const Point &inBegin, const Point &inDelta, Point::member_type inRadius, Point &outPoint, Point::member_type &outFraction); }; #endif // _SWEPT_ELLIPSOID_H_ --- NEW FILE: gameLoader.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _GAMELOADER_H_ #define _GAMELOADER_H_ #include "../tnl/tnl.h" #include "game.h" #include "gameObject.h" namespace Zap { class GameLoader { public: static void initGameFromFile(ServerGame *g, const char *file); }; }; #endif --- NEW FILE: CTFGame.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "CTFGame.h" #include "ship.h" #include "UIGame.h" #include "sfx.h" #include "glutInclude.h" namespace Zap { static void renderFlag(Point pos, Color c) { glPushMatrix(); glTranslatef(pos.x, pos.y, 0); glColor3f(c.r, c.g, c.b); glBegin(GL_LINES); glVertex2f(-15, -15); glVertex2f(15, -5); glVertex2f(15, -5); glVertex2f(-15, 5); glVertex2f(-15, -10); glVertex2f(10, -5); glVertex2f(10, -5); glVertex2f(-15, 0); glColor3f(1,1,1); glVertex2f(-15, -15); glVertex2f(-15, 15); glEnd(); glPopMatrix(); } TNL_IMPLEMENT_NETOBJECT(CTFGameType); void CTFGameType::renderInterfaceOverlay() { for(S32 i = 0; i < mTeams.size(); i++) { Point pos(750, 550 - i * 38); renderFlag(pos + Point(-20, 18), mTeams[i].color); glColor3f(1,1,1); UserInterface::drawStringf(pos.x, pos.y, 32, "%d", mTeams[i].score); } } void CTFGameType::shipTouchFlag(Ship *theShip, CTFFlagItem *theFlag) { GameConnection *controlConnection = theShip->getControllingClient(); S32 clientIndex = findClientIndexByConnection(controlConnection); if(clientIndex == -1) return; ClientRef &cl = mClientList[clientIndex]; if(cl.teamId == theFlag->getTeamIndex()) { if(!theFlag->isAtHome()) { s2cCTFMessage(CTFMsgReturnFlag, cl.clientId, theFlag->getTeamIndex()); theFlag->sendHome(); } else { // check if this client has an enemy flag mounted for(S32 i = 0; i < theShip->mMountedItems.size(); i++) { Item *theItem = theShip->mMountedItems[i]; CTFFlagItem *mountedFlag = dynamic_cast<CTFFlagItem *>(theItem); if(mountedFlag) { mTeams[cl.teamId].score++; s2cSetTeamScore(cl.teamId, mTeams[cl.teamId].score); s2cCTFMessage(CTFMsgCaptureFlag, cl.clientId, mountedFlag->getTeamIndex()); // score the flag for the client's team... mountedFlag->dismount(); mountedFlag->sendHome(); } } } } else { s2cCTFMessage(CTFMsgTakeFlag, cl.clientId, theFlag->getTeamIndex()); theFlag->mountToShip(theShip); } } static const char *CTFMessages[] = { "%s returned the %s flag.", "%s captured the %s flag!", "%s took the %s flag!", }; static U32 CTFFlagSounds[] = { SFXFlagReturn, SFXFlagCapture, SFXFlagSnatch, }; TNL_IMPLEMENT_NETOBJECT_RPC(CTFGameType, s2cCTFMessage, (U32 messageIndex, U32 clientId, U32 teamIndex), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { S32 clientIndex = findClientIndexById(clientId); gGameUserInterface.displayMessage(Color(0.6f, 1.0f, 0.8f), CTFMessages[messageIndex], mClientList[clientIndex].name.getString(), mTeams[teamIndex].name.getString()); SFXHandle h = new SFXObject(CTFFlagSounds[messageIndex]); h->play(); } TNL_IMPLEMENT_NETOBJECT(CTFFlagItem); CTFFlagItem::CTFFlagItem(Point pos) : Item(pos, false, 20) { teamIndex = 0; mNetFlags.set(Ghostable); } void CTFFlagItem::processArguments(S32 argc, const char **argv) { if(argc < 3) return; teamIndex = atoi(argv[0]); Parent::processArguments(argc-1, argv+1); initialPos = mMoveState[ActualState].pos; } U32 CTFFlagItem::packUpdate(GhostConnection *connection, U32 updateMask, BitStream *stream) { if(stream->writeFlag(updateMask & InitialMask)) stream->writeInt(teamIndex, 4); return Parent::packUpdate(connection, updateMask, stream); } void CTFFlagItem::unpackUpdate(GhostConnection *connection, BitStream *stream) { if(stream->readFlag()) teamIndex = stream->readInt(4); Parent::unpackUpdate(connection, stream); } bool CTFFlagItem::isAtHome() { return mMoveState[ActualState].pos == initialPos; } void CTFFlagItem::sendHome() { mMoveState[ActualState].pos = mMoveState[RenderState].pos = initialPos; setMaskBits(PositionMask); updateExtent(); } void CTFFlagItem::renderItem(Point pos) { Point offset; if(mIsMounted) offset.set(15, -15); Color c; GameType *gt = getGame()->getGameType(); c = gt->mTeams[teamIndex].color; renderFlag(pos + offset, c); } bool CTFFlagItem::collide(GameObject *hitObject) { if(isGhost() || mIsMounted) return false; if(!(hitObject->getObjectTypeMask() & ShipType)) return false; CTFGameType *theGameType = dynamic_cast<CTFGameType *>(getGame()->getGameType()); if(theGameType) theGameType->shipTouchFlag((Ship *) hitObject, this); return false; } }; --- NEW FILE: point.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _POINT_H_ #define _POINT_H_ #include <math.h> namespace Zap { struct Point { typedef float member_type; member_type x; member_type y; Point() { x = 0; y = 0; } Point(const Point& pt) { x = pt.x; y = pt.y; } Point(member_type in_x, member_type in_y) { x = in_x; y = in_y; } ... [truncated message content] |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:30
|
Update of /cvsroot/opentnl/tnl/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/test Added Files: Makefile TNLTest.def TNLTest.dsp TNLTest.suo TNLTest.vcproj client.cpp fractal.suo mondrian.ico server.cpp server.dsp server.vcproj test.rc test.suo testGame.cpp testGame.h testGameRender.cpp testWindow.cpp Log Message: Initial commit. --- NEW FILE: test.suo --- (This appears to be a binary file; contents omitted.) --- NEW FILE: server.vcproj --- <?xml version="1.0" encoding="Windows-1252"?> <VisualStudioProject ProjectType="Visual C++" Version="7.10" Name="server" ProjectGUID="{2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}" Keyword="Win32Proj"> <Platforms> <Platform Name="Win32"/> </Platforms> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="Debug" IntermediateDirectory="Debug" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" Optimization="0" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;DEBUG_NET;TNL_ENABLE_ASSERTS" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="Iphlpapi.lib wsock32.lib" OutputFile="../exe/serverd.exe" LinkIncremental="2" IgnoreDefaultLibraryNames="MSVCRTD" GenerateDebugInformation="TRUE" ProgramDatabaseFile="$(OutDir)/server.pdb" SubSystem="1" TargetMachine="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="Release" IntermediateDirectory="Release" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="4" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" DebugInformationFormat="3"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="Iphlpapi.lib wsock32.lib" OutputFile="../exe/server.exe" LinkIncremental="1" IgnoreDefaultLibraryNames="MSVCRT" GenerateDebugInformation="TRUE" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" TargetMachine="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> </Configurations> <References> </References> <Files> <File RelativePath=".\server.cpp"> </File> <File RelativePath=".\testGame.cpp"> </File> </Files> <Globals> </Globals> </VisualStudioProject> --- NEW FILE: TNLTest.vcproj --- <?xml version="1.0" encoding="Windows-1252"?> <VisualStudioProject ProjectType="Visual C++" Version="7.10" Name="TNLTest" ProjectGUID="{2BF337F1-B812-4324-A9BA-E4D580C8CFF1}" SccProjectName="" SccLocalPath=""> <Platforms> <Platform Name="Win32"/> </Platforms> <Configurations> <Configuration Name="Release|Win32" OutputDirectory="..\exe" IntermediateDirectory=".\Release" ConfigurationType="1" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE"> <Tool Name="VCCLCompilerTool" Optimization="2" InlineFunctionExpansion="1" AdditionalIncludeDirectories="" PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;WINVER=0x400;_MT;wxUSE_GUI=1" StringPooling="TRUE" ExceptionHandling="FALSE" RuntimeLibrary="2" EnableFunctionLevelLinking="TRUE" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="2" PrecompiledHeaderFile=".\Release/TNLTest.pch" AssemblerListingLocation=".\Release/" ObjectFile=".\Release/" ProgramDataBaseFileName=".\Release/" WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="Iphlpapi.lib libtomcrypt.lib opengl32.lib glu32.lib odbc32.lib odbccp32.lib comctl32.lib wsock32.lib tnl.lib ../glut/glut32.lib" OutputFile="..\exe\TNLTest.exe" LinkIncremental="1" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="../wxWindows/lib;../lib" IgnoreDefaultLibraryNames="LIBC" GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\Release/TNLTest.pdb" SubSystem="1" TargetMachine="1"/> <Tool Name="VCMIDLTool" PreprocessorDefinitions="NDEBUG" MkTypLibCompatible="TRUE" SuppressStartupBanner="TRUE" TargetEnvironment="1" TypeLibraryName=".\Release/TNLTest.tlb" HeaderFileName=""/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool" PreprocessorDefinitions="NDEBUG" Culture="1033" AdditionalIncludeDirectories="..\wxWindows\include"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> <Configuration Name="Debug|Win32" OutputDirectory="..\exe" IntermediateDirectory=".\Debug" ConfigurationType="1" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE"> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\wxWindows\include,..\wxWindows\lib/mswd,..\wxWindows\lib\mswd" PreprocessorDefinitions="TNL_ENABLE_LOGGING;TNL_ENABLE_ASSERTS;NDEBUG;WIN32;_WINDOWS;WINVER=0x400;_MT;wxUSE_GUI=1;" RuntimeLibrary="3" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="2" PrecompiledHeaderFile=".\Debug/TNLTest.pch" AssemblerListingLocation=".\Debug/" ObjectFile=".\Debug/" ProgramDataBaseFileName=".\Debug/" WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="Iphlpapi.lib libtomcryptd.lib tnld.lib opengl32.lib glu32.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib ../glut/glut32.lib" OutputFile="..\exe\TNLTestD.exe" LinkIncremental="2" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="../lib" IgnoreDefaultLibraryNames="MSVCRT,LIBCD" GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\Debug/TNLTest.pdb" SubSystem="1" TargetMachine="1"/> <Tool Name="VCMIDLTool" PreprocessorDefinitions="_DEBUG" MkTypLibCompatible="TRUE" SuppressStartupBanner="TRUE" TargetEnvironment="1" TypeLibraryName=".\Debug/TNLTest.tlb" HeaderFileName=""/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool" PreprocessorDefinitions="_DEBUG" Culture="1033" AdditionalIncludeDirectories="..\wxWindows\include"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> </Configurations> <References> </References> <Files> <File RelativePath=".\testGame.cpp"> </File> <File RelativePath=".\testGame.h"> </File> <File RelativePath=".\testGameRender.cpp"> </File> <File RelativePath=".\testWindow.cpp"> </File> </Files> <Globals> </Globals> </VisualStudioProject> --- NEW FILE: testGame.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - TNLTest example program // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include <math.h> #include "testGame.h" #include "../tnl/tnlBitStream.h" #include "../tnl/tnlNetConnection.h" #include "../tnl/tnlRandom.h" #include "../tnl/tnlSymmetricCipher.h" #include "../tnl/tnlAsymmetricKey.h" namespace TNLTest { TestGame *clientGame = NULL; TestGame *serverGame = NULL; //--------------------------------------------------------------------------------- TNL_IMPLEMENT_NETOBJECT(Player); // Player constructor Player::Player(Player::PlayerType pt) { // assign a random starting position for the player. startPos.x = Random::readF(); startPos.y = Random::readF(); endPos.x = startPos.x; endPos.y = startPos.y; renderPos = startPos; // preset the movement parameter for the player to the end of // the path t = 1.0; tDelta = 0; myPlayerType = pt; mNetFlags.set(Ghostable); game = NULL; } Player::~Player() { if(!game) return; // remove the player from the list of players in the game. for( S32 i = 0; i < game->players.size(); i++) { if(game->players[i] == this) { game->players.erase_fast(i); return; } } } void Player::addToGame(TestGame *theGame) { // add the player to the list of players in the game. theGame->players.push_back(this); game = theGame; if(myPlayerType == PlayerTypeMyClient) { // set the client player for the game for drawing the // scoping radius circle. game->clientPlayer = this; } } bool Player::onGhostAdd(GhostConnection *theConnection) { addToGame(((TestNetInterface *) theConnection->getInterface())->game); return true; } void Player::performScopeQuery(GhostConnection *connection) { // find all the objects that are "in scope" - for the purposes // of this test program, that is all objects in a circle of radius // 0.25 around the scope object, or a radius squared of 0.0625 for(S32 i = 0; i < game->players.size(); i++) { Position playerP = game->players[i]->renderPos; F32 dx = playerP.x - renderPos.x; F32 dy = playerP.y - renderPos.y; F32 distSquared = dx * dx + dy * dy; if(distSquared < 0.0625) connection->objectInScope(game->players[i]); } } U32 Player::packUpdate(GhostConnection *connection, U32 updateMask, BitStream *stream) { // if this is the initial update, write out some static // information about this player. Since we never call // setMaskBits(InitialMask), we're guaranteed that this state // will only be updated on the first update for this object. if(stream->writeFlag(updateMask & InitialMask)) { // write one bit if it's not an AI if(stream->writeFlag(myPlayerType != PlayerTypeAI)) { // write a flag to the client if this is the player that // that client controls. stream->writeFlag(connection->getScopeObject() == this); } } // see if we need to write out the position data // we must write a bit to let the unpackUpdate know whether to // read the position data out of the stream. if(stream->writeFlag(updateMask & PositionMask)) { // since the position data is all 0 to 1, we can use // the bit stream's writeFloat method to write it out. // 12 bits should be sufficient precision stream->writeFloat(startPos.x, 12); stream->writeFloat(startPos.y, 12); stream->writeFloat(endPos.x, 12); stream->writeFloat(endPos.y, 12); stream->write(t); // fully precise t and tDelta stream->write(tDelta); } // if I had other states on the player that changed independently // of position, I could test for and update them here. // ... // the return value from packUpdate is the update mask for this // object on this client _AFTER_ this update has been sent. // Normally this will be zero, but it could be nonzero if this // object has a state that depends on some other object that // hasn't yet been ghosted. return 0; } void Player::unpackUpdate(GhostConnection *connection, BitStream *stream) { // see if the initial packet data was written: if(stream->readFlag()) { // check to see if it's not an AI player. if(stream->readFlag()) { if(stream->readFlag()) myPlayerType = PlayerTypeMyClient; else myPlayerType = PlayerTypeClient; } else myPlayerType = PlayerTypeAIDummy; } // see if the player's position has been updated: if(stream->readFlag()) { startPos.x = stream->readFloat(12); startPos.y = stream->readFloat(12); endPos.x = stream->readFloat(12); endPos.y = stream->readFloat(12); stream->read(&t); stream->read(&tDelta); // update the render position update(0); } } void Player::serverSetPosition(Position inStartPos, Position inEndPos, F32 inT, F32 inTDelta) { // update the instance variables of the object startPos = inStartPos; endPos = inEndPos; t = inT; tDelta = inTDelta; // notify the network system that the position state of this object has changed: setMaskBits(PositionMask); // call a quick RPC to all the connections that have this object in scope rpcPlayerDidMove(inEndPos.x, inEndPos.y); } void Player::update(F32 timeDelta) { t += tDelta * timeDelta; if(t >= 1.0) { t = 1.0; tDelta = 0; renderPos = endPos; // if this is an AI player on the server, if(myPlayerType == PlayerTypeAI) { startPos = renderPos; t = 0; endPos.x = Random::readF(); endPos.y = Random::readF(); tDelta = 0.2f + Random::readF() * 0.1f; setMaskBits(PositionMask); // notify the network system that the network state has been updated } } renderPos.x = startPos.x + (endPos.x - startPos.x) * t; renderPos.y = startPos.y + (endPos.y - startPos.y) * t; } void Player::onGhostAvailable(GhostConnection *theConnection) { // this function is called every time a ghost of this object is known // to be available on a given client. // we'll use this to demonstrate targeting a NetObject RPC // to a specific connection. Normally a RPC method marked as // RPCToGhost will be broadcast to ALL ghosts of the object currently in // scope. // first we construct an event that will represent the RPC call... // the RPC macros create a RPCNAME_construct function that returns // a NetEvent that encapsulates the RPC. NetEvent *theRPCEvent = TNL_RPC_CONSTRUCT_NETEVENT(this, rpcPlayerIsInScope, (renderPos.x, renderPos.y)); // then we can just post the event to whatever connections we want to have // receive the message. // In the case of NetObject RPCs, if the source object is not ghosted, // the RPC will just be silently dropped. theConnection->postNetEvent(theRPCEvent); } TNL_IMPLEMENT_NETOBJECT_RPC(Player, rpcPlayerIsInScope, (Float<6> x, Float<6> y), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { F32 fx = x, fy = y; logprintf("A player is now in scope at %g, %g", fx, fy); } TNL_IMPLEMENT_NETOBJECT_RPC(Player, rpcPlayerWillMove, (const char *testString), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhostParent, 0) { logprintf("Expecting a player move from the connection: %s", testString); } TNL_IMPLEMENT_NETOBJECT_RPC(Player, rpcPlayerDidMove, (Float<6> x, Float<6> y), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCToGhost, 0) { F32 fx = x, fy = y; logprintf("A player moved to %g, %g", fx, fy); } //--------------------------------------------------------------------------------- TNL_IMPLEMENT_NETOBJECT(Building); Building::Building() { // place the "building" in a random position on the screen upperLeft.x = Random::readF(); upperLeft.y = Random::readF(); lowerRight.x = upperLeft.x + Random::readF() * 0.1f + 0.025f; lowerRight.y = upperLeft.y + Random::readF() * 0.1f + 0.025f; game = NULL; // always scope the buildings to the clients mNetFlags.set(Ghostable); setScopeAlways(); } Building::~Building() { if(!game) return; // remove the building from the list of buildings in the game. for( S32 i = 0; i < game->buildings.size(); i++) { if(game->buildings[i] == this) { game->buildings.erase_fast(i); return; } } } void Building::addToGame(TestGame *theGame) { // add it to the list of buildings in the game theGame->buildings.push_back(this); game = theGame; } bool Building::onGhostAdd(GhostConnection *theConnection) { addToGame(((TestNetInterface *) theConnection->getInterface())->game); return true; } U32 Building::packUpdate(GhostConnection *connection, U32 updateMask, BitStream *stream) { if(stream->writeFlag(updateMask & InitialMask)) { // we know all the positions are 0 to 1. // since this object is scope always, we don't care quite as much // how efficient the initial state updating is, since we're only // ever going to send this data when the client first connects // to this mission. stream->write(upperLeft.x); stream->write(upperLeft.y); stream->write(lowerRight.x); stream->write(lowerRight.y); } // for later - add a "color" field to the buildings that can change // when AIs or players move over them. return 0; } void Building::unpackUpdate(GhostConnection *connection, BitStream *stream) { if(stream->readFlag()) { stream->read(&upperLeft.x); stream->read(&upperLeft.y); stream->read(&lowerRight.x); stream->read(&lowerRight.y); } } //--------------------------------------------------------------------------------- TNL_IMPLEMENT_NETCONNECTION(TestConnection, NetClassGroupGame, true); TNL_DECLARE_RPC_MEM_ENUM(TestConnection, PlayerPosReplyBitSize); TNL_IMPLEMENT_RPC(TestConnection, rpcGotPlayerPos, (bool b1, bool b2, StringTableEntry string, Float<TestConnection::PlayerPosReplyBitSize> x, Float<TestConnection::PlayerPosReplyBitSize> y), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirAny, 0) { F32 xv = x, yv = y; logprintf("Server acknowledged position update - %d %d %s %g %g", b1, b2, string.getString(), xv, yv); } TNL_IMPLEMENT_RPC(TestConnection, rpcSetPlayerPos, (F32 x, F32 y), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) { Position newPosition; newPosition.x = x; newPosition.y = y; logprintf("%s - received new position (%g, %g) from client", getNetAddressString(), newPosition.x, newPosition.y); myPlayer->serverSetPosition(myPlayer->renderPos, newPosition, 0, 0.2f); // send an RPC back the other way! StringTableEntry helloString("Hello World!!"); rpcGotPlayerPos(true, false, helloString, x, y); }; TestConnection::TestConnection() { // every connection class instance must have a net class group set // before it is used. //setIsAdaptive(); // <-- Uncomment me if you want to use adaptive rate instead of fixed rate... } void TestConnection::onTimedOut() { logprintf("%s - connection to %s timed out.", getNetAddressString(), isConnectionToServer() ? "server" : "client" ); // if this is a client to server connection, set us back to pinging servers. if(isConnectionToServer()) ((TestNetInterface *) getInterface())->pingingServers = true; else delete (Player*)myPlayer; // delete the client's player object. } void TestConnection::onConnectTimedOut() { ((TestNetInterface *) getInterface())->pingingServers = true; } void TestConnection::onDisconnect(const char *reason) { logprintf("%s - %s disconnected.", getNetAddressString(), isConnectionToServer() ? "server" : "client" ); if(isConnectionToServer()) ((TestNetInterface *) getInterface())->pingingServers = true; else delete (Player*)myPlayer; } void TestConnection::onConnectionEstablished(bool isInitiator) { // call the parent's onConnectionEstablished. // by default this will set the initiator to be a connection // to "server" and the non-initiator to be a connnection to "client" Parent::onConnectionEstablished(isInitiator); // To see how this program performs with 50% packet loss, // Try uncommenting the next line :) //setSimulatedNetParams(0.5, 0); if(isInitiator) { setGhostFrom(false); setGhostTo(true); logprintf("%s - connected to server.", getNetAddressString()); ((TestNetInterface *) getInterface())->connectionToServer = this; } else { // on the server, we create a player object that will be the scope object // for this client. Player *player = new Player; myPlayer = player; myPlayer->setInterface(getInterface()); myPlayer->addToGame(((TestNetInterface *) getInterface())->game); setScopeObject(myPlayer); setGhostFrom(true); setGhostTo(false); activateGhosting(); logprintf("%s - client connected.", getNetAddressString()); } } //--------------------------------------------------------------------------------- TestNetInterface::TestNetInterface(TestGame *theGame, bool server, const Address &bindAddress, const Address &pingAddr) : NetInterface(bindAddress) { game = theGame; isServer = server; pingingServers = !server; lastPingTime = 0; pingAddress = pingAddr; } void TestNetInterface::sendPing() { PacketStream writeStream; // the ping packet right now just has one byte for packet type writeStream.write(U8(GamePingRequest)); writeStream.sendto(mSocket, pingAddress); logprintf("%s - sending ping.", pingAddress.toString()); } void TestNetInterface::tick() { U32 currentTime = Platform::getRealMilliseconds(); if(pingingServers && (lastPingTime + PingDelayTime < currentTime)) { lastPingTime = currentTime; sendPing(); } checkIncomingPackets(); processConnections(); } // handleInfoPacket for the test game is very simple - if this instance // is a client, it pings for servers until one is found to connect to. // If this instance is a server, it responds to ping packets from clients. // More complicated games could maintain server lists, request game information // and more. void TestNetInterface::handleInfoPacket(const Address &address, U8 packetType, BitStream *stream) { PacketStream writeStream; if(packetType == GamePingRequest && isServer) { logprintf("%s - received ping.", address.toString()); // we're a server, and we got a ping packet from a client, // so send back a GamePingResponse to let the client know it // has found a server. writeStream.write(U8(GamePingResponse)); writeStream.sendto(mSocket, address); logprintf("%s - sending ping response.", address.toString()); } else if(packetType == GamePingResponse && pingingServers) { // we were pinging servers and we got a response. Stop the server // pinging, and try to connect to the server. logprintf("%s - received ping response.", address.toString()); TestConnection *connection = new TestConnection; connection->connect(this, address); // connect to the server through the game's network interface logprintf("Connecting to server: %s", address.toString()); pingingServers = false; } } //--------------------------------------------------------------------------------- //--------------------------------------------------------------------------------- TestGame::TestGame(bool server, const Address &interfaceBindAddr, const Address &pingAddress) { isServer = server; myNetInterface = new TestNetInterface(this, isServer, interfaceBindAddr, pingAddress); AsymmetricKey *theKey = new AsymmetricKey(32); myNetInterface->setPrivateKey(theKey); myNetInterface->setRequiresKeyExchange(true); lastTime = Platform::getRealMilliseconds(); if(isServer) { // generate some buildings and AIs: for(S32 i = 0; i < 50; i ++) { Building *building = new Building; building->setInterface(myNetInterface); building->addToGame(this); } for(S32 i = 0; i < 15; i ++) { Player *aiPlayer = new Player(Player::PlayerTypeAI); aiPlayer->setInterface(myNetInterface); aiPlayer->addToGame(this); } serverPlayer = new Player(Player::PlayerTypeMyClient); serverPlayer->addToGame(this); } logprintf("Created a %s...", (server ? "server" : "client")); } TestGame::~TestGame() { delete myNetInterface; for(S32 i = 0; i < buildings.size(); i++) delete buildings[i]; for(S32 i = 0; i < players.size(); i++) delete players[i]; logprintf("Destroyed a %s...", (this->isServer ? "server" : "client")); } void TestGame::createLocalConnection(TestGame *serverGame) { myNetInterface->pingingServers = false; TestConnection *theConnection = new TestConnection; theConnection->connectLocal(myNetInterface, serverGame->myNetInterface); } void TestGame::tick() { U32 currentTime = Platform::getRealMilliseconds(); if(currentTime == lastTime) return; F32 timeDelta = (currentTime - lastTime) / 1000.0f; for(S32 i = 0; i < players.size(); i++) players[i]->update(timeDelta); myNetInterface->tick(); lastTime = currentTime; } void TestGame::moveMyPlayerTo(Position newPosition) { if(isServer) { serverPlayer->serverSetPosition(serverPlayer->renderPos, newPosition, 0, 0.2f); } else if(!myNetInterface->connectionToServer.isNull()) { logprintf("posting new position (%g, %g) to server", newPosition.x, newPosition.y); if(!clientPlayer.isNull()) clientPlayer->rpcPlayerWillMove("Whee! Foo!"); myNetInterface->connectionToServer->rpcSetPlayerPos(newPosition.x, newPosition.y); } } }; --- NEW FILE: Makefile --- # TNL Makefile # (c) 2003 GarageGames # # This makefile is for Linux atm. # # Configuration # CC=g++ -g #-O2 OBJECTS_SERVER=\ testGame.o\ server.o OBJECTS_CLIENT=\ testGame.o\ client.o OBJECTS_WXGUI=\ testGame.o\ testWindow.o \ testGameRender.o \ CFLAGS= .cpp.o : $(CC) -c $(CFLAGS) $< default: $(OBJECTS_SERVER) $(OBJECTS_CLIENT) @echo Building linux dedicated server... $(CC) -o server $(OBJECTS_SERVER) ../tnl/libtnl.a ../libtomcrypt/libtomcrypt.a -lstdc++ -lm $(CC) -o client $(OBJECTS_CLIENT) ../tnl/libtnl.a ../libtomcrypt/libtomcrypt.a -lstdc++ -lm wxgui: CFLAGS += `wx-config --cxxflags` wxgui: $(OBJECTS_WXGUI) @echo Building WX gui... $(CC) -o wxgui $(OBJECTS_WXGUI) ../tnl/libtnl.a ../libtomcrypt/libtomcrypt.a `wx-config --libs --gl-libs ` -lGL clean: rm -f $(OBJECTS_SERVER) $(OBJECTS_CLIENT) $(OBJECTS_WXGUI) server client wxgui --- NEW FILE: testGameRender.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - TNLTest example program // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #if defined(_WIN32) #include <windows.h> #include <gl/gl.h> #elif defined (__APPLE__) #include <OpenGL/gl.h> #else #include <GL/gl.h> #endif #include "testGame.h" #include <math.h> namespace TNLTest { void TestGame::renderFrame(int width, int height) { glClearColor(1, 1, 0, 0); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, 1, 1, 0, 0, 1); glMatrixMode(GL_MODELVIEW); // first, render the alpha blended circle around the player, // to show the scoping range. if(clientPlayer) { Position p = clientPlayer->renderPos; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBegin(GL_POLYGON); glColor4f(0.5f, 0.5f, 0.5f, 0.65f); for(F32 r = 0; r < 3.1415 * 2; r += 0.1f) { glVertex2f(p.x + 0.25f * cos(r), p.y + 0.25f * sin(r)); } glEnd(); glDisable(GL_BLEND); } // then draw all the buildings. for(S32 i = 0; i < buildings.size(); i++) { Building *b = buildings[i]; glBegin(GL_POLYGON); glColor3f(1, 0, 0); glVertex2f(b->upperLeft.x, b->upperLeft.y); glVertex2f(b->lowerRight.x, b->upperLeft.y); glVertex2f(b->lowerRight.x, b->lowerRight.y); glVertex2f(b->upperLeft.x, b->lowerRight.y); glEnd(); } // last, draw all the players in the game. for(S32 i = 0; i < players.size(); i++) { Player *p = players[i]; glBegin(GL_POLYGON); glColor3f(0,0,0); glVertex2f(p->renderPos.x - 0.012f, p->renderPos.y - 0.012f); glVertex2f(p->renderPos.x + 0.012f, p->renderPos.y - 0.012f); glVertex2f(p->renderPos.x + 0.012f, p->renderPos.y + 0.012f); glVertex2f(p->renderPos.x - 0.012f, p->renderPos.y + 0.012f); glEnd(); glBegin(GL_POLYGON); switch(p->myPlayerType) { case Player::PlayerTypeAI: case Player::PlayerTypeAIDummy: glColor3f(0, 0, 1); break; case Player::PlayerTypeClient: glColor3f(0.5, 0.5, 1); break; case Player::PlayerTypeMyClient: glColor3f(1, 1, 1); break; } glVertex2f(p->renderPos.x - 0.01f, p->renderPos.y - 0.01f); glVertex2f(p->renderPos.x + 0.01f, p->renderPos.y - 0.01f); glVertex2f(p->renderPos.x + 0.01f, p->renderPos.y + 0.01f); glVertex2f(p->renderPos.x - 0.01f, p->renderPos.y + 0.01f); glEnd(); } } }; --- NEW FILE: TNLTest.dsp --- # Microsoft Developer Studio Project File - Name="TNLTest" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Application" 0x0101 CFG=TNLTest - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "TNLTest.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "TNLTest.mak" CFG="TNLTest - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "TNLTest - Win32 Release" (based on "Win32 (x86) Application") !MESSAGE "TNLTest - Win32 Debug" (based on "Win32 (x86) Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "TNLTest - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W4 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /YX /FD /c # ADD CPP /nologo /MD /W3 /GR /O2 /I "../wxWindows/include" /I "..\wxWindows\lib\msw" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 # ADD BASE RSC /l 0x409 /i "../../include" /d "NDEBUG" # ADD RSC /l 0x409 /i "../wxWindows/include" /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:windows /machine:I386 # ADD LINK32 ../glut/glut32.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:console /machine:I386 /nodefaultlib:"LIBC" /out:"../exe/TNLTest.exe" /libpath:"../lib" # SUBTRACT LINK32 /pdb:none !ELSEIF "$(CFG)" == "TNLTest - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W4 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /YX /FD /c # ADD CPP /nologo /MDd /W3 /GR /Zi /Od /I "../wxWindows/include" /I "..\wxWindows\lib\msw" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D WINVER=0x400 /D "_MT" /D wxUSE_GUI=1 /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 # ADD BASE RSC /l 0x409 /i "../../include" /d "_DEBUG" # ADD RSC /l 0x409 /i "../wxWindows/include" /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # ADD LINK32 tnld.lib libtomcryptd.lib ../glut/glut32.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib rpcrt4.lib wsock32.lib /nologo /subsystem:console /debug /machine:I386 /nodefaultlib:"LIBCD" /out:"../exe/TNLTestD.exe" /pdbtype:sept /libpath:"../lib" # SUBTRACT LINK32 /pdb:none !ENDIF # Begin Target # Name "TNLTest - Win32 Release" # Name "TNLTest - Win32 Debug" # Begin Source File SOURCE=.\testGame.cpp # End Source File # Begin Source File SOURCE=.\testGame.h # End Source File # Begin Source File SOURCE=.\testGameRender.cpp # End Source File # Begin Source File SOURCE=.\testWindow.cpp # End Source File # End Target # End Project --- NEW FILE: test.rc --- wxSTD_FRAME ICON "mondrian.ico" #include "wx/msw/wx.rc" --- NEW FILE: testGame.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - TNLTest example program // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "../tnl/tnl.h" #include "../tnl/tnlNetBase.h" #include "../tnl/tnlGhostConnection.h" #include "../tnl/tnlNetInterface.h" #include "../tnl/tnlNetObject.h" #include "../tnl/tnlLog.h" #include "../tnl/tnlRPC.h" using namespace TNL; /// TNL Graphical Test Application. /// /// The TNLTest application demonstrates some of the more useful /// features of the Torque Network Library. The application presents /// a single window, representing an abstract simulation area. Red /// rectangles are used to represent "buildings" that small squares /// representing players move over. /// /// On the linux and Win32 platforms, TNLTest uses the wxWindows user /// interface API. On Mac OSX TNLTest uses the native Cocoa application /// framework to render. /// /// Each instance of TNLTest can run in one of four modes: as a server, /// able to host multiple clients; as a client, which searches for and then /// connects to a server for game data; a client pinging the localhost for /// connecting to a server on the local machine, and as a combined server /// and client. namespace TNLTest { class TestGame; /// Position structure used for positions of objects in the test game. struct Position { F32 x; ///< X position of the object, from 0 ... 1 F32 y; ///< Y position of the object, from 0 ... 1 }; /// The Player is an example of an object that can move around and update its /// position to clients in the system. Each client in the server controls /// a Player instance constructed for it upon joining the game. /// Client users click on the game window, which generates an event to the server to /// move that client's player to the desired point. class Player : public NetObject { typedef NetObject Parent; public: Position startPos, endPos; ///< All players move along a line from startPos to endPos. Position renderPos; ///< Position at which to render the player - computed during update(). F32 t; ///< Parameter of how far the player is along the line from startPos to endPos. F32 tDelta; ///< Change in t per second (ie, velocity). TestGame *game; ///< The game object this player is associated with /// Enumeration of possible player types in the game. enum PlayerType { PlayerTypeAI, ///< The player is an AI controlled player on the server. PlayerTypeAIDummy, ///< The player is the ghost of an AI controlled player on the server. PlayerTypeClient, ///< The player is owned by a client. If this is a ghost, it is owned by a user other than this client. PlayerTypeMyClient, ///< The player controlled by this client. }; PlayerType myPlayerType; ///< What type of player is this? /// Player constructor, assigns a random position in the playing field to the player, and /// if it is AI controlled will pick a first destination point. Player(PlayerType pt = PlayerTypeClient); /// Player destructor removes the player from the game. ~Player(); /// Mask bits used for determining which object states need to be updated /// to all the clients. enum MaskBits { InitialMask = (1 << 0), ///< This mask bit is never set explicitly, so it can be used for initialization data. PositionMask = (1 << 1), ///< This mask bit is set when the position information changes on the server. }; /// performScopeQuery is called to determine which objects are "in scope" for the client /// that controls this Player instance. In the TNLTest program, all objects in a circle /// of radius 0.25 around the scope object are considered to be in scope. void performScopeQuery(GhostConnection *connection); /// packUpdate writes the Player's ghost update from the server to the client. /// This function takes advantage of the fact that the InitialMask is only ever set /// for the first update of the object to send once-only state to the client. U32 packUpdate(GhostConnection *connection, U32 updateMask, BitStream *stream); /// unpackUpdate reads the data the server wrote in packUpdate from the packet. void unpackUpdate(GhostConnection *connection, BitStream *stream); /// serverSetPosition is called on the server when it receives notice from a client /// to change the position of the player it controls. serverSetPosition will call /// setMaskBits(PositionMask) to notify the network system that this object has /// changed state. void serverSetPosition(Position startPos, Position endPos, F32 t, F32 tDelta); /// Move this object along its path. /// /// If it hits the end point, and it's an AI, it will generate a new destination. void update(F32 timeDelta); /// onGhostAvailable is called on the server when it knows that this Player has been /// constructed on the specified client as a result of being "in scope". In TNLTest /// this method call is used to test the per-ghost targeted RPC functionality of /// NetObject subclasses by calling rpcPlayerIsInScope on the Player ghost on /// the specified connection. void onGhostAvailable(GhostConnection *theConnection); /// onGhostAdd is called for every NetObject on the client after the ghost has /// been constructed and its initial unpackUpdate is called. A return value of /// false from this function would indicate than an error had occured, notifying the /// network system that the connection should be terminated. bool onGhostAdd(GhostConnection *theConnection); /// Adds this Player to the list of Player instances in the specified game. void addToGame(TestGame *theGame); /// rpcPlayerWillMove is used in TNLTest to demonstrate ghost->parent NetObject RPCs. TNL_DECLARE_RPC(rpcPlayerWillMove, (const char *testString)); /// rpcPlayerDidMove is used in TNLTest to demostrate a broadcast RPC from the server /// to all of the ghosts on clients scoping this object. It also demonstrates the /// usage of the Float<> template argument, in this case using 6 bits for each X and /// Y position. Float arguments to RPCs are between 0 and 1. TNL_DECLARE_RPC(rpcPlayerDidMove, (Float<6> x, Float<6> y)); /// rpcPlayerIsInScope is the RPC method called by onGhostAvailable to demonstrate /// targeted NetObject RPCs. onGhostAvailable uses the TNL_RPC_CONSTRUCT_NETEVENT /// macro to construct a NetEvent from the RPC invocation and then posts it only /// to the client for which the object just came into scope. TNL_DECLARE_RPC(rpcPlayerIsInScope, (Float<6> x, Float<6> y)); /// This macro invocation declares the Player class to be known /// to the TNL class management system. TNL_DECLARE_CLASS(Player); }; /// The Building class is an example of a NetObject that is ScopeAlways. /// ScopeAlways objects are transmitted to all clients that are currently /// ghosting, regardless of whether or not the scope object calls GhostConnection::objectInScope /// for them or not. The "buildings" are represented by red rectangles on the /// playing field, and are constructed with random position and extents. class Building : public NetObject { typedef NetObject Parent; public: /// Mask bits used to determine what states are out of date for this /// object and what then represent. enum MaskBits { InitialMask = (1 << 0), ///< Building's only mask bit is the initial mask, as no other states are ever set. }; TestGame *game; ///< The game object this building is associated with Position upperLeft; ///< Upper left corner of the building rectangle on the screen. Position lowerRight; ///< Lower right corner of the building rectangle on the screen. /// The Building constructor creates a random position and extent for the building, and marks it as scopeAlways. Building(); /// The Building destructor removes the Building from the game, if it is associated with a game object. ~Building(); /// Called on the client when this Building object has been ghosted to the /// client and its first unpackUpdate has been called. onGhostAdd adds /// the building to the client game. bool onGhostAdd(GhostConnection *theConnection); /// addToGame is a helper function called by onGhostAdd and on the server /// to add the building to the specified game. void addToGame(TestGame *game); /// packUpdate is called on the server Building object to update any out-of-date network /// state information to the client. Since the Building object only declares an initial /// mask bit state and never calls setMaskBits, this method will only be invoked when /// the ghost is being created on the client. U32 packUpdate(GhostConnection *connection, U32 updateMask, BitStream *stream); /// Reads the update information about the building from the specified packet BitStream. void unpackUpdate(GhostConnection *connection, BitStream *stream); /// This macro declares Building to be a part of the TNL network class management system. TNL_DECLARE_CLASS(Building); }; /// TestConnection is the TNLTest connection class. /// /// The TestConnection class overrides particular methods for /// connection housekeeping, and for connected clients manages /// the transmission of client inputs to the server for player /// position updates. /// /// When a client's connection to the server is lost, the /// TestConnection notifies the network interface that it should begin /// searching for a new server to join. class TestConnection : public GhostConnection { typedef GhostConnection Parent; public: /// The TestConnection constructor. This method contains a line that can be /// uncommented to put the TestConnection into adaptive communications mode. TestConnection(); /// The player object associated with this connection. SafePtr<Player> myPlayer; /// onTimedOut is called when the connection to the server or client has been /// terminated due to a lack of network traffic from the remote host. /// When a TestConnection to a server times out, the client's network interface /// is notified so it can begin searching for another server to connect to. void onTimedOut(); /// onConnectTimedOut is called when the connection request to the server /// is unable to complete due to connection timeout. /// When a TestConnection connect request to a server times out, the client's network interface /// is notified so it can begin searching for another server to connect to. void onConnectTimedOut(); /// onDisconnect is called when the remote host has terminated the connection. /// When a TestConnection to a server is disconnected, the client's network interface /// is notified so it can begin searching for another server to connect to. void onDisconnect(const char *reason); /// onConnectionEstablished is called on both ends of a connection when the connection is established. /// On the server this will create a player for this client, and set it as the client's /// scope object. On both sides this will set the proper ghosting behavior for the connection (ie server to client). void onConnectionEstablished(bool isInitiator); /// Remote function that client calls to set the position of the player on the server. TNL_DECLARE_RPC(rpcSetPlayerPos, (F32 x, F32 y)); /// Enumeration constant used to specify the size field of Float<> parameters in the rpcGotPlayerPos method. enum RPCEnumerationValues { PlayerPosReplyBitSize = 6, ///< Size, in bits of the floats the server sends to the client to acknowledge position updates. }; /// Remote function the server sends back to the client when it gets a player position. /// We only use 6 bits of precision on each float to illustrate the float compression /// that's possible using TNL's RPC. This RPC also sends bool and StringTableEntry data, /// as well as showing the use of the TNL_DECLARE_RPC_ENUM macro. TNL_DECLARE_RPC(rpcGotPlayerPos, (bool b1, bool b2, StringTableEntry string, Float<PlayerPosReplyBitSize> x, Float<PlayerPosReplyBitSize> y)); /// TNL_DECLARE_NETCONNECTION is used to declare that TestConnection is a valid connection class to the /// TNL network system. TNL_DECLARE_NETCONNECTION(TestConnection); }; /// TestNetInterface - the NetInterface subclass used in TNLTest. /// TestNetInterface subclasses TNLTest to provide server pinging and response /// info packets. /// When a client TestNetInterface starts, it begins sending ping /// packets to the pingAddr address specified in the constructor. When a server /// receives a GamePingRequest packet, it sends a GamePingResponse packet to the /// source address of the GamePingRequest. Upon receipt of this response packet, /// the client attempts to connect to the server that returned the response. /// When the connection or connection attempt to that server is terminated, the /// TestNetInterface resumes pinging for available TNLTest servers. class TestNetInterface : public NetInterface { typedef NetInterface Parent; public: /// Constants used in this NetInterface enum Constants { PingDelayTime = 2000, ///< Milliseconds to wait between sending GamePingRequest packets. GamePingRequest = FirstValidInfoPacketId, ///< Byte value of the first byte of a GamePingRequest packet. GamePingResponse, ///< Byte value of the first byte of a GamePingResponse packet. }; bool pingingServers; ///< True if this is a client that is pinging for active servers. U32 lastPingTime; ///< The last platform time that a GamePingRequest was sent from this network interface. bool isServer; ///< True if this network interface is a server, false if it is a client. SafePtr<TestConnection> connectionToServer; ///< A safe pointer to the current connection to the server, if this is a client. Address pingAddress; ///< Network address to ping in searching for a server. This can be a specific host address or it can be a LAN broadcast address. TestGame *game; ///< The game object associated with this network interface. /// Constructor for this network interface, called from the constructor for TestGame. /// The constructor initializes and binds the network interface, as well as sets /// parameters for the associated game and whether or not it is a server. TestNetInterface(TestGame *theGame, bool server, const Address &bindAddress, const Address &pingAddr); /// handleInfoPacket overrides the method in the NetInterface class to handle processing /// of the GamePingRequest and GamePingResponse packet types. void handleInfoPacket(const Address &address, U8 packetType, BitStream *stream); /// sendPing sends a GamePingRequest packet to pingAddress of this TestNetInterface. void sendPing(); /// Tick checks to see if it is an appropriate time to send a ping packet, in addition /// to checking for incoming packets and processing connections. void tick(); }; /// The TestGame class manages a TNLTest client or server instance. /// TestGame maintains a list of all the Player and Building objects in the /// playing area, and interfaces with the specific platform's windowing /// system to respond to user input and render the current game display. class TestGame { public: Vector<Player *> players; ///< vector of player objects in the game Vector<Building *> buildings; ///< vector of buildings in the game bool isServer; ///< was this game created to be a server? TestNetInterface *myNetInterface; ///< network interface for this game U32 lastTime; ///< last time that tick() was called SafePtr<Player> serverPlayer; ///< the player that the server controls SafePtr<Player> clientPlayer; ///< the player that this client controls, if this game is a client /// Constructor for TestGame, determines whether this game will be a client /// or a server, and what addresses to bind to and ping. If this game is a /// server, it will construct 50 random buildings and 15 random AI players to /// populate the "world" with. TestGame also constructs an AsymmetricKey to /// demonstrate establishing secure connections with clients and servers. TestGame(bool server, const Address &bindAddress, const Address &pingAddress); /// Destroys a game, freeing all Player and Building objects associated with it. ~TestGame(); /// createLocalConnection demonstrates the use of so-called "short circuit" connections /// for connecting to a server NetInterface in the same process as this client game. void createLocalConnection(TestGame *serverGame); /// Called periodically by the platform windowing code, tick will update /// all the players in the simulation as well as tick() the game's /// network interface. void tick(); /// renderFrame is called by the platform windowing code to notify the game /// that it should render the current world using the specified window area. void renderFrame(int width, int height); /// moveMyPlayerTo is called by the platform windowing code in response to /// user input. void moveMyPlayerTo(Position newPosition); }; /// The instance of the client game, if there is a client currently running. extern TestGame *clientGame; /// The instance of the server game, if there is a server currently running. extern TestGame *serverGame; }; using namespace TNLTest; --- NEW FILE: server.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - TNLTest dedicated server and unit tests // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "testGame.h" #include <stdio.h> #include "../tnl/tnlSymmetricCipher.h" #include "../tnl/tnlAsymmetricKey.h" #include "../tnl/tnlCertificate.h" #include "../tnl/tnlBitStream.h" #define TNLTest_SERVER //#define TNL_TEST_RPC //#define TNL_TEST_PROTOCOL //#define TNL_TEST_RPC //#define TNL_TEST_NETINTERFACE //#define TNL_TEST_CERTIFICATE // server.cpp // // This file contains several different test programs, one of which // can be enabled by uncommenting one of the previous #define'd macros. // // All of the test programs use the following LogConsumer to write // output from the TNL to the standard output console. class DedicatedServerLogConsumer : public LogConsumer { public: void logString(const char *string) { printf("%s\n", string); } } gDedicatedServerLogConsumer; #if defined(TNLTest_SERVER) // The TNLTest_SERVER test is an example dedicated server for the // TNLTest application. int main(int argc, const char **argv) { const char *localBroadcastAddress = "IP:broadcast:28999"; S32 port = 28999; if(argc == 2) port = atoi(argv[1]); serverGame = new TestGame(true, Address(IPProtocol, Address::Any, port), Address(localBroadcastAddress)); for(;;) serverGame->tick(); return 0; } #elif defined(TNL_TEST_RPC) // The TNL_TEST_RPC exercises the RPC functionality of TNL. The RPC // code is the only code that is challenging to port to new platforms // because of its reliance on platform specific stack structure and // function invocation guidelines. // // All RPC methods are declared to be virtual and are invoked using a // virtual member function pointer. The assembly language output of the // VFTester calls below can be used to determine how to invoke virtual member // functions on different platforms and compilers. class RPCTestConnection : public EventConnection { public: /// Test RPC function for long argument lists, especially useful in debugging architectures that pass some arguments in registers, and some on the stack. TNL_DECLARE_RPC(rpcLongArgChainTest, (Float<7> i1, Float<6> i2, F32 i3, F32 i4, F32 i5, F32 i6, F32 i7, F32 i8, F32 i9, F32 i10, F32 i11, F32 i12, F32 i13, F32 i14, F32 i15, U32 i16, U32 i17, F32 i18, F32 i19, F32 i20, F32 i21, F32 i22)); TNL_DECLARE_RPC(rpcVectorTest, (IPAddressRef theIP, ByteBufferRef buf, const Vector<IPAddress> &v0, const Vector<const char *> &v1, const Vector<F32> &v2)); TNL_DECLARE_RPC(rpcSTETest, (StringTableEntry e1, const Vector<StringTableEntry> &v2)); }; TNL_IMPLEMENT_RPC(RPCTestConnection, rpcLongArgChainTest, (Float<7> i1, Float<6> i2, F32 i3, F32 i4, F32 i5, F32 i6, F32 i7, F32 i8, F32 i9, F32 i10, F32 i11, F32 i12, F32 i13, F32 i14, F32 i15, U32 i16, U32 i17, F32 i18, F32 i19, F32 i20, F32 i21, F32 i22), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirAny, 0) { F32 fi1 = i1; F32 fi2 = i2; logprintf( "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g %d %d %g %g %g %g %g", fi1, fi2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22); } TNL_IMPLEMENT_RPC(RPCTestConnection, rpcVectorTest, (IPAddressRef theIP, ByteBufferRef buf, const Vector<IPAddress> &v0, const Vector<const char *> &v1, const Vector<F32> &v2), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirAny, 0) { // The assembly output of the following lines is used to determine // how the RPC executor should dispatch RPC calls. VFTester *newTester = new VFTester; fptr thePtr = &VFTester::doSomething; (newTester->*thePtr)(50); logprintf("Vector 0 size: %d, Vector 1 si... [truncated message content] |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:30
|
Update of /cvsroot/opentnl/tnl/openal In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/openal Added Files: ALut.lib OpenAL32.lib al.h alInclude.h alc.h alctypes.h altypes.h alu.h alut.h Log Message: Initial commit. --- NEW FILE: alut.h --- #ifndef _ALUT_H_ #define _ALUT_H_ #define ALUTAPI #define ALUTAPIENTRY __cdecl #include "al.h" #include "alu.h" #ifdef __cplusplus extern "C" { #endif ALUTAPI ALvoid ALUTAPIENTRY alutInit(ALint *argc,ALbyte **argv); ALUTAPI ALvoid ALUTAPIENTRY alutExit(ALvoid); ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVFile(ALbyte *file,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop); ALUTAPI ALvoid ALUTAPIENTRY alutLoadWAVMemory(ALbyte *memory,ALenum *format,ALvoid **data,ALsizei *size,ALsizei *freq,ALboolean *loop); ALUTAPI ALvoid ALUTAPIENTRY alutUnloadWAV(ALenum format,ALvoid *data,ALsizei size,ALsizei freq); #ifdef __cplusplus } #endif #endif --- NEW FILE: alc.h --- #ifndef _ALC_H_ #define _ALC_H_ #include "altypes.h" #include "alctypes.h" #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 #ifdef _OPENAL32LIB #define ALCAPI __declspec(dllexport) #else #define ALCAPI __declspec(dllimport) #endif typedef struct ALCdevice_struct ALCdevice; typedef struct ALCcontext_struct ALCcontext; #define ALCAPIENTRY __cdecl #else #ifdef TARGET_OS_MAC #if TARGET_OS_MAC #pragma export on #endif #endif #define ALCAPI #define ALCAPIENTRY __cdecl #endif #ifndef ALC_NO_PROTOTYPES ALCAPI ALCubyte* ALCAPIENTRY alcGetString(ALCdevice *device,ALCenum param); ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALCsizei size,ALCint *data); ALCAPI ALCdevice* ALCAPIENTRY alcOpenDevice(ALCubyte *deviceName); ALCAPI ALCvoid ALCAPIENTRY alcCloseDevice(ALCdevice *device); ALCAPI ALCcontext*ALCAPIENTRY alcCreateContext(ALCdevice *device,ALCint *attrList); ALCAPI ALCboolean ALCAPIENTRY alcMakeContextCurrent(ALCcontext *context); ALCAPI ALCvoid ALCAPIENTRY alcProcessContext(ALCcontext *context); ALCAPI ALCcontext*ALCAPIENTRY alcGetCurrentContext(ALCvoid); ALCAPI ALCdevice* ALCAPIENTRY alcGetContextsDevice(ALCcontext *context); ALCAPI ALCvoid ALCAPIENTRY alcSuspendContext(ALCcontext *context); ALCAPI ALCvoid ALCAPIENTRY alcDestroyContext(ALCcontext *context); ALCAPI ALCenum ALCAPIENTRY alcGetError(ALCdevice *device); ALCAPI ALCboolean ALCAPIENTRY alcIsExtensionPresent(ALCdevice *device,ALCubyte *extName); ALCAPI ALCvoid * ALCAPIENTRY alcGetProcAddress(ALCdevice *device,ALCubyte *funcName); ALCAPI ALCenum ALCAPIENTRY alcGetEnumValue(ALCdevice *device,ALCubyte *enumName); #else /* AL_NO_PROTOTYPES */ ALCAPI ALCubyte* ALCAPIENTRY (*alcGetString)(ALCdevice *device,ALCenum param); ALCAPI ALCvoid ALCAPIENTRY (*alcGetIntegerv)(ALCdevice * device,ALCenum param,ALCsizei size,ALCint *data); ALCAPI ALCdevice* ALCAPIENTRY (*alcOpenDevice)(ALubyte *deviceName); ALCAPI ALCvoid ALCAPIENTRY (*alcCloseDevice)(ALCdevice *device); ALCAPI ALCcontext*ALCAPIENTRY (*alcCreateContext)(ALCdevice *device,ALCint *attrList); ALCAPI ALCboolean ALCAPIENTRY (*alcMakeContextCurrent)(ALCcontext *context); ALCAPI ALCvoid ALCAPIENTRY (*alcProcessContext)(ALCcontext *context); ALCAPI ALCcontext*ALCAPIENTRY (*alcGetCurrentContext)(ALCvoid); ALCAPI ALCdevice* ALCAPIENTRY (*alcGetContextsDevice)(ALCcontext *context); ALCAPI ALCvoid ALCAPIENTRY (*alcSuspendContext)(ALCcontext *context); ALCAPI ALCvoid ALCAPIENTRY (*alcDestroyContext)(ALCcontext *context); ALCAPI ALCenum ALCAPIENTRY (*alcGetError)(ALCdevice *device); ALCAPI ALCboolean ALCAPIENTRY (*alcIsExtensionPresent)(ALCdevice *device,ALCubyte *extName); ALCAPI ALCvoid * ALCAPIENTRY (*alcGetProcAddress)(ALCdevice *device,ALCubyte *funcName); ALCAPI ALCenum ALCAPIENTRY (*alcGetEnumValue)(ALCdevice *device,ALCubyte *enumName); #endif /* AL_NO_PROTOTYPES */ #ifdef TARGET_OS_MAC #if TARGET_OS_MAC #pragma export off #endif #endif #ifdef __cplusplus } #endif #endif --- NEW FILE: altypes.h --- #ifndef _ALTYPES_H_ #define _ALTYPES_H_ /** * OpenAL cross platform audio library * Copyright (C) 1999-2000 by authors. * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * Or go to http://www.gnu.org/copyleft/lgpl.html */ #ifdef __cplusplus extern "C" { #endif /** OpenAL boolean type. */ typedef char ALboolean; /** OpenAL 8bit signed byte. */ typedef char ALbyte; /** OpenAL 8bit unsigned byte. */ typedef unsigned char ALubyte; /** OpenAL 16bit signed short integer type. */ typedef short ALshort; /** OpenAL 16bit unsigned short integer type. */ typedef unsigned short ALushort; /** OpenAL 32bit unsigned integer type. */ typedef unsigned ALuint; /** OpenAL 32bit signed integer type. */ typedef int ALint; /** OpenAL 32bit floating point type. */ typedef float ALfloat; /** OpenAL 64bit double point type. */ typedef double ALdouble; /** OpenAL 32bit type. */ typedef unsigned int ALsizei; /** OpenAL void type */ typedef void ALvoid; /** OpenAL enumerations. */ typedef int ALenum; /* Bad value. */ #define AL_INVALID (-1) /* Disable value. */ #define AL_NONE 0 /* Boolean False. */ #define AL_FALSE 0 /* Boolean True. */ #define AL_TRUE 1 /** * Indicate the type of AL_SOURCE. * Sources can be spatialized */ #define AL_SOURCE_TYPE 0x200 /** Indicate source has absolute coordinates. */ #define AL_SOURCE_ABSOLUTE 0x201 /** Indicate Source has listener relative coordinates. */ #define AL_SOURCE_RELATIVE 0x202 /** * Directional source, inner cone angle, in degrees. * Range: [0-360] * Default: 360 */ #define AL_CONE_INNER_ANGLE 0x1001 /** * Directional source, outer cone angle, in degrees. * Range: [0-360] * Default: 360 */ #define AL_CONE_OUTER_ANGLE 0x1002 /** * Specify the pitch to be applied, either at source, * or on mixer results, at listener. * Range: [0.5-2.0] * Default: 1.0 */ #define AL_PITCH 0x1003 /** * Specify the current location in three dimensional space. * OpenAL, like OpenGL, uses a right handed coordinate system, * where in a frontal default view X (thumb) points right, * Y points up (index finger), and Z points towards the * viewer/camera (middle finger). * To switch from a left handed coordinate system, flip the * sign on the Z coordinate. * Listener position is always in the world coordinate system. */ #define AL_POSITION 0x1004 /** Specify the current direction as forward vector. */ #define AL_DIRECTION 0x1005 /** Specify the current velocity in three dimensional space. */ #define AL_VELOCITY 0x1006 /** * Indicate whether source has to loop infinite. * Type: ALboolean * Range: [AL_TRUE, AL_FALSE] * Default: AL_FALSE */ #define AL_LOOPING 0x1007 /** * Indicate the buffer to provide sound samples. * Type: ALuint. * Range: any valid Buffer id. */ #define AL_BUFFER 0x1009 /** * Indicate the gain (volume amplification) applied. * Type: ALfloat. * Range: ]0.0- ] * A value of 1.0 means un-attenuated/unchanged. * Each division by 2 equals an attenuation of -6dB. * Each multiplicaton with 2 equals an amplification of +6dB. * A value of 0.0 is meaningless with respect to a logarithmic * scale; it is interpreted as zero volume - the channel * is effectively disabled. */ #define AL_GAIN 0x100A /** * Indicate minimum source attenuation. * Type: ALfloat * Range: [0.0 - 1.0] */ #define AL_MIN_GAIN 0x100D /** * Indicate maximum source attenuation. * Type: ALfloat * Range: [0.0 - 1.0] */ #define AL_MAX_GAIN 0x100E /** * Specify the current orientation. * Type: ALfv6 (at/up) * Range: N/A */ #define AL_ORIENTATION 0x100F /* byte offset into source (in canon format). -1 if source * is not playing. Don't set this, get this. * * Type: ALfloat * Range: [0.0 - ] * Default: 1.0 */ #define AL_REFERENCE_DISTANCE 0x1020 /** * Indicate the rolloff factor for the source. * Type: ALfloat * Range: [0.0 - ] * Default: 1.0 */ #define AL_ROLLOFF_FACTOR 0x1021 /** * Indicate the gain (volume amplification) applied. * Type: ALfloat. * Range: ]0.0- ] * A value of 1.0 means un-attenuated/unchanged. * Each division by 2 equals an attenuation of -6dB. * Each multiplicaton with 2 equals an amplification of +6dB. * A value of 0.0 is meaningless with respect to a logarithmic * scale; it is interpreted as zero volume - the channel * is effectively disabled. */ #define AL_CONE_OUTER_GAIN 0x1022 /** * Specify the maximum distance. * Type: ALfloat * Range: [0.0 - ] */ #define AL_MAX_DISTANCE 0x1023 /** * Specify the channel mask. (Creative) * Type: ALuint * Range: [0 - 255] */ #define AL_CHANNEL_MASK 0x3000 /** * Source state information */ #define AL_SOURCE_STATE 0x1010 #define AL_INITIAL 0x1011 #define AL_PLAYING 0x1012 #define AL_PAUSED 0x1013 #define AL_STOPPED 0x1014 /** * Buffer Queue params */ #define AL_BUFFERS_QUEUED 0x1015 #define AL_BUFFERS_PROCESSED 0x1016 /** Sound buffers: format specifier. */ #define AL_FORMAT_MONO8 0x1100 #define AL_FORMAT_MONO16 0x1101 #define AL_FORMAT_STEREO8 0x1102 #define AL_FORMAT_STEREO16 0x1103 /** * Sound buffers: frequency, in units of Hertz [Hz]. * This is the number of samples per second. Half of the * sample frequency marks the maximum significant * frequency component. */ #define AL_FREQUENCY 0x2001 #define AL_BITS 0x2002 #define AL_CHANNELS 0x2003 #define AL_SIZE 0x2004 #define AL_DATA 0x2005 /** * Buffer state. * * Not supported for public use (yet). */ #define AL_UNUSED 0x2010 #define AL_PENDING 0x2011 #define AL_PROCESSED 0x2012 /** Errors: No Error. */ #define AL_NO_ERROR AL_FALSE /** * Illegal name passed as an argument to an AL call. */ #define AL_INVALID_NAME 0xA001 /** * Illegal enum passed as an argument to an AL call. */ #define AL_INVALID_ENUM 0xA002 /** * Illegal value passed as an argument to an AL call. * Applies to parameter values, but not to enumerations. */ #define AL_INVALID_VALUE 0xA003 /** * A function was called at inappropriate time, * or in an inappropriate way, causing an illegal state. * This can be an incompatible ALenum, object ID, * and/or function. */ #define AL_INVALID_OPERATION 0xA004 /** * A function could not be completed, * because there is not enough memory available. */ #define AL_OUT_OF_MEMORY 0xA005 /** Context strings: Vendor Name. */ #define AL_VENDOR 0xB001 #define AL_VERSION 0xB002 #define AL_RENDERER 0xB003 #define AL_EXTENSIONS 0xB004 /** Global tweakage. */ /** * Doppler scale. Default 1.0 */ #define AL_DOPPLER_FACTOR 0xC000 /** * Doppler velocity. Default 1.0 */ #define AL_DOPPLER_VELOCITY 0xC001 /** * Distance model. Default AL_INVERSE_DISTANCE_CLAMPED */ #define AL_DISTANCE_MODEL 0xD000 /** Distance models. */ #define AL_INVERSE_DISTANCE 0xD001 #define AL_INVERSE_DISTANCE_CLAMPED 0xD002 /** * enables */ #ifdef __cplusplus } #endif #endif --- NEW FILE: OpenAL32.lib --- (This appears to be a binary file; contents omitted.) --- NEW FILE: ALut.lib --- (This appears to be a binary file; contents omitted.) --- NEW FILE: alInclude.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - Cross-platform OpenAL include file // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _ALINCLUDE_H_ #define _ALINCLUDE_H_ #include <alc.h> #include <alut.h> #endif --- NEW FILE: al.h --- #ifndef _AL_H_ #define _AL_H_ /** * OpenAL cross platform audio library * Copyright (C) 1999-2000 by authors. * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * Or go to http://www.gnu.org/copyleft/lgpl.html */ #include "altypes.h" #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 #ifdef _OPENAL32LIB #define ALAPI __declspec(dllexport) #else #define ALAPI __declspec(dllimport) #endif #define ALAPIENTRY __cdecl #define AL_CALLBACK #else #ifdef TARGET_OS_MAC #if TARGET_OS_MAC #pragma export on #endif #endif #define ALAPI #define ALAPIENTRY __cdecl #define AL_CALLBACK #endif #define OPENAL #ifndef AL_NO_PROTOTYPES /** * OpenAL Maintenance Functions * Initialization and exiting. * State Management and Query. * Error Handling. * Extension Support. */ /** State management. */ ALAPI ALvoid ALAPIENTRY alEnable( ALenum capability ); ALAPI ALvoid ALAPIENTRY alDisable( ALenum capability ); ALAPI ALboolean ALAPIENTRY alIsEnabled( ALenum capability ); /** Application preferences for driver performance choices. */ ALAPI ALvoid ALAPIENTRY alHint( ALenum target, ALenum mode ); /** State retrieval. */ ALAPI ALboolean ALAPIENTRY alGetBoolean( ALenum param ); ALAPI ALint ALAPIENTRY alGetInteger( ALenum param ); ALAPI ALfloat ALAPIENTRY alGetFloat( ALenum param ); ALAPI ALdouble ALAPIENTRY alGetDouble( ALenum param ); ALAPI ALvoid ALAPIENTRY alGetBooleanv( ALenum param, ALboolean* data ); ALAPI ALvoid ALAPIENTRY alGetIntegerv( ALenum param, ALint* data ); ALAPI ALvoid ALAPIENTRY alGetFloatv( ALenum param, ALfloat* data ); ALAPI ALvoid ALAPIENTRY alGetDoublev( ALenum param, ALdouble* data ); ALAPI ALubyte* ALAPIENTRY alGetString( ALenum param ); /** * Error support. * Obtain the most recent error generated in the AL state machine. */ ALAPI ALenum ALAPIENTRY alGetError( ALvoid ); /** * Extension support. * Obtain the address of a function (usually an extension) * with the name fname. All addresses are context-independent. */ ALAPI ALboolean ALAPIENTRY alIsExtensionPresent( ALubyte* fname ); /** * Extension support. * Obtain the address of a function (usually an extension) * with the name fname. All addresses are context-independent. */ ALAPI ALvoid* ALAPIENTRY alGetProcAddress( ALubyte* fname ); /** * Extension support. * Obtain the integer value of an enumeration (usually an extension) with the name ename. */ ALAPI ALenum ALAPIENTRY alGetEnumValue( ALubyte* ename ); /** * LISTENER * Listener is the sample position for a given context. * The multi-channel (usually stereo) output stream generated * by the mixer is parametrized by this Listener object: * its position and velocity relative to Sources, within * occluder and reflector geometry. */ /** * * Listener Environment: default 0. */ ALAPI ALvoid ALAPIENTRY alListeneri( ALenum param, ALint value ); /** * * Listener Gain: default 1.0f. */ ALAPI ALvoid ALAPIENTRY alListenerf( ALenum param, ALfloat value ); /** * * Listener Position. * Listener Velocity. */ ALAPI ALvoid ALAPIENTRY alListener3f( ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); /** * * Listener Position: ALfloat[3] * Listener Velocity: ALfloat[3] * Listener Orientation: ALfloat[6] (forward and up vector). */ ALAPI ALvoid ALAPIENTRY alListenerfv( ALenum param, ALfloat* values ); ALAPI ALvoid ALAPIENTRY alGetListeneri( ALenum param, ALint* value ); ALAPI ALvoid ALAPIENTRY alGetListenerf( ALenum param, ALfloat* value ); ALAPI ALvoid ALAPIENTRY alGetListener3f( ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 ); ALAPI ALvoid ALAPIENTRY alGetListenerfv( ALenum param, ALfloat* values ); /** * SOURCE * Source objects are by default localized. Sources * take the PCM data provided in the specified Buffer, * apply Source-specific modifications, and then * submit them to be mixed according to spatial * arrangement etc. */ /** Create Source objects. */ ALAPI ALvoid ALAPIENTRY alGenSources( ALsizei n, ALuint* sources ); /** Delete Source objects. */ ALAPI ALvoid ALAPIENTRY alDeleteSources( ALsizei n, ALuint* sources ); /** Verify a handle is a valid Source. */ ALAPI ALboolean ALAPIENTRY alIsSource( ALuint id ); /** Set an integer parameter for a Source object. */ ALAPI ALvoid ALAPIENTRY alSourcei( ALuint source, ALenum param, ALint value ); ALAPI ALvoid ALAPIENTRY alSourcef( ALuint source, ALenum param, ALfloat value ); ALAPI ALvoid ALAPIENTRY alSource3f( ALuint source, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); ALAPI ALvoid ALAPIENTRY alSourcefv( ALuint source, ALenum param, ALfloat* values ); /** Get an integer parameter for a Source object. */ ALAPI ALvoid ALAPIENTRY alGetSourcei( ALuint source, ALenum param, ALint* value ); ALAPI ALvoid ALAPIENTRY alGetSourcef( ALuint source, ALenum param, ALfloat* value ); ALAPI ALvoid ALAPIENTRY alGetSource3f( ALuint source, ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 ); ALAPI ALvoid ALAPIENTRY alGetSourcefv( ALuint source, ALenum param, ALfloat* values ); ALAPI ALvoid ALAPIENTRY alSourcePlayv( ALsizei n, ALuint *sources ); ALAPI ALvoid ALAPIENTRY alSourcePausev( ALsizei n, ALuint *sources ); ALAPI ALvoid ALAPIENTRY alSourceStopv( ALsizei n, ALuint *sources ); ALAPI ALvoid ALAPIENTRY alSourceRewindv(ALsizei n,ALuint *sources); /** Activate a source, start replay. */ ALAPI ALvoid ALAPIENTRY alSourcePlay( ALuint source ); /** * Pause a source, * temporarily remove it from the mixer list. */ ALAPI ALvoid ALAPIENTRY alSourcePause( ALuint source ); /** * Stop a source, * temporarily remove it from the mixer list, * and reset its internal state to pre-Play. * To remove a Source completely, it has to be * deleted following Stop, or before Play. */ ALAPI ALvoid ALAPIENTRY alSourceStop( ALuint source ); /** * Rewinds a source, * temporarily remove it from the mixer list, * and reset its internal state to pre-Play. */ ALAPI ALvoid ALAPIENTRY alSourceRewind( ALuint source ); /** * BUFFER * Buffer objects are storage space for sample data. * Buffers are referred to by Sources. There can be more than * one Source using the same Buffer data. If Buffers have * to be duplicated on a per-Source basis, the driver has to * take care of allocation, copying, and deallocation as well * as propagating buffer data changes. */ /** Buffer object generation. */ ALAPI ALvoid ALAPIENTRY alGenBuffers( ALsizei n, ALuint* buffers ); ALAPI ALvoid ALAPIENTRY alDeleteBuffers( ALsizei n, ALuint* buffers ); ALAPI ALboolean ALAPIENTRY alIsBuffer( ALuint buffer ); /** * Specify the data to be filled into a buffer. */ ALAPI ALvoid ALAPIENTRY alBufferData( ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq ); ALAPI ALvoid ALAPIENTRY alGetBufferi( ALuint buffer, ALenum param, ALint* value ); ALAPI ALvoid ALAPIENTRY alGetBufferf( ALuint buffer, ALenum param, ALfloat* value ); /** * Queue stuff */ ALAPI ALvoid ALAPIENTRY alSourceQueueBuffers( ALuint source, ALsizei n, ALuint* buffers ); ALAPI ALvoid ALAPIENTRY alSourceUnqueueBuffers( ALuint source, ALsizei n, ALuint* buffers ); /** * Knobs and dials */ ALAPI ALvoid ALAPIENTRY alDistanceModel( ALenum value ); ALAPI ALvoid ALAPIENTRY alDopplerFactor( ALfloat value ); ALAPI ALvoid ALAPIENTRY alDopplerVelocity( ALfloat value ); #else /* AL_NO_PROTOTYPES */ /** * OpenAL Maintenance Functions * Initialization and exiting. * State Management and Query. * Error Handling. * Extension Support. */ /** State management. */ ALAPI ALvoid ALAPIENTRY (*alEnable)( ALenum capability ); ALAPI ALvoid ALAPIENTRY (*alDisable)( ALenum capability ); ALAPI ALboolean ALAPIENTRY (*alIsEnabled)( ALenum capability ); /** Application preferences for driver performance choices. */ ALAPI ALvoid ALAPIENTRY (*alHint)( ALenum target, ALenum mode ); /** State retrieval. */ ALAPI ALboolean ALAPIENTRY (*alGetBoolean)( ALenum param ); ALAPI ALint ALAPIENTRY (*alGetInteger)( ALenum param ); ALAPI ALfloat ALAPIENTRY (*alGetFloat)( ALenum param ); ALAPI ALdouble ALAPIENTRY (*alGetDouble)( ALenum param ); ALAPI ALvoid ALAPIENTRY (*alGetBooleanv)( ALenum param, ALboolean* data ); ALAPI ALvoid ALAPIENTRY (*alGetIntegerv)( ALenum param, ALint* data ); ALAPI ALvoid ALAPIENTRY (*alGetFloatv)( ALenum param, ALfloat* data ); ALAPI ALvoid ALAPIENTRY (*alGetDoublev)( ALenum param, ALdouble* data ); ALAPI ALubyte* ALAPIENTRY (*alGetString)( ALenum param ); /** * Error support. * Obtain the most recent error generated in the AL state machine. */ ALAPI ALenum ALAPIENTRY (*alGetError)( ALvoid ); /** * Extension support. * Obtain the address of a function (usually an extension) * with the name fname. All addresses are context-independent. */ ALAPI ALboolean ALAPIENTRY (*alIsExtensionPresent)( ALubyte* fname ); /** * Extension support. * Obtain the address of a function (usually an extension) * with the name fname. All addresses are context-independent. */ ALAPI ALvoid* ALAPIENTRY (*alGetProcAddress)( ALubyte* fname ); /** * Extension support. * Obtain the integer value of an enumeration (usually an extension) with the name ename. */ ALAPI ALenum ALAPIENTRY (*alGetEnumValue)( ALubyte* ename ); /** * LISTENER * Listener is the sample position for a given context. * The multi-channel (usually stereo) output stream generated * by the mixer is parametrized by this Listener object: * its position and velocity relative to Sources, within * occluder and reflector geometry. */ /** * * Listener Environment: default 0. */ ALAPI ALvoid ALAPIENTRY (*alListeneri)( ALenum param, ALint value ); /** * * Listener Gain: default 1.0f. */ ALAPI ALvoid ALAPIENTRY (*alListenerf)( ALenum param, ALfloat value ); /** * * Listener Position. * Listener Velocity. */ ALAPI ALvoid ALAPIENTRY (*alListener3f)( ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); /** * * Listener Position: ALfloat[3] * Listener Velocity: ALfloat[3] * Listener Orientation: ALfloat[6] (forward and up vector). */ ALAPI ALvoid ALAPIENTRY (*alListenerfv)( ALenum param, ALfloat* values ); ALAPI ALvoid ALAPIENTRY (*alGetListeneri)( ALenum param, ALint* value ); ALAPI ALvoid ALAPIENTRY (*alGetListenerf)( ALenum param, ALfloat* value ); ALAPI ALvoid ALAPIENTRY (*alGetListener3f)( ALenum param, ALfloat* v1, ALfloat* v2, ALfloat* v3 ); ALAPI ALvoid ALAPIENTRY (*alGetListenerfv)( ALenum param, ALfloat* values ); /** * SOURCE * Source objects are by default localized. Sources * take the PCM data provided in the specified Buffer, * apply Source-specific modifications, and then * submit them to be mixed according to spatial * arrangement etc. */ /** Create Source objects. */ ALAPI ALvoid ALAPIENTRY (*alGenSources)( ALsizei n, ALuint* sources ); /** Delete Source objects. */ ALAPI ALvoid ALAPIENTRY (*alDeleteSources)( ALsizei n, ALuint* sources ); /** Verify a handle is a valid Source. */ ALAPI ALboolean ALAPIENTRY (*alIsSource)( ALuint id ); /** Set an integer parameter for a Source object. */ ALAPI ALvoid ALAPIENTRY (*alSourcei)( ALuint source, ALenum param, ALint value ); ALAPI ALvoid ALAPIENTRY (*alSourcef)( ALuint source, ALenum param, ALfloat value ); ALAPI ALvoid ALAPIENTRY (*alSource3f)( ALuint source, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 ); ALAPI ALvoid ALAPIENTRY (*alSourcefv)( ALuint source, ALenum param, ALfloat* values ); /** Get an integer parameter for a Source object. */ ALAPI ALvoid ALAPIENTRY (*alGetSourcei)( ALuint source, ALenum param, ALint* value ); ALAPI ALvoid ALAPIENTRY (*alGetSourcef)( ALuint source, ALenum param, ALfloat* value ); ALAPI ALvoid ALAPIENTRY (*alGetSourcefv)( ALuint source, ALenum param, ALfloat* values ); ALAPI ALvoid ALAPIENTRY (*alSourcePlayv)( ALsizei n, ALuint *sources ); ALAPI ALvoid ALAPIENTRY (*alSourceStopv)( ALsizei n, ALuint *sources ); /** Activate a source, start replay. */ ALAPI ALvoid ALAPIENTRY (*alSourcePlay)( ALuint source ); /** * Pause a source, * temporarily remove it from the mixer list. */ ALAPI ALvoid ALAPIENTRY (*alSourcePause)( ALuint source ); /** * Stop a source, * temporarily remove it from the mixer list, * and reset its internal state to pre-Play. * To remove a Source completely, it has to be * deleted following Stop, or before Play. */ ALAPI ALvoid ALAPIENTRY (*alSourceStop)( ALuint source ); /** * BUFFER * Buffer objects are storage space for sample data. * Buffers are referred to by Sources. There can be more than * one Source using the same Buffer data. If Buffers have * to be duplicated on a per-Source basis, the driver has to * take care of allocation, copying, and deallocation as well * as propagating buffer data changes. */ /** Buffer object generation. */ ALAPI ALvoid ALAPIENTRY (*alGenBuffers)( ALsizei n, ALuint* buffers ); ALAPI ALvoid ALAPIENTRY (*alDeleteBuffers)( ALsizei n, ALuint* buffers ); ALAPI ALboolean ALAPIENTRY (*alIsBuffer)( ALuint buffer ); /** * Specify the data to be filled into a buffer. */ ALAPI ALvoid ALAPIENTRY (*alBufferData)( ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq ); ALAPI ALvoid ALAPIENTRY (*alGetBufferi)( ALuint buffer, ALenum param, ALint* value ); ALAPI ALvoid ALAPIENTRY (*alGetBufferf)( ALuint buffer, ALenum param, ALfloat* value ); /** * Queue stuff */ ALAPI ALvoid ALAPIENTRY (*alSourceQueueBuffers)( ALuint source, ALsizei n, ALuint* buffers ); ALAPI ALvoid ALAPIENTRY (*alSourceUnqueueBuffers)( ALuint source, ALsizei n, ALuint* buffers ); /** * Knobs and dials */ ALAPI ALvoid ALAPIENTRY (*alDistanceModel)( ALenum value ); ALAPI ALvoid ALAPIENTRY (*alDopplerFactor)( ALfloat value ); ALAPI ALvoid ALAPIENTRY (*alDopplerVelocity)( ALfloat value ); #endif /* AL_NO_PROTOTYPES */ #ifdef TARGET_OS_MAC #if TARGET_OS_MAC #pragma export off #endif #endif #ifdef __cplusplus } #endif #endif --- NEW FILE: alctypes.h --- #ifndef _ALCTYPES_H_ #define _ALCTYPES_H_ /** * OpenAL cross platform audio library * Copyright (C) 1999-2000 by authors. * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * Or go to http://www.gnu.org/copyleft/lgpl.html */ #ifdef __cplusplus extern "C" { #endif /** ALC boolean type. */ typedef char ALCboolean; /** ALC 8bit signed byte. */ typedef char ALCbyte; /** ALC 8bit unsigned byte. */ typedef unsigned char ALCubyte; /** ALC 16bit signed short integer type. */ typedef short ALCshort; /** ALC 16bit unsigned short integer type. */ typedef unsigned short ALCushort; /** ALC 32bit unsigned integer type. */ typedef unsigned ALCuint; /** ALC 32bit signed integer type. */ typedef int ALCint; /** ALC 32bit floating point type. */ typedef float ALCfloat; /** ALC 64bit double point type. */ typedef double ALCdouble; /** ALC 32bit type. */ typedef unsigned int ALCsizei; /** ALC void type */ typedef void ALCvoid; /** ALC enumerations. */ typedef int ALCenum; /* Bad value. */ #define ALC_INVALID (-1) /* Boolean False. */ #define ALC_FALSE 0 /* Boolean True. */ #define ALC_TRUE 1 /** Errors: No Error. */ #define ALC_NO_ERROR ALC_FALSE #define ALC_MAJOR_VERSION 0x1000 #define ALC_MINOR_VERSION 0x1001 #define ALC_ATTRIBUTES_SIZE 0x1002 #define ALC_ALL_ATTRIBUTES 0x1003 #define ALC_DEFAULT_DEVICE_SPECIFIER 0x1004 #define ALC_DEVICE_SPECIFIER 0x1005 #define ALC_EXTENSIONS 0x1006 #define ALC_FREQUENCY 0x1007 #define ALC_REFRESH 0x1008 #define ALC_SYNC 0x1009 /** * The device argument does not name a valid dvice. */ #define ALC_INVALID_DEVICE 0xA001 /** * The context argument does not name a valid context. */ #define ALC_INVALID_CONTEXT 0xA002 /** * A function was called at inappropriate time, * or in an inappropriate way, causing an illegal state. * This can be an incompatible ALenum, object ID, * and/or function. */ #define ALC_INVALID_ENUM 0xA003 /** * Illegal value passed as an argument to an AL call. * Applies to parameter values, but not to enumerations. */ #define ALC_INVALID_VALUE 0xA004 /** * A function could not be completed, * because there is not enough memory available. */ #define ALC_OUT_OF_MEMORY 0xA005 #ifdef __cplusplus } #endif #endif --- NEW FILE: alu.h --- #ifndef _ALU_H_ #define _ALU_H_ #define ALUAPI #define ALUAPIENTRY __cdecl #define BUFFERSIZE 48000 #define FRACTIONBITS 14 #define FRACTIONMASK ((1L<<FRACTIONBITS)-1) #define OUTPUTCHANNELS 2 #include "altypes.h" #ifdef __cplusplus extern "C" { #endif ALUAPI ALint ALUAPIENTRY aluF2L(ALfloat value); ALUAPI ALshort ALUAPIENTRY aluF2S(ALfloat value); ALUAPI ALvoid ALUAPIENTRY aluCrossproduct(ALfloat *inVector1,ALfloat *inVector2,ALfloat *outVector); ALUAPI ALfloat ALUAPIENTRY aluDotproduct(ALfloat *inVector1,ALfloat *inVector2); ALUAPI ALvoid ALUAPIENTRY aluNormalize(ALfloat *inVector); ALUAPI ALvoid ALUAPIENTRY aluMatrixVector(ALfloat matrix[3][3],ALfloat *vector); ALUAPI ALvoid ALUAPIENTRY aluCalculateSourceParameters(ALuint source,ALuint channels,ALfloat *drysend,ALfloat *wetsend,ALfloat *pitch); ALUAPI ALvoid ALUAPIENTRY aluMixData(ALvoid *context,ALvoid *buffer,ALsizei size,ALenum format); ALUAPI ALvoid ALUAPIENTRY aluSetReverb(ALvoid *Reverb,ALuint Environment); ALUAPI ALvoid ALUAPIENTRY aluReverb(ALvoid *Reverb,ALfloat Buffer[][2],ALsizei BufferSize); #ifdef __cplusplus } #endif #endif |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:27
|
Update of /cvsroot/opentnl/tnl/osx/tnl.xcode In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/osx/tnl.xcode Added Files: project.pbxproj Log Message: Initial commit. --- NEW FILE: project.pbxproj --- // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 39; objects = { 089C165CFE840E0CC02AAC07 = { children = ( 089C165DFE840E0CC02AAC07, ); isa = PBXVariantGroup; name = InfoPlist.strings; refType = 4; sourceTree = "<group>"; }; 089C165DFE840E0CC02AAC07 = { fileEncoding = 10; isa = PBXFileReference; [...3736 lines suppressed...] }; 8D1107310486CEB800E47090 = { fileEncoding = 4; isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; refType = 4; sourceTree = "<group>"; }; 8D1107320486CEB800E47090 = { explicitFileType = wrapper.application; includeInIndex = 0; isa = PBXFileReference; path = TNLTest.app; refType = 3; sourceTree = BUILT_PRODUCTS_DIR; }; }; rootObject = 29B97313FDCFA39411CA2CEA; } |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:27
|
Update of /cvsroot/opentnl/tnl/osx In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/osx Added Files: Info.plist MyOpenGLView.h MyOpenGLView.mm main.mm version.plist Log Message: Initial commit. --- NEW FILE: MyOpenGLView.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #import <Cocoa/Cocoa.h> @interface MyOpenGLView : NSOpenGLView { id textWindow; } - (void) tick; - (void)mouseDown:(NSEvent *)theEvent; - (void)insertLogText: (const char *) text; @end --- NEW FILE: Info.plist --- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>TNLTest</string> <key>CFBundleIconFile</key> <string></string> <key>CFBundleIdentifier</key> <string>com.apple.myCocoaApp</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>0.1</string> <key>NSMainNibFile</key> <string>MainMenu</string> <key>NSPrincipalClass</key> <string>NSApplication</string> </dict> </plist> --- NEW FILE: MyOpenGLView.mm --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include <OpenGL/gl.h> #import "MyOpenGLView.h" #include "testGame.h" class TestGameLog : public LogConsumer { id myView; public: TestGameLog(id aView) { myView = aView; } void logString(const char *string) { printf("%s\n", string); //[myView insertLogText: avar("%s\n", string)]; } }; TestGameLog *theLog; @implementation MyOpenGLView /* Override NSView's initWithFrame: to specify our pixel format: */ - (id) initWithFrame: (NSRect) frame { GLuint attribs[] = { NSOpenGLPFANoRecovery, NSOpenGLPFAWindow, NSOpenGLPFAAccelerated, NSOpenGLPFADoubleBuffer, NSOpenGLPFAColorSize, 24, NSOpenGLPFAAlphaSize, 8, NSOpenGLPFADepthSize, 24, NSOpenGLPFAStencilSize, 8, NSOpenGLPFAAccumSize, 0, 0 }; [NSTimer scheduledTimerWithTimeInterval: 0.02 target: self selector:@selector(tick) userInfo:NULL repeats: true]; NSOpenGLPixelFormat* fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*) attribs]; if (!fmt) NSLog(@"No OpenGL pixel format"); theLog = new TestGameLog(self); [self restartAsClient:self]; return self = [super initWithFrame:frame pixelFormat: [fmt autorelease]]; } - (void) tick { if(clientGame) clientGame->tick(); if(serverGame) serverGame->tick(); [self setNeedsDisplay: YES]; } - (void) awakeFromNib { } /* Override the view's drawRect: to draw our GL content. */ - (void) drawRect: (NSRect) rect { if(clientGame) clientGame->renderFrame((U32) rect.size.width, (U32) rect.size.height); else if(serverGame) serverGame->renderFrame((U32) rect.size.width, (U32) rect.size.height); [[self openGLContext] flushBuffer]; } - (void)insertLogText: (const char *) text { [textWindow insertText: [NSString stringWithCString:text]]; } - (void)mouseDown:(NSEvent *)theEvent { NSPoint mouseLoc; mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil]; NSRect tempRect = [self bounds]; Position p; p.x = mouseLoc.x / NSWidth(tempRect); p.y = 1.0f - mouseLoc.y / NSHeight(tempRect); if(clientGame) clientGame->moveMyPlayerTo(p); else if(serverGame) serverGame->moveMyPlayerTo(p); } - (void)restartAsServer:sender { delete serverGame; delete clientGame; serverGame = new TestGame(true, Address(IPProtocol, Address::Any, 28999), Address("IP:Broadcast:28999")); clientGame = NULL; } - (void)restartAsClientPingingLocalhost:sender { delete serverGame; delete clientGame; serverGame = NULL; clientGame = new TestGame(false, Address(IPProtocol, Address::Any, 0), Address("IP:localhost:28999")); } - (void)restartAsClient:sender { delete serverGame; delete clientGame; serverGame = NULL; clientGame = new TestGame(false, Address(IPProtocol, Address::Any, 0), Address("IP:broadcast:28999")); } - (void)restartAsClientAndServer:sender { delete serverGame; delete clientGame; serverGame = new TestGame(true, Address(IPProtocol, Address::Any, 28999), Address("IP:Broadcast:28999")); clientGame = new TestGame(false, Address(IPProtocol, Address::Any, 0), Address("IP:broadcast:28999")); clientGame->createLocalConnection(serverGame); } @end --- NEW FILE: main.mm --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #import <Cocoa/Cocoa.h> int main(int argc, const char *argv[]) { return NSApplicationMain(argc, argv); } --- NEW FILE: version.plist --- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>BuildVersion</key> <string>17</string> <key>CFBundleShortVersionString</key> <string>0.1</string> <key>CFBundleVersion</key> <string>0.1</string> <key>ProjectName</key> <string>NibPBTemplates</string> <key>SourceVersion</key> <string>1150000</string> </dict> </plist> |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:26
|
Update of /cvsroot/opentnl/tnl/osx/English.lproj/MainMenu.nib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/osx/English.lproj/MainMenu.nib Added Files: classes.nib info.nib keyedobjects.nib Log Message: Initial commit. --- NEW FILE: info.nib --- <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>IBDocumentLocation</key> <string>68 68 356 240 0 0 1024 746 </string> <key>IBEditorPositions</key> <dict> <key>29</key> <string>116 253 341 44 0 0 1024 746 </string> </dict> <key>IBFramework Version</key> <string>349.0</string> <key>IBOpenObjects</key> <array> <integer>21</integer> <integer>29</integer> </array> <key>IBSystem Version</key> <string>7D24</string> </dict> </plist> --- NEW FILE: classes.nib --- { IBClasses = ( {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, { ACTIONS = { restartAsClient = id; restartAsClientAndServer = id; restartAsClientPingingLocalhost = id; restartAsServer = id; }; CLASS = MyOpenGLView; LANGUAGE = ObjC; SUPERCLASS = NSOpenGLView; } ); IBVersion = 1; } --- NEW FILE: keyedobjects.nib --- (This appears to be a binary file; contents omitted.) |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:26
|
Update of /cvsroot/opentnl/tnl/master In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/master Added Files: Makefile main.cpp master.dsp master.vcproj masterInterface.cpp masterInterface.h Log Message: Initial commit. --- NEW FILE: masterInterface.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - Master Server // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifndef _MASTERINTERFACE_H_ #define _MASTERINTERFACE_H_ #include "tnlEventConnection.h" #include "tnlRPC.h" using namespace TNL; // Useful string constants... static const char *MasterNoSuchHost = "No Such Host"; static const char *MasterRequestTimedOut = "Timed Out"; enum MasterConstants { ConnectRequestTimeout = 30000, IPMessageAddressCount = 30, GameMissionTypesPerPacket = 20, }; /// The MasterServerInterface is the RPC interface to the TNL example Master Server. /// The default Master Server tracks a list of public servers and allows clients /// to query for them based on different filter criteria, including maximum number of players, /// region codes, game or mission type, and others. /// /// When a client wants to initiate a connection with a server listed by the master, it /// can ask the Master Server to arranage a connection. The masterclient example that /// ships with TNL demonstrates a client/server console application that uses the Master /// Server to arrange connections between a client and a server instance. /// /// Client/Server programs using the Master Server for server listing should create /// a subclass of MasterServerInterface named "MasterServerConnection", and override /// all of the RPC methods that begin with m2c, as they signify master to client messages. /// RPC methods can be overridden with the TNL_DECLARE_RPC_OVERRIDE and TNL_IMPLEMENT_RPC_OVERRIDE methods. class MasterServerInterface : public EventConnection { protected: public: enum { MasterServerInterfaceVersion = 1, }; /// c2mQueryGameTypes is sent from the client to the master to request a list of /// game and mission types that current game servers are reporting. The queryId /// is specified by the client to identify the returning list from the master server. TNL_DECLARE_RPC(c2mQueryGameTypes, (U32 queryId)); /// m2cQueryGameTypesResponse is sent by the master server in response to a c2mQueryGameTypes /// from a client. The queryId will match the original queryId sent by the client. Clients /// should override this method in their custom MasterServerConnection classes. If there are /// more game or mission types than will fit in a single message, the master server will send /// multiple m2cQueryGameTypesResponse RPCs. The master will always send a final /// m2cQueryGameTypesResponse with Vectors of size 0 to indicate that no more game or mission /// types are to be added. TNL_DECLARE_RPC(m2cQueryGameTypesResponse, (U32 queryId, const Vector<StringTableEntry> &gameTypes, const Vector<StringTableEntry> &missionTypes)); /// c2mQueryServers is sent by the client to the master server to request a list of /// servers that match the specified filter criteria. A c2mQueryServers request will /// result in one or more m2cQueryServersResponse RPCs, with the final call having an empty /// Vector of servers. TNL_DECLARE_RPC(c2mQueryServers, (U32 queryId, U32 regionMask, U32 minPlayers, U32 maxPlayers, U32 infoFlags, U32 maxBots, U32 minCPUSpeed, StringTableEntry gameType, StringTableEntry missionType)); /// m2cQueryServersResponse is sent by the master server in response to a c2mQueryServers RPC, to /// return a partial list of the servers that matched the specified filter criteria. Because packets /// are limited in size, the response server list is broken up into lists of at most IPMessageAddressCount IP addresses /// per message. The Master Server will always send a final, empty m2cQueryServersResponse to signify that the list /// is complete. TNL_DECLARE_RPC(m2cQueryServersResponse, (U32 queryId, const Vector<IPAddress> &ipList)); /// c2mRequestArrangedConnection is an RPC sent from the client to the master to request an arranged /// connection with the specified server address. The internalAddress should be the client's own self-reported /// IP address. The connectionParameters buffer will be sent without modification to the specified /// server. TNL_DECLARE_RPC(c2mRequestArrangedConnection, (U32 requestId, IPAddressRef remoteAddress, IPAddressRef internalAddress, ByteBufferRef connectionParameters)); /// m2cClientRequestedArranged connection is sent from the master to a server to notify it that /// a client has requested a connection. The possibleAddresses vector is a list of possible IP addresses /// that the server should attempt to connect to for that client if it accepts the connection request. TNL_DECLARE_RPC(m2cClientRequestedArrangedConnection, (U32 requestId, const Vector<IPAddress> &possibleAddresses, ByteBufferRef connectionParameters)); /// c2mAcceptArrangedConnection is sent by a server to notify the master that it will accept the connection /// request from a client. The requestId parameter sent by the MasterServer in m2cClientRequestedArrangedConnection /// should be sent back as the requestId field. The internalAddress is the server's self-determined IP address. TNL_DECLARE_RPC(c2mAcceptArrangedConnection, (U32 requestId, IPAddressRef internalAddress, ByteBufferRef connectionData)); /// c2mRejectArrangedConnection notifies the Master Server that the server is rejecting the arranged connection /// request specified by the requestId. The rejectData will be passed along to the requesting client. TNL_DECLARE_RPC(c2mRejectArrangedConnection, (U32 requestId, ByteBufferRef rejectData)); /// m2cArrangedConnectionAccepted is sent to a client that has previously requested a connection to a listed server /// via c2mRequestArrangedConnection if the server accepted the connection. The possibleAddresses vector is the list /// of IP addresses the client should attempt to connect to, and the connectionData buffer is the buffer sent by the /// server upon accepting the connection. TNL_DECLARE_RPC(m2cArrangedConnectionAccepted, (U32 requestId, const Vector<IPAddress> &possibleAddresses, ByteBufferRef connectionData)); /// m2cArrangedConnectionRejected is sent to a client when an arranged connection request is rejected by the /// server, or when the request times out because the server never responded. TNL_DECLARE_RPC(m2cArrangedConnectionRejected, (U32 requestId, ByteBufferRef rejectData)); /// c2mUpdateServerStatus updates the status of a server to the Master Server, specifying the current game /// and mission types, any player counts and the current info flags. TNL_DECLARE_RPC(c2mUpdateServerStatus, ( StringTableEntry gameType, StringTableEntry missionType, U32 botCount, U32 playerCount, U32 maxPlayers, U32 infoFlags)); }; #endif --- NEW FILE: main.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - Master Server // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "tnlNetInterface.h" #include "masterInterface.h" #include "tnlVector.h" #include "tnlAsymmetricKey.h" using namespace TNL; NetInterface *gNetInterface = NULL; class MissionGameType : public Object { public: MissionGameType(const StringTableEntry &name) { mName = name; } StringTableEntry mName; }; class MasterServerConnection; class GameConnectRequest { public: SafePtr<MasterServerConnection> initiator; SafePtr<MasterServerConnection> host; U32 initiatorQueryId; U32 hostQueryId; U32 requestTime; }; class MasterServerConnection : public MasterServerInterface { private: typedef MasterServerInterface Parent; protected: /// @name Linked List /// /// The server stores its connections on a linked list. /// /// @{ /// MasterServerConnection *mNext; MasterServerConnection *mPrev; /// @} /// @name Globals /// @{ /// static MasterServerConnection gServerList; static Vector< SafePtr<MissionGameType> > gMissionTypeList; static Vector< SafePtr<MissionGameType> > gGameTypeList; static Vector< GameConnectRequest* > gConnectList; /// @} /// @name Connection Info /// /// General information about this connection. /// /// @{ /// bool mIsGameServer; ///< True if this is a game server. U32 mStrikeCount; ///< Number of "strikes" this connection has... 3 strikes and you're out! U32 mLastQueryId; ///< The last query id for info from this master. U32 mLastActivityTime; ///< The last time we got a request or an update from this host. /// A list of connection requests we're working on fulfilling for this connection. Vector< GameConnectRequest* > mConnectList; /// @} /// @name Server Info /// /// This info is filled in if this connection maps to a /// game server. /// /// @{ U32 mRegionCode; ///< The region code in which this server operates. StringTableEntry mGameString; ///< The unique game string for this server or client. U32 mCPUSpeed; ///< The CPU speed of this server. U32 mInfoFlags; ///< Info flags describing this server. U32 mPlayerCount; ///< Current number of players on this server. U32 mMaxPlayers; ///< Maximum number of players on this server. U32 mNumBots; ///< Current number of bots on this server. RefPtr<MissionGameType> mCurrentGameType; RefPtr<MissionGameType> mCurrentMissionType; void setGameType(const StringTableEntry &gameType) { for(S32 i = 0; i < gGameTypeList.size(); i++) { if(gGameTypeList[i].isValid() && gGameTypeList[i]->mName == gameType) { mCurrentGameType = gGameTypeList[i]; return; } } mCurrentGameType = new MissionGameType(gameType); gGameTypeList.push_back((MissionGameType *)mCurrentGameType); } void setMissionType(const StringTableEntry &missionType) { for(S32 i = 0; i < gMissionTypeList.size(); i++) { if(gMissionTypeList[i].isValid() && gMissionTypeList[i]->mName == missionType) { mCurrentMissionType = gMissionTypeList[i]; return; } } mCurrentMissionType = new MissionGameType(missionType); gMissionTypeList.push_back((MissionGameType *) mCurrentMissionType); } /// @} public: /// Constructor initializes the linked list info with /// "safe" values so we don't explode if we destruct /// right away. MasterServerConnection() { mStrikeCount = 0; mLastActivityTime = 0; mNext = this; mPrev = this; setIsConnectionToClient(); setIsAdaptive(); } /// Destructor removes the connection from the doubly linked list of /// server connections. ~MasterServerConnection() { // unlink it if it's in the list mPrev->mNext = mNext; mNext->mPrev = mPrev; logprintf("%s disconnected", getNetAddress().toString()); } /// Adds this connection to the doubly linked list of servers. void linkToServerList() { mNext = gServerList.mNext; mPrev = gServerList.mNext->mPrev; mNext->mPrev = this; mPrev->mNext = this; } /// RPC's a list of mission and game types to the requesting client. /// This function also cleans up any game types from the global lists /// that are no longer referenced. TNL_DECLARE_RPC_OVERRIDE(c2mQueryGameTypes, (U32 queryId)) { Vector<StringTableEntry> gameTypes(GameMissionTypesPerPacket); Vector<StringTableEntry> missionTypes(GameMissionTypesPerPacket); U32 listSize = 0; // Iterate through game types list, culling out any null entries. // Add all non-null entries to the gameTypes vector. for(S32 i = 0; i < gGameTypeList.size(); ) { if(gGameTypeList[i].isNull()) { gGameTypeList.erase_fast(i); continue; } gameTypes.push_back(gGameTypeList[i]->mName); i++; listSize++; if(listSize >= GameMissionTypesPerPacket) { m2cQueryGameTypesResponse(queryId, gameTypes, missionTypes); listSize = 0; gameTypes.clear(); } } // Iterate through mission types list, culling out any null entries. // Add all non-null entries to the missionTypes vector. for(S32 i = 0; i < gMissionTypeList.size(); ) { if(gMissionTypeList[i].isNull()) { gMissionTypeList.erase_fast(i); continue; } missionTypes.push_back(gMissionTypeList[i]->mName); i++; listSize++; if(listSize >= GameMissionTypesPerPacket) { m2cQueryGameTypesResponse(queryId, gameTypes, missionTypes); listSize = 0; gameTypes.clear(); missionTypes.clear(); } } // Send the last lists to the client. m2cQueryGameTypesResponse(queryId, gameTypes, missionTypes); // Send a pair of empty lists to the client to signify that the // query is done. if(gameTypes.size() || missionTypes.size()) { gameTypes.clear(); missionTypes.clear(); m2cQueryGameTypesResponse(queryId, gameTypes, missionTypes); } } /// The query server method builds a piecewise list of servers /// that match the client's particular filter criteria and /// sends it to the client, followed by a QueryServersDone RPC. TNL_DECLARE_RPC_OVERRIDE(c2mQueryServers, (U32 queryId, U32 regionMask, U32 minPlayers, U32 maxPlayers, U32 infoFlags, U32 maxBots, U32 minCPUSpeed, StringTableEntry gameType, StringTableEntry missionType) ) { Vector<IPAddress> theVector(IPMessageAddressCount); theVector.reserve(IPMessageAddressCount); for(MasterServerConnection *walk = gServerList.mNext; walk != &gServerList; walk = walk->mNext) { // Skip to the next if we don't match on any particular... if(walk->mGameString != mGameString) continue; if(!(walk->mRegionCode & regionMask)) continue; if(walk->mPlayerCount > maxPlayers || walk->mPlayerCount < minPlayers) continue; if(infoFlags & ~walk->mInfoFlags) continue; if(maxBots < walk->mNumBots) continue; if(minCPUSpeed > walk->mCPUSpeed) continue; if(gameType.isNotNull() && (gameType != walk->mCurrentGameType->mName)) continue; if(missionType.isNotNull() && (missionType != walk->mCurrentMissionType->mName)) continue; // Somehow we matched! Add us to the results list. theVector.push_back(walk->getNetAddress().toIPAddress()); // If we get a packet's worth, send it to the client and empty our buffer... if(theVector.size() == IPMessageAddressCount) { m2cQueryServersResponse(queryId, theVector); theVector.clear(); } } m2cQueryServersResponse(queryId, theVector); // If we sent any with the previous message, send another list with no servers. if(theVector.size()) { theVector.clear(); m2cQueryServersResponse(queryId, theVector); } } /// checkActivityTime validates that this particular connection is /// not issuing too many requests at once in an attempt to DOS /// by flooding either the master server or any other server /// connected to it. A client whose last activity time falls /// within the specified delta gets a strike... 3 strikes and /// you're out! Strikes go away after being good for a while. void checkActivityTime(U32 timeDeltaMinimum) { U32 currentTime = Platform::getRealMilliseconds(); if(currentTime - mLastActivityTime < timeDeltaMinimum) { mStrikeCount++; if(mStrikeCount == 3) disconnect("You're out!"); } else if(mStrikeCount > 0) mStrikeCount--; } void removeConnectRequest(GameConnectRequest *gcr) { for(S32 j = 0; j < mConnectList.size(); j++) { if(gcr == mConnectList[j]) { mConnectList.erase_fast(j); break; } } } GameConnectRequest *findAndRemoveRequest(U32 requestId) { GameConnectRequest *req = NULL; for(S32 j = 0; j < mConnectList.size(); j++) { if(mConnectList[j]->hostQueryId == requestId) { req = mConnectList[j]; mConnectList.erase_fast(j); break; } } if(!req) return NULL; if(req->initiator.isValid()) req->initiator->removeConnectRequest(req); for(S32 j = 0; j < gConnectList.size(); j++) { if(gConnectList[j] == req) { gConnectList.erase_fast(j); break; } } return req; } // This is called when a client wishes to arrange a connection with a // server. TNL_DECLARE_RPC_OVERRIDE(c2mRequestArrangedConnection, (U32 requestId, IPAddressRef remoteAddress, IPAddressRef internalAddress, ByteBufferRef connectionParameters)) { // First, make sure that we're connected with the server that they're requesting a connection with. MasterServerConnection *conn = (MasterServerConnection *) gNetInterface->findConnection(remoteAddress); if(!conn) { c2mRejectArrangedConnection(requestId, ByteBuffer((U8 *) MasterNoSuchHost, strlen(MasterNoSuchHost) + 1)); return; } // Record the request... GameConnectRequest *req = new GameConnectRequest; req->initiator = this; req->host = conn; req->initiatorQueryId = requestId; req->hostQueryId = mLastQueryId++; req->requestTime = Platform::getRealMilliseconds(); char buf[256]; strcpy(buf, getNetAddress().toString()); logprintf("Client: %s requested connection to %s", buf, conn->getNetAddress().toString()); // Add the request to the relevan lists (the global list, this connection's list, // and the other connection's list). mConnectList.push_back(req); conn->mConnectList.push_back(req); gConnectList.push_back(req); // Do some DOS checking... checkActivityTime(2000); // Get our address... Address theAddress = conn->getNetAddress(); // Record some different addresses to try... Vector<IPAddress> possibleAddresses; // The address, but port+1 theAddress.port++; possibleAddresses.push_back(theAddress.toIPAddress()); // The address, with the original port theAddress.port--; possibleAddresses.push_back(theAddress.toIPAddress()); // Or the address the port thinks it's talking to. Address theInternalAddress(internalAddress); Address anyAddress; // (Only store that last one if it's not the any address.) if(!theInternalAddress.isEqualAddress(anyAddress) && theInternalAddress != theAddress) possibleAddresses.push_back(internalAddress); // And inform the other part of the request. conn->m2cClientRequestedArrangedConnection(req->hostQueryId, possibleAddresses, connectionParameters); } // Called to indicate a connect request is being accepted. TNL_DECLARE_RPC_OVERRIDE(c2mAcceptArrangedConnection, (U32 requestId, IPAddressRef internalAddress, ByteBufferRef connectionData)) { GameConnectRequest *req = findAndRemoveRequest(requestId); if(!req) return; Address theAddress = getNetAddress(); Vector<IPAddress> possibleAddresses; theAddress.port++; possibleAddresses.push_back(theAddress.toIPAddress()); theAddress.port--; possibleAddresses.push_back(theAddress.toIPAddress()); Address theInternalAddress(internalAddress); Address anyAddress; if(!theInternalAddress.isEqualAddress(anyAddress) && theInternalAddress != theAddress) possibleAddresses.push_back(internalAddress); char buffer[256]; strcpy(buffer, getNetAddress().toString()); logprintf("Server: %s accept connection request from %s", buffer, req->initiator.isValid() ? req->initiator->getNetAddress().toString() : "Unknown"); // If we still know about the requestor, tell him his connection was accepted... if(req->initiator.isValid()) req->initiator->m2cArrangedConnectionAccepted(req->initiatorQueryId, possibleAddresses, connectionData); delete req; } // Called to indicate a connect request is being rejected. TNL_DECLARE_RPC_OVERRIDE(c2mRejectArrangedConnection, (U32 requestId, ByteBufferRef rejectData)) { GameConnectRequest *req = findAndRemoveRequest(requestId); if(!req) return; logprintf("Server: %s reject connection request from %s", getNetAddress().toString(), req->initiator.isValid() ? req->initiator->getNetAddress().toString() : "Unknown"); if(req->initiator.isValid()) req->initiator->m2cArrangedConnectionRejected(req->initiatorQueryId, rejectData); delete req; } // Called to update the status of a game server. TNL_DECLARE_RPC_OVERRIDE(c2mUpdateServerStatus, ( StringTableEntry gameType, StringTableEntry missionType, U32 botCount, U32 playerCount, U32 maxPlayers, U32 infoFlags)) { // If we didn't know we were a game server, don't accept updates. if(!mIsGameServer) return; setGameType(gameType); setMissionType(missionType); mNumBots = botCount; mPlayerCount = playerCount; mMaxPlayers = maxPlayers; mInfoFlags = infoFlags; checkActivityTime(15000); logprintf("Server: %s updated server status (%s, %s, %d, %d, %d)", getNetAddress().toString(), gameType.getString(), missionType.getString(), botCount, playerCount, maxPlayers); } bool readConnectRequest(BitStream *bstream, const char **errorString) { if(!Parent::readConnectRequest(bstream, errorString)) return false; char gameString[256]; bstream->readString(gameString); mGameString = gameString; // If it's a game server, read status info... if((mIsGameServer = bstream->readFlag()) == true) { bstream->read(&mCPUSpeed); bstream->read(&mRegionCode); bstream->read(&mNumBots); bstream->read(&mPlayerCount); bstream->read(&mMaxPlayers); bstream->read(&mInfoFlags); bstream->readString(gameString); setGameType(StringTableEntry(gameString)); bstream->readString(gameString); setMissionType(StringTableEntry(gameString)); linkToServerList(); } logprintf("%s online at %s", mIsGameServer ? "Server" : "client", getNetAddress().toString()); return true; } static void checkConnectTimeouts() { U32 currentTime = Platform::getRealMilliseconds(); // Expire any connect requests that have grown old... for(S32 i = 0; i < gConnectList.size(); ) { GameConnectRequest *gcr = gConnectList[i]; if(currentTime - gcr->requestTime > ConnectRequestTimeout) { // It's old! // So remove it from the initiator's list... if(gcr->initiator.isValid()) { gcr->initiator->removeConnectRequest(gcr); gcr->initiator->c2mRejectArrangedConnection(gcr->initiatorQueryId, ByteBuffer((U8 *) MasterRequestTimedOut, strlen(MasterRequestTimedOut) + 1)); } // And the host's lists.. if(gcr->host.isValid()) gcr->host->removeConnectRequest(gcr); // Delete it... delete gcr; // And remove it from our list, too. gConnectList.erase_fast(i); continue; } i++; } } TNL_DECLARE_NETCONNECTION(MasterServerConnection); }; TNL_IMPLEMENT_NETCONNECTION(MasterServerConnection, NetClassGroupMaster, true); Vector< SafePtr<MissionGameType> > MasterServerConnection::gMissionTypeList; Vector< SafePtr<MissionGameType> > MasterServerConnection::gGameTypeList; Vector< GameConnectRequest* > MasterServerConnection::gConnectList; MasterServerConnection MasterServerConnection::gServerList; //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- //-------------------------------------------------------------------------- #include <stdio.h> class StdoutLogConsumer : public LogConsumer { public: void logString(const char *string) { printf("%s\n", string); } } gStdoutLogConsumer; int main(int argc, const char **argv) { // Parse command line parameters... if(argc < 2) { logprintf("Error - you must specify a port on the command line."); return 0; } U32 port = atoi(argv[1]); // Initialize our net interface so we can accept connections... gNetInterface = new NetInterface(Address(IPProtocol, Address::Any, port)); //for the master server alone, we don't need a key exchange - that would be a waste //gNetInterface->setRequiresKeyExchange(true); //gNetInterface->setPrivateKey(new AsymmetricKey(20)); logprintf("Master Server created - listening on port %d", port); // And until infinity, process whatever comes our way. for(;;) { U32 currentTime = Platform::getRealMilliseconds(); gNetInterface->checkIncomingPackets(); gNetInterface->processConnections(); Platform::sleep(1); } return 0; } --- NEW FILE: master.vcproj --- <?xml version="1.0" encoding="Windows-1252"?> <VisualStudioProject ProjectType="Visual C++" Version="7.10" Name="master" ProjectGUID="{CE4F0113-8119-491D-BCBE-20F5C3A555FC}" Keyword="Win32Proj"> <Platforms> <Platform Name="Win32"/> </Platforms> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="Debug" IntermediateDirectory="Debug" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="../tnl" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="wsock32.lib" OutputFile="../exe/masterd.exe" LinkIncremental="2" GenerateDebugInformation="TRUE" ProgramDatabaseFile="$(OutDir)/master.pdb" SubSystem="1" TargetMachine="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="Release" IntermediateDirectory="Release" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="../tnl" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="4" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" DebugInformationFormat="3"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="wsock32.lib" OutputFile="../exe/master.exe" LinkIncremental="1" GenerateDebugInformation="TRUE" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" TargetMachine="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> </Configurations> <References> </References> <Files> <File RelativePath=".\main.cpp"> </File> <File RelativePath=".\masterInterface.cpp"> </File> <File RelativePath=".\masterInterface.h"> </File> </Files> <Globals> </Globals> </VisualStudioProject> --- NEW FILE: masterInterface.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - Master Server // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #include "masterInterface.h" // Since this is an interface, we implement a bunch of stubs. TNL_IMPLEMENT_RPC(MasterServerInterface, c2mQueryGameTypes, (U32 queryId), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, m2cQueryGameTypesResponse, (U32 queryId, const Vector<StringTableEntry> &gameTypes, const Vector<StringTableEntry> &missionTypes), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirServerToClient, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, c2mQueryServers, (U32 queryId, U32 regionMask, U32 minPlayers, U32 maxPlayers, U32 infoFlags, U32 maxBots, U32 minCPUSpeed, StringTableEntry gameType, StringTableEntry missionType), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, m2cQueryServersResponse, (U32 queryId, const Vector<IPAddress> &ipList), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirServerToClient, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, c2mRequestArrangedConnection, (U32 requestId, IPAddressRef remoteAddress, IPAddressRef internalAddress, ByteBufferRef connectionParameters), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, m2cClientRequestedArrangedConnection, (U32 requestId, const Vector<IPAddress> &possibleAddresses, ByteBufferRef connectionParameters), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirServerToClient, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, c2mAcceptArrangedConnection, (U32 requestId, IPAddressRef internalAddress, ByteBufferRef connectionData), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, c2mRejectArrangedConnection, (U32 requestId, ByteBufferRef rejectData), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, m2cArrangedConnectionAccepted, (U32 requestId, const Vector<IPAddress> &possibleAddresses, ByteBufferRef connectionData), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirServerToClient, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, m2cArrangedConnectionRejected, (U32 requestId, ByteBufferRef rejectData), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirServerToClient, 0) {} TNL_IMPLEMENT_RPC(MasterServerInterface, c2mUpdateServerStatus, ( StringTableEntry gameType, StringTableEntry missionType, U32 botCount, U32 playerCount, U32 maxPlayers, U32 infoFlags), NetClassGroupMasterMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) {} --- NEW FILE: Makefile --- # TNL Makefile # (c) 2003 GarageGames # # This makefile is for Linux atm. # # Configuration # CC=g++ -g -I../tnl #-O2 OBJECTS_MASTER=\ main.o\ masterInterface.o CFLAGS= .cpp.o : $(CC) -c $(CFLAGS) $< default: $(OBJECTS_MASTER) $(CC) -o master $(OBJECTS_MASTER) ../tnl/libtnl.a ../libtomcrypt/libtomcrypt.a -lstdc++ -lm clean: rm -f $(OBJECTS_MASTER) master --- NEW FILE: master.dsp --- # Microsoft Developer Studio Project File - Name="master" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=master - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "master.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "master.mak" CFG="master - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "master - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "master - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "master - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GR /GX /O2 /I "../tnl" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../exe/master.exe" !ELSEIF "$(CFG)" == "master - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "master___Win32_Debug" # PROP BASE Intermediate_Dir "master___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "master___Win32_Debug" # PROP Intermediate_Dir "master___Win32_Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../tnl" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../exe/masterd.exe" /pdbtype:sept !ENDIF # Begin Target # Name "master - Win32 Release" # Name "master - Win32 Debug" # Begin Source File SOURCE=.\main.cpp # End Source File # Begin Source File SOURCE=.\masterInterface.cpp # End Source File # Begin Source File SOURCE=.\masterInterface.h # End Source File # End Target # End Project |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:25
|
Update of /cvsroot/opentnl/tnl/osx/English.lproj In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/osx/English.lproj Added Files: InfoPlist.strings Log Message: Initial commit. --- NEW FILE: InfoPlist.strings --- (This appears to be a binary file; contents omitted.) |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:25
|
Update of /cvsroot/opentnl/tnl/masterclient In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/masterclient Added Files: Makefile main.cpp masterclient.dsp masterclient.vcproj Log Message: Initial commit. --- NEW FILE: masterclient.vcproj --- <?xml version="1.0" encoding="Windows-1252"?> <VisualStudioProject ProjectType="Visual C++" Version="7.10" Name="masterclient" ProjectGUID="{F931A5FA-FF37-4977-8493-786AFD5D71EC}" Keyword="Win32Proj"> <Platforms> <Platform Name="Win32"/> </Platforms> <Configurations> <Configuration Name="Debug|Win32" OutputDirectory="Debug" IntermediateDirectory="Debug" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="../tnl" PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE" MinimalRebuild="TRUE" BasicRuntimeChecks="3" RuntimeLibrary="5" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" DebugInformationFormat="4"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="wsock32.lib" OutputFile="../exe/masterclientd.exe" LinkIncremental="2" GenerateDebugInformation="TRUE" ProgramDatabaseFile="$(OutDir)/masterclient.pdb" SubSystem="1" TargetMachine="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> <Configuration Name="Release|Win32" OutputDirectory="Release" IntermediateDirectory="Release" ConfigurationType="1" CharacterSet="2"> <Tool Name="VCCLCompilerTool" AdditionalIncludeDirectories="../tnl" PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE" RuntimeLibrary="4" RuntimeTypeInfo="TRUE" UsePrecompiledHeader="0" WarningLevel="3" Detect64BitPortabilityProblems="TRUE" DebugInformationFormat="3"/> <Tool Name="VCCustomBuildTool"/> <Tool Name="VCLinkerTool" AdditionalDependencies="wsock32.lib" OutputFile="../exe/masterclient.exe" LinkIncremental="1" GenerateDebugInformation="TRUE" SubSystem="1" OptimizeReferences="2" EnableCOMDATFolding="2" TargetMachine="1"/> <Tool Name="VCMIDLTool"/> <Tool Name="VCPostBuildEventTool"/> <Tool Name="VCPreBuildEventTool"/> <Tool Name="VCPreLinkEventTool"/> <Tool Name="VCResourceCompilerTool"/> <Tool Name="VCWebServiceProxyGeneratorTool"/> <Tool Name="VCXMLDataGeneratorTool"/> <Tool Name="VCWebDeploymentTool"/> <Tool Name="VCManagedWrapperGeneratorTool"/> <Tool Name="VCAuxiliaryManagedWrapperGeneratorTool"/> </Configuration> </Configurations> <References> </References> <Files> <File RelativePath=".\main.cpp"> </File> <File RelativePath="..\master\masterInterface.cpp"> </File> <File RelativePath="..\master\masterInterface.h"> </File> </Files> <Globals> </Globals> </VisualStudioProject> --- NEW FILE: Makefile --- # TNL Makefile # (c) 2003 GarageGames # # This makefile is for Linux atm. # # Configuration # CC=g++ -g -I../tnl #-O2 OBJECTS_MASTER=\ ../master/masterInterface.o\ main.o CFLAGS= .cpp.o : $(CC) -c $(CFLAGS) $< default: $(OBJECTS_MASTER) $(CC) -o masterclient $(OBJECTS_MASTER) ../tnl/libtnl.a ../libtomcrypt/libtomcrypt.a -lstdc++ -lm clean: rm -f $(OBJECTS_MASTER) masterclient --- NEW FILE: main.cpp --- //----------------------------------------------------------------------------------- // // Torque Network Library - Master Server Game Client/Server example // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ // Master server test client. // // This program operates in one of two modes - as a game client // or a game server. // // In game server mode, which you can access by running: // // masterclient <masterAddress> -server <port> // // the process creates a MasterServerConnection to the master server // and periodically updates its server status with a random game type // and mission string. If the connection to the master server times // out or is disconnected, the server will attempt to reconnect to the // master. If a client requests an arranged connection, the server will // accept it 75% of the time, using a GameConnection instance for // the arranged connection. The GameConnection lasts between 15 and // 30 seconds (random), at which point the server will force a disconnect // with the client. // // The client behaves in much the same way. It will log in to the // master server, and upon successful connection will query the master // for a list of game servers. It will pick one of the servers // out of the list to connect to randomly and will initiate an // arranged connection with that host. If the connection to the // server is rejected, or if it connects succesfully and later disconnects, // it will restart the process of requesting a server list from the master. // // This example client demonstrates everything you need to know to implement // your own master server clients. #include <stdio.h> #include "tnlNetInterface.h" #include "../master/masterInterface.h" #include "tnlVector.h" #include "tnlRandom.h" using namespace TNL; class MasterServerConnection; class GameConnection; //------------------------------------------------------------------------ RefPtr<MasterServerConnection> gMasterServerConnection; RefPtr<GameConnection> gClientConnection; StringTableEntry gCurrentGameType("SomeGameType"); StringTableEntry gCurrentMissionType("SomeMissionType"); bool gIsServer = false; bool gQuit = false; void GameConnectionDone(); //------------------------------------------------------------------------ class GameConnection : public EventConnection { public: // The server maintains a linked list of clients... GameConnection *mNext; GameConnection *mPrev; static GameConnection gClientList; // Time in milliseconds at which we were created. U32 mCreateTime; GameConnection() { mNext = mPrev = this; mCreateTime = Platform::getRealMilliseconds(); } ~GameConnection() { // unlink ourselves if we're in the client list mPrev->mNext = mNext; mNext->mPrev = mPrev; // Tell the user... logprintf("%s disconnected", getNetAddress().toString()); } /// Adds this connection to the doubly linked list of clients. void linkToClientList() { mNext = gClientList.mNext; mPrev = gClientList.mNext->mPrev; mNext->mPrev = this; mPrev->mNext = this; } void onConnectionEstablished(bool isInitiator) { logprintf("connection to %s - %s established.", isInitiator ? "server" : "client", getNetAddress().toString()); // If we're a server (ie, being connected to by the client) add this new connection to // our list of clients. if(!isInitiator) linkToClientList(); } static void checkGameTimeouts() { // Look for people who have been connected longer than the threshold and // disconnect them. U32 currentTime = Platform::getRealMilliseconds(); for(GameConnection *walk = gClientList.mNext; walk != &gClientList; walk = walk->mNext) { if(currentTime - walk->mCreateTime > 15000) { walk->disconnect("You're done!"); break; } } } // Various things that should trigger us to try another server... void onConnectTimedOut() { GameConnectionDone(); } void onDisconnect(const char *reason) { logprintf("Remote host disconnected - %s", reason); GameConnectionDone(); } void onTimedOut() { GameConnectionDone(); } TNL_DECLARE_NETCONNECTION(GameConnection); }; // Global list of clients (if we're a server). GameConnection GameConnection::gClientList; TNL_IMPLEMENT_NETCONNECTION(GameConnection, NetClassGroupGame, false); //------------------------------------------------------------------------ class MasterServerConnection : public MasterServerInterface { typedef MasterServerInterface Parent; // ID of our current query. U32 mCurrentQueryId; // List of game servers from our last query. Vector<IPAddress> mIPList; public: MasterServerConnection() { mCurrentQueryId = 0; setIsConnectionToServer(); } void startGameTypesQuery() { // Kick off a game types query. mCurrentQueryId++; c2mQueryGameTypes(mCurrentQueryId); } TNL_DECLARE_RPC_OVERRIDE(m2cQueryGameTypesResponse, (U32 queryId, const Vector<StringTableEntry> &gameTypes, const Vector<StringTableEntry> &missionTypes)) { // Ignore old queries... if(queryId != mCurrentQueryId) return; // Inform the user of the results... logprintf("Got game types response - %d game types, %d mission types", gameTypes.size(), missionTypes.size()); for(S32 i = 0; i < gameTypes.size(); i++) logprintf("G(%d): %s", i, gameTypes[i].getString()); for(S32 i = 0; i < missionTypes.size(); i++) logprintf("M(%d): %s", i, missionTypes[i].getString()); // when we receive the final list of mission and game types, // query for servers: if(gameTypes.size() == 0 && missionTypes.size() == 0) { // Invalidate old queries mCurrentQueryId++; mIPList.clear(); // And automatically do a server query as well - you may not want to do things // in this order in your own clients. c2mQueryServers(mCurrentQueryId, 0xFFFFFFFF, 0, 128, 0, 128, 0, "", ""); } } TNL_DECLARE_RPC_OVERRIDE(m2cQueryServersResponse, (U32 queryId, const Vector<IPAddress> &ipList)) { // Only process results from current query... if(queryId != mCurrentQueryId) return; // Add the new results to our master result list... for(S32 i = 0; i < ipList.size(); i++) mIPList.push_back(ipList[i]); // if this was the last response, then echo out the list of servers, // and attempt to connect to one of them: if(ipList.size() == 0) { // Display the results... logprintf("got a list of servers from the master: %d servers", mIPList.size()); for(S32 i = 0; i < mIPList.size(); i++) logprintf(" %s", Address(mIPList[i]).toString()); // If we got anything... if(mIPList.size()) { // pick a random server to connect to: U32 index = Random::readI(0, mIPList.size() - 1); // Invalidate the query... mCurrentQueryId++; // And request an arranged connnection (notice gratuitous hardcoded payload) c2mRequestArrangedConnection(mCurrentQueryId, mIPList[index], getInterface()->getFirstBoundInterfaceAddress().toIPAddress(), ByteBuffer((U8 *) "Hello World!", 13)); logprintf("Requesting arranged connection with %s", Address(mIPList[index]).toString()); } else { logprintf("No game servers available... exiting."); gQuit = true; } } } TNL_DECLARE_RPC_OVERRIDE(m2cClientRequestedArrangedConnection, (U32 requestId, const Vector<IPAddress> &possibleAddresses, ByteBufferRef connectionParameters)) { if(!gIsServer || Random::readF() > 0.75) { // We reject connections about 75% of the time... logprintf("Rejecting arranged connection from %s", Address(possibleAddresses[0]).toString()); c2mRejectArrangedConnection(requestId, connectionParameters); } else { // Ok, let's do the arranged connection! U8 data[Nonce::NonceSize * 2 + SymmetricCipher::KeySize * 2]; ByteBuffer b(data, sizeof(data)); Random::read(data, sizeof(data)); IPAddress localAddress = getInterface()->getFirstBoundInterfaceAddress().toIPAddress(); c2mAcceptArrangedConnection(requestId, localAddress, b); GameConnection *conn = new GameConnection(); Vector<Address> fullPossibleAddresses; for(S32 i = 0; i < possibleAddresses.size(); i++) fullPossibleAddresses.push_back(Address(possibleAddresses[i])); logprintf("Accepting arranged connection from %s", Address(fullPossibleAddresses[0]).toString()); logprintf(" Generated shared secret data: %s", b.encodeBase64()->getBuffer()); ByteBufferPtr theSharedData = new ByteBuffer(data + 2 * Nonce::NonceSize, sizeof(data) - 2 * Nonce::NonceSize); Nonce nonce(data); Nonce serverNonce(data + Nonce::NonceSize); conn->connectArranged(getInterface(), fullPossibleAddresses, nonce, serverNonce, theSharedData,false); } } TNL_DECLARE_RPC_OVERRIDE(m2cArrangedConnectionAccepted, (U32 requestId, const Vector<IPAddress> &possibleAddresses, ByteBufferRef connectionData)) { if(!gIsServer && requestId == mCurrentQueryId && connectionData.getBufferSize() >= Nonce::NonceSize * 2 + SymmetricCipher::KeySize * 2) { logprintf("Remote host accepted arranged connection."); logprintf(" Shared secret data: %s", connectionData.encodeBase64()->getBuffer()); GameConnection *conn = new GameConnection(); Vector<Address> fullPossibleAddresses; for(S32 i = 0; i < possibleAddresses.size(); i++) fullPossibleAddresses.push_back(Address(possibleAddresses[i])); ByteBufferPtr theSharedData = new ByteBuffer( (U8 *) connectionData.getBuffer() + Nonce::NonceSize * 2, connectionData.getBufferSize() - Nonce::NonceSize * 2 ); Nonce nonce(connectionData.getBuffer()); Nonce serverNonce(connectionData.getBuffer() + Nonce::NonceSize); conn->connectArranged(getInterface(), fullPossibleAddresses, nonce, serverNonce, theSharedData,true); } } TNL_DECLARE_RPC_OVERRIDE(m2cArrangedConnectionRejected, (U32 requestId, ByteBufferRef rejectData)) { if(!gIsServer && requestId == mCurrentQueryId) { logprintf("Remote host rejected arranged connection..."); logprintf("Requesting new game types list."); startGameTypesQuery(); } } void writeConnectRequest(BitStream *bstream) { Parent::writeConnectRequest(bstream); bstream->writeString("MasterServerTestGame"); // Game Name if(bstream->writeFlag(gIsServer)) { bstream->write((U32) 1000); // CPU speed bstream->write((U32) 0xFFFFFFFF); // region code bstream->write((U32) 5); // num bots bstream->write((U32) 10); // num players bstream->write((U32) 32); // max players bstream->write((U32) 0); // info flags bstream->writeString(gCurrentGameType.getString()); // Game type bstream->writeString(gCurrentMissionType.getString()); // Mission type } } void onConnectionEstablished(bool isInitiator) { if(!gIsServer) startGameTypesQuery(); } TNL_DECLARE_NETCONNECTION(MasterServerConnection); }; TNL_IMPLEMENT_NETCONNECTION(MasterServerConnection, NetClassGroupMaster, false); //------------------------------------------------------------------------ // This is called when we lose our connection to a game server. void GameConnectionDone() { // If we're still talking to the master server... if(gMasterServerConnection.isValid() && gMasterServerConnection->getConnectionState() == NetConnection::Connected) { // Query again! gMasterServerConnection->startGameTypesQuery(); } else { logprintf("GameConnectionDone: No connection to master server available - terminating!"); gQuit = true; } } //------------------------------------------------------------------------ class StdoutLogConsumer : public LogConsumer { public: void logString(const char *string) { printf("%s\n", string); } } gStdoutLogConsumer; //------------------------------------------------------------------------ int main(int argc, const char **argv) { // Parse command line arguments... if(argc < 2) { logprintf("Usage: masterclient <masterAddress> [-client|-server] [port]"); return 0; } Address masterAddress(argv[1]); if(argc > 2) gIsServer = !stricmp(argv[2], "-server"); U32 port = 0; if(argc > 3) port = atoi(argv[3]); // Announce master status. logprintf("%s started - master is at %s.", gIsServer ? "Server" : "Client", masterAddress.toString()); // Initialize the random number generator. U32 value = Platform::getRealMilliseconds(); Random::addEntropy((U8 *) &value, sizeof(U32)); Random::addEntropy((U8 *) &value, sizeof(U32)); Random::addEntropy((U8 *) &value, sizeof(U32)); Random::addEntropy((U8 *) &value, sizeof(U32)); // Open a network port... NetInterface *theInterface = new NetInterface(Address(IPProtocol, Address::Any, port)); // And start processing. while(!gQuit) { // If we don't have a connection to the master server, then // create one and connect to it. if(!gMasterServerConnection.isValid() || (gMasterServerConnection->getConnectionState() == NetConnection::TimedOut || gMasterServerConnection->getConnectionState() == NetConnection::Disconnected)) { logprintf("Connecting to master server at %s", masterAddress.toString()); gMasterServerConnection = new MasterServerConnection; gMasterServerConnection->connect(theInterface, masterAddress); } // Make sure to process network traffic and connected clients... theInterface->checkIncomingPackets(); theInterface->processConnections(); GameConnection::checkGameTimeouts(); // Sleep a bit so we don't saturate the system. Platform::sleep(1); } // All done! return 0; } --- NEW FILE: masterclient.dsp --- # Microsoft Developer Studio Project File - Name="masterclient" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=masterclient - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "masterclient.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "masterclient.mak" CFG="masterclient - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "masterclient - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "masterclient - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "masterclient - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GR /GX /O2 /I "../tnl" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"../exe/masterclient.exe" !ELSEIF "$(CFG)" == "masterclient - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "masterclient___Win32_Debug" # PROP BASE Intermediate_Dir "masterclient___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "masterclient___Win32_Debug" # PROP Intermediate_Dir "masterclient___Win32_Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GR /GX /ZI /Od /I "../tnl" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"../exe/masterclientd.exe" /pdbtype:sept !ENDIF # Begin Target # Name "masterclient - Win32 Release" # Name "masterclient - Win32 Debug" # Begin Source File SOURCE=.\main.cpp # End Source File # Begin Source File SOURCE=..\master\masterInterface.cpp # End Source File # Begin Source File SOURCE=..\master\masterInterface.h # End Source File # End Target # End Project |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:24
|
Update of /cvsroot/opentnl/tnl/docs In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/docs Added Files: doco.css docs.plaintext.txt doxygen.html.cfg footer.html header.html tnl.css Log Message: Initial commit. --- NEW FILE: doxygen.html.cfg --- # Doxyfile 1.3-rc2 #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- PROJECT_NAME = TNL PROJECT_NUMBER = OUTPUT_DIRECTORY = ./docs OUTPUT_LANGUAGE = English EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES SHORT_NAMES = NO HIDE_SCOPE_NAMES = NO VERBATIM_HEADERS = NO SHOW_INCLUDE_FILES = YES JAVADOC_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = YES INHERIT_DOCS = YES INLINE_INFO = YES SORT_MEMBER_DOCS = NO DISTRIBUTE_GROUP_DOC = NO TAB_SIZE = 4 GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ALIASES = ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO SHOW_USED_FILES = NO #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = doxygen.log #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = ./tnl/tnl.overview.txt \ ./tnl/tnl.changelog.txt \ ./tnl/ \ ./master/ \ ./test/ \ FILE_PATTERNS = *.h \ *.txt RECURSIVE = YES EXCLUDE = */cvs/* \ */platformMacCarb/* \ */platformX86UNIX/* EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = NO REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = ./docs/header.html HTML_FOOTER = ./docs/footer.html HTML_STYLESHEET = ./docs/doco.css HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = YES CHM_FILE = tnl.chm HHC_LOCATION = . GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = YES ENUM_VALUES_PER_LINE = 1 GENERATE_TREEVIEW = YES TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = pdf LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = YES RTF_HYPERLINKS = YES RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_SCHEMA = XML_DTD = #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = ./tnl/ INCLUDE_FILE_PATTERNS = PREDEFINED = DOXYGENIZING \ TNL_DEBUG \ TNL_ENABLE_ASSERTS \ TNL_ENABLE_LOGGING EXPAND_AS_DEFINED = DeclareTemplatizedReadWrite SKIP_FUNCTION_MACROS = NO #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = NO HAVE_DOT = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = NO TEMPLATE_RELATIONS = YES INCLUDE_GRAPH = NO INCLUDED_BY_GRAPH = NO GRAPHICAL_HIERARCHY = YES DOT_IMAGE_FORMAT = png DOT_PATH = "/cygdrive/c/Progra~1/ATT/Graphviz/bin" DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 4 GENERATE_LEGEND = YES DOT_CLEANUP = NO #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO CGI_NAME = search.cgi CGI_URL = DOC_URL = DOC_ABSPATH = BIN_ABSPATH = /usr/local/bin/ EXT_DOC_PATHS = --- NEW FILE: docs.plaintext.txt --- Preface The Torque Network Library is a networking API designed to allow developers to easily add world-class multiuser simulation capabilities to their products. The TNL has proven successful in some of the most demanding multiplayer internet games and has gone through years of steady, evolutionary improvement. Scope of This Documentation Getting Started gives new users the information they need to download TNL source files, set up projects on supported compilers, and build and run the library and example programs. History of the TNL gives a brief history of the Torque Network Library from its origins as the network technology behind Sierra/Dynamix's Starsiege: TRIBES to its current status as a standalone network programming solution. Introduction to Network Programming Concepts introduces the developer to some of the basic concepts of network programming, including fundamental limitations of data networks, standard protocols, application network topologies, security and the hurdles the TNL will help them overcome in providing a consistent simulation on an unreliable communications medium. Introduction to the Torque Network Library Fundamentals describes the general strategies used in the TNL to overcome the inherent limitations of today's networks. Torque Network Library Architecture gives an overview of the major classes in the TNL, from the basic Socket layer to the advanced state replication facilities provided by the GhostConnection and NetObject layer. Torque Network Library Tutorials and Examples walks the developer through the sample programs provided with the TNL, including a simple, networked "Hello World!" program, the TNLTest graphical multiuser simulation and the master server and masterclient test program. We presume the reader is familiar with C++ programming and concepts. Acknowledgments Tom St. Denis - libtomcrypt Ari Juels and John Brainard for their work on Client Puzzles. Tuomas Aura, Pekka Nikander, and Jussipekka Leiwo of the Helsinki University of Technology for their work on DoS resistant Authenticat with Client Puzzles Getting Started Getting started with the Torque Network Library is a fairly simple process. 1. Get a CVS client for your computer (What is CVS?) Download WinCVS 1.3 for Windows systems Download MacCVSX for computers running Mac OS X Download CVS for linux/unix systems 2. Use CVS to download the current version of the TNL Downloading TNL using WinCVS Downloading TNL using MaxCVSX Downloading TNL using CVS 3. Build TNL using your C++ compiler Build TNL using Microsoft Visual C++ 6.0 Build TNL using Microsoft Visual Studio .NET 2003 Build TNL using XCode on Mac OS X Build TNL using make on linux 4. Run the example programs TNLTest - the simple TNL example "game" master and masterclient - an example master server for listing game servers Troubleshooting and Questions If you have any difficulties or questions downloading, building and running TNL or the example programs, check the FAQ first to see if an answer to your problem already exists. If that doesn't help, you can search or ask in the TNL Private Forums for assistance. <future> What is CVS Getting CVS Downloading CVS Building TNL Running example programs </future> With that overview complete, you should now have a working version of the Torque Network Library and its sample programs up and running on your computer. History of the Torque Network Library Near the end of 1997, a team of developers at Dynamix were hard at work on a new, network only game that would push the requirements of internet gaming technology to a new level. Starsiege: TRIBES allowed up to 32 players to compete in seamless indoor and outdoor areas with futuristic weapons, jet packs and vehicles. Unlike other games at the time that were limited to tight indoor environments, the TRIBES environment posed a more difficult set of networking problems. Because of their open nature, clients in the game could often see most of the other players, along with a large number of projecticles and simulated vehicles, turrets and other objects. Also, given the state of most internet connections at the time, it was decided that TRIBES must run well even over a 28.8 kbps modem, imposing a meager 2 Kbytes per second of bandwidth limitation on each client. With these requirements in mind, Mark Frohnmayer, Rick Overman and Tim Gift designed a network architecture that would maximize the information value of every bit transmitted over the network, and created a new "Notify" protocol that harnessed the unreliable nature of the network transport medium to eliminate unnecessary retransmission of information. The Tribes Network Architecture was further refined during the development of Tribes 2 to server more players (up to 100 in a single gaming area served by a 1GHz Pentium III) and save even more packet data space, introducing the concept of a network string table and only periodic control object state updating during client-side prediction. When the Tribes 2 engine became GarageGames' Torque Game Engine, additional iterative improvements were made, including checksums on client state data and a new network interface class to encapsulate the connection startup and prevent connection depletion Denial-of-Service attacks. The final step in the history of the Torque Network Library was to refactor its constituent parts into a standalone network technology that didn't require any other components from the Torque Game Engine. As a part of this process, significant library structural improvements were made; every class and class member were documented, and strong encryption support was added. Other new features include a simple and powerful Remote Procedure Call (RPC) mechanism, client puzzles for protecting servers from server CPU depletion Denial-of-Service attacks, and 3rd-party negotiated direct connections to connect clients behind firewalls and NAT (Network Address Translation) routers, making TNL a robust, full-featured, secure networking solution for a wide variety of applications. Introduction to Network Programming Concepts Computer networking technology allows computers that share the network to send messages to one another. Computer networks vary greatly in complexity, from two machines connected together with a link cable, to the globe-spanning internet connecting millions of machines together over fiber-optics, satellite links, phone lines and other mediums. Fundamental Limitations of Computer Networks Computer networks of any size share some common limitations to varying degrees that must be accounted for in network simulations, with the internet being the most limited in all three regards. These three fundamental problems in network simulation are: Limited Bandwidth - There is a limit to the rate at which hosts on the network can send data to one another. If a computer is connected to the network with a 56 kbps modem, this might be 5 Kbytes per second, while computers on a local area network might be able to communicate at 128 megabytes per second. For service providers, additional bandwidth capacity can be costly, so even if there is no physical bandwidth limitation, bandwidth conservation is important for many projects. Packet Loss - Computer networks are inherently unreliable. Information transmitted over a network may become corrupted in transit, or may be dropped at a router where traffic has become congested. Even when (especially when) using a guaranteed message delivery protocol such as TCP, the unreliable nature of the underlying network still must be taken into account for network applications. Latency - Messages sent from one host to another on the network take time to arrive at the destination. The time can be influenced by many factors, including the medium over which the messages travel, how many intermediate hosts must route the message, an the level of traffic congestion at each of those network nodes. Latency becomes particularly problematic in network simulations that attempt to present a real-time interface to the client, when the latency of the connection may be perceptible in time. Standard Network Protocols When computers communicate over networks, they send and receive data using specific network protocols. These protocols ensure that the computers are using the same specifications to address, forward and process data on the network. The internet, certainly the most widely used computer network today, uses a stack of three primary protocols that facilitate communication over the network. They are: IP - Internet Protocol: The Internet Protocol is the basic building block for internet communications. IP is a routing protocol, which means that it is used to route information packets from a source host to a destination host, specified by an IP address. IP packets are not guaranteed to arrive at the destination specified by the sender, and those packets that do arrive are not guaranteed to arrive in the order they were sent. IP packet payloads may also be corrupted when they are delivered. IP is not useful as an application protocol - it is used mainly as a foundation for the higher level TCP and UDP protocols. UDP - User Datagram Protocol: The User Datagram Protocol supplies a thin layer on top of IP that performs error detection and application level routing on a single host. UDP packets are addressed using both an IP address to specify the physical host, and a port number, to specify which process on the machine the packet should be delivered to. UDP packets also contain a checksum, so that corrupted packets can be discarded. UDP packets that are corrupted or dropped by an intermediate host are not retransmitted by the sender, because the sender is never notified whether a given packet was delivered or not. TCP/IP - Transmission Control Protocol: TCP was designed to make internet programming easier by building a reliable, connection-based protocol on top of the unreliable IP. TCP does this by sending acknowledgements when data packets arrive, and resending data that was dropped. TCP is a stream protocol, so the network connection can be treated like any other file stream in the system. TCP is not suitable for simulation data, because any dropped packets will stall the data pipeline until the dropped data can be retransmitted. Network Protocols and TNL Some network systems use both TCP and UDP - TCP for messages that must arrive, but are not time sensitive, and UDP for time-sensitive simulation updates. The next chapter discusses why this is not optimal for bandwidth conservation, and explains the protocol solution implemented in TNL. Berkeley (BSD) Sockets - the standard network API The BSD Sockets API describes a set of C language interface routines for communicating using the TCP protocol suite, including IP and UDP. The sockets API allows processes to open communcation "sockets" that can then be assigned to a particular integer port number on the host. Sockets created to use the TCP stream protocol can either be set to "listen()" for connections from remote hosts, or can be set to "connect()" to a remote host that is currently listening for incoming connections. Once a connection is established between two stream sockets, either side can send and receive guaranteed data to the other. Sockets can also be created in datagram mode, in which case they will use the underlying UDP protocol for transmission of datagram packets. Since the datagram socket mode is connectionless, the destination IP address and port must be specified with each data packet sent. The socket API contains other utility routines for performing operations such as host name resolution and socket options configuration. The Microsoft Windows platform supplies a Windows socket API called Winsock that implements the BSD socket API. Application Network Topologies Networked applications can be designed to communicate with each other using different topological organization strategies. Some common communcations organization paradigms are discussed below. Peer-to-Peer: In a peer-to-peer network application, the client processes involved in the network communicate directly with one another. Though there may be one or more hosts with authoritative control over the network of peers, peer-to-peer applications largely distribute the responsibility for the simulation or application amongst the peers. Client-Server: In the client-server model, one host on the network, the server, acts as a central communications hub for all the other hosts (the clients). Typically the server is authoritative, and is responsible for routing communication between the several clients. Client-Tiered Server Cluster: In network applications where more clients want to subscribe to a service than can be accomodated by one server, the server's role will be handled by a cluster of servers peered together. The servers in the network communicate using the peer-to-peer model, and communicate with the clients using the client-server model. The servers may also communicate with an authoritative "super-server" to handle logins or resolve conflicts. TNL imposes no specific network topology on applications using it. Security and Encryption When a message is sent between two hosts on a network, that message may pass through any number of intermediate wires, hosts and routers or even sent wirelessly to a satellite or a WiFi base station. This opens up the potential that some third party who has access to any one of the intermediate communication forwarding points may eavesdrop on and/or change the contents of the message. Often networked applications send sensitive user data, like credit card numbers, bank account information or private correspondence. These applications rely on encryption algorithms to protect messages sent over an unsecure network. Symmetric Encryption Symmetric Encryption algorithms operate under the assumption that the two parties sending messages to each other share a common, secret key. This key is used to encode the data in such a way that only users with the secret key can decode it. In the ideal case, the ciphertext (encoded version of the message) looks like a random string of bits to any eavesdropper. There are many Symmetric Encryption algorithms of varying levels of security, but all of them when used alone have several drawbacks. First, both parties to the communication must have a copy of the shared secret key. If a client is attempting to communicate with a service it has never contacted before, and doesn't share a key with, it won't be able to communicate securely with it. Also, although an intermediate eavesdropper cannot read the data sent between the hosts, it can alter the messages, potentially causing one or more of the systems to fail. Message Authentication In order to detect when a message has been altered by a third party, a secure messaging system will send a message authentication code (MAC) along with the data. The MAC is generated using a cryptographically secure hashing function, such as MD5 or SHA. Secure hash algorithms take an array of bytes and compute a cryptographically secure message digest of some fixed number of bytes - 16 in the case of MD5, 32 for SHA-256 and so on. When a message is sent using a symmetric cipher, the hash or some portion of it is encrypted and sent along as well. Any changes in the message will cause the hash algorithm to compute a different hash than that which is encrypted and included with the message, notifying the receiving party that the message has been tampered with. Public Key Cryptography and Key Exchange Public Key Cryptography algorithms were invented to solve the symmetric key distribution problem. In public key algorithms, each participant in the communication has a key pair composed of a public key and a private key. The theory of public keys suggests that a message encrypted with the public key can only be decrypted with the private key and vice-versa. Key exchange algorithms (Diffie-Helman, ECDH) have certain properties such that two users, A and B can share their public keys with each other in plain text, and then, using each other's public key and their own private keys they can generate the same shared secret key. Eavesdroppers can see the public keys, but, because the private keys are never transmitted, cannot know the shared secret. Because public key algorithms are computationally much more expensive than symmetric cryptography, network applications generally use public key cryptography to share a secret key that is then used as a symmetric cipher key. Digital Signatures/Certificate Authorization Public key algorithms still have one vulnerability, known as the Man-in-the-Middle attack. Basically, an eavesdropper in the communication between A and B can intercept the public keys in transit and substitute its own public key, thereby establishing a secure connection with A and B - decrypting incoming data and reencrypting it with its shared key to the opposite party. To combat this attack, the concept of certificates was introduced. In this model, the public key of one or both of the participants in the communication is digitally signed with the private key of some known, trusted Certificate Authority (CA). Then, using the Certificate Authority's public key, the parties to the communication can validate the public key of the opposite parties. Security and the TNL The TNL uses the publicly available libtomcrypt (http://libtomcrypt.org) as its encryption foundation. The TNL features key exchange, secret session keys, message authentication and certificate verification. See <> for more information. More Information on Cryptography The preceding sections were only a very high level overview of some cryptographic algorithm theories. For more information, see the USENET cryptography FAQ at http://www.faqs.org/faqs/cryptography-faq/ Additional Challenges Facing Network Programmers Malicious Attackers and Denial of Service A problem facing developers of internet applications and web sites are Denial-of-Service attacks. Malicious users employing custom tools often attempt to shut down publicly available internet servers. There are a variety of well-known categories of DoS attacks. Traffic flooding: This attack sends a barrage of data to the public address of the server, in an attempt to overwhelm that server's connection to the internet. This attack often employs many machines, hijacked by the attacker and acting in concert. These attacks are often the most difficult to mount since they require a large number of available machines with high-speed internet access in order to attack a remote host effectively. Connection depletion: The connection depletion attack works by exploting a weakness of some connection based communications protocols. Connection depletion attacks work by initiating a constant flow of spurious connection attempts. When a legitimate user attempts to connect to the server, all available pending connection slots are already taken up by the spoofed connection attempts, thereby denying service to valid clients. Server CPU depletion: If the server performs public key cryptography as part of the connection sequence, a malicious client could be constructed to initiate bogus connection attempts in an effort to initiate many CPU intesive cryptographic operations on the server. The TNL uses a two-phase connection protocol to protect against connection depletion attacks, and implements a client-puzzle algorithm to prevent CPU depletion attacks. Also, TNL is built so that bogus packets are discarded as quickly as possible, preventing flooding attacks from impacting the server CPU. Firewalls and Network Address Translation (NAT) routers Firewalls are software or hardware devices designed to protect local networks from malicious external attackers. Most firewalls filter all incoming, unsolicited network traffic. NAT routers exist to allow potentially many machines to share a single IP address, but for practical purposes they share similar characteristics with firewalls, by often filtering out unsolicited network traffic. In client/server applications, firewalls and NATs aren't generally a problem. When a client behind a firewall or NAT makes a request to the server, the response is allowed to pass through the firewall or NAT because the network traffic was solicited first by the client. In peer-to-peer applications, NATs and firewalls pose a greater challenge. if both peers are behind different firewalls, then getting them to communicate to each other requires that they both initiate the connection in order for the other's data to be able to flow through the firewall or NAT. This can be facilitated by a third party server or client that both are able to communicate with directly. The TNL provides functionality for arranging a direct connection between two firewalled hosts via a third party master server. See chapter <> for more information. Torque Network Library Design Fundamentals The Torque Network Library was designed to overcome, as much as possible, the three fundamental limitations of network programming - high packet latency, limited bandwidth and packet loss. The following strategies were identified for each of the limitations: Bandwidth conservation Bandwidth conservation in multiuser simulations is of premium importance, not only for clients that may be connected over very low bandwidth transports, but also for servers whose operators have to pay for bandwidth usage. Realizing this, the following techniques are used to conserve bandwidth as much as possible: Send static data once, or not at all: Often in a networked application, a server will transmit some amount of static data to a client. This data may be initialization parameters for a 3D world, a client's name, or some object state that is immutable for objects of a given type. TNL provides direct facilities for caching string data (client names, mission descriptions, etc), sending a given string only once and an integer representation thereafter. The Torque Game Engine also shows how simulations can cache common object instance data in DataBlock objects, which are transmitted only when a client connects. Compress data to the minimum space necessary: When conserving bandwidth, every bit counts. TNL uses a utility class call BitStream to write standard data types into a packet compressed to the minimum number of bits necessary for that data. Boolean values are written as a single bit, integer writes can specify the bit field width, and floating point values can be specified as 0 to 1 compressed to a specified bit count. The BitStream also implements Huffman compression of string data and compression of 3D positions and surface normals. Only send information that is relevant to the client: In a client/server simulation, the server often has information that is not relevant at all to some or all of the clients. For example, in a 3D world, if an object is outside the visible distance of a given client, there is no reason to consume valuable packet space describing that object to the client. The TNL allows the application level code to easily specify which objects are relevant, or "in scope" for each client. Prioritize object updates: Because bandwidth is limited and there is generally a much greater amount of data a server could send to a given client than it has capacity for, the TNL implements a very fine-grained prioritization scheme for updating objects. User code can determine the policy by which objects are judged to be more or less "important" to each client in the simulation, and objects with more importance are updated with a greater frequency. Only update the parts of an object that have changed: Often in a networked simulation, not all object state is updated at the same time - for exampe, a player in a 3D action game may have state that includes the player's current position, velocity, health and ammunition. If the player moves, only the position and velocity states will change, so sending the full state, including the health and ammunition values would waste space unnecessarily. The TNL allows objects individual objects to have state that are updated independently of one another. Coping with Packet Loss In any networked simulation, packet loss will be a consideration - whether because of network congestion, hardware failure or software defects, some packets will inevitably be lost. One solution to the packet loss problem is to use a guaranteed messaging protocol like TCP/IP. Unfortunately, TCP has some behavioral characteristics that make it a poor choice for real-time networked simulations. TCP guarantees that all data sent over the network will arrive, and will arrive in order. This means that if a data packet sent using TCP is dropped in transit, the sending host must retransmit that data before any additional data, that may have already arrived at the remote host, can be processed. In practice this can mean a complete stall of ANY communications for several seconds. Also, TCP may be retransmitting data that is not important from the point of view of the simulation - holding up data that is. The other possible protocol choice would be to use UDP for time critical, but unguaranteed data, and use TCP only for data that will not hold up the real-time aspects of the simulation. This solution ends up being non-optimal for several reasons. First, maintaining two communications channels increases the complexity of the networking component. If an object is sent to a client using the guaranteed channel, unguaranteed messages sent to that object at a later time may arrive for processing before the original guaranteed send. Also, because the unguaranteed channel may lose information, the server will have to send more redundant data, with greater frequency. To solve these problems, TNL implements a new network protocol that fits somewhere between UDP and TCP in its feature set. This protocol, dubbed the "Notify" protocol, does not attempt to hide the underlying unreliability of the network as TCP does, but at the same time it provides more information to the application than straight UDP. The notify protocol is a connection-oriented unreliable communication protocol with packet delivery notification. When a datagram packet is sent from one process, that process will eventually be notified as to whether that datagram was received or not. Each data packet is sent with a packet header that includes acknowledgement information about packets the sending process has received from the remote process. This negates the need for seperate acknowledgement packets, thereby conserving additional bandwidth. The notify protocol foundation allows the TNL to provide a rich set of data transmission policies. Rather than simply grouping data as either guaranteed or unguaranteed, the TNL allows at least five different categorizations of data: Guaranteed Ordered data: Guaranteed Ordered data are data that would be sent using a guaranteed delivery protocol like TCP. Messages indicating clients joining a simulation, text messages between clients, and many other types of information would fall into this category. In TNL, Guaranteed Ordered data are sent using Event objects and RPC method calls. When the notify protocol determines that a packet containing guaranteed ordered data was lost, it requeues the data to be sent in a future packet. Guaranteed data: TNL processes Guaranteed data is in a way similar to Guaranteed Ordered data, with the only difference being that a client can process Guaranteed data as soon as it arrives, rather than waiting for any ordered data to arrive that was dropped. Unguaranteed data: Unguaranteed data is sent, and if the packet it is sent in arrives, is processed. If a packet containing unguaranteed data events is dropped, that data is not resent. The unguaranteed data sending policy could be used for information like real-time voice communication, where a retransmitted voice fragment would be useless. Current State data: For many objects in a simulation, the client isn't concerned with "intervening" states of an object on the server, but only its current state. For example, in a 3D action game, if an enemy player moves from point A to B to C, another client in the simulation is only interested in the final position, C of the object. With the notify protocol, TNL is able to resend object state from a dropped packet only if that state was not updated in a subsequent packet. Quickest Delivery data: Some information sent in a simulation is of such importance that it must be delivered as quickly as possible. In this situation, data can be sent with every packet until the remote host acknowledges any of the packets known to contain the data. Client movement information is an example of data that might be transmitted using this policy. By implementing various data delivery policies, the TNL is able to optimize packet space utilization in high packet loss environments. Strategies for Dealing With Latency Latency is a function of the time-based limitations of physical data networks. The time it takes information to travel from one host to another is dependent on many factors, and can definitely affect the user's perceptions of what is happening in the simulation. For example, in a client-server 3D simulation, suppose the round-trip time between one client and server is 250 milliseconds. If the client is observing an object that is moving. If the server is sending position updates of the object to the client, those positions will be "out of date" by 125 milliseconds by the time they arrive on the client. Also, suppose that the server is sending packets to the client at a rate of 10 packets per second. When the next update for the object arrives at the client, it may have moved a large distance relative to the perceptions of the client. Also, if the server is considered to be authoritative over the client's own position in the world, the client would have to wait at least a quarter of a second before its inputs were validated and reflected in its view of the world. This gives the appearance of very perceptible input "lag" on the client. In the worst case, the client would always see an out of date version of the server's world, as objects moved they would "pop" from one position to another, and each keypress wouldn't be reflected until a quarter of a second later. For most real-time simulations, this behavior is not optimal. Because TNL is predominantly a data transport and connection management API, it doesn't provide facilities for solving these problems directly. TNL provides a simple mechanism for computing the average round-trip time of a connection from which the following solutions to connection latency issues can be implemented: Interpolation: Interpolation is used to smoothly move an object from where the client thinks it is to where the server declares it to be over some short period of time. Parameters like position and rotation can be interpolated using linear or cubic interpolation to present a consistent, no "pop" view of the world to the client. The downside of interpolation when used alone is that it actually exacerbates the time difference between the client and the server, because the client is spending even more time than the one-way message time to move the object from its current position to the known server position. Extrapolation: To solve the problem of out-of-date state information, extrapolation can be employed. Extrapolation is a best guess of the current state of an object, given a known past state. For example, suppose a player object has a last known position and velocity. Rather than placing the player at the server's stated position, the player object can be placed at the position extrapolated forward by velocity times the time difference. In the Torque Game Engine, player objects controlled by other clients are simulated using both interpolation and extrapolation. When a player update is received from the server, the client extrapolates that position forward using the player's velocity and the sum of the time it will use to interpolate and the one-way message time from the server - essentially, the player interpolates to an extrapolated position. Once it has reached the extrapolated end point, the player will continue to extrapolate new positions until another update of the obect is received from the server. By using interpolation and extrapolation, the client view can be made to reasonably, smoothly approximate the world of the server, but neither approach is sufficient for real-time objects that are directly controlled by player input. To solve this third, more difficult problem, client-side prediction is employed. Client-side prediction is similar to extrapolation, in that the client is attempting to guess the server state of an object the server has authority over. In the case of simple extrapolation, however, the client doesn't have the benefit of the actual input data. Client-side prediction uses the inputs of the user to make a better guess about where the client-controlled object will be. Basically, the client performs the exact same object simulation as the server will eventually perform on that client's input data. As long as the client-controlled object is not acted upon by forces on the server that don't exist on the client or vice versa, the client and server state information for the object should perfectly agree. When they don't agree, interpolation can be employed to smoothly move the client object to the known server position and client-side prediction can be continued. Torque Network Library Archtectural Overview The Torque Network Library is built in layers, each adding more functionality to the layer below it. The Platform Layer At the lowest level, TNL provides a platform independent interface to operating system functions. The platform layer includes functions for querying system time, sleeping the current process and displaying alerts. The platform layer includes wrappers for all of the C standard library functions used in the TNL. The platform layer also contains the Socket and Address classes, which provide a cross-platform, simplified interface to datagram sockets and network addresses. The NetBase Layer The NetBase layer is the foundation upon which most of the classes in TNL are based. At the root of the class hierarchy is the Object base class. Every subclass of Object is associated with an instance of NetClassRep through a set of macros, allowing for instances of that class to be constructed by a class name string or by an automatically assigned class id. This id-based instantiation allows objects subclassed from NetEvent and NetObject to be serialized into data packets, transmitted, constructed on a remote host and deserialized. Object also has two helper template classes, SafePtr, which provides safe object pointers that become NULL when the referenced object is deleted, and a reference pointer class, RefPtr, that automatically deletes a referenced object when all the references to it are destructed. The BitStream and PacketStream classes The BitStream class presents a stream interface on top of a buffer of bytes. BitStream provides standard read and write functions for the various TNL basic data types, including integers, characters and floating point values. BitStream also allows fields to be written as bit-fields of specific size. An integer that is always between 3 and 9 inclusive can be written using only 3 bits using the writeRangedU32 method, for example. BitStream huffman encodes string data for additional space savings, and provides methods for compressing 3D points and normals, as routines for writing arbitrary buffers of bits. The PacketStream subclass of BitStream is simply a thin interface that statically allocates space up to the maximum size of a UDP packet. A routine can declare a stack allocated PacketStream instance, write data into it and send it to a remote address with just a few lines of code. The NetInterface and NetConnection Layer The NetInterface class wraps a platform Socket instance and manages the set of NetConnection instances that are communicating through that socket. NetInterface is manages the two-phase connection initiation process, dispatch of protocol packets to NetConnection objects, and provides a generic interface for subclasses to define and process their own unconnected datagram packets. The NetConnection class implements the connected Notify Protocol layered on UDP. NetConnection manages packet send rates, writes and decodes packet headers, and notifies subclasses when previously sent packets are known to be either received or dropped. NetInterface instances can be set to use a public/private key pair for creating secure connections. In order to prevent attackers from depleting server CPU resources, the NetItnerface issues a cryptographically difficult "client puzzle" to each host attempting to connect to the server. Client puzzles have the property that they can be made arbitrarily difficult for the client to solve, but whose solutions can be checked by the server in a trivial amount of time. This way, when a server is under attack from many connection attempts, it can increase the difficulty of the puzzle it issues to connecting clients. The ConnectionParameters structure maintains all of the information needed by the NetInterface to negotiate the startup phase of a NetConnection. The Event Layer - EventConnection, NetEvent and Remote Procedure Calls The EventConnection class subclasses NetConnection to provide several different types of data transmission policies. EventConnection uses the NetEvent class to encapsulate event data to be sent to remote hosts. Subclasses of NetEvent are responsible for serializing and deserializing themselves into BitStreams, as well as processing event data in the proper sequence. NetEvent subclasses can use one of three data guarantee policies. They can be declared as GuaranteedOrdered, for ordered, reliable message delivery; Guaranteed, for reliable but possibly out of order delivery, or Unguaranteed, for ordered but not guaranteed messaging. The EventConnection class uses the notify protocol to requeue dropped events for retransmission, and orders the invocations of the events' process methods if ordered processing is requested. Because declaring an individual NetEvent subclass for each type of message and payload to be sent over the network, with its corresponding pack, unpack and process routines, can be somewhat tedious, TNL provides a Remote Procedure Call (RPC) framework. Using some macro magic, argument list parsing and a little assembly language, methods in EventConnection subclasses can be declared as RPC methods. When called from C++, the methods construct an event containing the argument data passed to the function and send it to the remote host. When the event is unpacked and processed, the body of the RPC method implementation is executed. Ghosting - GhostConnection and NetObject The GhostConnection class subclasses EventConnection in order to provide the most-recent and partial object state data update policies. Instances of the NetObject class and its subclasses can be replicated over a connection from one host to another. The GhostConnection class manages the relationship between the original object, and its "ghost" on the client side of the connection. In order to best utilize the available bandwidth, the GhostConnection attempts to determine which objects are "interesting" to each client - and among those objects, which ones are most important. If an object is interesting to a client it is said to be "in scope" - for example, a visible enemy to a player in a first person shooter would be in scope. Each GhostConnection object maintains a NetObject instance called the scope object - responsible for determining which objects are in scope for that client. Before the GhostConnection writes ghost update information into each packet, it calls the scope object's performScopeQuery method which must determine which objects are "in scope" for that client. Each scoped object that needs to be updated is then prioritized based on the return value from the NetObject::getUpdatePriority() function, which by default returns a constant value. This function can be overridden by NetObject subclasses to take into account such factors as the object's distance from the camera, its velocity perpendicular to the view vector, its orientation relative to the view direction and more. Rather than always sending the full state of the object each time it is updated across the network, the TNL supports only sending portions of the object's state that have changed. To facilitate this, each NetObject can specify up to 32 independent states that can be modified individually. For example, a player object might have a movement state, detailing its position and velocity, a damage state, detailing its damage level and hit locations, and an animation state, signifying what animation, if any, the player is performing. A NetObject can notify the network system when one of its states has changed, allowing the GhostConnections that are ghosting that object to replicate the changed state to the clients for which that object is in scope. Encryption and TNL The TNL has hooks in various places to use encryption when requested. To enable encrypted connections, the NetInterface must be assigned an instance of AsymmetricKey as a public/private key pair using NetInterface::setPrivateKey. The NetInterface::setRequiresKeyExchange method may then be called to instruct the NetInterface that all incoming connection requests must include a key exchange. Asymmetric keys can be constructed with varying levels of security. The TNL uses Elliptic Curve public key crytpography, with key sizes ranging from 20 to 32 bytes. AsymmetricKey instances can be constructed either with a new, random key of a specified size, or can be created from an existing ByteBuffer. Once a secure connection handshake is completed, TNL uses the AES symmetric cipher to encode connected packets. The BitStream::hashAndEncrypt and BitStream::decryptAndCheckHash methods use an instance of SymmetricCipher to encrypt and decrypt packets using a shared session key. In order to have properly secure communications, the cryptographically strong pseudo-random number generator (PRNG) in TNL must be initialized with good (high entropy) random data. Useful Classes TNL uses a number of utility classes throughout. Some of these include: Vector - The Vector template class is a lightweight version of the STL Vector container. DataChunker - The DataChunker class performs small, very low overhead memory allocation out of a pool. Individual allocations cannot be freed, however the entire pool can be freed at once. ClassChunker - The ClassChunker template class uses the DataChunker to manage allocation and deallocation of instances of the specific class. ClassChunker maintains a free list for quick allocation and deallocation. StringTableEntry - StringTableEntry wraps a ref-counted element in the StringTable, with simple conversion operations to C strings. StringTableEntry instances can be sent in the parameter lists of RPC methods or using the EventConnection::packStringTableEntry method. ByteBuffer - The ByteBuffer class wraps a buffer of arbitray binary data. ByteBuffer serves as a base class for BitStream, as well as the cryptographic primitives. Debugging and Error Handling Correcting bugs in a networked simulation can sometimes be an incredibly difficult task. TNL provides some handy features to make debugging somewhat less challenging: Asserts - The TNLAssert and TNLAssertV macros specify a condition that, if false, will cause the application to display an error dialog and halt in the debugger where the assert was hit. Asserts are very useful for sanity-checking arguments to functions, and making sure network data is being properly read from and written to packets. Logging - TNL has a set of simple but effective facilities for logging status information. The TNLLogMessage and TNLLogMessageV macros allow the user to specify logging tokens with particular log messages. Logging of messages associated with a given token can be enabled or disabled using the TNLLogEnable macro. Also, the TNLLogBlock macro can be used to log multiple logprintf statements in a single test. Rather than log to a file or other destination, TNL applications must declare at least one instance of a sublclass of TNLLogConsumer. Every TNLLogConsumer instance receives all the logging messages that are currently enabled. Debugging object writes into packets - One of the most common errors programmers experience when using TNL is failing to properly match the NetEvent::pack and NetEvent::unpack or NetObject::packUpdate and NetObject::unpackUpdate routines. By default, if TNL_DEBUG is defined, the EventConnection and GhostConnection classes will write extra size information into the packet before each object's data are written. The ConnectionParameters::mDebugObjectSizes flag can be modified directly to further control this behavior. Simple Torque Network Library Tutorial: Hello World This simple tutorial walks the user through the creation of a very simple networked example program using the RPC functionality of the EventConnection class. This command-line program can be run in either client or server modes. As a client it will attempt to connect to a server at the specified address and send it a message every second. When the server receives a message from a client, it will respond back with a "Hello, World!" message. First, create a new source file, "simpleNet.cpp", containing the following lines to start: #include "tnl.h" #include "tnlEventConnection.h" #include "tnlNetInterface.h" #include "tnlRPC.h" #include <stdio.h> bool gQuit = false; // a flag used when the client wants to quit. using namespace TNL; // make sure we can simply use the TNL classes. If the compiler complains of missing include files, be sure the "tnl" directory is in the include path. Next, create a custom subclass of EventConnection for the example program to communicate across, and declare the client-to-server and server-to-client RPC methods: class SimpleEventConnection : public EventConnection { typedef EventConnection Parent; public: // Let the network system know this is a valid network connection. TNL_DECLARE_NETCONNECTION(SimpleEventConnection); // declare the client to server message TNL_DECLARE_RPC(rpcMessageClientToServer, (const char *theMessageString)); // declare the server to client message TNL_DECLARE_RPC(rpcMessageServerToClient, (const char *theMessageString)); }; The first macro invoked, TNL_DECLARE_NETCONNECTION declares members necessary to make this class work as a connection in TNL. The RPC methods are then declared using the TNL_DECLARE_RPC macro. The first parameter to the macro is the name of the RPC method, which can be invoked like any other member function on the object. The second argument is a parenthesized argument list to the RPC. Although these functions are both declared to take only a single string, RPC method parameter lists can contain all the basic TNL types, as well as StringTableEntry, ByteBuffer and Vector objects. Next, define the implementation of the SimpleEventConnection class: TNL_IMPLEMENT_NETCONNECTION(SimpleEventConnection, NetClassGroupGame, true); TNL_IMPLEMENT_RPC(SimpleEventConnection, rpcMessageClientToServer, (const char *messageString), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirClientToServer, 0) { // display the message the client sent printf("Got message from client: %s\n", messageString); // send a hello world back to the client. rpcMessageServerToClient("Hello, World!"); } TNL_IMPLEMENT_RPC(SimpleEventConnection, rpcMessageServerToClient, (const char *messageString), NetClassGroupGameMask, RPCGuaranteedOrdered, RPCDirServerToClient, 0) { // display the message the server sent printf("Got a message from server: %s\n", messageString); // once the client has heard back from the server, it should quit. gQuit = true; } The TNL_IMPLEMENT_NETCONNECTION macro specifies two properties. The first, NetClassGroupGame declares that this connection traffics only in NetEvent, NetObject and RPC instances that have the NetClassGroupGame mask bit set in their implementations. The second property, as declared by the boolean true specifies that remote hosts can request a connection of type SimpleEventConnection from this process. The TNL_IMPLEMENT_RPC macro behaves like a standard function signature declaration, but with some important additions. The first three arguments, class name, method name and arguments are fairly self-explanatory. The fourth argument is the connection type mask, which specifies which types of connections the specified RPC can travel over. Since RPC's (unlike NetEvent and NetObject subclasses) are declared for only a single connection class, this mask should always be the mask associated with the connection type declared in TNL_IMPLEMENT_NETCONNECTION. The fifth argument to the macro specifies the guarantee type of the RPC, which can be one of RPCGuaranteedOrdered, RPCGuaranteed or RPCUnguaranteed. The sixth parameter is the direction the RPC is allowed to travel, which when specified can make an application more secure from attacks that modify packets in transit. The last argument is a version number, which can be specified so that older clients can still connect to servers offering newer RPCs. The function body of the RPC similar to any other function body with one important difference. When an RPC method is invoked, the function body code is executed on the remote side of the connection. So if the client calls the method rpcMessageClientToServer("Hello?"), the code for the body will execute on the server. Now that the connection class is defined, all that is left to do is create the main() function that will start up the instance as either a client or a server. int main(int argc, const char **argv) { if(argc != 3) { printf("usage: simpletnltest <-server|-client> <connectAddress>"); return 1; } bool isClient = !strcmp(argv[1], "-client"); // convert the command-line address into TNL address form Address cmdAddress(argv[2]); RefPtr<NetInterface> theNetInterface; if(isClient) { Address bindAddress(IPProtocol, Address::Any, 0); // create a new NetInterface bound to any interface, any port (0) theNetInterface = new NetInterface(bindAddress); // create a new SimpleEventConnection and tell it to connect to the // server at cmdAddress. SimpleEventConnection *newConnection = new SimpleEventConnection; newConnection->connect(theNetInterface, cmdAddress); // post an RPC, to be executed when the connection is established newConnection->rpcMessageClientToServer("Hello??"); } else { // create a server net interface, bound to the cmdAddress theNetInterface = new NetInterface(cmdAddress); // notify the NetInterface that it can allow connections theNetInterface->setAllowsConnections(true); } // now just loop, processing incoming packets and sending outgoing packets // until the global quit flag is set. while(!gQuit) { theNetInterface->checkIncomingPackets(); theNetInterface->processConnections(); Platform::sleep(1); } return 0; } Once the code is written, use your compiler to build simpletnltest, making sure to link in the tnl library, along with whatever network libraries your platform requires (wsock32.li... [truncated message content] |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:24
|
Update of /cvsroot/opentnl/tnl/glut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/glut Added Files: glut.h glut32.lib glutInclude.h Log Message: Initial commit. --- NEW FILE: glut32.lib --- (This appears to be a binary file; contents omitted.) --- NEW FILE: glutInclude.h --- //----------------------------------------------------------------------------------- // // Torque Network Library - ZAP example multiplayer vector graphics space game // Copyright (C) 2004 GarageGames.com, Inc. // For more information see http://www.opentnl.org // // 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 2 of the License, or // (at your option) any later version. // // For use in products that are not compatible with the terms of the GNU // General Public License, alternative licensing options are available // from GarageGames.com. // // 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. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // //------------------------------------------------------------------------------------ #ifdef TNL_OS_MAC_OSX #include <GLUT/glut.h> #else #include "glut.h" #endif --- NEW FILE: glut.h --- #ifndef __glut_h__ #define __glut_h__ /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1998. */ /* This program is freely distributable without licensing fees and is provided without guarantee or warrantee expressed or implied. This program is -not- in the public domain. */ #if defined(_WIN32) /* GLUT 3.7 now tries to avoid including <windows.h> to avoid name space pollution, but Win32's <GL/gl.h> needs APIENTRY and WINGDIAPI defined properly. */ # if 0 /* This would put tons of macros and crap in our clean name space. */ # define WIN32_LEAN_AND_MEAN # include <windows.h> # else /* XXX This is from Win32's <windef.h> */ # ifndef APIENTRY # define GLUT_APIENTRY_DEFINED # if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__) # define APIENTRY __stdcall # else # define APIENTRY # endif # endif /* XXX This is from Win32's <winnt.h> */ # ifndef CALLBACK # if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) || defined(__LCC__) # define CALLBACK __stdcall # else # define CALLBACK # endif # endif /* XXX Hack for lcc compiler. It doesn't support __declspec(dllimport), just __stdcall. */ # if defined( __LCC__ ) # undef WINGDIAPI # define WINGDIAPI __stdcall # else /* XXX This is from Win32's <wingdi.h> and <winnt.h> */ # ifndef WINGDIAPI # define GLUT_WINGDIAPI_DEFINED # define WINGDIAPI __declspec(dllimport) # endif # endif /* XXX This is from Win32's <ctype.h> */ # ifndef _WCHAR_T_DEFINED typedef unsigned short wchar_t; # define _WCHAR_T_DEFINED # endif # endif /* To disable automatic library usage for GLUT, define GLUT_NO_LIB_PRAGMA in your compile preprocessor options. */ # if !defined(GLUT_BUILDING_LIB) && !defined(GLUT_NO_LIB_PRAGMA) # pragma comment (lib, "winmm.lib") /* link with Windows MultiMedia lib */ /* To enable automatic SGI OpenGL for Windows library usage for GLUT, define GLUT_USE_SGI_OPENGL in your compile preprocessor options. */ # ifdef GLUT_USE_SGI_OPENGL # pragma comment (lib, "opengl.lib") /* link with SGI OpenGL for Windows lib */ # pragma comment (lib, "glu.lib") /* link with SGI OpenGL Utility lib */ # pragma comment (lib, "glut.lib") /* link with Win32 GLUT for SGI OpenGL lib */ # else # pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */ # pragma comment (lib, "glu32.lib") /* link with Microsoft OpenGL Utility lib */ # pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */ # endif # endif /* To disable supression of annoying warnings about floats being promoted to doubles, define GLUT_NO_WARNING_DISABLE in your compile preprocessor options. */ # ifndef GLUT_NO_WARNING_DISABLE # pragma warning (disable:4244) /* Disable bogus VC++ 4.2 conversion warnings. */ # pragma warning (disable:4305) /* VC++ 5.0 version of above warning. */ # endif /* Win32 has an annoying issue where there are multiple C run-time libraries (CRTs). If the executable is linked with a different CRT from the GLUT DLL, the GLUT DLL will not share the same CRT static data seen by the executable. In particular, atexit callbacks registered in the executable will not be called if GLUT calls its (different) exit routine). GLUT is typically built with the "/MD" option (the CRT with multithreading DLL support), but the Visual C++ linker default is "/ML" (the single threaded CRT). One workaround to this issue is requiring users to always link with the same CRT as GLUT is compiled with. That requires users supply a non-standard option. GLUT 3.7 has its own built-in workaround where the executable's "exit" function pointer is covertly passed to GLUT. GLUT then calls the executable's exit function pointer to ensure that any "atexit" calls registered by the application are called if GLUT needs to exit. Note that the __glut*WithExit routines should NEVER be called directly. To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ /* XXX This is from Win32's <process.h> */ # if !defined(_MSC_VER) && !defined(__cdecl) /* Define __cdecl for non-Microsoft compilers. */ # define __cdecl # define GLUT_DEFINED___CDECL # endif # ifndef _CRTIMP # ifdef _NTSDK /* Definition compatible with NT SDK */ # define _CRTIMP # else /* Current definition */ # ifdef _DLL # define _CRTIMP __declspec(dllimport) # else # define _CRTIMP # endif # endif # define GLUT_DEFINED__CRTIMP # endif /* GLUT API entry point declarations for Win32. */ # ifdef GLUT_BUILDING_LIB # define GLUTAPI __declspec(dllexport) # else # ifdef _DLL # define GLUTAPI __declspec(dllimport) # else # define GLUTAPI extern # endif # endif /* GLUT callback calling convention for Win32. */ # define GLUTCALLBACK __cdecl #endif /* _WIN32 */ #include <GL/gl.h> #include <GL/glu.h> #ifdef __cplusplus extern "C" { #endif #if defined(_WIN32) # ifndef GLUT_BUILDING_LIB extern _CRTIMP void __cdecl exit(int); # endif #else /* non-Win32 case. */ /* Define APIENTRY and CALLBACK to nothing if we aren't on Win32. */ # define APIENTRY # define GLUT_APIENTRY_DEFINED # define CALLBACK /* Define GLUTAPI and GLUTCALLBACK as below if we aren't on Win32. */ # define GLUTAPI extern # define GLUTCALLBACK /* Prototype exit for the non-Win32 case (see above). */ extern void exit(int); #endif /** GLUT API revision history: GLUT_API_VERSION is updated to reflect incompatible GLUT API changes (interface changes, semantic changes, deletions, or additions). GLUT_API_VERSION=1 First public release of GLUT. 11/29/94 GLUT_API_VERSION=2 Added support for OpenGL/GLX multisampling, extension. Supports new input devices like tablet, dial and button box, and Spaceball. Easy to query OpenGL extensions. GLUT_API_VERSION=3 glutMenuStatus added. GLUT_API_VERSION=4 glutInitDisplayString, glutWarpPointer, glutBitmapLength, glutStrokeLength, glutWindowStatusFunc, dynamic video resize subAPI, glutPostWindowRedisplay, glutKeyboardUpFunc, glutSpecialUpFunc, glutIgnoreKeyRepeat, glutSetKeyRepeat, glutJoystickFunc, glutForceJoystickFunc (NOT FINALIZED!). **/ #ifndef GLUT_API_VERSION /* allow this to be overriden */ #define GLUT_API_VERSION 3 #endif /** GLUT implementation revision history: GLUT_XLIB_IMPLEMENTATION is updated to reflect both GLUT API revisions and implementation revisions (ie, bug fixes). GLUT_XLIB_IMPLEMENTATION=1 mjk's first public release of GLUT Xlib-based implementation. 11/29/94 GLUT_XLIB_IMPLEMENTATION=2 mjk's second public release of GLUT Xlib-based implementation providing GLUT version 2 interfaces. GLUT_XLIB_IMPLEMENTATION=3 mjk's GLUT 2.2 images. 4/17/95 GLUT_XLIB_IMPLEMENTATION=4 mjk's GLUT 2.3 images. 6/?/95 GLUT_XLIB_IMPLEMENTATION=5 mjk's GLUT 3.0 images. 10/?/95 GLUT_XLIB_IMPLEMENTATION=7 mjk's GLUT 3.1+ with glutWarpPoitner. 7/24/96 GLUT_XLIB_IMPLEMENTATION=8 mjk's GLUT 3.1+ with glutWarpPoitner and video resize. 1/3/97 GLUT_XLIB_IMPLEMENTATION=9 mjk's GLUT 3.4 release with early GLUT 4 routines. GLUT_XLIB_IMPLEMENTATION=11 Mesa 2.5's GLUT 3.6 release. GLUT_XLIB_IMPLEMENTATION=12 mjk's GLUT 3.6 release with early GLUT 4 routines + signal handling. GLUT_XLIB_IMPLEMENTATION=13 mjk's GLUT 3.7 beta with GameGLUT support. GLUT_XLIB_IMPLEMENTATION=14 mjk's GLUT 3.7 beta with f90gl friend interface. GLUT_XLIB_IMPLEMENTATION=15 mjk's GLUT 3.7 beta sync'ed with Mesa <GL/glut.h> **/ #ifndef GLUT_XLIB_IMPLEMENTATION /* Allow this to be overriden. */ #define GLUT_XLIB_IMPLEMENTATION 15 #endif /* Display mode bit masks. */ #define GLUT_RGB 0 #define GLUT_RGBA GLUT_RGB #define GLUT_INDEX 1 #define GLUT_SINGLE 0 #define GLUT_DOUBLE 2 #define GLUT_ACCUM 4 #define GLUT_ALPHA 8 #define GLUT_DEPTH 16 #define GLUT_STENCIL 32 #if (GLUT_API_VERSION >= 2) #define GLUT_MULTISAMPLE 128 #define GLUT_STEREO 256 #endif #if (GLUT_API_VERSION >= 3) #define GLUT_LUMINANCE 512 #endif /* Mouse buttons. */ #define GLUT_LEFT_BUTTON 0 #define GLUT_MIDDLE_BUTTON 1 #define GLUT_RIGHT_BUTTON 2 /* Mouse button state. */ #define GLUT_DOWN 0 #define GLUT_UP 1 #if (GLUT_API_VERSION >= 2) /* function keys */ #define GLUT_KEY_F1 1 #define GLUT_KEY_F2 2 #define GLUT_KEY_F3 3 #define GLUT_KEY_F4 4 #define GLUT_KEY_F5 5 #define GLUT_KEY_F6 6 #define GLUT_KEY_F7 7 #define GLUT_KEY_F8 8 #define GLUT_KEY_F9 9 #define GLUT_KEY_F10 10 #define GLUT_KEY_F11 11 #define GLUT_KEY_F12 12 /* directional keys */ #define GLUT_KEY_LEFT 100 #define GLUT_KEY_UP 101 #define GLUT_KEY_RIGHT 102 #define GLUT_KEY_DOWN 103 #define GLUT_KEY_PAGE_UP 104 #define GLUT_KEY_PAGE_DOWN 105 #define GLUT_KEY_HOME 106 #define GLUT_KEY_END 107 #define GLUT_KEY_INSERT 108 #endif /* Entry/exit state. */ #define GLUT_LEFT 0 #define GLUT_ENTERED 1 /* Menu usage state. */ #define GLUT_MENU_NOT_IN_USE 0 #define GLUT_MENU_IN_USE 1 /* Visibility state. */ #define GLUT_NOT_VISIBLE 0 #define GLUT_VISIBLE 1 /* Window status state. */ #define GLUT_HIDDEN 0 #define GLUT_FULLY_RETAINED 1 #define GLUT_PARTIALLY_RETAINED 2 #define GLUT_FULLY_COVERED 3 /* Color index component selection values. */ #define GLUT_RED 0 #define GLUT_GREEN 1 #define GLUT_BLUE 2 #if defined(_WIN32) /* Stroke font constants (use these in GLUT program). */ #define GLUT_STROKE_ROMAN ((void*)0) #define GLUT_STROKE_MONO_ROMAN ((void*)1) /* Bitmap font constants (use these in GLUT program). */ #define GLUT_BITMAP_9_BY_15 ((void*)2) #define GLUT_BITMAP_8_BY_13 ((void*)3) #define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4) #define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5) #if (GLUT_API_VERSION >= 3) #define GLUT_BITMAP_HELVETICA_10 ((void*)6) #define GLUT_BITMAP_HELVETICA_12 ((void*)7) #define GLUT_BITMAP_HELVETICA_18 ((void*)8) #endif #else /* Stroke font opaque addresses (use constants instead in source code). */ GLUTAPI void *glutStrokeRoman; GLUTAPI void *glutStrokeMonoRoman; /* Stroke font constants (use these in GLUT program). */ #define GLUT_STROKE_ROMAN (&glutStrokeRoman) #define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman) /* Bitmap font opaque addresses (use constants instead in source code). */ GLUTAPI void *glutBitmap9By15; GLUTAPI void *glutBitmap8By13; GLUTAPI void *glutBitmapTimesRoman10; GLUTAPI void *glutBitmapTimesRoman24; GLUTAPI void *glutBitmapHelvetica10; GLUTAPI void *glutBitmapHelvetica12; GLUTAPI void *glutBitmapHelvetica18; /* Bitmap font constants (use these in GLUT program). */ #define GLUT_BITMAP_9_BY_15 (&glutBitmap9By15) #define GLUT_BITMAP_8_BY_13 (&glutBitmap8By13) #define GLUT_BITMAP_TIMES_ROMAN_10 (&glutBitmapTimesRoman10) #define GLUT_BITMAP_TIMES_ROMAN_24 (&glutBitmapTimesRoman24) #if (GLUT_API_VERSION >= 3) #define GLUT_BITMAP_HELVETICA_10 (&glutBitmapHelvetica10) #define GLUT_BITMAP_HELVETICA_12 (&glutBitmapHelvetica12) #define GLUT_BITMAP_HELVETICA_18 (&glutBitmapHelvetica18) #endif #endif /* glutGet parameters. */ #define GLUT_WINDOW_X ((GLenum) 100) #define GLUT_WINDOW_Y ((GLenum) 101) #define GLUT_WINDOW_WIDTH ((GLenum) 102) #define GLUT_WINDOW_HEIGHT ((GLenum) 103) #define GLUT_WINDOW_BUFFER_SIZE ((GLenum) 104) #define GLUT_WINDOW_STENCIL_SIZE ((GLenum) 105) #define GLUT_WINDOW_DEPTH_SIZE ((GLenum) 106) #define GLUT_WINDOW_RED_SIZE ((GLenum) 107) #define GLUT_WINDOW_GREEN_SIZE ((GLenum) 108) #define GLUT_WINDOW_BLUE_SIZE ((GLenum) 109) #define GLUT_WINDOW_ALPHA_SIZE ((GLenum) 110) #define GLUT_WINDOW_ACCUM_RED_SIZE ((GLenum) 111) #define GLUT_WINDOW_ACCUM_GREEN_SIZE ((GLenum) 112) #define GLUT_WINDOW_ACCUM_BLUE_SIZE ((GLenum) 113) #define GLUT_WINDOW_ACCUM_ALPHA_SIZE ((GLenum) 114) #define GLUT_WINDOW_DOUBLEBUFFER ((GLenum) 115) #define GLUT_WINDOW_RGBA ((GLenum) 116) #define GLUT_WINDOW_PARENT ((GLenum) 117) #define GLUT_WINDOW_NUM_CHILDREN ((GLenum) 118) #define GLUT_WINDOW_COLORMAP_SIZE ((GLenum) 119) #if (GLUT_API_VERSION >= 2) #define GLUT_WINDOW_NUM_SAMPLES ((GLenum) 120) #define GLUT_WINDOW_STEREO ((GLenum) 121) #endif #if (GLUT_API_VERSION >= 3) #define GLUT_WINDOW_CURSOR ((GLenum) 122) #endif #define GLUT_SCREEN_WIDTH ((GLenum) 200) #define GLUT_SCREEN_HEIGHT ((GLenum) 201) #define GLUT_SCREEN_WIDTH_MM ((GLenum) 202) #define GLUT_SCREEN_HEIGHT_MM ((GLenum) 203) #define GLUT_MENU_NUM_ITEMS ((GLenum) 300) #define GLUT_DISPLAY_MODE_POSSIBLE ((GLenum) 400) #define GLUT_INIT_WINDOW_X ((GLenum) 500) #define GLUT_INIT_WINDOW_Y ((GLenum) 501) #define GLUT_INIT_WINDOW_WIDTH ((GLenum) 502) #define GLUT_INIT_WINDOW_HEIGHT ((GLenum) 503) #define GLUT_INIT_DISPLAY_MODE ((GLenum) 504) #if (GLUT_API_VERSION >= 2) #define GLUT_ELAPSED_TIME ((GLenum) 700) #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) #define GLUT_WINDOW_FORMAT_ID ((GLenum) 123) #endif #if (GLUT_API_VERSION >= 2) /* glutDeviceGet parameters. */ #define GLUT_HAS_KEYBOARD ((GLenum) 600) #define GLUT_HAS_MOUSE ((GLenum) 601) #define GLUT_HAS_SPACEBALL ((GLenum) 602) #define GLUT_HAS_DIAL_AND_BUTTON_BOX ((GLenum) 603) #define GLUT_HAS_TABLET ((GLenum) 604) #define GLUT_NUM_MOUSE_BUTTONS ((GLenum) 605) #define GLUT_NUM_SPACEBALL_BUTTONS ((GLenum) 606) #define GLUT_NUM_BUTTON_BOX_BUTTONS ((GLenum) 607) #define GLUT_NUM_DIALS ((GLenum) 608) #define GLUT_NUM_TABLET_BUTTONS ((GLenum) 609) #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) #define GLUT_DEVICE_IGNORE_KEY_REPEAT ((GLenum) 610) #define GLUT_DEVICE_KEY_REPEAT ((GLenum) 611) #define GLUT_HAS_JOYSTICK ((GLenum) 612) #define GLUT_OWNS_JOYSTICK ((GLenum) 613) #define GLUT_JOYSTICK_BUTTONS ((GLenum) 614) #define GLUT_JOYSTICK_AXES ((GLenum) 615) #define GLUT_JOYSTICK_POLL_RATE ((GLenum) 616) #endif #if (GLUT_API_VERSION >= 3) /* glutLayerGet parameters. */ #define GLUT_OVERLAY_POSSIBLE ((GLenum) 800) #define GLUT_LAYER_IN_USE ((GLenum) 801) #define GLUT_HAS_OVERLAY ((GLenum) 802) #define GLUT_TRANSPARENT_INDEX ((GLenum) 803) #define GLUT_NORMAL_DAMAGED ((GLenum) 804) #define GLUT_OVERLAY_DAMAGED ((GLenum) 805) #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) /* glutVideoResizeGet parameters. */ #define GLUT_VIDEO_RESIZE_POSSIBLE ((GLenum) 900) #define GLUT_VIDEO_RESIZE_IN_USE ((GLenum) 901) #define GLUT_VIDEO_RESIZE_X_DELTA ((GLenum) 902) #define GLUT_VIDEO_RESIZE_Y_DELTA ((GLenum) 903) #define GLUT_VIDEO_RESIZE_WIDTH_DELTA ((GLenum) 904) #define GLUT_VIDEO_RESIZE_HEIGHT_DELTA ((GLenum) 905) #define GLUT_VIDEO_RESIZE_X ((GLenum) 906) #define GLUT_VIDEO_RESIZE_Y ((GLenum) 907) #define GLUT_VIDEO_RESIZE_WIDTH ((GLenum) 908) #define GLUT_VIDEO_RESIZE_HEIGHT ((GLenum) 909) #endif /* glutUseLayer parameters. */ #define GLUT_NORMAL ((GLenum) 0) #define GLUT_OVERLAY ((GLenum) 1) /* glutGetModifiers return mask. */ #define GLUT_ACTIVE_SHIFT 1 #define GLUT_ACTIVE_CTRL 2 #define GLUT_ACTIVE_ALT 4 /* glutSetCursor parameters. */ /* Basic arrows. */ #define GLUT_CURSOR_RIGHT_ARROW 0 #define GLUT_CURSOR_LEFT_ARROW 1 /* Symbolic cursor shapes. */ #define GLUT_CURSOR_INFO 2 #define GLUT_CURSOR_DESTROY 3 #define GLUT_CURSOR_HELP 4 #define GLUT_CURSOR_CYCLE 5 #define GLUT_CURSOR_SPRAY 6 #define GLUT_CURSOR_WAIT 7 #define GLUT_CURSOR_TEXT 8 #define GLUT_CURSOR_CROSSHAIR 9 /* Directional cursors. */ #define GLUT_CURSOR_UP_DOWN 10 #define GLUT_CURSOR_LEFT_RIGHT 11 /* Sizing cursors. */ #define GLUT_CURSOR_TOP_SIDE 12 #define GLUT_CURSOR_BOTTOM_SIDE 13 #define GLUT_CURSOR_LEFT_SIDE 14 #define GLUT_CURSOR_RIGHT_SIDE 15 #define GLUT_CURSOR_TOP_LEFT_CORNER 16 #define GLUT_CURSOR_TOP_RIGHT_CORNER 17 #define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 18 #define GLUT_CURSOR_BOTTOM_LEFT_CORNER 19 /* Inherit from parent window. */ #define GLUT_CURSOR_INHERIT 100 /* Blank cursor. */ #define GLUT_CURSOR_NONE 101 /* Fullscreen crosshair (if available). */ #define GLUT_CURSOR_FULL_CROSSHAIR 102 #endif /* GLUT initialization sub-API. */ GLUTAPI void APIENTRY glutInit(int *argcp, char **argv); #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) GLUTAPI void APIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); #ifndef GLUT_BUILDING_LIB static void APIENTRY glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } #define glutInit glutInit_ATEXIT_HACK #endif #endif GLUTAPI void APIENTRY glutInitDisplayMode(unsigned int mode); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI void APIENTRY glutInitDisplayString(const char *string); #endif GLUTAPI void APIENTRY glutInitWindowPosition(int x, int y); GLUTAPI void APIENTRY glutInitWindowSize(int width, int height); GLUTAPI void APIENTRY glutMainLoop(void); /* GLUT window sub-API. */ GLUTAPI int APIENTRY glutCreateWindow(const char *title); #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) GLUTAPI int APIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); #ifndef GLUT_BUILDING_LIB static int APIENTRY glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } #define glutCreateWindow glutCreateWindow_ATEXIT_HACK #endif #endif GLUTAPI int APIENTRY glutCreateSubWindow(int win, int x, int y, int width, int height); GLUTAPI void APIENTRY glutDestroyWindow(int win); GLUTAPI void APIENTRY glutPostRedisplay(void); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) GLUTAPI void APIENTRY glutPostWindowRedisplay(int win); #endif GLUTAPI void APIENTRY glutSwapBuffers(void); GLUTAPI int APIENTRY glutGetWindow(void); GLUTAPI void APIENTRY glutSetWindow(int win); GLUTAPI void APIENTRY glutSetWindowTitle(const char *title); GLUTAPI void APIENTRY glutSetIconTitle(const char *title); GLUTAPI void APIENTRY glutPositionWindow(int x, int y); GLUTAPI void APIENTRY glutReshapeWindow(int width, int height); GLUTAPI void APIENTRY glutPopWindow(void); GLUTAPI void APIENTRY glutPushWindow(void); GLUTAPI void APIENTRY glutIconifyWindow(void); GLUTAPI void APIENTRY glutShowWindow(void); GLUTAPI void APIENTRY glutHideWindow(void); #if (GLUT_API_VERSION >= 3) GLUTAPI void APIENTRY glutFullScreen(void); GLUTAPI void APIENTRY glutSetCursor(int cursor); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI void APIENTRY glutWarpPointer(int x, int y); #endif /* GLUT overlay sub-API. */ GLUTAPI void APIENTRY glutEstablishOverlay(void); GLUTAPI void APIENTRY glutRemoveOverlay(void); GLUTAPI void APIENTRY glutUseLayer(GLenum layer); GLUTAPI void APIENTRY glutPostOverlayRedisplay(void); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) GLUTAPI void APIENTRY glutPostWindowOverlayRedisplay(int win); #endif GLUTAPI void APIENTRY glutShowOverlay(void); GLUTAPI void APIENTRY glutHideOverlay(void); #endif /* GLUT menu sub-API. */ GLUTAPI int APIENTRY glutCreateMenu(void (GLUTCALLBACK *func)(int)); #if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) GLUTAPI int APIENTRY __glutCreateMenuWithExit(void (GLUTCALLBACK *func)(int), void (__cdecl *exitfunc)(int)); #ifndef GLUT_BUILDING_LIB static int APIENTRY glutCreateMenu_ATEXIT_HACK(void (GLUTCALLBACK *func)(int)) { return __glutCreateMenuWithExit(func, exit); } #define glutCreateMenu glutCreateMenu_ATEXIT_HACK #endif #endif GLUTAPI void APIENTRY glutDestroyMenu(int menu); GLUTAPI int APIENTRY glutGetMenu(void); GLUTAPI void APIENTRY glutSetMenu(int menu); GLUTAPI void APIENTRY glutAddMenuEntry(const char *label, int value); GLUTAPI void APIENTRY glutAddSubMenu(const char *label, int submenu); GLUTAPI void APIENTRY glutChangeToMenuEntry(int item, const char *label, int value); GLUTAPI void APIENTRY glutChangeToSubMenu(int item, const char *label, int submenu); GLUTAPI void APIENTRY glutRemoveMenuItem(int item); GLUTAPI void APIENTRY glutAttachMenu(int button); GLUTAPI void APIENTRY glutDetachMenu(int button); /* GLUT window callback sub-API. */ GLUTAPI void APIENTRY glutDisplayFunc(void (GLUTCALLBACK *func)(void)); GLUTAPI void APIENTRY glutReshapeFunc(void (GLUTCALLBACK *func)(int width, int height)); GLUTAPI void APIENTRY glutKeyboardFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y)); GLUTAPI void APIENTRY glutMouseFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); GLUTAPI void APIENTRY glutMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); GLUTAPI void APIENTRY glutPassiveMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); GLUTAPI void APIENTRY glutEntryFunc(void (GLUTCALLBACK *func)(int state)); GLUTAPI void APIENTRY glutVisibilityFunc(void (GLUTCALLBACK *func)(int state)); GLUTAPI void APIENTRY glutIdleFunc(void (GLUTCALLBACK *func)(void)); GLUTAPI void APIENTRY glutTimerFunc(unsigned int millis, void (GLUTCALLBACK *func)(int value), int value); GLUTAPI void APIENTRY glutMenuStateFunc(void (GLUTCALLBACK *func)(int state)); #if (GLUT_API_VERSION >= 2) GLUTAPI void APIENTRY glutSpecialFunc(void (GLUTCALLBACK *func)(int key, int x, int y)); GLUTAPI void APIENTRY glutSpaceballMotionFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); GLUTAPI void APIENTRY glutSpaceballRotateFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); GLUTAPI void APIENTRY glutSpaceballButtonFunc(void (GLUTCALLBACK *func)(int button, int state)); GLUTAPI void APIENTRY glutButtonBoxFunc(void (GLUTCALLBACK *func)(int button, int state)); GLUTAPI void APIENTRY glutDialsFunc(void (GLUTCALLBACK *func)(int dial, int value)); GLUTAPI void APIENTRY glutTabletMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); GLUTAPI void APIENTRY glutTabletButtonFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); #if (GLUT_API_VERSION >= 3) GLUTAPI void APIENTRY glutMenuStatusFunc(void (GLUTCALLBACK *func)(int status, int x, int y)); GLUTAPI void APIENTRY glutOverlayDisplayFunc(void (GLUTCALLBACK *func)(void)); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI void APIENTRY glutWindowStatusFunc(void (GLUTCALLBACK *func)(int state)); #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) GLUTAPI void APIENTRY glutKeyboardUpFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y)); GLUTAPI void APIENTRY glutSpecialUpFunc(void (GLUTCALLBACK *func)(int key, int x, int y)); GLUTAPI void APIENTRY glutJoystickFunc(void (GLUTCALLBACK *func)(unsigned int buttonMask, int x, int y, int z), int pollInterval); #endif #endif #endif /* GLUT color index sub-API. */ GLUTAPI void APIENTRY glutSetColor(int, GLfloat red, GLfloat green, GLfloat blue); GLUTAPI GLfloat APIENTRY glutGetColor(int ndx, int component); GLUTAPI void APIENTRY glutCopyColormap(int win); /* GLUT state retrieval sub-API. */ GLUTAPI int APIENTRY glutGet(GLenum type); GLUTAPI int APIENTRY glutDeviceGet(GLenum type); #if (GLUT_API_VERSION >= 2) /* GLUT extension support sub-API */ GLUTAPI int APIENTRY glutExtensionSupported(const char *name); #endif #if (GLUT_API_VERSION >= 3) GLUTAPI int APIENTRY glutGetModifiers(void); GLUTAPI int APIENTRY glutLayerGet(GLenum type); #endif /* GLUT font sub-API */ GLUTAPI void APIENTRY glutBitmapCharacter(void *font, int character); GLUTAPI int APIENTRY glutBitmapWidth(void *font, int character); GLUTAPI void APIENTRY glutStrokeCharacter(void *font, int character); GLUTAPI int APIENTRY glutStrokeWidth(void *font, int character); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) GLUTAPI int APIENTRY glutBitmapLength(void *font, const unsigned char *string); GLUTAPI int APIENTRY glutStrokeLength(void *font, const unsigned char *string); #endif /* GLUT pre-built models sub-API */ GLUTAPI void APIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); GLUTAPI void APIENTRY glutWireCube(GLdouble size); GLUTAPI void APIENTRY glutSolidCube(GLdouble size); GLUTAPI void APIENTRY glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); GLUTAPI void APIENTRY glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); GLUTAPI void APIENTRY glutWireDodecahedron(void); GLUTAPI void APIENTRY glutSolidDodecahedron(void); GLUTAPI void APIENTRY glutWireTeapot(GLdouble size); GLUTAPI void APIENTRY glutSolidTeapot(GLdouble size); GLUTAPI void APIENTRY glutWireOctahedron(void); GLUTAPI void APIENTRY glutSolidOctahedron(void); GLUTAPI void APIENTRY glutWireTetrahedron(void); GLUTAPI void APIENTRY glutSolidTetrahedron(void); GLUTAPI void APIENTRY glutWireIcosahedron(void); GLUTAPI void APIENTRY glutSolidIcosahedron(void); #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) /* GLUT video resize sub-API. */ GLUTAPI int APIENTRY glutVideoResizeGet(GLenum param); GLUTAPI void APIENTRY glutSetupVideoResizing(void); GLUTAPI void APIENTRY glutStopVideoResizing(void); GLUTAPI void APIENTRY glutVideoResize(int x, int y, int width, int height); GLUTAPI void APIENTRY glutVideoPan(int x, int y, int width, int height); /* GLUT debugging sub-API. */ GLUTAPI void APIENTRY glutReportErrors(void); #endif #if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) /* GLUT device control sub-API. */ /* glutSetKeyRepeat modes. */ #define GLUT_KEY_REPEAT_OFF 0 #define GLUT_KEY_REPEAT_ON 1 #define GLUT_KEY_REPEAT_DEFAULT 2 /* Joystick button masks. */ #define GLUT_JOYSTICK_BUTTON_A 1 #define GLUT_JOYSTICK_BUTTON_B 2 #define GLUT_JOYSTICK_BUTTON_C 4 #define GLUT_JOYSTICK_BUTTON_D 8 GLUTAPI void APIENTRY glutIgnoreKeyRepeat(int ignore); GLUTAPI void APIENTRY glutSetKeyRepeat(int repeatMode); GLUTAPI void APIENTRY glutForceJoystickFunc(void); /* GLUT game mode sub-API. */ /* glutGameModeGet. */ #define GLUT_GAME_MODE_ACTIVE ((GLenum) 0) #define GLUT_GAME_MODE_POSSIBLE ((GLenum) 1) #define GLUT_GAME_MODE_WIDTH ((GLenum) 2) #define GLUT_GAME_MODE_HEIGHT ((GLenum) 3) #define GLUT_GAME_MODE_PIXEL_DEPTH ((GLenum) 4) #define GLUT_GAME_MODE_REFRESH_RATE ((GLenum) 5) #define GLUT_GAME_MODE_DISPLAY_CHANGED ((GLenum) 6) GLUTAPI void APIENTRY glutGameModeString(const char *string); GLUTAPI int APIENTRY glutEnterGameMode(void); GLUTAPI void APIENTRY glutLeaveGameMode(void); GLUTAPI int APIENTRY glutGameModeGet(GLenum mode); #endif #ifdef __cplusplus } #endif #ifdef GLUT_APIENTRY_DEFINED # undef GLUT_APIENTRY_DEFINED # undef APIENTRY #endif #ifdef GLUT_WINGDIAPI_DEFINED # undef GLUT_WINGDIAPI_DEFINED # undef WINGDIAPI #endif #ifdef GLUT_DEFINED___CDECL # undef GLUT_DEFINED___CDECL # undef __cdecl #endif #ifdef GLUT_DEFINED__CRTIMP # undef GLUT_DEFINED__CRTIMP # undef _CRTIMP #endif #endif /* __glut_h__ */ |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:22
|
Update of /cvsroot/opentnl/tnl/exe In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063/exe Added Files: OpenAL32.dll flag_capture.wav flag_drop.wav flag_return.wav flag_snatch.wav glut32.dll level1.txt level2.txt level3.txt phaser.wav phaser_impact.wav ship_explode.wav teleport_in.wav teleport_out.wav Log Message: Initial commit. --- NEW FILE: glut32.dll --- (This appears to be a binary file; contents omitted.) --- NEW FILE: OpenAL32.dll --- (This appears to be a binary file; contents omitted.) --- NEW FILE: phaser.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: level2.txt --- # World definition - BJG GridSize 128 GameType 8 2 8 14 Team Blue 0 0 1 BarrierMaker 0 0 5 0 6 1 7 0 10 0 10 10 0 10 0 0 BarrierMaker 8 4 8 4.5 BarrierMaker 8 5 8.5 6 7.5 6 8 5 BarrierMaker 7 7 9 7 9 9 7 9 7 7 BarrierMaker 5 8 6 7.5 6 8.5 5 8 BarrierMaker 11 8 10 8.5 10 7.5 11 8 BarrierMaker 8 11 7.5 10 8.5 10 8 11 BarrierMaker 8 11.5 8 12 Spawn 0 1 6 Spawn 0 4.5 1.5 Spawn 0 6.5 6.5 Spawn 0 7 2 Spawn 0 9 2 Spawn 0 8 1 TestItem 1 2 TestItem 8 2 TestItem 3 2 TestItem 7 2 TestItem 4 2 TestItem 5 2 TestItem 6 2 --- NEW FILE: flag_drop.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: teleport_in.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: level1.txt --- # World definition - BJG GridSize 256 CTFGameType Team Blue 0 0 1 Team Red 1 0 0 CTFFlagItem 0 8 2 CTFFlagItem 1 8 14 Spawn 0 1 6 Spawn 0 4.5 1.5 Spawn 0 6.5 6.5 Spawn 0 7 2 Spawn 0 9 2 Spawn 0 8 1 Spawn 0 14.5 0.5 Spawn 0 15.5 0.5 Spawn 0 14.5 1.5 Spawn 1 15 10 Spawn 1 11.5 14.5 Spawn 1 9.5 9.5 Spawn 1 7 14 Spawn 1 9 14 Spawn 1 8 15 Spawn 1 1.5 15.5 Spawn 1 0.5 15.5 Spawn 1 1.5 14.5 BarrierMaker 1 0 2 0 3 1 4 1 4.2 0.5 4.8 0.5 5 1 6 1 7 0 9 0 10 1 10 2 11 2 11.2 1.5 11.8 1.5 12 2 13 2 14 1 14 0 16 0 16 2 15 3 16 4 16 11 15 12 15 13 16 14 16 15 15 16 14 16 13 15 12 15 11.8 15.5 11.2 15.5 11 15 10 15 9 16 7 16 6 15 6 14 5 14 4.8 14.5 4.2 14.5 4 14 3 14 2 15 2 16 0 16 0 14 1 13 0 12 0 5 1 4 1 3 0 2 0 1 1 0 BarrierMaker 3 2 4 2 4.2 2.5 4.8 2.5 5 2 6 2 6 3 7 4 7 5 6 6 4 7 4 8.5 3.5 8.5 3.5 6 4 6 5 5 5 4 3 4 3 8.5 1 8.5 1 7 2 6 2 3 3 2 BarrierMaker 1 9 3 9 3 10 1 10 1 9 BarrierMaker 8 4 8 5 BarrierMaker 8 5 8.5 6 7.5 6 8 5 BarrierMaker 7 7 9 7 9 9 7 9 7 7 BarrierMaker 5 8 6 7.5 6 8.5 5 8 BarrierMaker 11 8 10 8.5 10 7.5 11 8 BarrierMaker 8 11 7.5 10 8.5 10 8 11 BarrierMaker 8 11 8 12 TestItem 8 6.5 TestItem 8 9.5 TestItem 6.5 8 TestItem 9.5 8 BarrierMaker 1 10.5 1 11 2 12 2 13 4 13 4.2 12.5 4.8 12.5 5 13 6 13 7 12 7 11 6 10 4 9 3.5 9 3.5 10.5 1 10.5 BarrierMaker 9 4 10 3 11 3 11.2 3.5 11.8 3.5 12 3 14 3 14 4 15 5 15 5.5 12.5 5.5 12.5 7 12 7 10 6 9 5 9 4 BarrierMaker 10 14 10 13 9 12 9 11 10 10 12 9 12 7.5 12.5 7.5 12.5 10 12 10 11 11 11 12 13 12 13 7.5 15 7.5 15 9 14 10 14 13 13 14 12 14 11.8 13.5 11.2 13.5 11 14 10 14 BarrierMaker 13 6 15 6 15 7 13 7 13 6 BarrierMaker 7 1.7 7 1.5 7.5 1 7.7 1 BarrierMaker 8.3 1 8.5 1 9 1.5 9 1.7 #BarrierMaker 7 2.3 7 2.5 7.5 3 7.7 3 #BarrierMaker 8.3 3 8.5 3 9 2.5 9 2.3 BarrierMaker 7 2.3 7 2.5 7.5 3 8.5 3 9 2.5 9 2.3 BarrierMaker 7 14.3 7 14.5 7.5 15 7.7 15 BarrierMaker 8.3 15 8.5 15 9 14.5 9 14.3 #BarrierMaker 7 13.7 7 13.5 7.5 13 7.7 13 #BarrierMaker 8.3 13 8.5 13 9 13.5 9 13.7 BarrierMaker 7 13.7 7 13.5 7.5 13 8.5 13 9 13.5 9 13.7 Teleporter 11.5 11.5 1.5 1.5 Teleporter 4.5 4.5 14.5 14.5 #Teleporter 0 0 8 2 #BarrierMaker 0 0 1 0 2 1 Ship 50 300 0 1 0 Ship 450 100 0 1 1 Ship 150 300 1 1 0 --- NEW FILE: teleport_out.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: phaser_impact.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: flag_return.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: flag_snatch.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: level3.txt --- GameType Team Yellow 1 1 0 Spawn 0 0.5 0.5 BarrierMaker 0 0 8 0 8 1 0 1 0 0 Teleporter 7.5 0.5 0.5 0.5 --- NEW FILE: ship_explode.wav --- (This appears to be a binary file; contents omitted.) --- NEW FILE: flag_capture.wav --- (This appears to be a binary file; contents omitted.) |
From: Ben G. <s_a...@us...> - 2004-04-20 04:27:21
|
Update of /cvsroot/opentnl/tnl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31063 Added Files: Makefile ReadMe.html tnl.dsw tnl.sln Log Message: Initial commit. --- NEW FILE: ReadMe.html --- <html> <head> <title>Torque Network Library Readme</title> <style> h1,h2,h3,h4 { border-bottom-style: solid; border-bottom-width: 1px; text-align: center; } h5,h6 { text-align: center; } .header { text-align: left; } </style> </head> <body marginwidth=40px> <h1>Torque Network Library</h1> <h2>Readme</h2> <h5>(c) GarageGames 2004</h5> <h2 class="header">Introduction</h2> <p>Developing computational simulations is a complex, interdisciplinary undertaking. To take a simulation of any sort and run it in a distributed environment introduces a whole new world of problems to overcome. The Torque Network Library provides a robust framework for message passing and efficient state replication, built on a UDP-based protocol.</p> <h2 class="header">Features</h2> <ul> <li>Portable <ul> <li>Platforms <ul> <li>Mac OSX <li>Linux <li>Win32 </ul> <li>Compilers <ul> <li>Xcode <li>GCC <li>Visual C++ 6/7 </ul> </ul> <li>Powerful RPC Support <ul> <li>Lightweight and efficient - not intended to be a replacement for CORBA. <li>Extremely easy to use - two simple macro definitions and you're done. <li>No complex wrapper classes to work with - write and call your functions as you normally would, and TNL will take care of the rest. </ul> <li>Robust UDP-based notification protocol <ul> <li>Supports fixed or adaptive rate data transfer. <li>Arbitrary sized packet window. <li>Robust connection handshaking. <li>Handles packet loss/out of order delivery. </ul> <li>Networked Objects <ul> <li>Instantiation of objects by name or ID. <li>IDs are assigned to NetGroups, so that only objects relevant to a connection can be references. </ul> <li>Event Support <ul> <li>Unguaranteed, guaranteed unordered, or guaranteed ordered event delivery. <li>Notification to the event when it has been received or dropped by a client. </ul> <li>Ghost Support <ul> <li>Most-recent state information is transmitted to clienst. <li>Scoping of objects to only those clients for which they are relevant - this helps prevent cheating or data sniffing and makes dramatically more effective use of available bandwidth. <li>Prioritization of state updates by arbitrary criteria, such as relative velocity, team, ownership, etc. </ul> <li>Extensible Protocol Architecture <ul> <li>Easy to extend the protocol, for instance, to transmit player move information with every packet, or add voice support. <li>See Torque for examples of additional capabilities that could be added to the protocol. </ul> </ul> <h2 class="header">Compiling TNL</h2> <h3 class="header">OSX/Xcode</h3> <p>Under the <code>osx</code> subdirectory there is an XCode project. It is set up to build TNL and the TNLTest app.</p> <h3 class="header">Linux/GCC</h3> <p>From the top level directory, type</p> <code>make</code> <p>If you have OpenGL and wxWindows installed, and OpenGL support enabled in wxWindows, you can build the wxgui test client/server program with</p> <code>cd test && make wxgui</code> <p>The wxgui is not built by default. <h3 class="header">Windows/VC6/VC7</h3> <p>There are VC6 and VC7 project workspaces in the root directory of the checkout. Individual project files are in their respective directories.</p> <h2 class="header">Documentation and Online Resources</h2> <p>The TNL comes with extensive Doxygen documentation. You can access this documentation online at <a href="">Some URL</a>, or generate it by downloading Doxygen from <a href="http://www.doxygen.org/">www.doxygen.org</a> and executing the following command line (assuming you installed Doxygen in the standard place) from the root of your TNL checkout...</p> <ul> <li>Under Windows:<br> <code>"c:\Program Files\doxygen\bin\doxygen.exe" docs\doxygen.html.cfg</code> <li>Under Linux or OSX:<br> <code>doxygen docs/doxygen.html.cfg</code> </ul> <p>This will produce a set of Doxygen docs in the docs\html subdirectory of your TNL checkout. Please note that these docs may ONLY be distributed to other TNL licensees.</p> </body> </html> --- NEW FILE: Makefile --- default: @$(MAKE) -C tnl @$(MAKE) -C libtomcrypt @$(MAKE) -C master @$(MAKE) -C masterclient @$(MAKE) -C test .PHONY: clean clean: @$(MAKE) -C tnl clean @$(MAKE) -C libtomcrypt clean @$(MAKE) -C master clean @$(MAKE) -C masterclient clean @$(MAKE) -C test clean --- NEW FILE: tnl.dsw --- Microsoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "TNLTest"=.\test\TNLTest.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name tnl End Project Dependency Begin Project Dependency Project_Dep_Name libtomcrypt End Project Dependency }}} ############################################################################### Project: "libtomcrypt"=.\libtomcrypt\libtomcrypt.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "master"=.\master\master.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name libtomcrypt End Project Dependency Begin Project Dependency Project_Dep_Name tnl End Project Dependency }}} ############################################################################### Project: "masterclient"=.\masterclient\masterclient.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name libtomcrypt End Project Dependency Begin Project Dependency Project_Dep_Name tnl End Project Dependency }}} ############################################################################### Project: "server"=.\test\server.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name tnl End Project Dependency Begin Project Dependency Project_Dep_Name libtomcrypt End Project Dependency }}} ############################################################################### Project: "tnl"=.\tnl\tnl.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "zap"=.\zap\zap.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name libtomcrypt End Project Dependency Begin Project Dependency Project_Dep_Name tnl End Project Dependency }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### --- NEW FILE: tnl.sln --- Microsoft Visual Studio Solution File, Format Version 8.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tnl", "tnl\tnl.vcproj", "{5FAF4911-1DA7-44FE-9DA1-49AE25B11250}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TNLTest", "test\TNLTest.vcproj", "{2BF337F1-B812-4324-A9BA-E4D580C8CFF1}" ProjectSection(ProjectDependencies) = postProject {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} = {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} = {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "server", "test\server.vcproj", "{2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}" ProjectSection(ProjectDependencies) = postProject {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} = {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} = {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtomcrypt", "libtomcrypt\libtomcrypt.vcproj", "{3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}" ProjectSection(ProjectDependencies) = postProject EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "master", "master\master.vcproj", "{CE4F0113-8119-491D-BCBE-20F5C3A555FC}" ProjectSection(ProjectDependencies) = postProject {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} = {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} = {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "masterclient", "masterclient\masterclient.vcproj", "{F931A5FA-FF37-4977-8493-786AFD5D71EC}" ProjectSection(ProjectDependencies) = postProject {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} = {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} = {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ZAP", "zap\ZAP.vcproj", "{F1A0916C-3232-4C2E-B52B-368955AA4C62}" ProjectSection(ProjectDependencies) = postProject {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} = {5FAF4911-1DA7-44FE-9DA1-49AE25B11250} {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} = {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A} EndProjectSection EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug Debug Win32 = Debug Win32 Debug Xbox = Debug Xbox Release = Release Release Win32 = Release Win32 Release Xbox = Release Xbox EndGlobalSection GlobalSection(ProjectConfiguration) = postSolution {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Debug.ActiveCfg = Debug|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Debug.Build.0 = Debug|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Debug Win32.ActiveCfg = Debug|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Debug Win32.Build.0 = Debug|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Debug Xbox.ActiveCfg = Debug|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Debug Xbox.Build.0 = Debug|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Release.ActiveCfg = Release|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Release.Build.0 = Release|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Release Win32.ActiveCfg = Release|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Release Win32.Build.0 = Release|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Release Xbox.ActiveCfg = Release|Win32 {5FAF4911-1DA7-44FE-9DA1-49AE25B11250}.Release Xbox.Build.0 = Release|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Debug.ActiveCfg = Debug|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Debug Win32.ActiveCfg = Debug|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Debug Xbox.ActiveCfg = Debug|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Debug Xbox.Build.0 = Debug|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Release.ActiveCfg = Release|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Release.Build.0 = Release|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Release Win32.ActiveCfg = Release|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Release Win32.Build.0 = Release|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Release Xbox.ActiveCfg = Release|Win32 {2BF337F1-B812-4324-A9BA-E4D580C8CFF1}.Release Xbox.Build.0 = Release|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Debug.ActiveCfg = Debug|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Debug Win32.ActiveCfg = Debug|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Debug Xbox.ActiveCfg = Debug|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Debug Xbox.Build.0 = Debug|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Release.ActiveCfg = Release|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Release.Build.0 = Release|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Release Win32.ActiveCfg = Release|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Release Win32.Build.0 = Release|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Release Xbox.ActiveCfg = Release|Win32 {2BC8A06B-B9E6-4C92-9E10-6B5E37CBFF96}.Release Xbox.Build.0 = Release|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Debug.ActiveCfg = Debug|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Debug Win32.ActiveCfg = Debug|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Debug Win32.Build.0 = Debug|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Debug Xbox.ActiveCfg = Debug|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Debug Xbox.Build.0 = Debug|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Release.ActiveCfg = Release|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Release.Build.0 = Release|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Release Win32.ActiveCfg = Release|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Release Win32.Build.0 = Release|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Release Xbox.ActiveCfg = Release|Win32 {3F7F7B79-4473-4CAB-A54E-4274A9F1A01A}.Release Xbox.Build.0 = Release|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Debug.ActiveCfg = Debug|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Debug Win32.ActiveCfg = Debug|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Debug Xbox.ActiveCfg = Debug|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Debug Xbox.Build.0 = Debug|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Release.ActiveCfg = Release|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Release.Build.0 = Release|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Release Win32.ActiveCfg = Release|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Release Win32.Build.0 = Release|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Release Xbox.ActiveCfg = Release|Win32 {CE4F0113-8119-491D-BCBE-20F5C3A555FC}.Release Xbox.Build.0 = Release|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Debug.ActiveCfg = Debug|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Debug Win32.ActiveCfg = Debug|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Debug Xbox.ActiveCfg = Debug|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Debug Xbox.Build.0 = Debug|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Release.ActiveCfg = Release|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Release.Build.0 = Release|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Release Win32.ActiveCfg = Release|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Release Win32.Build.0 = Release|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Release Xbox.ActiveCfg = Release|Win32 {F931A5FA-FF37-4977-8493-786AFD5D71EC}.Release Xbox.Build.0 = Release|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Debug.ActiveCfg = Debug|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Debug.Build.0 = Debug|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Debug Win32.ActiveCfg = Debug|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Debug Win32.Build.0 = Debug|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Debug Xbox.ActiveCfg = Debug|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Debug Xbox.Build.0 = Debug|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Release.ActiveCfg = Release|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Release.Build.0 = Release|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Release Win32.ActiveCfg = Release|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Release Win32.Build.0 = Release|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Release Xbox.ActiveCfg = Release|Win32 {F1A0916C-3232-4C2E-B52B-368955AA4C62}.Release Xbox.Build.0 = Release|Win32 EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution EndGlobalSection GlobalSection(ExtensibilityAddIns) = postSolution EndGlobalSection EndGlobal |
From: Ben G. <s_a...@us...> - 2004-04-20 04:23:30
|
Update of /cvsroot/opentnl/tnl/osx/English.lproj/MainMenu.nib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30644/MainMenu.nib Log Message: Directory /cvsroot/opentnl/tnl/osx/English.lproj/MainMenu.nib added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:23:21
|
Update of /cvsroot/opentnl/tnl/osx/English.lproj In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30620/English.lproj Log Message: Directory /cvsroot/opentnl/tnl/osx/English.lproj added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:23:21
|
Update of /cvsroot/opentnl/tnl/osx/tnl.xcode In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30620/tnl.xcode Log Message: Directory /cvsroot/opentnl/tnl/osx/tnl.xcode added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:17
|
Update of /cvsroot/opentnl/tnl/masterclient In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/masterclient Log Message: Directory /cvsroot/opentnl/tnl/masterclient added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:16
|
Update of /cvsroot/opentnl/tnl/master In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/master Log Message: Directory /cvsroot/opentnl/tnl/master added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:16
|
Update of /cvsroot/opentnl/tnl/exe In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/exe Log Message: Directory /cvsroot/opentnl/tnl/exe added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:15
|
Update of /cvsroot/opentnl/tnl/openal In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/openal Log Message: Directory /cvsroot/opentnl/tnl/openal added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:14
|
Update of /cvsroot/opentnl/tnl/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/test Log Message: Directory /cvsroot/opentnl/tnl/test added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:14
|
Update of /cvsroot/opentnl/tnl/zap In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/zap Log Message: Directory /cvsroot/opentnl/tnl/zap added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:14
|
Update of /cvsroot/opentnl/tnl/tnl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/tnl Log Message: Directory /cvsroot/opentnl/tnl/tnl added to the repository |
From: Ben G. <s_a...@us...> - 2004-04-20 04:20:09
|
Update of /cvsroot/opentnl/tnl/osx In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29911/osx Log Message: Directory /cvsroot/opentnl/tnl/osx added to the repository |