Improve error handling in XML classes (namely, atoi must die) since I was bitten several times now by insufficient error handling. Also set up base architecture to support the new gfx mode 'my kart is animated but not Ai karts', though it doesn't work atm for the simple reason that at the time the model node is created we do not yet know if the kart is player or AI...

git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@7432 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
auria 2011-01-16 00:06:59 +00:00
parent 8d05042376
commit 24d0d549ba
14 changed files with 171 additions and 45 deletions

View File

@ -69,10 +69,10 @@ void STKConfig::load(const std::string &filename)
catch(std::exception& err) catch(std::exception& err)
{ {
fprintf(stderr, "Error while parsing KartProperties '%s':\n", fprintf(stderr, "FATAL ERROR while reading StkConfig '%s':\n", filename.c_str());
filename.c_str()); fprintf(stderr, " %s", err.what());
fprintf(stderr, "%s", err.what());
fprintf(stderr, "\n"); fprintf(stderr, "\n");
exit(1);
} }
delete root; delete root;

View File

@ -423,7 +423,7 @@ void UserConfig::addDefaultPlayer()
class GuestPlayerProfile : public PlayerProfile class GuestPlayerProfile : public PlayerProfile
{ {
public: public:
GuestPlayerProfile() : PlayerProfile(_("Guest")) GuestPlayerProfile() : PlayerProfile(L"Guest")
{ {
m_is_guest_account = true; m_is_guest_account = true;
} }

View File

@ -204,6 +204,9 @@ public:
float& operator=(const FloatUserConfigParam& v) { m_value = (float)v; return m_value; } float& operator=(const FloatUserConfigParam& v) { m_value = (float)v; return m_value; }
}; };
const int ANIMS_NONE = 0;
const int ANIMS_PLAYERS_ONLY = 1;
const int ANIMS_ALL = 2;
/** /**
* Using X-macros for setting-possible values is not very pretty, but it's a no-maintenance case : * Using X-macros for setting-possible values is not very pretty, but it's a no-maintenance case :
@ -276,8 +279,10 @@ namespace UserConfigParams
PARAM_PREFIX BoolUserConfigParam m_weather_effects PARAM_PREFIX BoolUserConfigParam m_weather_effects
PARAM_DEFAULT( BoolUserConfigParam(true, "weather_gfx", &m_video_group) ); PARAM_DEFAULT( BoolUserConfigParam(true, "weather_gfx", &m_video_group) );
PARAM_PREFIX BoolUserConfigParam m_show_steering_animations PARAM_PREFIX IntUserConfigParam m_show_steering_animations
PARAM_DEFAULT( BoolUserConfigParam(true, "steering_animations", &m_video_group, "Display steering animations in race") ); PARAM_DEFAULT( IntUserConfigParam(ANIMS_ALL, "steering_animations", &m_video_group,
"Whether to display kart animations (0=disabled for all; "
"1=disabled for humans, disabled for AIs; 2=enabled for all") );
PARAM_PREFIX BoolUserConfigParam m_display_fps PARAM_PREFIX BoolUserConfigParam m_display_fps
PARAM_DEFAULT( BoolUserConfigParam(false, "show_fps", &m_video_group, "Display frame per seconds") ); PARAM_DEFAULT( BoolUserConfigParam(false, "show_fps", &m_video_group, "Display frame per seconds") );
@ -326,6 +331,7 @@ namespace UserConfigParams
PARAM_DEFAULT( IntUserConfigParam(2305, "server_port", "Information about last server used") ); PARAM_DEFAULT( IntUserConfigParam(2305, "server_port", "Information about last server used") );
// ---- Graphic Quality // ---- Graphic Quality
// FIXME: those are probably not needed...
PARAM_PREFIX GroupUserConfigParam m_graphics_quality PARAM_PREFIX GroupUserConfigParam m_graphics_quality
PARAM_DEFAULT( GroupUserConfigParam("GFX", "Graphics Quality Settings") ); PARAM_DEFAULT( GroupUserConfigParam("GFX", "Graphics Quality Settings") );
@ -334,7 +340,7 @@ namespace UserConfigParams
"Whether anisotropic filtering is allowed to be used (true or false)") ); "Whether anisotropic filtering is allowed to be used (true or false)") );
PARAM_PREFIX BoolUserConfigParam m_trilinear PARAM_PREFIX BoolUserConfigParam m_trilinear
PARAM_DEFAULT( BoolUserConfigParam(true, "trilinear", &m_graphics_quality, PARAM_DEFAULT( BoolUserConfigParam(true, "trilinear", &m_graphics_quality,
"Whether trilinear filtering is allowed to be used (true or false)") ); "Whether trilinear filtering is allowed to be used (true or false)") );
// ---- Misc // ---- Misc

View File

@ -231,11 +231,16 @@ io::IXMLReader *FileManager::createXMLReader(const std::string &filename)
*/ */
XMLNode *FileManager::createXMLTree(const std::string &filename) XMLNode *FileManager::createXMLTree(const std::string &filename)
{ {
io::IXMLReader *xml_reader = createXMLReader(filename); try
if(!xml_reader) return NULL; {
XMLNode* node = new XMLNode(xml_reader); XMLNode* node = new XMLNode(filename);
xml_reader->drop(); return node;
return node; }
catch (std::runtime_error& e)
{
fprintf(stderr, "[FileManager::createXMLTree] %s\n", e.what());
return NULL;
}
} // getXMLTree } // getXMLTree
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -22,8 +22,12 @@
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/vec3.hpp" #include "utils/vec3.hpp"
#include <stdexcept>
XMLNode::XMLNode(io::IXMLReader *xml) XMLNode::XMLNode(io::IXMLReader *xml)
{ {
m_file_name = "[unknown]";
while(xml->getNodeType()!=io::EXN_ELEMENT && xml->read()); while(xml->getNodeType()!=io::EXN_ELEMENT && xml->read());
readXML(xml); readXML(xml);
} // XMLNode } // XMLNode
@ -34,7 +38,15 @@ XMLNode::XMLNode(io::IXMLReader *xml)
*/ */
XMLNode::XMLNode(const std::string &filename) XMLNode::XMLNode(const std::string &filename)
{ {
m_file_name = filename;
io::IXMLReader *xml = file_manager->createXMLReader(filename); io::IXMLReader *xml = file_manager->createXMLReader(filename);
if (xml == NULL)
{
throw std::runtime_error("Cannot find file "+filename);
}
bool is_first_element = true; bool is_first_element = true;
while(xml->read()) while(xml->read())
{ {
@ -98,7 +110,9 @@ void XMLNode::readXML(io::IXMLReader *xml)
switch (xml->getNodeType()) switch (xml->getNodeType())
{ {
case io::EXN_ELEMENT: case io::EXN_ELEMENT:
m_nodes.push_back(new XMLNode(xml)); XMLNode* n = new XMLNode(xml);
n->m_file_name = m_file_name;
m_nodes.push_back(n);
break; break;
case io::EXN_ELEMENT_END: case io::EXN_ELEMENT_END:
// End of this element found. // End of this element found.
@ -255,9 +269,14 @@ int XMLNode::get(const std::string &attribute, int *value) const
{ {
std::string s; std::string s;
if(!get(attribute, &s)) return 0; if(!get(attribute, &s)) return 0;
// FIXME: don't use "atoi", if the number in the attribute is not an int we want an error message,
// not silently return 0... easy to get bitten by this if (!StringUtils::parseString<int>(s, value))
*value = atoi(s.c_str()); {
fprintf(stderr, "[XMLNode] WARNING: Expected int but found '%s' for attribute '%s' of node '%s' in file %s\n",
s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str());
return 0;
}
return 1; return 1;
} // get(int) } // get(int)
@ -266,7 +285,14 @@ int XMLNode::get(const std::string &attribute, unsigned int *value) const
{ {
std::string s; std::string s;
if(!get(attribute, &s)) return 0; if(!get(attribute, &s)) return 0;
*value = atoi(s.c_str());
if (!StringUtils::parseString<unsigned int>(s, value))
{
fprintf(stderr, "[XMLNode] WARNING: Expected uint but found '%s' for attribute '%s' of node '%s' in file %s\n",
s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str());
return 0;
}
return 1; return 1;
} // get(unsigned int) } // get(unsigned int)
@ -275,7 +301,14 @@ int XMLNode::get(const std::string &attribute, float *value) const
{ {
std::string s; std::string s;
if(!get(attribute, &s)) return 0; if(!get(attribute, &s)) return 0;
*value = (float)atof(s.c_str());
if (!StringUtils::parseString<float>(s, value))
{
fprintf(stderr, "[XMLNode] WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s\n",
s.c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str());
return 0;
}
return 1; return 1;
} // get(int) } // get(int)
@ -323,9 +356,19 @@ int XMLNode::get(const std::string &attribute,
std::vector<std::string> v = StringUtils::split(s,' '); std::vector<std::string> v = StringUtils::split(s,' ');
value->clear(); value->clear();
for(unsigned int i=0; i<v.size(); i++)
const unsigned int count = v.size();
for (unsigned int i=0; i<count; i++)
{ {
value->push_back((float)atof(v[i].c_str())); float curr;
if (!StringUtils::parseString<float>(v[i], &curr))
{
fprintf(stderr, "[XMLNode] WARNING: Expected float but found '%s' for attribute '%s' of node '%s' in file %s\n",
v[i].c_str(), attribute.c_str(), m_name.c_str(), m_file_name.c_str());
return 0;
}
value->push_back(curr);
} }
return value->size(); return value->size();
} // get(vector<float>) } // get(vector<float>)
@ -344,9 +387,19 @@ int XMLNode::get(const std::string &attribute, std::vector<int> *value) const
std::vector<std::string> v = StringUtils::split(s,' '); std::vector<std::string> v = StringUtils::split(s,' ');
value->clear(); value->clear();
for(unsigned int i=0; i<v.size(); i++)
const unsigned int count = v.size();
for (unsigned int i=0; i<count; i++)
{ {
value->push_back(atoi(v[i].c_str())); int val;
if (!StringUtils::parseString<int>(v[i], &val))
{
fprintf(stderr, "[XMLNode] WARNING: Expected int but found '%s' for attribute '%s' of node '%s'\n",
v[i].c_str(), attribute.c_str(), m_name.c_str());
return 0;
}
value->push_back(val);
} }
return value->size(); return value->size();
} // get(vector<int>) } // get(vector<int>)

View File

@ -43,10 +43,17 @@ private:
std::map<std::string, core::stringw> m_attributes; std::map<std::string, core::stringw> m_attributes;
/** List of all sub nodes. */ /** List of all sub nodes. */
std::vector<XMLNode *> m_nodes; std::vector<XMLNode *> m_nodes;
void readXML(io::IXMLReader *xml); void readXML(io::IXMLReader *xml);
std::string m_file_name;
public: public:
XMLNode(io::IXMLReader *xml); XMLNode(io::IXMLReader *xml);
/** \throw runtime_error if the file is not found */
XMLNode(const std::string &filename); XMLNode(const std::string &filename);
~XMLNode(); ~XMLNode();
const std::string &getName() const {return m_name; } const std::string &getName() const {return m_name; }
const XMLNode *getNode(const std::string &name) const; const XMLNode *getNode(const std::string &name) const;

View File

@ -71,9 +71,10 @@ Kart::Kart (const std::string& ident, int position,
#if defined(WIN32) && !defined(__CYGWIN__) #if defined(WIN32) && !defined(__CYGWIN__)
# pragma warning(1:4355) # pragma warning(1:4355)
#endif #endif
{ {
m_kart_properties = kart_properties_manager->getKart(ident); m_kart_properties = kart_properties_manager->getKart(ident);
assert(m_kart_properties != NULL); assert(m_kart_properties != NULL);
// We have to take a copy of the kart model, since otherwise // We have to take a copy of the kart model, since otherwise
// the animations will be mixed up (i.e. different instances of // the animations will be mixed up (i.e. different instances of
// the same model will set different animation frames). // the same model will set different animation frames).
@ -110,6 +111,8 @@ Kart::Kart (const std::string& ident, int position,
m_speed = 0.0f; m_speed = 0.0f;
m_wheel_rotation = 0; m_wheel_rotation = 0;
m_kart_model->setKart(this);
// Create SFXBase for each custom sound (TODO: add back when properly done) // Create SFXBase for each custom sound (TODO: add back when properly done)
/* /*
for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++) for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++)

View File

@ -24,6 +24,7 @@
#include "graphics/irr_driver.hpp" #include "graphics/irr_driver.hpp"
#include "graphics/mesh_tools.hpp" #include "graphics/mesh_tools.hpp"
#include "io/xml_node.hpp" #include "io/xml_node.hpp"
#include "karts/kart.hpp"
#include "utils/constants.hpp" #include "utils/constants.hpp"
float KartModel::UNDEFINED = -99.9f; float KartModel::UNDEFINED = -99.9f;
@ -55,7 +56,8 @@ float KartModel::UNDEFINED = -99.9f;
KartModel::KartModel(bool is_master) KartModel::KartModel(bool is_master)
{ {
m_is_master = is_master; m_is_master = is_master;
m_kart = NULL;
for(unsigned int i=0; i<4; i++) for(unsigned int i=0; i<4; i++)
{ {
m_wheel_graphics_position[i] = Vec3(UNDEFINED); m_wheel_graphics_position[i] = Vec3(UNDEFINED);
@ -188,7 +190,21 @@ KartModel* KartModel::makeCopy()
void KartModel::attachModel(scene::ISceneNode **node) void KartModel::attachModel(scene::ISceneNode **node)
{ {
assert(!m_is_master); assert(!m_is_master);
if(UserConfigParams::m_show_steering_animations)
bool animations = true;
const int anims = UserConfigParams::m_show_steering_animations;
if (anims == ANIMS_NONE)
{
animations = false;
}
else if (anims == ANIMS_PLAYERS_ONLY && m_kart != NULL && m_kart->getController() != NULL &&
!m_kart->getController()->isPlayerController())
{
animations = false;
}
if (animations)
{ {
*node = irr_driver->addAnimatedMesh(m_mesh); *node = irr_driver->addAnimatedMesh(m_mesh);
m_animated_node = static_cast<scene::IAnimatedMeshSceneNode*>(*node); m_animated_node = static_cast<scene::IAnimatedMeshSceneNode*>(*node);
@ -202,6 +218,7 @@ void KartModel::attachModel(scene::ISceneNode **node)
int straight_frame = m_animation_frame[AF_STRAIGHT]>=0 int straight_frame = m_animation_frame[AF_STRAIGHT]>=0
? m_animation_frame[AF_STRAIGHT] ? m_animation_frame[AF_STRAIGHT]
: 0; : 0;
printf("straight_frame = %i\n", straight_frame);
*node = irr_driver->addMesh(m_mesh->getMesh(straight_frame)); *node = irr_driver->addMesh(m_mesh->getMesh(straight_frame));
} }
#ifdef DEBUG #ifdef DEBUG
@ -239,7 +256,10 @@ bool KartModel::loadModels(const KartProperties &kart_properties)
} }
else else
{ {
if (!UserConfigParams::m_show_steering_animations) const int anims = UserConfigParams::m_show_steering_animations;
if (anims == ANIMS_NONE ||
(anims == ANIMS_PLAYERS_ONLY && m_kart != NULL && m_kart->getController() != NULL &&
!m_kart->getController()->isPlayerController()))
{ {
m_mesh->setHardwareMappingHint(scene::EHM_STATIC); m_mesh->setHardwareMappingHint(scene::EHM_STATIC);
} }
@ -352,8 +372,11 @@ void KartModel::setDefaultPhysicsPosition(const Vec3 &center_shift,
*/ */
void KartModel::setAnimation(AnimationFrameType type) void KartModel::setAnimation(AnimationFrameType type)
{ {
if(!UserConfigParams::m_show_steering_animations) return; const int anims = UserConfigParams::m_show_steering_animations;
if (anims == ANIMS_NONE) return;
if (m_kart != NULL && anims == ANIMS_PLAYERS_ONLY&& m_kart->getController() != NULL &&
!m_kart->getController()->isPlayerController()) return;
m_current_animation = type; m_current_animation = type;
if(m_current_animation==AF_DEFAULT) if(m_current_animation==AF_DEFAULT)
{ {
@ -472,7 +495,10 @@ void KartModel::update(float rotation, float steer, const float suspension[4])
if(m_animation_frame[AF_LEFT]<0) return; // no animations defined if(m_animation_frame[AF_LEFT]<0) return; // no animations defined
if(!UserConfigParams::m_show_steering_animations) return; const int anims = UserConfigParams::m_show_steering_animations;
if (anims == ANIMS_NONE) return;
if (m_kart != NULL && anims == ANIMS_PLAYERS_ONLY && m_kart->getController() != NULL &&
!m_kart->getController()->isPlayerController()) return;
// Update animation if necessary // Update animation if necessary
// ----------------------------- // -----------------------------

View File

@ -28,6 +28,7 @@ using namespace irr;
#include "utils/no_copy.hpp" #include "utils/no_copy.hpp"
#include "utils/vec3.hpp" #include "utils/vec3.hpp"
class Kart;
class KartProperties; class KartProperties;
class XMLNode; class XMLNode;
@ -130,6 +131,8 @@ private:
void OnAnimationEnd(scene::IAnimatedMeshSceneNode *node); void OnAnimationEnd(scene::IAnimatedMeshSceneNode *node);
Kart* m_kart;
public: public:
KartModel(bool is_master); KartModel(bool is_master);
~KartModel(); ~KartModel();
@ -175,5 +178,8 @@ public:
/** Enables- or disables the end animation. */ /** Enables- or disables the end animation. */
void setAnimation(AnimationFrameType type); void setAnimation(AnimationFrameType type);
/** Sets the kart this model is currently used for */
void setKart(Kart* k) { m_kart = k; }
}; // KartModel }; // KartModel
#endif #endif

View File

@ -416,11 +416,14 @@ void KartProperties::getAllData(const XMLNode * root)
plunger_node->get("in-face-time", &v); plunger_node->get("in-face-time", &v);
if(v.size()!=3) if(v.size()!=3)
{ {
printf("Invalid plunger in-face-time specification."); fprintf(stderr, "[KartProperties] ERROR: Invalid plunger in-face-time specification.");
}
else
{
m_plunger_in_face_duration[0] = v[0];
m_plunger_in_face_duration[1] = v[1];
m_plunger_in_face_duration[2] = v[2];
} }
m_plunger_in_face_duration[0] = v[0];
m_plunger_in_face_duration[1] = v[1];
m_plunger_in_face_duration[2] = v[2];
} }
if(const XMLNode *zipper_node= root->getNode("zipper")) if(const XMLNode *zipper_node= root->getNode("zipper"))

View File

@ -242,7 +242,7 @@ void cmdLineHelp (char* invocation)
" (Default: 0, OpenGL: 1, Direct3D9: 2, \n" " (Default: 0, OpenGL: 1, Direct3D9: 2, \n"
" Direct3D8: 3, Software: 4, \n" " Direct3D8: 3, Software: 4, \n"
" Burning's Software: 5, Null device: 6).\n" " Burning's Software: 5, Null device: 6).\n"
" --animations=n Play karts' animations (Enable: 1, Disable: 0).\n" " --animations=n Play karts' animations (Enable for All : 2, Enable for humans only: 1, Disable for all: 0).\n"
" --gfx=n Play other graphical effects like impact stars dance,\n" " --gfx=n Play other graphical effects like impact stars dance,\n"
" water animations or explosions (Enable: 1, Disable: 0).\n" " water animations or explosions (Enable: 1, Disable: 0).\n"
" --weather=n Show weather effects like rain or snow (0 or 1 as --gfx).\n" " --weather=n Show weather effects like rain or snow (0 or 1 as --gfx).\n"
@ -482,14 +482,7 @@ int handleCmdLine(int argc, char **argv)
} }
else if ( sscanf(argv[i], "--animations=%d", &n) ) else if ( sscanf(argv[i], "--animations=%d", &n) )
{ {
if (n) UserConfigParams::m_show_steering_animations = n;
{
UserConfigParams::m_show_steering_animations = true;
}
else
{
UserConfigParams::m_show_steering_animations = false;
}
} }
else if( (!strcmp(argv[i], "--kart") && i+1<argc )) else if( (!strcmp(argv[i], "--kart") && i+1<argc ))
{ {
@ -724,6 +717,10 @@ int handleCmdLine(int argc, char **argv)
void initUserConfig(char *argv[]) void initUserConfig(char *argv[])
{ {
file_manager = new FileManager(argv); file_manager = new FileManager(argv);
// FIXME: in which order do we call those? -.-
// the translation manager needs the user config to know if a language preference is set
// the user config needs the translation to translate "Guest"
user_config = new UserConfig(); // needs file_manager user_config = new UserConfig(); // needs file_manager
if (UserConfigParams::m_language.toString() != "system") if (UserConfigParams::m_language.toString() != "system")

View File

@ -198,7 +198,7 @@ Kart *World::createKart(const std::string &kart_ident, int index,
case RaceManager::KT_LEADER: case RaceManager::KT_LEADER:
break; break;
} }
new_kart->setController(controller);
return new_kart; return new_kart;
} // createKart } // createKart

View File

@ -43,7 +43,7 @@ DEFINE_SCREEN_SINGLETON( OptionsScreenVideo );
// Look-up table for GFX levels // Look-up table for GFX levels
const bool GFX [] = {false, true, true, true}; const bool GFX [] = {false, true, true, true};
const bool GFX_ANIM_KARTS[] = {false, false, true, true}; const int GFX_ANIM_KARTS[] = {0, 0, 2, 2 }; // TODO: use new limited anims mode
const bool GFX_WEATHER [] = {false, false, false, true}; const bool GFX_WEATHER [] = {false, false, false, true};
const int GFX_LEVEL_AMOUNT = 4; const int GFX_LEVEL_AMOUNT = 4;

View File

@ -318,6 +318,26 @@ namespace StringUtils
std::string s(chars); std::string s(chars);
return insertValues(s, v1); return insertValues(s, v1);
} }
template<typename T>
bool parseString(const char* input, T* output)
{
std::istringstream conv(input);
conv >> *output;
// check reading worked correctly and everything was read
if (conv.fail() || !conv.eof())
{
return false;
}
return true;
}
template<typename T>
bool parseString(const std::string& input, T* output)
{
return parseString(input.c_str(), output);
}
} // namespace StringUtils } // namespace StringUtils