⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chunkfile.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
字号:
//-----------------------------------------------------------------------------
// Torque Game Engine 
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "core/chunkFile.h"

InfiniteBitStream gChunkBuffer;
InfiniteBitStream gHeaderBuffer;

const U32 ChunkFile::csmFileFourCC = makeFourCCTag('T', 'C', 'H', 'K');
const U32 ChunkFile::csmFileVersion = 2;

//------------------------------------------------------------------------------

//------------------------------------------------------------------------------

bool ChunkFile::save(const char * filename)
{
   // Just to be sure, wipe stuff.
   gChunkBuffer.reset();

   // Get a stream...
   FileStream s;
   if(!ResourceManager->openFileForWrite(s, filename))
   {
      Con::errorf("ChunkFile::save - cannot open '%s' for write.", filename);
      return false;
   }

   // write preamble!
   s.write(csmFileFourCC);
   s.write(csmFileVersion);

   // Now save out the chunks!
   saveInner(s, getRoot());

   // Free any memory we had to use for buffering.
   gChunkBuffer.reset();
   gChunkBuffer.compact();

   // All done!
   return true;
}

bool ChunkFile::saveInner(Stream &s, SimChunk *c)
{
   // First, write the chunk to a buffer so we can meditate on it
   gChunkBuffer.reset();
   c->writeChunk(gChunkBuffer);

   // Buffer the header...
   gHeaderBuffer.reset();

   // Prepare the header
   gHeaderBuffer.writeCussedU32(c->getChunkVersion());
   gHeaderBuffer.writeCussedU32(gChunkBuffer.getPosition());
   gHeaderBuffer.writeString((const char *)c->getFourCCString(), 4);
   gHeaderBuffer.writeCussedU32(c->size()); // Child count.
   gHeaderBuffer.write(gChunkBuffer.getCRC());

   // Write the header (first size, then data)!
   AssertFatal(gHeaderBuffer.getPosition() < 256,
                                 "ChunkFile::saveInner - got too big header!");
   s.write(U8(gHeaderBuffer.getPosition())); 
   gHeaderBuffer.writeToStream(s);
   gHeaderBuffer.reset();

   // Write the chunk!
   gChunkBuffer.writeToStream(s);
   gChunkBuffer.reset();

   // Recurse!
   for(U32 i=0; i<c->size(); i++)
   {
      // We have to assume people will stuff all sorts of crap into this thing.
      SimChunk *sc = dynamic_cast<SimChunk*>((*c)[i]);

      if(sc)
         saveInner(s, sc);
      else
      {
         Con::errorf("ChunkFile::saveInner - got unexpected class '%s' as child of object %d!", 
            (c ? (*c)[i]->getClassName() : "NULL OBJECT"), c->getId());

         // Write a null header, eww gross.
         gHeaderBuffer.writeCussedU32(0);
         gHeaderBuffer.writeCussedU32(0);
         gHeaderBuffer.writeString("", 4);
         gHeaderBuffer.writeCussedU32(0); // Child count.
         gHeaderBuffer.write(0);

         // That should allow us to recover gracefully when we load...
      }
   }

   return true;
}

//------------------------------------------------------------------------------

bool ChunkFile::load(Stream &s)
{
   // check preamble!
   U32 fourcc, ver;
   s.read(&fourcc);
   s.read(&ver);

   if(fourcc != csmFileFourCC)
   {
      Con::errorf("ChunkFile::load - unexpected header value!");
      return false;
   }

   if(ver != csmFileVersion)
   {
      // Be clever
      if(ver > csmFileVersion)
      {
         Con::errorf("ChunkFile::load - encountered file header version from the future!");
      }
      else
      {
         Con::errorf("ChunkFile::load - encountered file header version from the past!");
      }

      // Error out.
      return false;
   }

   // Now recursively load all our children!
   mRoot = loadInner(s);

   // Add us to the ChunkFileGroup
   Sim::getChunkFileGroup()->addObject(mRoot);

   return true;
}

SimChunk *ChunkFile::loadInner(Stream &s, U32 childCount)
{
   U8 headerSize;
   U32 fourCC, ver, crc, size;
   S32 children;

   // Read the header size and prepare to read the header bitstream...
   s.read(&headerSize);

   U8 *headerBuff = new U8[headerSize];
   s.read(headerSize, headerBuff);

   BitStream hData(headerBuff, headerSize);

   // Read actual header values.
   ver      = hData.readCussedU32();
   size     = hData.readCussedU32();

   // Get the fourcc...
   char fcctmp[256]; // For safety we make it 256, longest size string we can read.
   hData.readString(fcctmp);
   fourCC = makeFourCCTag(fcctmp[0], fcctmp[1], fcctmp[2], fcctmp[3]);

   children = hData.readCussedU32();
   hData.read(&crc);

   delete[] headerBuff;

   // Create the chunk...
   SimChunk *sc = SimChunk::createChunkFromFourCC(fourCC);

   // Do some version sanity checking.
   if(ver > sc->getChunkVersion())
   {
      // uh oh, it's a chunk from the future!
      Con::warnf("ChunkFile::loadInner - found a '%s' chunk with version %d; highest supported version is %d. Treating as unknown chunk...",
                       fcctmp, ver, sc->getChunkVersion());

      // Let's use an unknown chunk instead.
      delete sc;
      sc = new UnknownChunk();
   }

   // Read the chunk data into a buffer...
   U8 *buff = new U8[size];
   s.read(size, buff);

   BitStream cData(buff, size);
   sc->readChunk(cData, size, ver, crc, fourCC);

   delete[] buff;

   // Register it!
   sc->registerObject();

   // Recurse on children, adding them to our SimChunk.
   for(S32 i=0; i<children; i++)
      sc->addObject(loadInner(s, childCount));

   // All done!
   return sc;
}

//------------------------------------------------------------------------------

ResourceInstance *ChunkFile::constructChunkFile(Stream &stream)
{
   ChunkFile *cf = new ChunkFile();
   if(cf->load(stream))
   {
      return cf;
   }
   else
   {
      delete cf;
      return NULL;
   }
}

//------------------------------------------------------------------------------
Vector<SimChunk::FourCCToAcr*> SimChunk::smFourCCList;

#ifdef TGE_RPG

 SimChunk::FourCCToAcr::FourCCToAcr(U32 fourCC, AbstractClassRep *acr)
{
   //FourCCToAcr * fcta = new FourCCToAcr();

   fourCC = fourCC;
   acr    = acr;       

   smFourCCList.push_back(this);
}

void SimChunk::consoleInit()
{
	//addFourCCToAcr(getFourCC(),getStaticClassRep());
}
#endif


void SimChunk::initChunkMappings()
{
   Con::printf("Initializing chunk mappings...");

#ifndef TGE_RPG
	/// 这样的处理算法,太不敢恭维了,要对所有consoleObject进行对象创建
	/// 干脆在consoleInit中实现同样的逻辑,省去调用 rep->create()麻烦
	///
   for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
   {
      ConsoleObject *obj = rep->create();

      SimChunk *chunk;

      if(obj && (chunk = dynamic_cast<SimChunk *>(obj)))
      {
         Con::printf("   o '%s' maps to %s", chunk->getFourCCString(), chunk->getClassName());

         FourCCToAcr * fcta = new FourCCToAcr();

         fcta->fourCC = chunk->getFourCC();
         fcta->acr    = rep;       

         smFourCCList.push_back(fcta);
      }

      delete obj;
   }
#endif
   // Also register the .chunk file format.
   ResourceManager->registerExtension(".chunk", ChunkFile::constructChunkFile);
}



#ifdef TGE_RPG
void SimChunk::destoryChunkMappings()
{
	//for(S32 n=0; n < smFourCCList.size(); n++)
	//{
	//	delete smFourCCList[n];
	//	smFourCCList[n] = 0;
	//}
}
#endif


SimChunk *SimChunk::createChunkFromFourCC(U32 fourCC)
{
   // Try to find a match.
   for(U32 i=0; i<smFourCCList.size(); i++)
   {
      if(smFourCCList[i]->fourCC == fourCC)
         return (SimChunk*)smFourCCList[i]->acr->create();
   }

   // Unknown 4cc, let's use the UnknownChunk
   U8 c[4];
   c[0] = fourCC >> 24;
   c[1] = fourCC >> 16;
   c[2] = fourCC >> 8;
   c[3] = fourCC >> 0;
   Con::warnf("SimChunk::createChunkFromFourCC - encountered unknown fourCC '%c%c%c%c'", c[0], c[1], c[2], c[3]);

   return new UnknownChunk();
}

//------------------------------------------------------------------------------

#ifdef TGE_RPG
IMPLEMENT_CHUNK(SimChunk);
#else
IMPLEMENT_CONOBJECT(SimChunk);
#endif

void SimChunk::writeChunk(BitStream &b)
{

}

void SimChunk::readChunk(BitStream &s, const U32 length, const U32 version, const U32 crc, const U32 fourCC)
{

}

//------------------------------------------------------------------------------

#ifdef TGE_RPG
//U32  UnknownChunk::mChunkFourCC	 = 0;
//U8   UnknownChunk::mChunkFourCCString[4] = {0};
//U32  UnknownChunk::mChunkVersion	 = 0;
#endif


#ifdef TGE_RPG
IMPLEMENT_CHUNK(UnknownChunk);
#else
IMPLEMENT_CONOBJECT(UnknownChunk);
#endif


#ifdef TGE_RPG

//void UnknownChunk::consoleInit()
//{
//	Parent::consoleInit();
//}
#endif

UnknownChunk::UnknownChunk()
{
#ifndef TGE_RPG
   mChunkFourCC = mChunkVersion = 
#endif
		mChunkCRC = mDataLength = 0;
   mDataBuffer = NULL;
}

UnknownChunk::~UnknownChunk()
{
   if(mDataBuffer)
      dFree(mDataBuffer);
   mDataBuffer = NULL;
}

void UnknownChunk::writeChunk(BitStream &b)
{
   b.write(mDataLength, mDataBuffer);
}

void UnknownChunk::readChunk(BitStream &s, const U32 length, const U32 version, const U32 crc, const U32 fourCC)
{
   mDataBuffer = (U8*)dMalloc(length);
   s.read(length, mDataBuffer);
}

//------------------------------------------------------------------------------


   void TextChunk::initPersistFields()
   {
      Parent::initPersistFields();

      addField("textData", TypeString, Offset(mText, TextChunk));
   }

   void TextChunk::readChunk(BitStream &s, const U32 length, const U32 version, const U32 crc, const U32 fourCC)
   {
      switch(version)
      {
         // Deal with older stuff.
      case 1:
         mText = s.readSTString();
         break;

         // Shiny new format!
      case 2:
         // Resize the buffer..
         U32 newSize;
         s.read(&newSize);

         char *tmpBuff = new char[newSize+1];
         s.readLongString(newSize, (char*)tmpBuff);

         mText = StringTable->insert(tmpBuff);

         delete[] tmpBuff;
         break;
      }
   }

	void TextChunk::writeChunk(BitStream &s)
   {
      s.write((U32)dStrlen(mText));
      s.writeLongString(dStrlen(mText), mText);
   }

//class TextChunk : public SimChunk
//{
//   typedef SimChunk Parent;
//
//protected:
//   const char * mText;
//
//public:
//   DECLARE_CHUNK(TextChunk, ('T','E','X','T'), 2);
//
//   TextChunk()
//   {
//      mText = StringTable->insert("");
//   }
//
//   ~TextChunk()
//   {
//      // No deletion, it's a string table entry.
//   }
//
//   static void initPersistFields()
//   {
//      Parent::initPersistFields();
//
//      addField("textData", TypeString, Offset(mText, TextChunk));
//   }
//
//   void readChunk(BitStream &s, const U32 length, const U32 version, const U32 crc, const U32 fourCC)
//   {
//      switch(version)
//      {
//         // Deal with older stuff.
//      case 1:
//         mText = s.readSTString();
//         break;
//
//         // Shiny new format!
//      case 2:
//         // Resize the buffer..
//         U32 newSize;
//         s.read(&newSize);
//
//         char *tmpBuff = new char[newSize+1];
//         s.readLongString(newSize, (char*)tmpBuff);
//
//         mText = StringTable->insert(tmpBuff);
//
//         delete[] tmpBuff;
//         break;
//      }
//   }
//
//   void writeChunk(BitStream &s)
//   {
//      s.write((U32)dStrlen(mText));
//      s.writeLongString(dStrlen(mText), mText);
//   }
//};
#ifdef TGE_RPG
IMPLEMENT_CHUNK(TextChunk);
#else
IMPLEMENT_CONOBJECT(TextChunk);
#endif

//------------------------------------------------------------------------------

ConsoleFunction(saveChunkFile, bool, 3, 3, "(SimChunk chunk, Filename file)"
                "Write a chunk hierarchy to a file.")
{
   SimChunk *rootChunk = NULL;
   const char *file = argv[2];

   if(!Sim::findObject(argv[1], rootChunk))
   {
      Con::errorf("writeChunkFile - Unable to locate root chunk '%s'", argv[1]);
      return false;
   }

   ChunkFile *cf = new ChunkFile();

   cf->setRoot(rootChunk);

   bool res = true;

   if(!cf->save(file))
   {
      Con::errorf("writeChunkFile - Failed to save '%s' to '%s'", argv[1],  file);
      res = false;
   }

   delete cf;

   return res;
}

ConsoleFunction(loadChunkFile, S32, 2, 2, "(Filename file)"
                "Read a chunk hierarchy from a file.")
{
   Resource<ChunkFile> ri = ResourceManager->load(argv[1]);

   if(bool(ri) == false)
   {
      Con::errorf("loadChunkFile - failed to open '%s'", argv[1]);
      return 0;
   }

   // Otherwise we're ok.
   return ri->getRoot()->getId();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -