[Add] Serialisation stuff.

This commit is contained in:
Tamir Atias 2012-02-24 02:11:06 +02:00
parent 7d00bfb34a
commit 9ca8983561
9 changed files with 373 additions and 224 deletions

View File

@ -19,6 +19,8 @@ HEADERS += ../src/Libs/wglext.h \
../src/libUnuk/Sprite/Texture.h \
../src/libUnuk/Sprite/ImageLoader.h \
../src/libUnuk/Sprite/ApplySurface.h \
../src/libUnuk/System/Serialisation.h \
../src/libUnuk/System/Serialisable.h \
../src/libUnuk/System/Rect.h \
../src/libUnuk/System/Input.h \
../src/libUnuk/System/FPS.h \
@ -57,6 +59,7 @@ SOURCES += ../src/libUnuk/Engine/WorldManager.cpp \
../src/libUnuk/Sprite/Texture.cpp \
../src/libUnuk/Sprite/ImageLoader.cpp \
../src/libUnuk/Sprite/ApplySurface.cpp \
../src/libUnuk/System/Serialisation.cpp \
../src/libUnuk/System/Timer.cpp \
../src/libUnuk/System/Rect.cpp \
../src/libUnuk/System/Input.cpp \
@ -76,6 +79,7 @@ SOURCES += ../src/libUnuk/Engine/WorldManager.cpp \
../src/libUnuk/LevelGen/LevelGen.cpp \
../src/libUnuk/LevelGen/MapEntities.cpp \
../src/libUnuk/LevelGen/MapElement.cpp \
../src/libUnuk/LevelGen/MapTile.cpp \
../src/libUnuk/LevelGen/AStarTile.cpp \
../src/libUnuk/UI/EventHistory.cpp \
../src/libUnuk/UI/Bar.cpp \

View File

@ -240,6 +240,10 @@
RelativePath="..\..\..\src\libUnuk\LevelGen\MapEntities.h"
>
</File>
<File
RelativePath="..\..\..\src\libUnuk\LevelGen\MapTile.cpp"
>
</File>
<File
RelativePath="..\..\..\src\libUnuk\LevelGen\MapTile.h"
>
@ -316,6 +320,18 @@
RelativePath="..\..\..\src\libUnuk\System\Rect.h"
>
</File>
<File
RelativePath="..\..\..\src\libUnuk\System\Serialisable.h"
>
</File>
<File
RelativePath="..\..\..\src\libUnuk\System\Serialiser.cpp"
>
</File>
<File
RelativePath="..\..\..\src\libUnuk\System\Serialiser.h"
>
</File>
<File
RelativePath="..\..\..\src\libUnuk\System\Timer.cpp"
>

View File

@ -2,6 +2,7 @@
#include "LevelGen.h"
#include "../Engine/NPC.h"
#include "../System/Serialiser.h"
#include "../../Unuk/Player.h"
LevelGen::LevelGen(void) : _world(this) {
@ -28,7 +29,6 @@ void LevelGen::New(void) {
_tile[x][y].SetTileSolidity(false);
_tile[x][y].SetTileXY(x * TILE_WIDTH, y * TILE_HEIGHT);
_tile[x][y].SetEntitySolidity(false);
_tile[x][y].SetZLevel(100);
}
}
@ -41,103 +41,14 @@ void LevelGen::New(void) {
void LevelGen::Load(const string& filename) {
Unload();
_currentMap = filename;
string fullMapPath = "../Data/Media/Maps/" + filename;
TiXmlDocument mapFile(fullMapPath.c_str());
assert(mapFile.LoadFile() == true);
Serialiser serialiser;
serialiser.Load(fullMapPath);
Inflate(&serialiser);
// Getting dirty with some XML. This seems like a nicer
// approach to loading maps, rather than parsing text files.
TiXmlElement* rootElem = NULL;
TiXmlElement* lineElem = NULL;
TiXmlElement* tileElem = NULL;
TiXmlElement* dataElem = NULL;
x = -1;
y = -1;
// <map> - Let's start parsing the map.
rootElem = mapFile.FirstChildElement("map");
assert(rootElem != NULL);
if(rootElem) {
// <line> - We want to tile one line at a time. line represents
// the row we are tiling.
lineElem = rootElem->FirstChildElement("line");
assert(lineElem != NULL);
while(lineElem) {
y++;
x = -1;
// <tile> - Then we will select the tile. and increment x to keep tiling that row.
tileElem = lineElem->FirstChildElement("tile");
assert(tileElem != NULL);
while(tileElem) {
x++;
_tile[x][y].SetTileXY(x * TILE_WIDTH, y * TILE_HEIGHT);
// <tileTexture> - Apply a teture to the tile.
dataElem = tileElem->FirstChildElement("tileTexture");
assert(dataElem != NULL);
stringstream tilePath;
tilePath << "../Data/Media/Images/Tiles/" << dataElem->GetText() << ".png";
_tile[x][y].SetTileTexture(_tileTextures.Add(tilePath.str()));
_tile[x][y].SetTileTextureName(dataElem->GetText());
// <tileTexture> - Finished applying the texture, move to the next sibling.
// <solidTile> - Check to see if the tile is solid or not.
dataElem = dataElem->NextSiblingElement("solidTile");
assert(dataElem != NULL);
string tileSolidity = dataElem->GetText();
assert(tileSolidity == "false" || tileSolidity == "true");
if(tileSolidity == "false")
_tile[x][y].SetTileSolidity(false);
else
_tile[x][y].SetTileSolidity(true);
// </solidTile>
// <entityTexture>
dataElem = dataElem->NextSiblingElement("entityTexture");
assert(dataElem != NULL);
string entityName = dataElem->GetText();
if(entityName != "null") {
stringstream entityPath;
entityPath << "../Data/Media/Images/Entities/" << entityName << ".png";
_tile[x][y].SetEntityTexture(_entityTextures.AddAlpha(entityPath.str()));
_tile[x][y].SetEntityTextureName(entityName);
_tile[x][y].SetEntityXY(_tile[x][y].GetTileX() + TILE_WIDTH / 2 - _tile[x][y].GetEntityWidth() / 2,
_tile[x][y].GetTileY() + TILE_HEIGHT / 2 - _tile[x][y].GetEntityHeight() / 2);
}
// </entityTexture>
// <SolidEntity>
dataElem = dataElem->NextSiblingElement("solidEntity");
assert(dataElem != NULL);
string entitySolidity = dataElem->GetText();
assert(entitySolidity == "false" || entitySolidity == "true");
if(entitySolidity == "false")
_tile[x][y].SetEntitySolidity(false);
else
_tile[x][y].SetEntitySolidity(true);
// </solidEntity>
// <zlevel>
dataElem = dataElem->NextSiblingElement("zLevel");
assert(dataElem != NULL);
_tile[x][y].SetZLevel(atoi(dataElem->GetText()));
// </zlevel>
tileElem = tileElem->NextSiblingElement("tile");
}
//</tile>
lineElem = lineElem->NextSiblingElement("line");
}
// </line>
}
// </map>
_world = WorldManager(this);
GenerateEnemies();
@ -145,59 +56,15 @@ void LevelGen::Load(const string& filename) {
UpdateAStarTiles();
}
void LevelGen::Save(const string& filename){
TiXmlDocument doc;
TiXmlElement* rootElem = new TiXmlElement("map");
for(y = 0; y < TILE_ARRAY_HEIGHT; y++) {
TiXmlElement* lineElem = new TiXmlElement("line");
for(x = 0; x < TILE_ARRAY_WIDTH; x++) {
TiXmlElement* tileElem = new TiXmlElement("tile");
TiXmlElement* tileTextureElem = new TiXmlElement("tileTexture");
TiXmlText* tileTextureText = new TiXmlText(_tile[x][y].GetTileTextureName().c_str());
tileTextureElem->LinkEndChild(tileTextureText);
TiXmlElement* solidTileElem = new TiXmlElement("solidTile");
TiXmlText* solidTileText = new TiXmlText(_tile[x][y].GetTileSolidity() ? "true" : "false");
solidTileElem->LinkEndChild(solidTileText);
string entityTextureName = _tile[x][y].GetEntityTextureName();
TiXmlElement* entityTextureElem = new TiXmlElement("entityTexture");
TiXmlText* entityTextureText = new TiXmlText(entityTextureName.empty() ? "null" : entityTextureName.c_str());
entityTextureElem->LinkEndChild(entityTextureText);
TiXmlElement* solidEntityElem = new TiXmlElement("solidEntity");
TiXmlText* solidEntityText = new TiXmlText(_tile[x][y].GetEntitySolitity() ? "true" : "false");
solidEntityElem->LinkEndChild(solidEntityText);
stringstream zLevelStr;
zLevelStr << _tile[x][y].GetZLevel();
TiXmlElement* zLevelElem = new TiXmlElement("zLevel");
TiXmlText* zLevelText = new TiXmlText(zLevelStr.str().c_str());
zLevelElem->LinkEndChild(zLevelText);
tileElem->LinkEndChild(tileTextureElem);
tileElem->LinkEndChild(solidTileElem);
tileElem->LinkEndChild(entityTextureElem);
tileElem->LinkEndChild(solidEntityElem);
tileElem->LinkEndChild(zLevelElem);
lineElem->LinkEndChild(tileElem);
}
rootElem->LinkEndChild(lineElem);
}
void LevelGen::Save(const string& filename) {
Serialiser serialiser;
Deflate(&serialiser);
_currentMap = filename;
string fullMapPath = "../Data/Media/Maps/" + filename;
doc.LinkEndChild(rootElem);
doc.SaveFile(fullMapPath.c_str());
serialiser.Save(fullMapPath);
}
void LevelGen::Update(void) {
@ -318,11 +185,6 @@ void LevelGen::FindSpawnPoint(int& xArg, int& yArg, int objWidth, int objHeight)
for(int i = 0; i < TILE_ARRAY_WIDTH; i++) {
for(int j = 0; j < TILE_ARRAY_HEIGHT; j++) {
if(_tile[i][j].GetTileSolidity()) {
FindSpawnPoint(xArg, yArg, objWidth, objHeight);
return;
}
if(_tile[i][j].GetEntitySolitity()) {
SDL_Rect entityRect;
entityRect.x = _tile[i][j].GetEntityX();
@ -460,6 +322,56 @@ void LevelGen::UpdateAStarTiles(void) {
}
}
void LevelGen::Deflate(Serialiser* serialiser) {
serialiser->StepIn("map");
for(int y = 0; y < TILE_ARRAY_HEIGHT; y++) {
serialiser->StepIn("line");
for(int x = 0; x < TILE_ARRAY_WIDTH; x++) {
serialiser->StepIn("tile");
_tile[x][y].Deflate(serialiser);
serialiser->StepOut();
}
serialiser->StepOut();
}
serialiser->StepOut();
}
void LevelGen::Inflate(Serialiser* serialiser) {
serialiser->FirstElement("map");
x = 0;
y = 0;
while(serialiser->NextElement("line")) {
x = 0;
while(serialiser->NextElement("tile")) {
_tile[x][y].Inflate(serialiser);
x++;
}
serialiser->RollBack();
y++;
}
for(x = 0; x < TILE_ARRAY_WIDTH; x++) {
for(y = 0; y < TILE_ARRAY_HEIGHT; y++) {
string tileTextureName = _tile[x][y].GetTileTextureName();
if(tileTextureName != "null") {
_tile[x][y].SetTileTexture(_tileTextures.AddAlpha("../Data/Media/Images/Tiles/" + tileTextureName + ".png"));
_tile[x][y].SetTileXY(x * TILE_WIDTH, y * TILE_HEIGHT);
}
string entityTextureName = _tile[x][y].GetEntityTextureName();
if(entityTextureName != "null") {
_tile[x][y].SetEntityTexture(_entityTextures.AddAlpha("../Data/Media/Images/Entities/" + entityTextureName + ".png"));
_tile[x][y].SetEntityXY(_tile[x][y].GetTileX() + TILE_WIDTH / 2 - _tile[x][y].GetEntityWidth() / 2,
_tile[x][y].GetTileY() + TILE_HEIGHT / 2 - _tile[x][y].GetEntityHeight() / 2);
}
}
}
}
string LevelGen::GetCurrentMap(void) {
return _currentMap;
}
@ -500,10 +412,6 @@ int LevelGen::GetEntityHeight(int xArg, int yArg) {
return _tile[xArg + 1][yArg + 1].GetEntityHeight();
}
int LevelGen::GetTileZLevel(int xArg, int yArg) {
return _tile[xArg + 1][yArg + 1].GetZLevel();
}
AStarTile& LevelGen::GetAStarTile(int xArg, int yArg) {
return _astarTile[xArg][yArg];
}
}

View File

@ -14,6 +14,7 @@
#include "../LevelGen/MapTile.h"
#include "../LevelGen/AStarTile.h"
#include "../System/Debug.h"
#include "../System/Serialisable.h"
#include "../Engine/WorldManager.h"
#include "../Engine/MemClass.h"
using namespace std;
@ -21,7 +22,7 @@ using namespace std;
class Character;
class Player;
class LevelGen {
class LevelGen : public Serialisable {
public:
LevelGen(void);
~LevelGen(void);
@ -70,11 +71,13 @@ private:
bool AStarTilePassable(int xArg, int yArg);
void UpdateAStarTiles(void);
void Deflate(Serialiser* serialiser);
void Inflate(Serialiser* serialiser);
string _currentMap;
int x;
int y;
MapTile _tile[TILE_ARRAY_WIDTH][TILE_ARRAY_HEIGHT];
AStarTile _astarTile[ASTAR_ARRAY_WIDTH][ASTAR_ARRAY_HEIGHT];

View File

@ -1,66 +1,42 @@
#include "MapTile.h"
#include "LevelGen.h"
MapTile::MapTile(const MapTile& source) {
_level = source._level;
_tile = source._tile;
_entity = source._entity;
_zLevel = source._zLevel;
void MapTile::Deflate(Serialiser* serialiser) {
string tileTexture = _tile.GetTextureName();
bool solidTile = _tile.GetSolidity();
string entityTexture = _entity.GetTextureName();
bool solidEntity = _entity.GetSolidity();
if(tileTexture.empty()) {
tileTexture = "null";
}
if(entityTexture.empty()) {
entityTexture = "null";
}
serialiser->RegisterMember("tileTexture", MEMBER_STRING, &tileTexture);
serialiser->RegisterMember("solidTile", MEMBER_BOOL, &solidTile);
serialiser->RegisterMember("entityTexture", MEMBER_STRING, &entityTexture);
serialiser->RegisterMember("solidEntity", MEMBER_BOOL, &solidEntity);
serialiser->WriteMembers();
}
bool MapTile::IsSameState(MapTile& tile) {
return (tile.GetTileX() == _tile.GetX()) && (tile.GetTileY() == _tile.GetY());
}
void MapTile::Inflate(Serialiser* serialiser) {
string tileTexture;
bool solidTile;
string entityTexture;
bool solidEntity;
bool MapTile::IsGoal(MapTile& tile) {
return IsSameState(tile);
}
serialiser->RegisterMember("tileTexture", MEMBER_STRING, &tileTexture);
serialiser->RegisterMember("solidTile", MEMBER_BOOL, &solidTile);
serialiser->RegisterMember("entityTexture", MEMBER_STRING, &entityTexture);
serialiser->RegisterMember("solidEntity", MEMBER_BOOL, &solidEntity);
float MapTile::GoalDistanceEstimate(MapTile& goal) {
Vec2 thisPos(_tile.GetX(), _tile.GetY());
Vec2 goalPos(goal.GetTileX(), goal.GetTileY());
return fabs(Vec2::DistanceSquared(thisPos, goalPos));
}
serialiser->ReadMembers();
float MapTile::GetCost(MapTile& goal) {
return 64.0f*64.0f;
}
_tile.SetTextureName(tileTexture);
_tile.SetSolidity(solidTile);
bool MapTile::GetSuccessors(AStarSearch<MapTile>* search, MapTile* parent) {
int tileX = _tile.GetX() / TILE_WIDTH;
int tileY = _tile.GetY() / TILE_HEIGHT;
// Add tile to the left if possible.
if(tileX > 0) {
MapTile& successor = _level->GetTile(tileX - 1, tileY);
if(successor.GetTileSolidity() || successor.GetEntitySolitity()) {
search->AddSuccessor(successor);
}
}
// Add tile to the right if possible
if(tileX < TILE_WIDTH) {
MapTile& successor = _level->GetTile(tileX + 1, tileY);
if(successor.GetTileSolidity() || successor.GetEntitySolitity()) {
search->AddSuccessor(successor);
}
}
// Add tile to the bottom if possible
if(tileY > 0) {
MapTile& successor = _level->GetTile(tileX, tileY - 1);
if(successor.GetTileSolidity() || successor.GetEntitySolitity()) {
search->AddSuccessor(successor);
}
}
// Add tile to the top if possible
if(tileY < TILE_HEIGHT) {
MapTile& successor = _level->GetTile(tileX, tileY + 1);
if(successor.GetTileSolidity() || successor.GetEntitySolitity()) {
search->AddSuccessor(successor);
}
}
return true;
}
_entity.SetTextureName(entityTexture);
_entity.SetSolidity(solidEntity);
}

View File

@ -7,15 +7,20 @@
#include "../Sprite/ApplySurface.h"
#include "../LevelGen/MapElement.h"
#include "../LevelGen/MapEntities.h"
#include "../System/Serialisable.h"
#include "../System/Serialiser.h"
using namespace std;
class MapTile {
class MapTile : public Serialisable {
public:
MapTile(void) { }
~MapTile(void) { }
void Render(void) { _tile.Render(), _entity.Render(); }
void Deflate(Serialiser* serialiser);
void Inflate(Serialiser* serialiser);
// Tile Mutators.
SDL_Surface* SetTileTexture(SDL_Surface* arg) { _tile.SetTexture(arg); return NULL; }
void SetTileTextureName(string path) { _tile.SetTextureName(path); }
@ -29,7 +34,6 @@ public:
int GetTileX(void) { return _tile.GetX(); }
int GetTileY(void) { return _tile.GetY(); }
// Entity Mutators.
void SetEntityTexture(SDL_Surface* arg) { _entity.SetTexture(arg); }
void SetEntityTextureName(string path) { _entity.SetTextureName(path); }
@ -44,15 +48,7 @@ public:
int GetEntityHeight(void) { return _entity.GetHeight(); }
string GetEntityTextureName(void) { return _entity.GetTextureName(); }
// ZLevel Mutators.
void SetZLevel(int arg) { _zLevel = arg; }
int GetZLevel(void) { return _zLevel; }
private:
MapElement _tile;
MapEntityGeneric _entity;
// -1 is a 'special' tile, the next tile that the player walks
// on is the players new zlevel.
int _zLevel;
};

View File

@ -0,0 +1,10 @@
#pragma once
#include <stdio.h>
class Serialiser;
class Serialisable {
public:
virtual void Deflate(Serialiser* serialiser) = 0;
virtual void Inflate(Serialiser* serialiser) = 0;
};

View File

@ -0,0 +1,171 @@
#include <sstream>
#include "Serialiser.h"
#include "Debug.h"
void Serialiser::StepIn(const string& name) {
if(_currentElement != NULL) {
// Save the current element as a parent element.
_parentElements.push_back(_currentElement);
}
// Create the new element.
_currentElement = new TiXmlElement(name.c_str());
if(_rootElement == NULL) {
_rootElement = _currentElement;
_parentElements.push_back(_rootElement);
}
}
void Serialiser::StepOut(void) {
if(_parentElements.size() == 0) {
return;
}
TiXmlElement* parentElement = _parentElements.back();
// This happens when stepping out of root.
if(parentElement == _currentElement) {
return;
}
// Append the current element to the end of the parent element.
parentElement->LinkEndChild(_currentElement);
// Set the current element to be the parent element.
_currentElement = parentElement;
// Remove the current element from the parent elements list.
_parentElements.pop_back();
}
bool Serialiser::FirstElement(const string& name) {
TiXmlElement* oldElement = _currentElement;
if(!_currentElement) {
_currentElement = _document.FirstChildElement(name.c_str());
} else {
_currentElement = _currentElement->FirstChildElement(name.c_str());
}
if(!_currentElement) {
// Restore the old element if new one was not found.
_currentElement = oldElement;
return false;
}
if(oldElement) {
// Save the old element as parent.
_parentElements.push_back(oldElement);
}
return true;
}
bool Serialiser::NextElement(const string& name) {
// Find first element of that name if current one is
// not named the same.
if(name != _currentElement->Value()) {
return FirstElement(name);
}
TiXmlElement* oldElement = _currentElement;
_currentElement = _currentElement->NextSiblingElement(name.c_str());
if(!_currentElement) {
// Restore the old element if new one was not found.
_currentElement = oldElement;
return false;
}
return true;
}
void Serialiser::RollBack(void) {
if(_parentElements.size() > 0) {
_currentElement = _parentElements.back();
_parentElements.pop_back();
}
}
void Serialiser::Load(const string& filename) {
_document.LoadFile(filename.c_str());
}
void Serialiser::Save(const string& filename) {
_document.LinkEndChild(_rootElement);
_document.SaveFile(filename.c_str());
}
void Serialiser::RegisterMember(const string& name, int type, void* data) {
SerialiserMember member(name, type, data);
_members.push_back(member);
}
void Serialiser::WriteMembers(void) {
Debug::logger->message("WriteMembers()");
std::stringstream sstream;
for(list<SerialiserMember>::iterator i = _members.begin(); i != _members.end(); ++i) {
TiXmlText* text = NULL;
// Convert the data to text.
if(i->_type == MEMBER_INT) {
sstream.clear();
sstream << *((int*)i->_data);
text = new TiXmlText(sstream.str().c_str());
} else if(i->_type == MEMBER_FLOAT) {
sstream.clear();
sstream << *((float*)i->_data);
text = new TiXmlText(sstream.str().c_str());
} else if(i->_type == MEMBER_STRING) {
text = new TiXmlText((*((string*)i->_data)).c_str());
} else if(i->_type == MEMBER_BOOL) {
bool b = *((bool*)i->_data);
text = new TiXmlText(b ? "true" : "false");
}
if(!text) {
continue;
}
TiXmlElement* element = new TiXmlElement(i->_name.c_str());
element->LinkEndChild(text);
_currentElement->LinkEndChild(element);
}
_members.clear();
}
void Serialiser::ReadMembers(void) {
for(list<SerialiserMember>::iterator i = _members.begin(); i != _members.end(); ++i) {
TiXmlElement* element = _currentElement->FirstChildElement(i->_name.c_str());
if(!element) {
continue;
}
// Read the data from the text of the element.
if(i->_type == MEMBER_INT) {
*((int*)i->_data) = atoi(element->GetText());
} else if(i->_type == MEMBER_FLOAT) {
*((float*)i->_data) = (float)atof(element->GetText());
} else if(i->_type == MEMBER_STRING) {
*((string*)i->_data) = string(element->GetText());
} else if(i->_type == MEMBER_BOOL) {
if(!strcmp(element->GetText(), "true")) {
*((bool*)i->_data) = true;
} else {
*((bool*)i->_data) = false;
}
}
}
_members.clear();
}

View File

@ -0,0 +1,65 @@
#pragma once
#include <string>
#include <list>
#include <tinyxml.h>
#include "Serialisable.h"
using std::string;
using std::list;
enum {
MEMBER_INT,
MEMBER_FLOAT,
MEMBER_BOOL,
MEMBER_STRING,
};
class SerialiserMember {
public:
SerialiserMember(const string& name, int type, void* data) : _name(name), _type(type), _data(data) {}
string _name;
int _type;
void* _data;
};
class Serialiser {
public:
Serialiser(void) : _rootElement(NULL), _currentElement(NULL) {}
// SERIALISATION:
// StepIn should be called when a new list of elements/members needs to be created (go further down the tree).
// StepOut should be called every time the processing of an element is complete (go further up the tree).
void StepIn(const string& name);
void StepOut(void);
// DESERIALISATION:
// FirstElement is used to find the first child element of the current element.
// NextElement should be called whenever the next element is requested, if another element
// was found, it will return true.
// RollBack will just go back to the parent element.
bool FirstElement(const string& name);
bool NextElement(const string& name);
void RollBack(void);
// Load should be called before the deserialisation.
// Save should be called after the serialisation.
void Load(const string& filename);
void Save(const string& filename);
// The members of the element should all be registered with RegisterMember.
// If serialisation is done, WriteMembers should be called after registration, otherwise,
// ReadMembers should be called after registration. After ReadMembers/WriteMembers is called,
// the list of members is clear.
void RegisterMember(const string& name, int _type, void* data);
void WriteMembers(void);
void ReadMembers(void);
private:
TiXmlDocument _document;
TiXmlElement* _rootElement;
TiXmlElement* _currentElement;
list<TiXmlElement*> _parentElements;
list<SerialiserMember> _members;
};