New TA3D Config class.

Everything related to the code /
Tout ce qui touche au code
Post Reply
User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

New TA3D Config class.

Post by Cire » Fri Dec 15, 2006 6:19 pm

Here is the header for the finailzation of the new TA3D Config class, I dubbed this file 'TA3D_Config.h'

Code: Select all

/*
**  File: TA3D_Config.h
** Notes:
**   Cire: This legacy class should manage to allow one to store and retreive
**          variables.  I have added support for float, double, int(32)
**          bool and std::string to its class,  It works something similar to a map
**          and a vector allowing access to its keys via either int or name
**          by overloading the [] operator.
**
** WARNINGS: This class does NOT protect string data that contains '\n' within its
**          confines.  Should string data contain such a thing its possible that it
**          could corrupt the remaing of the file from being read correctly.
**
**     TODO: This probably should have strong checks in some areas that may prevent
**          some functions from throwing an exception when there are no keys.
*/
#pragma once

namespace TA3D
{
	namespace UTILS
	{
		class cConfig
		{
			// Each variable we store is placed in a key (m_key),
			//   however for the most part a key is kept private to our class
			//   with the exception that operators will return a pointer to it.
			typedef struct m_Key
			{
				String KeyName;
				String KeyValue;
				uint8  KeyValueType;

				m_Key()
				{
					KeyName = String( "" );
					KeyValue = String( "" );
					KeyValueType = 0; // uses TA3D::VARS:CONSTS:TA3D_VAR_TYPES
				}
			};

			private:
				// a few typedefs to make life easier.
			typedef std::vector< m_Key * > KeyList;
			typedef KeyList::iterator KeyItor;

			String		m_sConfigFile; // config file is set via constructor
			KeyList		m_Keys;        // vector of our variables.
			bool		m_Dirty;       // will be true if we changed any data, useful
			                           // so that we can save if data is dirty.

			// private functions, do NOT expose these to public or
			//   something bad could happen.
			m_Key *GetKey( const String &KeyName );
			m_Key *GetOrCreateKey( const String &KeyName );
		public:
			// constructor
			cConfig( const String &FileName );

			// deconstructor.
			~cConfig();

			// returns the number of keys we have.
			uint32 NumKeys() { return (uint32)m_Keys.size(); }

			// Erases a key.
			bool EraseKey( const String &name );

			// operator overloading for subscripting
			m_Key *operator [](int i);

			// this allows subscripting like a map, but unlike a map
			//   it will not create a key if it don't exists.
			m_Key *operator []( const std::string &Name);

			// various function to set a value of a key.
			void SetKey( const String &name, const real32 v );
			void SetKey( const String &name, const real64 v );
			void SetKey( const String &name, const sint32 v );
			void SetKey( const String &name, const bool v );
			void SetKey( const String &name, const String &v );

			// various functions to pull data from a key.  Note that you can
			//   pull data from a key in any fasion you want, thus a key with
			//   an inital setting value of 'float' can be pulled as 'int' or 
			//   'string', ect.
			real32 KeyValueFloat( const String &name );
			real64 KeyValueDouble( const String &name );
			sint32 KeyValueInt( const String &name );
			bool   KeyValueBool( const String &name );
			String KeyValueString( const String &name );

			// functions to save/read config files.
			bool SaveConfigFile();
			bool ReadConfigFile();
		}; // class cConfig
	} // namespace UTILS
} // namespace TA3D
Note that this requries also a enum to be added to TA3D_Namespace.h like so:

Code: Select all

			enum TA3D_VAR_TYPE
			{
				TA3D_VAR_TYPE_UNKNOWN   = 0,
				TA3D_VAR_TYPE_FLOAT		= 1,
				TA3D_VAR_TYPE_DOUBLE	= 2,
				TA3D_VAR_TYPE_INT		= 3,
				TA3D_VAR_TYPE_BOOL		= 4,
				TA3D_VAR_TYPE_STRING	= 5
			};
The cpp file will follow this post as soon as I finish commenting it. Note that the class can acutally be used in other areas that may need to do simple configuation or variable tracking.

I Included the above file into TA3D_Namespace.h file, and set a external variable in VARS namespace to g_Config which is a pointer to the above class, so that we have a global configuration class.

It requres some changes to 'ta3d.cpp' and 'menu.cpp'. which I will post later.

++Cire.

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 15, 2006 6:41 pm

And the .cpp file

Code: Select all

/*
**  File: TA3D_Config.cpp
** Notes:
**   Cire: See notes in TA3D_hpi.h
*/

#include "stdafx.h" // get our pch file
#include "TA3D_NameSpace.h" // and our namespace, TA3D_Config.h is pulled here as well.

using namespace std;
using namespace TA3D;
using namespace TA3D::UTILS;
using namespace TA3D::VARS;

// global Configuation class, constructed and destroyed in ta3d.cpp
TA3D::UTILS::cConfig *TA3D::VARS::g_Config;

// Constructor pretty much sets our config filename, and dirty to false.
cConfig::cConfig( const String &FileName ) : m_sConfigFile( FileName ) 
{ 
	m_Dirty = false; 
}

// Deconstructor
cConfig::~cConfig() 
{ 
	if( m_Dirty ) // if we are dirty save data.
		SaveConfigFile();

	// iterate through the keys and delete them
	for( KeyItor k_Position = m_Keys.begin(); k_Position != this->m_Keys.end(); k_Position++ )
		delete(*k_Position);

	// now purge the vector.
	m_Keys.clear();
}

// Function: GetKey (private)
//   Inputs: std::string
//    Notes: Returns a pointer to a key if found otherwize NULL
TA3D::UTILS::cConfig::m_Key *cConfig::GetKey( const String &KeyName )
{
	KeyItor k_Position;
	m_Key *Result = NULL;

	for( k_Position = this->m_Keys.begin(); k_Position != this->m_Keys.end(); k_Position++ )
	{
		if( (*k_Position)->KeyName == KeyName )
		{
			Result =(*k_Position);
			break;
		}
	}

	return Result;
}

// Function: GetOrCreateKey (private)
//   Inputs: std::string
//    Notes: Tries to find a key first, if its found that is returned otherwize
//           a New key is created, its name is assigned and that key is returned.
TA3D::UTILS::cConfig::m_Key *cConfig::GetOrCreateKey( const String &KeyName )
{
	KeyItor k_Position;
	m_Key *Result = GetKey( KeyName );

	if( Result == NULL )
	{
		Result = new m_Key;
		Result->KeyName = KeyName;
	}

	return Result;
}


// Function: EraseKey
//   Inputs: std::string
//    Notes: Erases a key if found, returns true or false depending if it was found and
//           erased.
bool cConfig::EraseKey( const String &name )
{
	KeyItor k_Position;
	String KeyName = Lowercase( name );
	bool Result = false;

	if( m_Keys.size() < 1 )
		return false;

	for( k_Position = m_Keys.begin(); k_Position != m_Keys.end(); k_Position++ )
	{
		if( (*k_Position)->KeyName == KeyName )
		{
			m_Dirty = true;

			delete( *k_Position );

			m_Keys.erase( k_Position );

			Result = true;
			break;
		}
	}

	return Result;
}

// Function: SetKey
//   Inputs: std::string, float
//    Notes: Sets a keys value and type to that of a float
void cConfig::SetKey( const String &name, const real32 v ) // float
{
	std::stringstream s;
	m_Key *Key = GetOrCreateKey( Lowercase( name ) );

	s<<v;
	Key->KeyValue=s.str();
	Key->KeyValueType = TA3D::VARS::CONSTANTS::TA3D_VAR_TYPE_FLOAT;
	m_Dirty = true;
}

// Function: SetKey
//   Inputs: std::string, double
//    Notes: Sets a keys value and type to that of a double
void cConfig::SetKey( const String &name, const real64 v ) // double
{
	std::stringstream s;
	m_Key *Key = GetOrCreateKey( Lowercase( name ) );

	s<<v;
	Key->KeyValue=s.str();
	Key->KeyValueType = TA3D::VARS::CONSTANTS::TA3D_VAR_TYPE_DOUBLE;
	m_Dirty = true;
}

// Function: SetKey
//   Inputs: std::string, bool
//    Notes: Sets a keys value and type to that of a boolean
void cConfig::SetKey( const String &name, const bool v ) // bool
{
	std::stringstream s;
	m_Key *Key = GetOrCreateKey( Lowercase( name ) );

	s<<( (v) ? "true" : "false" );
	Key->KeyValue=s.str();
	Key->KeyValueType = TA3D::VARS::CONSTANTS::TA3D_VAR_TYPE_BOOL;

	m_Dirty = true;
}

// Function: SetKey
//   Inputs: std::string, int
//    Notes: Sets a keys value and type to that of a signed int 4 byte
void cConfig::SetKey( const String &name, const sint32 v ) // signed int 32
{
	std::stringstream s;
	m_Key *Key = GetOrCreateKey( Lowercase( name ) );

	s<<v;
	Key->KeyValue=s.str();
	Key->KeyValueType = TA3D::VARS::CONSTANTS::TA3D_VAR_TYPE_INT;

	m_Dirty = true;
}

// Function: SetKey
//   Inputs: std::string, std::string
//    Notes: Sets a keys value and type to that of a std::string
void cConfig::SetKey( const String &name, const String &v ) // string
{
	m_Key *Key = GetOrCreateKey( Lowercase( name ) );

	Key->KeyValue=String( v );
	Key->KeyValueType = TA3D::VARS::CONSTANTS::TA3D_VAR_TYPE_STRING;

	m_Dirty = true;
}

// Function: KeyValueFloat
//   Inputs: std::string
//    Notes: Pulls a keys value in float format
real32 cConfig::KeyValueFloat( const String &name )
{
	m_Key *Key = GetKey( Lowercase( name ) );

	return ( (Key==NULL) ? 0.0f : (float)atof( Key->KeyValue.c_str() ) );
}

// Function: KeyValueFloat
//   Inputs: std::string
//    Notes: Pulls a keys value in double format
real64 cConfig::KeyValueDouble( const String &name )
{
	m_Key *Key = GetKey( Lowercase( name ) );

	return ( (Key==NULL) ? (double)0.0 : (double)atof( Key->KeyValue.c_str() ) );
}

// Function: KeyValueFloat
//   Inputs: std::string
//    Notes: Pulls a keys value in int format
sint32 cConfig::KeyValueInt( const String &name )
{
	m_Key *Key = GetKey( Lowercase( name ) );

	return ( (Key==NULL) ? 0 : (sint32)atoi( Key->KeyValue.c_str() ) );
}

// Function: KeyValueFloat
//   Inputs: std::string
//    Notes: Pulls a keys value in bool
bool cConfig::KeyValueBool( const String &name )
{
	m_Key *Key = GetKey( Lowercase( name ) );

	return ( (Key==NULL) ? false : Key->KeyValue=="true" );
}

// Function: KeyValueFloat
//   Inputs: std::string
//    Notes: Pulls a keys value in string format
String cConfig::KeyValueString( const String &name )
{
	m_Key *Key = GetKey( Lowercase( name ) );

	return ( (Key==NULL) ? "" : Key->KeyValue );
}

// Function: ReadConfigFile
//   Inputs: 
//    Notes: Reads configuration settings if found.
bool cConfig::ReadConfigFile()
{
	std::ifstream file( m_sConfigFile.c_str(), ios::in );

	if( !file.is_open() ) return false;

	String line, name, value1, value2, tmp;
	int posEqual;
	uint8 valueType;

	while ( !file.eof() )
	{
		std::getline( file, line, '\n' );

		if( !line.length() ) continue;
		if (line[0] == '#' || line[0] == ';' ) continue;

		if( (posEqual=(int)line.find( '=' )) != string::npos )
		{
			name  = TrimString( line.substr( 0,posEqual ) );

			tmp = TrimString( line.substr( posEqual+1 ) );
			if( (posEqual=(int)line.find( ',' )) != string::npos )
			{
				value1 = TrimString( line.substr( 0,posEqual ) );
				value2 = TrimString( line.substr( posEqual+1 ) );

				valueType = (uint8)atoi( value1.c_str() );

				m_Key *Key=GetOrCreateKey( Lowercase( name ) );

				Key->KeyValue = String( value2 );
				Key->KeyValueType = valueType;
			}
		}
	}

	m_Dirty = false;

	file.close();

	return true;
}

// Function: SaveConfigFile
//   Inputs: 
//    Notes: Saves configuration settings.
bool cConfig::SaveConfigFile()
{
	if( !m_Dirty ) return true;

	std::ofstream file( m_sConfigFile.c_str(), ios::out | ios::trunc );

	if( !file.is_open() ) return false;

	KeyItor k_Position;

	for( k_Position = m_Keys.begin(); k_Position != m_Keys.end(); k_Position++ )
		file << (*k_Position)->KeyName << "=" << 
				(*k_Position)->KeyValueType << "," <<
		        (*k_Position)->KeyValue << "\n";

	m_Dirty = false;

	file.close();

	return true;
}

// Function: operator [] 
//   Inputs: int
//    Notes: allows access to a key via subscript int, retunrs a pointer to
//           m_Key structur if found, otherwize NULL;
TA3D::UTILS::cConfig::m_Key *cConfig::operator [](int i) {
	if( i < 0 || m_Keys.size() == 0 || i > m_Keys.size() )
		return NULL;

	return m_Keys[ i ]; 
}

// Function: operator [] 
//   Inputs: std::string
//    Notes: allows access to a key via subscript by string. Returns a 
//           m_Key structure if found, otherwize NULL;
TA3D::UTILS::cConfig::m_Key *cConfig::operator []( const std::string &Name) { 
	return GetKey( Lowercase( Name ) );
}

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 15, 2006 7:32 pm

Zuff, for me to fully implmeent the above config class I need to know what the config variables are, manly the values that they should contain.

g_Config = new TA3D::UTILS::cConfig( "ta3d.cfg" );
if( !g_Config->ReadConfigFile() )
{
g_Config->KeyValueBool("showfps", true );
g_Config->KeyValueBool("fps_limit", false );
g_Config->KeyValueBool("wireframe", true );
g_Config->KeyValueBool("particle", true );
g_Config->KeyValueBool("trees", true );
g_Config->KeyValueBool("shadow", true );
g_Config->KeyValueBool("shadow_quality", false );
g_Config->KeyValueBool("shadow_r", false );
g_Config->KeyValueBool("priority_level", false );
g_Config->KeyValueBool("timefactor", false );
g_Config->KeyValueBool("screen_width", false );
g_Config->KeyValueBool("screen_height", false );
g_Config->KeyValueBool("fullscreen", true );
g_Config->KeyValueBool("fsaa", false );
g_Config->KeyValueBool("water_quality", false );
g_Config->KeyValueInt("LANG", LANG);
g_Config->KeyValueInt("height_line", 0 );
}
These are how I set them I probably got them wrong, can you provide correct 'values types.

++Cire.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 15, 2006 8:00 pm

correct values types are:
showfps -> bool
fps_limit -> int
wireframe -> bool
particle -> bool
trees -> bool
shadow -> bool
shadow_quality -> int
shadow_r -> float
priority_level -> int
timefactor -> float
screen_width -> int
screen_height -> int
fullscreen -> bool
fsaa -> int
water_quality -> int
LANG -> int
height_line -> bool
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Fri Dec 15, 2006 8:08 pm

What are the ranges on the int/floats, the defaults would also be nice since i modifed the code already and don't know what to 'default' them too.

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Fri Dec 15, 2006 8:23 pm

showfps -> false
fps_limit -> float (sorry there was a mistake), -1.0f (-1.0f or >0.0f)
wireframe -> false
particle -> true
trees -> true
shadow -> false
shadow_quality -> 1 (>=1)
shadow_r -> 0.02f (>=0.0f)
priority_level -> 0 (0,1 or 2)
timefactor -> 1.0f (>=0.0f)
screen_width -> 640
screen_height -> 480
fullscreen -> false
fsaa -> 0 (depends on hardware)
water_quality -> 0 (0,1,2 or 3)
LANG -> TA3D_LANG_ENGLISH (depends on how many languages are supported)
height_line -> true
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Sat Dec 16, 2006 1:58 am

I added this function which is called from within the configuration menu and when loading config files from ta3d.cpp, which should make sure values are within correct ranges.

If these are incorrect values let me know right away

Code: Select all

void AssertTA3DConfigValues()
{
	if( g_Config->KeyValueFloat( "fps_limit" ) < -1.0f )
		g_Config->SetKey( "fps_limit", -1.0f );
	else if( g_Config->KeyValueFloat( "fps_limit" ) > 0.0f )
		g_Config->SetKey( "fps_limit", 0.0f );

	if( g_Config->KeyValueFloat( "shadow_quality" ) < 1.0f )
		g_Config->SetKey( "shadow_quality", 1.0f );
	else if( g_Config->KeyValueFloat( "fps_limit" ) > 12.0f )
		g_Config->SetKey( "shadow_quality", 12.0f );

	if( g_Config->KeyValueFloat( "shadow_r" ) < 0.0f )
		g_Config->SetKey( "shadow_r", 0.0f );
	else if( g_Config->KeyValueFloat( "shadow_r" ) > 100.0f )
		g_Config->SetKey( "shadow_r", 100.0f );

	if( g_Config->KeyValueInt( "priority_level" ) < 0 )
		g_Config->SetKey( "priority_level", 0 );
	else if( g_Config->KeyValueInt( "priority_level" ) > 2 )
		g_Config->SetKey( "priority_level", 2 );

	if( g_Config->KeyValueFloat( "timefactor" ) < 1.0f )
		g_Config->SetKey( "timefactor", 1.0f );
	else if( g_Config->KeyValueFloat( "timefactor" ) > 10.0f )
		g_Config->SetKey( "timefactor", 10.0f );

	if( g_Config->KeyValueInt( "water_quality" ) < 0 )
		g_Config->SetKey( "water_quality", 0 );
	else if( g_Config->KeyValueInt( "water_quality" ) > 3 )
		g_Config->SetKey( "water_quality", 3 );
}

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sat Dec 16, 2006 10:29 am

shadow_quality isn't float, fps_limit should be greater than 0!! (can you play with 0 fps??)

Code: Select all

mistake -> else if( g_Config->KeyValueFloat( "fps_limit" ) > 12.0f )
should be -> else if( g_Config->KeyValueInt( "shadow_quality" ) > 12.0f )
      g_Config->SetKey( "shadow_quality", 12.0f ); 
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Sat Dec 16, 2006 2:56 pm

better?

Code: Select all

void AssertTA3DConfigValues()
{
	if( g_Config->KeyValueFloat( "fps_limit" ) != 0.0f && g_Config->KeyValueFloat( "fps_limit" ) < 12.0f )
		g_Config->SetKey( "fps_limit", 12.0f );
	else if( g_Config->KeyValueFloat( "fps_limit" ) > 12.0f )
		g_Config->SetKey( "fps_limit", 12.0f );

	if( g_Config->KeyValueInt( "shadow_quality" ) < 1 )
		g_Config->SetKey( "shadow_quality", 1 );
	else if( g_Config->KeyValueInt( "shadow_quality" ) > 100 )
		g_Config->SetKey( "shadow_quality", 100 );

	if( g_Config->KeyValueFloat( "shadow_r" ) < 0.0f )
		g_Config->SetKey( "shadow_r", 0.0f );
	else if( g_Config->KeyValueFloat( "shadow_r" ) > 100.0f )
		g_Config->SetKey( "shadow_r", 100.0f );

	if( g_Config->KeyValueInt( "priority_level" ) < 0 )
		g_Config->SetKey( "priority_level", 0 );
	else if( g_Config->KeyValueInt( "priority_level" ) > 2 )
		g_Config->SetKey( "priority_level", 2 );

	if( g_Config->KeyValueFloat( "timefactor" ) < 1.0f )
		g_Config->SetKey( "timefactor", 1.0f );
	else if( g_Config->KeyValueFloat( "timefactor" ) > 10.0f )
		g_Config->SetKey( "timefactor", 10.0f );

	if( g_Config->KeyValueInt( "water_quality" ) < 0 )
		g_Config->SetKey( "water_quality", 0 );
	else if( g_Config->KeyValueInt( "water_quality" ) > 3 )
		g_Config->SetKey( "water_quality", 3 );
}

User avatar
zuzuf
Administrateur - Site Admin
Posts: 3281
Joined: Mon Oct 30, 2006 8:49 pm
Location: Toulouse, France
Contact:

Post by zuzuf » Sat Dec 16, 2006 4:35 pm

yes, but there is still a mistake:
fps_limit should be -1.0f (no limit) or greater than 25.0f (fps limited to fps_limit)
=>;-D Penguin Powered

User avatar
Cire
Moderator
Posts: 350
Joined: Tue Oct 31, 2006 5:59 pm
Location: Somewhere on Earth

Post by Cire » Sat Dec 16, 2006 4:45 pm

Ok i've made the change and debugged the code, there was a mistake in the class, which forgot to push new keys onto the vector, lol.

Anyhow you will need to make sure once i send you this new code that old config files are 'deleted' since this new one writes an extra value to the config file.

The new format looks like...
showfps=4,false
wireframe=4,false
particle=4,true
trees=4,true
shadow=4,false
fullscreen=4,false
height_line=4,true
lang=3,0
shadow_quality=3,1
priority_level=3,0
screen_width=3,640
screen_height=3,480
fsaa=3,0
water_quality=3,0
fps_limit=1,1
shadow_r=1,0.02
timefactor=1,1

Note that first # before the actual value which denotes the 'type' of variable. This class could probably be expanded to keep notes and write them as remarks, but I don't think we really need it. It will ignore lines starting with ; and # so comments can be added by hand if you want.

Keep in mind however platform returns, this uses '\n' not '\r\n' to find end lines, if extra '\r' are found could be in trouble as would be left in the buffer and applied to next var name which would corrupt the config files, just like \n stored on 'string' values.

You coudl use something else for getline to find to trigger the end, but if u use something non standard then you risk not being able to edit it via a text editor.

Empty lines are also ignored. My suggestion would be to make sure that when you pack it up for distrubution to make sure that you do NOT include a ta3d.cfg, and let each platform write it out to its own standards. If you really wana leave comments on how or what ranges are possible you might doc it in a README or somehting.

++Cire.

Post Reply

Who is online

Users browsing this forum: No registered users and 32 guests