From 24d0d549bade06620af061b433577b457a12b56a Mon Sep 17 00:00:00 2001 From: auria Date: Sun, 16 Jan 2011 00:06:59 +0000 Subject: [PATCH] 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 --- src/config/stk_config.cpp | 6 +- src/config/user_config.cpp | 2 +- src/config/user_config.hpp | 12 +++- src/io/file_manager.cpp | 15 +++-- src/io/xml_node.cpp | 73 ++++++++++++++++++--- src/io/xml_node.hpp | 7 ++ src/karts/kart.cpp | 7 +- src/karts/kart_model.cpp | 38 +++++++++-- src/karts/kart_model.hpp | 6 ++ src/karts/kart_properties.cpp | 11 ++-- src/main.cpp | 15 ++--- src/modes/world.cpp | 2 +- src/states_screens/options_screen_video.cpp | 2 +- src/utils/string_utils.hpp | 20 ++++++ 14 files changed, 171 insertions(+), 45 deletions(-) diff --git a/src/config/stk_config.cpp b/src/config/stk_config.cpp index 4ee7e1303..71923cae6 100644 --- a/src/config/stk_config.cpp +++ b/src/config/stk_config.cpp @@ -69,10 +69,10 @@ void STKConfig::load(const std::string &filename) catch(std::exception& err) { - fprintf(stderr, "Error while parsing KartProperties '%s':\n", - filename.c_str()); - fprintf(stderr, "%s", err.what()); + fprintf(stderr, "FATAL ERROR while reading StkConfig '%s':\n", filename.c_str()); + fprintf(stderr, " %s", err.what()); fprintf(stderr, "\n"); + exit(1); } delete root; diff --git a/src/config/user_config.cpp b/src/config/user_config.cpp index 543b3d779..19c87e6ab 100644 --- a/src/config/user_config.cpp +++ b/src/config/user_config.cpp @@ -423,7 +423,7 @@ void UserConfig::addDefaultPlayer() class GuestPlayerProfile : public PlayerProfile { public: - GuestPlayerProfile() : PlayerProfile(_("Guest")) + GuestPlayerProfile() : PlayerProfile(L"Guest") { m_is_guest_account = true; } diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index 9e9bc2854..953348fe5 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -204,6 +204,9 @@ public: 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 : @@ -276,8 +279,10 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_weather_effects PARAM_DEFAULT( BoolUserConfigParam(true, "weather_gfx", &m_video_group) ); - PARAM_PREFIX BoolUserConfigParam m_show_steering_animations - PARAM_DEFAULT( BoolUserConfigParam(true, "steering_animations", &m_video_group, "Display steering animations in race") ); + PARAM_PREFIX IntUserConfigParam m_show_steering_animations + 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_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") ); // ---- Graphic Quality + // FIXME: those are probably not needed... PARAM_PREFIX GroupUserConfigParam m_graphics_quality PARAM_DEFAULT( GroupUserConfigParam("GFX", "Graphics Quality Settings") ); @@ -334,7 +340,7 @@ namespace UserConfigParams "Whether anisotropic filtering is allowed to be used (true or false)") ); PARAM_PREFIX BoolUserConfigParam m_trilinear 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 diff --git a/src/io/file_manager.cpp b/src/io/file_manager.cpp index f793311b2..ce9795ba4 100644 --- a/src/io/file_manager.cpp +++ b/src/io/file_manager.cpp @@ -231,11 +231,16 @@ io::IXMLReader *FileManager::createXMLReader(const std::string &filename) */ XMLNode *FileManager::createXMLTree(const std::string &filename) { - io::IXMLReader *xml_reader = createXMLReader(filename); - if(!xml_reader) return NULL; - XMLNode* node = new XMLNode(xml_reader); - xml_reader->drop(); - return node; + try + { + XMLNode* node = new XMLNode(filename); + return node; + } + catch (std::runtime_error& e) + { + fprintf(stderr, "[FileManager::createXMLTree] %s\n", e.what()); + return NULL; + } } // getXMLTree //----------------------------------------------------------------------------- diff --git a/src/io/xml_node.cpp b/src/io/xml_node.cpp index 72084972b..6b6202986 100644 --- a/src/io/xml_node.cpp +++ b/src/io/xml_node.cpp @@ -22,8 +22,12 @@ #include "utils/string_utils.hpp" #include "utils/vec3.hpp" +#include + XMLNode::XMLNode(io::IXMLReader *xml) { + m_file_name = "[unknown]"; + while(xml->getNodeType()!=io::EXN_ELEMENT && xml->read()); readXML(xml); } // XMLNode @@ -34,7 +38,15 @@ XMLNode::XMLNode(io::IXMLReader *xml) */ XMLNode::XMLNode(const std::string &filename) { + m_file_name = filename; + io::IXMLReader *xml = file_manager->createXMLReader(filename); + + if (xml == NULL) + { + throw std::runtime_error("Cannot find file "+filename); + } + bool is_first_element = true; while(xml->read()) { @@ -98,7 +110,9 @@ void XMLNode::readXML(io::IXMLReader *xml) switch (xml->getNodeType()) { 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; case io::EXN_ELEMENT_END: // End of this element found. @@ -255,9 +269,14 @@ int XMLNode::get(const std::string &attribute, int *value) const { std::string s; 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 - *value = atoi(s.c_str()); + + if (!StringUtils::parseString(s, value)) + { + 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; } // get(int) @@ -266,7 +285,14 @@ int XMLNode::get(const std::string &attribute, unsigned int *value) const { std::string s; if(!get(attribute, &s)) return 0; - *value = atoi(s.c_str()); + + if (!StringUtils::parseString(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; } // get(unsigned int) @@ -275,7 +301,14 @@ int XMLNode::get(const std::string &attribute, float *value) const { std::string s; if(!get(attribute, &s)) return 0; - *value = (float)atof(s.c_str()); + + if (!StringUtils::parseString(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; } // get(int) @@ -323,9 +356,19 @@ int XMLNode::get(const std::string &attribute, std::vector v = StringUtils::split(s,' '); value->clear(); - for(unsigned int i=0; ipush_back((float)atof(v[i].c_str())); + float curr; + if (!StringUtils::parseString(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(); } // get(vector) @@ -344,9 +387,19 @@ int XMLNode::get(const std::string &attribute, std::vector *value) const std::vector v = StringUtils::split(s,' '); value->clear(); - for(unsigned int i=0; ipush_back(atoi(v[i].c_str())); + int val; + if (!StringUtils::parseString(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(); } // get(vector) diff --git a/src/io/xml_node.hpp b/src/io/xml_node.hpp index f949752f6..f05aa1076 100644 --- a/src/io/xml_node.hpp +++ b/src/io/xml_node.hpp @@ -43,10 +43,17 @@ private: std::map m_attributes; /** List of all sub nodes. */ std::vector m_nodes; + void readXML(io::IXMLReader *xml); + + std::string m_file_name; + public: XMLNode(io::IXMLReader *xml); + + /** \throw runtime_error if the file is not found */ XMLNode(const std::string &filename); + ~XMLNode(); const std::string &getName() const {return m_name; } const XMLNode *getNode(const std::string &name) const; diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index d20a6410a..645c29a34 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -71,9 +71,10 @@ Kart::Kart (const std::string& ident, int position, #if defined(WIN32) && !defined(__CYGWIN__) # pragma warning(1:4355) #endif -{ - m_kart_properties = kart_properties_manager->getKart(ident); +{ + m_kart_properties = kart_properties_manager->getKart(ident); assert(m_kart_properties != NULL); + // We have to take a copy of the kart model, since otherwise // the animations will be mixed up (i.e. different instances of // 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_wheel_rotation = 0; + m_kart_model->setKart(this); + // Create SFXBase for each custom sound (TODO: add back when properly done) /* for (int n = 0; n < SFXManager::NUM_CUSTOMS; n++) diff --git a/src/karts/kart_model.cpp b/src/karts/kart_model.cpp index c98f72255..3fcd083d2 100644 --- a/src/karts/kart_model.cpp +++ b/src/karts/kart_model.cpp @@ -24,6 +24,7 @@ #include "graphics/irr_driver.hpp" #include "graphics/mesh_tools.hpp" #include "io/xml_node.hpp" +#include "karts/kart.hpp" #include "utils/constants.hpp" float KartModel::UNDEFINED = -99.9f; @@ -55,7 +56,8 @@ float KartModel::UNDEFINED = -99.9f; KartModel::KartModel(bool is_master) { m_is_master = is_master; - + m_kart = NULL; + for(unsigned int i=0; i<4; i++) { m_wheel_graphics_position[i] = Vec3(UNDEFINED); @@ -188,7 +190,21 @@ KartModel* KartModel::makeCopy() void KartModel::attachModel(scene::ISceneNode **node) { 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); m_animated_node = static_cast(*node); @@ -202,6 +218,7 @@ void KartModel::attachModel(scene::ISceneNode **node) int straight_frame = m_animation_frame[AF_STRAIGHT]>=0 ? m_animation_frame[AF_STRAIGHT] : 0; + printf("straight_frame = %i\n", straight_frame); *node = irr_driver->addMesh(m_mesh->getMesh(straight_frame)); } #ifdef DEBUG @@ -239,7 +256,10 @@ bool KartModel::loadModels(const KartProperties &kart_properties) } 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); } @@ -352,8 +372,11 @@ void KartModel::setDefaultPhysicsPosition(const Vec3 ¢er_shift, */ 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; 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(!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 // ----------------------------- diff --git a/src/karts/kart_model.hpp b/src/karts/kart_model.hpp index a3999a793..7f39195ae 100644 --- a/src/karts/kart_model.hpp +++ b/src/karts/kart_model.hpp @@ -28,6 +28,7 @@ using namespace irr; #include "utils/no_copy.hpp" #include "utils/vec3.hpp" +class Kart; class KartProperties; class XMLNode; @@ -130,6 +131,8 @@ private: void OnAnimationEnd(scene::IAnimatedMeshSceneNode *node); + Kart* m_kart; + public: KartModel(bool is_master); ~KartModel(); @@ -175,5 +178,8 @@ public: /** Enables- or disables the end animation. */ void setAnimation(AnimationFrameType type); + + /** Sets the kart this model is currently used for */ + void setKart(Kart* k) { m_kart = k; } }; // KartModel #endif diff --git a/src/karts/kart_properties.cpp b/src/karts/kart_properties.cpp index 0feb27bbf..4788d2a54 100644 --- a/src/karts/kart_properties.cpp +++ b/src/karts/kart_properties.cpp @@ -416,11 +416,14 @@ void KartProperties::getAllData(const XMLNode * root) plunger_node->get("in-face-time", &v); 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")) diff --git a/src/main.cpp b/src/main.cpp index 9e6154a93..857a73013 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -242,7 +242,7 @@ void cmdLineHelp (char* invocation) " (Default: 0, OpenGL: 1, Direct3D9: 2, \n" " Direct3D8: 3, Software: 4, \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" " water animations or explosions (Enable: 1, Disable: 0).\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) ) { - if (n) - { - UserConfigParams::m_show_steering_animations = true; - } - else - { - UserConfigParams::m_show_steering_animations = false; - } + UserConfigParams::m_show_steering_animations = n; } else if( (!strcmp(argv[i], "--kart") && i+1setController(controller); + return new_kart; } // createKart diff --git a/src/states_screens/options_screen_video.cpp b/src/states_screens/options_screen_video.cpp index 9274a7e0c..9fe967bb3 100644 --- a/src/states_screens/options_screen_video.cpp +++ b/src/states_screens/options_screen_video.cpp @@ -43,7 +43,7 @@ DEFINE_SCREEN_SINGLETON( OptionsScreenVideo ); // Look-up table for GFX levels 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 int GFX_LEVEL_AMOUNT = 4; diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp index 8dbf53972..7c1007cd6 100644 --- a/src/utils/string_utils.hpp +++ b/src/utils/string_utils.hpp @@ -318,6 +318,26 @@ namespace StringUtils std::string s(chars); return insertValues(s, v1); } + + template + 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 + bool parseString(const std::string& input, T* output) + { + return parseString(input.c_str(), output); + } } // namespace StringUtils