Okie dokey, I've made a bit more progress in my attempt to build a text menu system, new source code is on its way. I decided that there were some minor design flaws in making it so that I would serialize each menu object individually, instead I decided that it was a good idea to instead serialize the manager classes themselves, in all their entirety. This simplifies the saving and loading functions ALOT. I had a couple discussions with some pretty smart people and have come to a few thoughts.
First off, I realized that in using an Object base class for all my game objects, I have alot of type safety issues. While I don't see this as really a problem, because all I need to do is make sure I don't use the types in an incorrect manner. The way I see it, it's like asking a yes or no question and expecting a different answer. If you don't put the different answer there it will never happen, it's all coding style I guess.
I've been beginning to question the actual need for a manager object because in reality it's just a wrapper for a map, when the map already has it's own functions for accessing it and whatnot. Then after that thought, I thought about where I would put the serialization function for the maps that contain my objects, to be honest I left at a blank with this question. Thus I think I will keep the manager classes for aesthetic purposes. I can save a manager object, but I don't think I can just save a map that is floating in free space, it has to be in an object, Either that or I'm just not sure how to go about doing that.
I was also told it might be better to use a map of strings and vectors of shared pointers of type T_, instead of using the generic Object base class, this would clean up the type safety issue but I'm not really certain about the necessity of this.
Heres the current code:
Object.h
Code:
#ifndef OBJECT_H
#define OBJECT_H
#pragma warning(disable: 4786)
#pragma warning(disable: 64)
#include <vector>
#include <map>
#include <string>
#include <boost\shared_ptr.hpp>
#include <boost\weak_ptr.hpp>
#include <boost\smart_ptr.hpp>
#include <iostream>
#include <fstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/shared_ptr.hpp>
class Object
{
public:
Object(){}
virtual void Create()
{}
virtual void Access()
{}
virtual void Delete()
{delete this;}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version){};
};
class Object_Manager
{
public:
Object_Manager() {};
~Object_Manager() {};
typedef boost::shared_ptr<Object> Object_Ptr;
typedef boost::weak_ptr<Object> Object_Observer;
typedef std::map< std::string, Object_Ptr > Object_Map;
void Add_Object(const std::string & name, Object * pObject)
{
Object_Ptr Raw_Object(pObject);
mObjects.insert(std::make_pair(name, Raw_Object));
}
Object_Observer Request_Object(const std::string & name)
{
Object_Map::iterator it = mObjects.find(name);
if (it == mObjects.end())
{
std::cout << "Internal program error, " << name << " does not exist!" << std::endl;
}
else
{
return Object_Observer(it->second);
}
}
void Request_Object_Removal(const std::string & name)
{
Object_Map::iterator it = mObjects.find(name);
if (it != mObjects.end())
{
mObjects.erase(it);
}
}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & mObjects;
}
Object_Map mObjects;
};
#endif
Database.h
Code:
#ifndef DATABASE_H
#define DATABASE_H
#include "Object.h"
#include <map>
#include <iostream>
class Database
{
public:
typedef boost::shared_ptr<Object_Manager> Manager_Ptr;
typedef boost::weak_ptr<Object_Manager> Manager_Observer;
typedef std::map< std::string, Manager_Ptr > Manager_Map;
// Function to access a specific manager within the map
Manager_Observer Access_Manager(std::string Filename)
{
Manager_Map::iterator it = Database_Manager.find(Filename);
// check if the manager exists in the map
if (it == Database_Manager.end())
{
// if not throw an error
std::cout << "Manager does not exist!" << std::endl;
}
else
{
// if so return a pointer to the manager
return Manager_Observer(it->second);
}
}
//Save a manager completely to a file
void Save_to_File(std::string Filename, const Object_Manager Data)
{
std::ofstream ofs(Filename.c_str());
boost::archive::text_oarchive oa(ofs);
// write class instance to archive
oa << Data;
Data.~Object_Manager();
// archive and stream closed when destructors are called
}
// Load a manager from a file and add it to the list of managers
void Read_File(std::string Filename, Object_Manager * Data)
{
// create and open an archive for input
std::ifstream ifs(Filename.c_str(), std::ios::binary);
boost::archive::text_iarchive ia(ifs);
// read class state from archive
ia >> Data;
// create a pointer to the data
Manager_Ptr Raw_Manager(Data);
// pair the filename with the manager typ for easy access
Database_Manager.insert(std::make_pair(Filename, Raw_Manager));
// archive and stream closed when destructors are called
}
private:
Manager_Map Database_Manager;
};
#endif
Menu_Object.h
Code:
#ifndef MENU_H
#define MENU_H
#include "Object.h"
#include <string>
#include <list>
#include <boost/serialization/string.hpp>
#include <boost/serialization/vector.hpp>
class Menu : public Object
{
public:
Menu(){};
Menu(std::string mSelection)
{
mSelection = Selection;
}
virtual ~Menu() { Destroy(); }
// deletes self
void Release() { delete this; }
// call update on all children
virtual void Update()
{
for( std::list<Menu*>::iterator i = MenuChoices.begin();
i != MenuChoices.end(); i++ )
{
(*i)->Update();
}
}
// recursively destroy all children and self
void Destroy()
{
for( std::list<Menu*>::iterator i = MenuChoices.begin();
i != MenuChoices.end(); i++ )
(*i)->Release();
MenuChoices.clear();
}
// add a child
void MenuSelection( Menu* MenuSelection )
{
MenuSelection->SetRootMenu(this);
MenuChoices.push_back(MenuSelection);
}
// Set the parent of the child
void SetRootMenu(Menu* Root)
{
RootMenu = Root;
}
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
ar & boost::serialization::base_object<CObject>(*this);
ar & Selection;
ar & RootMenu;
ar & MenuChoices;
}
// list of children
std::list<Menu*> MenuChoices;
// pointer to parent
Menu * RootMenu;
std::string Selection;
};
#endif
Thats it so far, to test out everything all I need to do is make a utility class to build and save menu trees to an object manager. Anyone wanna help me do that? I'm not sure on the process of events I need in a function to create a massive tree object in one function.