Skip to content

Instantly share code, notes, and snippets.

@jamesu
Created September 26, 2025 15:02
Show Gist options
  • Save jamesu/f31cef752da7dc38f9d119ee77265489 to your computer and use it in GitHub Desktop.
Save jamesu/f31cef752da7dc38f9d119ee77265489 to your computer and use it in GitHub Desktop.
Code to dump packet info from onverse connections
//#pragma GCC visibility push(hidden)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/poll.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <vector>
// BitStream
// g++ -m32 -fPIC -dynamiclib -shared replacement_lib.c -o replacement.dylib
#undef M_PI
#undef M_SQRT2
#define M_PI 3.14159265358979323846
#define M_SQRT2 1.41421356237309504880
#define M_2PI (3.1415926535897932384626433 * 2.0)
#define M_SQRTHALF 0.7071067811865475244008443
#define M_PI_F 3.14159265358979323846f
#define M_SQRT2_F 1.41421356237309504880f
#define M_2PI_F (3.1415926535897932384626433f * 2.0f)
#define M_SQRTHALF_F 0.7071067811865475244008443f
#define BIT(x) (1 << (x)) ///< Returns value with bit x set (2^x)
#define DECLARE_OVERLOADED_READ(type) \
bool read(type* out_read) { \
return read(sizeof(type), out_read); \
}
#define DECLARE_OVERLOADED_WRITE(type) \
bool write(type in_write) { \
return write(sizeof(type), &in_write); \
}
#define DECLARE_ENDIAN_OVERLOADED_READ(type) \
bool read(type* out_read) { \
type temp; \
bool success = read(sizeof(type), &temp); \
*out_read = (temp); \
return success; \
}
#define DECLARE_ENDIAN_OVERLOADED_WRITE(type) \
bool write(type in_write) { \
type temp = (in_write); \
return write(sizeof(type), &temp); \
}
typedef unsigned int U32;
typedef signed int S32;
typedef unsigned char U8;
typedef unsigned short U16;
typedef short S16;
typedef char S8;
typedef float F32;
class OVNetAddress;
enum EventConstants
{
MaxPacketDataSize = 1500, ///< Maximum allowed size of a packet.
MaxConsoleLineSize = 512 ///< Maximum allowed size of a console line.
};
void AssertFatal(bool cond, const char *str)
{
if (!cond)
{
//printf("%s\n", str);
}
}
inline F32 mSqrt(const F32 val)
{
return (F32) sqrt(val);
}
inline F32 mFabs(const F32 val)
{
return (F32) fabs(val);
}
inline F32 mCos(const F32 angle)
{
return (F32) cos(angle);
}
inline F32 mSin(const F32 angle)
{
return (F32) sin(angle);
}
inline F32 mAsin(const F32 val)
{
return (F32) asin(val);
}
inline F32 mAtan(const F32 x, const F32 y)
{
return (F32) atan2(x, y);
}
inline U32 getNextPow2(U32 io_num);
/// Determines if the given U32 is some 2^n
/// @returns true if in_num is a power of two, otherwise false
inline bool isPow2(const U32 in_num)
{
return (in_num == getNextPow2(in_num));
}
// note: impl from T2D
inline U32 getNextPow2(U32 io_num)
{
S32 oneCount = 0;
S32 shiftCount = -1;
while (io_num) {
if(io_num & 1)
oneCount++;
shiftCount++;
io_num >>= 1;
}
if(oneCount > 1)
shiftCount++;
return U32(1 << shiftCount);
}
// note: impl from T2D
inline U32 getBinLog2(U32 io_num)
{
AssertFatal(io_num != 0 && isPow2(io_num) == true,
"Error, this only works on powers of 2 > 0");
S32 shiftCount = 0;
while (io_num) {
shiftCount++;
io_num >>= 1;
}
return U32(shiftCount - 1);
}
/// Returns the lesser of the two parameters: a & b.
inline U32 getMin(U32 a, U32 b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline U16 getMin(U16 a, U16 b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline U8 getMin(U8 a, U8 b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline S32 getMin(S32 a, S32 b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline S16 getMin(S16 a, S16 b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline S8 getMin(S8 a, S8 b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline float getMin(float a, float b)
{
return a>b ? b : a;
}
/// Returns the lesser of the two parameters: a & b.
inline double getMin(double a, double b)
{
return a>b ? b : a;
}
/// Returns the greater of the two parameters: a & b.
inline U32 getMax(U32 a, U32 b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline U16 getMax(U16 a, U16 b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline U8 getMax(U8 a, U8 b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline S32 getMax(S32 a, S32 b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline S16 getMax(S16 a, S16 b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline S8 getMax(S8 a, S8 b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline float getMax(float a, float b)
{
return a>b ? a : b;
}
/// Returns the greater of the two parameters: a & b.
inline double getMax(double a, double b)
{
return a>b ? a : b;
}
inline S32 mClamp(S32 val, S32 low, S32 high)
{
return getMax(getMin(val, high), low);
}
inline F32 mClampF(F32 val, F32 low, F32 high)
{
return (F32) getMax(getMin(val, high), low);
}
/// A convenience class to manipulate a set of bits.
///
/// Notice that bits are accessed directly, ie, by passing
/// a variable with the relevant bit set or not, instead of
/// passing the index of the relevant bit.
class BitSet32
{
private:
/// Internal representation of bitset.
U32 mbits;
public:
BitSet32() { mbits = 0; }
BitSet32(const BitSet32& in_rCopy) { mbits = in_rCopy.mbits; }
BitSet32(const U32 in_mask) { mbits = in_mask; }
operator U32() const { return mbits; }
U32 getMask() const { return mbits; }
/// Set all bits to true.
void set() { mbits = 0xFFFFFFFFUL; }
/// Set the specified bit(s) to true.
void set(const U32 m) { mbits |= m; }
/// Masked-set the bitset; ie, using s as the mask and then setting the masked bits
/// to b.
void set(BitSet32 s, bool b) { mbits = (mbits&~(s.mbits))|(b?s.mbits:0); }
/// Clear all bits.
void clear() { mbits = 0; }
/// Clear the specified bit(s).
void clear(const U32 m) { mbits &= ~m; }
/// Toggle the specified bit(s).
void toggle(const U32 m) { mbits ^= m; }
/// Are any of the specified bit(s) set?
bool test(const U32 m) const { return (mbits & m) != 0; }
/// Are ALL the specified bit(s) set?
bool testStrict(const U32 m) const { return (mbits & m) == m; }
/// @name Operator Overloads
/// @{
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); }
/// @}
};
class Point3F;
class HuffmanProcessor;
struct Point3F
{
F32 x,y,z;
Point3F() : x(0), y(0), z(0) {;}
Point3F(F32 _x, F32 _y, F32 _z) : x(_x), y(_y), z(_z) { ; }
inline Point3F operator-(const Point3F& in) const
{
return Point3F(x - in.x, y - in.y, z - in.z);
}
inline Point3F operator-=(const Point3F& in)
{
x -= in.x;
y -= in.y;
z -= in.z;
return *this;
}
inline F32 len()
{
return mSqrt(x*x + y*y + z*z);
}
};
class Stream
{
// Public structs and enumerations...
public:
/// Status constantants for the stream
enum Status {
Ok = 0, ///< Ok!
IOError, ///< Read or Write error
EOS, ///< End of Stream reached (mostly for reads)
IllegalCall, ///< An unsupported operation used. Always w/ accompanied by AssertWarn
Closed, ///< Tried to operate on a closed stream (or detached filter)
UnknownError ///< Catchall
};
enum Capability {
StreamWrite = BIT(0), ///< Can this stream write?
StreamRead = BIT(1), ///< Can this stream read?
StreamPosition = BIT(2) ///< Can this stream position?
};
// Accessible only through inline accessors
private:
Status m_streamStatus;
public:
virtual bool _read (const U32 size,void* d) = 0;
virtual bool _write(const U32 size,const void* d) = 0;
// Overloaded write and read ops..
public:
bool read(const U32 in_numBytes, void* out_pBuffer) {
return _read(in_numBytes, out_pBuffer);
}
bool write(const U32 in_numBytes, const void* in_pBuffer) {
return _write(in_numBytes, in_pBuffer);
}
DECLARE_OVERLOADED_WRITE(S8)
DECLARE_OVERLOADED_WRITE(U8)
DECLARE_ENDIAN_OVERLOADED_WRITE(S16)
DECLARE_ENDIAN_OVERLOADED_WRITE(S32)
DECLARE_ENDIAN_OVERLOADED_WRITE(U16)
DECLARE_ENDIAN_OVERLOADED_WRITE(U32)
DECLARE_ENDIAN_OVERLOADED_WRITE(F32)
DECLARE_OVERLOADED_READ(S8)
DECLARE_OVERLOADED_READ(U8)
DECLARE_ENDIAN_OVERLOADED_READ(S16)
DECLARE_ENDIAN_OVERLOADED_READ(S32)
DECLARE_ENDIAN_OVERLOADED_READ(U16)
DECLARE_ENDIAN_OVERLOADED_READ(U32)
DECLARE_ENDIAN_OVERLOADED_READ(F32)
};
// should be 52 bytes
class BitStream : public Stream
{
public:
U8 *dataPtr;
S32 bitNum;
S32 bufSize;
bool error;
S32 maxReadBitNum;
S32 maxWriteBitNum;
char *stringBuffer;
bool mCompressRelative;
Point3F mCompressPoint;
friend class HuffmanProcessor;
public:
static BitStream *getPacketStream(U32 writeSize = 0);
static void sendPacketStream(const OVNetAddress *addr);
void setBuffer(void *bufPtr, S32 bufSize, S32 maxSize = 0);
U8* getBuffer() { return dataPtr; }
U8* getBytePtr();
U32 getReadByteSize();
S32 getCurPos() const;
void setCurPos(const U32);
BitStream(void *bufPtr, S32 bufSize, S32 maxWriteSize = -1) { setBuffer(bufPtr, bufSize,maxWriteSize); stringBuffer = NULL; }
void clear();
void setStringBuffer(char buffer[256]);
void writeInt(S32 value, S32 bitCount);
S32 readInt(S32 bitCount);
/// Use this method to write out values in a concise but ass backwards way...
/// Good for values you expect to be frequently zero, often small. Worst case
/// this will bloat values by nearly 20% (5 extra bits!) Best case you'll get
/// one bit (if it's zero).
///
/// This is not so much for efficiency's sake, as to make life painful for
/// people that want to reverse engineer our network or file formats.
void writeCussedU32(U32 val)
{
// Is it zero?
if(writeFlag(val == 0))
return;
if(writeFlag(val <= 0xF)) // 4 bit
writeRangedU32(val, 0, 0xF);
else if(writeFlag(val <= 0xFF)) // 8 bit
writeRangedU32(val, 0, 0xFF);
else if(writeFlag(val <= 0xFFFF)) // 16 bit
writeRangedU32(val, 0, 0xFFFF);
else if(writeFlag(val <= 0xFFFFFF)) // 24 bit
writeRangedU32(val, 0, 0xFFFFFF);
else
writeRangedU32(val, 0, 0xFFFFFFFF);
}
U32 readCussedU32()
{
if(readFlag())
return 0;
if(readFlag())
return readRangedU32(0, 0xF);
else if(readFlag())
return readRangedU32(0, 0xFF);
else if(readFlag())
return readRangedU32(0, 0xFFFF);
else if(readFlag())
return readRangedU32(0, 0xFFFFFF);
else
return readRangedU32(0, 0xFFFFFFFF);
}
void writeSignedInt(S32 value, S32 bitCount);
S32 readSignedInt(S32 bitCount);
void writeRangedU32(U32 value, U32 rangeStart, U32 rangeEnd);
U32 readRangedU32(U32 rangeStart, U32 rangeEnd);
/// Writes a clamped signed integer to the stream using
/// an optimal amount of bits for the range.
void writeRangedS32( S32 value, S32 min, S32 max );
/// Reads a ranged signed integer written with writeRangedS32.
S32 readRangedS32( S32 min, S32 max );
// read and write floats... floats are 0 to 1 inclusive, signed floats are -1 to 1 inclusive
F32 readFloat(S32 bitCount);
F32 readSignedFloat(S32 bitCount);
void writeFloat(F32 f, S32 bitCount);
void writeSignedFloat(F32 f, S32 bitCount);
/// Writes a clamped floating point value to the
/// stream with the desired bits of precision.
void writeRangedF32( F32 value, F32 min, F32 max, U32 numBits );
/// Reads a ranged floating point value written with writeRangedF32.
F32 readRangedF32( F32 min, F32 max, U32 numBits );
void writeClassId(U32 classId, U32 classType, U32 classGroup);
S32 readClassId(U32 classType, U32 classGroup); // returns -1 if the class type is out of range
// writes a normalized vector
void writeNormalVector(const Point3F& vec, S32 bitCount);
void readNormalVector(Point3F *vec, S32 bitCount);
void clearCompressionPoint();
void setCompressionPoint(const Point3F& p);
// Matching calls to these compression methods must, of course,
// have matching scale values.
void writeCompressedPoint(const Point3F& p,F32 scale = 0.01f);
void readCompressedPoint(Point3F* p,F32 scale = 0.01f);
// Uses the above method to reduce the precision of a normal vector so the server can
// determine exactly what is on the client. (Pre-dumbing the vector before sending
// to the client can result in precision errors...)
static Point3F dumbDownNormal(const Point3F& vec, S32 bitCount);
// writes a normalized vector using alternate method
void writeNormalVector(const Point3F& vec, S32 angleBitCount, S32 zBitCount);
void readNormalVector(Point3F *vec, S32 angleBitCount, S32 zBitCount);
void readVector(Point3F * vec, F32 minMag, F32 maxMag, S32 magBits, S32 angleBits, S32 zBits);
void writeVector(Point3F vec, F32 minMag, F32 maxMag, S32 magBits, S32 angleBits, S32 zBits);
virtual void writeBits(S32 bitCount, const void *bitPtr);
virtual void readBits(S32 bitCount, void *bitPtr);
virtual bool writeFlag(bool val);
virtual bool readFlag();
void setBit(S32 bitCount, bool set);
bool testBit(S32 bitCount);
bool isFull() { return bitNum > (bufSize << 3); }
bool isValid() { return !error; }
bool _read (const U32 size,void* d);
bool _write(const U32 size,const void* d);
void readString(char stringBuf[256]);
void writeString(const char *stringBuf, S32 maxLen=255);
bool hasCapability(const Capability) const { return true; }
U32 getPosition() const;
bool setPosition(const U32 in_newPosition);
U32 getStreamSize();
static void copyState(BitStream* in, BitStream* out)
{
out->dataPtr = in->dataPtr;
out->bitNum = in->bitNum;
out->bufSize = in->bufSize;
out->error = in->error;
out->maxReadBitNum = in->maxReadBitNum;
out->maxWriteBitNum = in->maxWriteBitNum;
out->stringBuffer = in->stringBuffer;
out->mCompressRelative = in->mCompressRelative;
out->mCompressPoint = in->mCompressPoint;
}
};
//------------------------------------------------------------------------------
//-------------------------------------- INLINES
//
inline S32 BitStream::getCurPos() const
{
return bitNum;
}
inline void BitStream::setCurPos(const U32 in_position)
{
AssertFatal(in_position < (U32)(bufSize << 3), "Out of range bitposition");
bitNum = S32(in_position);
}
inline bool BitStream::readFlag()
{
if(bitNum > maxReadBitNum)
{
error = true;
AssertFatal(false, "Out of range read");
return false;
}
S32 mask = 1 << (bitNum & 0x7);
bool ret = (*(dataPtr + (bitNum >> 3)) & mask) != 0;
bitNum++;
return ret;
}
inline void BitStream::writeRangedU32(U32 value, U32 rangeStart, U32 rangeEnd)
{
AssertFatal(value >= rangeStart && value <= rangeEnd, "Out of bounds value!");
AssertFatal(rangeEnd >= rangeStart, "error, end of range less than start");
U32 rangeSize = rangeEnd - rangeStart + 1;
U32 rangeBits = getBinLog2(getNextPow2(rangeSize));
writeInt(S32(value - rangeStart), S32(rangeBits));
}
inline U32 BitStream::readRangedU32(U32 rangeStart, U32 rangeEnd)
{
AssertFatal(rangeEnd >= rangeStart, "error, end of range less than start");
U32 rangeSize = rangeEnd - rangeStart + 1;
U32 rangeBits = getBinLog2(getNextPow2(rangeSize));
U32 val = U32(readInt(S32(rangeBits)));
return val + rangeStart;
}
inline void BitStream::writeRangedS32( S32 value, S32 min, S32 max )
{
value = mClamp( value, min, max );
writeRangedU32( ( value - min ), 0, ( max - min ) );
}
inline S32 BitStream::readRangedS32( S32 min, S32 max )
{
return readRangedU32( 0, ( max - min ) ) + min;
}
inline void BitStream::writeRangedF32( F32 value, F32 min, F32 max, U32 numBits )
{
value = ( mClampF( value, min, max ) - min ) / ( max - min );
writeInt( (S32)(value * ( (1 << numBits) - 1 )), numBits );
}
inline F32 BitStream::readRangedF32( F32 min, F32 max, U32 numBits )
{
F32 value = (F32)readInt( numBits );
value /= F32( ( 1 << numBits ) - 1 );
return min + value * ( max - min );
}
static BitStream gPacketStream(NULL, 0);
static U8 gPacketBuffer[MaxPacketDataSize];
// bitstream utility functions
void BitStream::setStringBuffer(char buffer[256])
{
stringBuffer = buffer;
}
typedef BitStream* (*fpGetPacketStream)(void);
BitStream *BitStream::getPacketStream(U32 writeSize)
{
// hook into orig ver
// @ 0x000adc02
const fpGetPacketStream _func = (fpGetPacketStream)0x53780;
return _func();
}
typedef const char* (*fpSendPacketStream)(const OVNetAddress*);
void BitStream::sendPacketStream(const OVNetAddress *addr)
{
// hook into orig ver
const fpSendPacketStream _func = (fpSendPacketStream)0x53aa0;
_func(addr);
}
// FIXMEFIXMEFIXME MATH
inline bool IsEqual(F32 a, F32 b) { return a == b; }
class HuffmanProcessor
{
static const U32 csm_charFreqs[256];
bool m_tablesBuilt;
void buildTables();
struct HuffNode {
U32 pop;
S16 index0;
S16 index1;
};
struct HuffLeaf {
U32 pop;
U8 numBits;
U8 symbol;
U32 code; // no code should be longer than 32 bits.
};
// We have to be a bit careful with these, mSince they are pointers...
struct HuffWrap {
HuffNode* pNode;
HuffLeaf* pLeaf;
public:
HuffWrap() : pNode(NULL), pLeaf(NULL) { }
void set(HuffLeaf* in_leaf) { pNode = NULL; pLeaf = in_leaf; }
void set(HuffNode* in_node) { pLeaf = NULL; pNode = in_node; }
U32 getPop() { if (pNode) return pNode->pop; else return pLeaf->pop; }
};
std::vector<HuffNode> m_huffNodes;
std::vector<HuffLeaf> m_huffLeaves;
S16 determineIndex(HuffWrap&);
void generateCodes(BitStream&, S32, S32);
public:
HuffmanProcessor() : m_tablesBuilt(false) { }
static HuffmanProcessor g_huffProcessor;
bool readHuffBuffer(BitStream* pStream, char* out_pBuffer);
bool writeHuffBuffer(BitStream* pStream, const char* out_pBuffer, S32 maxLen);
};
HuffmanProcessor HuffmanProcessor::g_huffProcessor;
void BitStream::setBuffer(void *bufPtr, S32 size, S32 maxSize)
{
dataPtr = (U8 *) bufPtr;
bitNum = 0;
bufSize = size;
maxReadBitNum = size << 3;
if(maxSize < 0)
maxSize = size;
maxWriteBitNum = maxSize << 3;
error = false;
mCompressRelative = false;
}
U32 BitStream::getPosition() const
{
return (bitNum + 7) >> 3;
}
bool BitStream::setPosition(const U32 pos)
{
bitNum = pos << 3;
return (true);
}
U32 BitStream::getStreamSize()
{
return bufSize;
}
U8 *BitStream::getBytePtr()
{
return dataPtr + getPosition();
}
U32 BitStream::getReadByteSize()
{
return (maxReadBitNum >> 3) - getPosition();
}
void BitStream::clear()
{
memset(dataPtr, 0, bufSize);
}
void BitStream::writeClassId(U32 classId, U32 classType, U32 classGroup)
{
//AssertFatal(classType < NetClassTypesCount, "Out of range class type.");
//AssertFatal(classId < AbstractClassRep::NetClassCount[classGroup][classType], "Out of range class id.");
//writeInt(classId, AbstractClassRep::NetClassBitSize[classGroup][classType]);
}
//-----------------------------------------------------------------------------
enum NetClassTypes {
NetClassTypeObject = 0,
NetClassTypeDataBlock,
NetClassTypeEvent,
NetClassTypesCount,
};
//-----------------------------------------------------------------------------
enum NetClassGroups {
NetClassGroupGame = 0,
NetClassGroupCommunity,
NetClassGroup3,
NetClassGroup4,
NetClassGroupsCount,
};
U32 __NetClassBitSize[NetClassGroupsCount][NetClassTypesCount];
S32 BitStream::readClassId(U32 classType, U32 classGroup)
{
//AssertFatal(classType < NetClassTypesCount, "Out of range class type.");
printf("Type %u group %u\n", classType, classGroup);
S32 ret = readInt(__NetClassBitSize[classGroup][classType]);
//printf("Read packet bits: %u\n", __NetClassBitSize[classGroup][classType]);
return ret;
}
void BitStream::writeBits(S32 bitCount, const void *bitPtr)
{
if(!bitCount)
return;
if(bitCount + bitNum > maxWriteBitNum)
{
error = true;
AssertFatal(false, "Out of range write");
return;
}
// [tom, 8/17/2006] This is probably a lot lamer then it needs to be. However,
// at least it doesnt clobber data or overrun the buffer like the old code did.
const U8 *ptr = (U8 *)bitPtr;
for(S32 srcBitNum = 0;srcBitNum < bitCount;srcBitNum++)
{
if((*(ptr + (srcBitNum >> 3)) & (1 << (srcBitNum & 0x7))) != 0)
*(dataPtr + (bitNum >> 3)) |= (1 << (bitNum & 0x7));
else
*(dataPtr + (bitNum >> 3)) &= ~(1 << (bitNum & 0x7));
bitNum++;
}
}
void BitStream::setBit(S32 bitCount, bool set)
{
if(set)
*(dataPtr + (bitCount >> 3)) |= (1 << (bitCount & 0x7));
else
*(dataPtr + (bitCount >> 3)) &= ~(1 << (bitCount & 0x7));
}
bool BitStream::testBit(S32 bitCount)
{
return (*(dataPtr + (bitCount >> 3)) & (1 << (bitCount & 0x7))) != 0;
}
bool BitStream::writeFlag(bool val)
{
if(bitNum + 1 > maxWriteBitNum)
{
error = true;
AssertFatal(false, "Out of range write");
return false;
}
if(val)
*(dataPtr + (bitNum >> 3)) |= (1 << (bitNum & 0x7));
else
*(dataPtr + (bitNum >> 3)) &= ~(1 << (bitNum & 0x7));
bitNum++;
return (val);
}
void BitStream::readBits(S32 bitCount, void *bitPtr)
{
if(!bitCount)
return;
if(bitCount + bitNum > maxReadBitNum)
{
error = true;
AssertFatal(false, "Out of range read");
//AssertWarn(false, "Out of range read");
return;
}
U8 *stPtr = dataPtr + (bitNum >> 3);
S32 byteCount = (bitCount + 7) >> 3;
U8 *ptr = (U8 *) bitPtr;
S32 downShift = bitNum & 0x7;
S32 upShift = 8 - downShift;
U8 curB = *stPtr;
while(byteCount--)
{
U8 nextB = *++stPtr;
*ptr++ = (curB >> downShift) | (nextB << upShift);
curB = nextB;
}
bitNum += bitCount;
}
bool BitStream::_read(U32 size, void *dataPtr)
{
readBits(size << 3, dataPtr);
return true;
}
bool BitStream::_write(U32 size, const void *dataPtr)
{
writeBits(size << 3, dataPtr);
return true;
}
S32 BitStream::readInt(S32 bitCount)
{
S32 ret = 0;
readBits(bitCount, &ret);
ret = (ret);
if(bitCount == 32)
return ret;
else
ret &= (1 << bitCount) - 1;
return ret;
}
void BitStream::writeInt(S32 val, S32 bitCount)
{
val = (val);
writeBits(bitCount, &val);
}
void BitStream::writeFloat(F32 f, S32 bitCount)
{
writeInt((S32)(f * ((1 << bitCount) - 1)), bitCount);
}
F32 BitStream::readFloat(S32 bitCount)
{
return readInt(bitCount) / F32((1 << bitCount) - 1);
}
void BitStream::writeSignedFloat(F32 f, S32 bitCount)
{
writeInt((S32)(((f + 1) * .5) * ((1 << bitCount) - 1)), bitCount);
}
F32 BitStream::readSignedFloat(S32 bitCount)
{
return readInt(bitCount) * 2 / F32((1 << bitCount) - 1) - 1.0f;
}
void BitStream::writeSignedInt(S32 value, S32 bitCount)
{
if(writeFlag(value < 0))
writeInt(-value, bitCount - 1);
else
writeInt(value, bitCount - 1);
}
S32 BitStream::readSignedInt(S32 bitCount)
{
if(readFlag())
return -readInt(bitCount - 1);
else
return readInt(bitCount - 1);
}
void BitStream::writeNormalVector(const Point3F& vec, S32 bitCount)
{
F32 phi = mAtan(vec.x, vec.y) / (F32)M_PI;
F32 theta = mAtan(vec.z, mSqrt(vec.x*vec.x + vec.y*vec.y)) / ((F32)M_PI/2.0f);
writeSignedFloat(phi, bitCount+1);
writeSignedFloat(theta, bitCount);
}
void BitStream::readNormalVector(Point3F *vec, S32 bitCount)
{
F32 phi = readSignedFloat(bitCount+1) * (U32)M_PI;
F32 theta = readSignedFloat(bitCount) * ((F32)M_PI/2.0f);
vec->x = mSin(phi)*mCos(theta);
vec->y = mCos(phi)*mCos(theta);
vec->z = mSin(theta);
}
Point3F BitStream::dumbDownNormal(const Point3F& vec, S32 bitCount)
{
U8 buffer[128];
BitStream temp(buffer, 128);
temp.writeNormalVector(vec, bitCount);
temp.setCurPos(0);
Point3F ret;
temp.readNormalVector(&ret, bitCount);
return ret;
}
void BitStream::writeNormalVector(const Point3F& vec, S32 angleBitCount, S32 zBitCount)
{
writeSignedFloat( vec.z, zBitCount );
// don't need to write x and y if they are both zero, which we can assess
// by checking for |z| == 1
if(!IsEqual(mFabs(vec.z), 1.0f))
{
writeSignedFloat( mAtan(vec.x,vec.y) / (F32)M_2PI, angleBitCount );
}
else
{
// angle won't matter...
writeSignedFloat(0.0f,angleBitCount);
}
}
void BitStream::readNormalVector(Point3F * vec, S32 angleBitCount, S32 zBitCount)
{
vec->z = readSignedFloat(zBitCount);
F32 angle = (F32)M_2PI * readSignedFloat(angleBitCount);
F32 mult = mSqrt(1.0f - vec->z * vec->z);
vec->x = mult * mSin(angle);
vec->y = mult * mCos(angle);
}
//----------------------------------------------------------------------------
void BitStream::clearCompressionPoint()
{
mCompressRelative = false;
}
void BitStream::setCompressionPoint(const Point3F& p)
{
mCompressRelative = true;
mCompressPoint = p;
}
static U32 gBitCounts[4] = {
16, 18, 20, 32
};
void BitStream::writeCompressedPoint(const Point3F& p,F32 scale)
{
// Same # of bits for all axis
Point3F vec;
F32 invScale = 1 / scale;
U32 type;
if(mCompressRelative)
{
vec = p - mCompressPoint;
F32 dist = vec.len() * invScale;
if(dist < (1 << 15))
type = 0;
else if(dist < (1 << 17))
type = 1;
else if(dist < (1 << 19))
type = 2;
else
type = 3;
}
else
type = 3;
writeInt(type, 2);
if (type != 3)
{
type = gBitCounts[type];
writeSignedInt(S32(vec.x * invScale),type);
writeSignedInt(S32(vec.y * invScale),type);
writeSignedInt(S32(vec.z * invScale),type);
}
else
{
write(p.x);
write(p.y);
write(p.z);
}
}
void BitStream::readCompressedPoint(Point3F* p,F32 scale)
{
// Same # of bits for all axis
U32 type = readInt(2);
if(type == 3)
{
read(&p->x);
read(&p->y);
read(&p->z);
}
else
{
type = gBitCounts[type];
p->x = (F32)readSignedInt(type);
p->y = (F32)readSignedInt(type);
p->z = (F32)readSignedInt(type);
p->x = mCompressPoint.x + p->x * scale;
p->y = mCompressPoint.y + p->y * scale;
p->z = mCompressPoint.z + p->z * scale;
}
}
//------------------------------------------------------------------------------
void BitStream::readString(char buf[256])
{
if(stringBuffer)
{
if(readFlag())
{
if (error)
return;
S32 offset = readInt(8);
//printf("offset %i\n", offset);
HuffmanProcessor::g_huffProcessor.readHuffBuffer(this, stringBuffer + offset);
stringBuffer[offset + 255] = '\0';
if (!error) strcpy(buf, stringBuffer);
return;
}
}
HuffmanProcessor::g_huffProcessor.readHuffBuffer(this, buf);
stringBuffer[255] = '\0';
if(stringBuffer && !error)
strcpy(stringBuffer, buf);
}
void BitStream::writeString(const char *string, S32 maxLen)
{
if(!string)
string = "";
if(stringBuffer)
{
S32 j;
for(j = 0; j < maxLen && stringBuffer[j] == string[j] && string[j];j++)
;
strncpy(stringBuffer, string, maxLen);
stringBuffer[maxLen] = 0;
if(writeFlag(j > 2))
{
writeInt(j, 8);
HuffmanProcessor::g_huffProcessor.writeHuffBuffer(this, string + j, maxLen - j);
return;
}
}
HuffmanProcessor::g_huffProcessor.writeHuffBuffer(this, string, maxLen);
}
void HuffmanProcessor::buildTables()
{
AssertFatal(m_tablesBuilt == false, "Cannot build tables twice!");
m_tablesBuilt = true;
S32 i;
// First, construct the array of wraps...
//
m_huffLeaves.resize(256);
m_huffNodes.reserve(256);
m_huffNodes.push_back(HuffNode());
for (i = 0; i < 256; i++) {
HuffLeaf& rLeaf = m_huffLeaves[i];
rLeaf.pop = csm_charFreqs[i] + 1;
rLeaf.symbol = U8(i);
memset(&rLeaf.code, 0, sizeof(rLeaf.code));
rLeaf.numBits = 0;
}
S32 currWraps = 256;
HuffWrap* pWrap = new HuffWrap[256];
for (i = 0; i < 256; i++) {
pWrap[i].set(&m_huffLeaves[i]);
}
while (currWraps != 1) {
U32 min1 = 0xfffffffe, min2 = 0xffffffff;
S32 index1 = -1, index2 = -1;
for (i = 0; i < currWraps; i++) {
if (pWrap[i].getPop() < min1) {
min2 = min1;
index2 = index1;
min1 = pWrap[i].getPop();
index1 = i;
} else if (pWrap[i].getPop() < min2) {
min2 = pWrap[i].getPop();
index2 = i;
}
}
AssertFatal(index1 != -1 && index2 != -1 && index1 != index2, "hrph");
// Create a node for this...
m_huffNodes.push_back(HuffNode());
HuffNode& rNode = m_huffNodes.back();
rNode.pop = pWrap[index1].getPop() + pWrap[index2].getPop();
rNode.index0 = determineIndex(pWrap[index1]);
rNode.index1 = determineIndex(pWrap[index2]);
S32 mergeIndex = index1 > index2 ? index2 : index1;
S32 nukeIndex = index1 > index2 ? index1 : index2;
pWrap[mergeIndex].set(&rNode);
if (index2 != (currWraps - 1)) {
pWrap[nukeIndex] = pWrap[currWraps - 1];
}
currWraps--;
}
AssertFatal(currWraps == 1, "wrong wraps?");
AssertFatal(pWrap[0].pNode != NULL && pWrap[0].pLeaf == NULL, "Wrong wrap type!");
// Ok, now we have one wrap, which is a node. we need to make sure that this
// is the first node in the node list.
m_huffNodes[0] = *(pWrap[0].pNode);
delete [] pWrap;
U32 code = 0;
BitStream bs(&code, 4);
generateCodes(bs, 0, 0);
}
void HuffmanProcessor::generateCodes(BitStream& rBS, S32 index, S32 depth)
{
if (index < 0) {
// leaf node, copy the code in, and back out...
HuffLeaf& rLeaf = m_huffLeaves[-(index + 1)];
memcpy(&rLeaf.code, rBS.dataPtr, sizeof(rLeaf.code));
rLeaf.numBits = depth;
} else {
HuffNode& rNode = m_huffNodes[index];
S32 pos = rBS.getCurPos();
rBS.writeFlag(false);
generateCodes(rBS, rNode.index0, depth + 1);
rBS.setCurPos(pos);
rBS.writeFlag(true);
generateCodes(rBS, rNode.index1, depth + 1);
rBS.setCurPos(pos);
}
}
S16 HuffmanProcessor::determineIndex(HuffWrap& rWrap)
{
if (rWrap.pLeaf != NULL) {
AssertFatal(rWrap.pNode == NULL, "Got a non-NULL pNode in a HuffWrap with a non-NULL leaf.");
return -((rWrap.pLeaf - m_huffLeaves.data()) + 1);
} else {
AssertFatal(rWrap.pNode != NULL, "Got a NULL pNode in a HuffWrap with a NULL leaf.");
return rWrap.pNode - m_huffNodes.data();
}
}
bool HuffmanProcessor::readHuffBuffer(BitStream* pStream, char* out_pBuffer)
{
if (m_tablesBuilt == false)
buildTables();
if (pStream->readFlag()) {
if (pStream->error)
return false;
S32 len = pStream->readInt(8);
for (S32 i = 0; i < len; i++) {
if (pStream->error)
return false;
S32 index = 0;
while (true) {
if (index >= 0) {
if (pStream->readFlag() == true) {
index = m_huffNodes[index].index1;
} else {
index = m_huffNodes[index].index0;
}
} else {
out_pBuffer[i] = m_huffLeaves[-(index+1)].symbol;
break;
}
}
}
out_pBuffer[len] = '\0';
return true;
} else {
// Uncompressed string...
U32 len = pStream->readInt(8);
if (pStream->error)
return false;
pStream->read(len, out_pBuffer);
out_pBuffer[len] = '\0';
return true;
}
}
bool HuffmanProcessor::writeHuffBuffer(BitStream* pStream, const char* out_pBuffer, S32 maxLen)
{
if (out_pBuffer == NULL) {
pStream->writeFlag(false);
pStream->writeInt(0, 8);
return true;
}
if (m_tablesBuilt == false)
buildTables();
S32 len = out_pBuffer ? strlen(out_pBuffer) : 0;
//AssertWarn(len <= 255, "String TOO long for writeString");
//AssertWarn(len <= 255, out_pBuffer);
if (len > maxLen)
len = maxLen;
S32 numBits = 0;
S32 i;
for (i = 0; i < len; i++)
numBits += m_huffLeaves[(unsigned char)out_pBuffer[i]].numBits;
if (numBits >= (len * 8)) {
pStream->writeFlag(false);
pStream->writeInt(len, 8);
pStream->write(len, out_pBuffer);
} else {
pStream->writeFlag(true);
pStream->writeInt(len, 8);
for (i = 0; i < len; i++) {
HuffLeaf& rLeaf = m_huffLeaves[((unsigned char)out_pBuffer[i])];
pStream->writeBits(rLeaf.numBits, &rLeaf.code);
}
}
return true;
}
const U32 HuffmanProcessor::csm_charFreqs[256] = {
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
329 ,
21 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
2809 ,
68 ,
0 ,
27 ,
0 ,
58 ,
3 ,
62 ,
4 ,
7 ,
0 ,
0 ,
15 ,
65 ,
554 ,
3 ,
394 ,
404 ,
189 ,
117 ,
30 ,
51 ,
27 ,
15 ,
34 ,
32 ,
80 ,
1 ,
142 ,
3 ,
142 ,
39 ,
0 ,
144 ,
125 ,
44 ,
122 ,
275 ,
70 ,
135 ,
61 ,
127 ,
8 ,
12 ,
113 ,
246 ,
122 ,
36 ,
185 ,
1 ,
149 ,
309 ,
335 ,
12 ,
11 ,
14 ,
54 ,
151 ,
0 ,
0 ,
2 ,
0 ,
0 ,
211 ,
0 ,
2090 ,
344 ,
736 ,
993 ,
2872 ,
701 ,
605 ,
646 ,
1552 ,
328 ,
305 ,
1240 ,
735 ,
1533 ,
1713 ,
562 ,
3 ,
1775 ,
1149 ,
1469 ,
979 ,
407 ,
553 ,
59 ,
279 ,
31 ,
0 ,
0 ,
0 ,
68 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0 ,
0
};
struct OVNetAddress {
int type; ///< Type of address (IPAddress currently)
/// Acceptable NetAddress types.
enum {
IPAddress,
IPXAddress
};
U8 netNum[4]; ///< For IP: sin_addr<br>
/// For IPX: sa_netnum
U16 port; ///< For IP: sin_port<br>
/// For IPX: sa_socket
};
#include <iostream> // std::cin, std::cout
#include <fstream> // std::filebuf
const char* packetNames[] = {
"Data",
"Ping",
"Ack"
};
enum PacketTypes
{
DataPacket,
PingPacket,
AckPacket,
InvalidPacketType,
};
typedef bool (*fpReadUpdatePacketType)(BitStream&);
struct PacketReadClass
{
U32 index;
U32 typeID;
const char* name;
fpReadUpdatePacketType readFunc;
};
bool doReadGeneralTransmitField(BitStream &s)
{
char buf1[256];
char buf2[256];
U32 num = 0;
int num2 = 0;
s.readString(buf1);
num = s.readRangedU32(0, 0x9fff);
printf("STR=%s, int=%u int2=%i\n", buf1, num, num2);
return true;
}
bool doReadClientTransmitPersistField(BitStream &s)
{
char buf1[256];
char buf2[256];
buf1[0] = '\0';
buf2[0] = '\0';
U32 num = 0;
int num2 = 0;
s.readString(buf1);
num = s.readRangedU32(0, 0x8000);
s.read(&num2);
printf("STR=%s, int=%u int2=%i\n", buf1, num, num2);
return true;
}
const U32 GhostIdBitSize = 0xf;
const U32 GhostIndexBitSize = 0x4;
bool doReadConnectionMessageEvent(BitStream &s)
{
U32 seq;
U32 msg;
U32 gc;
s.read(&seq);
msg = s.readInt(3);
s.readInt(GhostIdBitSize + 1);
return true;
}
PacketReadClass sReadClasses[] = {
13, NetClassTypeEvent, "GeneralTransmitField", &doReadGeneralTransmitField,
7, NetClassTypeEvent, "ClientTransmitPersistField", &doReadClientTransmitPersistField,
6, NetClassTypeObject, "ClientEditAIPlayerObject", NULL,
26, NetClassTypeEvent, "UpdateClientAIPlayerPersistField", NULL,
52, NetClassTypeObject, "MountablePlayer", NULL,
21, NetClassTypeDataBlock, "MountablePlayerData", NULL,
18, NetClassTypeObject, "ClientEditLightning", NULL,
38, NetClassTypeObject, "GameScriptObject", NULL,
12, NetClassTypeObject, "ClientEditGameScriptObject", NULL,
27, NetClassTypeEvent, "UpdateClientGameScriptPersistField", NULL,
39, NetClassTypeObject, "GiftItem", NULL,
28, NetClassTypeDataBlock, "PowerupData", NULL,
5, NetClassTypeObject, "CameraBlocker", NULL,
59, NetClassTypeObject, "PlayerBlocker", NULL,
31, NetClassTypeObject, "ClientEditVehicleBlocker", NULL,
9, NetClassTypeObject, "ClientEditCameraBlocker", NULL,
20, NetClassTypeObject, "ClientEditPlayerBlocker", NULL,
8, NetClassTypeObject, "ClientEditCamera", NULL,
22, NetClassTypeObject, "ClientEditPrecipitation", NULL,
40, NetClassTypeObject, "GuidedProjectile", NULL,
73, NetClassTypeObject, "ShoulderPet", NULL,
35, NetClassTypeObject, "ShoulderPetData", NULL,
0, NetClassTypeObject, "AIPet", NULL,
0, NetClassTypeDataBlock, "AIPetData", NULL,
36, NetClassTypeObject, "GameArea", NULL,
11, NetClassTypeObject, "ClientEditGameArea", NULL,
40, NetClassTypeDataBlock, "ToolImageData", NULL,
30, NetClassTypeObject, "ClientEditTrigger", NULL,
79, NetClassTypeObject, "StoreArea", NULL,
69, NetClassTypeObject, "PurchaseWheeledVehicle", NULL,
66, NetClassTypeObject, "PurchaseMountablePlayer", NULL,
67, NetClassTypeObject, "PurchaseShoulderPet", NULL,
63, NetClassTypeObject, "PurchaseAIPet", NULL,
68, NetClassTypeObject, "PurchaseToolObject", NULL,
64, NetClassTypeObject, "PurchaseClothingObject", NULL,
65, NetClassTypeObject, "PurchaseInteractiveObject", NULL,
25, NetClassTypeObject, "ClientEditStoreArea", NULL,
14, NetClassTypeObject, "ClientEditHomePoint", NULL,
13, NetClassTypeObject, "ClientEditHomeArea", NULL,
42, NetClassTypeObject, "HomePoint", NULL,
15, NetClassTypeDataBlock, "HomePointData", NULL,
41, NetClassTypeObject, "HomeArea", NULL,
28, NetClassTypeEvent, "UpdateClientInteractivePersistField", NULL,
15, NetClassTypeObject, "ClientEditInteractiveObject", NULL,
7, NetClassTypeObject, "ClientEditInteractiveObjectData", NULL,
44, NetClassTypeObject, "InteractiveObject", NULL,
17, NetClassTypeDataBlock, "InteractiveObjectData", NULL,
29, NetClassTypeEvent, "UpdatePersistField", NULL,
27, NetClassTypeObject, "ClientEditSunLight", NULL,
19, NetClassTypeObject, "ClientEditParticleEmitterNode", NULL,
17, NetClassTypeObject, "ClientEditLightObject", NULL,
7, NetClassTypeObject, "ClientEditAudioEmitter", NULL,
60, NetClassTypeObject, "PoiPoint", NULL,
21, NetClassTypeObject, "ClientEditPoiPoint", NULL,
29, NetClassTypeObject, "ClientEditTerrainBlock", NULL,
3, NetClassTypeEvent, "ClientTerrainAckStart", NULL,
5, NetClassTypeEvent, "ClientTerrainFilesChanged", NULL,
6, NetClassTypeEvent, "ClientTerrainTransactionData", NULL,
4, NetClassTypeEvent, "ClientTerrainBeginTransaction", NULL,
8, NetClassTypeDataBlock, "ClothingData", NULL,
2, NetClassTypeEvent, "ClientObjectTransformChanged", NULL,
32, NetClassTypeObject, "ClientEditWaterBlock", NULL,
28, NetClassTypeObject, "ClientEditTSStatic", NULL,
26, NetClassTypeObject, "ClientEditSun", NULL,
24, NetClassTypeObject, "ClientEditSky", NULL,
23, NetClassTypeObject, "ClientEditShapeReplicator", NULL,
16, NetClassTypeObject, "ClientEditInteriorInstance", NULL,
10, NetClassTypeObject, "ClientEditFoliageReplicator", NULL,
91, NetClassTypeObject, "fxRenderObject", NULL,
99, NetClassTypeObject, "volumeLight", NULL,
97, NetClassTypeObject, "sgMissionLightingFilter", NULL,
48, NetClassTypeDataBlock, "sgMissionLightingFilterData", NULL,
98, NetClassTypeObject, "sgUniversalStaticLight", NULL,
49, NetClassTypeDataBlock, "sgUniversalStaticLightData", NULL,
96, NetClassTypeObject, "sgLightObject", NULL,
47, NetClassTypeDataBlock, "sgLightObjectData", NULL,
95, NetClassTypeObject, "sgDecalProjector", NULL,
53, NetClassTypeObject, "ParticleEmitter", NULL,
22, NetClassTypeDataBlock, "ParticleData", NULL,
23, NetClassTypeDataBlock, "ParticleEmitterData", NULL,
70, NetClassTypeObject, "RigidShape", NULL,
31, NetClassTypeDataBlock, "RigidShapeData", NULL,
39, NetClassTypeDataBlock, "TSShapeConstructor", NULL,
85, NetClassTypeObject, "WaterBlock", NULL,
82, NetClassTypeObject, "TerrainBlock", NULL,
80, NetClassTypeObject, "Sun", NULL,
75, NetClassTypeObject, "Sky", NULL,
49, NetClassTypeObject, "Marker", NULL,
17, NetClassTypeEvent, "PathManagerEvent", NULL,
14, NetClassTypeEvent, "GhostAlwaysObjectEvent", NULL,
11, NetClassTypeEvent, "FileNoneExistEvent", NULL,
19, NetClassTypeEvent, "RequestResendFileChunkEvent", NULL,
0, NetClassTypeEvent, "AckFileChunkEvent", NULL,
9, NetClassTypeEvent, "FileChunkEvent", NULL,
10, NetClassTypeEvent, "FileDownloadRequestEvent", NULL,
12, NetClassTypeEvent, "FileVerifyCheckSum", NULL,
8, NetClassTypeEvent, "ConnectionMessageEvent", &doReadConnectionMessageEvent,
10, NetClassTypeDataBlock, "DecalData", NULL,
16, NetClassTypeEvent, "NetStringEvent", NULL,
26, NetClassTypeDataBlock,"PathedInteriorData", NULL,
56, NetClassTypeDataBlock,"PathedInterior", NULL,
46, NetClassTypeObject, "InteriorMap", NULL,
45, NetClassTypeObject, "InteriorInstance", NULL,
88, NetClassTypeObject, "WheeledVehicle", NULL,
43, NetClassTypeDataBlock, "WheeledVehicleData", NULL,
44, NetClassTypeDataBlock, "WheeledVehicleSpring", NULL,
45, NetClassTypeDataBlock, "WheeledVehicleTire", NULL,
84, NetClassTypeObject, "VehicleBlocker", NULL,
43, NetClassTypeObject, "HoverVehicle", NULL,
16, NetClassTypeDataBlock,"HoverVehicleData", NULL,
35, NetClassTypeObject, "FlyingVehicle", NULL,
13, NetClassTypeDataBlock,"FlyingVehicleData", NULL,
81, NetClassTypeObject, "TSStatic", NULL,
83, NetClassTypeObject, "Trigger", NULL,
41, NetClassTypeDataBlock,"TriggerData", NULL,
78, NetClassTypeObject, "StaticShape", NULL,
38, NetClassTypeDataBlock, "StaticShapeData", NULL,
34, NetClassTypeDataBlock, "ShapeBaseImageData", NULL,
72, NetClassTypeObject, "ShapeBase", NULL,
33, NetClassTypeDataBlock, "ShapeBaseData", NULL,
71, NetClassTypeObject, "ScopeAlwaysShape", NULL,
32, NetClassTypeDataBlock, "ScopeAlwaysShapeData", NULL,
62, NetClassTypeObject, "Projectile", NULL,
30, NetClassTypeDataBlock, "ProjectileData", NULL,
58, NetClassTypeObject, "Player", NULL,
27, NetClassTypeDataBlock, "PlayerData", NULL,
57, NetClassTypeObject, "PhysicalZone", NULL,
55, NetClassTypeObject, "PathCamera", NULL,
25, NetClassTypeDataBlock, "PathCameraData", NULL,
74, NetClassTypeObject, "SimpleNetObject", NULL,
25, NetClassTypeEvent, "SimpleMessageEvent", NULL,
18, NetClassTypeEvent, "RemoteCommandEvent", NULL,
76, NetClassTypeObject, "SpawnSphere", NULL,
86, NetClassTypeObject, "WayPoint", NULL,
51, NetClassTypeObject, "MissionMarker", NULL,
20, NetClassTypeDataBlock, "MissionMarkerData", NULL,
50, NetClassTypeObject, "MissionArea", NULL,
47, NetClassTypeObject, "Item", NULL,
18, NetClassTypeDataBlock, "ItemData", NULL,
1, NetClassTypeEvent, "ClientFurnitureTransformChanged", NULL,
20, NetClassTypeEvent, "SetMissionCRCEvent", NULL,
22, NetClassTypeEvent, "Sim3DAudioEvent", NULL,
21, NetClassTypeEvent, "Sim2DAudioEvent", NULL,
23, NetClassTypeEvent, "SimDataBlockAckEvent", NULL,
24, NetClassTypeEvent, "SimDataBlockEvent", NULL,
37, NetClassTypeObject, "GameBase", NULL,
14, NetClassTypeDataBlock, "GameBaseData", NULL,
87, NetClassTypeObject, "WeatherLightning", NULL,
42, NetClassTypeDataBlock, "WeatherLightningData", NULL,
30, NetClassTypeEvent, "WeatherLightningStrikeEvent", NULL,
77, NetClassTypeObject, "Splash", NULL,
37, NetClassTypeDataBlock, "SplashData", NULL,
29, NetClassTypeDataBlock, "PrecipitationData", NULL,
61, NetClassTypeObject, "Precipitation", NULL,
54, NetClassTypeObject, "ParticleEmitterNode", NULL,
24, NetClassTypeDataBlock, "ParticleEmitterNodeData", NULL,
15, NetClassTypeEvent, "LightningStrikeEvent", NULL,
48, NetClassTypeObject, "Lightning", NULL,
19, NetClassTypeDataBlock, "LightningData", NULL,
94, NetClassTypeObject, "fxSunLight", NULL,
92, NetClassTypeObject, "fxShapeReplicatedStatic", NULL,
93, NetClassTypeObject, "fxShapeReplicator", NULL,
90, NetClassTypeObject, "fxLight", NULL,
46, NetClassTypeDataBlock, "fxLightData", NULL,
89, NetClassTypeObject, "fxFoliageReplicator", NULL,
11, NetClassTypeDataBlock, "ExplosionData", NULL,
12, NetClassTypeDataBlock, "FireballAtmosphereData", NULL,
34, NetClassTypeObject, "FireballAtmosphere", NULL,
33, NetClassTypeObject, "Debris", NULL,
9, NetClassTypeDataBlock, "DebrisData", NULL,
4, NetClassTypeObject, "Camera", NULL,
6, NetClassTypeDataBlock, "CameraData", NULL,
3, NetClassTypeObject, "AudioEmitter", NULL,
2, NetClassTypeObject, "AIWheeledVehicle", NULL,
1, NetClassTypeObject, "AIPlayer", NULL,
1, NetClassTypeDataBlock, "AIPlayerData", NULL,
36, NetClassTypeDataBlock, "SimDataBlock", NULL,
4, NetClassTypeDataBlock, "AudioProfile", NULL,
2, NetClassTypeDataBlock, "AudioDescription", NULL,
5, NetClassTypeDataBlock, "AudioSampleEnvironment", NULL,
3, NetClassTypeDataBlock, "AudioEnvironment", NULL
};
PacketReadClass* findClassInfo(U32 idx, U32 typeID)
{
for (int i=0; i<sizeof(sReadClasses) / sizeof(sReadClasses[0]); i++)
{
if (sReadClasses[i].index == idx && sReadClasses[i].typeID == typeID)
return sReadClasses + i;
}
return NULL;
}
bool eventReadPacket(BitStream &s)
{
S32 prevSeq = -2;
bool unguaranteedPhase = true;
while (1)
{
bool bit = s.readFlag();
if(unguaranteedPhase && !bit)
{
unguaranteedPhase = false;
printf("NOW READING GUARANTEED EVENTS\n");
bit = s.readFlag();
}
if(!unguaranteedPhase && !bit)
{
printf("END READ EVENT\n");
break;
}
printf("Reading event...\n");
S32 seq = -1;
if(!unguaranteedPhase) // get the sequence
{
if(s.readFlag())
seq = (prevSeq + 1) & 0x7f;
else
seq = s.readInt(7);
prevSeq = seq;
}
S32 classId = s.readClassId(NetClassTypeEvent, NetClassGroupGame);
if(classId == -1)
{
printf("Invalid event packet.\n");
return false;
}
PacketReadClass *info = findClassInfo(classId, NetClassTypeEvent);
if(!info)
{
printf("Invalid packet classID=%u.\n", classId);
return false;
}
if (!info->readFunc)
{
printf("TODO: %s\n", info->name);
return false;
}
if (!info->readFunc(s))
{
printf("Packet read error class=%u\n", classId);
return false;
}
}
return true;
}
bool ghostReadPacket(BitStream &s)
{
//char stringBuf[256*10];
//stringBuf[0] = 0;
//s.setStringBuffer(stringBuf);
bool hasEvent = s.readFlag();
if (hasEvent)
{
S32 idSize = s.readInt(GhostIndexBitSize);
printf("Has ghosts, idSize=%i\n", idSize);
while (s.readFlag())
{
S32 idx = s.readInt(idSize);
printf("Ghost %i update\n", idx);
S32 bitPos = s.getCurPos();
U32 count = 0;
while (s.getReadByteSize() != 0)
{
s.error = false;
s.setCurPos(bitPos + count);
//s.setStringBuffer(stringBuf);
char str[256*10];
memset(str, '\0', sizeof(str));
//memset(stringBuf, '\0', sizeof(stringBuf));
str[0] = '\0';
s.readString(str);
//if (str[0] == '~' && str[1] == '/')
if (strlen(str) != 0)
{
printf("STRING %s\n", str);
}
count++;
}
if (s.readFlag())
{
printf("^^ BEING DELETED\n");
}
else
{
printf("TODO: see if this is a new object?\n");
}
return false;
}
}
return true;
}
int main(int argc, char **argv)
{
std::filebuf fb;
char buffer[1024*1024];
uint32_t sz = 0;
U32 lastSequenceNumber = 0xFFFFFF;
memset(__NetClassBitSize, '\0', sizeof(__NetClassBitSize));
__NetClassBitSize[NetClassGroupGame][NetClassTypeObject] = 7;
__NetClassBitSize[NetClassGroupGame][NetClassTypeDataBlock] = 6;
__NetClassBitSize[NetClassGroupGame][NetClassTypeEvent] = 5;
for (int i=1; i<argc; i++)
{
printf("%s ", argv[i]);
}
printf("\n");
for (int i=1; i<argc; i++)
{
printf("Open %s\n", argv[i]);
if (fb.open (argv[i], std::ios::in))
{
std::istream is(&fb);
is.seekg (0, is.end);
sz = is.tellg();
is.seekg (0, is.beg);
is.read(&buffer[0], sz);
fb.close();
}
printf("Now for bitstream (%u)...\n", sz);
BitStream s(&buffer[0], sz);
printf("BITSIZE = %u\n", s.getReadByteSize());
{
if (!s.readFlag()) // get rid of the game info packet bit
{
printf("NON-PROTOCOL PACKET\n");
continue;
}
U32 pkConnectSeqBit = s.readInt(1);
U32 pkSequenceNumber = s.readInt(9);
U32 pkHighestAck = s.readInt(9);
U32 pkPacketType = s.readInt(2);
S32 pkAckByteCount = s.readInt(3);
const char* packetName = pkPacketType < InvalidPacketType ? packetNames[pkPacketType] : "INVALID";
printf("SEQB %u SEQN %u HACK %u PT %s BC %u\n", pkConnectSeqBit, pkSequenceNumber, pkHighestAck, packetName, pkAckByteCount);
U32 ackMask = s.readInt(pkAckByteCount*8);
if (pkPacketType == PingPacket)
{
continue;
}
else if (pkPacketType == DataPacket)
{
if (lastSequenceNumber == 0xFFFFFF)
{
lastSequenceNumber = pkSequenceNumber;
}
else if (lastSequenceNumber != pkSequenceNumber)
{
printf("Sequence changed...\n");
if (s.readFlag())
{
printf("Rate changed\n");
U32 curDelay = s.readInt(10);
U32 packetSize = s.readInt(10);
}
if (s.readFlag())
{
printf("max changed\n");
U32 omaxDelay = s.readInt(10);
S32 omaxSize = s.readInt(10);
}
// GameConnection::readPacket comes first
char stringBuf[256];
stringBuf[0] = 0;
s.setStringBuffer(stringBuf);
s.clearCompressionPoint();
U32 lastMoveAck = s.readInt(32);
printf("lastMoveAck %u\n", lastMoveAck);
if (s.readFlag())
{
if (s.readFlag())
{
F32 flash = s.readFloat(7);
}
if (s.readFlag())
{
F32 whiteOut = s.readFloat(7) * 1.5;
}
printf("Flash/whiteout change\n");
}
else
{
printf("no flash or whiteout\n");
}
if (s.readFlag())
{
if (s.readFlag()) // control object dirty
{
S32 gIdx = s.readInt(GhostIdBitSize);
printf("CONTROL OBJECT CHANGED TO %i, NEED TO READ PACKET\n", gIdx);
// TODO: read packet
continue;
}
else
{
Point3F pos;
s.read(&pos.x);
s.read(&pos.y);
s.read(&pos.z);
s.setCompressionPoint(pos);
printf("Compression point %f,%f,%f\n", pos.x, pos.y, pos.z);
}
}
else
{
printf("no control changes\n");
}
if (s.readFlag())
{
S32 gIdx = s.readInt(GhostIdBitSize);
printf("CAMERA OBJECT CHANGED TO %i, NEED TO READ PACKET\n", gIdx);
// TODO: read packet
continue;
}
else
{
printf("no camera changes\n");
}
if (s.readFlag())
{
bool flag = s.readFlag();
printf("Toggled first person to %s", flag ? "true" : "false");
}
else
{
printf("no FP changes\n");
}
if (s.readFlag())
{
S32 fov = s.readInt(8);
printf("FOV change to %i", fov);
}
else
{
printf("no FOV changes\n");
}
printf("--\n");
if (!eventReadPacket(s))
{
s.clearCompressionPoint();
continue;
}
if (!ghostReadPacket(s))
{
s.clearCompressionPoint();
continue;
}
}
}
else
{
printf("WTF\n");
break;
}
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment