2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

CWE Directory Reorganization

Rearrange directory structure of CWE to be loosely equivalent to
the H'uru Plasma repository.

Part 1: Movement of directories and files.
This commit is contained in:
rarified
2021-05-15 12:49:46 -06:00
parent c3f4a640a3
commit 96903e8dca
4002 changed files with 159 additions and 644 deletions

View File

@ -0,0 +1,644 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plBSDiffBuffer - A utility class for writing and applying a difference
// buffer--i.e. a buffer containing a series of modifications
// that will modify an old data buffer to match a new one.
// It's a useful utility class when doing binary file
// patching, for example, as you can write out the changes
// to this class, get back a data buffer suitable for writing,
// then use this class again later to reconstruct the new buffer.
//
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plBSDiffBuffer.h"
#include "hsUtils.h"
#include "hsStream.h"
#define plBSDiffBuffer_MIN(x,y) (((x)<(y)) ? (x) : (y))
//////////////////////////////////////////////////////////////////////////////
//// Constructor/Destructors /////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Creation Constructor ////////////////////////////////////////////////////
// Use this constructor when creating a new diff buffer. Pass in the length
// of the final new buffer. You don't need to pass in the length of the old
// buffer, but if you do, it'll help this class do some internal space
// optimization.
plBSDiffBuffer::plBSDiffBuffer( UInt32 newLength, UInt32 oldLength )
: fNewLength( newLength )
, fPatchLength( 0 )
{
fPatchBuffer = nil;
fWriting = true;
}
//// Application Constructor /////////////////////////////////////////////////
// Use this constructor when taking a diff buffer and applying it to an old
// buffer. Pass in a pointer to the diff buffer and its length. The buffer
// will be copied, so you don't need to keep it around after you construct
// this object.
plBSDiffBuffer::plBSDiffBuffer( void *buffer, UInt32 length )
: fNewLength( 0 )
, fPatchLength( 0 )
, fPatchBuffer( nil )
, fWriting( false )
{
if (!buffer || length < 32)
hsAssert(false, "Corrupt Patch Buffer!");
if((fPatchBuffer=TRACKED_NEW unsigned char[length+1])!=nil)
{
fPatchLength = length;
memcpy(fPatchBuffer, buffer, fPatchLength);
}
}
plBSDiffBuffer::~plBSDiffBuffer()
{
if ( fPatchBuffer )
delete[] fPatchBuffer;
}
//////////////////////////////////////////////////////////////////////////////
//// Creation/Write Functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Diff /////////////////////////////////////////////////////////////////////
// Diff() creates the diff buffer from the new and old.
UInt32 plBSDiffBuffer::Diff( UInt32 oldLength, void *oldBuffer, UInt32 newLength, void *newBuffer )
{
hsAssert( fWriting, "Trying to Add() to a difference buffer that's reading" );
Int32 *I,*V;
Int32 scan,pos,len;
Int32 lastscan,lastpos,lastoffset;
Int32 oldscore,scsc;
Int32 s,Sf,lenf,Sb,lenb;
Int32 overlap,Ss,lens;
Int32 i;
UInt32 cblen,dblen,eblen;
unsigned char *oldbuf, *newbuf;
unsigned char *cb,*db,*eb;
unsigned char header[32];
if (oldBuffer == nil ||
oldLength < 0 ||
newBuffer == nil ||
newLength < 0)
{
return (-1);
}
oldbuf = (unsigned char *)oldBuffer;
newbuf = (unsigned char *)newBuffer;
if(((I=TRACKED_NEW Int32[oldLength+1])==nil) ||
((V=TRACKED_NEW Int32[oldLength+1])==nil))
{
delete[] I;
delete[] V;
return fPatchLength;
}
IQSuffixSort(I,V,oldbuf,oldLength);
delete[] V;
/*
* These could probably be smaller, especially cb.
*/
if(((cb=TRACKED_NEW unsigned char[newLength+1])==nil) ||
((db=TRACKED_NEW unsigned char[newLength+1])==nil) ||
((eb=TRACKED_NEW unsigned char[newLength+1])==nil))
{
delete[] I;
delete[] cb;
delete[] db;
delete[] eb;
return fPatchLength;
}
cblen=0;
dblen=0;
eblen=0;
/* Header is
0 8 "BSDIFF40"
8 8 length of bzip2ed ctrl block
16 8 length of bzip2ed diff block
24 8 length of new file */
/* File is
0 32 Header
32 ?? Bzip2ed ctrl block
?? ?? Bzip2ed diff block
?? ?? Bzip2ed extra block */
memcpy(header,"BSDIFF40",8);
memset(header+8,0,24);
scan=0;len=0;
lastscan=0;lastpos=0;lastoffset=0;
while(scan<newLength) {
oldscore=0;
for(scsc=scan+=len;scan<newLength;scan++) {
len=ISearch(I,oldbuf,oldLength,newbuf+scan,newLength-scan,
0,oldLength,&pos);
for(;scsc<scan+len;scsc++)
if((scsc+lastoffset<oldLength) &&
(oldbuf[scsc+lastoffset] == newbuf[scsc]))
oldscore++;
if(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffset<oldLength) &&
(oldbuf[scan+lastoffset] == newbuf[scan]))
oldscore--;
};
if((len!=oldscore) || (scan==newLength)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+i<scan)&&(lastpos+i<oldLength);) {
if(oldbuf[lastpos+i]==newbuf[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
lenb=0;
if(scan<newLength) {
s=0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(oldbuf[pos-i]==newbuf[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
if(lastscan+lenf>scan-lenb) {
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;i<overlap;i++) {
if(newbuf[lastscan+lenf-overlap+i]==
oldbuf[lastpos+lenf-overlap+i]) s++;
if(newbuf[scan-lenb+i]==
oldbuf[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
lenf+=lens-overlap;
lenb-=lens;
};
for(i=0;i<lenf;i++)
db[dblen+i]=newbuf[lastscan+i]-oldbuf[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=newbuf[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
IWriteUnsignedInt8(lenf,cb+cblen);
IWriteUnsignedInt8((scan-lenb)-(lastscan+lenf),cb+cblen+8);
IWriteUnsignedInt8((pos-lenb)-(lastpos+lenf),cb+cblen+16);
cblen+=24;
lastscan=scan-lenb;
lastpos=pos-lenb;
lastoffset=pos-scan;
};
};
IWriteUnsignedInt8(cblen,header+8);
IWriteUnsignedInt8(dblen,header+16);
IWriteUnsignedInt8(newLength,header+24);
fPatchLength = 32 + cblen + dblen + eblen;
fPatchBuffer = nil;
if((fPatchBuffer=TRACKED_NEW unsigned char[fPatchLength])!=nil)
{
memcpy(fPatchBuffer,header,32);
memcpy(fPatchBuffer+32,cb,cblen);
memcpy(fPatchBuffer+32+cblen,db,dblen);
memcpy(fPatchBuffer+32+cblen+dblen,eb,eblen);
}
else
{
fPatchLength = 0;
}
delete[] cb;
delete[] db;
delete[] eb;
delete[] I;
return fPatchLength;
}
//// GetBuffer ///////////////////////////////////////////////////////////////
// GetBuffer() will copy the diff stream into a new buffer and return it.
// You are responsible for freeing the buffer. Call this once you're done
// adding ops and want the raw data to write out somewhere. Note: this
// function will rewind the diff stream, so once you call it, you can't do
// anything else on the object.
void plBSDiffBuffer::GetBuffer( UInt32 &length, void *&bufferPtr )
{
hsAssert( fWriting, "Trying to GetBuffer() on a difference buffer that's reading" );
if (fPatchBuffer && fPatchLength)
{
length = fPatchLength;
if (bufferPtr = (void *)TRACKED_NEW unsigned char[ length ])
memcpy(bufferPtr, fPatchBuffer, length);
}
else
{
length = 0;
bufferPtr = nil;
}
}
//////////////////////////////////////////////////////////////////////////////
//// Application Functions ///////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#define hsAssertAndBreak( cond, msg ) { if( cond ) { hsAssert( false, msg ); break; } }
// Patch() will take this diff buffer and apply it to the given old buffer,
// allocating and producing a new buffer. You are responsible for freeing the new buffer.
UInt32 plBSDiffBuffer::Patch( UInt32 oldLength, void *oldBuffer, UInt32 &newLength, void *&newBuffer )
{
hsAssert( !fWriting, "Trying to Patch() a difference buffer that's writing" );
unsigned char *ctrlpipe, *ctrlend;
unsigned char *diffpipe, *diffend;
unsigned char *extrapipe;
UInt32 ctrllen,datalen;
int version=0;
unsigned char *newpos, *newend;
unsigned char *oldpos, *oldend;
unsigned char *patchend;
UInt32 ctrl[3];
UInt32 i;
if (oldBuffer == nil ||
oldLength < 0 ||
newBuffer != nil ||
newLength != 0 ||
fPatchBuffer == nil ||
fPatchLength < 32)
{
return (-1);
}
patchend = fPatchBuffer + fPatchLength;
/*
Ok, this is going to be messy. There are two different patch
formats which we need to support.
The old format (pre-4.0) is:
0 8 "QSUFDIFF" or "BSDIFF30"
8 8 X
16 8 Y
24 8 sizeof(newfile)
32 X bzip2(control block)
32+X Y bzip2(data block)
with control block a set of pairs (x,y) meaning "seek forward
in oldfile by y bytes, and add the next x bytes to x bytes from
the data block".
The new format (4.0) is:
0 8 "BSDIFF40"
8 8 X
16 8 Y
24 8 sizeof(newfile)
32 X bzip2(control block)
32+X Y bzip2(diff block)
32+X+Y ??? bzip2(extra block)
with control block a set of triples (x,y,z) meaning "add x bytes
from oldfile to x bytes from the diff block; copy y bytes from the
extra block; seek forwards in oldfile by z bytes".
*/
if(memcmp(fPatchBuffer,"QSUFDIFF",8)==0) version=1;
if(memcmp(fPatchBuffer,"BSDIFF30",8)==0) version=1;
if(memcmp(fPatchBuffer,"BSDIFF40",8)==0) version=2;
if(!version) return (-1);
ctrllen=IReadUnsignedInt8(fPatchBuffer+8);
datalen=IReadUnsignedInt8(fPatchBuffer+16);
newLength=IReadUnsignedInt8(fPatchBuffer+24);
if((ctrllen<0) || (datalen<0) || (newLength<0) ||
((version==1) && (32+ctrllen+datalen!=fPatchLength)))
return (-1);
ctrlpipe=fPatchBuffer+32;
ctrlend =ctrlpipe+ctrllen;
diffpipe=ctrlend;
diffend = diffpipe + datalen;
if(version==2) {
extrapipe=diffpipe+datalen;
};
if((newBuffer=(void *)TRACKED_NEW unsigned char[newLength+1])==nil) return(-1);
newpos = (unsigned char *)newBuffer;
newend = (unsigned char *)newBuffer + newLength;
oldpos = (unsigned char *)oldBuffer;
oldend = (unsigned char *)oldBuffer + oldLength;
while(newpos<newend) {
for(i=0;i<=version;i++) {
if(ctrlend-ctrlpipe < 8) return (-1);
ctrl[i]=IReadUnsignedInt8(ctrlpipe);
ctrlpipe += 8;
};
if(version==1) oldpos+=ctrl[1];
ISafeMemcpy(newpos, diffpipe, ctrl[0], newend, diffend);
diffpipe += ctrl[0];
for(i=0;i<ctrl[0];i++)
if(oldpos<oldend)
{
*newpos += *oldpos;
newpos++;
oldpos++;
}
if(version==2) {
ISafeMemcpy(newpos,extrapipe,ctrl[1],newend,patchend);
extrapipe += ctrl[1];
newpos+=ctrl[1];
oldpos+=ctrl[2];
};
};
if((ctrlpipe != ctrlend) ||
(diffpipe != diffend) ||
((version==2) && (extrapipe != patchend)))
{
return (-1);
}
if(newpos != newend)
{
delete[] newBuffer;
newLength = 0;
}
return newLength;
}
//////////////////////////////////////////////////////////////////////////////
//// Private Helper Functions ///////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Reads in an 8-byte unsigned integer least significant byte first and returns a
// UInt32. We'll ignore the top four bytes.
UInt32 plBSDiffBuffer::IReadUnsignedInt8(unsigned char *buf)
{
UInt32 y;
y=buf[7]&0x7F;
y=y*256;y+=buf[6];
y=y*256;y+=buf[5];
y=y*256;y+=buf[4];
y=y*256;y+=buf[3];
y=y*256;y+=buf[2];
y=y*256;y+=buf[1];
y=y*256;y+=buf[0];
// casting added so compiler doesn't warn about negating an unsigned value
Int32 signedY = (Int32)y;
if(buf[7]&0x80) signedY=-signedY;
y = (UInt32)signedY;
return y;
}
void plBSDiffBuffer::IWriteUnsignedInt8(UInt32 x,unsigned char *buf)
{
UInt32 y;
Int32 signedY, signedX = (Int32)x;
// casting added so compiler doesn't warn about negating an unsigned value
if(x<0) signedY=-signedX; else signedY=signedX;
y = (UInt32)signedY;
buf[0]=(unsigned char)(y%256);y-=buf[0];
y=y/256;buf[1]=(unsigned char)(y%256);y-=buf[1];
y=y/256;buf[2]=(unsigned char)(y%256);y-=buf[2];
y=y/256;buf[3]=(unsigned char)(y%256);y-=buf[3];
y=y/256;buf[4]=(unsigned char)(y%256);y-=buf[4];
y=y/256;buf[5]=(unsigned char)(y%256);y-=buf[5];
y=y/256;buf[6]=(unsigned char)(y%256);y-=buf[6];
y=y/256;buf[7]=(unsigned char)(y%256);
if(x<0) buf[7]|=0x80;
}
/*
* This function will ensure that no boundary errors occur. It also increments *src
* by nbytes when done.
*/
void plBSDiffBuffer::ISafeMemcpy(unsigned char *dest, unsigned char *src, size_t nbytes,
unsigned char *destend, unsigned char *srcend)
{
if((destend - dest < nbytes) ||
(srcend - src < nbytes))
{
hsAssert(false,"Corrupt patch\n");
}
memcpy(dest,src,nbytes);
}
void plBSDiffBuffer::ISplit(Int32 *I,Int32 *V,UInt32 start,UInt32 len,UInt32 h)
{
UInt32 i,j,k,x,tmp,jj,kk;
if(len<16) {
for(k=start;k<start+len;k+=j) {
j=1;x=V[I[k]+h];
for(i=1;k+i<start+len;i++) {
if(V[I[k+i]+h]<x) {
x=V[I[k+i]+h];
j=0;
};
if(V[I[k+i]+h]==x) {
tmp=I[k+j];I[k+j]=I[k+i];I[k+i]=tmp;
j++;
};
};
for(i=0;i<j;i++) V[I[k+i]]=k+j-1;
if(j==1) I[k]=-1;
};
return;
};
x=V[I[start+len/2]+h];
jj=0;kk=0;
for(i=start;i<start+len;i++) {
if(V[I[i]+h]<x) jj++;
if(V[I[i]+h]==x) kk++;
};
jj+=start;kk+=jj;
i=start;j=0;k=0;
while(i<jj) {
if(V[I[i]+h]<x) {
i++;
} else if(V[I[i]+h]==x) {
tmp=I[i];I[i]=I[jj+j];I[jj+j]=tmp;
j++;
} else {
tmp=I[i];I[i]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
while(jj+j<kk) {
if(V[I[jj+j]+h]==x) {
j++;
} else {
tmp=I[jj+j];I[jj+j]=I[kk+k];I[kk+k]=tmp;
k++;
};
};
if(jj>start) ISplit(I,V,start,jj-start,h);
for(i=0;i<kk-jj;i++) V[I[jj+i]]=kk-1;
if(jj==kk-1) I[jj]=-1;
if(start+len>kk) ISplit(I,V,kk,start+len-kk,h);
}
void plBSDiffBuffer::IQSuffixSort(Int32 *I,Int32 *V,unsigned char *old,UInt32 oldsize)
{
UInt32 buckets[256];
UInt32 i,h,len;
for(i=0;i<256;i++) buckets[i]=0;
for(i=0;i<oldsize;i++) buckets[old[i]]++;
for(i=1;i<256;i++) buckets[i]+=buckets[i-1];
for(i=255;i>0;i--) buckets[i]=buckets[i-1];
buckets[0]=0;
for(i=0;i<oldsize;i++) I[++buckets[old[i]]]=i;
I[0]=oldsize;
for(i=0;i<oldsize;i++) V[i]=buckets[old[i]];
V[oldsize]=0;
for(i=1;i<256;i++) if(buckets[i]==buckets[i-1]+1) I[buckets[i]]=-1;
I[0]=-1;
// oldsize converted to Int32 to stop warning about negating unsigned numbers
for(h=1;I[0]!=-(Int32)(oldsize+1);h+=h) {
len=0;
for(i=0;i<oldsize+1;) {
if(I[i]<0) {
len-=I[i];
i-=I[i];
} else {
// len converted to Int32 to stop the warning about negating an unsigned number
if(len) I[i-len]=-(Int32)len;
len=V[I[i]]+1-i;
ISplit(I,V,i,len,h);
i+=len;
len=0;
};
};
// len converted to Int32 to stop the warning about negating an unsigned number
if(len) I[i-len]=-(Int32)len;
};
for(i=0;i<oldsize+1;i++) I[V[i]]=i;
}
UInt32 plBSDiffBuffer::IMatchLen( unsigned char *oldBuffer, UInt32 oldLength,
unsigned char *newBuffer, UInt32 newLength)
{
UInt32 i;
for(i=0;(i<oldLength)&&(i<newLength);i++)
if(oldBuffer[i]!=newBuffer[i]) break;
return i;
}
UInt32 plBSDiffBuffer::ISearch( Int32 *I,
unsigned char *oldBuffer, UInt32 oldLength,
unsigned char *newBuffer, UInt32 newLength,
UInt32 st, UInt32 en, Int32 *pos)
{
UInt32 x,y;
if(en-st<2) {
x=IMatchLen(oldBuffer+I[st],oldLength-I[st],newBuffer,newLength);
y=IMatchLen(oldBuffer+I[en],oldLength-I[en],newBuffer,newLength);
if(x>y) {
*pos=I[st];
return x;
} else {
*pos=I[en];
return y;
}
};
x=st+(en-st)/2;
if(memcmp(oldBuffer+I[x],newBuffer,plBSDiffBuffer_MIN(oldLength-I[x],newLength))<0) {
return ISearch(I,oldBuffer,oldLength,newBuffer,newLength,x,en,pos);
} else {
return ISearch(I,oldBuffer,oldLength,newBuffer,newLength,st,x,pos);
};
}

View File

@ -0,0 +1,127 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plBSDiffBuffer - A utility class for writing and applying a difference
// buffer--i.e. a buffer containing a series of modifications
// that will modify an old data buffer to match a new one.
// It's a useful utility class when doing binary file
// patching, for example, as you can write out the changes
// to this class, get back a data buffer suitable for writing,
// then use this class again later to reconstruct the new buffer.
//
// This class is copied in structure (not substance) from
// plDiffBuffer. It is based on bsdiff-4.1 from BSD
// Linux (http://www.daemonology.org/bsdiff). It's *extremely*
// hard to read code (written by a PhD), but it works well. The
// original BSD code has been modified to have the bzip2 pipes
// it used to compress data removed. It has also been converted
// to work a C++ utility class.
//
// There isn't really an Add or Copy command in bsdiff. It just
// uses three control numbers and two diff/data buffers.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _plBSDiffBuffer_h
#define _plBSDiffBuffer_h
#include "hsTypes.h"
#include "hsStream.h"
//// Class Definition ////////////////////////////////////////////////////////
class hsRAMStream;
class plBSDiffBuffer
{
protected:
hsBool fWriting;
UInt32 fNewLength, fPatchLength;
unsigned char* fPatchBuffer;
public:
plBSDiffBuffer( UInt32 newLength, UInt32 oldLength = 0 ); // Constructor for writing new buffers. oldLength isn't required but helpful for optimizations
plBSDiffBuffer( void *buffer, UInt32 length ); // Constructor for applying a given diff set
// to an old buffer
virtual ~plBSDiffBuffer();
/// Creation/write functions
// Diff() creates the diff buffer from the new and old.
UInt32 Diff( UInt32 oldLength, void *oldBuffer, UInt32 newLength, void *newBuffer );
// GetBuffer() will copy the diff stream into a new buffer and return it. You are responsible for freeing the buffer.
void GetBuffer( UInt32 &length, void *&bufferPtr );
/// Apply functions
// Apply() is another way to call Patch().
UInt32 Apply( UInt32 oldLength, void *oldBuffer, UInt32 &newLength, void *&newBuffer )
{ return Patch(oldLength, oldBuffer, newLength, newBuffer); };
// Patch() will take this diff buffer and apply it to the given old buffer,
// allocating and producing a new buffer. You are responsible for freeing the new buffer.
UInt32 Patch( UInt32 oldLength, void *oldBuffer, UInt32 &newLength, void *&newBuffer );
private:
UInt32 IReadUnsignedInt8(unsigned char *buf);
void IWriteUnsignedInt8(UInt32 x,unsigned char *buf);
void ISafeMemcpy(unsigned char *dest, unsigned char *src, size_t nbytes,
unsigned char *destend, unsigned char *srcend);
void ISplit(Int32 *I,Int32 *V,UInt32 start,UInt32 len,UInt32 h);
void IQSuffixSort(Int32 *I,Int32 *V,unsigned char *old,UInt32 oldsize);
UInt32 IMatchLen( unsigned char *oldBuffer, UInt32 oldLength,
unsigned char *newBuffer, UInt32 newLength);
UInt32 ISearch( Int32 *I,
unsigned char *oldBuffer, UInt32 oldLength,
unsigned char *newBuffer, UInt32 newLength,
UInt32 st, UInt32 en, Int32 *pos);
};
#endif // _plBSDiffBuffer_h

View File

@ -0,0 +1,266 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plDiffBuffer - A utility class for writing and applying a difference
// buffer--i.e. a buffer containing a series of modifications
// (specifically, adds and copys) that will modify an old
// data buffer to match a new one. It's a useful utility
// class when doing binary file patching, for example, as you
// can write out the changes to this class, get back a data
// buffer suitable for writing, then use this class again
// later to reconstruct the new buffer.
//
//// History /////////////////////////////////////////////////////////////////
//
// 7.24.2002 mcn - Created (Happy late b-day to me!)
//
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plDiffBuffer.h"
#include "plBSDiffBuffer.h"
#include "hsUtils.h"
#include "hsStream.h"
//////////////////////////////////////////////////////////////////////////////
//// Constructor/Destructors /////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Creation Constructor ////////////////////////////////////////////////////
// Use this constructor when creating a new diff buffer. Pass in the length
// of the final new buffer. You don't need to pass in the length of the old
// buffer, but if you do, it'll help this class do some internal space
// optimization.
plDiffBuffer::plDiffBuffer( UInt32 newLength, UInt32 oldLength )
: fBSDiffBuffer( nil )
, fIsBSDiff( false )
{
// Basically, if the new and old lengths can both fit into 16 bits
// (not including a potential negation), then we can store all the
// segment info as 16-bit values instead of 32.
if( oldLength > 0 && oldLength < 32767 && newLength < 32767 )
f16BitMode = true;
else
f16BitMode = false;
fNewLength = newLength;
fStream = TRACKED_NEW hsRAMStream();
fStream->WriteSwap32( fNewLength );
fStream->WriteBool( f16BitMode );
fWriting = true;
}
//// Application Constructor /////////////////////////////////////////////////
// Use this constructor when taking a diff buffer and applying it to an old
// buffer. Pass in a pointer to the diff buffer and its length. The buffer
// will be copied, so you don't need to keep it around after you construct
// this object.
plDiffBuffer::plDiffBuffer( void *buffer, UInt32 length )
: fBSDiffBuffer( nil )
, fStream( nil )
, fIsBSDiff( false )
, fWriting( false )
{
// Check to see if this uses the newer BSDiff format
if ( buffer && length > 32 &&
memcmp(buffer,"BSDIFF40",8)==0 )
{
// This is a bsdiff buffer. Use plBSDiffBuffer to handle it.
fBSDiffBuffer = TRACKED_NEW plBSDiffBuffer(buffer, length);
fIsBSDiff = true;
}
else
{
fStream = TRACKED_NEW hsRAMStream();
fStream->Write( length, buffer );
fStream->Rewind();
fNewLength = fStream->ReadSwap32();
f16BitMode = fStream->ReadBool();
}
}
plDiffBuffer::~plDiffBuffer()
{
if (fStream)
delete fStream;
if (fBSDiffBuffer)
delete fBSDiffBuffer;
}
//////////////////////////////////////////////////////////////////////////////
//// Creation/Write Functions ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Add /////////////////////////////////////////////////////////////////////
// Add() appends an Add-New-Data operation to the diff buffer. The data
// supplied will be copied internally, so you can discard it after you call
// this function.
void plDiffBuffer::Add( Int32 length, void *newData )
{
hsAssert( fWriting, "Trying to Add() to a difference buffer that's reading" );
// We flag our two different op types by the sign of the length. Negative
// lengths are an add operation, positive ones are copy ops.
if( f16BitMode )
fStream->WriteSwap16( -( (Int16)length ) );
else
fStream->WriteSwap32( -length );
fStream->Write( length, newData );
}
//// Copy ////////////////////////////////////////////////////////////////////
// Copy() appends a Copy-Data-From-Old operation to the diff buffer.
void plDiffBuffer::Copy( Int32 length, UInt32 oldOffset )
{
hsAssert( fWriting, "Trying to Copy() to a difference buffer that's reading" );
// We flag our two different op types by the sign of the length. Negative
// lengths are an add operation, positive ones are copy ops.
if( f16BitMode )
{
fStream->WriteSwap16( (Int16)length );
fStream->WriteSwap16( (UInt16)oldOffset );
}
else
{
fStream->WriteSwap32( length );
fStream->WriteSwap32( oldOffset );
}
}
//// GetBuffer ///////////////////////////////////////////////////////////////
// GetBuffer() will copy the diff stream into a new buffer and return it.
// You are responsible for freeing the buffer. Call this once you're done
// adding ops and want the raw data to write out somewhere. Note: this
// function will rewind the diff stream, so once you call it, you can't do
// anything else on the object.
void plDiffBuffer::GetBuffer( UInt32 &length, void *&bufferPtr )
{
hsAssert( fWriting, "Trying to GetBuffer() on a difference buffer that's reading" );
length = fStream->GetPosition();
bufferPtr = (void *)TRACKED_NEW UInt8[ length ];
fStream->Rewind();
fStream->Read( length, bufferPtr );
}
//////////////////////////////////////////////////////////////////////////////
//// Application Functions ///////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Apply ///////////////////////////////////////////////////////////////////
// Apply() will take this diff buffer and apply it to the given old buffer,
// allocating and producing a new buffer. You are responsible for freeing
// the new buffer.
#define hsAssertAndBreak( cond, msg ) { if( cond ) { hsAssert( false, msg ); break; } }
void plDiffBuffer::Apply( UInt32 oldLength, void *oldBuffer, UInt32 &newLength, void *&newBuffer )
{
hsAssert( !fWriting, "Trying to Apply() a difference buffer that's writing" );
// Is this is a BSDiff patch, use plBSDiffBuffer and return.
if (fIsBSDiff)
{
fBSDiffBuffer->Apply(oldLength, oldBuffer, newLength, newBuffer);
return;
}
/// Step 1: Allocate the new buffer
newLength = fNewLength;
UInt8 *new8Buffer = TRACKED_NEW UInt8[ newLength ];
UInt8 *old8Buffer = (UInt8 *)oldBuffer;
newBuffer = (void *)new8Buffer;
/// Step 2: Loop through the difference stream
Int32 opLength;
UInt32 newBufferPos = 0;
while( newBufferPos < newLength )
{
// Read in the op length
if( f16BitMode )
{
Int16 opLen16 = fStream->ReadSwap16();
if( opLen16 < 0 )
opLength = -( (Int32)( -opLen16 ) );
else
opLength = (UInt32)opLen16;
}
else
opLength = fStream->ReadSwap32();
// As defined, negative ops are add ops, positive ones are copys
if( opLength < 0 )
{
hsAssertAndBreak( newBufferPos - opLength > newLength, "Destination buffer offset in plDiffBuffer() is out of range!" );
// Add op, read in the added data
fStream->Read( -opLength, &new8Buffer[ newBufferPos ] );
newBufferPos += -opLength;
}
else
{
// Copy op, so get the old offset and copy from there
UInt32 oldOffset = f16BitMode ? fStream->ReadSwap16() : fStream->ReadSwap32();
hsAssertAndBreak( newBufferPos + opLength > newLength, "Destination buffer offset in plDiffBuffer() is out of range!" );
hsAssertAndBreak( oldOffset + opLength > oldLength, "Difference buffer offset in plDiffBuffer() is out of range of the old buffer!" );
memcpy( &new8Buffer[ newBufferPos ], old8Buffer + oldOffset, opLength );
newBufferPos += opLength;
}
}
hsAssert( newBufferPos == newLength, "Invalid sequence of difference ops in plDiffBuffer::Apply()" );
}

View File

@ -0,0 +1,119 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plDiffBuffer - A utility class for writing and applying a difference
// buffer--i.e. a buffer containing a series of modifications
// (specifically, adds and copys) that will modify an old
// data buffer to match a new one. It's a useful utility
// class when doing binary file patching, for example, as you
// can write out the changes to this class, get back a data
// buffer suitable for writing, then use this class again
// later to reconstruct the new buffer.
//
// This class is meant to construct diff buffers using two
// ops: add and copy. Basically, the syntax is defined so
// that to reconstruct the new buffer, you run through the
// list of ops sequentially, each one defining the next
// chunk of data in the new buffer. Add ops will add new data
// to the buffer that didn't exist in the old buffer, and
// copy ops will copy data that existed in the old buffer
// (from an arbitrary offset, to facilitate encoding data
// shuffling). Delete ops are implicit, as they simply aren't
// defined in the stream of ops.
//
//// History /////////////////////////////////////////////////////////////////
//
// 7.24.2002 mcn - Created (Happy late b-day to me!)
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _plDiffBuffer_h
#define _plDiffBuffer_h
#include "hsTypes.h"
#include "hsStream.h"
//// Class Definition ////////////////////////////////////////////////////////
class hsRAMStream;
class plBSDiffBuffer;
class plDiffBuffer
{
protected:
hsBool fWriting, f16BitMode;
UInt32 fNewLength;
hsRAMStream *fStream;
// Support for BSDiff patch buffers (Patching only)
plBSDiffBuffer *fBSDiffBuffer;
hsBool fIsBSDiff;
public:
plDiffBuffer( UInt32 newLength, UInt32 oldLength = 0 ); // Constructor for writing new buffers. oldLength isn't required but helpful for optimizations
plDiffBuffer( void *buffer, UInt32 length ); // Constructor for applying a given diff set
// to an old buffer
virtual ~plDiffBuffer();
/// Creation/write functions
// Add() appends an Add-New-Data operation to the diff buffer. The data supplied will be copied internally.
void Add( Int32 length, void *newData );
// Copy() appends a Copy-Data-From-Old operation to the diff buffer
void Copy( Int32 length, UInt32 oldOffset );
// GetBuffer() will copy the diff stream into a new buffer and return it. You are responsible for freeing the buffer.
void GetBuffer( UInt32 &length, void *&bufferPtr );
/// Apply functions
// Apply() will take this diff buffer and apply it to the given old buffer, allocating and producing a new buffer. You are responsible for freeing the new buffer.
void Apply( UInt32 oldLength, void *oldBuffer, UInt32 &newLength, void *&newBuffer );
};
#endif // _plDiffBuffer_h

View File

@ -0,0 +1,211 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#define plIndexFile_cpp // for version numbers in plVersion.h
#include "plIndexFile.h"
#include "hsStream.h"
#include "plVersion.h"
//--------------------
// plIndexFileHeader
//--------------------
plIndexFileHeader::plIndexFileHeader()
{
fTimeStamp[ 0 ] = fTimeStamp[ 1 ] = 0;
fStrTblStartPos = 0;
fStrTblKnt = 0;
fMajorVersion = plVersion::GetMajorVersion();
fMinorVersion = plVersion::GetMinorVersion();
fExportLocal = 0;
}
void plIndexFileHeader::Write(hsStream *s)
{
s->WriteSwap32(2,fTimeStamp);
s->WriteSwap32(fStrTblStartPos);
s->WriteSwap16(fStrTblKnt);
s->WriteSwap16(fMajorVersion);
s->WriteSwap16(fMinorVersion);
s->WriteSwap16(fExportLocal);
}
void plIndexFileHeader::Read(hsStream *s)
{
s->ReadSwap32(2,fTimeStamp);
fStrTblStartPos = s->ReadSwap32();
fStrTblKnt = s->ReadSwap16();
fMajorVersion = s->ReadSwap16();
fMinorVersion = s->ReadSwap16();
fExportLocal = s->ReadSwap16();
}
//--------------------
// plIndexFileRoom
//--------------------
void plIndexFileRoom::Write(hsStream *s)
{
fRmUoid.Write(s);
s->WriteSwap32(fTypesInRoom);
s->WriteSwap16(fFiller1_16);
s->WriteSwap32(fFiller2_32);
s->WriteSwap32(fFiller3_32);
}
void plIndexFileRoom::Read(hsStream *s)
{
fRmUoid.Read(s);
fTypesInRoom = s->ReadSwap32();
s->ReadSwap16();
s->ReadSwap32();
s->ReadSwap32();
}
//--------------------
// plIndexFileType
//--------------------
void plIndexFileType::Write(hsStream *s)
{
fTypeUoid.Write(s);
s->WriteSwap32(fNumKeys);
s->WriteSwap32(fFiller1_32);
s->WriteSwap32(fFiller2_32);
}
void plIndexFileType::Read(hsStream *s)
{
fTypeUoid.Read(s);
fNumKeys = s->ReadSwap32();
s->ReadSwap32();
s->ReadSwap32();
}
//--------------------
// plIndexFileKey
//--------------------
void plIndexFileKey::Write(hsStream *s)
{
fKeyUoid.Write(s);
s->WriteSwap32(fStartPos);
s->WriteSwap32(fDataLen);
s->WriteSwap16(fNameIx);
s->WriteSwap16(fFiller1_16);
}
void plIndexFileKey::Read(hsStream *s)
{
fKeyUoid.Read(s);
fStartPos = s->ReadSwap32();
fDataLen = s->ReadSwap32();
fNameIx = s->ReadSwap16();
s->ReadSwap16();
}
//--------------------
// plIxStrTbl
//--------------------
plIxStrTbl::~plIxStrTbl()
{
if (fpStrings) delete []fpStrings; // if strings came from elsewhere, not our responsibility
}
UInt16 plIxStrTbl::AddString(const char *p)
{ Int16 ix = FindString(p);
if (ix != -1)
return ix; // duplicate
fStringTbl.push_back(p); return fStringTbl.size() - 1;
}
Int16 plIxStrTbl::FindString(const char *p)
{
for (int i=0; i < fStringTbl.size(); i++)
{
if (!_stricmp(p,fStringTbl[i]))
return i;
}
return -1;
}
void plIxStrTbl::Write(hsStream *s)
{
for (int i=0; i < fStringTbl.size(); i++)
{ Int32 len= fStringTbl[i] ? strlen(fStringTbl[i]) : 0;
hsAssert(len < 256,"Name string too long");
UInt8 l = (UInt8) len;
s->WriteByte(l); // FUTURE, don't really need length!
if (len)
{
s->Write(len, fStringTbl[i]);
}
s->WriteByte(0); // Null terminate
}
}
void plIxStrTbl::Read(hsStream *s)
{ UInt32 pos = s->GetPosition();
s->FastFwd();
fTabSize = s->GetPosition() - pos; // Get size of table
s->SetPosition(pos);
fpStrings = new char[fTabSize];
hsAssert(fpStrings,"new failed");
s->Read(fTabSize,fpStrings); // Read all the string in
char *p = fpStrings;
while (p < fpStrings + fTabSize)
{
UInt8 len = *p;
p++;
hsAssert(p < fpStrings + fTabSize,"String Index error");
fStringTbl.push_back(p);
p += len + 1; // past len and NULL
};
}

View File

@ -0,0 +1,168 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef PLINDEXFILE_H
#define PLINDEXFILE_H
#include "../pnKeyedObject/plUoid.h"
#include <vector>
//---------------------------------------------------------------
// These Classes are used to Read and Write the Index file for the Database
// Records are kept the same size Currently 20 Bytes
// At the End of the file, the Strings are stored
// plIxStrTbl is used to Read and Write the String section of the Index
//---------------------------------------------------------------
//---------------------------------------------------------------
// Main header Entry, One per Index file
//---------------------------------------------------------------
class plIndexFileHeader
{
public:
plIndexFileHeader(); // I buried Paul
~plIndexFileHeader(){}
UInt32 fTimeStamp[2];
UInt32 fStrTblStartPos; // where the String table starts in the Index file
UInt16 fStrTblKnt; // how many strings in the string table
UInt16 fMajorVersion;
UInt16 fMinorVersion;
UInt16 fExportLocal; // was this file exported locally or downloaded from server?
void Write(hsStream *s);
void Read(hsStream *s);
};
//---------------------------------------------------------------
// Room Entry One Entry per Room
//---------------------------------------------------------------
class plIndexFileRoom
{
public:
plIndexFileRoom() { memset(this,1,sizeof(this)); } // no virtuals...relax
~plIndexFileRoom(){}
plUoid fRmUoid;
UInt16 fTypesInRoom;
UInt16 fFiller1_16;
UInt32 fFiller2_32;
UInt32 fFiller3_32;
void Write(hsStream *s);
void Read(hsStream *s);
};
//---------------------------------------------------------------
// Type Entry One Entry per Type in each Room
//---------------------------------------------------------------
class plIndexFileType
{
public:
plIndexFileType() { memset(this,1,sizeof(this)); } // no virtuals...relax
~plIndexFileType(){}
plUoid fTypeUoid;
UInt16 fNumKeys;
UInt32 fFiller1_32;
UInt32 fFiller2_32;
void Write(hsStream *s);
void Read(hsStream *s);
};
//---------------------------------------------------------------
// Key Entry One Entry per Type in each Room
//---------------------------------------------------------------
class plIndexFileKey
{
public:
plIndexFileKey() { memset(this,1,sizeof(this)); } // no virtuals...relax
~plIndexFileKey(){}
plUoid fKeyUoid;
UInt32 fStartPos;
UInt32 fDataLen;
UInt16 fNameIx; // Index into string table of name
UInt16 fFiller1_16;
void Write(hsStream *s) ;
void Read(hsStream *s);
};
//---------------------------------------------------------------
// String Table, Lives at the end of the Index File
//---------------------------------------------------------------
class plIxStrTbl
{
std::vector<const char *>fStringTbl;
char *fpStrings;
UInt32 fTabSize; // buffer size for strings
public:
plIxStrTbl() :fpStrings(nil), fTabSize(0){}
~plIxStrTbl();
Int16 FindString(const char *p); // returns -1 if not found, otherwise the index from zero
UInt16 AddString(const char *p);
UInt16 NumStrings() { return fStringTbl.size(); }
const char * GetString(UInt16 x) { return fStringTbl[x]; }
void Write(hsStream *s);
void Read(hsStream *s);
};
class plLinkRecord
{
public:
plLinkRecord(UInt16 a, UInt16 d, UInt16 r) : fAgeIx(a), fDistIx(d), fRoomIx(r){}
~plLinkRecord(){}
UInt16 fAgeIx; // Index into string table
UInt16 fDistIx;
UInt16 fRoomIx;
UInt32 fTimeStamp[2];
};
#endif

View File

@ -0,0 +1,514 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plKeyFinder.h"
#include "hsTemplates.h"
#include "hsStlUtils.h"
#include "hsResMgr.h"
#include "plResManager.h"
#include "plRegistryHelpers.h"
#include "plRegistryNode.h"
#include "plRegistryKeyList.h"
#include "plPageInfo.h"
#include "../pnFactory/plFactory.h"
#include "hsUtils.h"
#include "plCreatableIndex.h"
plResManager* IGetResMgr() { return (plResManager*)hsgResMgr::ResMgr(); }
plKeyFinder& plKeyFinder::Instance()
{
static plKeyFinder theInstance;
return theInstance;
}
const char* plKeyFinder::GetLastErrorString() // For Console display
{
// For Console display
static const char* KeyFinderErrors[] =
{
"Ok",
"Age not found",
"Page not found",
"Invalid class",
"None of those classes in this page",
"Object not found"
};
return KeyFinderErrors[fLastError];
}
//
// Does name string compare with potentially mangled (ie. [1 0 0]foo) names
//
hsBool NameMatches(const char* obName, const char* pKName, hsBool subString)
{
if (!obName || !pKName)
return false;
const char *o = obName;
const char *p = pKName;
// If names are mangled, unmangle
if (*o != '[' || *p != '[')
{
// skip past ']' in both names in case mangled
while (*o && *o != ']')
o++;
o = (*o==']') ? o+1 : obName;
while (*p && *p != ']')
p++;
p = (*p==']') ? p+1 : pKName;
}
if (!subString)
{
if (!_stricmp(o, p))
return true; // FOUND IT!!!!!!!!!!!!!!!!!!!
}
else
{
char oCopy[256], pCopy[256];
strcpy(oCopy, o);
strcpy(pCopy, p);
hsStrLower(oCopy);
hsStrLower(pCopy);
if (strstr(pCopy, oCopy))
return true;
}
return false;
}
plKey plKeyFinder::StupidSearch(const char * age, const char * rm,
const char *className, const char *obName, hsBool subString)
{
UInt16 ty = plFactory::FindClassIndex(className);
return StupidSearch(age, rm, ty, obName, subString);
}
class plKeyFinderIter : public plRegistryKeyIterator, public plRegistryPageIterator
{
protected:
UInt16 fClassType;
const char *fObjName;
hsBool fSubstr;
plKey fFoundKey;
const char *fAgeName;
public:
plKey GetFoundKey( void ) const { return fFoundKey; }
plKeyFinderIter( UInt16 classType, const char *obName, hsBool substr )
: fFoundKey( nil ), fClassType( classType ), fObjName( obName ), fSubstr( substr ) { }
plKeyFinderIter( UInt16 classType, const char *obName, hsBool substr, const char *ageName )
: fFoundKey( nil ), fClassType( classType ), fObjName( obName ), fSubstr( substr ),
fAgeName( ageName ) {}
virtual hsBool EatKey( const plKey& key )
{
if( key->GetUoid().GetClassType() == fClassType &&
NameMatches( fObjName, key->GetUoid().GetObjectName(), fSubstr ) )
{
fFoundKey = key;
return false;
}
return true;
}
virtual hsBool EatPage( plRegistryPageNode *pageNode )
{
#ifndef _DEBUG
try
{
#endif
if( stricmp( pageNode->GetPageInfo().GetAge(), fAgeName ) == 0 )
{
// Try loading and searching thru this page
std::set<plKey> keyRefs;
IGetResMgr()->LoadPageKeys( pageNode );
plKeyCollector coll( keyRefs );
pageNode->IterateKeys( &coll );
if( !pageNode->IterateKeys( this ) )
return false;
}
#ifndef _DEBUG
} catch (...)
{
}
#endif
return true;
}
};
plKey plKeyFinder::StupidSearch(const char * age, const char * rm,
UInt16 classType, const char *obName, hsBool subString)
{
if (!obName)
return nil;
plUoid newOid;
fLastError = kOk;
UInt16 maxClasses = plFactory::GetNumClasses();
UInt16 ty = classType;
if (ty == maxClasses) // error
{ fLastError = kInvalidClass;
return nil;
}
if( age != nil && rm != nil )
{
const plLocation &loc = IGetResMgr()->FindLocation( age, rm );
if( !loc.IsValid() )
{
fLastError = kPageNotFound;
return nil;
}
plKeyFinderIter keyFinder( classType, obName, subString );
if( !IGetResMgr()->IterateKeys( &keyFinder, loc ) )
// Return value of false means it stopped somewhere, i.e. found something
return keyFinder.GetFoundKey();
}
else if( age != nil )
{
plKeyFinderIter keyFinder(classType, obName, subString, age);
if( !IGetResMgr()->IterateAllPages( &keyFinder ) )
return keyFinder.GetFoundKey();
}
else
{
plKeyFinderIter keyFinder( classType, obName, subString );
if( !IGetResMgr()->IterateKeys( &keyFinder ) )
// Return value of false means it stopped somewhere, i.e. found something
return keyFinder.GetFoundKey();
}
fLastError = kObjectNotFound;
return nil;
}
void plKeyFinder::ReallyStupidResponderSearch(const char *name, std::vector<plKey>& foundKeys, const plLocation &hintLocation )
{
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plResponderModifier), foundKeys, hintLocation);
}
void plKeyFinder::ReallyStupidActivatorSearch(const char *name, std::vector<plKey>& foundKeys, const plLocation &hintLocation)
{
// use the createable macro so we don't have to pull in all of Python
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plLogicModifier), foundKeys, hintLocation);
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plPythonFileMod), foundKeys, hintLocation);
ReallyStupidSubstringSearch(name, CLASS_INDEX_SCOPED(plSittingModifier), foundKeys, hintLocation);
}
void plKeyFinder::IGetNames(std::vector<std::string>& names, const char* searchName, int index)
{
// Not really searching for any particular key, just need all the logic mods
std::vector<plKey> keys;
ReallyStupidSubstringSearch(searchName, index, keys);
for (int i = 0; i < keys.size(); i++)
{
// Only allow loaded ones to cut down on the crap
plKey key = keys[i];
if (key->ObjectIsLoaded())
names.push_back(key->GetName());
}
}
void plKeyFinder::GetResponderNames(std::vector<std::string>& names)
{
IGetNames(names, "", CLASS_INDEX_SCOPED(plResponderModifier));
}
void plKeyFinder::GetActivatorNames(std::vector<std::string>& names)
{
IGetNames(names, "", CLASS_INDEX_SCOPED(plLogicModifier));
}
class plKeyFinderIterator : public plRegistryKeyIterator, public plRegistryPageIterator
{
protected:
UInt16 fClassType;
const char *fObjName;
std::vector<plKey> &fFoundKeys;
public:
plKeyFinderIterator( UInt16 classType, const char *obName, std::vector<plKey>& foundKeys )
: fClassType( classType ), fObjName( obName ), fFoundKeys( foundKeys ) { }
virtual hsBool EatKey( const plKey& key )
{
if( key->GetUoid().IsValid() && key->GetUoid().GetClassType() == fClassType &&
strstr( key->GetUoid().GetObjectName(), fObjName ) )
{
fFoundKeys.push_back( key );
}
return true;
}
virtual hsBool EatPage( plRegistryPageNode *page )
{
hsBool ret = page->IterateKeys( this );
return ret;
}
};
void plKeyFinder::ReallyStupidSubstringSearch(const char *name, UInt16 objType, std::vector<plKey>& foundKeys, const plLocation &hintLocation )
{
if (!name)
return;
plKeyFinderIterator collector( objType, name, foundKeys );
if( hintLocation.IsValid() )
{
plRegistryPageNode *hintPage = IGetResMgr()->FindPage( hintLocation );
if( hintPage != nil )
{
// Try all pages in the same age as that page
IGetResMgr()->IteratePages( &collector, hintPage->GetPageInfo().GetAge() );
}
if (foundKeys.size() > 0)
{
return;
}
}
//fpReg->IterateKeys( &collector );
IGetResMgr()->IterateAllPages( &collector );
}
//// Helper Class for FindSceneNodeKey ///////////////////////////////////////
class plPageFinder : public plRegistryPageIterator
{
protected:
plRegistryPageNode **fPagePtr;
const char *fFindString, *fAgeString;
public:
plPageFinder( plRegistryPageNode **page, const char *find ) : fPagePtr( page ), fFindString( find ), fAgeString( nil )
{ *fPagePtr = nil; }
plPageFinder( plRegistryPageNode **page, const char *ageS, const char *pageS ) : fPagePtr( page ), fFindString( pageS ), fAgeString( ageS )
{ *fPagePtr = nil; }
virtual hsBool EatPage( plRegistryPageNode *node )
{
static char str[ 512 ];
const plPageInfo &info = node->GetPageInfo();
// Are we searching by age/page?
if( fAgeString != nil )
{
if( stricmp( info.GetAge(), fAgeString ) == 0 &&
stricmp( info.GetPage(), fFindString ) == 0 )
{
*fPagePtr = node;
return false;
}
return true;
}
// Try for page only
if( stricmp( info.GetPage(), fFindString ) == 0 )
{
*fPagePtr = node;
return false;
}
// Try for full location
sprintf( str, "%s_%s_%s", info.GetAge(), info.GetPage() );
if( stricmp( str, fFindString ) == 0 )
{
*fPagePtr = node;
return false;
}
return true; // Keep searching
}
};
//// FindSceneNodeKey ////////////////////////////////////////////////////////
// Given a string for either a page name or a fully qualified location name,
// finds the page and then returns the key for the sceneNode in that page.
// Note: in our case, we want to force the page's keys to load if necessary,
// since the only time we call this function will be to actually load
// the darned thing.
plKey plKeyFinder::FindSceneNodeKey( const char *pageOrFullLocName ) const
{
plRegistryPageNode *pageNode;
plPageFinder pageFinder( &pageNode, pageOrFullLocName );
// Use our own page finder, since we want to do nifty things like partial
// matches, etc.
if( IGetResMgr()->IterateAllPages( &pageFinder ) || pageNode == nil )
return nil;
return IFindSceneNodeKey( pageNode );
}
//// FindSceneNodeKey ////////////////////////////////////////////////////////
// Age/page pair version
plKey plKeyFinder::FindSceneNodeKey( const char *ageName, const char *pageName ) const
{
plRegistryPageNode *pageNode;
plPageFinder pageFinder( &pageNode, ageName, pageName );
// Use our own page finder, since we want to do nifty things like partial
// matches, etc.
if (IGetResMgr()->IterateAllPages(&pageFinder) || pageNode == nil)
return nil;
return IFindSceneNodeKey( pageNode );
}
//// FindSceneNodeKey ////////////////////////////////////////////////////////
// plLocation version
plKey plKeyFinder::FindSceneNodeKey(const plLocation& location) const
{
plRegistryPageNode* pageNode = IGetResMgr()->FindPage(location);
if (pageNode == nil)
return nil;
return IFindSceneNodeKey(pageNode);
}
//// IFindSceneNodeKey ///////////////////////////////////////////////////////
plKey plKeyFinder::IFindSceneNodeKey(plRegistryPageNode* page) const
{
// Got the pageNode, try a find before loading
plRegistryKeyList* keyList = page->IGetKeyList(CLASS_INDEX_SCOPED(plSceneNode));
if (keyList)
{
if (keyList->fStaticKeys.size() == 1)
{
return plKey::Make((plKeyData*)keyList->fStaticKeys[0]);
}
else if (keyList->fDynamicKeys.size() == 1) // happens during export
{
plRegistryKeyList::DynSet::const_iterator it = keyList->fDynamicKeys.begin();
plKeyImp* keyImp = *it;
return plKey::Make(keyImp);
}
}
// Try loading and see if that helps
if (page->IsFullyLoaded())
return nil;
IGetResMgr()->LoadPageKeys(page);
// Get the list of all sceneNodes
plKey retVal(nil);
keyList = page->IGetKeyList(CLASS_INDEX_SCOPED(plSceneNode));
if (keyList && keyList->fStaticKeys.size() == 1)
{
retVal = plKey::Make((plKeyData*)keyList->fStaticKeys[0]);
}
// If we just loaded up all the keys for this page, then we
// may have a bunch of keys with a refcount of 0. For any of
// these keys that nothing else refs (yes, we have unused objects
// in the data), they don't get deleted because the refcount never
// rises above zero or falls back to zero. So we'll go ahead and
// ref and unref all of them. The ones in use stay put, the ones
// not being used go away. This is less than ideal.
IGetResMgr()->DumpUnusedKeys(page);
return retVal;
}
//// FindLocation ////////////////////////////////////////////////////////////
const plLocation &plKeyFinder::FindLocation( const char *age, const char *page ) const
{
if (age == nil)
{
static plLocation invalidLoc;
plRegistryPageNode *pageNode;
plPageFinder pageFinder( &pageNode, page );
if( IGetResMgr()->IterateAllPages( &pageFinder ) || pageNode == nil )
return invalidLoc;
return pageNode->GetPageInfo().GetLocation();
}
return IGetResMgr()->FindLocation( age, page );
}
//// GetLocationInfo /////////////////////////////////////////////////////////
const plPageInfo* plKeyFinder::GetLocationInfo( const plLocation &loc ) const
{
plRegistryPageNode *node = IGetResMgr()->FindPage( loc );
if (node)
return &node->GetPageInfo();
else
return nil;
}

View File

@ -0,0 +1,122 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plKeyFinder_h_inc
#define plKeyFinder_h_inc
//----------------------------
// plKeyFinder
//----------------------------
// provides a way to look up an object (via its plKey)
// Using strings. The should only be used at Program Init time or console use (cause its not fast)
// The error codes are remembered, and used for subsequent calls to GetLastErrorString(); which can
// be display to tell the user where he screwed up the input.
// If a key is not found it returns nil
//----------------------------
// EXAMPLE OF USE:
//----------------------------
//
// plKeyFinder *pFind = hsgResMgr::ResMgr()->GetKeyFinder();
// plKey pKey = pFind->StupidSearch("Global", "Globalx", "1", "plSceneNode", "1");
// if (!pKey)
// hsStatusMessage(pFind->GetLastErrorString());
// delete pFind;
//
//----------------------------
#include "hsTypes.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plUoid.h"
#include "hsStlUtils.h"
#include <string>
class plLocation;
class plRegistryPageNode;
class plPageInfo;
class plKeyFinder
{
public:
enum eErrCodes
{
kOk,
kAgeNotFound,
kPageNotFound,
kInvalidClass,
kNoClassesInPage,
kObjectNotFound
};
static plKeyFinder& Instance();
// These are Stupid search because they just do string searchs on the objects.
plKey StupidSearch(const char * age, const char * rm, const char *className, const char *obName, hsBool subString=false);
plKey StupidSearch(const char * age, const char * rm, UInt16 objType, const char *obName, hsBool subString=false);
eErrCodes GetLastErrorCode() { return fLastError; }
const char* GetLastErrorString(); // For Console display
void ReallyStupidResponderSearch(const char* name, std::vector<plKey>& foundKeys, const plLocation& hintLocation = plLocation::kInvalidLoc);
void ReallyStupidActivatorSearch(const char* name, std::vector<plKey>& foundKeys, const plLocation& hintLocation = plLocation::kInvalidLoc);
void ReallyStupidSubstringSearch(const char* name, UInt16 objType, std::vector<plKey>& foundKeys, const plLocation& hintLocation = plLocation::kInvalidLoc);
void GetActivatorNames(std::vector<std::string>& names);
void GetResponderNames(std::vector<std::string>& names);
plKey FindSceneNodeKey(const char* pageOrFullLocName) const;
plKey FindSceneNodeKey(const char* ageName, const char* pageName) const;
plKey FindSceneNodeKey(const plLocation& location) const;
const plLocation& FindLocation(const char* age, const char* page) const;
const plPageInfo* GetLocationInfo(const plLocation& loc) const;
protected:
plKeyFinder() {}
void IGetNames(std::vector<std::string>& names, const char* name, int index);
plKey IFindSceneNodeKey(plRegistryPageNode* page) const;
eErrCodes fLastError;
};
#endif // plKeyFinder_h_inc

View File

@ -0,0 +1,91 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plLoc.h"
#include "../pnKeyedObject/hsKeyedObject.h"
plLocFileParser::plLocFileParser(): fThrowBack(nil), fThrowBackLevel(0)
{ fpFile = fopen(LOCTXTFILE,"rt"); // NEED to figure out where to put this
}
int plLocFileParser::NextLine(char **pP)
{
int levelKnt=0;
*pP = 0;
// If someone previously threwback a line...use it...
if (ThrowBackAvailable())
{ *pP = fThrowBack;
int rtnLevel = fThrowBackLevel;
ClearThrowBack();
return rtnLevel;
}
// Get a New Line from the file
char str[512];
while(fgets(str,512 - 1,fpFile))
{
if (*str == '#') // indicates a missing file message, ignore
continue;
int len = strlen(str);
str[len - 1] = 0; // clobber new line
//----------------------------------------------
// If its the database file, remember the name, and skip it.
//----------------------------------------------
int i=0;
while (str[i] == '\t')
{ levelKnt++;
i++;
}
*pP = hsStrcpy(str + levelKnt); // Allocate a string copy, advance past TABS
return levelKnt;
}
return LOC_EOF;
}

View File

@ -0,0 +1,80 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef PLLOC_H
#define PLLOC_H
#include "HeadSpin.h"
#include "hsUtils.h"
// Values for UOID, such as AGE, District Room
// Are kept in configuration file(s)
// Levels are defined by the number of TABS in front of a string.
const int LOC_EOF = -1;
// plLocFileParser Is a utility class used by plRegistry to Parse the Location.txt
// configuration file.
#if HS_BUILD_FOR_WIN32
#define LOCTXTFILE "c:\\Location.txt"
#else
#define LOCTXTFILE "./Location.txt"
#endif
class plLocFileParser
{
public:
plLocFileParser();
~plLocFileParser() { if (fpFile) fclose(fpFile); fpFile = 0; }
void ThrowBack(char *p,UInt8 lev) { fThrowBack = p; fThrowBackLevel = lev; }
void ClearThrowBack() { fThrowBack = NULL; fThrowBackLevel = 0; }
bool ThrowBackAvailable() { return (fThrowBack == NULL) ? false: true; }
int NextLine(char **pP); // returns an Allocated string in pP of next valid line, and Level #, or LOC_EOF
hsBool8 Ready() { return fpFile ? true: false; }
private:
FILE * fpFile;
char * fThrowBack; // If a line is not used, it can be thrown back...unget()
int fThrowBackLevel;
};
#endif

View File

@ -0,0 +1,278 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plLocalization.h"
#include "../plFile/plFileUtils.h"
#include "hsUtils.h"
plLocalization::Language plLocalization::fLanguage = plLocalization::kEnglish;
const char* plLocalization::fLangTags[] =
{
"_eng", // kEnglish
"_fre", // kFrench
"_ger", // kGerman
"_spa", // kSpanish
"_ita", // kItalian
"_jpn" // kJapanese
};
const int kLangTagLen = 4;
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
std::string fLangCodes_en[] = {"eng", "en"};
std::string fLangCodes_fr[] = {"fre", "fra", "fr"};
std::string fLangCodes_de[] = {"ger", "deu", "de"};
std::string fLangCodes_es[] = {"spa", "es"};
std::string fLangCodes_it[] = {"ita", "it"};
std::string fLangCodes_ja[] = {"jpn", "ja"};
const std::set<std::string> plLocalization::fLangCodes[] =
{
std::set<std::string>(std::begin(fLangCodes_en), std::end(fLangCodes_en)),
std::set<std::string>(std::begin(fLangCodes_fr), std::end(fLangCodes_fr)),
std::set<std::string>(std::begin(fLangCodes_de), std::end(fLangCodes_de)),
std::set<std::string>(std::begin(fLangCodes_es), std::end(fLangCodes_it)),
std::set<std::string>(std::begin(fLangCodes_it), std::end(fLangCodes_it)),
std::set<std::string>(std::begin(fLangCodes_ja), std::end(fLangCodes_ja))
};
#endif
const char* plLocalization::fLangNames[] =
{
"English", // kEnglish
"French", // kFrench
"German", // kGerman
"Spanish", // kSpanish
"Italian", // kItalian
"Japanese" // kJapanese
};
bool plLocalization::fUsesUnicode[] =
{
false, // kEnglish
false, // kFrench
false, // kGerman
false, // kSpanish
false, // kItalian
true // kJapanese
};
plLocalization::encodingTypes plLocalization::fUnicodeEncoding[] =
{
Enc_Unencoded, // kEnglish
Enc_Unencoded, // kFrench
Enc_Unencoded, // kGerman
Enc_Unencoded, // kSpanish
Enc_Unencoded, // kItalian
Enc_UTF8, // kJapanese
};
hsBool plLocalization::IGetLocalized(const char* name, Language lang, char* localizedName)
{
const char* underscore = strrchr(name, '_');
if (underscore)
{
char langTag[kLangTagLen+1];
strncpy(langTag,underscore,kLangTagLen);
langTag[kLangTagLen] = '\0';
if (strncmp(langTag, fLangTags[kEnglish], kLangTagLen) == 0)
{
if (localizedName)
{
strcpy(localizedName, name);
int underscorePos = underscore - name;
memcpy(localizedName + underscorePos, fLangTags[lang], kLangTagLen);
}
return true;
}
}
return false;
}
hsBool plLocalization::ExportGetLocalized(const char* name, int lang, char* localizedName)
{
return IGetLocalized(name, Language(lang+1), localizedName) &&
plFileUtils::FileExists(localizedName);
}
std::string plLocalization::LocalToString(const std::vector<std::string> & localizedText)
{
std::string retVal = "";
for (int i=0; i<localizedText.size(); i++)
{
if (i > kNumLanguages-1)
break;
std::string langHeader = "$";
std::string langName = GetLanguageName((Language)i);
langHeader += langName.substr(0,2) + "$";
retVal += langHeader + localizedText[i];
}
return retVal;
}
std::vector<std::string> plLocalization::StringToLocal(const std::string & localizedText)
{
std::vector<std::string> retVal;
wchar_t *temp = hsStringToWString(localizedText.c_str());
std::wstring wLocalizedText = temp;
delete [] temp;
std::vector<std::wstring> wStringVector = StringToLocal(wLocalizedText);
int i;
for (i=0; i<wStringVector.size(); i++)
{
char *local = hsWStringToString(wStringVector[i].c_str());
std::string val = local;
delete [] local;
retVal.push_back(val);
}
return retVal;
}
std::vector<std::wstring> plLocalization::StringToLocal(const std::wstring & localizedText)
{
std::vector<std::wstring> tags;
std::vector<int> tagLocs;
std::vector<int> sortedTagLocs;
std::vector<std::wstring> retVal;
int i;
for (i=0; i<kNumLanguages; i++)
{
std::wstring tag = L"$";
std::string temp = GetLanguageName((Language)i);
wchar_t *wTemp = hsStringToWString(temp.c_str());
std::wstring langName = wTemp;
delete [] wTemp;
tag += langName.substr(0,2) + L"$";
tags.push_back(tag);
tagLocs.push_back(localizedText.find(tag));
sortedTagLocs.push_back(i);
retVal.push_back(L"");
}
for (i=0; i<kNumLanguages-1; i++)
{
for (int j=i; j<kNumLanguages; j++)
{
if (tagLocs[sortedTagLocs[i]] > tagLocs[sortedTagLocs[j]])
sortedTagLocs[i]^=sortedTagLocs[j]^=sortedTagLocs[i]^=sortedTagLocs[j]; // swap the contents (yes, it works)
}
}
// now sortedTagLocs has the indexes of tagLocs sorted from smallest loc to highest loc
hsBool noTags = true;
for (i=0; i<kNumLanguages; i++)
{
int lang = sortedTagLocs[i]; // the language we are extracting
if (tagLocs[lang] != -1)
{
noTags = false; // at least one tag was found in the text
int startLoc = tagLocs[lang] + tags[lang].length();
int endLoc;
if (i+1 == kNumLanguages)
endLoc = localizedText.length();
else
endLoc = tagLocs[sortedTagLocs[i+1]];
retVal[lang] = localizedText.substr(startLoc,endLoc-startLoc);
}
}
if (noTags)
retVal[0] = localizedText; // if no tags were in the text, we assume it to be English
return retVal;
}
#include "hsWindows.h"
void plLocalization::SetDefaultLanguage()
{
fLanguage = kEnglish;
#if 0 // disable all languages
#ifdef HS_BUILD_FOR_WIN32
HKEY hLocalKey = NULL;
HKEY hMSKey = NULL;
HKEY hWindowsKey = NULL;
HKEY hCurVerKey = NULL;
HKEY hUninstKey = NULL;
HKEY hUruKey = NULL;
#define RegOpen(key, retKey, subKeyName) RegOpenKeyEx(key, subKeyName, 0, KEY_READ, &retKey) == ERROR_SUCCESS
if (RegOpen(HKEY_LOCAL_MACHINE, hLocalKey, "software") &&
RegOpen(hLocalKey, hMSKey, "microsoft") &&
RegOpen(hMSKey, hWindowsKey, "windows") &&
RegOpen(hWindowsKey, hCurVerKey, "currentversion") &&
RegOpen(hCurVerKey, hUninstKey, "uninstall") &&
RegOpen(hUninstKey, hUruKey, "Uru - Ages Beyond Myst"))
{
char value[20];
DWORD bufsize = sizeof(value);
if (RegQueryValueEx(hUruKey, "Lang", NULL, NULL, (LPBYTE)value, &bufsize) == ERROR_SUCCESS)
{
if (hsStrEQ(value, "en"))
fLanguage = kEnglish;
else if (hsStrEQ(value, "fr"))
fLanguage = kFrench;
else if (hsStrEQ(value, "de"))
fLanguage = kGerman;
else if (hsStrEQ(value, "es"))
fLanguage = kSpanish;
else if (hsStrEQ(value, "it"))
fLanguage = kItalian;
else if (hsStrEQ(value, "jp"))
fLanguage = kJapanese;
else
fLanguage = kEnglish;
}
}
RegCloseKey(hLocalKey);
RegCloseKey(hMSKey);
RegCloseKey(hWindowsKey);
RegCloseKey(hCurVerKey);
RegCloseKey(hUninstKey);
RegCloseKey(hUruKey);
#endif // HS_BUILD_FOR_WIN32
#endif // 0
}

View File

@ -0,0 +1,140 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plLocalization_h_inc
#define plLocalization_h_inc
#include "hsStlUtils.h"
#include <set>
class plLocalization
{
public:
enum Language
{
kEnglish,
kFrench,
kGerman,
kSpanish,
kItalian,
kJapanese,
kNumLanguages,
};
typedef enum encodingTypes
{
Enc_Unencoded, // This can also mean that python did the decoding for us and we don't need to tweak it on our end
Enc_Split_String,
Enc_Hybrid_Split_String,
Enc_UTF8,
Enc_UTF16,
Enc_Unicode_Escape,
Enc_Raw_Unicode_Escape,
Enc_Latin_1,
Enc_ASCII,
Enc_MBCS
};
protected:
static Language fLanguage;
static const char* fLangTags[kNumLanguages];
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
static const std::set<std::string> fLangCodes[kNumLanguages];
#endif
static const char* fLangNames[kNumLanguages];
static bool fUsesUnicode[kNumLanguages];
static encodingTypes fUnicodeEncoding[kNumLanguages];
static hsBool IGetLocalized(const char* name, Language lang, char* localizedName);
public:
// Sets the default language, as determined by the installer
static void SetDefaultLanguage();
static void SetLanguage(Language lang) { fLanguage = lang; }
static Language GetLanguage() { return fLanguage; }
static const char* GetLanguageName(Language lang) { return fLangNames[lang]; }
#if defined(_MSC_VER) && _MSC_VER >= 1600
static std::set<std::string> GetLanguageCodes(Language lang) { return fLangCodes[lang]; }
#endif
static hsBool UsingUnicode() { return fUsesUnicode[fLanguage]; }
static encodingTypes UnicodeEncoding() { return fUnicodeEncoding[fLanguage]; }
// Returns true if we're using localized assets. If it returns false, you
// don't need to bother calling GetLocalized
static hsBool IsLocalized() { return fLanguage != kEnglish; }
// Pass in a key name and this will give you the localized name
// Returns false if the original keyname is not for a localized asset
static hsBool GetLocalized(const char* name, char* localizedName) { return IGetLocalized(name, fLanguage, localizedName); }
//
// Export only
//
// When you're exporting an asset that could be localized, you'll want to do
// a loop something like this to try and find any localized versions.
//
// for (int i = 0; i < plLocalization::GetNumLocales(); i++)
// {
// char localName[MAX_PATH];
// if (plLocalization::ExportGetLocalized(fileName, i, localName))
// {
// ...
// }
// }
//
static int GetNumLocales() { return kNumLanguages - 1; }
static hsBool ExportGetLocalized(const char* name, int lang, char* localizedName);
// Just tells us if this is localized, doesn't actually convert it for us
static hsBool IsLocalizedName(const char* name) { return IGetLocalized(name, kEnglish, nil); }
// Converts a vector of translated strings to a encoded string that can be decoded by StringToLocal()
// The index in the vector of a string is it's language
static std::string LocalToString(const std::vector<std::string> & localizedText);
// Converts a string encoded by LocalToString to a vector of translated strings
static std::vector<std::string> StringToLocal(const std::string & localizedText);
static std::vector<std::wstring> StringToLocal(const std::wstring & localizedText);
};
#endif // plLocalization_h_inc

View File

@ -0,0 +1,209 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plPageInfo.h"
#include "hsUtils.h"
#include "hsStream.h"
#include "../pnKeyedObject/plUoid.h"
#include "plVersion.h"
static UInt32 sCurrPageInfoVersion = 6;
//// Constructor/Destructor //////////////////////////////////////////////////
plPageInfo::plPageInfo()
{
IInit();
}
plPageInfo::plPageInfo( const plLocation &loc )
{
IInit();
fLocation = loc;
}
void plPageInfo::IInit()
{
fAge = fPage = nil;
fLocation.Invalidate();
SetMajorVersion(plVersion::GetMajorVersion());
fClassVersions.clear();
fChecksum = 0;
fDataStart = fIndexStart = 0;
}
plPageInfo::~plPageInfo()
{
SetStrings( nil, nil );
}
plPageInfo::plPageInfo( const plPageInfo &src )
{
IInit();
ISetFrom( src );
}
plPageInfo &plPageInfo::operator=( const plPageInfo &src )
{
ISetFrom( src );
return *this;
}
void plPageInfo::ISetFrom( const plPageInfo &src )
{
fLocation = src.fLocation;
SetStrings( src.fAge, src.fPage );
fMajorVersion = src.fMajorVersion;
fClassVersions = src.fClassVersions;
fChecksum = src.fChecksum;
fDataStart = src.fDataStart;
fIndexStart = src.fIndexStart;
}
void plPageInfo::SetStrings( const char *age, const char *page )
{
delete [] fAge;
delete [] fPage;
fAge = ( age == nil ) ? nil : hsStrcpy( age );
fPage = ( page == nil ) ? nil : hsStrcpy( page );
}
void plPageInfo::SetLocation( const plLocation &loc )
{
fLocation = loc;
}
void plPageInfo::AddClassVersion(UInt16 classIdx, UInt16 version)
{
ClassVersion cv;
cv.Class = classIdx;
cv.Version = version;
fClassVersions.push_back(cv);
}
const plLocation& plPageInfo::GetLocation() const
{
return fLocation;
}
void plPageInfo::Read( hsStream *s )
{
delete [] fAge;
delete [] fPage;
IInit();
// 5 is the earliest version since we began working again on the P20 codebase in Sep 2005,
// after Uru's online component was cancelled in Feb 2004, so I've removed support for
// anything prior to that to clean things up a bit.
UInt32 version = s->ReadSwap32();
if (version > sCurrPageInfoVersion || version < 5)
{
hsAssert( false, "Invalid header version in plPageInfo::Read()" );
return;
}
if (version >= 5)
{
fLocation.Read( s );
fAge = s->ReadSafeString();
if (version < 6)
delete s->ReadSafeString(); // fChapter was never used, and always "District".
fPage = s->ReadSafeString();
s->ReadSwap( &fMajorVersion );
if (version < 6)
{
UInt16 unusedMinorVersion;
s->ReadSwap(&unusedMinorVersion);
Int32 unusedReleaseVersion;
s->ReadSwap(&unusedReleaseVersion); // This was always zero... yanked.
UInt32 unusedFlags;
s->ReadSwap(&unusedFlags);
}
s->ReadSwap( &fChecksum );
s->ReadSwap( &fDataStart );
s->ReadSwap( &fIndexStart );
}
if (version >= 6)
{
UInt16 numClassVersions = s->ReadSwap16();
fClassVersions.reserve(numClassVersions);
for (UInt16 i = 0; i < numClassVersions; i++)
{
ClassVersion cv;
cv.Class = s->ReadSwap16();
cv.Version = s->ReadSwap16();
fClassVersions.push_back(cv);
}
}
}
void plPageInfo::Write( hsStream *s )
{
s->WriteSwap32( sCurrPageInfoVersion );
fLocation.Write( s );
s->WriteSafeString( fAge );
s->WriteSafeString( fPage );
s->WriteSwap( fMajorVersion );
s->WriteSwap( fChecksum );
s->WriteSwap( fDataStart );
s->WriteSwap( fIndexStart );
UInt16 numClassVersions = UInt16(fClassVersions.size());
s->WriteSwap16(numClassVersions);
for (UInt16 i = 0; i < numClassVersions; i++)
{
ClassVersion& cv = fClassVersions[i];
s->WriteSwap16(cv.Class);
s->WriteSwap16(cv.Version);
}
}
//// IsValid /////////////////////////////////////////////////////////////////
// Just a simple test for now.
hsBool plPageInfo::IsValid( void ) const
{
return fLocation.IsValid();
}

View File

@ -0,0 +1,112 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plPageInfo - Pack of info about an individual page
//
#ifndef _plPageInfo_h
#define _plPageInfo_h
#include "hsTypes.h"
#include "../pnKeyedObject/plUoid.h"
#include <vector>
class hsStream;
class plLocation;
class plPageInfo
{
public:
struct ClassVersion { UInt16 Class; UInt16 Version; };
typedef std::vector<ClassVersion> ClassVerVec;
protected:
plLocation fLocation;
char* fAge;
char* fPage;
UInt16 fMajorVersion;
ClassVerVec fClassVersions;
UInt32 fChecksum;
UInt32 fDataStart, fIndexStart;
void IInit( void );
void ISetFrom( const plPageInfo &src );
public:
plPageInfo();
plPageInfo( const plLocation &loc );
plPageInfo( const plPageInfo &src );
virtual ~plPageInfo();
const char* GetAge() const { return fAge; }
const char* GetPage() const { return fPage; }
plPageInfo &operator=( const plPageInfo &src );
void ClearClassVersions() { fClassVersions.clear(); }
void AddClassVersion(UInt16 classIdx, UInt16 version);
const ClassVerVec& GetClassVersions() const { return fClassVersions; }
void SetStrings( const char *age, const char *page );
void SetLocation(const plLocation& loc);
const plLocation& GetLocation() const;
UInt16 GetMajorVersion() const { return fMajorVersion; }
void SetMajorVersion(UInt16 major) { fMajorVersion = major; }
void SetChecksum( UInt32 c ) { fChecksum = c; }
UInt32 GetChecksum( void ) const { return fChecksum; }
void Read( hsStream *s );
void Write( hsStream *s );
hsBool IsValid( void ) const;
UInt32 GetDataStart( void ) const { return fDataStart; }
void SetDataStart( UInt32 s ) { fDataStart = s; }
UInt32 GetIndexStart( void ) const { return fIndexStart; }
void SetIndexStart( UInt32 s ) { fIndexStart = s; }
};
#endif // _plPageInfo_h

View File

@ -0,0 +1,49 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plRegistryHelpers.h"
#include "plRegistryNode.h"
hsBool plIndirectUnloadIterator::EatPage(plRegistryPageNode* page)
{
page->IterateKeys(this);
return true;
}

View File

@ -0,0 +1,106 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plRegistryHelpers - Little helper classes for the registry and resManager
//
//// History /////////////////////////////////////////////////////////////////
//
// 3.25.2002 mcn - Created
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _plRegistryHelpers_h
#define _plRegistryHelpers_h
#include "hsTypes.h"
#include "../pnKeyedObject/plKey.h"
#include <set>
class plKey;
class plRegistryPageNode;
//// Little Iterator Class Defs //////////////////////////////////////////////
class plRegistryKeyIterator
{
public:
virtual ~plRegistryKeyIterator() {}
virtual hsBool EatKey(const plKey& key) = 0;
};
class plRegistryPageIterator
{
public:
virtual ~plRegistryPageIterator() {}
virtual hsBool EatPage(plRegistryPageNode* keyNode) = 0;
};
//// plKeyCollector //////////////////////////////////////////////////////////
// Helper key iterator that collects keys into an std::set
class plKeyCollector : public plRegistryKeyIterator
{
protected:
std::set<plKey>& fKeys;
public:
plKeyCollector(std::set<plKey>& keys) : fKeys(keys) { }
virtual hsBool EatKey(const plKey& key)
{
fKeys.insert(key);
return true;
}
};
// If you loaded keys with another iterator, this will ensure that they're unloaded
class plIndirectUnloadIterator : public plRegistryPageIterator, public plRegistryKeyIterator
{
public:
plIndirectUnloadIterator() {}
hsBool EatKey(const plKey& key) { return true; }
hsBool EatPage(plRegistryPageNode* page);
};
#endif // _plRegistryHelpers_h

View File

@ -0,0 +1,363 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plRegistryKeyList.h"
#include "plRegistryHelpers.h"
#include "hsStream.h"
#include <algorithm>
plRegistryKeyList::plRegistryKeyList(UInt16 classType)
{
fClassType = classType;
fReffedStaticKeys = 0;
fLocked = 0;
fFlags = 0;
}
plRegistryKeyList::~plRegistryKeyList()
{
hsAssert(fLocked == 0, "Key list still locked on delete");
for (int i = 0; i < fStaticKeys.size(); i++)
{
plKeyImp* keyImp = fStaticKeys[i];
if (!keyImp->ObjectIsLoaded())
delete keyImp;
}
}
// Special dummy key that lets us set the return value of the GetName call.
// Makes it easier to do STL searches.
class plSearchKeyImp : public plKeyImp
{
public:
const char* fSearchKeyName;
const char* GetName() const { return fSearchKeyName; }
};
plKeyImp* plRegistryKeyList::FindKey(const char* keyName)
{
static plSearchKeyImp searchKey;
searchKey.fSearchKeyName = keyName;
// Search the static key list
if (fFlags & kStaticUnsorted)
{
// We're unsorted, brute force it. May do a separate search table in the
// future if this is a bottlneck
for (int i = 0; i < fStaticKeys.size(); i++)
{
plKeyImp* curKey = fStaticKeys[i];
if (curKey && hsStrCaseEQ(keyName, curKey->GetName()))
return curKey;
}
}
else
{
// We're sorted, do a fast lookup
StaticVec::const_iterator it = std::lower_bound(fStaticKeys.begin(), fStaticKeys.end(), &searchKey, KeySorter());
if (it != fStaticKeys.end() && hsStrCaseEQ(keyName, (*it)->GetName()))
return *it;
}
// Search the dynamic key list
DynSet::const_iterator dynIt = fDynamicKeys.find(&searchKey);
if (dynIt != fDynamicKeys.end())
return *dynIt;
return nil;
}
plKeyImp* plRegistryKeyList::FindKey(const plUoid& uoid)
{
UInt32 objectID = uoid.GetObjectID();
// Key is dynamic or doesn't know it's index. Do a find by name.
if (objectID == 0)
return FindKey(uoid.GetObjectName());
// Direct lookup
if (objectID <= fStaticKeys.size())
{
#ifdef PLASMA_EXTERNAL_RELEASE
return fStaticKeys[objectID-1];
#else
// If this is an internal release, our objectIDs might not match
// because of local data. Verify that we have the right key by
// name, and if it's wrong, do the slower find-by-name.
plKeyImp *keyImp = fStaticKeys[objectID-1];
if (!hsStrCaseEQ(keyImp->GetName(), uoid.GetObjectName()))
return FindKey(uoid.GetObjectName());
else
return keyImp;
#endif // PLASMA_EXTERNAL_RELEASE
}
// If we got here it probably means we just deleted all our keys of the matching type
// because no one was using them. No worries. The resManager will catch this and
// reload our keys, then try again.
return nil;
}
void plRegistryKeyList::ILock()
{
fLocked++;
}
void plRegistryKeyList::IUnlock()
{
fLocked--;
if (fLocked == 0)
IRepack();
}
bool plRegistryKeyList::IterateKeys(plRegistryKeyIterator* iterator)
{
ILock();
for (int i = 0; i < fStaticKeys.size(); i++)
{
plKeyImp* keyImp = fStaticKeys[i];
if (keyImp != nil)
{
if (!iterator->EatKey(plKey::Make(keyImp)))
{
IUnlock();
return false;
}
}
}
DynSet::const_iterator it;
for (it = fDynamicKeys.begin(); it != fDynamicKeys.end(); it++)
{
plKeyImp* keyImp = *it;
hsAssert(keyImp, "Shouldn't ever have a nil dynamic key");
if (!iterator->EatKey(plKey::Make(keyImp)))
{
IUnlock();
return false;
}
}
IUnlock();
return true;
}
void plRegistryKeyList::AddKey(plKeyImp* key, LoadStatus& loadStatusChange)
{
loadStatusChange = kNoChange;
hsAssert(fLocked == 0, "Don't currently support adding keys while locked");
if (fLocked == 0 && key != nil)
{
// If this is the first key added, we just became loaded
if (fDynamicKeys.empty())
loadStatusChange = kDynLoaded;
hsAssert(fDynamicKeys.find(key) == fDynamicKeys.end(), "Key already added");
fDynamicKeys.insert(key);
}
}
void plRegistryKeyList::SetKeyUsed(plKeyImp* key)
{
// If this is a static key, mark that we used it. Otherwise, just ignore it.
UInt32 id = key->GetUoid().GetObjectID();
if (id > 0)
fReffedStaticKeys++;
}
bool plRegistryKeyList::SetKeyUnused(plKeyImp* key, LoadStatus& loadStatusChange)
{
loadStatusChange = kNoChange;
// Clones never officially get added to the key list (they're maintained by
// the original key), so just ignore them
if (key->GetUoid().IsClone())
{
delete key;
return true;
}
// Check if it's a static key
UInt32 id = key->GetUoid().GetObjectID();
hsAssert(id <= fStaticKeys.size(), "Bad static key id");
if (id != 0 && id <= fStaticKeys.size())
{
fReffedStaticKeys--;
if (fLocked == 0)
IRepack();
// That was our last used static key, we're static unloaded
if (fReffedStaticKeys == 0)
loadStatusChange = kStaticUnloaded;
return true;
}
// Try to find it in the dynamic key list
DynSet::iterator dynIt = fDynamicKeys.find(key);
if (dynIt != fDynamicKeys.end())
{
hsAssert(fLocked == 0, "Don't currently support removing dynamic keys while locked");
if (fLocked == 0)
{
fDynamicKeys.erase(dynIt);
delete key;
// That was our last dynamic key, notify of dynamic unloaded
if (fDynamicKeys.empty())
loadStatusChange = kDynUnloaded;
return true;
}
return false;
}
hsAssert(0, "Couldn't find this key, what is it?");
return false;
}
//// IRepack /////////////////////////////////////////////////////////////////
// Frees the memory for our static key array if none of them are loaded
void plRegistryKeyList::IRepack()
{
if (fReffedStaticKeys == 0 && !fStaticKeys.empty())
{
for (int i = 0; i < fStaticKeys.size(); i++)
delete fStaticKeys[i];
fStaticKeys.clear();
}
}
void plRegistryKeyList::PrepForWrite()
{
// If we have any static keys already, we were read in. To keep from
// invalidating old key indexes any new keys have to go on the end, hence we're
// unsorted now.
if (!fStaticKeys.empty())
fFlags |= kStaticUnsorted;
// If a dynamic keys doesn't have an object assigned to it, we're not writing
// it out. Figure out how many valid keys we have.
int numDynKeys = 0;
DynSet::const_iterator cIt;
for (cIt = fDynamicKeys.begin(); cIt != fDynamicKeys.end(); cIt++)
{
plKeyImp* key = *cIt;
// We're only going to write out keys that have objects
if (key->ObjectIsLoaded())
numDynKeys++;
}
// Start our new object id's after any already created ones
UInt32 objectID = fStaticKeys.size()+1;
// Make room for our new keys
fStaticKeys.resize(fStaticKeys.size()+numDynKeys);
DynSet::iterator it = fDynamicKeys.begin();
while (it != fDynamicKeys.end())
{
plKeyImp* key = *it;
it++;
// If we're gonna use this key, tag it with it's object id and move it to the static array.
if (key->ObjectIsLoaded())
{
key->SetObjectID(objectID);
fStaticKeys[objectID-1] = key;
objectID++;
fReffedStaticKeys++;
fDynamicKeys.erase(key);
}
}
}
void plRegistryKeyList::Read(hsStream* s)
{
UInt32 keyListLen = s->ReadSwap32();
if (!fStaticKeys.empty())
{
s->Skip(keyListLen);
return;
}
fFlags = s->ReadByte();
UInt32 numKeys = s->ReadSwap32();
fStaticKeys.resize(numKeys);
for (int i = 0; i < numKeys; i++)
{
plKeyImp* newKey = TRACKED_NEW plKeyImp;
newKey->Read(s);
fStaticKeys[i] = newKey;
}
}
void plRegistryKeyList::Write(hsStream* s)
{
// Save space for the length of our data
UInt32 beginPos = s->GetPosition();
s->WriteSwap32(0);
s->WriteByte(fFlags);
int numKeys = fStaticKeys.size();
s->WriteSwap32(numKeys);
// Write out all our keys (anything in dynamic is unused, so just ignore those)
for (int i = 0; i < numKeys; i++)
{
plKeyImp* key = fStaticKeys[i];
key->Write(s);
}
// Go back to the start and write the length of our data
UInt32 endPos = s->GetPosition();
s->SetPosition(beginPos);
s->WriteSwap32(endPos-beginPos-sizeof(UInt32));
s->SetPosition(endPos);
}

View File

@ -0,0 +1,129 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plRegistryKeyList_h_inc
#define plRegistryKeyList_h_inc
#include "hsTypes.h"
#include "../pnKeyedObject/plKeyImp.h"
#include <vector>
#include <set>
class plRegistryKeyIterator;
class KeySorter
{
public:
bool operator() (plKeyImp* k1, plKeyImp* k2) const
{
hsAssert(k1 && k2, "Should have valid keys here");
return stricmp(k1->GetName(), k2->GetName()) < 0;
}
};
//
// List of keys for a single class type.
//
class plRegistryKeyList
{
protected:
friend class plKeyFinder;
UInt16 fClassType;
// Lock counter for iterating. If this is >0, don't do any ops that
// can change key positions in the array (instead, just leave holes)
UInt16 fLocked;
enum Flags { kStaticUnsorted = 0x1 };
UInt8 fFlags;
// Static keys are one's we read off disk. These don't change and are
// assumed to be already sorted when they're read in.
typedef std::vector<plKeyImp*> StaticVec;
StaticVec fStaticKeys;
UInt32 fReffedStaticKeys; // Number of static keys that are loaded
// Dynamic keys are anything created at runtime. They are put in the
// correct sorted position when they are added
typedef std::set<plKeyImp*, KeySorter> DynSet;
DynSet fDynamicKeys;
plRegistryKeyList() {}
void ILock();
void IUnlock();
void IRepack();
public:
plRegistryKeyList(UInt16 classType);
~plRegistryKeyList();
UInt16 GetClassType() const { return fClassType; }
// Find a key by name (case-insensitive)
plKeyImp* FindKey(const char* keyName);
// Find a key by uoid index.
plKeyImp* FindKey(const plUoid& uoid);
bool IterateKeys(plRegistryKeyIterator* iterator);
// Changes in our load status that can be caused by loading or unloading a key
enum LoadStatus
{
kNoChange,
kDynLoaded,
kDynUnloaded,
kStaticUnloaded,
};
void AddKey(plKeyImp* key, LoadStatus& loadStatusChange);
void SetKeyUsed(plKeyImp* key);
bool SetKeyUnused(plKeyImp* key, LoadStatus& loadStatusChange);
// Export time only. Before we write to disk, assign all the static keys
// object ID's that they can use to do fast lookups at load time.
void PrepForWrite();
void Read(hsStream* s);
void Write(hsStream* s);
};
#endif // plRegistryKeyList_h_inc

View File

@ -0,0 +1,419 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plRegistryNode.h"
#include "plRegistryKeyList.h"
#include "plRegistryHelpers.h"
#include "../pnKeyedObject/plKeyImp.h"
#include "../plStatusLog/plStatusLog.h"
#include "../pnFactory/plFactory.h"
#include "../plFile/plFileUtils.h"
#include "hsStlUtils.h"
#include "plVersion.h"
plRegistryPageNode::plRegistryPageNode(const char* path)
: fValid(kPageCorrupt)
, fPath(nil)
, fDynLoadedTypes(0)
, fStaticLoadedTypes(0)
, fOpenRequests(0)
, fIsNewPage(false)
{
fPath = hsStrcpy(path);
hsStream* stream = OpenStream();
if (stream)
{
fPageInfo.Read(&fStream);
fValid = IVerify();
CloseStream();
}
}
plRegistryPageNode::plRegistryPageNode(const plLocation& location, const char* age, const char* page, const char* dataPath)
: fValid(kPageOk)
, fPath(nil)
, fPageInfo(location)
, fDynLoadedTypes(0)
, fStaticLoadedTypes(0)
, fOpenRequests(0)
, fIsNewPage(true)
{
fPageInfo.SetStrings(age, page);
char filePath[512];
// Copy the path over
strncpy(filePath, dataPath, sizeof(filePath));
plFileUtils::AddSlash(filePath);
// Time to construct our actual file name. For now, we'll use the same old format
// of age_page.extension
strncat(filePath, fPageInfo.GetAge(), sizeof(filePath));
strncat(filePath, "_District_", sizeof(filePath));
strncat(filePath, fPageInfo.GetPage(), sizeof(filePath));
strncat(filePath, ".prp", sizeof(filePath));
fPath = hsStrcpy(filePath);
}
plRegistryPageNode::~plRegistryPageNode()
{
delete [] fPath;
UnloadKeys();
}
PageCond plRegistryPageNode::IVerify()
{
// Check the checksum values first, to make sure the files aren't corrupt
UInt32 ourChecksum = 0;
hsStream* stream = OpenStream();
if (stream)
{
ourChecksum = stream->GetEOF() - fPageInfo.GetDataStart();
CloseStream();
}
if (ourChecksum != fPageInfo.GetChecksum())
return kPageCorrupt;
// If major version out-of-date, entire location is screwed
if (fPageInfo.GetMajorVersion() > plVersion::GetMajorVersion())
return kPageTooNew;
else if (fPageInfo.GetMajorVersion() < plVersion::GetMajorVersion())
return kPageOutOfDate;
// Check the minor versions
const plPageInfo::ClassVerVec& classVersions = fPageInfo.GetClassVersions();
for (int i = 0; i < classVersions.size(); i++)
{
const plPageInfo::ClassVersion& cv = classVersions[i];
UInt16 curVersion = plVersion::GetCreatableVersion(cv.Class);
if (curVersion > cv.Version)
return kPageOutOfDate;
else if (curVersion < cv.Version)
return kPageTooNew;
}
return kPageOk;
}
hsStream* plRegistryPageNode::OpenStream()
{
if (fOpenRequests == 0)
{
if (!fStream.Open(fPath, "rb"))
return nil;
}
fOpenRequests++;
return &fStream;
}
void plRegistryPageNode::CloseStream()
{
if (fOpenRequests > 0)
fOpenRequests--;
if (fOpenRequests == 0)
fStream.Close();
}
void plRegistryPageNode::LoadKeys()
{
hsAssert(IsValid(), "Trying to load keys for invalid page");
hsAssert(!fIsNewPage, "Trying to read a new page");
if (IsFullyLoaded())
return;
hsStream* stream = OpenStream();
if (!stream)
{
hsAssert(0, xtl::format("plRegistryPageNode::LoadKeysFromSource - bad stream %s,%s",
GetPageInfo().GetAge(), GetPageInfo().GetPage()).c_str());
return;
}
// If we're loading keys in the middle of a read because FindKey() failed, we'd better
// make note of our stream position and restore it when we're done.
UInt32 oldPos = stream->GetPosition();
stream->SetPosition(GetPageInfo().GetIndexStart());
// Read in the number of key types
UInt32 numTypes = stream->ReadSwap32();
for (UInt32 i = 0; i < numTypes; i++)
{
UInt16 classType = stream->ReadSwap16();
plRegistryKeyList* keyList = IGetKeyList(classType);
if (!keyList)
{
keyList = TRACKED_NEW plRegistryKeyList(classType);
fKeyLists[classType] = keyList;
}
keyList->Read(stream);
}
stream->SetPosition(oldPos);
CloseStream();
fStaticLoadedTypes = fKeyLists.size();
}
void plRegistryPageNode::UnloadKeys()
{
KeyMap::iterator it = fKeyLists.begin();
for (; it != fKeyLists.end(); it++)
{
plRegistryKeyList* keyList = it->second;
delete keyList;
}
fKeyLists.clear();
fDynLoadedTypes = 0;
fStaticLoadedTypes = 0;
}
//// plWriteIterator /////////////////////////////////////////////////////////
// Key iterator for writing objects
class plWriteIterator : public plRegistryKeyIterator
{
protected:
hsStream* fStream;
public:
plWriteIterator(hsStream* s) : fStream(s) {}
virtual hsBool EatKey(const plKey& key)
{
plKeyImp* imp = (plKeyImp*)key;
imp->WriteObject(fStream);
return true;
}
};
void plRegistryPageNode::Write()
{
hsAssert(fOpenRequests == 0, "Trying to write while the page is open for reading");
if (!fStream.Open(fPath, "wb"))
{
hsAssert(0, "Couldn't open file for writing");
return;
}
// Some prep stuff. Assign object IDs for every key in this page, and put the
// versions of all our creatable types in the pageinfo.
fPageInfo.ClearClassVersions();
KeyMap::const_iterator it;
for (it = fKeyLists.begin(); it != fKeyLists.end(); it++)
{
plRegistryKeyList* keyList = it->second;
keyList->PrepForWrite();
int ver = plVersion::GetCreatableVersion(keyList->GetClassType());
fPageInfo.AddClassVersion(keyList->GetClassType(), ver);
}
// First thing we write is the pageinfo. Later we'll rewind and overwrite this with the final values
fPageInfo.Write(&fStream);
fPageInfo.SetDataStart(fStream.GetPosition());
// Write all our objects
plWriteIterator writer(&fStream);
IterateKeys(&writer);
fPageInfo.SetIndexStart(fStream.GetPosition());
// Write our keys
fStream.WriteSwap32(fKeyLists.size());
for (it = fKeyLists.begin(); it != fKeyLists.end(); it++)
{
plRegistryKeyList* keyList = it->second;
fStream.WriteSwap16(keyList->GetClassType());
keyList->Write(&fStream);
}
// Rewind and write the pageinfo with the correct data and index offsets
fStream.Rewind();
fPageInfo.SetChecksum(fStream.GetEOF() - fPageInfo.GetDataStart());
fPageInfo.Write(&fStream);
fStream.Close();
}
//// IterateKeys /////////////////////////////////////////////////////////////
hsBool plRegistryPageNode::IterateKeys(plRegistryKeyIterator* iterator) const
{
KeyMap::const_iterator it = fKeyLists.begin();
for (; it != fKeyLists.end(); it++)
{
plRegistryKeyList* keyList = it->second;
if (!keyList->IterateKeys(iterator))
return false;
}
return true;
}
//// IterateKeys /////////////////////////////////////////////////////////////
// Restricted version that only iterates through the keys of a given class
// type.
hsBool plRegistryPageNode::IterateKeys(plRegistryKeyIterator* iterator, UInt16 classToRestrictTo) const
{
plRegistryKeyList* keyList = IGetKeyList(classToRestrictTo);
if (keyList != nil)
return keyList->IterateKeys(iterator);
return true;
}
plKeyImp* plRegistryPageNode::FindKey(UInt16 classType, const char* name) const
{
plRegistryKeyList* keys = IGetKeyList(classType);
if (keys == nil)
return nil;
return keys->FindKey(name);
}
plKeyImp* plRegistryPageNode::FindKey(const plUoid& uoid) const
{
plRegistryKeyList* keys = IGetKeyList(uoid.GetClassType());
if (keys == nil)
return nil;
return keys->FindKey(uoid);
}
void plRegistryPageNode::AddKey(plKeyImp* key)
{
UInt16 classType = key->GetUoid().GetClassType();
plRegistryKeyList* keys = fKeyLists[classType];
if (keys == nil)
{
keys = TRACKED_NEW plRegistryKeyList(classType);
fKeyLists[classType] = keys;
}
// Error check
if (keys->FindKey(key->GetUoid().GetObjectName()) != nil)
{
//char str[512], tempStr[128];
//sprintf(str, "Attempting to add a key with a duplicate name. Not allowed."
// "\n\n(Key name: %s, Class: %s, Loc: %s)", key->GetUoid().GetObjectName(),
// plFactory::GetNameOfClass(classType), key->GetUoid().GetLocation().StringIze(tempStr));
//hsStatusMessage(str);
hsBool recovered = false;
// Attempt recovery
for (int i = 0; i < 500; i++)
{
char tempName[512];
sprintf(tempName, "%s%d", key->GetUoid().GetObjectName(), i);
if (keys->FindKey(tempName) == nil)
{
plUoid uoid(key->GetUoid().GetLocation(), key->GetUoid().GetClassType(), tempName, key->GetUoid().GetLoadMask());
key->SetUoid(uoid);
recovered = true;
break;
}
}
if (!recovered)
{
hsAssert(0, "Couldn't allocate a unique key");
return;
}
}
plRegistryKeyList::LoadStatus loadStatusChange;
keys->AddKey(key, loadStatusChange);
if (loadStatusChange == plRegistryKeyList::kDynLoaded)
fDynLoadedTypes++;
}
void plRegistryPageNode::SetKeyUsed(plKeyImp* key)
{
plRegistryKeyList* keys = IGetKeyList(key->GetUoid().GetClassType());
if (keys == nil)
return;
keys->SetKeyUsed(key);
}
hsBool plRegistryPageNode::SetKeyUnused(plKeyImp* key)
{
plRegistryKeyList* keys = IGetKeyList(key->GetUoid().GetClassType());
if (keys == nil)
return false;
plRegistryKeyList::LoadStatus loadStatusChange;
hsBool removed = keys->SetKeyUnused(key, loadStatusChange);
// If the key type just changed load status, update our load counts
if (loadStatusChange == plRegistryKeyList::kDynUnloaded)
fDynLoadedTypes--;
else if (loadStatusChange == plRegistryKeyList::kStaticUnloaded)
fStaticLoadedTypes--;
return removed;
}
plRegistryKeyList* plRegistryPageNode::IGetKeyList(UInt16 classType) const
{
KeyMap::const_iterator it = fKeyLists.find(classType);
if (it != fKeyLists.end())
return it->second;
return nil;
}
void plRegistryPageNode::DeleteSource()
{
hsAssert(fOpenRequests == 0, "Deleting a stream that's open for reading");
plFileUtils::RemoveFile(fPath);
}

View File

@ -0,0 +1,148 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plRegistryNode_h_inc
#define plRegistryNode_h_inc
#include "hsTypes.h"
#include "hsStream.h"
#include "plPageInfo.h"
#include <map>
class plRegistryKeyList;
class hsStream;
class plKeyImp;
class plRegistryKeyIterator;
enum PageCond
{
kPageOk,
kPageOutOfDate,
kPageTooNew,
kPageCorrupt,
};
//
// Represents one entire (age,page) location and contains all keys in that
// location. Note: just because the node exists does not mean that the keys are loaded.
//
class plRegistryPageNode
{
protected:
friend class plKeyFinder;
// Map from class type to a list of keys of that type
typedef std::map<UInt16, plRegistryKeyList*> KeyMap;
KeyMap fKeyLists;
int fDynLoadedTypes; // The number of key types that have dynamic keys loaded
int fStaticLoadedTypes; // The number of key types that have all their keys loaded
PageCond fValid; // Condition of the page
char* fPath; // Path to the page file
plPageInfo fPageInfo; // Info about this page
hsBufferedStream fStream; // Stream for reading/writing our page
UInt8 fOpenRequests; // How many handles there are to fStream (or
// zero if it's closed)
hsBool fIsNewPage; // True if this page is new (not read off disk)
plRegistryPageNode() {}
inline plRegistryKeyList* IGetKeyList(UInt16 classType) const;
PageCond IVerify();
public:
// For reading a page off disk
plRegistryPageNode(const char* path);
// For creating a new page.
plRegistryPageNode(const plLocation& location, const char* age, const char* page, const char* dataPath);
~plRegistryPageNode();
hsBool IsValid() const { return fValid == kPageOk; }
PageCond GetPageCondition() { return fValid; }
// True if we have any static or dynamic keys loaded
hsBool IsLoaded() const { return fDynLoadedTypes > 0 || fStaticLoadedTypes > 0; }
// True if all of our static keys are loaded
hsBool IsFullyLoaded() const { return (fStaticLoadedTypes == fKeyLists.size() && !fKeyLists.empty()) || fIsNewPage; }
// Export time only. If we want to reuse a page, load the keys we want then
// call SetNewPage, so it will be considered a new page from now on. That
// way we won't try to load it's keys again.
hsBool IsNewPage() const { return fIsNewPage; }
void SetNewPage() { fIsNewPage = true; }
const plPageInfo& GetPageInfo() const { return fPageInfo; }
void LoadKeys(); // Loads the keys off disk
void UnloadKeys(); // Frees all our keys
// Find a key by type and name
plKeyImp* FindKey(UInt16 classType, const char* name) const;
// Find a key by direct uoid lookup (or fallback to name lookup if that doesn't work)
plKeyImp* FindKey(const plUoid& uoid) const;
void AddKey(plKeyImp* key);
// Sets a key as used or unused, ie there aren't any refs to it anymore.
// When all the static keys are unused we can free the memory associated with
// them. When a dynamic key is unused we just delete it right away.
void SetKeyUsed(plKeyImp* key);
hsBool SetKeyUnused(plKeyImp* key);
hsBool IterateKeys(plRegistryKeyIterator* iterator) const;
hsBool IterateKeys(plRegistryKeyIterator* iterator, UInt16 classToRestrictTo) const;
// Call this to get a read stream for the page. If a valid pointer is
// returned, make sure to call CloseStream when you're done using it.
hsStream* OpenStream();
void CloseStream();
// Takes care of everything involved in writing this page to disk
void Write();
void DeleteSource();
const char* GetPagePath() const { return fPath; }
};
#endif // plRegistryNode_h_inc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,243 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plResManager_h_inc
#define plResManager_h_inc
#include "hsResMgr.h"
#include <set>
#include <map>
#include <vector>
class plRegistryPageNode;
class plRegistryKeyIterator;
class plRegistryPageIterator;
class plRegistryDataStream;
class plResAgeHolder;
class plResManagerHelper;
class plDispatch;
// plProgressProc is a proc called every time an object loads, to keep a progress bar for
// loading ages up-to-date.
typedef void(*plProgressProc)(plKey key);
class plResManager : public hsResMgr
{
public:
plResManager();
virtual ~plResManager();
// If the ResManager has already been initialized, you should call Reset after setting this
void SetDataPath(const char* path) { fDataPath = path; }
// Mainly for external tools.
void AddSinglePage(const char* path);
plRegistryPageNode* FindSinglePage(const char* path) const;
void RemoveSinglePage(const char* path);
//---------------------------
// Load and Unload
//---------------------------
virtual void Load (const plKey& objKey); // places on list to be loaded
virtual hsBool Unload(const plKey& objKey); // Unregisters (deletes) an object, Return true if successful
virtual plKey CloneKey(const plKey& objKey);
//---------------------------
// Finding Functions
//---------------------------
plKey FindOriginalKey(const plUoid&);
virtual plKey FindKey(const plUoid&); // Same as above, but will check the uoid for clones
const plLocation& FindLocation(const char* age, const char* page) const;
// Use nil for any strings you don't need
const void GetLocationStrings(const plLocation& loc, char* ageBuffer, char* pageBuffer) const;
//---------------------------
// Establish reference linkage
//---------------------------
virtual hsBool AddViaNotify(const plKey& key, plRefMsg* msg, plRefFlags::Type flags);
virtual hsBool AddViaNotify(plRefMsg* msg, plRefFlags::Type flags); // msg->fRef->GetKey() == sentKey
virtual hsBool SendRef(const plKey& key, plRefMsg* refMsg, plRefFlags::Type flags);
virtual hsBool SendRef(hsKeyedObject* ko, plRefMsg* refMsg, plRefFlags::Type flags);
//---------------------------
// Reding and Writing keys
//---------------------------
// Read a Key in, and Notify me when the Object is loaded
virtual plKey ReadKeyNotifyMe(hsStream* stream, plRefMsg* retMsg, plRefFlags::Type flags);
// Just read the Key data in and find a match in the registry and return it.
virtual plKey ReadKey(hsStream* stream);
// For convenience you can write a key using the KeyedObject or the Key...same result
virtual void WriteKey(hsStream* s, hsKeyedObject* obj);
virtual void WriteKey(hsStream* s, const plKey& key);
//---------------------------
// Reding and Writing Objects directly
//---------------------------
virtual plCreatable* ReadCreatable(hsStream* s);
virtual void WriteCreatable(hsStream* s, plCreatable* cre);
virtual plCreatable* ReadCreatableVersion(hsStream* s);
virtual void WriteCreatableVersion(hsStream* s, plCreatable* cre);
//---------------------------
// Registry Modification Functions
//---------------------------
virtual plKey NewKey(const char* name, hsKeyedObject* object, const plLocation& loc, const plLoadMask& m = plLoadMask::kAlways);
virtual plKey NewKey(plUoid& newUoid, hsKeyedObject* object);
virtual plDispatchBase* Dispatch();
virtual void SetProgressBarProc(plProgressProc proc);
//---------------------------
// Load optimizations
//---------------------------
void LoadAgeKeys(const char* age);
void DropAgeKeys(const char* age);
void PageInRoom(const plLocation& page, UInt16 objClassToRef, plRefMsg* refMsg);
void PageInAge(const char* age);
// Usually, a page file is kept open during load because the first keyed object
// read causes all the other objects to be read before it returns. In some
// cases though (mostly just the texture file), this doesn't work. In that
// case, we just want to force it to stay open until we're done reading the age.
void KeepPageOpen(const plLocation& page, hsBool keepOpen);
// We're on the way down, act accordingly.
virtual void BeginShutdown();
// Determines whether the time to read each object is dumped to a log
void LogReadTimes(hsBool logReadTimes);
// All keys version
hsBool IterateKeys(plRegistryKeyIterator* iterator);
// Single page version
hsBool IterateKeys(plRegistryKeyIterator* iterator, const plLocation& pageToRestrictTo);
// Iterate through loaded pages
hsBool IteratePages(plRegistryPageIterator* iterator, const char* ageToRestrictTo = nil);
// Iterate through ALL pages, loaded or not
hsBool IterateAllPages(plRegistryPageIterator* iterator);
// Helpers for key iterators
void LoadPageKeys(plRegistryPageNode* pageNode);
void UnloadPageObjects(plRegistryPageNode* pageNode, UInt16 classIndexHint);
void DumpUnusedKeys(plRegistryPageNode* page) const;
plRegistryPageNode* FindPage(const plLocation& location) const;
plRegistryPageNode* FindPage(const char* age, const char* page) const;
// Runs through all the pages and verifies that the data versions are good
hsBool VerifyPages();
protected:
friend class hsKeyedObject;
friend class plKeyImp;
friend class plResManagerHelper;
virtual plKey ReRegister(const char* nm, const plUoid& uoid);
virtual hsBool ReadObject(plKeyImp* key); // plKeys call this when needed
virtual hsBool IReadObject(plKeyImp* pKey, hsStream *stream);
plCreatable* IReadCreatable(hsStream* s) const;
plKey ICloneKey(const plUoid& objUoid, UInt32 playerID, UInt32 cloneID);
virtual void IKeyReffed(plKeyImp* key);
virtual void IKeyUnreffed(plKeyImp* key);
virtual hsBool IReset();
virtual hsBool IInit();
virtual void IShutdown();
void IPageOutSceneNodes(hsBool forceAll);
void IDropAllAgeKeys();
hsKeyedObject* IGetSharedObject(plKeyImp* pKey);
void IUnloadPageKeys(plRegistryPageNode* pageNode, hsBool dontClear = false);
hsBool IDeleteBadPages(hsTArray<plRegistryPageNode*>& invalidPages, hsBool conflictingSeqNums);
hsBool IWarnNewerPages(hsTArray<plRegistryPageNode*>& newerPages);
void ILockPages();
void IUnlockPages();
void AddPage(plRegistryPageNode* page);
// Adds a key to the registry. Assumes uoid already set
void AddKey(plKeyImp* key);
plRegistryPageNode* CreatePage(const plLocation& location, const char* age, const char* page);
hsBool fInited;
UInt16 fPageOutHint;
// True if we're reading in an object. We only read one object at a time
hsBool fReadingObject;
std::vector<plKey> fQueuedReads;
std::string fDataPath;
plDispatch* fDispatch;
UInt32 fCurCloneID; // Current clone ID. If it isn't zero, we're cloning
UInt32 fCurClonePlayerID;
UInt32 fCloningCounter; // Next clone ID to use.
typedef std::map<std::string,plResAgeHolder*> HeldAgeKeyMap;
HeldAgeKeyMap fHeldAgeKeys;
plProgressProc fProgressProc;
plResManagerHelper *fMyHelper;
hsBool fLogReadTimes;
UInt8 fPageListLock; // Number of locks on the page lists. If it's greater than zero, they can't be modified
hsBool fPagesNeedCleanup; // True if something modified the page lists while they were locked.
typedef std::set<plRegistryPageNode*> PageSet;
PageSet fAllPages; // All the pages, loaded or not
PageSet fLoadedPages; // Just the loaded pages
mutable plRegistryPageNode* fLastFoundPage;
};
#endif // plResManager_h_inc

View File

@ -0,0 +1,741 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plResManagerHelper - The wonderful helper class that can receive messages
// for the resManager.
//
//// History /////////////////////////////////////////////////////////////////
//
// 6.7.2002 mcn - Created
//
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "plResManagerHelper.h"
#include "plResManager.h"
#include "plRegistryNode.h"
#include "plRegistryHelpers.h"
//#include "plRegistry.h"
#include "plResMgrSettings.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../plMessage/plResMgrHelperMsg.h"
#include "../plStatusLog/plStatusLog.h"
#include "hsTimer.h"
#ifdef MCN_RESMGR_DEBUGGING
static const int kLogSize = 40;
static const float kUpdateDelay = 0.5f;
#include "../plInputCore/plInputInterface.h"
#include "../plInputCore/plInputDevice.h"
#include "../plInputCore/plInputInterfaceMgr.h"
#include "../pnInputCore/plInputMap.h"
#include "../plMessage/plInputEventMsg.h"
#include "../plMessage/plInputIfaceMgrMsg.h"
#include "../pnKeyedObject/plKeyImp.h"
#endif
/// Logging #define for easier use
#define kResMgrLog( level ) if( plResMgrSettings::Get().GetLoggingLevel() >= level ) plStatusLog::AddLineS( "resources.log",
//// Constructor/Destructor //////////////////////////////////////////////////
plResManagerHelper *plResManagerHelper::fInstance = nil;
plResManagerHelper::plResManagerHelper( plResManager *resMgr )
{
fResManager = resMgr;
fInstance = this;
fInShutdown = false;
#ifdef MCN_RESMGR_DEBUGGING
fDebugScreen = nil;
fCurrAge = -1;
fCurrAgeExpanded = false;
fRefreshing = false;
fDebugDisplayType = 0;
#endif
}
plResManagerHelper::~plResManagerHelper()
{
fInstance = nil;
}
//// Shutdown ////////////////////////////////////////////////////////////////
void plResManagerHelper::Shutdown( void )
{
EnableDebugScreen( false );
UnRegisterAs( kResManagerHelper_KEY );
}
//// Init ////////////////////////////////////////////////////////////////////
void plResManagerHelper::Init( void )
{
RegisterAs( kResManagerHelper_KEY );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool plResManagerHelper::MsgReceive( plMessage *msg )
{
plResMgrHelperMsg *refferMsg = plResMgrHelperMsg::ConvertNoRef( msg );
if( refferMsg != nil )
{
if( refferMsg->GetCommand() == plResMgrHelperMsg::kKeyRefList )
{
// Message to let go of these keys. So unref the key list, destroy it and we're done!
kResMgrLog( 2 ) 0xff80ff80, "Dropping page keys after timed delay" );
hsStatusMessage( "*** Dropping page keys after timed delay ***" );
delete refferMsg->fKeyList;
refferMsg->fKeyList = nil;
}
else if( refferMsg->GetCommand() == plResMgrHelperMsg::kUpdateDebugScreen )
{
IUpdateDebugScreen();
}
else if( refferMsg->GetCommand() == plResMgrHelperMsg::kEnableDebugScreen )
EnableDebugScreen( true );
else if( refferMsg->GetCommand() == plResMgrHelperMsg::kDisableDebugScreen )
EnableDebugScreen( false );
return true;
}
return hsKeyedObject::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void plResManagerHelper::Read( hsStream *s, hsResMgr *mgr )
{
hsAssert( false, "You should never read me in!" );
}
void plResManagerHelper::Write( hsStream *s, hsResMgr *mgr )
{
hsAssert( false, "You should never write me out!" );
}
//// LoadAndHoldPageKeys /////////////////////////////////////////////////////
// Loads and refs the keys for the given page, then sends the ref list as
// a list to ourself, time delayed 1 second, so that we can unref them one
// second later.
void plResManagerHelper::LoadAndHoldPageKeys( plRegistryPageNode *page )
{
hsAssert( GetKey() != nil, "Can't load and hold keys when we don't have a key for the helper" );
// Create our msg
plResMgrHelperMsg *refferMsg = TRACKED_NEW plResMgrHelperMsg( plResMgrHelperMsg::kKeyRefList );
refferMsg->fKeyList = TRACKED_NEW plResPageKeyRefList;
fResManager->LoadPageKeys(page);
page->IterateKeys( refferMsg->fKeyList );
// Load and ref the keys
#ifdef HS_DEBUGGING
char msg[ 256 ];
sprintf( msg, "*** Temporarily loading keys for room %s>%s based on FindKey() query, will drop in 1 sec ***", page->GetPageInfo().GetAge(), page->GetPageInfo().GetPage() );
hsStatusMessage( msg );
#endif
kResMgrLog( 2 ) 0xff80ff80, "Temporarily loading keys for room %s>%s, will drop in 1 sec", page->GetPageInfo().GetAge(), page->GetPageInfo().GetPage() );
// Deliver the message to ourselves!
refferMsg->SetTimeStamp( hsTimer::GetSysSeconds() + 1.f );
refferMsg->Send( GetKey() );
}
#ifdef MCN_RESMGR_DEBUGGING
//////////////////////////////////////////////////////////////////////////////
//// plResMgrDebugInterface Definition ///////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class plResMgrDebugInterface : public plInputInterface
{
protected:
plResManagerHelper * const fParent;
virtual ControlEventCode *IGetOwnedCodeList( void ) const
{
static ControlEventCode codes[] = { END_CONTROLS };
return codes;
}
public:
plResMgrDebugInterface( plResManagerHelper * const mgr ) : fParent( mgr ) { SetEnabled( true ); }
virtual UInt32 GetPriorityLevel( void ) const { return kGUISystemPriority + 10; }
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg )
{
plKeyEventMsg *pKeyMsg = plKeyEventMsg::ConvertNoRef( pMsg );
if( pKeyMsg != nil && pKeyMsg->GetKeyDown() )
{
if( pKeyMsg->GetKeyCode() == KEY_UP && fParent->fCurrAge >= 0 )
{
fParent->fCurrAge--;
fParent->IUpdateDebugScreen( true );
return true;
}
else if( pKeyMsg->GetKeyCode() == KEY_DOWN )
{
fParent->fCurrAge++;
fParent->IUpdateDebugScreen( true );
return true;
}
else if( pKeyMsg->GetKeyCode() == KEY_ENTER )
{
fParent->fCurrAgeExpanded = !fParent->fCurrAgeExpanded;
fParent->IUpdateDebugScreen( true );
return true;
}
else if( pKeyMsg->GetKeyCode() == KEY_ESCAPE )
{
plResMgrHelperMsg *msg = TRACKED_NEW plResMgrHelperMsg( plResMgrHelperMsg::kDisableDebugScreen );
msg->Send( fParent->GetKey() );
return true;
}
else if( pKeyMsg->GetKeyCode() == KEY_RIGHT )
{
if( !fParent->fCurrAgeExpanded )
fParent->fCurrAgeExpanded = true;
else
{
fParent->fDebugDisplayType++;
if( fParent->fDebugDisplayType == plResManagerHelper::kMaxDisplayType )
fParent->fDebugDisplayType = 0;
}
fParent->IUpdateDebugScreen( true );
return true;
}
else if( pKeyMsg->GetKeyCode() == KEY_LEFT )
{
fParent->fCurrAgeExpanded = false;
fParent->IUpdateDebugScreen( true );
return true;
}
}
return false;
}
virtual UInt32 GetCurrentCursorID( void ) const { return 0; }
virtual hsBool HasInterestingCursorID( void ) const { return false; }
};
#endif
//// EnableDebugScreen ///////////////////////////////////////////////////////
void plResManagerHelper::EnableDebugScreen( hsBool enable )
{
#ifdef MCN_RESMGR_DEBUGGING
if( enable )
{
if( fDebugScreen == nil )
{
fDebugScreen = plStatusLogMgr::GetInstance().CreateStatusLog( kLogSize, "ResManager Status", plStatusLog::kFilledBackground | plStatusLog::kDontWriteFile );
fRefreshing = true;
plResMgrHelperMsg *msg = TRACKED_NEW plResMgrHelperMsg( plResMgrHelperMsg::kUpdateDebugScreen );
// msg->SetTimeStamp( hsTimer::GetSysSeconds() + kUpdateDelay );
msg->Send( GetKey() );
fDebugInput = TRACKED_NEW plResMgrDebugInterface( this );
plInputIfaceMgrMsg *imsg = TRACKED_NEW plInputIfaceMgrMsg( plInputIfaceMgrMsg::kAddInterface );
imsg->SetIFace( fDebugInput );
imsg->Send();
}
}
else
{
fRefreshing = false;
if( fDebugScreen != nil )
{
delete fDebugScreen;
fDebugScreen = nil;
plInputIfaceMgrMsg *imsg = TRACKED_NEW plInputIfaceMgrMsg( plInputIfaceMgrMsg::kRemoveInterface );
imsg->SetIFace( fDebugInput );
imsg->Send();
hsRefCnt_SafeUnRef( fDebugInput );
fDebugInput = nil;
}
}
#endif
}
//// IUpdateDebugScreen /////////////////////////////////////////////////////
#ifdef MCN_RESMGR_DEBUGGING
class plDebugPrintIterator : public plRegistryPageIterator, plRegistryKeyIterator
{
public:
plStatusLog *fLog;
UInt8 fStep, fLines;
UInt32 &fLoadedCount, &fHoldingCount, fPageCount, fAgeIndex;
char fCurrAge[ 128 ];
UInt32 fLoadedKeys, fTotalKeys, fTotalSize, fLoadedSize;
plResManagerHelper *fParent;
plDebugPrintIterator( plResManagerHelper *parent, plStatusLog *log, UInt32 &loadedCount, UInt32 &holdingCount )
: fParent( parent ), fLog( log ), fStep( 0 ), fLines( 0 ), fLoadedCount( loadedCount ), fHoldingCount( holdingCount )
{
fLoadedCount = fHoldingCount = 0;
fCurrAge[ 0 ] = 0;
fPageCount = 0;
fAgeIndex = 0;
}
virtual hsBool EatPage( plRegistryPageNode *page )
{
if( fStep == 0 )
{
fLog->AddLineF( 0xff80ff80, "Loaded Pages" );
fStep = 1;
fLines++;
}
else if( fStep == 1 && page != nil && !page->IsLoaded() )
{
fStep = 2;
fLog->AddLineF( 0xff80ff80, "Holding Pages" );
fLines++;
}
if( page != nil && page->IsLoaded() )
fLoadedCount++;
else if( page != nil )
fHoldingCount++;
// Changed ages?
if( page == nil || strcmp( fCurrAge, page->GetPageInfo().GetAge() ) != 0 )
{
// Print some info for the last age we were on
if( fCurrAge[ 0 ] != 0 )
{
if( fParent->fCurrAge != fAgeIndex || !fParent->fCurrAgeExpanded )
{
if( fLines < kLogSize - 4 )
{
UInt32 color = plStatusLog::kWhite;
if( fParent->fCurrAge == fAgeIndex )
color = plStatusLog::kYellow;
fLog->AddLineF( color, " %s (%d pages)", fCurrAge, fPageCount );
fLines++;
}
else if( fLines == kLogSize - 4 )
{
fLog->AddLineF( plStatusLog::kWhite, " ..." );
fLines++;
}
}
fAgeIndex++;
}
fPageCount = 0;
if( page != nil )
strncpy( fCurrAge, page->GetPageInfo().GetAge(), sizeof( fCurrAge ) - 1 );
else
fCurrAge[ 0 ] = 0;
if( fParent->fCurrAge == fAgeIndex && fParent->fCurrAgeExpanded )
{
// Print header now, since we won't be printing a footer
if( fLines < kLogSize - 4 )
{
fLog->AddLineF( plStatusLog::kYellow, " %s>", fCurrAge );
fLines++;
}
else if( fLines == kLogSize - 4 )
{
fLog->AddLineF( plStatusLog::kWhite, " ..." );
fLines++;
}
}
}
fPageCount++;
if( fParent->fCurrAge == fAgeIndex && fParent->fCurrAgeExpanded && page != nil )
{
// Count keys for this page
fTotalKeys = fLoadedKeys = fTotalSize = fLoadedSize = 0;
page->IterateKeys( this );
// Print page for this expanded age view
if( fLines < kLogSize - 4 )
{
if( fParent->fDebugDisplayType == plResManagerHelper::kSizes )
fLog->AddLineF( plStatusLog::kWhite, " %s (%d keys @ %4.1fk, %d loaded @ %4.1fk)", page->GetPageInfo().GetPage(), fTotalKeys, fTotalSize / 1024.f, fLoadedKeys, fLoadedSize / 1024.f );
else if( fParent->fDebugDisplayType == plResManagerHelper::kPercents )
fLog->AddLineF( plStatusLog::kWhite, " %s (%d%% loaded of %d keys @ %4.1fk)", page->GetPageInfo().GetPage(), fLoadedSize * 100 / ( fTotalSize > 0 ? fTotalSize : -1 ), fTotalKeys, fTotalSize / 1024.f );
else //if( fParent->fDebugDisplayType == plResManagerHelper::kBars )
{
const int startPos = 20, length = 32;
char line[ 128 ];
memset( line, ' ', sizeof( line ) - 1 );
line[ 127 ] = 0;
if( strlen( page->GetPageInfo().GetPage() ) < startPos - 2 )
memcpy( line + 2, page->GetPageInfo().GetPage(), strlen( page->GetPageInfo().GetPage() ) );
else
memcpy( line + 2, page->GetPageInfo().GetPage(), startPos - 2 );
line[ startPos ] = '|';
if( fTotalSize == 0 )
{
line[ startPos + 1 ] = '|';
line[ startPos + 2 ] = 0;
}
else
{
char temp[ 12 ];
sprintf( temp, "%d%%", fLoadedSize * 100 / fTotalSize );
line[ startPos + length + 1 ] = '|';
int i, sum = 0;
for( i = startPos + 1; i < startPos + length + 1 && sum < fLoadedSize; i++ )
{
line[ i ] = '=';
sum += fTotalSize / length;
}
line[ startPos + length + 2 ] = 0;
memcpy( line + startPos + 1, temp, strlen( temp ) );
}
fLog->AddLine( line, plStatusLog::kWhite );
}
fLines++;
}
else if( fLines == kLogSize - 4 )
{
fLog->AddLineF( plStatusLog::kWhite, " ..." );
fLines++;
}
}
return true;
}
virtual hsBool EatKey( const plKey& key )
{
if( key->ObjectIsLoaded() )
{
fLoadedKeys++;
fLoadedSize += ((plKeyImp *)key)->GetDataLen();
}
fTotalKeys++;
fTotalSize += ((plKeyImp *)key)->GetDataLen();
return true;
}
};
#endif
void plResManagerHelper::IUpdateDebugScreen( hsBool force )
{
#ifdef MCN_RESMGR_DEBUGGING
if( !fRefreshing )
return;
plRegistry *reg = fResManager->IGetRegistry();
UInt32 loadedCnt, holdingCnt;
fDebugScreen->Clear();
plDebugPrintIterator iter( this, fDebugScreen, loadedCnt, holdingCnt );
reg->IterateAllPages( &iter );
iter.EatPage( nil ); // Force a final update
fDebugScreen->AddLineF( plStatusLog::kGreen, "%d pages loaded, %d holding", loadedCnt, holdingCnt );
if( fCurrAge >= iter.fAgeIndex )
fCurrAge = -1;
// Repump our update
if( !force )
{
plResMgrHelperMsg *msg = TRACKED_NEW plResMgrHelperMsg( plResMgrHelperMsg::kUpdateDebugScreen );
msg->SetTimeStamp( hsTimer::GetSysSeconds() + kUpdateDelay );
msg->Send( GetKey() );
}
#endif
}
#if 0
// FIXME
hsBool VerifyKeyUnloaded(const char* logFile, const plKey& key);
// Verifies that a key which shouldn't be loaded isn't, and if it is tries to figure out why.
void VerifyAgeUnloaded(const char* logFile, const char* age);
// Helper for VerifyKeyUnloaded
hsBool IVerifyKeyUnloadedRecur(const char* logFile, const plKey& baseKey, const plKey& upKey, const char* baseAge);
bool ILookForCyclesRecur(const char* logFile, const plKey& key, hsTArray<plKey>& tree, int& cycleStart);
bool plResManager::ILookForCyclesRecur(const char* logFile, const plKey& key, hsTArray<plKey>& tree, int& cycleStart)
{
int idx = tree.Find(key);
tree.Append(key);
if (tree.kMissingIndex != idx)
{
cycleStart = idx;
// Found a cycle.
return true;
}
// Now recurse up the active reference tree.
for (int i = 0; i < key->GetNumNotifyCreated(); i++)
{
if (key->GetActiveBits().IsBitSet(i))
{
for (int j = 0; j < key->GetNotifyCreated(i)->GetNumReceivers(); j++)
{
plKey reffer = key->GetNotifyCreated(i)->GetReceiver(j);
if (ILookForCyclesRecur(logFile, reffer, tree, cycleStart))
return true;
}
}
}
tree.Pop();
return false;
}
bool plResManager::IVerifyKeyUnloadedRecur(const char* logFile, const plKey& baseKey, const plKey& upKey, const char* baseAge)
{
const plPageInfo& pageInfo = FindPage(upKey->GetUoid().GetLocation())->GetPageInfo();
const char* upAge = pageInfo.GetAge();
const char* upPage = pageInfo.GetPage();
if( !upKey->GetActiveRefs() )
{
// We've hit a key active reffing us that should be inactive.
// If it's object is loaded, then it somehow missed getting unloaded.
// Else it must have missed letting go of us when it got unloaded.
if( upKey->ObjectIsLoaded() )
{
plStatusLog::AddLineS(logFile, "\tHeld by %s [%s] page %s which is loaded but nothing is reffing",
upKey->GetName(),
plFactory::GetNameOfClass(upKey->GetUoid().GetClassType()),
upPage);
return true;
}
else
{
plStatusLog::AddLineS(logFile, "\tHeld by %s [%s] page %s which isn't even loaded",
upKey->GetName(),
plFactory::GetNameOfClass(upKey->GetUoid().GetClassType()),
upPage);
return true;
}
}
// if the age of this key is different from the age on the baseKey,
// we've got a cross age active ref, which is illegal.
if( stricmp(upAge, baseAge) )
{
plStatusLog::AddLineS(logFile, "\tHeld by %s [%s] which is in a different age %s-%s",
upKey->GetName(),
plFactory::GetNameOfClass(upKey->GetUoid().GetClassType()),
upAge,
upPage);
return true;
}
int numActive = 0;
int i;
for( i = 0; i < upKey->GetNumNotifyCreated(); i++ )
{
if( upKey->GetActiveBits().IsBitSet(i) )
{
numActive++;
}
}
if( numActive < upKey->GetActiveRefs() )
{
// Someone has AddRef'd us
plStatusLog::AddLineS(logFile, "\tHeld by %s [%s] page %s which is loaded due to %d AddRef(s)",
upKey->GetName(),
plFactory::GetNameOfClass(upKey->GetUoid().GetClassType()),
upPage,
upKey->GetActiveRefs()-numActive);
return true;
}
// Now recurse up the active reference tree.
for( i = 0; i < upKey->GetNumNotifyCreated(); i++ )
{
if( upKey->GetActiveBits().IsBitSet(i) )
{
int j;
for( j = 0; j < upKey->GetNotifyCreated(i)->GetNumReceivers(); j++ )
{
plKey reffer = upKey->GetNotifyCreated(i)->GetReceiver(j);
if( IVerifyKeyUnloadedRecur(logFile, baseKey, reffer, baseAge) )
{
return true;
}
}
}
}
return false;
}
hsBool plResManager::VerifyKeyUnloaded(const char* logFile, const plKey& key)
{
if( key->ObjectIsLoaded() )
{
const plPageInfo& pageInfo = FindPage(key->GetUoid().GetLocation())->GetPageInfo();
const char* age = pageInfo.GetAge();
const char* page = pageInfo.GetPage();
plStatusLog::AddLineS(logFile, "==================================");
plStatusLog::AddLineS(logFile, "Object %s [%s] page %s is loaded", key->GetName(), plFactory::GetNameOfClass(key->GetUoid().GetClassType()), page);
hsTArray<plKey> tree;
int cycleStart;
hsBool hasCycle = ILookForCyclesRecur(logFile, key, tree, cycleStart);
if( hasCycle )
{
plStatusLog::AddLineS(logFile, "\t%s [%s] held by dependency cycle", key->GetName(), plFactory::GetNameOfClass(key->GetUoid().GetClassType()));
int i;
for( i = cycleStart; i < tree.GetCount(); i++ )
{
plStatusLog::AddLineS(logFile, "\t%s [%s]", tree[i]->GetName(), plFactory::GetNameOfClass(tree[i]->GetUoid().GetClassType()));
}
plStatusLog::AddLineS(logFile, "\tEnd Cycle");
return true;
}
else
{
return IVerifyKeyUnloadedRecur(logFile, key, key, age);
}
}
return false;
}
class plValidateKeyIterator : public plRegistryKeyIterator
{
protected:
plRegistry* fRegistry;
const char* fLogFile;
public:
plValidateKeyIterator(const char* logFile, plRegistry* reg)
{
fRegistry = reg;
fLogFile = logFile;
}
virtual hsBool EatKey(const plKey& key)
{
fRegistry->VerifyKeyUnloaded(fLogFile, key);
return true;
}
};
class plValidatePageIterator : public plRegistryPageIterator
{
protected:
const char* fAge;
plRegistryKeyIterator* fIter;
public:
plValidatePageIterator(const char* age, plRegistryKeyIterator* iter) : fAge(age), fIter(iter) {}
virtual hsBool EatPage( plRegistryPageNode *keyNode )
{
if( !stricmp(fAge, keyNode->GetPageInfo().GetAge()) )
return keyNode->IterateKeys( fIter );
return true;
}
};
void plResManager::VerifyAgeUnloaded(const char* logFile, const char* age)
{
hsBool autoLog = false;
char buff[256];
if( !logFile || !*logFile )
{
sprintf(buff, "%s.log", age);
logFile = buff;
autoLog = true;
}
if( !autoLog )
{
plStatusLog::AddLineS(logFile, "///////////////////////////////////");
plStatusLog::AddLineS(logFile, "Begin Verification of age %s", age);
}
plValidateKeyIterator keyIter(logFile, this);
plValidatePageIterator pageIter(age, &keyIter);
IterateAllPages(&pageIter);
if( !autoLog )
{
plStatusLog::AddLineS(logFile, "End Verification of age %s", age);
plStatusLog::AddLineS(logFile, "///////////////////////////////////");
}
}
#endif

View File

@ -0,0 +1,145 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plResManagerHelper - The wonderful helper class that can receive messages
// for the resManager.
//
//// History /////////////////////////////////////////////////////////////////
//
// 6.7.2002 mcn - Created
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _plResManagerHelper_h
#define _plResManagerHelper_h
#include "hsTypes.h"
#include "hsTemplates.h"
#include "plRegistryHelpers.h"
#include "../pnKeyedObject/hsKeyedObject.h"
// Defined as a project setting so we can do this right
//#define MCN_RESMGR_DEBUGGING
//// Class Definition ////////////////////////////////////////////////////////
#ifdef MCN_RESMGR_DEBUGGING
class plStatusLog;
class plDebugPrintIterator;
class plResMgrDebugInterface;
#endif
class plResManager;
class plRegistryPageNode;
class plResManagerHelper : public hsKeyedObject
{
protected:
plResManager *fResManager;
static plResManagerHelper *fInstance;
hsBool fInShutdown;
#ifdef MCN_RESMGR_DEBUGGING
friend class plDebugPrintIterator;
friend class plResMgrDebugInterface;
plStatusLog *fDebugScreen;
hsBool fRefreshing, fCurrAgeExpanded;
int fCurrAge;
int fDebugDisplayType;
enum DebugDisplayTypes
{
kSizes = 0,
kPercents,
kBars,
kMaxDisplayType
};
plResMgrDebugInterface *fDebugInput;
#endif
void IUpdateDebugScreen( hsBool force = false );
public:
plResManagerHelper( plResManager *resMgr );
virtual ~plResManagerHelper();
CLASSNAME_REGISTER( plResManagerHelper );
GETINTERFACE_ANY( plResManagerHelper, hsKeyedObject );
virtual hsBool MsgReceive( plMessage *msg );
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
void Init( void );
void Shutdown( void );
void LoadAndHoldPageKeys( plRegistryPageNode *page );
void EnableDebugScreen( hsBool enable );
// Please let the res manager handle telling this.
void SetInShutdown(hsBool b) { fInShutdown = b; }
hsBool GetInShutdown() const { return fInShutdown; }
static plResManagerHelper *GetInstance( void ) { return fInstance; }
};
//// Reffer Class ////////////////////////////////////////////////////////////
class plResPageKeyRefList : public plKeyCollector
{
protected:
std::set<plKey> fKeyList;
public:
plResPageKeyRefList() : plKeyCollector( fKeyList ) {}
};
#endif // _plResManagerHelper_h

View File

@ -0,0 +1,45 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// Future home of plResMgr

View File

@ -0,0 +1,42 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
// Future home of plResMgr

View File

@ -0,0 +1,53 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plResMgrCreatable_inc
#define plResMgrCreatable_inc
#include "../pnFactory/plCreator.h"
#include "plResManagerHelper.h"
REGISTER_NONCREATABLE(plResManagerHelper);
#endif // plResMgrCreatable_inc

View File

@ -0,0 +1,108 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
//
// plResMgrSettings - Class that holds all the various settings for
// plResManager
//
//// History /////////////////////////////////////////////////////////////////
//
// 6.22.2002 mcn - Created
//
//////////////////////////////////////////////////////////////////////////////
#ifndef _plResMgrSettings_h
#define _plResMgrSettings_h
#include "hsTypes.h"
class plResMgrSettings
{
protected:
friend class plResManager;
bool fFilterOlderPageVersions;
bool fFilterNewerPageVersions;
UInt8 fLoggingLevel;
bool fPassiveKeyRead;
bool fLoadPagesOnInit;
plResMgrSettings()
{
fFilterOlderPageVersions = true;
fFilterNewerPageVersions = true;
fPassiveKeyRead = false;
fLoadPagesOnInit = true;
fLoggingLevel = 0;
}
public:
enum LogLevels
{
kNoLogging = 0,
kBasicLogging = 1,
kDetailedLogging = 2,
kObjectLogging = 3,
kObjectDetailLogging = 4
};
bool GetFilterOlderPageVersions() const { return fFilterOlderPageVersions; }
void SetFilterOlderPageVersions(bool f) { fFilterOlderPageVersions = f; }
bool GetFilterNewerPageVersions() const { return fFilterNewerPageVersions; }
void SetFilterNewerPageVersions(bool f) { fFilterNewerPageVersions = f; }
UInt8 GetLoggingLevel() const { return fLoggingLevel; }
void SetLoggingLevel(UInt8 level) { fLoggingLevel = level; }
bool GetPassiveKeyRead() const { return fPassiveKeyRead; }
void SetPassiveKeyRead(bool p) { fPassiveKeyRead = p; }
bool GetLoadPagesOnInit() const { return fLoadPagesOnInit; }
void SetLoadPagesOnInit(bool load) { fLoadPagesOnInit = load; }
static plResMgrSettings& Get();
};
#endif // _plResMgrSettings_h

View File

@ -0,0 +1,107 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plVersion.h"
#include "../pnFactory/plFactory.h"
#include <vector>
#include "plCreatableIndex.h"
#define ChangedCreatable(ver, creatable) if (minorVersion == ver) creatables.push_back(CLASS_INDEX_SCOPED(creatable));
//
// Every time you bump the minor version number, add entries here for each
// creatable that was changed. Every time the minor version is reset (for a
// major version change), delete all the entries.
//
static void GetChangedCreatables(int minorVersion, std::vector<UInt16>& creatables)
{
ChangedCreatable(1, plLoadAvatarMsg);
ChangedCreatable(1, plArmatureMod);
ChangedCreatable(2, plAvBrainHuman);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static int CreatableVersions[plCreatableIndex::plNumClassIndices];
static void CalcCreatableVersions()
{
memset(CreatableVersions, 0, sizeof(CreatableVersions));
for (int minorVer = 1; minorVer <= PLASMA2_MINOR_VERSION; minorVer++)
{
std::vector<UInt16> changedTypes;
changedTypes.reserve(10);
GetChangedCreatables(minorVer, changedTypes);
for (int i = 0; i < changedTypes.size(); i++)
{
UInt16 changedType = changedTypes[i];
CreatableVersions[changedType] = minorVer;
// Bump any classes that derive from this one
for (UInt16 toCheck = 0; toCheck < plFactory::GetNumClasses(); toCheck++)
{
if (plFactory::DerivesFrom(changedType, toCheck))
CreatableVersions[toCheck] = minorVer;
}
}
}
}
UInt16 plVersion::GetMajorVersion() { return PLASMA2_MAJOR_VERSION; }
UInt16 plVersion::GetMinorVersion() { return PLASMA2_MINOR_VERSION; }
int plVersion::GetCreatableVersion(UInt16 creatableIndex)
{
static bool calced = false;
if (!calced)
{
calced = true;
CalcCreatableVersions();
}
return CreatableVersions[creatableIndex];
}

View File

@ -0,0 +1,293 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plVersion_h_inc
#define plVersion_h_inc
#include "hsTypes.h"
// RULES:
// Log your change
// Set Minor Version to ZERO when you Bump Major Version
// If you change the minor, see GetChangedCreateables in plVersion.cpp
#define PLASMA2_MAJOR_VERSION 70 // Major Version...every file will need to be reexported
#define PLASMA2_MINOR_VERSION 2 // Minor Version...only files with the specified creatables
// will need to be reexported
// Don't modify this, it's automatically updated when branches are made
#define PLASMA2_BRANCH_NAME "Main Branch"
class plVersion
{
public:
static UInt16 GetMajorVersion();
static UInt16 GetMinorVersion();
// Pass in a creatable index to get its current version. Zero means it
// hasn't changed since the last major version change, anything else is the
// last minor version it changed at. This takes into account the version of
// parent classes.
static int GetCreatableVersion(UInt16 creatableIndex);
};
/* Major Log ---Death to those who do not log changes---
# Date Who comment
1 5/8/01 Paulg Added version Number
2 5/11/01 mf Changed sortable mesh format by 2 bytes.
3 5/14/01 Paulg Index files Location is used for ReadConfig at Client Startup, RoomLoc added to Index
4 5/21/01 matt Fixed errant bounding types for physicals (old bad codes will choke)
5 5/24/01 mf Added Occluders to the data format.
6 5/29/01 mf Purvis changed the sound data format and didn't change the version.
7 5/3/01 thamer Cleaned up some object read/write routines
8 6/12/01 mcn Obliterated hsGTexture on down. Now we use plBitmaps and plMipmaps (class IDs changed)
9 6/21/01 mcn Updated drawable disk format. Forgot a field that made particle systems break when it wasn't there
10 6/25/01 mcn Updated plMipmap format. Helps resolve the huge memory issues we were having
11 6/28/01 mf Slight changes to material and geometry formats to support projective texturing.
12 7/02/01 mcn Changed file format to fix disappearing objects in SceneViewer
13 7/09/01 bob Changed file format of plSimpleParticleGenerator to allow mesh generated systems.
14 7/13/01 thamer Changed uoid read/write to include clone number
15 7/20/01 thamer Changed uoid sequence to support up to 4 player rooms
16 7/20/01 mcn Added a second drawable + key to drawInterfaces
17 7/22/01 bob Changed file format to have particle systems support material diffuse/opacity animations
18 7/27/01 mcn Added stuff to drawableSpans for SceneViewer. Are we ever going to have another non-zero minor version? :)
19 7/31/01 mf Did a get and the format had changed but the version hadn't been updated (again). Is this version thing dead?
20 8/13/01 mcn Not that I know of. Change to various object formats to support object instancing.
21 8/20/01 mf Like you'd know. Revised inter-object dependency connections throughout the five scene graphs.
22 8/21/01 mf CoordinateInterfaces keep refs to child SceneObjects instead of child CoordinateInterfaces.
22 8/21/01 mcn You hurt my feelings. I bump major version in retaliation. (Also upped max UV count)
23 8/24/01 mf Made runtime lights respect Max's OTM.
24 8/26/01 mcn Changed plSound format to support stereo (background music) sounds
25 9/05/01 thamer Changed uoid to support 32bit clones
26 9/14/01 mcn Added all 12 parameters to the Audio Region component.
27 9/25/01 mf Added soft volumes to run-time lights. Breaks any scene with RT lights.
28 10/03/01 matt Changed physics format just enough to make everyone reexport everything.
29 10/9/01 ee Changed Uoid member types to a new format that can accomodate strings.
30 10/10/01 mcn Split diffuse layer colors to static and runtime diffuse colors. Breaks the entire universe and parts of New Jersey.
31 10/11/01 ee Activated string usage in uoids -- this version thing is sure not dead now.
32 10/11/01 mf Changed format of plSpan. Only breaks scenes with visible geometry. Should that be Minor Version?
33 10/12/01 cp changed read/write functions in plAnimTimeConvert. Breaks all previously exported animations
34 10/22/01 Colin Changed format of plBitmap
35 10/30/01 mf Change to span format, breaks anything with visible geometry.
36 11/5/01 mcn Changed structure of sound classes to be far more intuitive and bug-free.
37 11/9/01 ee Just for fun.
38 11/13/01 bob Changed file format for plAnimTimeConvert / plAnimCmdMsg / plAGAnim (sense a theme?)
39 11/25/01 mf More sorting info for drawable geometry.
40 11/29/01 mcn Fixed sound fade param read/write. Anything with sounds must be re-exported.
41 12/04/01 bob More animation file format changes.
42 12/05/01 mcn Changes to sound format. Now properties are in a general props field. Also added disable-LOD prop to sounds
43 12/18/01 cjp changes to physics system
44 12/18/01 bob anim file format.
45 12/19/01 Colin anim file format, again.
46 12/28/01 mf DrawInterface format change to purge the last of the Opaque/Blending dualism.
47 1/2/01 mf Decoupled the hardware and software skinning vertex formats.
48 1/6/01 mf Added grey area to Soft Regions (formerly Soft Volumes).
49 1/17/02 cp new camera system checked into client and plugins
50 1/21/02 Colin Physics changes
51 1/24/02 Colin Animation format change
52 2/14/02 bob plAnimTimeConvert format change
53 2/14/02 matt made all brains non-keyed. reordering all over the place
54 3/15/02 cjp new LOS query types, format change to plHKPhysical
55 4/09/02 cjp more new LOS query types, format change to plHKPhysical, camera type changes
56 4/23/02 bob nuked plSimpleModifier from plAGMasterMod. Changes file format for animation.
57 5/17/02 Colin Changed Uoid format for cloning
58 7/02/02 thamer Changed synchedOject R/W format to support more LocalOnly options
59 8/14/02 bob Anim file format
60 2/08/03 mf Changed formats for everything drawable and/or physical. That leaves behaviors, but it's about time for a major version change anyway.
61 2/18/03 mf Between my changes and Bob's, we're just not sure what hasn't changed anymore. At least drawables and avatars.
62 3/30/03 mf Added LoadMask to plUoid
63 5/30/03 thamer optimized Uoid size
64 10/28/05 jeff changed plLocation to handle more pages and plUoid for optimization reasons
65 2/22/06 bob animation key rewrite to save space
66 2/27/06 bob 64-bit quaternion anim keys
67 2/28/06 bob Anims store UInt16 frame numbers, not 32-bit float times.
68 3/03/06 bob constant anim channels (plMatrixConstant, plScalarConstant had no R/W methods)
69 5/08/06 bob changed plVertCoder and hsMatrix44::Read/Write
70 2/12/07 bob Merged in several registry/resMangaer fixes
*/
/* Minor Log ---Death to those who do not log changes---
# Date Who comment
1 5/8/01 Paulg Added version Number
2 5/9/01 mcn Changed color components of drawableSpans
0 5/11/01 mf Dropped back to zero on Major Version change
1 8/06/01 thamer Upped the version for mf's anim callback changes.
2 8/06/01 bob Changes to particle system read/write.
0 8/13/01 mcn Bumped back to 0 due to major version change.
1 8/23/01 bob Added animation controller to particle systems, changing their format.
0 8/24/01 mcn Bumped back to 0 yet again.
1 8/27/01 mcn Changed how emissive flags are handled on materials.
2 8/29/01 bob Changed plAvatarMod file format
0 9/05/01 thamer Bumped back to 0 yet again.
1 9/17/01 matt Avatar only.
2 9/24/01 bob Avatar and sound file formats changed. (For age linking effects)
0 9/25/01 mf Reset to zero for major change.
1 10/7/01 Colin Format of plResponderModifier and plEventCallbackMsg changed.
0 10/9/01 ee Reset to zero for major change.
1 10/11/01 mcn Changed sound format. Anything with sounds (including avatar b/c of linking sounds) breaks. Is this a record for # of version changes in one week?
1 10/15/01 mcn Added soft volumes to sounds. Breaks anything with sounds. Again.
2 10/17/01 Colin Changed format of plAGAnim
0 10/22/01 Colin Reset to zero for major change.
1 11/01/01 bob Changed format for plAGAnim and plAGMasterMod. Will break avatars without re-export.
0 11/02/01 mf Reset to zero for major change.
1 11/28/01 mcn Changed meaning of sound volume property. Will work if not re-exported, but will sound wrong.
0 11/29/01 mcn Reset on major version change.
1 12/10/01 bob Changes to animTimeConvert. Animated materials will need a re-export.
0 12/18/01 bob Reset to zero for major change.
1 1/07/02 bob File format change for particle systems.
0 1/21/02 Colin Reset to zero for major change.
1 1/24/02 Colin File format for responders
2 1/24/02 mcn Changed postEffectMod format. Not many people use it though, so only minor version change.
0 1/24/02 Colin Reset to zero for major change.
1 1/28/02 bob File format change to avatars for clothing customization.
2 1/30/02 Colin File format change to sit component
3 1/31/02 Colin File format change to logic modifier (all detector components)
4 2/13/02 Colin File format change to ladder modifier
0 2/14/02 bob Reset to zero for major change.
1(5) 2/14/02 mcn GUI control format changes to support dynamic text layers (the RIGHT way)
2(6) 2/19/02 mcn Added version field to dialogs, to allow synching with C++ and Python code (just in case)
7 3/01/02 mcn Moved GUI controls to pfGUIColorScheme methods of handling colors/fonts
8 3/01/02 cjp changed format of new camera brains, only affects the few using them right now
10 3/08/02 mcn Changed internal format of sounds to facilitate packing them in files later
11 3/08/02 mcn Added a shadow option to GUI color schemes. Also added mouse-over animations to buttons.
12 3/12/02 bob Change format of clothing
13 3/15/02 matt Changed base class for sit modifier
0 3/15/02 cjp Only chris forgot to log it - mf
1 3/29/02 mf Added light group support for particle systems.
2 4/02/02 Colin Format change for responder modifiers
0 4/15/02 cjp Only chris forgot to log it - mf
1 4/15/02 mf Added a parm to partycle systems just for fun.
2 4/17/02 cjp Added new modifier for interface information, changed plMaxNode.cpp.
0 4/23/02 bob Reset to zero.
1 4/25/02 mcn GUI objects no longer fog. Must reexport GUI components.
2 5/05/02 mf Particle system enhancements
3 5/06/02 matt Changes to one shot modifier and multistage modifier
4 5/06/02 bob Changes to plArmatureMod and Clothing stuff. For swappable meshes and footsteps.
5 5/07/02 bob Changed clothing item file format (again) for text descriptions and thumbnails
6 5/09/02 mcn Added sound event capabilities to GUI controls
7 5/13/02 mcn Added some new options to GUI knobs
8 5/14/02 matt Fix net propagation for animation stages (fading) and generic brains (exit flags)
0 5/17/02 Colin Reset for major version
1 5/21/02 mcn Added a channel select option for plWin32Sounds
2 5/23/02 bob Added multiple texture layers per element in plClothingItem
3 5/23/02 mcn Added some options to plSoundBuffer.
4 6/18/02 mcn Added some more options to plSound, incl. localOnly flags
6 6/21/02 mcn Updated plDynamicTextMap to include an initial image buffer
7 6/26/02 mcn Major revision to sound system to support hardware acceleration
0 7/02/02 thamer Reset for major version
1 7/08/02 matt Format change for animation stages -- added next/prevStage override
2 7/10/02 bob Format changes for avatar footstep sounds
3 7/12/02 mcn Format change to sounds for EAX effects
4 7/23/02 bob Format change to footstep sounds for more surface options
5 7/29/02 mcn More EAX format changes to sounds
6 7/29/02 mcn Added cutoff attenuation to spot/omni lights
7 8/01/02 bob Format change to clothing items
0 8/14/02 bob Reset for major version
1 8/19/02 bob plClothingItem file format
2 9/02/02 bob plArmatureLODMod file format change for bone LOD
3 9/12/02 mf Making ripples and waves play nice with each other.
4 9/18/02 bob plClothingItem file format... again
5 9/19/02 mcn New GUI control proxy stuff
6 9/23/02 mcn Removed dead sound stuff
7 9/24/02 mcn Sound priority stuff
8 9/25/02 mcn Support for new grouped random sound objects
9 10/15/02 mcn Material anim support in GUI controls
10 10/21/02 mcn Variable volume support to group sounds. No format break.
11 10/29/02 cjp proper python notification of avatar page out & last avatar out plus elevator persistance fix - breaks message format for exclude regions
12 10/29/02 mcn Fixing chris's booboo
13 10/29/02 cjp Changed camera component data format slightly.
16 11/18.02 cjp changed camera speed components & objects, don't know where v 14 & 15 went
17 12/04/20 matt New line-of-sight categories; format change for physicals.
18 12/05/02 mf Enhanced linefollowmod to play nice with stereizer, and added field to occluder's cullpoly.
19 12/17/02 matt Bumped armaturemod, based on strong circumstantial evidenced that I missed something.
20 12/31/02 matt New format for animation stages, written by the multistage mod.
21 01/03/03 matt Change to sitmodifier.
22 01/16/03 matt More simplification for animation stages and generic brains.
23 01/20/03 bob Added layer to clothing items for aged skin blending
24 01/21/03 mf plLayers now read and write out their shaders.
25 01/29/03 bob plMorphSequence read/writes the plSharedMeshes it uses
27 02/05/03 mcn Updates to pfGUIButtonMod
0 02/18/03 mf Reset for major version change.
1 02/19/03 bob Added layers to plClothingItem. Took the opp to cleanup the R/W functions
2 02/21/03 mf Added features to dynamic water. No one should notice.
3 02/24/03 cjp changed animated cameras - added new commands for controlling them
4 02/24/03 mcn Updates to GUI stuff to support, er, new GUI stuff.
5 03/11/03 bob Clothing and linkSound format change
0 03/30/03 mf Reset for major version change.
9 04/14/03 Colin Havok change. At 9 since mf forgot to bump the version (and Matt did a bunch of undocumented bumps)
10 04/15/03 bob Added a footstep surface type
11 4/18/03 mcn Added list of the layers grabbed by a GUI DynDisplay
12 4/23/03 bob File format for plMultistageBehMod, needed for a ladder fix
13 05/01/03 Colin Changed how Havok vectors and quats are written
14 03/30/03 mf Particle effect enhancement
0 05/30/03 thamer Reset for major version change.
1 06/01/03 bob Added a flags variable to plSharedMesh
2 06/06/03 markd Added NotifyType for GUIButtons
3 06/07/03 mcn Added sound groups to physicals
4 06/24/03 bob More params for Flocking particles
5 07/05/03 mf Particle and footprints working together
6 07/13/03 bob Avatar file format
7 07/31/03 bob LinkToAgeMsg (which affects responders) and panic link regions
8 08/21/03 Colin Removed some stuff from plSoundBuffer
9 08/22/03 bob Added info to plClothingItem
10 09/16/03 bob Removed stuff in plAnimCmdMsg, which affects responders.
11 09/18/03 mf Changed plLoadMask, of which plWaveSet7 is the biggest user.
12 01/03/04 jeff pfGUIDynDisplayCtrl now stores material as well as layer information
!! 11 02/10/04 mf Dropped back a version, to reduce patch size for Expansion 1.
12 03/12/04 bob New stuff in Swim Regions
0 10/28/05 jeff Reset for major version change
1 11/28/05 jeff GUI text boxes can now pull strings from the localization mgr
2 12/01/05 jeff pfKIMsg can now handle unicode strings
3 02/02/06 adam modified plDynamicEnvMap as a part of back-porting planar reflections from P21
0 02/22/06 bob Reset for major version change
1 04/12/06 Colin Changed physical format
0 05/08/06 bob Reset for major version change
1 05/16/06 markd Changed physics format to include boxes
2 06/26/06 jeff Changed coop brain format so book sharing works again
3 12/05/06 bob Avatar uses a render target instead of a plMipmap.
4 01/16/07 bob Still does, it's just not created at export.
5 01/24/07 adam Changed plAGMasterMod so one can be set as a group master in grouped anims
0 02/12/07 bob Reset for major version change
1 03/29/07 jeff Changed plLoadAvatarMsg and plArmatureMod to be more flexible
2 06/28/07 jeff Changed plAvBrainHuman format to store whether it's an actor or not
*/
#endif // plVersion_h_inc