parent
2e30160056
commit
d642db574b
419 changed files with 75576 additions and 0 deletions
@ -0,0 +1,9 @@ |
||||
*.db |
||||
.vs/ |
||||
x64/ |
||||
x64_v142/ |
||||
common/x64_v142/ |
||||
fs/x64/ |
||||
skse64/.vs/ |
||||
skse64/skse64/x64/ |
||||
skse64/skse64_common/x64/ |
@ -0,0 +1,102 @@ |
||||
#include "IArchive.h" |
||||
#include "IErrors.h" |
||||
|
||||
#if ENABLE_IDYNAMICCREATE |
||||
|
||||
IDynamic * IArchive::iterator::Instantiate(void) |
||||
{ |
||||
IDataSubStream subStream(owner->theStream, GetDataOffset(), GetDataLength()); |
||||
|
||||
return IClassRegistry::Instantiate(GetTypeID(), &subStream); |
||||
} |
||||
|
||||
void * IArchive::iterator::GetBuffer(UInt32 * outLength) |
||||
{ |
||||
HeaderEntry * entry = GetData(); |
||||
UInt8 * buf = new UInt8[entry->dataLength]; |
||||
|
||||
owner->theStream->SetOffset(entry->dataOffset); |
||||
owner->theStream->ReadBuf(buf, entry->dataLength); |
||||
|
||||
if(outLength) |
||||
*outLength = entry->dataLength; |
||||
|
||||
return buf; |
||||
} |
||||
|
||||
void IArchive::iterator::NextOfType(UInt32 typeID) |
||||
{ |
||||
idx++; |
||||
|
||||
while((GetData()->typeID != typeID) && (idx < owner->header.numEntries)) |
||||
idx++; |
||||
} |
||||
|
||||
void IArchive::iterator::PrevOfType(UInt32 typeID) |
||||
{ |
||||
idx--; |
||||
|
||||
while((GetData()->typeID != typeID) && (idx > 0)) |
||||
idx--; |
||||
} |
||||
|
||||
IArchive::IArchive() |
||||
:theStream(NULL), entries(NULL), nameTable(NULL) |
||||
{ |
||||
|
||||
} |
||||
|
||||
IArchive::IArchive(IDataStream * stream) |
||||
:theStream(NULL), entries(NULL), nameTable(NULL) |
||||
{ |
||||
AttachStream(stream); |
||||
} |
||||
|
||||
IArchive::~IArchive() |
||||
{ |
||||
Dispose(); |
||||
} |
||||
|
||||
void IArchive::AttachStream(IDataStream * inStream) |
||||
{ |
||||
Dispose(); |
||||
|
||||
theStream = inStream; |
||||
} |
||||
|
||||
void IArchive::Dispose(void) |
||||
{ |
||||
if(entries) |
||||
{ |
||||
delete entries; |
||||
entries = NULL; |
||||
} |
||||
|
||||
if(nameTable) |
||||
{ |
||||
delete nameTable; |
||||
nameTable = NULL; |
||||
} |
||||
} |
||||
|
||||
void IArchive::ReadHeader(void) |
||||
{ |
||||
ASSERT(theStream); |
||||
|
||||
theStream->Rewind(); |
||||
|
||||
theStream->ReadBuf(&header, sizeof(FileHeader)); |
||||
|
||||
entries = new HeaderEntry[header.numEntries]; |
||||
theStream->ReadBuf(entries, header.numEntries * sizeof(HeaderEntry)); |
||||
|
||||
if(header.nameTableLength) |
||||
{ |
||||
nameTable = new char[header.nameTableLength]; |
||||
|
||||
theStream->SetOffset(header.nameTableOffset); |
||||
theStream->ReadBuf(nameTable, header.nameTableLength); |
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,95 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IDataStream.h" |
||||
#include "common/IDynamicCreate.h" |
||||
|
||||
#if ENABLE_IDYNAMICCREATE |
||||
|
||||
/**
|
||||
* An object archive |
||||
*
|
||||
* This class implements reading and instantiating objects from an object archive. |
||||
*/ |
||||
class IArchive |
||||
{ |
||||
public: |
||||
class iterator; |
||||
friend iterator; |
||||
|
||||
IArchive(); |
||||
IArchive(IDataStream * inStream); |
||||
~IArchive(); |
||||
|
||||
void AttachStream(IDataStream * inStream); |
||||
void Dispose(void); |
||||
|
||||
iterator begin(void) { return iterator(0, this); } |
||||
iterator end(void) { return iterator(header.numEntries, this); } |
||||
|
||||
static const UInt32 kFileID = CHAR_CODE(0x00, 'A', 'R', 0x01); |
||||
static const UInt32 kCurrentVersion = VERSION_CODE(1, 0, 0); |
||||
|
||||
private: |
||||
struct FileHeader |
||||
{ |
||||
UInt32 fileID; // IArchive::kFileID
|
||||
UInt32 version; // IArchive::kCurrentVersion
|
||||
UInt32 numEntries; |
||||
UInt32 nameTableOffset; |
||||
UInt32 nameTableLength; |
||||
}; |
||||
|
||||
struct HeaderEntry |
||||
{ |
||||
UInt32 typeID; |
||||
UInt32 subID; |
||||
UInt32 dataOffset; |
||||
UInt32 dataLength; |
||||
UInt32 nameOffset; |
||||
}; |
||||
|
||||
void ReadHeader(void); |
||||
|
||||
IDataStream * theStream; |
||||
|
||||
FileHeader header; |
||||
HeaderEntry * entries; |
||||
|
||||
char * nameTable; |
||||
|
||||
public: |
||||
class iterator |
||||
{ |
||||
public: |
||||
iterator() { idx = 0; owner = NULL; } |
||||
iterator(UInt32 inIdx, IArchive * inArchive) { idx = inIdx; owner = inArchive; } |
||||
~iterator() { } |
||||
|
||||
IDynamic * Instantiate(void); |
||||
|
||||
UInt32 GetTypeID(void) { return GetData()->typeID; } |
||||
UInt32 GetSubID(void) { return GetData()->subID; } |
||||
UInt32 GetDataLength(void) { return GetData()->dataLength; } |
||||
char * GetName(void) { return &owner->nameTable[GetData()->nameOffset]; } |
||||
void * GetBuffer(UInt32 * outLength); |
||||
|
||||
iterator & operator++() { Next(); return *this; } |
||||
iterator & operator--() { Prev(); return *this; } |
||||
|
||||
void NextOfType(UInt32 typeID); |
||||
void Next(void) { idx++; } |
||||
|
||||
void PrevOfType(UInt32 typeID); |
||||
void Prev(void) { idx--; } |
||||
|
||||
private: |
||||
HeaderEntry * GetData(void) { return &owner->entries[idx]; } |
||||
|
||||
UInt32 GetDataOffset(void) { return GetData()->dataOffset; } |
||||
|
||||
UInt32 idx; |
||||
IArchive * owner; |
||||
}; |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,58 @@ |
||||
#include "IBufferStream.h" |
||||
|
||||
IBufferStream::IBufferStream() |
||||
:streamBuf(NULL), flags(0) |
||||
{ |
||||
|
||||
} |
||||
|
||||
IBufferStream::IBufferStream(const IBufferStream & rhs) |
||||
{ |
||||
// explicitly not supporting copy constructor for self-owned buffers
|
||||
ASSERT((flags & kFlag_OwnedBuf) == 0); |
||||
} |
||||
|
||||
IBufferStream::IBufferStream(void * buf, UInt64 inLength) |
||||
:streamBuf(NULL), flags(0) |
||||
{ |
||||
SetBuffer(buf, inLength); |
||||
} |
||||
|
||||
IBufferStream::~IBufferStream() |
||||
{ |
||||
if(flags & kFlag_OwnedBuf) |
||||
{ |
||||
delete [] streamBuf; |
||||
} |
||||
} |
||||
|
||||
IBufferStream & IBufferStream::operator=(IBufferStream & rhs) |
||||
{ |
||||
// explicitly not supporting copying for self-owned buffers
|
||||
ASSERT((flags & kFlag_OwnedBuf) == 0); |
||||
|
||||
streamBuf = rhs.streamBuf; |
||||
flags = rhs.flags; |
||||
|
||||
return *this; |
||||
} |
||||
|
||||
void IBufferStream::SetBuffer(void * buf, UInt64 inLength) |
||||
{ |
||||
streamBuf = (UInt8 *)buf; |
||||
streamLength = inLength; |
||||
|
||||
Rewind(); |
||||
} |
||||
|
||||
void IBufferStream::ReadBuf(void * buf, UInt32 inLength) |
||||
{ |
||||
memcpy(buf, &streamBuf[streamOffset], inLength); |
||||
streamOffset += inLength; |
||||
} |
||||
|
||||
void IBufferStream::WriteBuf(const void * buf, UInt32 inLength) |
||||
{ |
||||
memcpy(&streamBuf[streamOffset], buf, inLength); |
||||
streamOffset += inLength; |
||||
} |
@ -0,0 +1,35 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IDataStream.h" |
||||
|
||||
class IBufferStream : public IDataStream |
||||
{ |
||||
public: |
||||
IBufferStream(); |
||||
IBufferStream(const IBufferStream & rhs); |
||||
IBufferStream(void * buf, UInt64 inLength); |
||||
virtual ~IBufferStream(); |
||||
|
||||
IBufferStream & operator=(IBufferStream & rhs); |
||||
|
||||
void SetBuffer(void * buf, UInt64 inLength); |
||||
void * GetBuffer(void) { return streamBuf; } |
||||
|
||||
void OwnBuffer(void) { flags |= kFlag_OwnedBuf; } |
||||
void DisownBuffer(void) { flags &= ~kFlag_OwnedBuf; } |
||||
|
||||
// read
|
||||
virtual void ReadBuf(void * buf, UInt32 inLength); |
||||
|
||||
// write
|
||||
virtual void WriteBuf(const void * buf, UInt32 inLength); |
||||
|
||||
protected: |
||||
UInt8 * streamBuf; |
||||
UInt32 flags; |
||||
|
||||
enum |
||||
{ |
||||
kFlag_OwnedBuf = 1 << 0 |
||||
}; |
||||
}; |
@ -0,0 +1,116 @@ |
||||
#include "common/IConsole.h" |
||||
#include <cstdarg> |
||||
#include <cstring> |
||||
#include <Windows.h> |
||||
|
||||
IConsole::IConsole() |
||||
{ |
||||
AllocConsole(); |
||||
|
||||
SetConsoleTitle("Console"); |
||||
|
||||
inputHandle = GetStdHandle(STD_INPUT_HANDLE); |
||||
outputHandle = GetStdHandle(STD_OUTPUT_HANDLE); |
||||
|
||||
ASSERT_STR(inputHandle, "IConsole: couldn't get input handle"); |
||||
ASSERT_STR(outputHandle, "IConsole: couldn't get output handle"); |
||||
|
||||
SetConsoleMode(inputHandle, ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT); |
||||
SetConsoleMode(outputHandle, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); |
||||
} |
||||
|
||||
IConsole::~IConsole() |
||||
{ |
||||
|
||||
} |
||||
|
||||
/**
|
||||
* Writes a string to the console |
||||
*/ |
||||
void IConsole::Write(char * buf) |
||||
{ |
||||
UInt32 charsWritten; |
||||
|
||||
WriteConsole(outputHandle, buf, std::strlen(buf), &charsWritten, NULL); |
||||
} |
||||
|
||||
/**
|
||||
* Writes a formatted string to the console |
||||
*
|
||||
* You may specify a temp buffer to use for the formatted text, but if NULL |
||||
* is used a local buffer will be provided. |
||||
*
|
||||
* @param buf a temporary buffer, or NULL to use the internal buffer |
||||
* @param fmt the format string |
||||
*/ |
||||
void IConsole::Write(char * buf, UInt32 bufLen, const char * fmt, ...) |
||||
{ |
||||
static char tempBuf[4096]; |
||||
|
||||
if(!buf) |
||||
{ |
||||
buf = tempBuf; |
||||
bufLen = sizeof(tempBuf); |
||||
} |
||||
|
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
vsprintf_s(buf, bufLen, fmt, args); |
||||
va_end(args); |
||||
|
||||
Write(buf); |
||||
} |
||||
|
||||
/**
|
||||
* Reads a single character from the console |
||||
*/ |
||||
char IConsole::ReadChar(void) |
||||
{ |
||||
char data; |
||||
UInt32 charsRead; |
||||
|
||||
ReadConsole(inputHandle, &data, 1, &charsRead, NULL); |
||||
|
||||
return data; |
||||
} |
||||
|
||||
/**
|
||||
* Reads a newline-terminated string from the console |
||||
*
|
||||
* @param buf output buffer |
||||
* @param len buffer size |
||||
* @return number of characters read |
||||
*/ |
||||
UInt32 IConsole::ReadBuf(char * buf, UInt32 len) |
||||
{ |
||||
UInt32 charsRead; |
||||
|
||||
buf[0] = 0; |
||||
|
||||
do |
||||
{ |
||||
ReadConsole(inputHandle, buf, len, &charsRead, NULL); |
||||
} |
||||
while(!charsRead); |
||||
|
||||
int done = 0; |
||||
for(UInt32 i = charsRead - 1; (i > 0) && !done; i--) |
||||
{ |
||||
switch(buf[i]) |
||||
{ |
||||
case 0x0A: |
||||
case 0x0D: |
||||
buf[i] = 0; |
||||
break; |
||||
|
||||
default: |
||||
done = 1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
buf[charsRead] = 0; |
||||
|
||||
return charsRead; |
||||
} |
@ -0,0 +1,26 @@ |
||||
#pragma once |
||||
|
||||
#include "common/ITypes.h" |
||||
#include "common/ISingleton.h" |
||||
#include <Windows.h> |
||||
|
||||
/**
|
||||
* Wrapper class for a standard Windows console |
||||
*
|
||||
* @todo make nonblocking |
||||
*/ |
||||
class IConsole : public ISingleton<IConsole> |
||||
{ |
||||
public: |
||||
IConsole(); |
||||
~IConsole(); |
||||
|
||||
void Write(char * buf); |
||||
void Write(char * buf, UInt32 bufLen, const char * fmt, ...); |
||||
|
||||
char ReadChar(void); |
||||
UInt32 ReadBuf(char * buf, UInt32 len); |
||||
|
||||
private: |
||||
HANDLE inputHandle, outputHandle; |
||||
}; |
@ -0,0 +1,35 @@ |
||||
#pragma once |
||||
|
||||
class ICriticalSection |
||||
{ |
||||
public: |
||||
ICriticalSection() { InitializeCriticalSection(&critSection); } |
||||
~ICriticalSection() { DeleteCriticalSection(&critSection); } |
||||
|
||||
void Enter(void) { EnterCriticalSection(&critSection); } |
||||
void Leave(void) { LeaveCriticalSection(&critSection); } |
||||
bool TryEnter(void) { return TryEnterCriticalSection(&critSection) != 0; } |
||||
|
||||
private: |
||||
CRITICAL_SECTION critSection; |
||||
}; |
||||
|
||||
class IScopedCriticalSection |
||||
{ |
||||
public: |
||||
IScopedCriticalSection(ICriticalSection * cs) |
||||
:m_cs(cs) |
||||
{ |
||||
m_cs->Enter(); |
||||
} |
||||
|
||||
~IScopedCriticalSection() |
||||
{ |
||||
m_cs->Leave(); |
||||
} |
||||
|
||||
private: |
||||
IScopedCriticalSection(); // undefined
|
||||
|
||||
ICriticalSection * m_cs; |
||||
}; |
@ -0,0 +1,472 @@ |
||||
#include "IDataStream.h" |
||||
|
||||
/**** IDataStream *************************************************************/ |
||||
|
||||
IDataStream::IDataStream() |
||||
:streamLength(0), streamOffset(0), swapBytes(false) |
||||
{ |
||||
|
||||
} |
||||
|
||||
IDataStream::~IDataStream() |
||||
{ |
||||
|
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns an 8-bit value from the stream |
||||
*/ |
||||
UInt8 IDataStream::Read8(void) |
||||
{ |
||||
UInt8 out; |
||||
|
||||
ReadBuf(&out, sizeof(UInt8)); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 16-bit value from the stream |
||||
*/ |
||||
UInt16 IDataStream::Read16(void) |
||||
{ |
||||
UInt16 out; |
||||
|
||||
ReadBuf(&out, sizeof(UInt16)); |
||||
|
||||
if(swapBytes) |
||||
out = Swap16(out); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 32-bit value from the stream |
||||
*/ |
||||
UInt32 IDataStream::Read32(void) |
||||
{ |
||||
UInt32 out; |
||||
|
||||
ReadBuf(&out, sizeof(UInt32)); |
||||
|
||||
if(swapBytes) |
||||
out = Swap32(out); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 64-bit value from the stream |
||||
*/ |
||||
UInt64 IDataStream::Read64(void) |
||||
{ |
||||
UInt64 out; |
||||
|
||||
ReadBuf(&out, sizeof(UInt64)); |
||||
|
||||
if(swapBytes) |
||||
out = Swap64(out); |
||||
|
||||
return out; |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 32-bit floating point value from the stream |
||||
*/ |
||||
float IDataStream::ReadFloat(void) |
||||
{ |
||||
UInt32 out = Read32(); |
||||
|
||||
return *((float *)&out); |
||||
} |
||||
|
||||
/**
|
||||
* Reads a null-or-return-terminated string from the stream |
||||
*
|
||||
* If the buffer is too small to hold the entire string, it is truncated and |
||||
* properly terminated. |
||||
*
|
||||
* @param buf the output buffer |
||||
* @param bufLength the size of the output buffer |
||||
* @return the number of characters written to the buffer |
||||
*/ |
||||
UInt32 IDataStream::ReadString(char * buf, UInt32 bufLength, char altTerminator, char altTerminator2) |
||||
{ |
||||
char * traverse = buf; |
||||
bool breakOnReturns = false; |
||||
|
||||
if((altTerminator == '\n') || (altTerminator2 == '\n')) |
||||
breakOnReturns = true; |
||||
|
||||
ASSERT_STR(bufLength > 0, "IDataStream::ReadString: zero-sized buffer"); |
||||
|
||||
if(bufLength == 1) |
||||
{ |
||||
buf[0] = 0; |
||||
return 0; |
||||
} |
||||
|
||||
bufLength--; |
||||
|
||||
for(UInt32 i = 0; i < bufLength; i++) |
||||
{ |
||||
if(HitEOF()) break; |
||||
|
||||
UInt8 data = Read8(); |
||||
|
||||
if(breakOnReturns) |
||||
{ |
||||
if(data == 0x0D) |
||||
{ |
||||
if(Peek8() == 0x0A) |
||||
Skip(1); |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
if(!data || (data == altTerminator) || (data == altTerminator2)) |
||||
{ |
||||
break; |
||||
} |
||||
|
||||
*traverse++ = data; |
||||
} |
||||
|
||||
*traverse++ = 0; |
||||
|
||||
return traverse - buf - 1; |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns an 8-bit value from the stream without advancing the stream's position |
||||
*/ |
||||
UInt8 IDataStream::Peek8(void) |
||||
{ |
||||
IDataStream_PositionSaver saver(this); |
||||
|
||||
return Read8(); |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 16-bit value from the stream without advancing the stream's position |
||||
*/ |
||||
UInt16 IDataStream::Peek16(void) |
||||
{ |
||||
IDataStream_PositionSaver saver(this); |
||||
|
||||
return Read16(); |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 32-bit value from the stream without advancing the stream's position |
||||
*/ |
||||
UInt32 IDataStream::Peek32(void) |
||||
{ |
||||
IDataStream_PositionSaver saver(this); |
||||
|
||||
return Read32(); |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 32-bit value from the stream without advancing the stream's position |
||||
*/ |
||||
UInt64 IDataStream::Peek64(void) |
||||
{ |
||||
IDataStream_PositionSaver saver(this); |
||||
|
||||
return Read64(); |
||||
} |
||||
|
||||
/**
|
||||
* Reads and returns a 32-bit floating point value from the stream without advancing the stream's position |
||||
*/ |
||||
float IDataStream::PeekFloat(void) |
||||
{ |
||||
IDataStream_PositionSaver saver(this); |
||||
|
||||
return ReadFloat(); |
||||
} |
||||
|
||||
/**
|
||||
* Reads raw data into a buffer without advancing the stream's position |
||||
*/ |
||||
void IDataStream::PeekBuf(void * buf, UInt32 inLength) |
||||
{ |
||||
IDataStream_PositionSaver saver(this); |
||||
|
||||
ReadBuf(buf, inLength); |
||||
} |
||||
|
||||
/**
|
||||
* Skips a specified number of bytes down the stream |
||||
*/ |
||||
void IDataStream::Skip(SInt64 inBytes) |
||||
{ |
||||
SetOffset(GetOffset() + inBytes); |
||||
} |
||||
|
||||
/**
|
||||
* Writes an 8-bit value to the stream. |
||||
*/ |
||||
void IDataStream::Write8(UInt8 inData) |
||||
{ |
||||
WriteBuf(&inData, sizeof(UInt8)); |
||||
} |
||||
|
||||
/**
|
||||
* Writes a 16-bit value to the stream. |
||||
*/ |
||||
void IDataStream::Write16(UInt16 inData) |
||||
{ |
||||
if(swapBytes) |
||||
inData = Swap16(inData); |
||||
|
||||
WriteBuf(&inData, sizeof(UInt16)); |
||||
} |
||||
|
||||
/**
|
||||
* Writes a 32-bit value to the stream. |
||||
*/ |
||||
void IDataStream::Write32(UInt32 inData) |
||||
{ |
||||
if(swapBytes) |
||||
inData = Swap32(inData); |
||||
|
||||
WriteBuf(&inData, sizeof(UInt32)); |
||||
} |
||||
|
||||
/**
|
||||
* Writes a 64-bit value to the stream. |
||||
*/ |
||||
void IDataStream::Write64(UInt64 inData) |
||||
{ |
||||
if(swapBytes) |
||||
inData = Swap64(inData); |
||||
|
||||
WriteBuf(&inData, sizeof(UInt64)); |
||||
} |
||||
|
||||
/**
|
||||
* Writes a 32-bit floating point value to the stream. |
||||
*/ |
||||
void IDataStream::WriteFloat(float inData) |
||||
{ |
||||
if(swapBytes) |
||||
{ |
||||
UInt32 temp = *((UInt32 *)&inData); |
||||
|
||||
temp = Swap32(temp); |
||||
|
||||
WriteBuf(&temp, sizeof(UInt32)); |
||||
} |
||||
else |
||||
{ |
||||
WriteBuf(&inData, sizeof(float)); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Writes a null-terminated string to the stream. |
||||
*/ |
||||
void IDataStream::WriteString(const char * buf) |
||||
{ |
||||
WriteBuf(buf, std::strlen(buf) + 1); |
||||
} |
||||
|
||||
/**
|
||||
* Returns the length of the stream |
||||
*/ |
||||
SInt64 IDataStream::GetLength(void) |
||||
{ |
||||
return streamLength; |
||||
} |
||||
|
||||
/**
|
||||
* Returns the number of bytes remaining in the stream |
||||
*/ |
||||
SInt64 IDataStream::GetRemain(void) |
||||
{ |
||||
return streamLength - streamOffset; |
||||
} |
||||
|
||||
/**
|
||||
* Returns the current offset into the stream |
||||
*/ |
||||
SInt64 IDataStream::GetOffset(void) |
||||
{ |
||||
return streamOffset; |
||||
} |
||||
|
||||
/**
|
||||
* Returns whether we have reached the end of the stream or not |
||||
*/ |
||||
bool IDataStream::HitEOF(void) |
||||
{ |
||||
return streamOffset >= streamLength; |
||||
} |
||||
|
||||
/**
|
||||
* Moves the current offset into the stream |
||||
*/ |
||||
void IDataStream::SetOffset(SInt64 inOffset) |
||||
{ |
||||
streamOffset = inOffset; |
||||
} |
||||
|
||||
/**
|
||||
* Enables or disables byte swapping for basic data transfers |
||||
*/ |
||||
void IDataStream::SwapBytes(bool inSwapBytes) |
||||
{ |
||||
swapBytes = inSwapBytes; |
||||
} |
||||
|
||||
IDataStream * IDataStream::GetRootParent(void) |
||||
{ |
||||
IDataStream * parent = GetParent(); |
||||
|
||||
if(parent) |
||||
return parent->GetRootParent(); |
||||
else |
||||
return this; |
||||
} |
||||
|
||||
void IDataStream::CopyStreams(IDataStream * out, IDataStream * in, UInt64 bufferSize, UInt8 * buf) |
||||
{ |
||||
in->Rewind(); |
||||
|
||||
bool ourBuffer = false; |
||||
|
||||
if(!buf) |
||||
{ |
||||
buf = new UInt8[bufferSize]; |
||||
ourBuffer = true; |
||||
} |
||||
|
||||
UInt64 remain = in->GetLength(); |
||||
|
||||
while(remain > 0) |
||||
{ |
||||
UInt64 transferSize = remain; |
||||
|
||||
if(transferSize > bufferSize) |
||||
transferSize = bufferSize; |
||||
|
||||
in->ReadBuf(buf, transferSize); |
||||
out->WriteBuf(buf, transferSize); |
||||
|
||||
remain -= transferSize; |
||||
} |
||||
|
||||
if(ourBuffer) |
||||
delete [] buf; |
||||
} |
||||
|
||||
void IDataStream::CopySubStreams(IDataStream * out, IDataStream * in, UInt64 remain, UInt64 bufferSize, UInt8 * buf) |
||||
{ |
||||
bool ourBuffer = false; |
||||
|
||||
if(!buf) |
||||
{ |
||||
buf = new UInt8[bufferSize]; |
||||
ourBuffer = true; |
||||
} |
||||
|
||||
while(remain > 0) |
||||
{ |
||||
UInt64 transferSize = remain; |
||||
|
||||
if(transferSize > bufferSize) |
||||
transferSize = bufferSize; |
||||
|
||||
in->ReadBuf(buf, transferSize); |
||||
out->WriteBuf(buf, transferSize); |
||||
|
||||
remain -= transferSize; |
||||
} |
||||
|
||||
if(ourBuffer) |
||||
delete [] buf; |
||||
} |
||||
|
||||
/**** IDataStream_PositionSaver ***********************************************/ |
||||
|
||||
/**
|
||||
* The constructor; save the stream's position |
||||
*/ |
||||
IDataStream_PositionSaver::IDataStream_PositionSaver(IDataStream * tgt) |
||||
{ |
||||
stream = tgt; |
||||
offset = tgt->GetOffset(); |
||||
} |
||||
|
||||
/**
|
||||
* The destructor; restore the stream's saved position |
||||
*/ |
||||
IDataStream_PositionSaver::~IDataStream_PositionSaver() |
||||
{ |
||||
stream->SetOffset(offset); |
||||
} |
||||
|
||||
/**** IDataSubStream **********************************************************/ |
||||
|
||||
IDataSubStream::IDataSubStream() |
||||
:stream(NULL), subBase(0) |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
IDataSubStream::IDataSubStream(IDataStream * inStream, SInt64 inOffset, SInt64 inLength) |
||||
{ |
||||
stream = inStream; |
||||
subBase = inOffset; |
||||
streamLength = inLength; |
||||
|
||||
stream->SetOffset(inOffset); |
||||
} |
||||
|
||||
IDataSubStream::~IDataSubStream() |
||||
{ |
||||
|
||||
} |
||||
|
||||
void IDataSubStream::Attach(IDataStream * inStream, SInt64 inOffset, SInt64 inLength) |
||||
{ |
||||
stream = inStream; |
||||
subBase = inOffset; |
||||
streamLength = inLength; |
||||
|
||||
stream->SetOffset(inOffset); |
||||
} |
||||
|
||||
void IDataSubStream::ReadBuf(void * buf, UInt32 inLength) |
||||
{ |
||||
ASSERT_STR(inLength <= GetRemain(), "IDataSubStream::ReadBuf: hit eof"); |
||||
|
||||
if(stream->GetOffset() != subBase + streamOffset) |
||||
stream->SetOffset(subBase + streamOffset); |
||||
|
||||
stream->ReadBuf(buf, inLength); |
||||
|
||||
streamOffset += inLength; |
||||
} |
||||
|
||||
void IDataSubStream::WriteBuf(const void * buf, UInt32 inLength) |
||||
{ |
||||
if(stream->GetOffset() != subBase + streamOffset) |
||||
stream->SetOffset(subBase + streamOffset); |
||||
|
||||
stream->WriteBuf(buf, inLength); |
||||
|
||||
streamOffset += inLength; |
||||
|
||||
if(streamLength < streamOffset) |
||||
streamLength = streamOffset; |
||||
} |
||||
|
||||
void IDataSubStream::SetOffset(SInt64 inOffset) |
||||
{ |
||||
stream->SetOffset(subBase + inOffset); |
||||
streamOffset = inOffset; |
||||
} |
@ -0,0 +1,102 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IErrors.h" |
||||
|
||||
/**
|
||||
* An arbitrary data stream |
||||
*/ |
||||
class IDataStream |
||||
{ |
||||
public: |
||||
IDataStream(); |
||||
virtual ~IDataStream(); |
||||
|
||||
// read
|
||||
virtual UInt8 Read8(void); |
||||
virtual UInt16 Read16(void); |
||||
virtual UInt32 Read32(void); |
||||
virtual UInt64 Read64(void); |
||||
virtual float ReadFloat(void); |
||||
virtual UInt32 ReadString(char * buf, UInt32 bufLength, char altTerminator = 0, char altTerminator2 = 0); |
||||
virtual void ReadBuf(void * buf, UInt32 inLength) = 0; |
||||
|
||||
// peek
|
||||
virtual UInt8 Peek8(void); |
||||
virtual UInt16 Peek16(void); |
||||
virtual UInt32 Peek32(void); |
||||
virtual UInt64 Peek64(void); |
||||
virtual float PeekFloat(void); |
||||
virtual void PeekBuf(void * buf, UInt32 inLength); |
||||
|
||||
virtual void Skip(SInt64 inBytes); |
||||
|
||||
// write
|
||||
virtual void Write8(UInt8 inData); |
||||
virtual void Write16(UInt16 inData); |
||||
virtual void Write32(UInt32 inData); |
||||
virtual void Write64(UInt64 inData); |
||||
virtual void WriteFloat(float inData); |
||||
virtual void WriteString(const char * buf); |
||||
virtual void WriteBuf(const void * buf, UInt32 inLength) = 0; |
||||
|
||||
SInt64 GetLength(void); |
||||
SInt64 GetRemain(void); |
||||
SInt64 GetOffset(void); |
||||
bool HitEOF(void); |
||||
|
||||
virtual void SetOffset(SInt64 inOffset); |
||||
void Rewind(void) { SetOffset(0); } |
||||
|
||||
void SwapBytes(bool inSwapBytes); |
||||
|
||||
virtual SInt64 GetParentOffset(void) { return GetOffset(); } |
||||
virtual IDataStream * GetParent(void) { return NULL; } |
||||
|
||||
IDataStream * GetRootParent(void); |
||||
|
||||
static void CopyStreams(IDataStream * out, IDataStream * in, UInt64 bufferSize = 1024 * 1024, UInt8 * buf = NULL); |
||||
static void CopySubStreams(IDataStream * out, IDataStream * in, UInt64 remain, UInt64 bufferSize = 1024 * 1024, UInt8 * buf = NULL); |
||||
|
||||
protected: |
||||
SInt64 streamLength; |
||||
SInt64 streamOffset; |
||||
bool swapBytes; |
||||
}; |
||||
|
||||
/**
|
||||
* A utility class to automatically save and restore the current position of an IDataStream |
||||
*/ |
||||
class IDataStream_PositionSaver |
||||
{ |
||||
public: |
||||
IDataStream_PositionSaver(IDataStream * tgt); |
||||
~IDataStream_PositionSaver(); |
||||
|
||||
private: |
||||
IDataStream * stream; |
||||
SInt64 offset; |
||||
}; |
||||
|
||||
class IDataSubStream : public IDataStream |
||||
{ |
||||
public: |
||||
IDataSubStream(); |
||||
IDataSubStream(IDataStream * inStream, SInt64 inOffset, SInt64 inLength); |
||||
~IDataSubStream(); |
||||
|
||||
void Attach(IDataStream * inStream, SInt64 inOffset, SInt64 inLength); |
||||
|
||||
void ReadBuf(void * buf, UInt32 inLength); |
||||
void WriteBuf(const void * buf, UInt32 inLength); |
||||
void SetOffset(SInt64 inOffset); |
||||
|
||||
virtual SInt64 GetParentOffset(void) { return stream->GetOffset(); } |
||||
virtual IDataStream * GetParent(void) { return stream; } |
||||
|
||||
SInt64 GetSubBase(void) { return subBase; } |
||||
|
||||
private: |
||||
IDataStream * stream; |
||||
|
||||
SInt64 subBase; |
||||
}; |
@ -0,0 +1 @@ |
||||
#include "IDatabase.h" |
@ -0,0 +1,116 @@ |
||||
#pragma once |
||||
|
||||
#include <map> |
||||
#include "common/IDataStream.h" |
||||
#include "common/IFilestream.h" |
||||
|
||||
template <class DataType> |
||||
class IDatabase |
||||
{ |
||||
public: |
||||
typedef std::map <UInt64, DataType> DataMapType; |
||||
typedef typename DataMapType::iterator DataMapIterator; |
||||
|
||||
static const UInt64 kGUIDMask = 0x0FFFFFFFFFFFFFFF; |
||||
|
||||
IDatabase() { newKeyHint = 1; } |
||||
virtual ~IDatabase() { } |
||||
|
||||
DataType * Get(UInt64 key) |
||||
{ |
||||
key &= kGUIDMask; |
||||
|
||||
if(!key) |
||||
return NULL; |
||||
|
||||
DataMapType::iterator iter = theDataMap.find(key); |
||||
|
||||
return (iter == theDataMap.end()) ? NULL : &((*iter).second); |
||||
} |
||||
|
||||
DataType * Alloc(UInt64 key) |
||||
{ |
||||
key &= kGUIDMask; |
||||
|
||||
if(!key) |
||||
return NULL; |
||||
|
||||
DataMapType::iterator iter = theDataMap.find(key); |
||||
|
||||
return (iter == theDataMap.end()) ? &theDataMap[key] : NULL; |
||||
} |
||||
|
||||
DataType * Alloc(UInt64 * key) |
||||
{ |
||||
UInt64 newKey = newKeyHint; |
||||
|
||||
do |
||||
{ |
||||
if(!newKey) |
||||
newKey++; |
||||
|
||||
DataMapType::iterator iter = theDataMap.find(newKey); |
||||
|
||||
// is 'newKey' unused?
|
||||
if(iter == theDataMap.end()) |
||||
{ |
||||
*key = newKey; |
||||
newKeyHint = (newKey + 1) & kGUIDMask; |
||||
return &theDataMap[newKey]; |
||||
} |
||||
else |
||||
{ |
||||
++iter; |
||||
if(iter == theDataMap.end()) |
||||
{ |
||||
newKey = 1; |
||||
} |
||||
else |
||||
{ |
||||
UInt64 nextKey = (newKey + 1) & kGUIDMask; |
||||
if(iter->first != nextKey) |
||||
{ |
||||
*key = nextKey; |
||||
newKeyHint = (nextKey + 1) & kGUIDMask; |
||||
return &theDataMap[nextKey]; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
while(1); |
||||
|
||||
*key = 0; |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
void Delete(UInt64 key) |
||||
{ |
||||
if(key) |
||||
{ |
||||
key &= kGUIDMask; |
||||
|
||||
theDataMap.erase(key); |
||||
|
||||
newKeyHint = key; |
||||
} |
||||
} |
||||
|
||||
void Save(IDataStream * stream); |
||||
void Load(IDataStream * stream); |
||||
|
||||
bool SaveToFile(char * name); |
||||
bool LoadFromFile(char * name); |
||||
|
||||
DataMapType & GetData(void) { return theDataMap; } |
||||
|
||||
DataMapIterator Begin(void) { return theDataMap.begin(); } |
||||
DataMapIterator End(void) { return theDataMap.end(); } |
||||
UInt32 Length(void) { return theDataMap.size(); } |
||||
|
||||
private: |
||||
DataMapType theDataMap; |
||||
UInt64 newKeyHint; |
||||
}; |
||||
|
||||
#include "common/IDatabase.inc" |
Binary file not shown.
@ -0,0 +1,324 @@ |
||||
#include "common/IDebugLog.h" |
||||
#include <share.h> |
||||
#include "common/IFileStream.h" |
||||
#include <shlobj.h> |
||||
|
||||
std::FILE * IDebugLog::logFile = NULL; |
||||
char IDebugLog::sourceBuf[16] = { 0 }; |
||||
char IDebugLog::headerText[16] = { 0 }; |
||||
char IDebugLog::formatBuf[8192] = { 0 }; |
||||
int IDebugLog::indentLevel = 0; |
||||
int IDebugLog::rightMargin = 0; |
||||
int IDebugLog::cursorPos = 0; |
||||
int IDebugLog::inBlock = 0; |
||||
bool IDebugLog::autoFlush = true; |
||||
IDebugLog::LogLevel IDebugLog::logLevel = IDebugLog::kLevel_DebugMessage; |
||||
IDebugLog::LogLevel IDebugLog::printLevel = IDebugLog::kLevel_Message; |
||||
|
||||
IDebugLog::IDebugLog() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
IDebugLog::IDebugLog(const char * name) |
||||
{ |
||||
Open(name); |
||||
} |
||||
|
||||
IDebugLog::~IDebugLog() |
||||
{ |
||||
if(logFile) |
||||
fclose(logFile); |
||||
} |
||||
|
||||
void IDebugLog::Open(const char * path) |
||||
{ |
||||
logFile = _fsopen(path, "w", _SH_DENYWR); |
||||
|
||||
if(!logFile) |
||||
{ |
||||
UInt32 id = 0; |
||||
char name[1024]; |
||||
|
||||
do |
||||
{ |
||||
sprintf_s(name, sizeof(name), "%s%d", path, id); |
||||
id++; |
||||
|
||||
logFile = NULL; |
||||
logFile = _fsopen(name, "w", _SH_DENYWR); |
||||
} |
||||
while(!logFile && (id < 5)); |
||||
} |
||||
} |
||||
|
||||
void IDebugLog::OpenRelative(int folderID, const char * relPath) |
||||
{ |
||||
char path[MAX_PATH]; |
||||
|
||||
HRESULT err = SHGetFolderPath(NULL, folderID | CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, path); |
||||
if(!SUCCEEDED(err)) |
||||
{ |
||||
_FATALERROR("SHGetFolderPath %08X failed (result = %08X lasterr = %08X)", folderID, err, GetLastError()); |
||||
} |
||||
ASSERT_CODE(SUCCEEDED(err), err); |
||||
|
||||
strcat_s(path, sizeof(path), relPath); |
||||
|
||||
IFileStream::MakeAllDirs(path); |
||||
|
||||
Open(path); |
||||
} |
||||
|
||||
/**
|
||||
* Output a non-formatted message to the log file |
||||
*
|
||||
* @param message the message |
||||
* @param source the source of the message, or NULL to use the previous source |
||||
*/ |
||||
void IDebugLog::Message(const char * message, const char * source, bool newLine) |
||||
{ |
||||
if(source) |
||||
SetSource(source); |
||||
|
||||
if(inBlock) |
||||
{ |
||||
SeekCursor(RoundToTab((indentLevel * 4) + strlen(headerText))); |
||||
} |
||||
else |
||||
{ |
||||
SeekCursor(indentLevel * 4); |
||||
|
||||
PrintText(headerText); |
||||
} |
||||
|
||||
PrintText(message); |
||||
|
||||
if(newLine) |
||||
NewLine(); |
||||
} |
||||
|
||||
/**
|
||||
* Output a formatted message to the log file |
||||
*
|
||||
* @note It is impossible to set the source of a formatted message. |
||||
* The previous source will be used. |
||||
*/ |
||||
void IDebugLog::FormattedMessage(const char * fmt, ...) |
||||
{ |
||||
va_list argList; |
||||
|
||||
va_start(argList, fmt); |
||||
vsprintf_s(formatBuf, sizeof(formatBuf), fmt, argList); |
||||
Message(formatBuf); |
||||
va_end(argList); |
||||
} |
||||
|
||||
/**
|
||||
* Output a formatted message to the log file |
||||
*
|
||||
* @note It is impossible to set the source of a formatted message. |
||||
* The previous source will be used. |
||||
*/ |
||||
void IDebugLog::FormattedMessage(const char * fmt, va_list args) |
||||
{ |
||||
vsprintf_s(formatBuf, sizeof(formatBuf), fmt, args); |
||||
Message(formatBuf); |
||||
} |
||||
|
||||
void IDebugLog::Log(LogLevel level, const char * fmt, va_list args) |
||||
{ |
||||
bool log = (level <= logLevel); |
||||
bool print = (level <= printLevel); |
||||
|
||||
if(log || print) |
||||
vsprintf_s(formatBuf, sizeof(formatBuf), fmt, args); |
||||
|
||||
if(log) |
||||
Message(formatBuf); |
||||
|
||||
if(print) |
||||
printf("%s\n", formatBuf); |
||||
} |
||||
|
||||
void IDebugLog::LogNNL(LogLevel level, const char * fmt, va_list args) |
||||
{ |
||||
bool log = (level <= logLevel); |
||||
bool print = (level <= printLevel); |
||||
|
||||
if(log || print) |
||||
vsprintf_s(formatBuf, sizeof(formatBuf), fmt, args); |
||||
|
||||
if(log) |
||||
Message(formatBuf, NULL, false); |
||||
|
||||
if(print) |
||||
printf("%s", formatBuf); |
||||
} |
||||
|
||||
/**
|
||||
* Set the current message source |
||||
*/ |
||||
void IDebugLog::SetSource(const char * source) |
||||
{ |
||||
strcpy_s(sourceBuf, sizeof(sourceBuf), source); |
||||
strcpy_s(headerText, sizeof(headerText), "[ ]\t"); |
||||
|
||||
char * tgt = headerText + 1; |
||||
char * src = sourceBuf; |
||||
|
||||
for(int i = 0; (i < 8) && *src; i++, tgt++, src++) |
||||
*tgt = *src; |
||||
} |
||||
|
||||
/**
|
||||
* Clear the current message source |
||||
*/ |
||||
void IDebugLog::ClearSource(void) |
||||
{ |
||||
sourceBuf[0] = 0; |
||||
} |
||||
|
||||
/**
|
||||
* Increase the indentation level |
||||
*/ |
||||
void IDebugLog::Indent(void) |
||||
{ |
||||
indentLevel++; |
||||
} |
||||
|
||||
/**
|
||||
* Decrease the indentation level |
||||
*/ |
||||
void IDebugLog::Outdent(void) |
||||
{ |
||||
if(indentLevel) |
||||
indentLevel--; |
||||
} |
||||
|
||||
/**
|
||||
* Enter a logical block |
||||
*/ |
||||
void IDebugLog::OpenBlock(void) |
||||
{ |
||||
SeekCursor(indentLevel * 4); |
||||
|
||||
PrintText(headerText); |
||||
|
||||
inBlock = 1; |
||||
} |
||||
|
||||
/**
|
||||
* Close a logical block |
||||
*/ |
||||
void IDebugLog::CloseBlock(void) |
||||
{ |
||||
inBlock = 0; |
||||
} |
||||
|
||||
/**
|
||||
* Enable/disable autoflush |
||||
*
|
||||
* @param inAutoFlush autoflush state |
||||
*/ |
||||
void IDebugLog::SetAutoFlush(bool inAutoFlush) |
||||
{ |
||||
autoFlush = inAutoFlush; |
||||
} |
||||
|
||||
/**
|
||||
* Print spaces to the log |
||||
*
|
||||
* If possible, tabs are used instead of spaces. |
||||
*/ |
||||
void IDebugLog::PrintSpaces(int numSpaces) |
||||
{ |
||||
int originalNumSpaces = numSpaces; |
||||
|
||||
if(logFile) |
||||
{ |
||||
while(numSpaces > 0) |
||||
{ |
||||
if(numSpaces >= TabSize()) |
||||
{ |
||||
numSpaces -= TabSize(); |
||||
fputc('\t', logFile); |
||||
} |
||||
else |
||||
{ |
||||
numSpaces--; |
||||
fputc(' ', logFile); |
||||
} |
||||
} |
||||
} |
||||
|
||||
cursorPos += originalNumSpaces; |
||||
} |
||||
|
||||
/**
|
||||
* Prints raw text to the log file |
||||
*/ |
||||
void IDebugLog::PrintText(const char * buf) |
||||
{ |
||||
if(logFile) |
||||
{ |
||||
fputs(buf, logFile); |
||||
if(autoFlush) |
||||
fflush(logFile); |
||||
} |
||||
|
||||
const char * traverse = buf; |
||||
char data; |
||||
|
||||
while(data = *traverse++) |
||||
{ |
||||
if(data == '\t') |
||||
cursorPos += TabSize(); |
||||
else |
||||
cursorPos++; |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* Moves to the next line of the log file |
||||
*/ |
||||
void IDebugLog::NewLine(void) |
||||
{ |
||||
if(logFile) |
||||
{ |
||||
fputc('\n', logFile); |
||||
|
||||
if(autoFlush) |
||||
fflush(logFile); |
||||
} |
||||
|
||||
cursorPos = 0; |
||||
} |
||||
|
||||
/**
|
||||
* Prints spaces to align the cursor to the requested position |
||||
*
|
||||
* @note The cursor move will not be performed if the request would move the cursor |
||||
* backwards. |
||||
*/ |
||||
void IDebugLog::SeekCursor(int position) |
||||
{ |
||||
if(position > cursorPos) |
||||
PrintSpaces(position - cursorPos); |
||||
} |
||||
|
||||
/**
|
||||
* Returns the number of spaces a tab would occupy at the current cursor position |
||||
*/ |
||||
int IDebugLog::TabSize(void) |
||||
{ |
||||
return ((~cursorPos) & 3) + 1; |
||||
} |
||||
|
||||
/**
|
||||
* Rounds a number of spaces to the nearest tab |
||||
*/ |
||||
int IDebugLog::RoundToTab(int spaces) |
||||
{ |
||||
return (spaces + 3) & ~3; |
||||
} |
@ -0,0 +1,133 @@ |
||||
#pragma once |
||||
|
||||
#include <cstdarg> |
||||
|
||||
/**
|
||||
* A simple debug log file |
||||
*
|
||||
* This class supports prefix blocks describing the source of the log event. |
||||
* It also allows logical blocks and outlining.\n |
||||
*/ |
||||
class IDebugLog |
||||
{ |
||||
public: |
||||
IDebugLog(); |
||||
IDebugLog(const char * name); |
||||
~IDebugLog(); |
||||
|
||||
static void Open(const char * path); |
||||
static void OpenRelative(int folderID, const char * relPath); |
||||
|
||||
static void Message(const char * message, const char * source = NULL, bool newLine = true); |
||||
static void FormattedMessage(const char * fmt, ...); |
||||
static void FormattedMessage(const char * fmt, va_list args); |
||||
|
||||
enum LogLevel |
||||
{ |
||||
kLevel_FatalError = 0, |
||||
kLevel_Error, |
||||
kLevel_Warning, |
||||
kLevel_Message, |
||||
kLevel_VerboseMessage, |
||||
kLevel_DebugMessage |
||||
}; |
||||
|
||||
static void Log(LogLevel level, const char * fmt, va_list args); |
||||
static void LogNNL(LogLevel level, const char * fmt, va_list args); // No new line
|
||||
|
||||
static void SetSource(const char * source); |
||||
static void ClearSource(void); |
||||
|
||||
static void Indent(void); |
||||
static void Outdent(void); |
||||
|
||||
static void OpenBlock(void); |
||||
static void CloseBlock(void); |
||||
|
||||
static void SetAutoFlush(bool inAutoFlush); |
||||
|
||||
static void SetLogLevel(LogLevel in) { logLevel = in; } |
||||
static void SetPrintLevel(LogLevel in) { printLevel = in; } |
||||
|
||||
private: |
||||
static void PrintSpaces(int numSpaces); |
||||
static void PrintText(const char * buf); |
||||
static void NewLine(void); |
||||
|
||||
static void SeekCursor(int position); |
||||
|
||||
static int TabSize(void); |
||||
static int RoundToTab(int spaces); |
||||
|
||||
static FILE * logFile; //!< the output file
|
||||
|
||||
static char sourceBuf[16]; //!< name of current source, used in prefix
|
||||
static char headerText[16]; //!< current text to use as line prefix
|
||||
static char formatBuf[8192]; //!< temp buffer used for formatted messages
|
||||
|
||||
static int indentLevel; //!< the current indentation level (in tabs)
|
||||
static int rightMargin; //!< the column at which text should be wrapped
|
||||
static int cursorPos; //!< current cursor position
|
||||
static int inBlock; //!< are we in a block?
|
||||
|
||||
static bool autoFlush; //!< automatically flush the file after writing
|
||||
|
||||
static LogLevel logLevel; //!< least important log level to write
|
||||
static LogLevel printLevel; //!< least important log level to print
|
||||
}; |
||||
|
||||
extern IDebugLog gLog; |
||||
|
||||
inline void _FATALERROR(const char * fmt, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
gLog.Log(IDebugLog::kLevel_FatalError, fmt, args); |
||||
va_end(args); |
||||
} |
||||
|
||||
inline void _ERROR(const char * fmt, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
gLog.Log(IDebugLog::kLevel_Error, fmt, args); |
||||
va_end(args); |
||||
} |
||||
|
||||
inline void _WARNING(const char * fmt, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
gLog.Log(IDebugLog::kLevel_Warning, fmt, args); |
||||
va_end(args); |
||||
} |
||||
|
||||
inline void _MESSAGE(const char * fmt, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
gLog.Log(IDebugLog::kLevel_Message, fmt, args); |
||||
va_end(args); |
||||
} |
||||
|
||||
inline void _VMESSAGE(const char * fmt, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
gLog.Log(IDebugLog::kLevel_VerboseMessage, fmt, args); |
||||
va_end(args); |
||||
} |
||||
|
||||
inline void _DMESSAGE(const char * fmt, ...) |
||||
{ |
||||
va_list args; |
||||
|
||||
va_start(args, fmt); |
||||
gLog.Log(IDebugLog::kLevel_DebugMessage, fmt, args); |
||||
va_end(args); |
||||
} |
@ -0,0 +1,45 @@ |
||||
#include "IDirectoryIterator.h" |
||||
#include <string> |
||||
|
||||
IDirectoryIterator::IDirectoryIterator(const char * path, const char * match) |
||||
:m_searchHandle(INVALID_HANDLE_VALUE), m_done(false) |
||||
{ |
||||
if(!match) match = "*"; |
||||
|
||||
strcpy_s(m_path, sizeof(m_path), path); |
||||
|
||||
char wildcardPath[MAX_PATH]; |
||||
sprintf_s(wildcardPath, sizeof(wildcardPath), "%s\\%s", path, match); |
||||
|
||||
m_searchHandle = FindFirstFile(wildcardPath, &m_result); |
||||
if(m_searchHandle == INVALID_HANDLE_VALUE) |
||||
m_done = true; |
||||
} |
||||
|
||||
IDirectoryIterator::~IDirectoryIterator() |
||||
{ |
||||
if(m_searchHandle != INVALID_HANDLE_VALUE) |
||||
FindClose(m_searchHandle); |
||||
} |
||||
|
||||
void IDirectoryIterator::GetFullPath(char * out, UInt32 outLen) |
||||
{ |
||||
sprintf_s(out, outLen, "%s\\%s", m_path, m_result.cFileName); |
||||
} |
||||
|
||||
std::string IDirectoryIterator::GetFullPath(void) |
||||
{ |
||||
return std::string(m_path) + "\\" + std::string(m_result.cFileName); |
||||
} |
||||
|
||||
void IDirectoryIterator::Next(void) |
||||
{ |
||||
BOOL result = FindNextFile(m_searchHandle, &m_result); |
||||
if(!result) |
||||
m_done = true; |
||||
} |
||||
|
||||
bool IDirectoryIterator::Done(void) |
||||
{ |
||||
return m_done; |
||||
} |
@ -0,0 +1,24 @@ |
||||
#pragma once |
||||
|
||||
class IDirectoryIterator |
||||
{ |
||||
public: |
||||
IDirectoryIterator(const char * path, const char * match = NULL); |
||||
virtual ~IDirectoryIterator(); |
||||
|
||||
WIN32_FIND_DATA * Get(void) { return &m_result; } |
||||
void GetFullPath(char * out, UInt32 outLen); |
||||
std::string GetFullPath(void); |
||||
|
||||
void Next(void); |
||||
bool Done(void); |
||||
|
||||
private: |
||||
IDirectoryIterator(); // undefined, disallow
|
||||
|
||||
HANDLE m_searchHandle; |
||||
WIN32_FIND_DATA m_result; |
||||
bool m_done; |
||||
|
||||
char m_path[MAX_PATH]; |
||||
}; |
@ -0,0 +1,38 @@ |
||||
#include "IDynamicCreate.h" |
||||
|
||||
#if ENABLE_IDYNAMICCREATE |
||||
|
||||
IClassRegistry _gClassRegistry; |
||||
|
||||
IClassRegistry::IClassRegistry() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
IClassRegistry::~IClassRegistry() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
void IClassRegistry::RegisterClassInfo(UInt32 id, IDynamicType * typeInfo) |
||||
{ |
||||
theClassRegistry[id] = typeInfo; |
||||
} |
||||
|
||||
IDynamicType * IClassRegistry::LookupClassInfo(UInt32 id) |
||||
{ |
||||
ClassRegistryType::iterator iter = theClassRegistry.find(id); |
||||
|
||||
return (iter == theClassRegistry.end()) ? NULL : (*iter).second; |
||||
} |
||||
|
||||
IDynamicType * IClassRegistry::LookupClassInfo(char * name) |
||||
{ |
||||
for(ClassRegistryType::iterator iter = theClassRegistry.begin(); iter != theClassRegistry.end(); iter++) |
||||
if(!strcmp((*iter).second->GetName(), name)) |
||||
return (*iter).second; |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,118 @@ |
||||
#pragma once |
||||
|
||||
#include <map> |
||||
#include "common/IDataStream.h" |
||||
#include "common/IErrors.h" |
||||
|
||||
// this screws with edit-and-continue and we don't use it
|
||||
#define ENABLE_IDYNAMICCREATE 0 |
||||
|
||||
#if ENABLE_IDYNAMICCREATE |
||||
|
||||
//! Get a pointer to the IDynamicType for a class.
|
||||
//! @note This is not a function; the parameter must be constant.
|
||||
#define GetDynType(name) (&(##name##::__DYN_DynamicType)) |
||||
|
||||
//! Declare the members used for dynamic class creation
|
||||
#define DYNAMIC_DECLARE(name) \ |
||||
public: \
|
||||
class __DYN_##name##_DynamicType : public IDynamicType \
|
||||
{ \
|
||||
public: \
|
||||
__DYN_##name##_DynamicType() { } \
|
||||
~__DYN_##name##_DynamicType() { } \
|
||||
\
|
||||
virtual IDynamic * Create(void) { return new name; } \
|
||||
virtual char * GetName(void) { return #name; } \
|
||||
virtual IDynamic * Instantiate(IDataStream * stream); \
|
||||
}; \
|
||||
\
|
||||
static __DYN_##name##_DynamicType __DYN_DynamicType; \
|
||||
virtual IDynamicType * __DYN_GetDynamicType(void) { return &__DYN_DynamicType; } \
|
||||
\
|
||||
friend __DYN_##name##_DynamicType; |
||||
|
||||
//! Define the members used for dynamic class creation
|
||||
#define DYNAMIC_DEFINE(name) name##::__DYN_##name##_DynamicType name##::__DYN_DynamicType; |
||||
|
||||
//! Define a dynamic instantiation handler
|
||||
#define DYNAMIC_INSTANTIATE_HANDLER(name) IDynamic * name##::__DYN_##name##_DynamicType::Instantiate(IDataStream * stream) { name * object = new name; |
||||
#define END_DYNAMIC_INSTANTIATE_HANDLER return object; } |
||||
|
||||
//! Specifies that a dynamic class should not be instantiated automatically
|
||||
#define NO_DYNAMIC_INSTANTIATE_HANDLER(name) DYNAMIC_INSTANTIATE_HANDLER(name) { HALT("attempted to instantiate " #name); } END_DYNAMIC_INSTANTIATE_HANDLER |
||||
|
||||
//! Casts
|
||||
#define CAST(ptr, type) _DynamicCast <type>(ptr); |
||||
|
||||
class IDynamicType; |
||||
|
||||
/**
|
||||
* Pure virtual base class allowing dynamic creation of objects |
||||
*
|
||||
* To allow dynamic creation of a class, publicly inherit IDynamic, add the |
||||
* macro DYNAMIC_DECLARE(classname) first in the class declaration, and add |
||||
* the macro DYNAMIC_DEFINE(classname) somewhere in the class definition file. |
||||
*/ |
||||
class IDynamic |
||||
{ |
||||
public: |
||||
IDynamic() { } |
||||
virtual ~IDynamic() { } |
||||
|
||||
virtual IDynamicType * __DYN_GetDynamicType(void) = 0; |
||||
}; |
||||
|
||||
/**
|
||||
* Pure virtual base class allowing class instantiation and information retrieval |
||||
*/ |
||||
class IDynamicType |
||||
{ |
||||
public: |
||||
IDynamicType() { } |
||||
virtual ~IDynamicType() { } |
||||
|
||||
virtual IDynamic * Create(void) = 0; |
||||
virtual char * GetName(void) = 0; |
||||
|
||||
virtual IDynamic * Instantiate(IDataStream * stream) = 0; |
||||
}; |
||||
|
||||
//!
|
||||
template <typename T> |
||||
T * _DynamicCast(IDynamic * ptr) |
||||
{ |
||||
if(ptr && (&T::__DYN_DynamicType == ptr->__DYN_GetDynamicType())) |
||||
return static_cast<T *>(ptr); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
/**
|
||||
* Registry of dynamic classes |
||||
*/ |
||||
class IClassRegistry |
||||
{ |
||||
public: |
||||
IClassRegistry(); |
||||
~IClassRegistry(); |
||||
|
||||
static void RegisterClassInfo(UInt32 id, IDynamicType * typeInfo); |
||||
|
||||
static IDynamicType * LookupClassInfo(UInt32 id); |
||||
static IDynamicType * LookupClassInfo(char * name); |
||||
|
||||
static IDynamic * Create(UInt32 id) { IDynamicType * info = LookupClassInfo(id); return info ? info->Create() : NULL; } |
||||
static IDynamic * Create(char * name) { IDynamicType * info = LookupClassInfo(name); return info ? info->Create() : NULL; } |
||||
|
||||
static IDynamic * Instantiate(UInt32 id, IDataStream * stream) { IDynamicType * info = LookupClassInfo(id); return info ? info->Instantiate(stream) : NULL; } |
||||
static IDynamic * Instantiate(char * name, IDataStream * stream) { IDynamicType * info = LookupClassInfo(name); return info ? info->Instantiate(stream) : NULL; } |
||||
|
||||
static char * GetName(UInt32 id) { IDynamicType * info = LookupClassInfo(id); return info ? info->GetName() : NULL; } |
||||
|
||||
private: |
||||
typedef std::map <UInt32, IDynamicType *> ClassRegistryType; |
||||
static ClassRegistryType theClassRegistry; |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,59 @@ |
||||
#include "common/IErrors.h" |
||||
#include "common/IDebugLog.h" |
||||
#include <cstdlib> |
||||
|
||||
__declspec(noreturn) static void IErrors_Halt(void) |
||||
{ |
||||
// crash
|
||||
*((int *)0) = 0xDEADBEEF; |
||||
} |
||||
|
||||
/**
|
||||
* Report a failed assertion and exit the program |
||||
*
|
||||
* @param file the file where the error occured |
||||
* @param line the line number where the error occured |
||||
* @param desc an error message |
||||
*/ |
||||
void _AssertionFailed(const char * file, unsigned long line, const char * desc) |
||||
{ |
||||
_FATALERROR("Assertion failed in %s (%d): %s", file, line, desc); |
||||
|
||||
IErrors_Halt(); |
||||
} |
||||
|
||||
/**
|
||||
* Report a failed assertion and exit the program |
||||
*
|
||||
* @param file the file where the error occured |
||||
* @param line the line number where the error occured |
||||
* @param desc an error message |
||||
* @param code the error code |
||||
*/ |
||||
void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, unsigned long long code) |
||||
{ |
||||
if(code & 0xFFFFFFFF00000000) |
||||
_FATALERROR("Assertion failed in %s (%d): %s (code = %16I64X (%I64d))", file, line, desc, code, code); |
||||
else |
||||
{ |
||||
UInt32 code32 = code; |
||||
_FATALERROR("Assertion failed in %s (%d): %s (code = %08X (%d))", file, line, desc, code32, code32); |
||||
} |
||||
|
||||
IErrors_Halt(); |
||||
} |
||||
|
||||
/**
|
||||
* Report a failed assertion and exit the program |
||||
*
|
||||
* @param file the file where the error occured |
||||
* @param line the line number where the error occured |
||||
* @param desc an error message |
||||
* @param code the error code |
||||
*/ |
||||
void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, const char * code) |
||||
{ |
||||
_FATALERROR("Assertion failed in %s (%d): %s (code = %s)", file, line, desc, code); |
||||
|
||||
IErrors_Halt(); |
||||
} |
@ -0,0 +1,32 @@ |
||||
#pragma once |
||||
|
||||
void _AssertionFailed(const char * file, unsigned long line, const char * desc); |
||||
void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, unsigned long long code); |
||||
void _AssertionFailed_ErrCode(const char * file, unsigned long line, const char * desc, const char * code); |
||||
|
||||
//! Exit the program if the condition is not true
|
||||
#define ASSERT(a) do { if(!(a)) _AssertionFailed(__FILE__, __LINE__, #a); } while(0) |
||||
//! Exit the program if the condition is not true, with an error message
|
||||
#define ASSERT_STR(a, b) do { if(!(a)) _AssertionFailed(__FILE__, __LINE__, b); } while(0) |
||||
//! Exit the program if the condition is not true, reporting an error code
|
||||
#define ASSERT_CODE(a, b) do { if(!(a)) _AssertionFailed_ErrCode(__FILE__, __LINE__, #a, b); } while(0) |
||||
//! Exit the program if the condition is not true, reporting an error code and message
|
||||
#define ASSERT_STR_CODE(a, b, c) do { if(!(a)) _AssertionFailed_ErrCode(__FILE__, __LINE__, b, c); } while(0) |
||||
//! Exit the program with an error message
|
||||
#define HALT(a) do { _AssertionFailed(__FILE__, __LINE__, a); } while(0) |
||||
//! Exit the program with and error code and message
|
||||
#define HALT_CODE(a, b) do { _AssertionFailed_ErrCode(__FILE__, __LINE__, a, b); } while(0) |
||||
|
||||
// based on the boost implementation of static asserts
|
||||
template <bool x> struct StaticAssertFailure; |
||||
template <> struct StaticAssertFailure <true> { enum { a = 1 }; }; |
||||
template <int x> struct static_assert_test { }; |
||||
|
||||
#define __MACRO_JOIN__(a, b) __MACRO_JOIN_2__(a, b) |
||||
#define __MACRO_JOIN_2__(a, b) __MACRO_JOIN_3__(a, b) |
||||
#define __MACRO_JOIN_3__(a, b) a##b |
||||
#define __PREPRO_TOKEN_STR2__(a) #a |
||||
#define __PREPRO_TOKEN_STR__(a) __PREPRO_TOKEN_STR2__(a) |
||||
#define __LOC__ __FILE__ "("__PREPRO_TOKEN_STR__(__LINE__)") : " |
||||
|
||||
#define STATIC_ASSERT(a) typedef static_assert_test <sizeof(StaticAssertFailure<(bool)(a)>)> __MACRO_JOIN__(static_assert_typedef_, __COUNTER__) |
@ -0,0 +1,48 @@ |
||||
#include "IEvent.h" |
||||
|
||||
IEvent::IEvent() |
||||
{ |
||||
theEvent = CreateEvent(NULL, true, true, NULL); |
||||
ASSERT(theEvent); |
||||
|
||||
blockCount.Set(0); |
||||
} |
||||
|
||||
IEvent::~IEvent() |
||||
{ |
||||
CloseHandle(theEvent); |
||||
} |
||||
|
||||
bool IEvent::Block(void) |
||||
{ |
||||
if(blockCount.Increment() == 1) |
||||
return (ResetEvent(theEvent) != 0); |
||||
else |
||||
return true; |
||||
} |
||||
|
||||
bool IEvent::UnBlock(void) |
||||
{ |
||||
if(blockCount.Decrement() == 0) |
||||
return (SetEvent(theEvent) != 0); |
||||
else |
||||
return true; |
||||
} |
||||
|
||||
bool IEvent::Wait(UInt32 timeout) |
||||
{ |
||||
switch(WaitForSingleObject(theEvent, timeout)) |
||||
{ |
||||
case WAIT_ABANDONED: |
||||
HALT("IEvent::Wait: got abandoned event"); |
||||
return false; |
||||
|
||||
case WAIT_OBJECT_0: |
||||
return true; |
||||
|
||||
default: |
||||
case WAIT_TIMEOUT: |
||||
gLog.FormattedMessage("IEvent::Wait: timeout"); |
||||
return false; |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IInterlockedLong.h" |
||||
|
||||
class IEvent |
||||
{ |
||||
public: |
||||
static const UInt32 kDefaultTimeout = 1000 * 10; |
||||
|
||||
IEvent(); |
||||
~IEvent(); |
||||
|
||||
bool Block(void); |
||||
bool UnBlock(void); |
||||
bool Wait(UInt32 timeout = kDefaultTimeout); |
||||
|
||||
bool IsBlocked(void) { return blockCount.Get() > 0; } |
||||
|
||||
private: |
||||
HANDLE theEvent; |
||||
IInterlockedLong blockCount; |
||||
}; |
@ -0,0 +1,85 @@ |
||||
#include "IFIFO.h" |
||||
|
||||
IFIFO::IFIFO(UInt32 length) |
||||
{ |
||||
fifoBuf = new UInt8[length]; |
||||
fifoBufSize = length; |
||||
fifoBase = 0; |
||||
fifoDataLength = 0; |
||||
} |
||||
|
||||
IFIFO::~IFIFO() |
||||
{ |
||||
delete fifoBuf; |
||||
} |
||||
|
||||
bool IFIFO::Push(UInt8 * buf, UInt32 length) |
||||
{ |
||||
// would that overflow the buffer?
|
||||
if(length > GetBufferRemain()) |
||||
return false; |
||||
|
||||
UInt32 writeOffset = GetWriteOffset(); |
||||
|
||||
// will this cross the end of the buffer?
|
||||
if(writeOffset + length > fifoBufSize) |
||||
{ |
||||
UInt32 segmentLength = fifoBufSize - writeOffset; |
||||
|
||||
std::memcpy(&fifoBuf[writeOffset], buf, segmentLength); |
||||
std::memcpy(fifoBuf, &buf[segmentLength], length - segmentLength); |
||||
} |
||||
else |
||||
{ |
||||
std::memcpy(&fifoBuf[writeOffset], buf, length); |
||||
} |
||||
|
||||
// update pointers
|
||||
fifoDataLength += length; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
bool IFIFO::Pop(UInt8 * buf, UInt32 length) |
||||
{ |
||||
bool result = Peek(buf, length); |
||||
|
||||
// update pointers if we were successful
|
||||
if(result) |
||||
{ |
||||
fifoDataLength -= length; |
||||
fifoBase = ToRawOffset(fifoBase + length); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
bool IFIFO::Peek(UInt8 * buf, UInt32 length) |
||||
{ |
||||
// would that underflow the buffer?
|
||||
if(length > fifoDataLength) |
||||
return false; |
||||
|
||||
// will this cross the end of the buffer?
|
||||
if(fifoBase + length > fifoBufSize) |
||||
{ |
||||
UInt32 segmentLength = fifoBufSize - fifoBase; |
||||
|
||||
std::memcpy(buf, &fifoBuf[fifoBase], segmentLength); |
||||
std::memcpy(&buf[segmentLength], fifoBuf, length - segmentLength); |
||||
} |
||||
else |
||||
{ |
||||
std::memcpy(buf, &fifoBuf[fifoBase], length); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void IFIFO::Clear(void) |
||||
{ |
||||
fifoDataLength = 0; |
||||
|
||||
// this isn't needed, but staying away from the buffer end is always good
|
||||
fifoBase = 0; |
||||
} |
@ -0,0 +1,27 @@ |
||||
#pragma once |
||||
|
||||
class IFIFO |
||||
{ |
||||
public: |
||||
IFIFO(UInt32 length = 0); |
||||
virtual ~IFIFO(); |
||||
|
||||
virtual bool Push(UInt8 * buf, UInt32 length); |
||||
virtual bool Pop(UInt8 * buf, UInt32 length); |
||||
virtual bool Peek(UInt8 * buf, UInt32 length); |
||||
virtual void Clear(void); |
||||
|
||||
UInt32 GetBufferSize(void) { return fifoBufSize; } |
||||
UInt32 GetBufferRemain(void) { return fifoBufSize - fifoDataLength; } |
||||
UInt32 GetDataLength(void) { return fifoDataLength; } |
||||
|
||||
private: |
||||
UInt32 ToRawOffset(UInt32 in) { return in % fifoBufSize; } |
||||
UInt32 ToDataOffset(UInt32 in) { return ToRawOffset(fifoBase + in); } |
||||
UInt32 GetWriteOffset(void) { return ToDataOffset(fifoDataLength); } |
||||
|
||||
UInt8 * fifoBuf; |
||||
UInt32 fifoBufSize; // size of the buffer (in bytes)
|
||||
UInt32 fifoBase; // pointer to the beginning of the data block
|
||||
UInt32 fifoDataLength; // size of the data block
|
||||
}; |
@ -0,0 +1,240 @@ |
||||
#include "IFileStream.h" |
||||
#include "IDebugLog.h" |
||||
#include "IErrors.h" |
||||
#include <direct.h> |
||||
|
||||
IFileStream::IFileStream() |
||||
:theFile(INVALID_HANDLE_VALUE) |
||||
{ |
||||
|
||||
} |
||||
|
||||
IFileStream::IFileStream(const char * name) |
||||
:theFile(INVALID_HANDLE_VALUE) |
||||
{ |
||||
Open(name); |
||||
} |
||||
|
||||
IFileStream::~IFileStream() |
||||
{ |
||||
Close(); |
||||
} |
||||
|
||||
/**
|
||||
* Opens a file for reading and attaches it to the stream |
||||
*/ |
||||
bool IFileStream::Open(const char * name) |
||||
{ |
||||
Close(); |
||||
|
||||
theFile = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
||||
if(theFile != INVALID_HANDLE_VALUE) |
||||
{ |
||||
LARGE_INTEGER temp; |
||||
|
||||
GetFileSizeEx(theFile, &temp); |
||||
|
||||
streamLength = temp.QuadPart; |
||||
streamOffset = 0; |
||||
} |
||||
|
||||
return theFile != INVALID_HANDLE_VALUE; |
||||
} |
||||
|
||||
static UINT_PTR CALLBACK BrowseEventProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam) |
||||
{ |
||||
return 0; |
||||
} |
||||
|
||||
bool IFileStream::BrowseOpen(void) |
||||
{ |
||||
bool result = false; |
||||
OPENFILENAME info; |
||||
char path[4096]; |
||||
|
||||
path[0] = 0; |
||||
|
||||
info.lStructSize = sizeof(info); |
||||
info.hwndOwner = NULL; |
||||
info.hInstance = NULL; |
||||
info.lpstrFilter = NULL; |
||||
info.lpstrCustomFilter = NULL; |
||||
info.nMaxCustFilter = 0; |
||||
info.nFilterIndex = 0; |
||||
info.lpstrFile = path; |
||||
info.nMaxFile = sizeof(path); |
||||
info.lpstrFileTitle = NULL; |
||||
info.nMaxFileTitle = 0; |
||||
info.lpstrInitialDir = NULL; |
||||
info.lpstrTitle = NULL; |
||||
info.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_FILEMUSTEXIST | OFN_ENABLEHOOK | OFN_NOCHANGEDIR; |
||||
info.lpstrDefExt = NULL; |
||||
info.lCustData = NULL; |
||||
info.lpfnHook = BrowseEventProc; |
||||
info.lpTemplateName = NULL; |
||||
// info.pvReserved = NULL;
|
||||
// info.dwReserved = NULL;
|
||||
// info.FlagsEx = 0;
|
||||
|
||||
if(GetOpenFileName(&info)) |
||||
{ |
||||
result = Open(path); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/**
|
||||
* Creates a new file for writing, overwriting any previously-existing files, |
||||
* and attaches it to the stream |
||||
*/ |
||||
bool IFileStream::Create(const char * name) |
||||
{ |
||||
Close(); |
||||
|
||||
theFile = CreateFile(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); |
||||
if(theFile != INVALID_HANDLE_VALUE) |
||||
{ |
||||
streamLength = 0; |
||||
streamOffset = 0; |
||||
} |
||||
|
||||
return theFile != INVALID_HANDLE_VALUE; |
||||
} |
||||
|
||||
bool IFileStream::BrowseCreate(const char * defaultName, const char * defaultPath, const char * title) |
||||
{ |
||||
bool result = false; |
||||
OPENFILENAME info; |
||||
char path[4096]; |
||||
|
||||
if(defaultName) |
||||
strcpy_s(path, sizeof(path), defaultName); |
||||
|
||||
info.lStructSize = sizeof(info); |
||||
info.hwndOwner = NULL; |
||||
info.hInstance = NULL; |
||||
info.lpstrFilter = NULL; |
||||
info.lpstrCustomFilter = NULL; |
||||
info.nMaxCustFilter = 0; |
||||
info.nFilterIndex = 0; |
||||
info.lpstrFile = path; |
||||
info.nMaxFile = sizeof(path); |
||||
info.lpstrFileTitle = NULL; |
||||
info.nMaxFileTitle = 0; |
||||
info.lpstrInitialDir = defaultPath; |
||||
info.lpstrTitle = title; |
||||
info.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_ENABLEHOOK | |
||||
OFN_NOCHANGEDIR | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; |
||||
info.lpstrDefExt = NULL; |
||||
info.lCustData = NULL; |
||||
info.lpfnHook = BrowseEventProc; |
||||
info.lpTemplateName = NULL; |
||||
// info.pvReserved = NULL;
|
||||
// info.dwReserved = NULL;
|
||||
// info.FlagsEx = 0;
|
||||
|
||||
if(GetSaveFileName(&info)) |
||||
{ |
||||
result = Create(path); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/**
|
||||
* Closes the current file |
||||
*/ |
||||
void IFileStream::Close(void) |
||||
{ |
||||
if(theFile) |
||||
{ |
||||
CloseHandle(theFile); |
||||
theFile = INVALID_HANDLE_VALUE; |
||||
} |
||||
} |
||||
|
||||
void IFileStream::ReadBuf(void * buf, UInt32 inLength) |
||||
{ |
||||
UInt32 bytesRead; |
||||
|
||||
ReadFile(theFile, buf, inLength, &bytesRead, NULL); |
||||
|
||||
streamOffset += bytesRead; |
||||
} |
||||
|
||||
void IFileStream::WriteBuf(const void * buf, UInt32 inLength) |
||||
{ |
||||
UInt32 bytesWritten; |
||||
|
||||
// check for file expansion
|
||||
if(streamOffset > streamLength) |
||||
SetEndOfFile(theFile); |
||||
|
||||
WriteFile(theFile, buf, inLength, &bytesWritten, NULL); |
||||
|
||||
streamOffset += bytesWritten; |
||||
|
||||
if(streamLength < streamOffset) |
||||
streamLength = streamOffset; |
||||
} |
||||
|
||||
void IFileStream::SetOffset(SInt64 inOffset) |
||||
{ |
||||
LARGE_INTEGER temp; |
||||
|
||||
temp.QuadPart = inOffset; |
||||
|
||||
SetFilePointerEx(theFile, temp, NULL, FILE_BEGIN); |
||||
streamOffset = inOffset; |
||||
} |
||||
|
||||
void IFileStream::SetLength(UInt64 length) |
||||
{ |
||||
SetOffset(length); |
||||
SetEndOfFile(theFile); |
||||
|
||||
streamLength = length; |
||||
} |
||||
|
||||
// ### TODO: get rid of buf
|
||||
void IFileStream::MakeAllDirs(const char * path) |
||||
{ |
||||
char buf[1024]; |
||||
char * traverse = buf; |
||||
|
||||
while(1) |
||||
{ |
||||
char data = *path++; |
||||
|
||||
if(!data) |
||||
break; |
||||
|
||||
if((data == '\\') || (data == '/')) |
||||
{ |
||||
*traverse = 0; |
||||
_mkdir(buf); |
||||
} |
||||
|
||||
*traverse++ = data; |
||||
} |
||||
} |
||||
|
||||
char * IFileStream::ExtractFileName(char * path) |
||||
{ |
||||
char * traverse = path; |
||||
char * lastSlash = NULL; |
||||
|
||||
while(1) |
||||
{ |
||||
char data = *traverse++; |
||||
|
||||
if((data == '\\') || (data == '/')) |
||||
lastSlash = traverse; |
||||
|
||||
if(!data) |
||||
break; |
||||
} |
||||
|
||||
return lastSlash; |
||||
} |
@ -0,0 +1,37 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IDataStream.h" |
||||
|
||||
/**
|
||||
* An input file stream |
||||
*/ |
||||
class IFileStream : public IDataStream |
||||
{ |
||||
public: |
||||
IFileStream(); |
||||
IFileStream(const char * name); |
||||
~IFileStream(); |
||||
|
||||
bool Open(const char * name); |
||||
bool BrowseOpen(void); |
||||
|
||||
bool Create(const char * name); |
||||
bool BrowseCreate(const char * defaultName = NULL, const char * defaultPath = NULL, const char * title = NULL); |
||||
|
||||
void Close(void); |
||||
|
||||
HANDLE GetHandle(void) { return theFile; } |
||||
|
||||
virtual void ReadBuf(void * buf, UInt32 inLength); |
||||
virtual void WriteBuf(const void * buf, UInt32 inLength); |
||||
virtual void SetOffset(SInt64 inOffset); |
||||
|
||||
// can truncate. implicitly seeks to the end of the file
|
||||
void SetLength(UInt64 length); |
||||
|
||||
static void MakeAllDirs(const char * path); |
||||
static char * ExtractFileName(char * path); |
||||
|
||||
protected: |
||||
HANDLE theFile; |
||||
}; |
@ -0,0 +1,3 @@ |
||||
#include "IInterlockedLong.h" |
||||
|
||||
// all functions are inlined
|
@ -0,0 +1,19 @@ |
||||
#pragma once |
||||
|
||||
struct IInterlockedLong |
||||
{ |
||||
public: |
||||
long Increment(void) { return InterlockedIncrement(&value); } |
||||
long Decrement(void) { return InterlockedDecrement(&value); } |
||||
long Get(void) { return value; } |
||||
long Set(long in) { return InterlockedExchange(&value, in); } |
||||
long TrySetIf(long newValue, long expectedOldValue) |
||||
{ return InterlockedCompareExchange(&value, newValue, expectedOldValue); } |
||||
|
||||
// interlock variable semantics
|
||||
bool Claim(void) { return TrySetIf(1, 0) == 0; } |
||||
bool Release(void) { return TrySetIf(0, 1) == 1; } |
||||
|
||||
private: |
||||
volatile long value; |
||||
}; |
@ -0,0 +1,91 @@ |
||||
#pragma once |
||||
|
||||
// ILink members must be public
|
||||
template <typename T> |
||||
struct ILink |
||||
{ |
||||
static const UInt32 s_offset; |
||||
|
||||
ILink <T> * next; |
||||
ILink <T> * prev; |
||||
|
||||
T * GetObj(void) { return (T *)(((uintptr_t)this) - s_offset); } |
||||
|
||||
static ILink <T> * GetLink(T * obj) { return (ILink <T> *)(((uintptr_t)obj) + s_offset); } |
||||
|
||||
void Unlink(void) |
||||
{ |
||||
if(next) next->prev = prev; |
||||
if(prev) prev->next = next; |
||||
|
||||
next = prev = NULL; |
||||
} |
||||
|
||||
void LinkBefore(T * obj) |
||||
{ |
||||
LinkBefore(GetLink(obj)); |
||||
} |
||||
|
||||
void LinkAfter(T * obj) |
||||
{ |
||||
LinkAfter(GetLink(obj)); |
||||
} |
||||
|
||||
void LinkBefore(ILink <T> * link) |
||||
{ |
||||
link->next = this; |
||||
link->prev = prev; |
||||
|
||||
if(prev) |
||||
{ |
||||
prev->next = link; |
||||
} |
||||
|
||||
prev = link; |
||||
} |
||||
|
||||
void LinkAfter(ILink <T> * link) |
||||
{ |
||||
link->next = next; |
||||
link->prev = this; |
||||
|
||||
if(next) |
||||
{ |
||||
next->prev = link; |
||||
} |
||||
|
||||
next = link; |
||||
} |
||||
}; |
||||
|
||||
template <typename T> |
||||
struct ILinkedList |
||||
{ |
||||
ILink <T> begin; |
||||
ILink <T> end; |
||||
|
||||
void Reset(void) |
||||
{ |
||||
begin.next = &end; |
||||
begin.prev = NULL; |
||||
end.next = NULL; |
||||
end.prev = &begin; |
||||
} |
||||
|
||||
void PushFront(T * obj) |
||||
{ |
||||
ILink <T> * objLink = ILink <T>::GetLink(obj); |
||||
|
||||
objLink->next = begin.next; |
||||
objLink->prev = &begin; |
||||
|
||||
if(objLink->next) |
||||
{ |
||||
objLink->next->prev = objLink; |
||||
} |
||||
|
||||
begin.next = objLink; |
||||
} |
||||
}; |
||||
|
||||
#define ILINK_INIT(baseType, memberName) template <typename T> const UInt32 ILink <T>::s_offset = offsetof(baseType, memberName) |
@ -0,0 +1,43 @@ |
||||
#include "IMemPool.h" |
||||
|
||||
void Test_IMemPool(void) |
||||
{ |
||||
IMemPool <UInt32, 3> pool; |
||||
|
||||
_DMESSAGE("main: pool test"); |
||||
gLog.Indent(); |
||||
|
||||
_DMESSAGE("start"); |
||||
pool.Dump(); |
||||
|
||||
UInt32 * data0, * data1, * data2; |
||||
|
||||
data0 = pool.Allocate(); |
||||
_DMESSAGE("alloc0 = %08X", data0); |
||||
pool.Dump(); |
||||
|
||||
data1 = pool.Allocate(); |
||||
_DMESSAGE("alloc1 = %08X", data1); |
||||
pool.Dump(); |
||||
|
||||
data2 = pool.Allocate(); |
||||
_DMESSAGE("alloc2 = %08X", data2); |
||||
pool.Dump(); |
||||
|
||||
_DMESSAGE("free0 %08X", data0); |
||||
pool.Free(data0); |
||||
pool.Dump(); |
||||
|
||||
data0 = pool.Allocate(); |
||||
_DMESSAGE("alloc0 = %08X", data0); |
||||
pool.Dump(); |
||||
|
||||
_DMESSAGE("free2 %08X", data2); |
||||
pool.Free(data2); |
||||
pool.Dump(); |
||||
|
||||
_DMESSAGE("done"); |
||||
pool.Dump(); |
||||
|
||||
gLog.Outdent(); |
||||
} |
@ -0,0 +1,312 @@ |
||||
#pragma once |
||||
|
||||
#include "common/ICriticalSection.h" |
||||
|
||||
template <typename T, UInt32 size> |
||||
class IMemPool |
||||
{ |
||||
public: |
||||
IMemPool() |
||||
:m_free(NULL), m_alloc(NULL) |
||||
{ |
||||
Reset(); |
||||
} |
||||
|
||||
~IMemPool() { Clear(); } |
||||
|
||||
void Reset(void) |
||||
{ |
||||
for(UInt32 i = 0; i < size - 1; i++) |
||||
{ |
||||
m_items[i].next = &m_items[i + 1]; |
||||
} |
||||
|
||||
m_items[size - 1].next = NULL; |
||||
m_free = m_items; |
||||
m_alloc = NULL; |
||||
} |
||||
|
||||
T * Allocate(void) |
||||
{ |
||||
if(m_free) |
||||
{ |
||||
PoolItem * item = m_free; |
||||
m_free = m_free->next; |
||||
|
||||
item->next = m_alloc; |
||||
m_alloc = item; |
||||
|
||||
T * obj = item->GetObj(); |
||||
|
||||
new (obj) T; |
||||
return obj; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
void Free(T * obj) |
||||
{ |
||||
PoolItem * item = reinterpret_cast <PoolItem *>(obj); |
||||
|
||||
if(item == m_alloc) |
||||
{ |
||||
m_alloc = item->next; |
||||
} |
||||
else |
||||
{ |
||||
PoolItem * traverse = m_alloc; |
||||
while(traverse->next != item) |
||||
traverse = traverse->next; |
||||
traverse->next = traverse->next->next; |
||||
} |
||||
|
||||
item->next = m_free; |
||||
m_free = item; |
||||
|
||||
obj->~T(); |
||||
} |
||||
|
||||
UInt32 GetSize(void) { return size; } |
||||
|
||||
T * Begin(void) |
||||
{ |
||||
T * result = NULL; |
||||
|
||||
if(m_alloc) |
||||
result = m_alloc->GetObj(); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
T * Next(T * obj) |
||||
{ |
||||
PoolItem * item = reinterpret_cast <PoolItem *>(obj); |
||||
PoolItem * next = item->next; |
||||
T * result = NULL; |
||||
|
||||
if(next) |
||||
result = next->GetObj(); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
void Dump(void) |
||||
{ |
||||
gLog.Indent(); |
||||
|
||||
_DMESSAGE("free:"); |
||||
gLog.Indent(); |
||||
for(PoolItem * traverse = m_free; traverse; traverse = traverse->next) |
||||
_DMESSAGE("%08X", traverse); |
||||
gLog.Outdent(); |
||||
|
||||
_DMESSAGE("alloc:"); |
||||
gLog.Indent(); |
||||
for(PoolItem * traverse = m_alloc; traverse; traverse = traverse->next) |
||||
_DMESSAGE("%08X", traverse); |
||||
gLog.Outdent(); |
||||
|
||||
gLog.Outdent(); |
||||
} |
||||
|
||||
bool Full(void) |
||||
{ |
||||
return m_free == NULL; |
||||
} |
||||
|
||||
bool Empty(void) |
||||
{ |
||||
return m_alloc == NULL; |
||||
} |
||||
|
||||
void Clear(void) |
||||
{ |
||||
while(m_alloc) |
||||
Free(m_alloc->GetObj()); |
||||
} |
||||
|
||||
private: |
||||
struct PoolItem |
||||
{ |
||||
UInt8 obj[sizeof(T)]; |
||||
PoolItem * next; |
||||
|
||||
T * GetObj(void) { return reinterpret_cast <T *>(obj); } |
||||
}; |
||||
|
||||
PoolItem m_items[size]; |
||||
PoolItem * m_free; |
||||
PoolItem * m_alloc; |
||||
}; |
||||
|
||||
template <typename T, UInt32 size> |
||||
class IBasicMemPool |
||||
{ |
||||
public: |
||||
IBasicMemPool() |
||||
:m_free(NULL) |
||||
{ |
||||
Reset(); |
||||
} |
||||
|
||||
~IBasicMemPool() { } |
||||
|
||||
void Reset(void) |
||||
{ |
||||
for(UInt32 i = 0; i < size - 1; i++) |
||||
{ |
||||
m_items[i].next = &m_items[i + 1]; |
||||
} |
||||
|
||||
m_items[size - 1].next = NULL; |
||||
m_free = m_items; |
||||
} |
||||
|
||||
T * Allocate(void) |
||||
{ |
||||
if(m_free) |
||||
{ |
||||
PoolItem * item = m_free; |
||||
m_free = m_free->next; |
||||
|
||||
T * obj = item->GetObj(); |
||||
|
||||
new (obj) T; |
||||
return obj; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
void Free(T * obj) |
||||
{ |
||||
obj->~T(); |
||||
|
||||
PoolItem * item = reinterpret_cast <PoolItem *>(obj); |
||||
|
||||
item->next = m_free; |
||||
m_free = item; |
||||
} |
||||
|
||||
UInt32 GetSize(void) { return size; } |
||||
|
||||
bool Full(void) |
||||
{ |
||||
return m_free == NULL; |
||||
} |
||||
|
||||
UInt32 GetIdx(T * obj) |
||||
{ |
||||
PoolItem * item = reinterpret_cast <PoolItem *>(obj); |
||||
|
||||
return item - m_items; |
||||
} |
||||
|
||||
T * GetByID(UInt32 id) |
||||
{ |
||||
return m_items[id].GetObj(); |
||||
} |
||||
|
||||
private: |
||||
union PoolItem |
||||
{ |
||||
UInt8 obj[sizeof(T)]; |
||||
PoolItem * next; |
||||
|
||||
T * GetObj(void) { return reinterpret_cast <T *>(obj); } |
||||
}; |
||||
|
||||
PoolItem m_items[size]; |
||||
PoolItem * m_free; |
||||
}; |
||||
|
||||
template <typename T, UInt32 size> |
||||
class IThreadSafeBasicMemPool |
||||
{ |
||||
public: |
||||
IThreadSafeBasicMemPool() |
||||
:m_free(NULL) |
||||
{ |
||||
Reset(); |
||||
} |
||||
|
||||
~IThreadSafeBasicMemPool() { } |
||||
|
||||
void Reset(void) |
||||
{ |
||||
m_mutex.Enter(); |
||||
|
||||
for(UInt32 i = 0; i < size - 1; i++) |
||||
{ |
||||
m_items[i].next = &m_items[i + 1]; |
||||
} |
||||
|
||||
m_items[size - 1].next = NULL; |
||||
m_free = m_items; |
||||
|
||||
m_mutex.Leave(); |
||||
} |
||||
|
||||
T * Allocate(void) |
||||
{ |
||||
T * result = NULL; |
||||
|
||||
m_mutex.Enter(); |
||||
|
||||
if(m_free) |
||||
{ |
||||
PoolItem * item = m_free; |
||||
m_free = m_free->next; |
||||
|
||||
m_mutex.Leave(); |
||||
|
||||
result = item->GetObj(); |
||||
|
||||
new (result) T; |
||||
} |
||||
else |
||||
{ |
||||
m_mutex.Leave(); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
void Free(T * obj) |
||||
{ |
||||
obj->~T(); |
||||
|
||||
PoolItem * item = reinterpret_cast <PoolItem *>(obj); |
||||
|
||||
m_mutex.Enter(); |
||||
|
||||
item->next = m_free; |
||||
m_free = item; |
||||
|
||||
m_mutex.Leave(); |
||||
} |
||||
|
||||
UInt32 GetSize(void) { return size; } |
||||
|
||||
bool Full(void) |
||||
{ |
||||
return m_free == NULL; |
||||
} |
||||
|
||||
private: |
||||
union PoolItem |
||||
{ |
||||
UInt8 obj[sizeof(T)]; |
||||
PoolItem * next; |
||||
|
||||
T * GetObj(void) { return reinterpret_cast <T *>(obj); } |
||||
}; |
||||
|
||||
PoolItem m_items[size]; |
||||
PoolItem * m_free; |
||||
|
||||
ICriticalSection m_mutex; |
||||
}; |
||||
|
||||
void Test_IMemPool(void); |
@ -0,0 +1,34 @@ |
||||
#include "IMutex.h" |
||||
|
||||
IMutex::IMutex() |
||||
{ |
||||
theMutex = CreateMutex(NULL, true, NULL); |
||||
} |
||||
|
||||
IMutex::~IMutex() |
||||
{ |
||||
CloseHandle(theMutex); |
||||
} |
||||
|
||||
bool IMutex::Wait(UInt32 timeout) |
||||
{ |
||||
switch(WaitForSingleObject(theMutex, timeout)) |
||||
{ |
||||
case WAIT_ABANDONED: |
||||
HALT("IMutex::Wait: got abandoned mutex"); |
||||
return false; |
||||
|
||||
case WAIT_OBJECT_0: |
||||
return true; |
||||
|
||||
default: |
||||
case WAIT_TIMEOUT: |
||||
gLog.FormattedMessage("IMutex::Wait: timeout"); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
void IMutex::Release(void) |
||||
{ |
||||
ASSERT_STR(ReleaseMutex(theMutex), "IMutex::Release: failed to release mutex"); |
||||
} |
@ -0,0 +1,16 @@ |
||||
#pragma once |
||||
|
||||
class IMutex |
||||
{ |
||||
public: |
||||
static const UInt32 kDefaultTimeout = 1000 * 10; |
||||
|
||||
IMutex(); |
||||
~IMutex(); |
||||
|
||||
bool Wait(UInt32 timeout = kDefaultTimeout); |
||||
void Release(void); |
||||
|
||||
private: |
||||
HANDLE theMutex; |
||||
}; |
@ -0,0 +1,60 @@ |
||||
#include "IPipeClient.h" |
||||
|
||||
IPipeClient::IPipeClient() |
||||
:m_pipe(INVALID_HANDLE_VALUE) |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
IPipeClient::~IPipeClient() |
||||
{ |
||||
Close(); |
||||
} |
||||
|
||||
bool IPipeClient::Open(const char * name) |
||||
{ |
||||
Close(); |
||||
|
||||
m_pipe = CreateFile( |
||||
name, |
||||
GENERIC_READ | GENERIC_WRITE, |
||||
0, |
||||
NULL, |
||||
OPEN_EXISTING, |
||||
0, |
||||
NULL); |
||||
|
||||
return m_pipe != INVALID_HANDLE_VALUE; |
||||
} |
||||
|
||||
void IPipeClient::Close(void) |
||||
{ |
||||
if(m_pipe != INVALID_HANDLE_VALUE) |
||||
{ |
||||
CloseHandle(m_pipe); |
||||
m_pipe = INVALID_HANDLE_VALUE; |
||||
} |
||||
} |
||||
|
||||
bool IPipeClient::ReadMessage(UInt8 * buf, UInt32 length) |
||||
{ |
||||
UInt32 bytesRead; |
||||
|
||||
ReadFile(m_pipe, buf, length, &bytesRead, NULL); |
||||
|
||||
IPipeServer::MessageHeader * header = (IPipeServer::MessageHeader *)buf; |
||||
|
||||
return |
||||
(bytesRead >= sizeof(IPipeServer::MessageHeader)) && // has a valid header
|
||||
(bytesRead >= (sizeof(IPipeServer::MessageHeader) + header->length)); |
||||
} |
||||
|
||||
bool IPipeClient::WriteMessage(IPipeServer::MessageHeader * msg) |
||||
{ |
||||
UInt32 bytesWritten; |
||||
UInt32 length = sizeof(IPipeServer::MessageHeader) + msg->length; |
||||
|
||||
WriteFile(m_pipe, msg, length, &bytesWritten, NULL); |
||||
|
||||
return bytesWritten >= length; |
||||
} |
@ -0,0 +1,20 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IPipeServer.h" |
||||
|
||||
class IPipeClient |
||||
{ |
||||
public: |
||||
IPipeClient(); |
||||
virtual ~IPipeClient(); |
||||
|
||||
bool Open(const char * name); |
||||
void Close(void); |
||||
|
||||
bool ReadMessage(UInt8 * buf, UInt32 length); |
||||
bool WriteMessage(IPipeServer::MessageHeader * msg); |
||||
|
||||
private: |
||||
HANDLE m_pipe; |
||||
std::string m_name; |
||||
}; |
@ -0,0 +1,74 @@ |
||||
#include "IPipeServer.h" |
||||
|
||||
IPipeServer::IPipeServer() |
||||
:m_pipe(INVALID_HANDLE_VALUE) |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
IPipeServer::~IPipeServer() |
||||
{ |
||||
Close(); |
||||
} |
||||
|
||||
bool IPipeServer::Open(const char * name) |
||||
{ |
||||
Close(); |
||||
|
||||
m_pipe = CreateNamedPipe( |
||||
name, |
||||
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE, |
||||
PIPE_TYPE_MESSAGE | PIPE_TYPE_MESSAGE | PIPE_WAIT, |
||||
PIPE_UNLIMITED_INSTANCES, |
||||
8192, 8192, |
||||
10 * 1000, // 10 seconds
|
||||
NULL); |
||||
|
||||
return m_pipe != INVALID_HANDLE_VALUE; |
||||
} |
||||
|
||||
void IPipeServer::Close(void) |
||||
{ |
||||
if(m_pipe != INVALID_HANDLE_VALUE) |
||||
{ |
||||
CloseHandle(m_pipe); |
||||
m_pipe = INVALID_HANDLE_VALUE; |
||||
} |
||||
} |
||||
|
||||
bool IPipeServer::WaitForClient(void) |
||||
{ |
||||
bool result = ConnectNamedPipe(m_pipe, NULL) != 0; |
||||
|
||||
// already connected?
|
||||
if(!result) |
||||
{ |
||||
if(GetLastError() == ERROR_PIPE_CONNECTED) |
||||
result = true; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
bool IPipeServer::ReadMessage(UInt8 * buf, UInt32 length) |
||||
{ |
||||
UInt32 bytesRead; |
||||
|
||||
ReadFile(m_pipe, buf, length, &bytesRead, NULL); |
||||
|
||||
MessageHeader * header = (MessageHeader *)buf; |
||||
|
||||
return |
||||
(bytesRead >= sizeof(MessageHeader)) && // has a valid header
|
||||
(bytesRead >= (sizeof(MessageHeader) + header->length)); |
||||
} |
||||
|
||||
bool IPipeServer::WriteMessage(MessageHeader * msg) |
||||
{ |
||||
UInt32 bytesWritten; |
||||
UInt32 length = sizeof(MessageHeader) + msg->length; |
||||
|
||||
WriteFile(m_pipe, msg, length, &bytesWritten, NULL); |
||||
|
||||
return bytesWritten >= length; |
||||
} |
@ -0,0 +1,25 @@ |
||||
#pragma once |
||||
|
||||
class IPipeServer |
||||
{ |
||||
public: |
||||
struct MessageHeader |
||||
{ |
||||
UInt32 type; |
||||
UInt32 length; |
||||
}; |
||||
|
||||
IPipeServer(); |
||||
virtual ~IPipeServer(); |
||||
|
||||
bool Open(const char * name); |
||||
void Close(void); |
||||
|
||||
bool WaitForClient(void); |
||||
|
||||
bool ReadMessage(UInt8 * buf, UInt32 length); |
||||
bool WriteMessage(MessageHeader * msg); |
||||
|
||||
private: |
||||
HANDLE m_pipe; |
||||
}; |
@ -0,0 +1 @@ |
||||
#include "IPrefix.h" |
@ -0,0 +1,23 @@ |
||||
#pragma once |
||||
|
||||
// 4018 - signed/unsigned mismatch
|
||||
// 4200 - zero-sized array
|
||||
// 4244 - loss of data by assignment
|
||||
// 4267 - possible loss of data (truncation)
|
||||
// 4305 - truncation by assignment
|
||||
// 4288 - disable warning for crap microsoft extension screwing up the scope of variables defined in for loops
|
||||
// 4311 - pointer truncation
|
||||
// 4312 - pointer extension
|
||||
#pragma warning(disable: 4018 4200 4244 4267 4305 4288 4312 4311) |
||||
|
||||
#include <cstdlib> |
||||
#include <cstdio> |
||||
#include <cstring> |
||||
#include <string> |
||||
#include "common/ITypes.h" |
||||
#include "common/IErrors.h" |
||||
#include "common/IDynamicCreate.h" |
||||
#include "common/IDebugLog.h" |
||||
#include "common/ISingleton.h" |
||||
#include <winsock2.h> |
||||
#include <Windows.h> |
@ -0,0 +1 @@ |
||||
#include "IRangeMap.h" |
@ -0,0 +1,215 @@ |
||||
#pragma once |
||||
|
||||
#include <map> |
||||
|
||||
// t_key must be a numeric type
|
||||
// ### you can't create a range taking up the entire range of t_key
|
||||
// ### (could be done by switching from start/length -> start/end)
|
||||
template <typename t_key, typename t_data> |
||||
class IRangeMap |
||||
{ |
||||
public: |
||||
struct Entry |
||||
{ |
||||
bool Contains(t_key addr, t_key base) |
||||
{ |
||||
return (addr >= base) && (addr <= (base + length - 1)); |
||||
} |
||||
|
||||
t_key length; |
||||
t_data data; |
||||
}; |
||||
|
||||
typedef std::map <t_key, Entry> EntryMapType; |
||||
typedef typename EntryMapType::iterator Iterator; |
||||
|
||||
IRangeMap() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
virtual ~IRangeMap() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
void Clear(void) |
||||
{ |
||||
m_entries.clear(); |
||||
} |
||||
|
||||
t_data * Add(t_key start, t_key length) |
||||
{ |
||||
t_data * result = NULL; |
||||
Entry * entry = NULL; |
||||
|
||||
t_key end = start + length - 1; |
||||
|
||||
if(end >= start) // check for overflow ### should also check for overflow on length - 1, but that's pedantic
|
||||
{ |
||||
// special-case empty lists
|
||||
if(m_entries.empty()) |
||||
{ |
||||
entry = &m_entries[start]; |
||||
} |
||||
else |
||||
{ |
||||
// collision check
|
||||
|
||||
EntryMapType::iterator iter = m_entries.lower_bound(start); |
||||
// iter contains the first entry at or after start (or null)
|
||||
|
||||
if(iter == m_entries.begin()) |
||||
{ |
||||
// there can't be anything before this entry
|
||||
// so we only need to check if it's colliding with us
|
||||
|
||||
if(iter->first > end) |
||||
{ |
||||
// can't provide a hint because we're inserting at the top
|
||||
entry = &m_entries[start]; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// see if this entry doesn't collide
|
||||
// can be null (null entries don't collide)
|
||||
if((iter == m_entries.end()) || (iter->first > end)) |
||||
{ |
||||
// we didn't get the first entry in the map
|
||||
// and there is at least one entry in the map
|
||||
// therefore there's an entry before iter
|
||||
EntryMapType::iterator preIter = iter; |
||||
preIter--; |
||||
|
||||
// check if this collides
|
||||
// guaranteed to be the first entry before start
|
||||
t_key preEnd = preIter->first + preIter->second.length - 1; |
||||
|
||||
if(preEnd < start) |
||||
{ |
||||
// cool, everything's fine, allocate it
|
||||
EntryMapType::iterator newEntry = m_entries.insert(preIter, EntryMapType::value_type(start, Entry())); |
||||
entry = &newEntry->second; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// set up the entry
|
||||
if(entry) |
||||
{ |
||||
entry->length = length; |
||||
|
||||
result = &entry->data; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
t_data * Lookup(t_key addr, t_key * base = NULL, t_key * length = NULL) |
||||
{ |
||||
t_data * result = NULL; |
||||
|
||||
EntryMapType::iterator iter = LookupIter(addr); |
||||
if(iter != m_entries.end()) |
||||
{ |
||||
if(base) *base = iter->first; |
||||
if(length) *length = iter->second.length; |
||||
|
||||
result = &iter->second.data; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
bool Erase(t_key addr, t_key * base = NULL, t_key * length = NULL) |
||||
{ |
||||
bool result = false; |
||||
|
||||
EntryMapType::iterator iter = LookupIter(addr); |
||||
if(iter != m_entries.end()) |
||||
{ |
||||
if(base) *base = iter->first; |
||||
if(length) *length = iter->second.length; |
||||
|
||||
m_entries.erase(iter); |
||||
|
||||
result = true; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
t_key GetDataRangeLength(t_data * data) |
||||
{ |
||||
Entry * entry = reinterpret_cast <Entry *>(reinterpret_cast <UInt8 *>(data) - offsetof(Entry, data)); |
||||
|
||||
return entry->length; |
||||
} |
||||
|
||||
typename EntryMapType::iterator LookupIter(t_key addr) |
||||
{ |
||||
EntryMapType::iterator result = m_entries.end(); |
||||
|
||||
if(!m_entries.empty()) |
||||
{ |
||||
// we need to find the last entry less than or equal to addr
|
||||
|
||||
// find the first entry not less than addr
|
||||
EntryMapType::iterator iter = m_entries.lower_bound(addr); |
||||
|
||||
// iter is either equal to addr, greater than addr, or the end
|
||||
if(iter == m_entries.end()) |
||||
{ |
||||
// iter is the end
|
||||
// can only be in the entry before this
|
||||
// which does exist because map isn't empty
|
||||
--iter; |
||||
|
||||
if(iter->second.Contains(addr, iter->first)) |
||||
{ |
||||
result = iter; |
||||
} |
||||
} |
||||
// at this point iter must be valid
|
||||
else if(iter->first > addr) |
||||
{ |
||||
// iter is greater than addr
|
||||
// can only be in the entry before this
|
||||
// but there may not be an entry before this
|
||||
|
||||
if(iter != m_entries.begin()) |
||||
{ |
||||
--iter; |
||||
|
||||
if(iter->second.Contains(addr, iter->first)) |
||||
{ |
||||
result = iter; |
||||
} |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
// iter is equal to addr and matches
|
||||
result = iter; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
typename EntryMapType::iterator Begin(void) |
||||
{ |
||||
return m_entries.begin(); |
||||
} |
||||
|
||||
typename EntryMapType::iterator End(void) |
||||
{ |
||||
return m_entries.end(); |
||||
} |
||||
|
||||
private: |
||||
EntryMapType m_entries; |
||||
}; |
@ -0,0 +1,43 @@ |
||||
#include "IReadWriteLock.h" |
||||
|
||||
IReadWriteLock::IReadWriteLock() |
||||
{ |
||||
readCount.Set(0); |
||||
readBlocker.UnBlock(); |
||||
writeBlocker.UnBlock(); |
||||
} |
||||
|
||||
IReadWriteLock::~IReadWriteLock() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
void IReadWriteLock::StartRead(void) |
||||
{ |
||||
enterBlocker.Enter(); |
||||
readBlocker.Wait(); |
||||
if(readCount.Increment() == 1) |
||||
writeBlocker.Block(); |
||||
enterBlocker.Leave(); |
||||
} |
||||
|
||||
void IReadWriteLock::EndRead(void) |
||||
{ |
||||
if(!readCount.Decrement()) |
||||
writeBlocker.UnBlock(); |
||||
} |
||||
|
||||
void IReadWriteLock::StartWrite(void) |
||||
{ |
||||
writeMutex.Enter(); |
||||
enterBlocker.Enter(); |
||||
readBlocker.Block(); |
||||
writeBlocker.Wait(); |
||||
enterBlocker.Leave(); |
||||
} |
||||
|
||||
void IReadWriteLock::EndWrite(void) |
||||
{ |
||||
readBlocker.UnBlock(); |
||||
writeMutex.Leave(); |
||||
} |
@ -0,0 +1,24 @@ |
||||
#pragma once |
||||
|
||||
#include "common/ICriticalSection.h" |
||||
#include "common/IEvent.h" |
||||
#include "common/IInterlockedLong.h" |
||||
|
||||
class IReadWriteLock |
||||
{ |
||||
public: |
||||
IReadWriteLock(); |
||||
~IReadWriteLock(); |
||||
|
||||
void StartRead(void); |
||||
void EndRead(void); |
||||
void StartWrite(void); |
||||
void EndWrite(void); |
||||
|
||||
private: |
||||
IEvent readBlocker; |
||||
IEvent writeBlocker; |
||||
ICriticalSection enterBlocker; |
||||
ICriticalSection writeMutex; |
||||
IInterlockedLong readCount; |
||||
}; |
@ -0,0 +1,76 @@ |
||||
#include "common/ISegmentStream.h" |
||||
|
||||
ISegmentStream::ISegmentStream() |
||||
{ |
||||
streamLength = 0; |
||||
} |
||||
|
||||
ISegmentStream::~ISegmentStream() |
||||
{ |
||||
|
||||
} |
||||
|
||||
void ISegmentStream::AttachStream(IDataStream * inStream) |
||||
{ |
||||
parent = inStream; |
||||
streamLength = 0; |
||||
streamOffset = 0; |
||||
} |
||||
|
||||
void ISegmentStream::AddSegment(UInt64 offset, UInt64 length, UInt64 parentOffset) |
||||
{ |
||||
segmentInfo.push_back(SegmentInfo(offset, length, parentOffset)); |
||||
|
||||
if(streamLength < (parentOffset + length)) |
||||
streamLength = parentOffset + length; |
||||
} |
||||
|
||||
void ISegmentStream::ReadBuf(void * buf, UInt32 inLength) |
||||
{ |
||||
UInt32 remain = inLength; |
||||
UInt8 * out = (UInt8 *)buf; |
||||
|
||||
while(remain > 0) |
||||
{ |
||||
SegmentInfo * info = LookupInfo(streamOffset); |
||||
ASSERT(info); |
||||
|
||||
UInt64 segmentOffset = streamOffset - info->offset; |
||||
UInt64 transferLength = info->length - segmentOffset; |
||||
|
||||
if(transferLength > remain) |
||||
transferLength = remain; |
||||
|
||||
parent->SetOffset(info->parentOffset + segmentOffset); |
||||
parent->ReadBuf(out, transferLength); |
||||
|
||||
streamOffset += transferLength; |
||||
remain -= transferLength; |
||||
} |
||||
} |
||||
|
||||
void ISegmentStream::WriteBuf(const void * buf, UInt32 inLength) |
||||
{ |
||||
HALT("ISegmentStream::WriteBuf: writing unsupported"); |
||||
} |
||||
|
||||
void ISegmentStream::SetOffset(SInt64 inOffset) |
||||
{ |
||||
SegmentInfo * info = LookupInfo(inOffset); |
||||
ASSERT(info); |
||||
|
||||
UInt64 segmentOffset = inOffset - info->offset; |
||||
|
||||
parent->SetOffset(info->parentOffset + segmentOffset); |
||||
|
||||
streamOffset = inOffset; |
||||
} |
||||
|
||||
ISegmentStream::SegmentInfo * ISegmentStream::LookupInfo(UInt64 offset) |
||||
{ |
||||
for(SegmentInfoListType::iterator iter = segmentInfo.begin(); iter != segmentInfo.end(); iter++) |
||||
if((offset >= (*iter).offset) && (offset < (*iter).offset + (*iter).length)) |
||||
return &(*iter); |
||||
|
||||
return NULL; |
||||
} |
@ -0,0 +1,44 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IDataStream.h" |
||||
#include <vector> |
||||
|
||||
/**
|
||||
* An stream composed of many non-contiguous segments of a larger stream |
||||
*/ |
||||
class ISegmentStream : public IDataStream |
||||
{ |
||||
public: |
||||
ISegmentStream(); |
||||
~ISegmentStream(); |
||||
|
||||
void AttachStream(IDataStream * inStream); |
||||
|
||||
void AddSegment(UInt64 offset, UInt64 length, UInt64 parentOffset); |
||||
|
||||
virtual void ReadBuf(void * buf, UInt32 inLength); |
||||
virtual void WriteBuf(const void * buf, UInt32 inLength); |
||||
virtual void SetOffset(SInt64 inOffset); |
||||
|
||||
protected: |
||||
IDataStream * parent; |
||||
|
||||
struct SegmentInfo |
||||
{ |
||||
SegmentInfo(UInt64 inOffset, UInt64 inLength, UInt64 inParentOffset) |
||||
{ |
||||
offset = inOffset; |
||||
length = inLength; |
||||
parentOffset = inParentOffset; |
||||
} |
||||
|
||||
UInt64 offset; |
||||
UInt64 length; |
||||
UInt64 parentOffset; |
||||
}; |
||||
|
||||
typedef std::vector <SegmentInfo> SegmentInfoListType; |
||||
SegmentInfoListType segmentInfo; |
||||
|
||||
SegmentInfo * LookupInfo(UInt64 offset); |
||||
}; |
@ -0,0 +1,3 @@ |
||||
#include "common/ISingleton.h" |
||||
|
||||
//template <typename T> T * Singleton <T>::ms_Singleton = 0;
|
@ -0,0 +1,53 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IErrors.h" |
||||
|
||||
#pragma warning(push) |
||||
#pragma warning(disable: 4311 4312) |
||||
|
||||
/**
|
||||
* A singleton base class |
||||
*
|
||||
* Singletons are useful when you have a class that will be instantiated once, |
||||
* like a global manager. |
||||
*/ |
||||
template <typename T> |
||||
class ISingleton |
||||
{ |
||||
static T * ms_Singleton; |
||||
|
||||
public: |
||||
ISingleton() |
||||
{ |
||||
ASSERT(!ms_Singleton); |
||||
intptr_t offset = (intptr_t)(T *)1 - (intptr_t)(ISingleton <T> *)(T *)1; |
||||
ms_Singleton = (T *)((intptr_t)this + offset); |
||||
} |
||||
|
||||
virtual ~ISingleton() |
||||
{ |
||||
ASSERT(ms_Singleton); |
||||
ms_Singleton = 0; |
||||
} |
||||
|
||||
/**
|
||||
* Returns the single instance of the derived class |
||||
*/ |
||||
static T& GetSingleton(void) |
||||
{ |
||||
ASSERT(ms_Singleton); |
||||
return *ms_Singleton; |
||||
} |
||||
|
||||
/**
|
||||
* Returns a pointer to the single instance of the derived class |
||||
*/ |
||||
static T * GetSingletonPtr(void) |
||||
{ |
||||
return ms_Singleton; |
||||
} |
||||
}; |
||||
|
||||
template <typename T> T * ISingleton <T>::ms_Singleton = 0; |
||||
|
||||
#pragma warning(pop) |
@ -0,0 +1,83 @@ |
||||
#include "ITextParser.h" |
||||
#include "IDataStream.h" |
||||
|
||||
ITextParser::ITextParser() |
||||
:m_stream(NULL) |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
ITextParser::ITextParser(IDataStream * stream) |
||||
:m_stream(stream) |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
ITextParser::~ITextParser() |
||||
{ |
||||
//
|
||||
} |
||||
|
||||
void ITextParser::Attach(IDataStream * stream) |
||||
{ |
||||
m_stream = stream; |
||||
} |
||||
|
||||
void ITextParser::SkipWhitespace(void) |
||||
{ |
||||
while(!m_stream->HitEOF()) |
||||
{ |
||||
char data = m_stream->Peek8(); |
||||
|
||||
if(!isspace(data)) |
||||
break; |
||||
|
||||
m_stream->Skip(1); |
||||
} |
||||
} |
||||
|
||||
void ITextParser::SkipLine(void) |
||||
{ |
||||
while(!m_stream->HitEOF()) |
||||
{ |
||||
char data = m_stream->Peek8(); |
||||
|
||||
if((data != '\n') && (data != '\r')) |
||||
break; |
||||
|
||||
m_stream->Skip(1); |
||||
} |
||||
} |
||||
|
||||
void ITextParser::ReadLine(char * out, UInt32 length) |
||||
{ |
||||
m_stream->ReadString(out, length, '\n', '\r'); |
||||
} |
||||
|
||||
void ITextParser::ReadToken(char * buf, UInt32 bufLength) |
||||
{ |
||||
char * traverse = buf; |
||||
|
||||
ASSERT_STR(bufLength > 0, "ITextParser::ReadToken: zero-sized buffer"); |
||||
|
||||
if(bufLength == 1) |
||||
{ |
||||
buf[0] = 0; |
||||
} |
||||
else |
||||
{ |
||||
bufLength--; |
||||
|
||||
for(UInt32 i = 0; (i < bufLength) && !m_stream->HitEOF(); i++) |
||||
{ |
||||
UInt8 data = m_stream->Read8(); |
||||
|
||||
if(isspace(data) || !data) |
||||
break; |
||||
|
||||
*traverse++ = data; |
||||
} |
||||
|
||||
*traverse++ = 0; |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IDataStream.h" |
||||
|
||||
class ITextParser |
||||
{ |
||||
public: |
||||
ITextParser(); |
||||
ITextParser(IDataStream * stream); |
||||
~ITextParser(); |
||||
|
||||
void Attach(IDataStream * stream); |
||||
IDataStream * GetStream(void) { return m_stream; } |
||||
|
||||
bool HitEOF(void) { return m_stream->HitEOF(); } |
||||
|
||||
void SkipWhitespace(void); |
||||
void SkipLine(void); |
||||
|
||||
void ReadLine(char * out, UInt32 length); |
||||
void ReadToken(char * out, UInt32 length); |
||||
|
||||
private: |
||||
IDataStream * m_stream; |
||||
}; |
@ -0,0 +1,65 @@ |
||||
#include "IThread.h" |
||||
|
||||
IThread::IThread() |
||||
{ |
||||
mainProc = NULL; |
||||
mainProcParam = NULL; |
||||
stopRequested = false; |
||||
isRunning = false; |
||||
theThread = NULL; |
||||
threadID = 0; |
||||
} |
||||
|
||||
IThread::~IThread() |
||||
{ |
||||
ForceStop(); |
||||
|
||||
if(theThread) |
||||
{ |
||||
CloseHandle(theThread); |
||||
} |
||||
} |
||||
|
||||
void IThread::Start(MainProcPtr proc, void * procParam) |
||||
{ |
||||
if(!isRunning) |
||||
{ |
||||
isRunning = true; |
||||
stopRequested = false; |
||||
|
||||
mainProc = proc; |
||||
mainProcParam = procParam; |
||||
|
||||
theThread = CreateThread(NULL, 0, _ThreadProc, static_cast<IThread *>(this), 0, &threadID); |
||||
} |
||||
} |
||||
|
||||
void IThread::Stop(void) |
||||
{ |
||||
if(isRunning) |
||||
{ |
||||
stopRequested = true; |
||||
} |
||||
} |
||||
|
||||
void IThread::ForceStop(void) |
||||
{ |
||||
if(isRunning) |
||||
{ |
||||
TerminateThread(theThread, 0); |
||||
|
||||
isRunning = false; |
||||
} |
||||
} |
||||
|
||||
UInt32 IThread::_ThreadProc(void * param) |
||||
{ |
||||
IThread * _this = (IThread *)param; |
||||
|
||||
if(_this->mainProc) |
||||
_this->mainProc(_this->mainProcParam); |
||||
|
||||
_this->isRunning = false; |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,32 @@ |
||||
#pragma once |
||||
|
||||
// TODO: I really don't like the interface for this
|
||||
|
||||
class IThread |
||||
{ |
||||
public: |
||||
typedef void (* MainProcPtr)(void * param); |
||||
|
||||
IThread(); |
||||
~IThread(); |
||||
|
||||
void Start(MainProcPtr proc, void * procParam = NULL); |
||||
void Stop(void); |
||||
void ForceStop(void); |
||||
|
||||
bool IsRunning(void) { return isRunning; } |
||||
bool StopRequested(void) { return stopRequested; } |
||||
|
||||
HANDLE GetHandle(void) { return theThread; } |
||||
|
||||
protected: |
||||
MainProcPtr mainProc; |
||||
void * mainProcParam; |
||||
volatile bool stopRequested; |
||||
bool isRunning; |
||||
HANDLE theThread; |
||||
UInt32 threadID; |
||||
|
||||
private: |
||||
static UInt32 WINAPI _ThreadProc(void * param); |
||||
}; |
@ -0,0 +1,133 @@ |
||||
#include "ITimer.h" |
||||
|
||||
// QueryPerformanceCounter is very accurate, but hardware bugs can cause it to return inaccurate results
|
||||
// this code uses multimedia timers to check for glitches in QPC
|
||||
|
||||
double ITimer::s_secondsPerCount = 0; |
||||
TIMECAPS ITimer::s_timecaps = { 0 }; |
||||
bool ITimer::s_setTime = false; |
||||
UInt64 ITimer::s_lastQPC = 0; |
||||
UInt64 ITimer::s_qpcWrapMargin = 0; |
||||
bool ITimer::s_hasLastQPC = false; |
||||
UInt32 ITimer::s_qpcWrapCount = 0; |
||||
UInt32 ITimer::s_qpcInaccurateCount = 0; |
||||
|
||||
ITimer::ITimer() |
||||
:m_qpcBase(0), m_tickBase(0) |
||||
{ |
||||
Init(); |
||||
} |
||||
|
||||
ITimer::~ITimer() |
||||
{ |
||||
|
||||
} |
||||
|
||||
void ITimer::Init(void) |
||||
{ |
||||
if(!s_secondsPerCount) |
||||
{ |
||||
// init qpc
|
||||
UInt64 countsPerSecond; |
||||
BOOL res = QueryPerformanceFrequency((LARGE_INTEGER *)&countsPerSecond); |
||||
|
||||
ASSERT_STR(res, "ITimer: no high-resolution timer support"); |
||||
|
||||
s_secondsPerCount = 1.0 / countsPerSecond; |
||||
|
||||
s_qpcWrapMargin = (UInt64)(-((SInt64)(countsPerSecond * 60))); // detect if we've wrapped around by a delta greater than this - also limits max time
|
||||
_MESSAGE("s_qpcWrapMargin: %016I64X", s_qpcWrapMargin); |
||||
_MESSAGE("wrap time: %fs", ((double)0xFFFFFFFFFFFFFFFF) * s_secondsPerCount); |
||||
|
||||
// init multimedia timer
|
||||
timeGetDevCaps(&s_timecaps, sizeof(s_timecaps)); |
||||
|
||||
_MESSAGE("min timer period = %d", s_timecaps.wPeriodMin); |
||||
|
||||
s_setTime = (timeBeginPeriod(s_timecaps.wPeriodMin) == TIMERR_NOERROR); |
||||
if(!s_setTime) |
||||
_WARNING("couldn't change timer period"); |
||||
} |
||||
} |
||||
|
||||
void ITimer::DeInit(void) |
||||
{ |
||||
if(s_secondsPerCount) |
||||
{ |
||||
if(s_setTime) |
||||
{ |
||||
timeEndPeriod(s_timecaps.wPeriodMin); |
||||
s_setTime = false; |
||||
} |
||||
|
||||
if(s_qpcWrapCount) |
||||
_MESSAGE("s_qpcWrapCount: %d", s_qpcWrapCount); |
||||
|
||||
s_secondsPerCount = 0; |
||||
} |
||||
} |
||||
|
||||
void ITimer::Start(void) |
||||
{ |
||||
m_qpcBase = GetQPC(); |
||||
m_tickBase = timeGetTime(); |
||||
} |
||||
|
||||
double ITimer::GetElapsedTime(void) |
||||
{ |
||||
UInt64 qpcNow = GetQPC(); |
||||
UInt32 tickNow = timeGetTime(); |
||||
|
||||
UInt64 qpcDelta = qpcNow - m_qpcBase; |
||||
UInt64 tickDelta = tickNow - m_tickBase; |
||||
|
||||
double qpcSeconds = ((double)qpcDelta) * s_secondsPerCount; |
||||
double tickSeconds = ((double)tickDelta) * 0.001; // ticks are in milliseconds
|
||||
double qpcTickDelta = qpcSeconds - tickSeconds; |
||||
|
||||
if(qpcTickDelta < 0) qpcTickDelta = -qpcTickDelta; |
||||
|
||||
// if they differ by more than one second, something's wrong, return
|
||||
if(qpcTickDelta > 1) |
||||
{ |
||||
s_qpcInaccurateCount++; |
||||
return tickSeconds; |
||||
} |
||||
else |
||||
{ |
||||
return qpcSeconds; |
||||
} |
||||
} |
||||
|
||||
UInt64 ITimer::GetQPC(void) |
||||
{ |
||||
UInt64 now; |
||||
|
||||
QueryPerformanceCounter((LARGE_INTEGER *)&now); |
||||
|
||||
if(s_hasLastQPC) |
||||
{ |
||||
UInt64 delta = now - s_lastQPC; |
||||
|
||||
if(delta > s_qpcWrapMargin) |
||||
{ |
||||
// we've gone back in time, return a kludged value
|
||||
|
||||
s_lastQPC = now; |
||||
now = s_lastQPC + 1; |
||||
|
||||
s_qpcWrapCount++; |
||||
} |
||||
else |
||||
{ |
||||
s_lastQPC = now; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
s_hasLastQPC = true; |
||||
s_lastQPC = now; |
||||
} |
||||
|
||||
return now; |
||||
} |
@ -0,0 +1,38 @@ |
||||
#pragma once |
||||
|
||||
#include "common/ITypes.h" |
||||
|
||||
/**
|
||||
* A high-resolution timer. |
||||
*/ |
||||
class ITimer |
||||
{ |
||||
public: |
||||
ITimer(); |
||||
~ITimer(); |
||||
|
||||
static void Init(void); |
||||
static void DeInit(void); |
||||
|
||||
void Start(void); |
||||
|
||||
double GetElapsedTime(void); // seconds
|
||||
|
||||
private: |
||||
UInt64 m_qpcBase; // QPC
|
||||
UInt32 m_tickBase; // timeGetTime
|
||||
|
||||
static double s_secondsPerCount; |
||||
static TIMECAPS s_timecaps; |
||||
static bool s_setTime; |
||||
|
||||
// safe QPC stuff
|
||||
static UInt64 GetQPC(void); |
||||
|
||||
static UInt64 s_lastQPC; |
||||
static UInt64 s_qpcWrapMargin; |
||||
static bool s_hasLastQPC; |
||||
|
||||
static UInt32 s_qpcWrapCount; |
||||
static UInt32 s_qpcInaccurateCount; |
||||
}; |
@ -0,0 +1,66 @@ |
||||
#include "ITypes.h" |
||||
|
||||
Bitstring::Bitstring() |
||||
:data(NULL) |
||||
{ |
||||
|
||||
} |
||||
|
||||
Bitstring::Bitstring(UInt32 inLength) |
||||
:data(NULL) |
||||
{ |
||||
Alloc(inLength); |
||||
} |
||||
|
||||
Bitstring::~Bitstring() |
||||
{ |
||||
Dispose(); |
||||
} |
||||
|
||||
void Bitstring::Alloc(UInt32 inLength) |
||||
{ |
||||
Dispose(); |
||||
|
||||
inLength = (inLength + 7) & ~7; |
||||
length = inLength >> 3; |
||||
|
||||
data = new UInt8[length]; |
||||
} |
||||
|
||||
void Bitstring::Dispose(void) |
||||
{ |
||||
delete [] data; |
||||
} |
||||
|
||||
void Bitstring::Clear(void) |
||||
{ |
||||
std::memset(data, 0, length); |
||||
} |
||||
|
||||
void Bitstring::Clear(UInt32 idx) |
||||
{ |
||||
ASSERT_STR(idx < (length << 3), "Bitstring::Clear: out of range"); |
||||
|
||||
data[idx >> 3] &= ~(1 << (idx & 7)); |
||||
} |
||||
|
||||
void Bitstring::Set(UInt32 idx) |
||||
{ |
||||
ASSERT_STR(idx < (length << 3), "Bitstring::Set: out of range"); |
||||
|
||||
data[idx >> 3] |= (1 << (idx & 7)); |
||||
} |
||||
|
||||
bool Bitstring::IsSet(UInt32 idx) |
||||
{ |
||||
ASSERT_STR(idx < (length << 3), "Bitstring::IsSet: out of range"); |
||||
|
||||
return (data[idx >> 3] & (1 << (idx & 7))) ? true : false; |
||||
} |
||||
|
||||
bool Bitstring::IsClear(UInt32 idx) |
||||
{ |
||||
ASSERT_STR(idx < (length << 3), "Bitstring::IsClear: out of range"); |
||||
|
||||
return (data[idx >> 3] & (1 << (idx & 7))) ? false : true; |
||||
} |
@ -0,0 +1,344 @@ |
||||
#pragma once |
||||
|
||||
#include "common/IErrors.h" |
||||
|
||||
#pragma warning(disable: 4221) |
||||
#include <cmath> |
||||
|
||||
typedef unsigned char UInt8; //!< An unsigned 8-bit integer value
|
||||
typedef unsigned short UInt16; //!< An unsigned 16-bit integer value
|
||||
typedef unsigned long UInt32; //!< An unsigned 32-bit integer value
|
||||
typedef unsigned long long UInt64; //!< An unsigned 64-bit integer value
|
||||
typedef signed char SInt8; //!< A signed 8-bit integer value
|
||||
typedef signed short SInt16; //!< A signed 16-bit integer value
|
||||
typedef signed long SInt32; //!< A signed 32-bit integer value
|
||||
typedef signed long long SInt64; //!< A signed 64-bit integer value
|
||||
typedef float Float32; //!< A 32-bit floating point value
|
||||
typedef double Float64; //!< A 64-bit floating point value
|
||||
|
||||
inline UInt32 Extend16(UInt32 in) |
||||
{ |
||||
return (in & 0x8000) ? (0xFFFF0000 | in) : in; |
||||
} |
||||
|
||||
inline UInt32 Extend8(UInt32 in) |
||||
{ |
||||
return (in & 0x80) ? (0xFFFFFF00 | in) : in; |
||||
} |
||||
|
||||
inline UInt16 Swap16(UInt16 in) |
||||
{ |
||||
return ((in >> 8) & 0x00FF) | |
||||
((in << 8) & 0xFF00); |
||||
} |
||||
|
||||
inline UInt32 Swap32(UInt32 in) |
||||
{ |
||||
return ((in >> 24) & 0x000000FF) | |
||||
((in >> 8) & 0x0000FF00) | |
||||
((in << 8) & 0x00FF0000) | |
||||
((in << 24) & 0xFF000000); |
||||
} |
||||
|
||||
inline UInt64 Swap64(UInt64 in) |
||||
{ |
||||
UInt64 temp; |
||||
|
||||
temp = Swap32(in); |
||||
temp <<= 32; |
||||
temp |= Swap32(in >> 32); |
||||
|
||||
return temp; |
||||
} |
||||
|
||||
inline void SwapFloat(float * in) |
||||
{ |
||||
UInt32 * temp = (UInt32 *)in; |
||||
|
||||
*temp = Swap32(*temp); |
||||
} |
||||
|
||||
inline void SwapDouble(double * in) |
||||
{ |
||||
UInt64 * temp = (UInt64 *)in; |
||||
|
||||
*temp = Swap64(*temp); |
||||
} |
||||
|
||||
inline bool IsBigEndian(void) |
||||
{ |
||||
union |
||||
{ |
||||
UInt16 u16; |
||||
UInt8 u8[2]; |
||||
} temp; |
||||
|
||||
temp.u16 = 0x1234; |
||||
|
||||
return temp.u8[0] == 0x12; |
||||
} |
||||
|
||||
inline bool IsLittleEndian(void) |
||||
{ |
||||
return !IsBigEndian(); |
||||
} |
||||
|
||||
#define CHAR_CODE(a, b, c, d) (((a & 0xFF) << 0) | ((b & 0xFF) << 8) | ((c & 0xFF) << 16) | ((d & 0xFF) << 24)) |
||||
#define MACRO_SWAP16(a) ((((a) & 0x00FF) << 8) | (((a) & 0xFF00) >> 8)) |
||||
#define MACRO_SWAP32(a) ((((a) & 0x000000FF) << 24) | (((a) & 0x0000FF00) << 8) | (((a) & 0x00FF0000) >> 8) | (((a) & 0xFF000000) >> 24)) |
||||
|
||||
#define VERSION_CODE(primary, secondary, sub) (((primary & 0xFFF) << 20) | ((secondary & 0xFFF) << 8) | ((sub & 0xFF) << 0)) |
||||
#define VERSION_CODE_PRIMARY(in) ((in >> 20) & 0xFFF) |
||||
#define VERSION_CODE_SECONDARY(in) ((in >> 8) & 0xFFF) |
||||
#define VERSION_CODE_SUB(in) ((in >> 0) & 0xFF) |
||||
|
||||
#define MAKE_COLOR(a, r, g, b) (((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF) << 0)) |
||||
#define COLOR_ALPHA(in) ((in >> 24) & 0xFF) |
||||
#define COLOR_RED(in) ((in >> 16) & 0xFF) |
||||
#define COLOR_GREEN(in) ((in >> 8) & 0xFF) |
||||
#define COLOR_BLUE(in) ((in >> 0) & 0xFF) |
||||
|
||||
/**
|
||||
* A 64-bit variable combiner |
||||
*
|
||||
* Useful for endian-independent value extraction. |
||||
*/ |
||||
union VarCombiner |
||||
{ |
||||
UInt64 u64; |
||||
SInt64 s64; |
||||
double f64; |
||||
struct { UInt32 b; UInt32 a; } u32; |
||||
struct { SInt32 b; SInt32 a; } s32; |
||||
struct { float b; float a; } f32; |
||||
struct { UInt16 d; UInt16 c; UInt16 b; UInt16 a; } u16; |
||||
struct { SInt16 d; SInt16 c; SInt16 b; SInt16 a; } s16; |
||||
struct { UInt8 h; UInt8 g; UInt8 f; UInt8 e; |
||||
UInt8 d; UInt8 c; UInt8 b; UInt8 a; } u8; |
||||
struct { SInt8 h; SInt8 g; SInt8 f; SInt8 e; |
||||
SInt8 d; SInt8 c; SInt8 b; SInt8 a; } s8; |
||||
}; |
||||
|
||||
/**
|
||||
* A bitfield. |
||||
*/ |
||||
template <typename T> |
||||
class Bitfield |
||||
{ |
||||
public: |
||||
Bitfield() { } |
||||
~Bitfield() { } |
||||
|
||||
void Clear(void) { field = 0; } //!< Clears all bits
|
||||
void RawSet(UInt32 data) { field = data; } //!< Modifies all bits
|
||||
|
||||
void Set(UInt32 data) { field |= data; } //!< Sets individual bits
|
||||
void Clear(UInt32 data) { field &= ~data; } //!< Clears individual bits
|
||||
void UnSet(UInt32 data) { Clear(data); } //!< Clears individual bits
|
||||
void Mask(UInt32 data) { field &= data; } //!< Masks individual bits
|
||||
void Toggle(UInt32 data) { field ^= data; } //!< Toggles individual bits
|
||||
void Write(UInt32 data, bool state) |
||||
{ if(state) Set(data); else Clear(data); } |
||||
|
||||
T Get(void) const { return field; } //!< Gets all bits
|
||||
T Get(UInt32 data) const { return field & data; } //!< Gets individual bits
|
||||
T Extract(UInt32 bit) const { return (field >> bit) & 1; } //!< Extracts a bit
|
||||
T ExtractField(UInt32 shift, UInt32 length) //!< Extracts a series of bits
|
||||
{ return (field >> shift) & (0xFFFFFFFF >> (32 - length)); } |
||||
|
||||
bool IsSet(UInt32 data) const { return ((field & data) == data) ? true : false; } //!< Are all these bits set?
|
||||
bool IsUnSet(UInt32 data) const { return (field & data) ? false : true; } //!< Are all these bits clear?
|
||||
bool IsClear(UInt32 data) const { return IsUnSet(data); } //!< Are all these bits clear?
|
||||
|
||||
private: |
||||
T field; //!< bitfield data
|
||||
}; |
||||
|
||||
typedef Bitfield <UInt8> Bitfield8; //!< An 8-bit bitfield
|
||||
typedef Bitfield <UInt16> Bitfield16; //!< A 16-bit bitfield
|
||||
typedef Bitfield <UInt32> Bitfield32; //!< A 32-bit bitfield
|
||||
|
||||
STATIC_ASSERT(sizeof(Bitfield8) == 1); |
||||
STATIC_ASSERT(sizeof(Bitfield16) == 2); |
||||
STATIC_ASSERT(sizeof(Bitfield32) == 4); |
||||
|
||||
/**
|
||||
* A bitstring |
||||
*
|
||||
* Essentially a long bitvector. |
||||
*/ |
||||
class Bitstring |
||||
{ |
||||
public: |
||||
Bitstring(); |
||||
Bitstring(UInt32 inLength); |
||||
~Bitstring(); |
||||
|
||||
void Alloc(UInt32 inLength); |
||||
void Dispose(void); |
||||
|
||||
void Clear(void); |
||||
void Clear(UInt32 idx); |
||||
void Set(UInt32 idx); |
||||
|
||||
bool IsSet(UInt32 idx); |
||||
bool IsClear(UInt32 idx); |
||||
|
||||
private: |
||||
UInt8 * data; |
||||
UInt32 length; //!< length in bytes
|
||||
}; |
||||
|
||||
/**
|
||||
* Time storage |
||||
*/ |
||||
class Time |
||||
{ |
||||
public: |
||||
Time() { Clear(); } |
||||
~Time() { } |
||||
|
||||
//! Deinitialize the class
|
||||
void Clear(void) { seconds = minutes = hours = 0; hasData = false; } |
||||
//! Sets the class to the current time
|
||||
//! @todo implement this
|
||||
void SetToNow(void) { Set(1, 2, 3); } |
||||
|
||||
//! Sets the class to the specified time
|
||||
void Set(UInt8 inS, UInt8 inM, UInt8 inH) |
||||
{ seconds = inS; minutes = inM; hours = inH; hasData = true; } |
||||
|
||||
//! Gets whether the class has been initialized or not
|
||||
bool IsSet(void) { return hasData; } |
||||
|
||||
UInt8 GetSeconds(void) { return seconds; } //!< return the seconds portion of the time
|
||||
UInt8 GetMinutes(void) { return minutes; } //!< return the minutes portion of the time
|
||||
UInt8 GetHours(void) { return hours; } //!< return the hours portion of the time
|
||||
|
||||
private: |
||||
UInt8 seconds, minutes, hours; |
||||
bool hasData; |
||||
}; |
||||
|
||||
const float kFloatEpsilon = 0.0001f; |
||||
|
||||
inline bool FloatEqual(float a, float b) { float magnitude = a - b; if(magnitude < 0) magnitude = -magnitude; return magnitude < kFloatEpsilon; } |
||||
|
||||
class Vector2 |
||||
{ |
||||
public: |
||||
Vector2() { } |
||||
Vector2(const Vector2 & in) { x = in.x; y = in.y; } |
||||
Vector2(float inX, float inY) { x = inX; y = inY; } |
||||
~Vector2() { } |
||||
|
||||
void Set(float inX, float inY) { x = inX; y = inY; } |
||||
void SetX(float inX) { x = inX; } |
||||
void SetY(float inY) { y = inY; } |
||||
void Get(float * outX, float * outY) { *outX = x; *outY = y; } |
||||
float GetX(void) { return x; } |
||||
float GetY(void) { return y; } |
||||
|
||||
void Normalize(void) { float mag = Magnitude(); x /= mag; y /= mag; } |
||||
float Magnitude(void) { return sqrt(x*x + y*y); } |
||||
|
||||
void Reverse(void) { float temp = -x; x = -y; y = temp; } |
||||
|
||||
void Scale(float scale) { x *= scale; y *= scale; } |
||||
|
||||
void SwapBytes(void) { SwapFloat(&x); SwapFloat(&y); } |
||||
|
||||
Vector2 & operator+=(const Vector2 & rhs) { x += rhs.x; y += rhs.y; return *this; } |
||||
Vector2 & operator-=(const Vector2 & rhs) { x -= rhs.x; y -= rhs.y; return *this; } |
||||
Vector2 & operator*=(float rhs) { x *= rhs; y *= rhs; return *this; } |
||||
Vector2 & operator/=(float rhs) { x /= rhs; y /= rhs; return *this; } |
||||
|
||||
float x; |
||||
float y; |
||||
}; |
||||
|
||||
inline Vector2 operator+(const Vector2 & lhs, const Vector2 & rhs) |
||||
{ |
||||
return Vector2(lhs.x + rhs.x, lhs.y + rhs.y); |
||||
}; |
||||
|
||||
inline Vector2 operator-(const Vector2 & lhs, const Vector2 & rhs) |
||||
{ |
||||
return Vector2(lhs.x - rhs.x, lhs.y - rhs.y); |
||||
}; |
||||
|
||||
inline Vector2 operator*(const Vector2 & lhs, float rhs) |
||||
{ |
||||
return Vector2(lhs.x * rhs, lhs.y * rhs); |
||||
}; |
||||
|
||||
inline Vector2 operator/(const Vector2 & lhs, float rhs) |
||||
{ |
||||
return Vector2(lhs.x / rhs, lhs.y / rhs); |
||||
}; |
||||
|
||||
inline bool MaskCompare(void * lhs, void * rhs, void * mask, UInt32 size) |
||||
{ |
||||
UInt8 * lhs8 = (UInt8 *)lhs; |
||||
UInt8 * rhs8 = (UInt8 *)rhs; |
||||
UInt8 * mask8 = (UInt8 *)mask; |
||||
|
||||
for(UInt32 i = 0; i < size; i++) |
||||
if((lhs8[i] & mask8[i]) != (rhs8[i] & mask8[i])) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
class Vector3 |
||||
{ |
||||
public: |
||||
Vector3() { } |
||||
Vector3(const Vector3 & in) { x = in.x; y = in.y; z = in.z; } |
||||
Vector3(float inX, float inY, float inZ) { x = inX; y = inY; z = inZ; } |
||||
~Vector3() { } |
||||
|
||||
void Set(float inX, float inY, float inZ) { x = inX; y = inY; z = inZ; } |
||||
void Get(float * outX, float * outY, float * outZ) { *outX = x; *outY = y; *outZ = z; } |
||||
|
||||
void Normalize(void) { float mag = Magnitude(); x /= mag; y /= mag; z /= mag; } |
||||
float Magnitude(void) { return sqrt(x*x + y*y + z*z); } |
||||
|
||||
void Scale(float scale) { x *= scale; y *= scale; z *= scale; } |
||||
|
||||
void SwapBytes(void) { SwapFloat(&x); SwapFloat(&y); SwapFloat(&z); } |
||||
|
||||
Vector3 & operator+=(const Vector3 & rhs) { x += rhs.x; y += rhs.y; z += rhs.z; return *this; } |
||||
Vector3 & operator-=(const Vector3 & rhs) { x -= rhs.x; y -= rhs.y; z -= rhs.z; return *this; } |
||||
Vector3 & operator*=(const Vector3 & rhs) { x *= rhs.x; y *= rhs.y; z *= rhs.z; return *this; } |
||||
Vector3 & operator/=(const Vector3 & rhs) { x /= rhs.x; y /= rhs.y; z /= rhs.z; return *this; } |
||||
|
||||
union |
||||
{ |
||||
struct |
||||
{ |
||||
float x, y, z; |
||||
}; |
||||
float d[3]; |
||||
}; |
||||
}; |
||||
|
||||
inline Vector3 operator+(const Vector3 & lhs, const Vector3 & rhs) |
||||
{ |
||||
return Vector3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z); |
||||
} |
||||
|
||||
inline Vector3 operator-(const Vector3 & lhs, const Vector3 & rhs) |
||||
{ |
||||
return Vector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z); |
||||
} |
||||
|
||||
inline Vector3 operator*(const Vector3 & lhs, const Vector3 & rhs) |
||||
{ |
||||
return Vector3(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z); |
||||
} |
||||
|
||||
inline Vector3 operator/(const Vector3 & lhs, const Vector3 & rhs) |
||||
{ |
||||
return Vector3(lhs.x / rhs.x, lhs.y / rhs.y, lhs.z / rhs.z); |
||||
} |
@ -0,0 +1,419 @@ |
||||
<?xml version="1.0" encoding="Windows-1252"?> |
||||
<VisualStudioProject |
||||
ProjectType="Visual C++" |
||||
Version="8.00" |
||||
Name="common" |
||||
ProjectGUID="{20C6411C-596F-4B85-BE4E-8BC91F59D8A6}" |
||||
RootNamespace="common" |
||||
SccProjectName="Perforce Project" |
||||
SccLocalPath="." |
||||
SccProvider="MSSCCI:Perforce SCM" |
||||
Keyword="Win32Proj" |
||||
> |
||||
<Platforms> |
||||
<Platform |
||||
Name="Win32" |
||||
/> |
||||
</Platforms> |
||||
<ToolFiles> |
||||
</ToolFiles> |
||||
<Configurations> |
||||
<Configuration |
||||
Name="Debug|Win32" |
||||
OutputDirectory="Debug" |
||||
IntermediateDirectory="Debug" |
||||
ConfigurationType="4" |
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="0" |
||||
AdditionalIncludeDirectories="$(SolutionDir);$(SolutionDir)\.." |
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" |
||||
MinimalRebuild="true" |
||||
BasicRuntimeChecks="3" |
||||
RuntimeLibrary="1" |
||||
RuntimeTypeInfo="true" |
||||
UsePrecompiledHeader="0" |
||||
PrecompiledHeaderThrough="" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="false" |
||||
DebugInformationFormat="4" |
||||
ForcedIncludeFiles="common/IPrefix.h" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLibrarianTool" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCFxCopTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="Release|Win32" |
||||
OutputDirectory="Release" |
||||
IntermediateDirectory="Release" |
||||
ConfigurationType="4" |
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
AdditionalIncludeDirectories="$(SolutionDir);$(SolutionDir)\.." |
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" |
||||
RuntimeLibrary="0" |
||||
RuntimeTypeInfo="true" |
||||
UsePrecompiledHeader="0" |
||||
PrecompiledHeaderThrough="" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="false" |
||||
DebugInformationFormat="3" |
||||
ForcedIncludeFiles="common/IPrefix.h" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLibrarianTool" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCFxCopTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
</Configurations> |
||||
<References> |
||||
</References> |
||||
<Files> |
||||
<Filter |
||||
Name="streams" |
||||
> |
||||
<File |
||||
RelativePath=".\IBufferStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IBufferStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDataStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDataStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFileStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFileStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISegmentStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISegmentStream.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="debug" |
||||
> |
||||
<File |
||||
RelativePath=".\IDebugLog.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDebugLog.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IErrors.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IErrors.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="threads" |
||||
> |
||||
<File |
||||
RelativePath=".\ICriticalSection.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IEvent.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IEvent.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IInterlockedLong.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IInterlockedLong.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMutex.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMutex.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IReadWriteLock.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IReadWriteLock.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IThread.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IThread.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="datatypes" |
||||
> |
||||
<File |
||||
RelativePath=".\IArchive.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IArchive.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.inc" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFIFO.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFIFO.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ILinkedList.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IRangeMap.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IRangeMap.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISingleton.cpp" |
||||
> |
||||
<FileConfiguration |
||||
Name="Debug|Win32" |
||||
ExcludedFromBuild="true" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
</File> |
||||
<File |
||||
RelativePath="ISingleton.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITextParser.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITextParser.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITypes.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITypes.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="utilities" |
||||
> |
||||
<File |
||||
RelativePath="IConsole.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IConsole.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDynamicCreate.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDynamicCreate.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITimer.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITimer.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="memory" |
||||
> |
||||
<File |
||||
RelativePath=".\IMemPool.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMemPool.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="pipe" |
||||
> |
||||
<File |
||||
RelativePath=".\IPipeClient.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeClient.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeServer.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeServer.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="files" |
||||
> |
||||
<File |
||||
RelativePath=".\IDirectoryIterator.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDirectoryIterator.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<File |
||||
RelativePath=".\IPrefix.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPrefix.h" |
||||
> |
||||
</File> |
||||
</Files> |
||||
<Globals> |
||||
</Globals> |
||||
</VisualStudioProject> |
@ -0,0 +1,22 @@ |
||||
This license applies to all of the files in src/common: |
||||
|
||||
Copyright (c) 2006-2011 Ian Patterson |
||||
|
||||
This software is provided 'as-is', without any express or implied |
||||
warranty. In no event will the authors be held liable for any damages |
||||
arising from the use of this software. |
||||
|
||||
Permission is granted to anyone to use this software for any purpose, |
||||
including commercial applications, and to alter it and redistribute it |
||||
freely, subject to the following restrictions: |
||||
|
||||
1. The origin of this software must not be misrepresented; you must not |
||||
claim that you wrote the original software. If you use this software |
||||
in a product, an acknowledgment in the product documentation would be |
||||
appreciated but is not required. |
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be |
||||
misrepresented as being the original software. |
||||
|
||||
3. This notice may not be removed or altered from any source |
||||
distribution. |
@ -0,0 +1,418 @@ |
||||
<?xml version="1.0" encoding="Windows-1252"?> |
||||
<VisualStudioProject |
||||
ProjectType="Visual C++" |
||||
Version="9.00" |
||||
Name="common_vc12" |
||||
ProjectGUID="{20C6411C-596F-4B85-BE4E-8BC91F59D8A6}" |
||||
RootNamespace="common" |
||||
SccProjectName="Perforce Project" |
||||
SccLocalPath="." |
||||
SccProvider="MSSCCI:Perforce SCM" |
||||
Keyword="Win32Proj" |
||||
TargetFrameworkVersion="131072" |
||||
> |
||||
<Platforms> |
||||
<Platform |
||||
Name="Win32" |
||||
/> |
||||
</Platforms> |
||||
<ToolFiles> |
||||
</ToolFiles> |
||||
<Configurations> |
||||
<Configuration |
||||
Name="Debug|Win32" |
||||
OutputDirectory="Debug VC12" |
||||
IntermediateDirectory="Debug VC12" |
||||
ConfigurationType="4" |
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="0" |
||||
AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)\..";"$(SolutionDir)\..\.."" |
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" |
||||
MinimalRebuild="true" |
||||
BasicRuntimeChecks="3" |
||||
RuntimeLibrary="1" |
||||
RuntimeTypeInfo="true" |
||||
UsePrecompiledHeader="0" |
||||
PrecompiledHeaderThrough="" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="false" |
||||
DebugInformationFormat="4" |
||||
ForcedIncludeFiles="common/IPrefix.h" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLibrarianTool" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCFxCopTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="Release|Win32" |
||||
OutputDirectory="Release VC12" |
||||
IntermediateDirectory="Release VC12" |
||||
ConfigurationType="4" |
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)\..";"$(SolutionDir)\..\.."" |
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" |
||||
RuntimeLibrary="0" |
||||
RuntimeTypeInfo="true" |
||||
UsePrecompiledHeader="0" |
||||
PrecompiledHeaderThrough="" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="false" |
||||
DebugInformationFormat="3" |
||||
ForcedIncludeFiles="common/IPrefix.h" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLibrarianTool" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCFxCopTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
</Configurations> |
||||
<References> |
||||
</References> |
||||
<Files> |
||||
<Filter |
||||
Name="streams" |
||||
> |
||||
<File |
||||
RelativePath=".\IBufferStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IBufferStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDataStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDataStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFileStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFileStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISegmentStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISegmentStream.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="debug" |
||||
> |
||||
<File |
||||
RelativePath=".\IDebugLog.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDebugLog.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IErrors.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IErrors.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="threads" |
||||
> |
||||
<File |
||||
RelativePath=".\ICriticalSection.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IEvent.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IEvent.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IInterlockedLong.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IInterlockedLong.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMutex.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMutex.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IReadWriteLock.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IReadWriteLock.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IThread.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IThread.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="datatypes" |
||||
> |
||||
<File |
||||
RelativePath=".\IArchive.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IArchive.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.inc" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFIFO.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFIFO.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ILinkedList.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IRangeMap.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IRangeMap.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISingleton.cpp" |
||||
> |
||||
<FileConfiguration |
||||
Name="Debug|Win32" |
||||
ExcludedFromBuild="true" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
</File> |
||||
<File |
||||
RelativePath="ISingleton.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITextParser.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITextParser.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITypes.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITypes.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="utilities" |
||||
> |
||||
<File |
||||
RelativePath="IConsole.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IConsole.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDynamicCreate.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDynamicCreate.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITimer.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITimer.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="memory" |
||||
> |
||||
<File |
||||
RelativePath=".\IMemPool.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMemPool.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="pipe" |
||||
> |
||||
<File |
||||
RelativePath=".\IPipeClient.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeClient.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeServer.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeServer.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="files" |
||||
> |
||||
<File |
||||
RelativePath=".\IDirectoryIterator.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDirectoryIterator.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<File |
||||
RelativePath=".\IPrefix.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPrefix.h" |
||||
> |
||||
</File> |
||||
</Files> |
||||
</VisualStudioProject> |
@ -0,0 +1,420 @@ |
||||
<?xml version="1.0" encoding="Windows-1252"?> |
||||
<VisualStudioProject |
||||
ProjectType="Visual C++" |
||||
Version="9.00" |
||||
Name="common_vc9" |
||||
ProjectGUID="{20C6411C-596F-4B85-BE4E-8BC91F59D8A6}" |
||||
RootNamespace="common" |
||||
SccProjectName="Perforce Project" |
||||
SccLocalPath="." |
||||
SccProvider="MSSCCI:Perforce SCM" |
||||
Keyword="Win32Proj" |
||||
TargetFrameworkVersion="131072" |
||||
> |
||||
<Platforms> |
||||
<Platform |
||||
Name="Win32" |
||||
/> |
||||
</Platforms> |
||||
<ToolFiles> |
||||
</ToolFiles> |
||||
<Configurations> |
||||
<Configuration |
||||
Name="Debug|Win32" |
||||
OutputDirectory="Debug VC9" |
||||
IntermediateDirectory="Debug VC9" |
||||
ConfigurationType="4" |
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
Optimization="0" |
||||
AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)\..";"$(SolutionDir)\..\.."" |
||||
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS" |
||||
MinimalRebuild="true" |
||||
BasicRuntimeChecks="3" |
||||
RuntimeLibrary="1" |
||||
RuntimeTypeInfo="true" |
||||
UsePrecompiledHeader="0" |
||||
PrecompiledHeaderThrough="" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="false" |
||||
DebugInformationFormat="4" |
||||
ForcedIncludeFiles="common/IPrefix.h" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLibrarianTool" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCFxCopTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
<Configuration |
||||
Name="Release|Win32" |
||||
OutputDirectory="Release VC9" |
||||
IntermediateDirectory="Release VC9" |
||||
ConfigurationType="4" |
||||
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" |
||||
CharacterSet="2" |
||||
> |
||||
<Tool |
||||
Name="VCPreBuildEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCustomBuildTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXMLDataGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCWebServiceProxyGeneratorTool" |
||||
/> |
||||
<Tool |
||||
Name="VCMIDLTool" |
||||
/> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
AdditionalIncludeDirectories=""$(SolutionDir)";"$(SolutionDir)\..";"$(SolutionDir)\..\.."" |
||||
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS" |
||||
RuntimeLibrary="0" |
||||
RuntimeTypeInfo="true" |
||||
UsePrecompiledHeader="0" |
||||
PrecompiledHeaderThrough="" |
||||
WarningLevel="3" |
||||
Detect64BitPortabilityProblems="false" |
||||
DebugInformationFormat="3" |
||||
ForcedIncludeFiles="common/IPrefix.h" |
||||
/> |
||||
<Tool |
||||
Name="VCManagedResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCResourceCompilerTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPreLinkEventTool" |
||||
/> |
||||
<Tool |
||||
Name="VCLibrarianTool" |
||||
/> |
||||
<Tool |
||||
Name="VCALinkTool" |
||||
/> |
||||
<Tool |
||||
Name="VCXDCMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCBscMakeTool" |
||||
/> |
||||
<Tool |
||||
Name="VCFxCopTool" |
||||
/> |
||||
<Tool |
||||
Name="VCPostBuildEventTool" |
||||
/> |
||||
</Configuration> |
||||
</Configurations> |
||||
<References> |
||||
</References> |
||||
<Files> |
||||
<Filter |
||||
Name="streams" |
||||
> |
||||
<File |
||||
RelativePath=".\IBufferStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IBufferStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDataStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDataStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFileStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFileStream.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISegmentStream.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISegmentStream.h" |
||||
> |
||||
</File> |
||||
<Filter |
||||
Name="pipe" |
||||
> |
||||
<File |
||||
RelativePath=".\IPipeClient.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeClient.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeServer.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPipeServer.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
</Filter> |
||||
<Filter |
||||
Name="debug" |
||||
> |
||||
<File |
||||
RelativePath=".\IDebugLog.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDebugLog.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IErrors.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IErrors.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="threads" |
||||
> |
||||
<File |
||||
RelativePath=".\ICriticalSection.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IEvent.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IEvent.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IInterlockedLong.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IInterlockedLong.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMutex.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMutex.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IReadWriteLock.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IReadWriteLock.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IThread.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IThread.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="datatypes" |
||||
> |
||||
<File |
||||
RelativePath=".\IArchive.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IArchive.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDatabase.inc" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFIFO.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IFIFO.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ILinkedList.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IRangeMap.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IRangeMap.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ISingleton.cpp" |
||||
> |
||||
<FileConfiguration |
||||
Name="Debug|Win32" |
||||
ExcludedFromBuild="true" |
||||
> |
||||
<Tool |
||||
Name="VCCLCompilerTool" |
||||
/> |
||||
</FileConfiguration> |
||||
</File> |
||||
<File |
||||
RelativePath="ISingleton.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITextParser.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITextParser.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITypes.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITypes.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="utilities" |
||||
> |
||||
<File |
||||
RelativePath="IConsole.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath="IConsole.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDynamicCreate.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDynamicCreate.h" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITimer.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\ITimer.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="memory" |
||||
> |
||||
<File |
||||
RelativePath=".\IMemPool.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IMemPool.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<Filter |
||||
Name="files" |
||||
> |
||||
<File |
||||
RelativePath=".\IDirectoryIterator.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IDirectoryIterator.h" |
||||
> |
||||
</File> |
||||
</Filter> |
||||
<File |
||||
RelativePath=".\IPrefix.cpp" |
||||
> |
||||
</File> |
||||
<File |
||||
RelativePath=".\IPrefix.h" |
||||
> |
||||
</File> |
||||
</Files> |
||||
<Globals> |
||||
</Globals> |
||||
</VisualStudioProject> |
@ -0,0 +1,115 @@ |
||||
#include "Achievements.h" |
||||
#include "skse64/GameMenus.h" |
||||
#include "skse64/GameEvents.h" |
||||
#include "steam\steam_api.h" |
||||
#include <string> |
||||
#include <processenv.h> |
||||
|
||||
class InitSteamOnEvent : public BSTEventSink<MenuOpenCloseEvent> { |
||||
public: |
||||
virtual ~InitSteamOnEvent() {} |
||||
virtual EventResult ReceiveEvent(MenuOpenCloseEvent * evn, EventDispatcher<MenuOpenCloseEvent> * dispatcher) { |
||||
if (std::strcmp(evn->menuName.data, "Main Menu")) { |
||||
_MESSAGE("Main menu opened, trying to init steam API."); |
||||
Achievements::startSteam(); |
||||
} |
||||
return EventResult::kEvent_Continue; |
||||
} |
||||
}; |
||||
|
||||
namespace Achievements { |
||||
|
||||
bool setAchievementUnlocked(StaticFunctionTag* tag, BSFixedString achievement) |
||||
{ |
||||
return singleton->setAchievementUnlocked(achievement.data); |
||||
} |
||||
|
||||
void registerMainMenuEvent() { |
||||
MenuManager * mm = MenuManager::GetSingleton(); |
||||
if (mm) { |
||||
mm->MenuOpenCloseEventDispatcher()->AddEventSink(new InitSteamOnEvent()); |
||||
} |
||||
else { |
||||
_MESSAGE("Failed to register SKSE menuEventHandler!"); |
||||
} |
||||
} |
||||
|
||||
void steamInit(StaticFunctionTag* tag) { |
||||
startSteam(); |
||||
} |
||||
|
||||
void startSteam() |
||||
{ |
||||
try { |
||||
if (singleton.get() == nullptr) { |
||||
SteamAPI_Shutdown(); |
||||
SetEnvironmentVariable("SteamAppID", "933480"); |
||||
SetEnvironmentVariable("SteamGameId", "933480"); |
||||
bool success = SteamAPI_Init(); |
||||
if (success) |
||||
_MESSAGE("Steam api init was successfull"); |
||||
else |
||||
_MESSAGE("Error while initializing the steam api"); |
||||
|
||||
singleton.swap(std::make_unique<AchievementHolder>()); |
||||
singleton->start(); |
||||
} |
||||
else { |
||||
_MESSAGE("Already initialized steam api, skipping it"); |
||||
} |
||||
} |
||||
catch (const std::exception& ex) { |
||||
std::string msg = "Exception while initializing the Steam API, steam achievements will not be available: " + std::string(ex.what()); |
||||
_MESSAGE(msg.c_str()); |
||||
} |
||||
|
||||
} |
||||
|
||||
bool RegisterFuncs(VMClassRegistry * registry) |
||||
{ |
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, bool, BSFixedString>("UnlockAchievement", "Game", Achievements::setAchievementUnlocked, registry)); |
||||
registry->RegisterFunction( new NativeFunction0<StaticFunctionTag, void>("SteamInit", "Game", Achievements::steamInit, registry)); |
||||
Achievements::registerMainMenuEvent(); |
||||
return true; |
||||
} |
||||
|
||||
AchievementHolder::AchievementHolder() : stats(SteamUserStats()), callback(this, &AchievementHolder::onUserStatsReceived) |
||||
{ |
||||
} |
||||
|
||||
void AchievementHolder::onUserStatsReceived(UserStatsReceived_t * event) { |
||||
try { |
||||
std::string msg = "User id: " + std::to_string(event->m_steamIDUser.ConvertToUint64()) + ", game id: " + std::to_string(event->m_nGameID) + ", success state: " + std::to_string(event->m_eResult); |
||||
_MESSAGE(msg.c_str()); |
||||
|
||||
uint32 achievementCount = this->stats->GetNumAchievements(); |
||||
msg = "There are " + std::to_string(achievementCount) + " achievements"; |
||||
_MESSAGE(msg.c_str()); |
||||
} |
||||
catch (const std::exception& ex) { |
||||
std::string msg = "Exception during steam callback: onUserStatsReceived. Failed to print data: " + std::string(ex.what()); |
||||
_MESSAGE(msg.c_str()); |
||||
} |
||||
} |
||||
|
||||
bool AchievementHolder::setAchievementUnlocked(const char * achievementName) |
||||
{ |
||||
std::string msg = "Unlocking achievement: " + std::string(achievementName); |
||||
_MESSAGE(msg.c_str()); |
||||
bool success = this->stats->SetAchievement(achievementName); |
||||
if (!success) { |
||||
_MESSAGE("Error while unlocking achievement"); |
||||
return false; |
||||
} |
||||
success = this->stats->StoreStats(); |
||||
if (!success) { |
||||
_MESSAGE("Error while storing unlocked achievement"); |
||||
} |
||||
return success; |
||||
} |
||||
|
||||
void AchievementHolder::start() |
||||
{ |
||||
this->stats->RequestCurrentStats(); |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
#pragma once |
||||
#include "skse64/PapyrusNativeFunctions.h" |
||||
#include "skse64/GameReferences.h" |
||||
//Steam API Version 1.31 matches the Skyrim Steam API version
|
||||
#include "steam\steam_api.h" |
||||
#include <memory> |
||||
|
||||
namespace Achievements { |
||||
|
||||
class AchievementHolder { |
||||
private: |
||||
ISteamUserStats * stats; |
||||
CCallback<AchievementHolder, UserStatsReceived_t, false> callback; |
||||
|
||||
public: |
||||
AchievementHolder(); |
||||
|
||||
void start(); |
||||
void onUserStatsReceived(UserStatsReceived_t * event); |
||||
bool setAchievementUnlocked(const char * achievementName); |
||||
}; |
||||
|
||||
static std::unique_ptr<AchievementHolder> singleton(nullptr); |
||||
|
||||
void startSteam(); |
||||
void registerMainMenuEvent(); |
||||
|
||||
bool setAchievementUnlocked(StaticFunctionTag* tag, BSFixedString achievement); |
||||
void steamInit(StaticFunctionTag* tag); |
||||
bool RegisterFuncs(VMClassRegistry* registry); |
||||
} |
@ -0,0 +1,45 @@ |
||||
#include "CreatePotion.h" |
||||
#include "skse64\GameObjects.h" |
||||
#include "skse64\GameData.h" |
||||
#include <string> |
||||
|
||||
namespace CreatePotion { |
||||
|
||||
AlchemyItem * createPotion(StaticFunctionTag * tag, VMArray<EffectSetting*> effects, VMArray<float> magnitudes, VMArray<UInt32> areas, VMArray<UInt32> durations, UInt32 arraySize) |
||||
{ |
||||
AlchemyItem * result = NULL; |
||||
|
||||
if (effects.Length() >= arraySize && magnitudes.Length() >= arraySize && areas.Length() >= arraySize && durations.Length() >= arraySize) { |
||||
tArray<MagicItem::EffectItem> effectItems; |
||||
effectItems.Allocate(arraySize); |
||||
|
||||
UInt32 count = 0; |
||||
for (UInt32 i = 0; i < arraySize; ++i) { |
||||
EffectSetting * magicEffect = NULL; |
||||
effects.Get(&magicEffect, i); |
||||
if (magicEffect) { // Only add effects that actually exist
|
||||
magnitudes.Get(&effectItems[count].magnitude, i); |
||||
areas.Get(&effectItems[count].area, i); |
||||
durations.Get(&effectItems[count].duration, i); |
||||
effectItems[count].mgef = magicEffect; |
||||
++count; |
||||
} |
||||
} |
||||
effectItems.count = count; // Set count to existing count
|
||||
CALL_MEMBER_FN(PersistentFormManager::GetSingleton(), CreatePotion)(&result, &effectItems); |
||||
Heap_Free(effectItems.entries); |
||||
} |
||||
else { |
||||
_MESSAGE("Illegal arrays for creating a potion"); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
typedef AlchemyItem*(*CreatePotionType)(StaticFunctionTag * tag, VMArray<EffectSetting*> effects, VMArray<float> magnitudes, VMArray<UInt32> areas, VMArray<UInt32> durations); |
||||
|
||||
bool RegisterFuncs(VMClassRegistry* registry) { |
||||
registry->RegisterFunction( |
||||
new NativeFunction5<StaticFunctionTag, AlchemyItem *, VMArray<EffectSetting*>, VMArray<float>, VMArray<UInt32>, VMArray<UInt32>, UInt32>("CreatePotion", "EnderalLib", CreatePotion::createPotion, registry)); |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,11 @@ |
||||
#pragma once |
||||
#include "skse64/PapyrusNativeFunctions.h" |
||||
#include "skse64/GameReferences.h" |
||||
#include "skse64/GameObjects.h" |
||||
|
||||
namespace CreatePotion |
||||
{ |
||||
AlchemyItem* createPotion(AlchemyItem* toCopy, VMArray<EffectSetting*> effects, VMArray<float> magnitudes, VMArray<UInt32> areas, VMArray<UInt32> durations, UInt32 arraySize); |
||||
|
||||
bool RegisterFuncs(VMClassRegistry* registry); |
||||
} |
@ -0,0 +1,157 @@ |
||||
#include "PhasmalistInventoryFunctions.h" |
||||
#include "skse64\GameExtraData.h" |
||||
#include "skse64\GameBSExtraData.h" |
||||
#include "skse64\GameRTTI.h" |
||||
#include "skse64\PapyrusWornObject.h" |
||||
#include "skse64\PapyrusEnchantment.h" |
||||
#include "skse64\PapyrusWeapon.h" |
||||
#include "skse64\PapyrusArmor.h" |
||||
#include "skse64\PapyrusBook.h" |
||||
#include "skse64\PapyrusSpell.h" |
||||
#include <string> |
||||
|
||||
namespace PhasmalistScripts { |
||||
|
||||
static constexpr float magicWeight = 0.1; |
||||
|
||||
EntryDataList * getEntryData(TESObjectREFR *container) { |
||||
ExtraContainerChanges * ecc = DYNAMIC_CAST |
||||
(container->extraData.GetByType(kExtraData_ContainerChanges), BSExtraData, ExtraContainerChanges); |
||||
if (!ecc) { |
||||
return 0; |
||||
} |
||||
return ecc->data->objList; |
||||
} |
||||
|
||||
float getMagicEffectStrength(EffectSetting * magicEffect, float magnitude, float area, float duration) { |
||||
float result = magicEffect->properties.baseCost; |
||||
if (magnitude > 0) { |
||||
result *= magnitude; |
||||
} |
||||
if (area > 0) { |
||||
result *= area; |
||||
} |
||||
if (duration > 0) { |
||||
result *= duration; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
float getEnchantmentStrength(EnchantmentItem * ench) { |
||||
if (!ench) { |
||||
return 0.0; |
||||
} |
||||
float result = 0; |
||||
for (int i = papyrusEnchantment::GetNumEffects(ench) - 1; i >= 0; i--) { |
||||
result += getMagicEffectStrength( |
||||
papyrusEnchantment::GetNthEffectMagicEffect(ench, i), |
||||
papyrusEnchantment::GetNthEffectMagnitude(ench, i), |
||||
papyrusEnchantment::GetNthEffectArea(ench, i), |
||||
papyrusEnchantment::GetNthEffectDuration(ench, i)); |
||||
} |
||||
return result * magicWeight; |
||||
} |
||||
|
||||
float getSpellStrength(SpellItem * spell) { |
||||
if (!spell) { |
||||
return 0.0; |
||||
} |
||||
float result = 0; |
||||
for (int i = papyrusSpell::GetNumEffects(spell) - 1; i >= 0; i--) { |
||||
result += getMagicEffectStrength( |
||||
papyrusSpell::GetNthEffectMagicEffect(spell, i), |
||||
papyrusSpell::GetNthEffectMagnitude(spell, i), |
||||
papyrusSpell::GetNthEffectDuration(spell, i), |
||||
papyrusSpell::GetNthEffectArea(spell, i)); |
||||
} |
||||
return result * magicWeight; |
||||
} |
||||
|
||||
float getAdditionalExtendDataStrength(InventoryEntryData * itemStack, float physicalStrength) { |
||||
float strength = 0; |
||||
for (int i = itemStack->extendDataList->Count() - 1; i >= 0; i--) { |
||||
BaseExtraList * extraData = itemStack->extendDataList->GetNthItem(i); |
||||
if (!extraData) { |
||||
continue; |
||||
} |
||||
ExtraCount * exCount = DYNAMIC_CAST(extraData->GetByType(kExtraData_Count), BSExtraData, ExtraCount); |
||||
int count = 1; |
||||
if (exCount) { |
||||
count = exCount->count; |
||||
} |
||||
if (extraData->HasType(kExtraData_Enchantment)) { |
||||
//item has been enchanted
|
||||
EnchantmentItem * ench = referenceUtils::GetEnchantment(extraData); |
||||
strength += getEnchantmentStrength(ench) * count; |
||||
} |
||||
if (extraData->HasType(kExtraData_Health)) { |
||||
//item has been tempered
|
||||
ExtraHealth * health = DYNAMIC_CAST(extraData->GetByType(kExtraData_Health), BSExtraData, ExtraHealth); |
||||
if (health) { |
||||
strength += physicalStrength * (health->health - 1.0) * count; |
||||
} |
||||
} |
||||
} |
||||
return strength; |
||||
} |
||||
|
||||
float getItemStackStrength(InventoryEntryData * itemStack) { |
||||
float strength = 0; |
||||
float physicalStrength = 0; |
||||
|
||||
if (itemStack->type->IsWeapon()) { |
||||
TESObjectWEAP * asWeapon = static_cast<TESObjectWEAP*>(itemStack->type); |
||||
if (asWeapon) { |
||||
float baseDmg = papyrusWeapon::GetBaseDamage(asWeapon); |
||||
float speed = papyrusWeapon::GetSpeed(asWeapon); |
||||
physicalStrength = baseDmg * speed; |
||||
strength += physicalStrength; |
||||
strength += getEnchantmentStrength(papyrusWeapon::GetEnchantment(asWeapon)); |
||||
} |
||||
} |
||||
|
||||
if (itemStack->type->IsArmor()) { |
||||
TESObjectARMO * asArmor = static_cast<TESObjectARMO*>(itemStack->type); |
||||
if (asArmor) { |
||||
physicalStrength = papyrusArmor::GetArmorRating(asArmor); |
||||
strength += physicalStrength; |
||||
strength += getEnchantmentStrength(papyrusArmor::GetEnchantment(asArmor)); |
||||
} |
||||
} |
||||
|
||||
if (itemStack->type->formType == kFormType_Book) { |
||||
TESObjectBOOK * asBook = static_cast<TESObjectBOOK*>(itemStack->type); |
||||
if (asBook) { |
||||
SpellItem * spell = papyrusBook::GetSpell(asBook); |
||||
return getSpellStrength(spell); |
||||
} |
||||
} |
||||
|
||||
strength = strength * itemStack->countDelta; |
||||
|
||||
strength += getAdditionalExtendDataStrength(itemStack, physicalStrength); |
||||
|
||||
return strength; |
||||
} |
||||
|
||||
float calculateContentStrength(StaticFunctionTag * tag, TESObjectREFR *container) { |
||||
if (!container) { |
||||
return 0.0; |
||||
} |
||||
float strength = 0; |
||||
for (int i = getEntryData(container)->Count() - 1; i >= 0; --i) { |
||||
InventoryEntryData * ed = getEntryData(container)->GetNthItem(i); |
||||
if (!ed) { |
||||
continue; |
||||
} |
||||
strength += getItemStackStrength(ed); |
||||
} |
||||
return strength; |
||||
} |
||||
|
||||
bool RegisterFuncs(VMClassRegistry* registry) { |
||||
registry->RegisterFunction( |
||||
new NativeFunction1<StaticFunctionTag, float, TESObjectREFR *>("calculateContentStrength", "EnderalLib", PhasmalistScripts::calculateContentStrength, registry)); |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,10 @@ |
||||
#pragma once |
||||
#include "skse64/PapyrusNativeFunctions.h" |
||||
#include "skse64/GameReferences.h" |
||||
|
||||
namespace PhasmalistScripts |
||||
{ |
||||
float calculateContentStrength(TESObjectREFR *base); |
||||
|
||||
bool RegisterFuncs(VMClassRegistry* registry); |
||||
} |
@ -0,0 +1,4 @@ |
||||
LIBRARY "fs" |
||||
EXPORTS |
||||
SKSEPlugin_Query |
||||
SKSEPlugin_Load |
@ -0,0 +1,69 @@ |
||||
#include "skse64/PluginAPI.h" // super |
||||
#include "skse64_common/skse_version.h" // What version of SKSE is running? |
||||
#include <shlobj.h> // CSIDL_MYCODUMENTS |
||||
|
||||
#include "PhasmalistInventoryFunctions.h" |
||||
#include "CreatePotion.h" |
||||
|
||||
static PluginHandle g_pluginHandle = kPluginHandle_Invalid; |
||||
static SKSEPapyrusInterface * g_papyrus = NULL; |
||||
|
||||
extern "C" { |
||||
|
||||
bool SKSEPlugin_Query(const SKSEInterface * skse, PluginInfo * info) { // Called by SKSE to learn about this plugin and check that it's safe to load it
|
||||
gLog.OpenRelative(CSIDL_MYDOCUMENTS, "\\My Games\\Enderal Special Edition\\SKSE\\FS.log"); |
||||
gLog.SetPrintLevel(IDebugLog::kLevel_Error); |
||||
gLog.SetLogLevel(IDebugLog::kLevel_DebugMessage); |
||||
|
||||
_MESSAGE("fs_skse_functions"); |
||||
|
||||
// populate info structure
|
||||
info->infoVersion = PluginInfo::kInfoVersion; |
||||
info->name = "fs_skse_functions"; |
||||
info->version = 1; |
||||
|
||||
// store plugin handle so we can identify ourselves later
|
||||
g_pluginHandle = skse->GetPluginHandle(); |
||||
|
||||
if (skse->isEditor) |
||||
{ |
||||
_MESSAGE("loaded in editor, marking as incompatible"); |
||||
|
||||
return false; |
||||
} |
||||
else if (skse->runtimeVersion != RUNTIME_VERSION_1_5_97) |
||||
{ |
||||
_MESSAGE("unsupported runtime version %08X", skse->runtimeVersion); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// ### do not do anything else in this callback
|
||||
// ### only fill out PluginInfo and return true/false
|
||||
|
||||
// supported runtime version
|
||||
return true; |
||||
} |
||||
|
||||
bool SKSEPlugin_Load(const SKSEInterface * skse) { // Called by SKSE to load this plugin
|
||||
_MESSAGE("fs_skse_functions loaded"); |
||||
|
||||
g_papyrus = (SKSEPapyrusInterface *)skse->QueryInterface(kInterface_Papyrus); |
||||
|
||||
//Check if the function registration was a success...
|
||||
bool btest = g_papyrus->Register(PhasmalistScripts::RegisterFuncs); |
||||
|
||||
if (btest) { |
||||
_MESSAGE("Register Succeeded: Phasmalist functions"); |
||||
} |
||||
|
||||
btest = g_papyrus->Register(CreatePotion::RegisterFuncs); |
||||
|
||||
if (btest) { |
||||
_MESSAGE("Register Succeeded: CreatePotion functions"); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
}; |
@ -0,0 +1,4 @@ |
||||
#include "skse64/BSModelDB.h" |
||||
|
||||
// 206875324DD3C045FB854CB2889AFBCA94C7790B+89
|
||||
RelocPtr <BSModelDB::BSModelProcessor*> g_TESProcessor(0x01EC3C10); |
@ -0,0 +1,50 @@ |
||||
#pragma once |
||||
|
||||
#include "skse64_common/Utilities.h" |
||||
|
||||
class NiAVObject; |
||||
|
||||
class BSModelDB |
||||
{ |
||||
public: |
||||
struct ModelData |
||||
{ |
||||
UInt64 unk00; // 00
|
||||
|
||||
enum |
||||
{ |
||||
kFlag_Unk1 = (1 << 0), |
||||
kFlag_Dynamic = (1 << 1), |
||||
kFlag_PostProcess = (1 << 3), |
||||
kFlag_Unk2 = (1 << 4), |
||||
kFlag_Unk3 = (1 << 5) |
||||
}; |
||||
|
||||
UInt8 modelFlags; // 08
|
||||
// ...
|
||||
}; |
||||
|
||||
class BSModelProcessor |
||||
{ |
||||
public: |
||||
virtual ~BSModelProcessor() { }; |
||||
|
||||
virtual void Process(ModelData * modelData, const char * modelName, NiAVObject ** root, UInt32 * typeOut) { }; |
||||
}; |
||||
|
||||
class TESProcessor : public BSModelProcessor |
||||
{ |
||||
public: |
||||
TESProcessor() { } |
||||
virtual ~TESProcessor() { CALL_MEMBER_FN(this, dtor)(); }; |
||||
|
||||
virtual void Process(ModelData * modelData, const char * modelName, NiAVObject ** root, UInt32 * typeOut) override { CALL_MEMBER_FN(this, Impl_Process)(modelData, modelName, root, typeOut); } |
||||
|
||||
MEMBER_FN_PREFIX(TESProcessor); |
||||
// find from ??_7BSModelProcessor@BSModelDB@@6B@
|
||||
DEFINE_MEMBER_FN(dtor, void, 0x00D2ECA0); |
||||
DEFINE_MEMBER_FN(Impl_Process, void, 0x00181800, ModelData * modelData, const char * modelName, NiAVObject ** root, UInt32 * typeOut); |
||||
}; |
||||
}; |
||||
|
||||
extern RelocPtr <BSModelDB::BSModelProcessor*> g_TESProcessor; |
@ -0,0 +1,198 @@ |
||||
#include "Colors.h" |
||||
|
||||
UInt32 ARGBColor::GetColor() |
||||
{ |
||||
return MAKE_COLOR(m_alpha, m_red, m_green, m_blue); |
||||
} |
||||
|
||||
void ARGBColor::SetARGB(UInt8 alpha, UInt8 red, UInt8 green, UInt8 blue) |
||||
{ |
||||
m_alpha = alpha; |
||||
m_red = red; |
||||
m_green = green; |
||||
m_blue = blue; |
||||
} |
||||
|
||||
void ARGBColor::GetARGB(UInt8 & alpha, UInt8 & red, UInt8 & green, UInt8 & blue) |
||||
{ |
||||
alpha = m_alpha; |
||||
red = m_red; |
||||
green = m_green; |
||||
blue = m_blue; |
||||
} |
||||
|
||||
void ARGBColor::SetHSV(double hue, double saturation, double value) |
||||
{ |
||||
double h,s,v; |
||||
double r,g,b; |
||||
|
||||
h = hue; |
||||
s = saturation; |
||||
v = value; |
||||
|
||||
if (hue < 0.0) |
||||
hue += 360.0; |
||||
|
||||
if (s != 0.0) { |
||||
double f, p, q, t; |
||||
if (h == 360.0) |
||||
h = 0.0; |
||||
h /= 60.0; |
||||
|
||||
int i = (int)h; |
||||
f = h - i; |
||||
p = v * (1.0 - s); |
||||
q = v * (1.0 - (s * f)); |
||||
t = v * (1.0 - (s * (1.0 - f))); |
||||
|
||||
switch (i) { |
||||
case 0: r = v; g = t; b = p; break; |
||||
case 1: r = q; g = v; b = p; break; |
||||
case 2: r = p; g = v; b = t; break; |
||||
case 3: r = p; g = q; b = v; break; |
||||
case 4: r = t; g = p; b = v; break; |
||||
case 5: r = v; g = p; b = q; break; |
||||
} |
||||
} |
||||
else { |
||||
r = v; |
||||
g = v; |
||||
b = v; |
||||
} |
||||
|
||||
m_red = r * 255; |
||||
m_green = g * 255; |
||||
m_blue = b * 255; |
||||
} |
||||
|
||||
void ARGBColor::GetHSV(double & hue, double & saturation, double & value) |
||||
{ |
||||
double r,g,b, rgb_max, rgb_min, delta, h, s; |
||||
r = m_red / 255.0; |
||||
g = m_green / 255.0; |
||||
b = m_blue / 255.0; |
||||
rgb_max = MAX3(r, g, b); |
||||
rgb_min = MIN3(r, g, b); |
||||
delta = rgb_max - rgb_min; |
||||
h = 0; |
||||
s = 0; |
||||
|
||||
if ( rgb_max != 0.0 ) |
||||
s = delta / rgb_max; |
||||
|
||||
if ( s != 0.0 ) |
||||
{ |
||||
double rc = (rgb_max - r) / delta; |
||||
double gc = (rgb_max - g) / delta; |
||||
double bc = (rgb_max - b) / delta; |
||||
|
||||
if ( r == rgb_max ) |
||||
h = bc - gc; |
||||
else if ( g == rgb_max ) |
||||
h = 2.0f + rc - bc; |
||||
else if ( b == rgb_max ) |
||||
h = 4.0f + gc - rc; |
||||
|
||||
h *= 60.0f; |
||||
if ( h < 0.0 ) |
||||
h += 360.0f; |
||||
} |
||||
|
||||
hue = h; |
||||
saturation = s; |
||||
value = rgb_max; |
||||
} |
||||
|
||||
UInt8 ARGBColor::GetAlpha() |
||||
{ |
||||
return m_alpha; |
||||
} |
||||
|
||||
UInt8 ARGBColor::GetRed() |
||||
{ |
||||
return m_red; |
||||
} |
||||
|
||||
UInt8 ARGBColor::GetGreen() |
||||
{ |
||||
return m_green; |
||||
} |
||||
|
||||
UInt8 ARGBColor::GetBlue() |
||||
{ |
||||
return m_blue; |
||||
} |
||||
|
||||
void ARGBColor::SetAlpha(UInt8 alpha) |
||||
{ |
||||
m_alpha = alpha; |
||||
} |
||||
|
||||
void ARGBColor::SetRed(UInt8 red) |
||||
{ |
||||
m_red = red; |
||||
} |
||||
|
||||
void ARGBColor::SetGreen(UInt8 green) |
||||
{ |
||||
m_green = green; |
||||
} |
||||
|
||||
void ARGBColor::SetBlue(UInt8 blue) |
||||
{ |
||||
m_blue = blue; |
||||
} |
||||
|
||||
void ARGBColor::SetHue(double newHue) |
||||
{ |
||||
double hue; |
||||
double sat; |
||||
double val; |
||||
GetHSV(hue, sat, val); |
||||
SetHSV(newHue, sat, val); |
||||
} |
||||
|
||||
void ARGBColor::SetSaturation(double newSat) |
||||
{ |
||||
double hue; |
||||
double sat; |
||||
double val; |
||||
GetHSV(hue, sat, val); |
||||
SetHSV(hue, newSat, val); |
||||
} |
||||
|
||||
void ARGBColor::SetValue(double newVal) |
||||
{ |
||||
double hue; |
||||
double sat; |
||||
double val; |
||||
GetHSV(hue, sat, val); |
||||
SetHSV(hue, sat, newVal); |
||||
} |
||||
|
||||
double ARGBColor::GetHue() |
||||
{ |
||||
double hue; |
||||
double sat; |
||||
double val; |
||||
GetHSV(hue, sat, val); |
||||
return hue; |
||||
} |
||||
|
||||
double ARGBColor::GetSaturation() |
||||
{ |
||||
double hue; |
||||
double sat; |
||||
double val; |
||||
GetHSV(hue, sat, val); |
||||
return sat; |
||||
} |
||||
|
||||
double ARGBColor::GetValue() |
||||
{ |
||||
double hue; |
||||
double sat; |
||||
double val; |
||||
GetHSV(hue, sat, val); |
||||
return val; |
||||
} |
@ -0,0 +1,50 @@ |
||||
#pragma once |
||||
|
||||
#include "common/ITypes.h" |
||||
|
||||
#define MIN3(x,y,z) ((y) <= (z) ? ((x) <= (y) ? (x) : (y)) : ((x) <= (z) ? (x) : (z))) |
||||
#define MAX3(x,y,z) ((y) >= (z) ? ((x) >= (y) ? (x) : (y)) : ((x) >= (z) ? (x) : (z))) |
||||
|
||||
class ARGBColor |
||||
{ |
||||
public: |
||||
ARGBColor(UInt32 argb) { |
||||
m_alpha = COLOR_ALPHA(argb); |
||||
m_red = COLOR_RED(argb); |
||||
m_green = COLOR_GREEN(argb); |
||||
m_blue = COLOR_BLUE(argb); |
||||
}; |
||||
ARGBColor(UInt8 _a, UInt8 _r, UInt8 _g, UInt8 _b) : m_alpha(_a), m_red(_r), m_green(_g), m_blue(_b) {}; |
||||
|
||||
UInt32 GetColor(); |
||||
|
||||
void SetARGB(UInt8 alpha, UInt8 red, UInt8 green, UInt8 blue); |
||||
void GetARGB(UInt8 & alpha, UInt8 & red, UInt8 & green, UInt8 & blue); |
||||
|
||||
void SetHSV(double hue, double saturation, double value); |
||||
void GetHSV(double & hue, double & saturation, double & value); |
||||
|
||||
UInt8 GetAlpha(); |
||||
UInt8 GetRed(); |
||||
UInt8 GetGreen(); |
||||
UInt8 GetBlue(); |
||||
|
||||
void SetAlpha(UInt8 alpha); |
||||
void SetRed(UInt8 red); |
||||
void SetGreen(UInt8 green); |
||||
void SetBlue(UInt8 blue); |
||||
|
||||
void SetHue(double hue); |
||||
void SetSaturation(double saturation); |
||||
void SetValue(double value); |
||||
|
||||
double GetHue(); |
||||
double GetSaturation(); |
||||
double GetValue(); |
||||
|
||||
private: |
||||
UInt8 m_alpha; |
||||
UInt8 m_red; |
||||
UInt8 m_green; |
||||
UInt8 m_blue; |
||||
}; |
@ -0,0 +1,17 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |
||||
<ImportGroup Label="PropertySheets" /> |
||||
<PropertyGroup Label="UserMacros" /> |
||||
<PropertyGroup> |
||||
<TargetName>$(ProjectName)_1_5_97</TargetName> |
||||
</PropertyGroup> |
||||
<ItemDefinitionGroup> |
||||
<ClCompile> |
||||
<AdditionalIncludeDirectories>$(SolutionDir);$(SolutionDir)\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
||||
<ForcedIncludeFiles>common/IPrefix.h</ForcedIncludeFiles> |
||||
<WarningLevel>Level3</WarningLevel> |
||||
<PreprocessorDefinitions>_WINDOWS;_USRDLL;SKSE64_EXPORTS;RUNTIME_VERSION=0x01050610;RUNTIME;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
||||
</ClCompile> |
||||
</ItemDefinitionGroup> |
||||
<ItemGroup /> |
||||
</Project> |
@ -0,0 +1,75 @@ |
||||
#include "skse64/CustomMenu.h" |
||||
|
||||
std::string CustomMenuCreator::swfPath_; |
||||
|
||||
IMenu* CustomMenuCreator::Create(void) |
||||
{ |
||||
void* p = ScaleformHeap_Allocate(sizeof(CustomMenu)); |
||||
if (p) |
||||
{ |
||||
IMenu* menu = new (p) CustomMenu(swfPath_.c_str()); |
||||
return menu; |
||||
} |
||||
else |
||||
{ |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
void CustomMenuCreator::SetSwfPath(const char* path) |
||||
{ |
||||
swfPath_ = path; |
||||
} |
||||
|
||||
CustomMenu::CustomMenu(const char* swfPath) |
||||
{ |
||||
CALL_MEMBER_FN(GFxLoader::GetSingleton(), LoadMovie)(this, &view, swfPath, GFxMovieView::ScaleModeType::kNoBorder, 0.0); |
||||
|
||||
flags = IMenu::kFlag_Modal | IMenu::kFlag_PausesGame; |
||||
unk0C = 0xA; |
||||
unk14 = 1; |
||||
|
||||
if(!InputEventDispatcher::GetSingleton()->IsGamepadEnabled()) |
||||
flags |= IMenu::kFlag_UpdateUsesCursor | IMenu::kFlag_UsesCursor; // Shows the cursor when no gamepad is enabled
|
||||
|
||||
#ifdef _CUSTOMMENU_ITEMDISPLAY |
||||
flags |= IMenu::kFlag_RendersOffscreenTargets; |
||||
#endif |
||||
} |
||||
#ifdef _CUSTOMMENU_ITEMDISPLAY |
||||
void UpdateItem3D(const FxDelegateArgs & params) |
||||
{ |
||||
if(params.menu) { |
||||
UInt32 formId = (UInt32)params.args->GetNumber(); |
||||
if(formId) { |
||||
TESForm * form = LookupFormByID(formId); |
||||
if(form) { |
||||
CALL_MEMBER_FN(Inventory3DManager::GetSingleton(), UpdateMagic3D)(form, 0); |
||||
} |
||||
} else { |
||||
CALL_MEMBER_FN(Inventory3DManager::GetSingleton(), Clear3D)(); |
||||
} |
||||
} |
||||
} |
||||
#endif |
||||
void CustomMenu::Accept(CallbackProcessor * processor) |
||||
{ |
||||
GString playSound("PlaySound"); |
||||
processor->Process(playSound, PlaySoundCallback); |
||||
|
||||
#ifdef _CUSTOMMENU_ITEMDISPLAY |
||||
GString renderItem("UpdateItem3D"); |
||||
processor->Process(renderItem, UpdateItem3D); |
||||
#endif |
||||
} |
||||
|
||||
|
||||
void CustomMenu::Render() |
||||
{ |
||||
if(view) { |
||||
view->Render(); |
||||
#ifdef _CUSTOMMENU_ITEMDISPLAY |
||||
CALL_MEMBER_FN(Inventory3DManager::GetSingleton(), Render)(); |
||||
#endif |
||||
} |
||||
} |
@ -0,0 +1,24 @@ |
||||
#pragma once |
||||
|
||||
#include "skse64/GameMenus.h" |
||||
#include "skse64/ScaleformLoader.h" |
||||
|
||||
class CustomMenuCreator |
||||
{ |
||||
public: |
||||
static IMenu* Create(void); |
||||
static void SetSwfPath(const char* path); |
||||
|
||||
private: |
||||
CustomMenuCreator(); |
||||
|
||||
static std::string swfPath_; |
||||
}; |
||||
|
||||
class CustomMenu : public IMenu |
||||
{ |
||||
public: |
||||
CustomMenu(const char* swfPath); |
||||
virtual void Accept(CallbackProcessor * processor); |
||||
virtual void Render(void); |
||||
}; |
@ -0,0 +1,70 @@ |
||||
#include "skse64/GameAPI.h" |
||||
|
||||
// 4371A3D33EB5D62C7C548EBD5F760AF15A9B0B96+41
|
||||
RelocPtr <Heap> g_mainHeap(0x01EBD280); |
||||
|
||||
// 75643FD50A96D1F83B1AC4797EC84EF1C53039AC+68
|
||||
RelocPtr <ConsoleManager *> g_console(0x02F000F0); |
||||
|
||||
// E1E59B64FDA5B8A9085AE9314353ABEEA0DB2823+C4
|
||||
RelocPtr <UInt32> g_consoleHandle(0x02F4C31C); |
||||
|
||||
// 52DD97B7C619EA732D3CD95637F449FC7A23DD12+24
|
||||
RelocPtr<UInt32> g_TlsIndexPtr(0x03497408); |
||||
|
||||
// BC8BF08A45C960EB35F2BAFEC9432C80365A1473+14A
|
||||
RelocPtr<PlayerCharacter*> g_thePlayer(0x02F26EF8); |
||||
|
||||
void * Heap_Allocate(size_t size) |
||||
{ |
||||
return CALL_MEMBER_FN(g_mainHeap, Allocate)(size, 0, false); |
||||
} |
||||
|
||||
void Heap_Free(void * ptr) |
||||
{ |
||||
CALL_MEMBER_FN(g_mainHeap, Free)(ptr, false); |
||||
} |
||||
|
||||
void Console_Print(const char * fmt, ...) |
||||
{ |
||||
ConsoleManager * mgr = *g_console; |
||||
if(mgr) |
||||
{ |
||||
va_list args; |
||||
va_start(args, fmt); |
||||
|
||||
CALL_MEMBER_FN(mgr, VPrint)(fmt, args); |
||||
|
||||
va_end(args); |
||||
} |
||||
} |
||||
|
||||
struct TLSData |
||||
{ |
||||
// thread local storage
|
||||
|
||||
UInt8 unk000[0x600]; // 000
|
||||
UInt8 consoleMode; // 600
|
||||
UInt8 pad601[7]; // 601
|
||||
}; |
||||
|
||||
static TLSData * GetTLSData() |
||||
{ |
||||
UInt32 TlsIndex = *g_TlsIndexPtr; |
||||
TLSData ** data = (TLSData **)__readgsqword(0x58); |
||||
|
||||
return data[TlsIndex]; |
||||
} |
||||
|
||||
|
||||
bool IsConsoleMode(void) |
||||
{ |
||||
return GetTLSData()->consoleMode != 0; |
||||
} |
||||
|
||||
__int64 GetPerfCounter(void) |
||||
{ |
||||
LARGE_INTEGER li; |
||||
QueryPerformanceCounter(&li); |
||||
return li.QuadPart; |
||||
} |
@ -0,0 +1,34 @@ |
||||
#pragma once |
||||
|
||||
#include "skse64_common/Utilities.h" |
||||
|
||||
class PlayerCharacter; |
||||
|
||||
class Heap |
||||
{ |
||||
public: |
||||
MEMBER_FN_PREFIX(Heap); |
||||
DEFINE_MEMBER_FN(Allocate, void *, 0x00C02260, size_t size, size_t alignment, bool aligned); |
||||
DEFINE_MEMBER_FN(Free, void, 0x00C02560, void * buf, bool aligned); |
||||
}; |
||||
|
||||
extern RelocPtr <Heap> g_mainHeap; |
||||
|
||||
void * Heap_Allocate(size_t size); |
||||
void Heap_Free(void * ptr); |
||||
|
||||
class ConsoleManager |
||||
{ |
||||
public: |
||||
MEMBER_FN_PREFIX(ConsoleManager); |
||||
DEFINE_MEMBER_FN(VPrint, void, 0x0085C2C0, const char * fmt, va_list args); |
||||
// DEFINE_MEMBER_FN(Print, void, 0x001D2050, const char * str);
|
||||
}; |
||||
|
||||
extern RelocPtr <ConsoleManager *> g_console; |
||||
extern RelocPtr <UInt32> g_consoleHandle; |
||||
extern RelocPtr <PlayerCharacter*> g_thePlayer; |
||||
|
||||
void Console_Print(const char * fmt, ...); |
||||
bool IsConsoleMode(void); |
||||
__int64 GetPerfCounter(void); |
@ -0,0 +1,280 @@ |
||||
#include "GameBSExtraData.h" |
||||
#include "GameExtraData.h" |
||||
#include "GameRTTI.h" |
||||
|
||||
extern const void * RTTIForExtraType[0xB4] =
|
||||
{ |
||||
NULL, // 0x0
|
||||
RTTI_ExtraHavok, // 0x1,
|
||||
RTTI_ExtraCell3D, // 0x2,
|
||||
RTTI_ExtraCellWaterType, // 0x3,
|
||||
RTTI_ExtraRegionList, // 0x4,
|
||||
RTTI_ExtraSeenData, // 0x5,
|
||||
RTTI_ExtraEditorID, // 0x6,
|
||||
RTTI_ExtraCellMusicType, // 0x7,
|
||||
RTTI_ExtraCellSkyRegion, // 0x8,
|
||||
RTTI_ExtraProcessMiddleLow, // 0x9,
|
||||
RTTI_ExtraDetachTime, // 0xA,
|
||||
RTTI_ExtraPersistentCell, // 0xB,
|
||||
NULL, // 0xC,
|
||||
RTTI_ExtraAction, // 0xD,
|
||||
RTTI_ExtraStartingPosition, // 0xE,
|
||||
NULL, // 0xF,
|
||||
RTTI_ExtraAnimGraphManager, // 0x10,
|
||||
NULL, // 0x11,
|
||||
RTTI_ExtraUsedMarkers, // 0x12,
|
||||
RTTI_ExtraDistantData, // 0x13,
|
||||
RTTI_ExtraRagDollData, // 0x14,
|
||||
RTTI_ExtraContainerChanges, // 0x15,
|
||||
RTTI_ExtraWorn, // 0x16,
|
||||
RTTI_ExtraWornLeft, // 0x17,
|
||||
RTTI_ExtraPackageStartLocation, // 0x18,
|
||||
RTTI_ExtraPackage, // 0x19,
|
||||
RTTI_ExtraTresPassPackage, // 0x1A,
|
||||
RTTI_ExtraRunOncePacks, // 0x1B,
|
||||
RTTI_ExtraReferenceHandle, // 0x1C,
|
||||
RTTI_ExtraFollower, // 0x1D,
|
||||
RTTI_ExtraLevCreaModifier, // 0x1E,
|
||||
RTTI_ExtraGhost, // 0x1F,
|
||||
RTTI_ExtraOriginalReference, // 0x20,
|
||||
RTTI_ExtraOwnership, // 0x21,
|
||||
RTTI_ExtraGlobal, // 0x22,
|
||||
RTTI_ExtraRank, // 0x23,
|
||||
RTTI_ExtraCount, // 0x24,
|
||||
RTTI_ExtraHealth, // 0x25,
|
||||
NULL, // 0x26,
|
||||
RTTI_ExtraTimeLeft, // 0x27,
|
||||
RTTI_ExtraCharge, // 0x28,
|
||||
RTTI_ExtraLight, // 0x29,
|
||||
RTTI_ExtraLock, // 0x2A,
|
||||
RTTI_ExtraTeleport, // 0x2B,
|
||||
RTTI_ExtraMapMarker, // 0x2C,
|
||||
RTTI_ExtraLeveledCreature, // 0x2D,
|
||||
RTTI_ExtraLeveledItem, // 0x2E,
|
||||
RTTI_ExtraScale, // 0x2F,
|
||||
NULL, // 0x30, was ExtraSeed, removed in 1.7.7.0
|
||||
NULL, // 0x31,
|
||||
NULL, // 0x32,
|
||||
NULL, // 0x33,
|
||||
RTTI_ExtraPlayerCrimeList, // 0x34,
|
||||
NULL, // 0x35
|
||||
RTTI_ExtraEnableStateParent, // 0x36,
|
||||
RTTI_ExtraEnableStateChildren, // 0x37,
|
||||
RTTI_ExtraItemDropper, // 0x38,
|
||||
RTTI_ExtraDroppedItemList, // 0x39,
|
||||
RTTI_ExtraRandomTeleportMarker, // 0x3A,
|
||||
NULL, // 0x3B
|
||||
RTTI_ExtraSavedHavokData, // 0x3C,
|
||||
RTTI_ExtraCannotWear, // 0x3D,
|
||||
RTTI_ExtraPoison, // 0x3E,
|
||||
NULL, // 0x3F
|
||||
RTTI_ExtraLastFinishedSequence, // 0x40,
|
||||
RTTI_ExtraSavedAnimation, // 0x41,
|
||||
RTTI_ExtraNorthRotation, // 0x42,
|
||||
RTTI_ExtraSpawnContainer, // 0x43,
|
||||
RTTI_ExtraFriendHits, // 0x44,
|
||||
RTTI_ExtraHeadingTarget, // 0x45,
|
||||
NULL, // 0x46
|
||||
RTTI_ExtraRefractionProperty, // 0x47,
|
||||
RTTI_ExtraStartingWorldOrCell, // 0x48,
|
||||
RTTI_ExtraHotkey, // 0x49,
|
||||
NULL, // 0x4A
|
||||
RTTI_ExtraEditorRefMoveData, // 0x4B,
|
||||
RTTI_ExtraInfoGeneralTopic, // 0x4C,
|
||||
RTTI_ExtraHasNoRumors, // 0x4D,
|
||||
RTTI_ExtraSound, // 0x4E,
|
||||
RTTI_ExtraTerminalState, // 0x4F,
|
||||
RTTI_ExtraLinkedRef, // 0x50,
|
||||
RTTI_ExtraLinkedRefChildren, // 0x51,
|
||||
RTTI_ExtraActivateRef, // 0x52,
|
||||
RTTI_ExtraActivateRefChildren, // 0x53,
|
||||
RTTI_ExtraCanTalkToPlayer, // 0x54,
|
||||
RTTI_ExtraObjectHealth, // 0x55,
|
||||
RTTI_ExtraCellImageSpace, // 0x56,
|
||||
RTTI_ExtraNavMeshPortal, // 0x57,
|
||||
RTTI_ExtraModelSwap, // 0x58,
|
||||
RTTI_ExtraRadius, // 0x59,
|
||||
NULL, // 0x5A,
|
||||
RTTI_ExtraFactionChanges, // 0x5B,
|
||||
RTTI_ExtraDismemberedLimbs, // 0x5C,
|
||||
RTTI_ExtraActorCause, // 0x5D,
|
||||
RTTI_ExtraMultiBound, // 0x5E,
|
||||
NULL, // 0x5F, was ExtraMultiBoundData, removed in 1.7.7.0
|
||||
RTTI_ExtraMultiBoundRef, // 0x60,
|
||||
RTTI_ExtraReflectedRefs, // 0x61,
|
||||
RTTI_ExtraReflectorRefs, // 0x62,
|
||||
RTTI_ExtraEmittanceSource, // 0x63,
|
||||
NULL, // 0x64, was ExtraRadioData, removed in 1.7.7.0
|
||||
RTTI_ExtraCombatStyle, // 0x65,
|
||||
NULL, // 0x66,
|
||||
RTTI_ExtraPrimitive, // 0x67,
|
||||
RTTI_ExtraOpenCloseActivateRef, // 0x68,
|
||||
RTTI_ExtraAnimNoteReceiver, // 0x69,
|
||||
RTTI_ExtraAmmo, // 0x6A,
|
||||
RTTI_ExtraPatrolRefData, // 0x6B,
|
||||
RTTI_ExtraPackageData, // 0x6C,
|
||||
RTTI_ExtraOcclusionShape, // 0x6D,
|
||||
RTTI_ExtraCollisionData, // 0x6E,
|
||||
RTTI_ExtraSayTopicInfoOnceADay, // 0x6F,
|
||||
RTTI_ExtraEncounterZone, // 0x70,
|
||||
RTTI_ExtraSayToTopicInfo, // 0x71,
|
||||
RTTI_ExtraOcclusionPlaneRefData, // 0x72,
|
||||
RTTI_ExtraPortalRefData, // 0x73,
|
||||
RTTI_ExtraPortal, // 0x74,
|
||||
RTTI_ExtraRoom, // 0x75,
|
||||
RTTI_ExtraHealthPerc, // 0x76,
|
||||
RTTI_ExtraRoomRefData, // 0x77,
|
||||
RTTI_ExtraGuardedRefData, // 0x78,
|
||||
RTTI_ExtraCreatureAwakeSound, // 0x79,
|
||||
NULL, // 0x7A,
|
||||
RTTI_ExtraHorse, // 0x7B,
|
||||
RTTI_ExtraIgnoredBySandbox, // 0x7C,
|
||||
RTTI_ExtraCellAcousticSpace, // 0x7D,
|
||||
RTTI_ExtraReservedMarkers, // 0x7E,
|
||||
RTTI_ExtraWeaponIdleSound, // 0x7F,
|
||||
RTTI_ExtraWaterLightRefs, // 0x80,
|
||||
RTTI_ExtraLitWaterRefs, // 0x81,
|
||||
RTTI_ExtraWeaponAttackSound, // 0x82,
|
||||
RTTI_ExtraActivateLoopSound, // 0x83,
|
||||
RTTI_ExtraPatrolRefInUseData, // 0x84,
|
||||
RTTI_ExtraAshPileRef, // 0x85,
|
||||
NULL, // 0x86
|
||||
RTTI_ExtraFollowerSwimBreadcrumbs, // 0x87,
|
||||
RTTI_ExtraAliasInstanceArray, // 0x88,
|
||||
RTTI_ExtraLocation, // 0x89,
|
||||
NULL, // 0x8A,
|
||||
RTTI_ExtraLocationRefType, // 0x8B,
|
||||
RTTI_ExtraPromotedRef, // 0x8C,
|
||||
NULL, // 0x8D,
|
||||
RTTI_ExtraOutfitItem, // 0x8E,
|
||||
NULL, // 0x8F,
|
||||
RTTI_ExtraLeveledItemBase, // 0x90,
|
||||
RTTI_ExtraLightData, // 0x91,
|
||||
RTTI_ExtraSceneData, // 0x92,
|
||||
RTTI_ExtraBadPosition, // 0x93,
|
||||
RTTI_ExtraHeadTrackingWeight, // 0x94,
|
||||
RTTI_ExtraFromAlias, // 0x95,
|
||||
RTTI_ExtraShouldWear, // 0x96,
|
||||
RTTI_ExtraFavorCost, // 0x97,
|
||||
RTTI_ExtraAttachedArrows3D, // 0x98,
|
||||
RTTI_ExtraTextDisplayData, // 0x99,
|
||||
RTTI_ExtraAlphaCutoff, // 0x9A,
|
||||
RTTI_ExtraEnchantment, // 0x9B,
|
||||
RTTI_ExtraSoul, // 0x9C,
|
||||
RTTI_ExtraForcedTarget, // 0x9D,
|
||||
NULL, // 0x9E,
|
||||
RTTI_ExtraUniqueID, // 0x9F,
|
||||
RTTI_ExtraFlags, // 0xA0,
|
||||
RTTI_ExtraRefrPath, // 0xA1,
|
||||
RTTI_ExtraDecalGroup, // 0xA2,
|
||||
RTTI_ExtraLockList, // 0xA3,
|
||||
RTTI_ExtraForcedLandingMarker, // 0xA4,
|
||||
RTTI_ExtraLargeRefOwnerCells, // 0xA5,
|
||||
RTTI_ExtraCellWaterEnvMap, // 0xA6,
|
||||
RTTI_ExtraCellGrassData, // 0xA7,
|
||||
RTTI_ExtraTeleportName, // 0xA8,
|
||||
RTTI_ExtraInteraction, // 0xA9,
|
||||
RTTI_ExtraWaterData, // 0xAA,
|
||||
RTTI_ExtraWaterCurrentZoneData, // 0xAB,
|
||||
RTTI_ExtraAttachRef, // 0xAC,
|
||||
RTTI_ExtraAttachRefChildren, // 0xAD,
|
||||
RTTI_ExtraGroupConstraint, // 0xAE,
|
||||
RTTI_ExtraScriptedAnimDependence, // 0xAF,
|
||||
RTTI_ExtraCachedScale, // 0xB0,
|
||||
RTTI_ExtraRaceData, // 0xB1,
|
||||
RTTI_ExtraGIDBuffer, // 0xB2,
|
||||
RTTI_ExtraMissingRefIDs, // 0xB3
|
||||
}; |
||||
|
||||
|
||||
BSExtraData* BaseExtraList::GetByType(UInt32 type) |
||||
{ |
||||
BSReadLocker locker(&m_lock); |
||||
if (!HasType(type)) return NULL; |
||||
|
||||
const void* rttiType = RTTIForExtraType[type]; |
||||
|
||||
for(BSExtraData * traverse = m_data; traverse; traverse = traverse->next) { |
||||
if (Runtime_DynamicCast((void*)(traverse), RTTI_BSExtraData, rttiType) != NULL) { |
||||
return traverse; |
||||
} |
||||
//if(traverse->type == type)
|
||||
// return traverse;
|
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
bool BaseExtraList::Remove(UInt8 type, BSExtraData* toRemove) |
||||
{ |
||||
BSWriteLocker locker(&m_lock); |
||||
if (!toRemove) return false; |
||||
|
||||
if (HasType(type)) { |
||||
bool bRemoved = false; |
||||
if (m_data == toRemove) { |
||||
m_data = m_data->next; |
||||
bRemoved = true; |
||||
} |
||||
|
||||
for (BSExtraData* traverse = m_data; traverse; traverse = traverse->next) { |
||||
if (traverse->next == toRemove) { |
||||
traverse->next = toRemove->next; |
||||
bRemoved = true; |
||||
break; |
||||
} |
||||
} |
||||
if (bRemoved) { |
||||
MarkType(type, true); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
bool BaseExtraList::Add(UInt8 type, BSExtraData* toAdd) |
||||
{ |
||||
if (!toAdd || HasType(type)) return false; |
||||
|
||||
BSWriteLocker locker(&m_lock); |
||||
BSExtraData* next = m_data; |
||||
m_data = toAdd; |
||||
toAdd->next = next; |
||||
MarkType(type, false); |
||||
return true; |
||||
} |
||||
|
||||
bool BaseExtraList::CheckContainerExtraData(bool isEquipped) |
||||
{ |
||||
return CALL_MEMBER_FN(this, CheckContainerExtraData_Internal)(isEquipped); |
||||
} |
||||
|
||||
const char * BaseExtraList::GetDisplayName(TESForm * type) |
||||
{ |
||||
float healthValue = 1.0; |
||||
|
||||
ExtraHealth* xHealth = static_cast<ExtraHealth*>(GetByType(kExtraData_Health)); |
||||
if(xHealth) |
||||
healthValue = xHealth->health; |
||||
|
||||
ExtraTextDisplayData * xText = CALL_MEMBER_FN(this, GetExtraTextDisplayData_Internal)(); |
||||
if (!xText && healthValue != 1.0) |
||||
{ |
||||
xText = ExtraTextDisplayData::Create(); |
||||
Add(kExtraData_TextDisplayData, xText); |
||||
} |
||||
|
||||
if (xText) |
||||
return xText->GenerateName(type, healthValue); |
||||
else |
||||
return NULL; |
||||
} |
||||
|
||||
BSExtraData* BSExtraData::Create(UInt32 size, uintptr_t vtbl) |
||||
{ |
||||
void* memory = Heap_Allocate(size); |
||||
memset(memory, 0, size); |
||||
((uintptr_t *)memory)[0] = vtbl; |
||||
BSExtraData* xData = (BSExtraData*)memory; |
||||
return xData; |
||||
} |
@ -0,0 +1,268 @@ |
||||
#pragma once |
||||
|
||||
#include "GameTypes.h" |
||||
#include "skse64_common/Utilities.h" |
||||
|
||||
class ExtraTextDisplayData; |
||||
|
||||
enum ExtraDataType |
||||
{ |
||||
kExtraData_Havok = 0x1, |
||||
kExtraData_Cell3D = 0x2, |
||||
kExtraData_CellWaterType = 0x3, |
||||
kExtraData_RegionList = 0x4, |
||||
kExtraData_SeenData = 0x5, |
||||
kExtraData_EditorID = 0x6, |
||||
kExtraData_CellMusicType = 0x7, |
||||
kExtraData_CellSkyRegion = 0x8, |
||||
kExtraData_ProcessMiddleLow = 0x9, |
||||
kExtraData_DetachTime = 0xA, |
||||
kExtraData_PersistentCell = 0xB, |
||||
// ?? = 0xC,
|
||||
kExtraData_Action = 0xD, |
||||
kExtraData_StartingPosition = 0xE, |
||||
// ?? = 0xF,
|
||||
kExtraData_AnimGraphManager = 0x10, |
||||
// ?? = 0x11,
|
||||
kExtraData_UsedMarkers = 0x12, |
||||
kExtraData_DistantData = 0x13, |
||||
kExtraData_RagDollData = 0x14, |
||||
kExtraData_ContainerChanges = 0x15, |
||||
kExtraData_Worn = 0x16, |
||||
kExtraData_WornLeft = 0x17, |
||||
kExtraData_PackageStartLocation = 0x18, |
||||
kExtraData_Package = 0x19, |
||||
kExtraData_TresPassPackage = 0x1A, |
||||
kExtraData_RunOncePacks = 0x1B, |
||||
kExtraData_ReferenceHandle = 0x1C, |
||||
kExtraData_Follower = 0x1D, |
||||
kExtraData_LevCreaModifier = 0x1E, |
||||
kExtraData_Ghost = 0x1F, |
||||
kExtraData_OriginalReference = 0x20, |
||||
kExtraData_Ownership = 0x21, |
||||
kExtraData_Global = 0x22, |
||||
kExtraData_Rank = 0x23, |
||||
kExtraData_Count = 0x24, |
||||
kExtraData_Health = 0x25, |
||||
// ?? = 0x26,
|
||||
kExtraData_TimeLeft = 0x27, |
||||
kExtraData_Charge = 0x28, |
||||
kExtraData_Light = 0x29, |
||||
kExtraData_Lock = 0x2A, |
||||
kExtraData_Teleport = 0x2B, |
||||
kExtraData_MapMarker = 0x2C, |
||||
kExtraData_LeveledCreature = 0x2D, |
||||
kExtraData_LeveledItem = 0x2E, |
||||
kExtraData_Scale = 0x2F, |
||||
kExtraData_Seed = 0x30, |
||||
kExtraData_MagicCaster = 0x31, // ExtraMagicLight??
|
||||
// ?? = 0x32,
|
||||
// ?? = 0x33,
|
||||
kExtraData_PlayerCrimeList = 0x34, |
||||
// ?? = 0x35,
|
||||
kExtraData_EnableStateParent = 0x36, |
||||
kExtraData_EnableStateChildren = 0x37, |
||||
kExtraData_ItemDropper = 0x38, |
||||
kExtraData_DroppedItemList = 0x39, |
||||
kExtraData_RandomTeleportMarker = 0x3A, |
||||
//?? = 0x3B
|
||||
kExtraData_SavedHavokData = 0x3C, |
||||
kExtraData_CannotWear = 0x3D, |
||||
kExtraData_Poison = 0x3E, |
||||
//?? = 0x3F
|
||||
kExtraData_LastFinishedSequence = 0x40, |
||||
kExtraData_SavedAnimation = 0x41, |
||||
kExtraData_NorthRotation = 0x42, |
||||
kExtraData_SpawnContainer = 0x43, |
||||
kExtraData_FriendHits = 0x44, |
||||
kExtraData_HeadingTarget = 0x45, |
||||
//?? = 0x46
|
||||
kExtraData_RefractionProperty = 0x47, |
||||
kExtraData_StartingWorldOrCell = 0x48, |
||||
kExtraData_Hotkey = 0x49, |
||||
//?? 0x4A
|
||||
kExtraData_EditiorRefMoveData = 0x4B, |
||||
kExtraData_InfoGeneralTopic = 0x4C, |
||||
kExtraData_HasNoRumors = 0x4D, |
||||
kExtraData_Sound = 0x4E, |
||||
kExtraData_TerminalState = 0x4F, |
||||
kExtraData_LinkedRef = 0x50, |
||||
kExtraData_LinkedRefChildren = 0x51, |
||||
kExtraData_ActivateRef = 0x52, |
||||
kExtraData_ActivateRefChildren =0x53, |
||||
kExtraData_CanTalkToPlayer = 0x54, |
||||
kExtraData_ObjectHealth = 0x55, |
||||
kExtraData_CellImageSpace = 0x56, |
||||
kExtraData_NavMeshPortal = 0x57, |
||||
kExtraData_ModelSwap = 0x58, |
||||
kExtraData_Radius = 0x59, |
||||
//?? = 0x5A,
|
||||
kExtraData_FactionChanges = 0x5B, |
||||
kExtraData_DismemberedLimbs = 0x5C, |
||||
kExtraData_ActorCause = 0x5D, |
||||
kExtraData_MultiBound = 0x5E, |
||||
kExtraData_MultiBoundData = 0x5F, |
||||
kExtraData_MultiBoundRef = 0x60, |
||||
kExtraData_ReflectedRefs = 0x61, |
||||
kExtraData_ReflectorRefs = 0x62, |
||||
kExtraData_EmittanceSource = 0x63, |
||||
kExtraData_RadioData = 0x64, |
||||
kExtraData_CombatStyle = 0x65, |
||||
//?? = 0x66,
|
||||
kExtraData_Primitive = 0x67, |
||||
kExtraData_OpenCloseActivateRef = 0x68, |
||||
kExtraData_AnimNoteReceiver = 0x69, |
||||
kExtraData_Ammo = 0x6A, |
||||
kExtraData_PatrolRefData = 0x6B, |
||||
kExtraData_PackageData = 0x6C, |
||||
kExtraData_OcclusionShape = 0x6D, |
||||
kExtraData_CollisionData = 0x6E, |
||||
kExtraData_SayTopicInfoOnceADay = 0x6F, |
||||
kExtraData_EncounterZone = 0x70, |
||||
kExtraData_SayTopicInfo = 0x71, |
||||
kExtraData_OcclusionPlaneRefData = 0x72, |
||||
kExtraData_PortalRefData = 0x73, |
||||
kExtraData_Portal = 0x74, |
||||
kExtraData_Room = 0x75, |
||||
kExtraData_HealthPerc = 0x76, |
||||
kExtraData_RoomRefData = 0x77, |
||||
kExtraData_GuardedRefData = 0x78, |
||||
kExtraData_CreatureAwakeSound = 0x79, |
||||
//?? = 0x7A,
|
||||
kExtraData_Horse = 0x7B, |
||||
kExtraData_IgnoredBySandbox = 0x7C, |
||||
kExtraData_CellAcousticSpace = 0x7D, |
||||
kExtraData_ReservedMarkers = 0x7E, |
||||
kExtraData_WeaponIdleSound = 0x7F, |
||||
kExtraData_WaterLightRefs = 0x80, |
||||
kExtraData_LitWaterRefs = 0x81, |
||||
kExtraData_WeaponAttackSound = 0x82, |
||||
kExtraData_ActivateLoopSound = 0x83, |
||||
kExtraData_PatrolRefInUseData = 0x84, |
||||
kExtraData_AshPileRef = 0x85, |
||||
//?? = 0x86
|
||||
kExtraData_FollowerSwimBreadcrumbs = 0x87, |
||||
kExtraData_AliasInstanceArray = 0x88, |
||||
kExtraData_Location = 0x89, |
||||
//?? = 0x8A,
|
||||
kExtraData_LocationRefType = 0x8B, |
||||
kExtraData_PromotedRef = 0x8C, |
||||
//?? = 0x8D,
|
||||
kExtraData_OutfitItem = 0x8E, |
||||
//?? = 0x8F,
|
||||
kExtraData_LeveledItemBase = 0x90, |
||||
kExtraData_LightData = 0x91, |
||||
kExtraData_SceneData = 0x92, |
||||
kExtraData_BadPosition = 0x93, |
||||
kExtraData_HeadTrackingWeight = 0x94, |
||||
kExtraData_FromAlias = 0x95, |
||||
kExtraData_ShouldWear = 0x96, |
||||
kExtraData_FavorCost = 0x97, |
||||
kExtraData_AttachedArrows3D = 0x98, |
||||
kExtraData_TextDisplayData = 0x99, |
||||
kExtraData_AlphaCutoff = 0x9A, |
||||
kExtraData_Enchantment = 0x9B, |
||||
kExtraData_Soul = 0x9C, |
||||
kExtraData_ForcedTarget = 0x9D, |
||||
//?? = 0x9E,
|
||||
kExtraData_UniqueID = 0x9F, |
||||
kExtraData_Flags = 0xA0, |
||||
kExtraData_RefrPath = 0xA1, |
||||
kExtraData_DecalGroup = 0xA2, |
||||
kExtraData_LockList = 0xA3, |
||||
kExtraData_ForcedLandingMarker = 0xA4, |
||||
kExtraData_LargeRefOwnerCells = 0xA5, |
||||
kExtraData_CellWaterEnvMap = 0xA6, |
||||
kExtraData_CellGrassData = 0xA7, |
||||
kExtraData_TeleportName = 0xA8, |
||||
kExtraData_Interaction = 0xA9, |
||||
kExtraData_WaterData = 0xAA, |
||||
kExtraData_WaterCurrentZoneData = 0xAB, |
||||
kExtraData_AttachRef = 0xAC, |
||||
kExtraData_AttachRefChildren = 0xAD, |
||||
kExtraData_GroupConstraint = 0xAE, |
||||
kExtraData_ScriptedAnimDependence = 0xAF, |
||||
kExtraData_CachedScale = 0xB0, |
||||
kExtraData_RaceData = 0xB1, |
||||
kExtraData_GIDBuffer = 0xB2, |
||||
kExtraData_MissingRefIDs = 0xB3 |
||||
}; |
||||
|
||||
// 10
|
||||
class BSExtraData |
||||
{ |
||||
public: |
||||
BSExtraData(); |
||||
virtual ~BSExtraData(); |
||||
virtual UInt32 GetType(void); |
||||
|
||||
BSExtraData* next; // 08
|
||||
//UInt8 type; // 10
|
||||
//UInt8 padding[3];
|
||||
static BSExtraData* Create(UInt32 size, uintptr_t vtbl); |
||||
}; |
||||
//STATIC_ASSERT(sizeof(BSExtraData) == 0x10);
|
||||
|
||||
// 18
|
||||
class BaseExtraList |
||||
{ |
||||
public: |
||||
BaseExtraList(); |
||||
~BaseExtraList(); |
||||
|
||||
struct PresenceBitfield |
||||
{ |
||||
bool HasType(UInt32 type) const |
||||
{ |
||||
UInt32 index = (type >> 3); |
||||
UInt8 bitMask = 1 << (type % 8); |
||||
return (bits[index] & bitMask) != 0; |
||||
} |
||||
|
||||
UInt8 bits[0x18]; |
||||
}; |
||||
|
||||
bool HasType(UInt32 type) |
||||
{ |
||||
BSReadLocker locker(&m_lock); |
||||
return (m_presence) ? m_presence->HasType(type) : false; |
||||
} |
||||
|
||||
void MarkType(UInt32 type, bool bCleared) |
||||
{ |
||||
UInt32 index = (type >> 3); |
||||
UInt8 bitMask = 1 << (type % 8); |
||||
UInt8& flag = m_presence->bits[index]; |
||||
if (bCleared) { |
||||
flag &= ~bitMask; |
||||
} else { |
||||
flag |= bitMask; |
||||
} |
||||
} |
||||
|
||||
bool Remove(UInt8 type, BSExtraData* toRemove); |
||||
bool Add(UInt8 type, BSExtraData* toAdd); |
||||
|
||||
bool CheckContainerExtraData(bool isEquipped); |
||||
|
||||
const char * GetDisplayName(TESForm * type); |
||||
|
||||
BSExtraData* GetByType(UInt32 type); |
||||
BSExtraData * m_data; // 00
|
||||
PresenceBitfield * m_presence; // 08
|
||||
|
||||
// These added in SE
|
||||
BSReadWriteLock m_lock; |
||||
|
||||
private: |
||||
MEMBER_FN_PREFIX(BaseExtraList); |
||||
// 6AE109C256B98466C001B25B75BD48FB62F884B1+5A
|
||||
DEFINE_MEMBER_FN(CheckContainerExtraData_Internal, bool, 0x0010CC40, bool isEquipped); |
||||
// This also does some internal ReferenceHandle lookup
|
||||
// B995A21984B048C2B4F61777E615FFFB2806F9B7
|
||||
DEFINE_MEMBER_FN(GetExtraTextDisplayData_Internal, ExtraTextDisplayData*, 0x00111420); |
||||
}; |
||||
|
||||
typedef tList<BaseExtraList> ExtendDataList; |
||||
|
||||
STATIC_ASSERT(sizeof(BaseExtraList) == 0x18); |
@ -0,0 +1,27 @@ |
||||
#include "GameCamera.h" |
||||
|
||||
void LocalMapCamera::SetDefaultStateMinFrustumDimensions(float width, float height) |
||||
{ |
||||
defaultState->minFrustumWidth = width / 2.0; |
||||
defaultState->minFrustumHeight = height / 2.0; |
||||
} |
||||
|
||||
void LocalMapCamera::SetAreaBounds(NiPoint3 * maxBound, NiPoint3 * minBound) |
||||
{ |
||||
areaBoundsMin = *minBound; |
||||
areaBoundsMax = *maxBound; |
||||
areaBoundsMax.z += (*g_mapLocalHeight); |
||||
} |
||||
|
||||
void LocalMapCamera::SetDefaultStateMaxBound(NiPoint3 * maxBound) |
||||
{ |
||||
defaultState->someBoundMax = *maxBound; |
||||
defaultState->someBoundMax.z += (*g_mapLocalHeight); |
||||
} |
||||
|
||||
void LocalMapCamera::SetDefaultStateBounds(float x, float y, float z) |
||||
{ |
||||
defaultState->someBoundMin.x = x - defaultState->someBoundMax.x; |
||||
defaultState->someBoundMin.y = y - defaultState->someBoundMax.y; |
||||
defaultState->someBoundMin.z = z - defaultState->someBoundMax.z; |
||||
} |
@ -0,0 +1,387 @@ |
||||
#pragma once |
||||
|
||||
#include "GameTypes.h" |
||||
#include "GameInput.h" |
||||
|
||||
#include "GameSettings.h" |
||||
|
||||
#include "skse64/NiObjects.h" |
||||
#include "skse64/NiTypes.h" |
||||
|
||||
class TESCamera; |
||||
class NiNode; |
||||
|
||||
// 20
|
||||
class TESCameraState |
||||
{ |
||||
public: |
||||
TESCameraState(); |
||||
virtual ~TESCameraState(); |
||||
|
||||
virtual void OnStateStart(); // pure
|
||||
virtual void OnStateEnd(); // pure
|
||||
virtual void OnUpdate(void * unk1); |
||||
virtual void Unk_04(); |
||||
virtual void Unk_05(); |
||||
virtual void Unk_06(); // pure
|
||||
virtual void Unk_07(); // pure
|
||||
virtual void Unk_08(); // pure
|
||||
|
||||
BSIntrusiveRefCounted refCount; // 08
|
||||
TESCamera * camera; // 10
|
||||
UInt32 stateId; // 18
|
||||
UInt32 pad1C; // 1C
|
||||
}; |
||||
|
||||
// 90
|
||||
class FirstPersonState : public TESCameraState |
||||
{ |
||||
public: |
||||
FirstPersonState(); |
||||
virtual ~FirstPersonState(); |
||||
|
||||
PlayerInputHandler inputHandler; // 20
|
||||
float unk30[6]; // 30
|
||||
UInt64 unk48; // 48
|
||||
UInt64 unk50; // 50
|
||||
void* unk58; // 58
|
||||
void* unk60; // 60
|
||||
float unk68[3]; // 70
|
||||
UInt32 unk74; // 74
|
||||
UInt32 unk78; // 78
|
||||
float unk7C; // 7C
|
||||
UInt32 unk80; // 80
|
||||
UInt8 unk84[4]; // 84
|
||||
UInt64 unk88; // 88
|
||||
}; |
||||
STATIC_ASSERT(sizeof(FirstPersonState) == 0x90); |
||||
|
||||
// E8
|
||||
class ThirdPersonState : public TESCameraState |
||||
{ |
||||
public: |
||||
ThirdPersonState(); |
||||
virtual ~ThirdPersonState(); |
||||
virtual void Unk_09(void); |
||||
virtual void Unk_0A(void); |
||||
virtual void UpdateMode(bool weaponDrawn); |
||||
|
||||
PlayerInputHandler inputHandler; // 20
|
||||
NiNode * cameraNode; // 30
|
||||
NiNode * controllerNode; // 38
|
||||
float unk40[4]; // 40
|
||||
UInt32 unk50[3]; // 50
|
||||
float fOverShoulderPosX; // 5C
|
||||
float fOverShoulderCombatAddY; // 60
|
||||
float fOverShoulderPosZ; // 64
|
||||
float unk68[3]; // 68
|
||||
UInt32 unk74[6]; // 74
|
||||
float unk8C; // 8C - init'd 7F7FFFFF
|
||||
UInt32 unk90[3]; // 90
|
||||
float unk9C; // 9C - init'd 7F7FFFFF
|
||||
UInt64 unkA0; // A0
|
||||
UInt64 unkA8; // A8
|
||||
float unkB0; // B0
|
||||
UInt32 unkB4[3]; // B4
|
||||
float unkC0[6]; // C0
|
||||
UInt32 unkD8; // D8
|
||||
UInt8 unkDC[7]; // DC
|
||||
UInt8 padE3[5]; // E3
|
||||
}; |
||||
STATIC_ASSERT(sizeof(ThirdPersonState) == 0xE8); |
||||
|
||||
// 110
|
||||
class DragonCameraState : public ThirdPersonState |
||||
{ |
||||
public: |
||||
DragonCameraState(); |
||||
virtual ~DragonCameraState(); |
||||
|
||||
UInt32 unkE8; // 0E8
|
||||
UInt32 unkEC; // 0EC
|
||||
UInt8 unkF0; // 0F0
|
||||
UInt8 padF1[3]; // 0F1
|
||||
float unkF4; // 0F4 - init'd to 1
|
||||
UInt8 unkF8; // 0F8
|
||||
UInt8 padF9[3]; // 0F9
|
||||
float unkFC[4]; // 0FC
|
||||
UInt32 unk10C; // 10C
|
||||
}; |
||||
|
||||
// F8
|
||||
class HorseCameraState : public ThirdPersonState |
||||
{ |
||||
public: |
||||
HorseCameraState(); |
||||
virtual ~HorseCameraState(); |
||||
|
||||
UInt32 unkE8; // E8
|
||||
UInt32 unkEC; // EC
|
||||
UInt8 unkF0; // F0
|
||||
UInt8 padF1[7]; // F1
|
||||
}; |
||||
|
||||
// 50
|
||||
class TweenMenuCameraState : public TESCameraState |
||||
{ |
||||
public: |
||||
TweenMenuCameraState(); |
||||
virtual ~TweenMenuCameraState(); |
||||
|
||||
float unk20[4]; // 20
|
||||
UInt32 unk30; // 30
|
||||
float unk34[4]; // 34
|
||||
UInt32 unk44; // 44
|
||||
UInt32 unk48; // 48
|
||||
UInt8 unk4C; // 4C
|
||||
UInt8 pad4D[3]; // 4D
|
||||
}; |
||||
|
||||
// 38
|
||||
class VATSCameraState : public TESCameraState |
||||
{ |
||||
public: |
||||
VATSCameraState(); |
||||
virtual ~VATSCameraState(); |
||||
|
||||
float unk20[6]; // 20
|
||||
}; |
||||
|
||||
// 50
|
||||
class FreeCameraState : public TESCameraState |
||||
{ |
||||
public: |
||||
FreeCameraState(); |
||||
virtual ~FreeCameraState(); |
||||
|
||||
PlayerInputHandler inputHandler; // 20
|
||||
float unk30[7]; // 30
|
||||
UInt32 unk4C; // 4C
|
||||
}; |
||||
|
||||
// 28
|
||||
class AutoVanityState : public TESCameraState |
||||
{ |
||||
public: |
||||
AutoVanityState(); |
||||
virtual ~AutoVanityState(); |
||||
|
||||
UInt32 unk20; // 20
|
||||
UInt32 pad24; // 24
|
||||
}; |
||||
|
||||
// 40
|
||||
class FurnitureCameraState : public TESCameraState |
||||
{ |
||||
public: |
||||
FurnitureCameraState(); |
||||
virtual ~FurnitureCameraState(); |
||||
|
||||
UInt32 unk20; // 20
|
||||
float unk24; // 24
|
||||
float unk28; // 28
|
||||
float unk2C; // 2C
|
||||
UInt32 unk30; // 30
|
||||
UInt32 unk34; // 34
|
||||
UInt32 unk38; // 38
|
||||
UInt8 unk3C; // 3C
|
||||
UInt8 unk3D; // 3D
|
||||
UInt8 unk3E; // 3E
|
||||
UInt8 pad3F; // 3F
|
||||
}; |
||||
|
||||
// 28
|
||||
class IronSightsState : public TESCameraState |
||||
{ |
||||
public: |
||||
IronSightsState(); |
||||
virtual ~IronSightsState(); |
||||
|
||||
UInt64 unk20; // 20
|
||||
}; |
||||
|
||||
// 138
|
||||
class BleedoutCameraState : public ThirdPersonState |
||||
{ |
||||
public: |
||||
BleedoutCameraState(); |
||||
virtual ~BleedoutCameraState(); |
||||
|
||||
float unkE8[8]; // E8
|
||||
UInt32 unk108; // 108
|
||||
float unk10C; // 10C - init'd to 200
|
||||
float unk110; // 110 - init'd to 0.523599 (PI/6)
|
||||
UInt32 unk114; // 114
|
||||
float unk118; // 118
|
||||
UInt32 pad11C; // 11C
|
||||
UInt64 unk120; // 120
|
||||
UInt32 unk128; // 128 - init'd to FFFFFFFF
|
||||
UInt8 unk12C; // 12C
|
||||
UInt8 pad12D[3]; // 12D
|
||||
UInt32 unk130; // 130
|
||||
UInt8 unk134; // 134
|
||||
UInt8 pad135[3]; // 135
|
||||
}; |
||||
|
||||
// 40
|
||||
class PlayerCameraTransitionState : public TESCameraState |
||||
{ |
||||
public: |
||||
PlayerCameraTransitionState(); |
||||
virtual ~PlayerCameraTransitionState(); |
||||
|
||||
UInt32 unk20; // 20
|
||||
UInt32 unk24; // 24
|
||||
UInt64 unk28; // 28
|
||||
UInt64 unk30; // 30
|
||||
UInt32 unk38; // 38
|
||||
UInt8 unk3C; // 3C
|
||||
UInt8 unk3D; // 3D
|
||||
UInt16 pad3E; |
||||
}; |
||||
|
||||
// 38
|
||||
class TESCamera |
||||
{ |
||||
public: |
||||
TESCamera(); |
||||
virtual ~TESCamera(); |
||||
|
||||
virtual void SetNode(NiNode * node); |
||||
virtual void Update(); |
||||
|
||||
float rotZ; // 08
|
||||
float rotX; // 0C
|
||||
NiPoint3 pos; // 10
|
||||
float zoom; // 1C
|
||||
NiNode * cameraNode; // 20 - First child is usually NiCamera
|
||||
TESCameraState * cameraState; // 28
|
||||
UInt8 unk30; // 30
|
||||
UInt8 pad31[7]; // 31
|
||||
|
||||
MEMBER_FN_PREFIX(TESCamera); |
||||
DEFINE_MEMBER_FN(SetCameraState, UInt32, 0x004F5C80, TESCameraState * cameraState); |
||||
}; |
||||
STATIC_ASSERT(offsetof(TESCamera, cameraNode) == 0x20); |
||||
STATIC_ASSERT(sizeof(TESCamera) == 0x38); |
||||
|
||||
// 68
|
||||
class LocalMapCamera : public TESCamera |
||||
{ |
||||
public: |
||||
LocalMapCamera(); |
||||
virtual ~LocalMapCamera(); |
||||
|
||||
// 48
|
||||
class DefaultState : public TESCameraState |
||||
{ |
||||
public: |
||||
NiPoint3 someBoundMax; // 20
|
||||
NiPoint3 someBoundMin; // 2C
|
||||
float zoomPercent; // 38
|
||||
float minFrustumWidth; // 3C
|
||||
float minFrustumHeight; // 40
|
||||
UInt32 pad44; // 44
|
||||
}; |
||||
|
||||
NiPoint3 areaBoundsMax; // 38
|
||||
NiPoint3 areaBoundsMin; // 44
|
||||
DefaultState * defaultState; // 50
|
||||
NiObject * niCamera; // 58
|
||||
float northRotation; // 60
|
||||
UInt32 pad64; // 64
|
||||
|
||||
void SetDefaultStateMinFrustumDimensions(float width, float height); |
||||
void SetAreaBounds(NiPoint3 * maxBound, NiPoint3 * minBound); |
||||
void SetDefaultStateMaxBound(NiPoint3 * maxBound); |
||||
void SetDefaultStateBounds(float x, float y, float z); |
||||
|
||||
MEMBER_FN_PREFIX(LocalMapCamera); |
||||
DEFINE_MEMBER_FN(ctor, void, 0x001F5390); |
||||
DEFINE_MEMBER_FN(SetNorthRotation, void, 0x001F5750, float northRotation); |
||||
}; |
||||
|
||||
STATIC_ASSERT(offsetof(LocalMapCamera, northRotation) == 0x60); |
||||
|
||||
// 90
|
||||
class MapCamera : public TESCamera |
||||
{ |
||||
public: |
||||
MapCamera(); |
||||
virtual ~MapCamera(); |
||||
|
||||
float unk38[5]; // 38
|
||||
UInt32 unk4C[3]; // 4C
|
||||
UInt64 unk58; // 58
|
||||
UInt32 unk60; // 60
|
||||
UInt32 unk64; // 64
|
||||
UInt64 unk68[2]; // 68
|
||||
UInt64 unk78; // 78
|
||||
UInt64 unk80; // 80
|
||||
UInt8 unk88; // 88
|
||||
UInt8 pad89[7]; // 89
|
||||
}; |
||||
|
||||
// 38
|
||||
class RaceSexCamera : public TESCamera |
||||
{ |
||||
public: |
||||
RaceSexCamera(); |
||||
virtual ~RaceSexCamera(); |
||||
}; |
||||
|
||||
// 168
|
||||
class PlayerCamera : public TESCamera |
||||
{ |
||||
public: |
||||
PlayerCamera(); |
||||
virtual ~PlayerCamera(); |
||||
|
||||
static PlayerCamera * GetSingleton(void) |
||||
{ |
||||
// 0FAF5D3C755F11266ECC496FD392A0A2EA23403B+37
|
||||
static RelocPtr<PlayerCamera*> g_playerCamera(0x02EC59B8); |
||||
return *g_playerCamera; |
||||
} |
||||
|
||||
enum |
||||
{ |
||||
kCameraState_FirstPerson = 0, |
||||
kCameraState_AutoVanity, |
||||
kCameraState_VATS, |
||||
kCameraState_Free, |
||||
kCameraState_IronSights, |
||||
kCameraState_Furniture, |
||||
kCameraState_Transition, |
||||
kCameraState_TweenMenu, |
||||
kCameraState_ThirdPerson1, |
||||
kCameraState_ThirdPerson2, |
||||
kCameraState_Horse, |
||||
kCameraState_Bleedout, |
||||
kCameraState_Dragon, |
||||
kNumCameraStates |
||||
}; |
||||
|
||||
UInt8 unk38[0xB8-0x38]; // 028
|
||||
TESCameraState * cameraStates[kNumCameraStates]; // 0B8
|
||||
UInt64 unk120; // 120
|
||||
UInt64 unk128; // 128
|
||||
UInt64 unk130; // 130
|
||||
UInt32 unk138; // 138
|
||||
float worldFOV; // 13C
|
||||
float firstPersonFOV; // 140
|
||||
UInt8 unk144[0x160-0x144]; // 144
|
||||
UInt8 unk160; // 160
|
||||
UInt8 unk161; // 161
|
||||
UInt8 unk162; // 162 - init'd to 1
|
||||
UInt8 unk163; // 163
|
||||
UInt8 unk164; // 164
|
||||
UInt8 unk165; // 165
|
||||
UInt8 pad166[2]; // 166
|
||||
|
||||
MEMBER_FN_PREFIX(PlayerCamera); |
||||
DEFINE_MEMBER_FN(UpdateThirdPerson, void, 0x0084D630, bool weaponDrawn); |
||||
}; |
||||
|
||||
STATIC_ASSERT(offsetof(PlayerCamera, cameraStates) == 0xB8); |
||||
STATIC_ASSERT(offsetof(PlayerCamera, pad166) == 0x166); |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue