Database Structure
by Demolishun · in Torque Game Engine · 08/24/2007 (7:50 pm) · 1 replies
I am looking into structuring my database for keeping information about missions. That is fine and dandy, but I am thinking about how to allow a second database applied after the first to change all default data the first one provides. It would be akin to a save game file, but it allows the player to "edit" the game.
Should I figure out how to merge my databases before each mission? I am using sqlite so I could create a memory database.
Should I create all the objects and then apply the second databases information? In this case a dead object that has been removed would have to be removed after initially added.
My goal is to allow for editing of most aspects of the game as far as objects placed in the mission. I want the player to be able to change their world and save the changes to a database. My chosen database is sqlite as this seems very efficient for a single file database.
Here is my basic plan:
1. create master database with all default objects and all code functions stored in this database as well, objects will be created dynamically rather than stored in disparate source files
2. allow loading of other databases to provide data for changed objects in missions and new missions
3. rectify differences before a mission is "run" and display the result
Anybody with any experience in doing this with a better structure?
Should I figure out how to merge my databases before each mission? I am using sqlite so I could create a memory database.
Should I create all the objects and then apply the second databases information? In this case a dead object that has been removed would have to be removed after initially added.
My goal is to allow for editing of most aspects of the game as far as objects placed in the mission. I want the player to be able to change their world and save the changes to a database. My chosen database is sqlite as this seems very efficient for a single file database.
Here is my basic plan:
1. create master database with all default objects and all code functions stored in this database as well, objects will be created dynamically rather than stored in disparate source files
2. allow loading of other databases to provide data for changed objects in missions and new missions
3. rectify differences before a mission is "run" and display the result
Anybody with any experience in doing this with a better structure?
About the author
I love programming, I love programming things that go click, whirr, boom. For organized T3D Links visit: http://demolishun.com/?page_id=67
Torque Owner Demolishun
DemolishunConsulting Rocks!
#ifndef _DYNMEMSTREAM_H_ #define _DYNMEMSTREAM_H_ #ifndef _MEMSTREAM_H_ #include "core/memstream.h" #endif class DynMemStream : public MemStream { typedef MemStream Parent; protected: U32 m_blockSize; ///< Chunk size for new allocations U32 m_writSize; ///< Bytes we have written public: DynMemStream(const U32 in_blockSize, const bool in_allowRead = true, const bool in_allowWrite = true); ~DynMemStream(); U32 getStreamSize() {return m_writSize;} char *getData() {return (char*)m_pBufferBase;} protected: bool _write(const U32 in_numBytes, const void* in_pBuffer); }; #endif //_DYNMEMSTREAM_H_ //Includes #include "platform/platform.h" #include "streams/dynamicMemStream.h" DynMemStream::DynMemStream(const U32 in_blockSize, const bool in_allowRead, const bool in_allowWrite) { m_blockSize = in_blockSize; m_instCaps = 0; m_currentPosition = 0; m_writSize = 0; AssertFatal(in_blockSize > 0, "Invalid block size"); AssertFatal(in_allowRead || in_allowWrite, "Either write or read must be allowed"); char *data = (char*)dMalloc(in_blockSize); cm_bufferSize = in_blockSize; m_pBufferBase = (void*)data; if (in_allowRead) m_instCaps |= Stream::StreamRead; if (in_allowWrite) m_instCaps |= Stream::StreamWrite; setStatus(Ok); } DynMemStream::~DynMemStream() { dFree(m_pBufferBase); } bool DynMemStream::_write(const U32 in_numBytes, const void *in_pBuffer) { AssertFatal(getStatus() != Closed, "Attempted write to a closed stream"); if (in_numBytes == 0) return true; AssertFatal(in_pBuffer != NULL, "Invalid input buffer"); if (hasCapability(StreamWrite) == false) { AssertWarn(0, "Writing is disallowed on this stream"); setStatus(IllegalCall); return false; } bool success = true; if ((m_currentPosition + in_numBytes) > cm_bufferSize) { // TODO: could be a bit more accurate... U32 newSize = (((m_currentPosition + in_numBytes) - cm_bufferSize) / m_blockSize)+1; newSize *= m_blockSize; m_pBufferBase = dRealloc((char*)m_pBufferBase, newSize); AssertFatal(m_pBufferBase, "Failed to reallocate buffer!"); cm_bufferSize = newSize; } // Obtain a current pointer, and do the copy void* pCurrent = (void*)((char*)m_pBufferBase + m_currentPosition); dMemcpy(pCurrent, in_pBuffer, in_numBytes); // Advance the stream position m_currentPosition += in_numBytes; if (m_currentPosition > m_writSize) m_writSize += in_numBytes; if (m_currentPosition == cm_bufferSize) setStatus(EOS); else setStatus(Ok); return success; }This is a class I think James wrote to create dynamic streams.Now the code that uses this:
// save to string ConsoleMethod(SimObject, saveToString, const char*, 2, 3, "obj.save(<selectedOnly>)") { static const char *beginMessage = "//--- OBJECT WRITE BEGIN ---"; 8static const char *endMessage = "//--- OBJECT WRITE END ---"; DynMemStream stream(4096, false, true); // check for flags <selected, ...> U32 writeFlags = 0; if(argc > 3) { if(dAtob(argv[3])) writeFlags |= SimObject::SelectedOnly; } // Write the begin message stream.write(dStrlen(beginMessage), beginMessage); stream.write(2, "\r\n"); // Write the object's serialization into the stream object->write(stream, 0, writeFlags); // Write the end message stream.write(dStrlen(endMessage), endMessage); stream.write(2, "\r\n"); char *ret = Con::getReturnBuffer(stream.getStreamSize() + 1); dStrncpy(ret, stream.getData(), stream.getStreamSize()); ret[stream.getStreamSize()] = 0; return ret; } // end save to stringThis will save an object(s) to a string rather than a file. This was written by someone else as well. I updated these to work with 1.5 engine.The DynMemStream now uses char instead of U8 because of UTF8 errors cropping up. The saveToString function now uses the DynMemSteam function instead of MemStream.