From a7102c143f2f44701c95e2824ab93a459bb5d162 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 26 Feb 2013 14:33:05 +0100 Subject: [PATCH 1/9] ESX variable type cleanup --- apps/openmw/mwworld/globals.cpp | 66 ++++++++++++++++----------------- components/esm/defs.hpp | 4 +- components/esm/loadglob.cpp | 4 +- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index f010661b9..8742dd892 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -21,21 +21,21 @@ namespace MWWorld Globals::Collection::const_iterator Globals::find (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); - - return iter; + + return iter; } Globals::Collection::iterator Globals::find (const std::string& name) { Collection::iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) throw std::runtime_error ("unknown global variable: " + name); - - return iter; + + return iter; } Globals::Globals (const MWWorld::ESMStore& store) @@ -46,44 +46,44 @@ namespace MWWorld { char type = ' '; Data value; - + switch (iter->mType) { case ESM::VT_Short: - + type = 's'; value.mShort = *reinterpret_cast ( &iter->mValue); break; - - case ESM::VT_Int: - + + case ESM::VT_Long: + type = 'l'; value.mLong = *reinterpret_cast ( &iter->mValue); break; - + case ESM::VT_Float: - + type = 'f'; value.mFloat = *reinterpret_cast ( &iter->mValue); break; - + default: - + throw std::runtime_error ("unsupported global variable type"); - } + } mVariables.insert (std::make_pair (iter->mId, std::make_pair (type, value))); } - + if (mVariables.find ("dayspassed")==mVariables.end()) { // vanilla Morrowind does not define dayspassed. Data value; value.mLong = 0; - + mVariables.insert (std::make_pair ("dayspassed", std::make_pair ('l', value))); } } @@ -91,31 +91,31 @@ namespace MWWorld const Globals::Data& Globals::operator[] (const std::string& name) const { Collection::const_iterator iter = find (name); - + return iter->second.second; } Globals::Data& Globals::operator[] (const std::string& name) { Collection::iterator iter = find (name); - + return iter->second.second; } - + void Globals::setInt (const std::string& name, int value) { Collection::iterator iter = find (name); - + switch (iter->second.first) { case 's': iter->second.second.mShort = value; break; case 'l': iter->second.second.mLong = value; break; case 'f': iter->second.second.mFloat = value; break; - + default: throw std::runtime_error ("unsupported global variable type"); } } - + void Globals::setFloat (const std::string& name, float value) { Collection::iterator iter = find (name); @@ -127,9 +127,9 @@ namespace MWWorld case 'f': iter->second.second.mFloat = value; break; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + int Globals::getInt (const std::string& name) const { Collection::const_iterator iter = find (name); @@ -141,13 +141,13 @@ namespace MWWorld case 'f': return iter->second.second.mFloat; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + float Globals::getFloat (const std::string& name) const { Collection::const_iterator iter = find (name); - + switch (iter->second.first) { case 's': return iter->second.second.mShort; @@ -155,16 +155,16 @@ namespace MWWorld case 'f': return iter->second.second.mFloat; default: throw std::runtime_error ("unsupported global variable type"); - } + } } - + char Globals::getType (const std::string& name) const { Collection::const_iterator iter = mVariables.find (name); - + if (iter==mVariables.end()) return ' '; - + return iter->second.first; } } diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index aa870f925..143d90034 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -13,9 +13,9 @@ enum VarType { VT_Unknown, VT_None, - VT_Short, + VT_Short, // stored as a float, kinda VT_Int, - VT_Long, + VT_Long, // stored as a float VT_Float, VT_String, VT_Ignored diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index ceaa86948..429c6ff1d 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -12,7 +12,7 @@ void Global::load(ESMReader &esm) if (tmp == "s") mType = VT_Short; else if (tmp == "l") - mType = VT_Int; + mType = VT_Long; else if (tmp == "f") mType = VT_Float; else @@ -30,7 +30,7 @@ void Global::save(ESMWriter &esm) esm.writeHNString("FNAM", "s"); break; - case VT_Int: + case VT_Long: esm.writeHNString("FNAM", "l"); break; From 3bd228f71b1dab4f5d454b1a1cb7b2506a94afaa Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 28 Feb 2013 11:50:29 +0100 Subject: [PATCH 2/9] fix for global variables of type short --- components/esm/loadglob.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 429c6ff1d..9e20578ce 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -20,6 +20,14 @@ void Global::load(ESMReader &esm) // Note: Both floats and longs are represented as floats. esm.getHNT(mValue, "FLTV"); + + if (mType==VT_Short) + { + if (mValue!=mValue) + mValue = 0; // nan + else + mValue = static_cast (mValue); + } } void Global::save(ESMWriter &esm) From 65081f5520b733b235b87a9b98e5f6afbb331962 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Mar 2013 13:59:06 +0100 Subject: [PATCH 3/9] added variant class --- apps/opencs/view/world/vartypedelegate.hpp | 2 + components/CMakeLists.txt | 2 +- components/esm/defs.hpp | 12 - components/esm/loadglob.hpp | 1 + components/esm/loadgmst.hpp | 1 + components/esm/loadinfo.hpp | 1 + components/esm/variant.cpp | 256 ++++++++++++++++++++ components/esm/variant.hpp | 85 +++++++ components/esm/variantimp.cpp | 262 +++++++++++++++++++++ components/esm/variantimp.hpp | 179 ++++++++++++++ 10 files changed, 788 insertions(+), 13 deletions(-) create mode 100644 components/esm/variant.cpp create mode 100644 components/esm/variant.hpp create mode 100644 components/esm/variantimp.cpp create mode 100644 components/esm/variantimp.hpp diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp index 621dd316b..c8493f029 100644 --- a/apps/opencs/view/world/vartypedelegate.hpp +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_VARTYPEDELEGATE_H #define CSV_WORLD_VARTYPEDELEGATE_H +#include + #include "enumdelegate.hpp" namespace CSVWorld diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 00342e2ac..0c75123cb 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -39,7 +39,7 @@ add_component_dir (esm loadclas loadclot loadcont loadcrea loadcrec loaddial loaddoor loadench loadfact loadglob loadgmst loadinfo loadingr loadland loadlevlist loadligh loadlocks loadltex loadmgef loadmisc loadnpcc loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat - loadweap records aipackage effectlist spelllist + loadweap records aipackage effectlist spelllist variant variantimp ) add_component_dir (misc diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 143d90034..bd86f9ba0 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -9,18 +9,6 @@ namespace ESM // Pixel color value. Standard four-byte rr,gg,bb,aa format. typedef int32_t Color; -enum VarType -{ - VT_Unknown, - VT_None, - VT_Short, // stored as a float, kinda - VT_Int, - VT_Long, // stored as a float - VT_Float, - VT_String, - VT_Ignored -}; - enum Specialization { SPC_Combat = 0, diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 6111648a6..96d2fcaf4 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -4,6 +4,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index f7aec5c76..12f212081 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -4,6 +4,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index f1decb9c6..ca08c3b55 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -5,6 +5,7 @@ #include #include "defs.hpp" +#include "variant.hpp" namespace ESM { diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp new file mode 100644 index 000000000..bf8d2069b --- /dev/null +++ b/components/esm/variant.cpp @@ -0,0 +1,256 @@ +#include "variant.hpp" + +#include +#include + +#include "esmreader.hpp" +#include "variantimp.hpp" + +ESM::Variant::Variant() : mType (VT_None), mData (0) {} + +ESM::Variant::~Variant() +{ + delete mData; +} + +ESM::Variant& ESM::Variant::operator= (const Variant& variant) +{ + if (&variant!=this) + { + VariantDataBase *newData = variant.mData ? variant.mData->clone() : 0; + + delete mData; + + mType = variant.mType; + mData = newData; + } + + return *this; +} + +ESM::Variant::Variant (const Variant& variant) +: mType (variant.mType), mData (variant.mData ? variant.mData->clone() : 0) +{} + +ESM::VarType ESM::Variant::getType() const +{ + return mType; +} + +std::string ESM::Variant::toString() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to string"); + + return mData->getString(); +} + +int ESM::Variant::getInteger() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to integer"); + + return mData->getInteger(); +} + +float ESM::Variant::getFloat() const +{ + if (!mData) + throw std::runtime_error ("can not convert empty variant to float"); + + return mData->getFloat(); +} + +void ESM::Variant::read (ESMReader& esm, Format format) +{ + // type + VarType type = VT_Unknown; + + if (format==Format_Global) + { + std::string typeId = esm.getHNString ("FNAM"); + + if (typeId == "s") + type = VT_Short; + else if (typeId == "l") + type = VT_Long; + else if (typeId == "f") + type = VT_Float; + else + esm.fail ("illegal global variable type " + typeId); + } + else // GMST + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="STRV") + { + type = VT_String; + } + else if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } + + setType (type); + + // data + if (mData) + mData->read (esm, format, mType); +} + +void ESM::Variant::write (ESMWriter& esm, Format format) const +{ + if (mType==VT_Unknown) + { + throw std::runtime_error ("can not serialise variant of unknown type"); + } + else if (mType==VT_None) + { + if (format==Format_Global) + throw std::runtime_error ("can not serialise variant of type none to global format"); + + // nothing to do here for GMST format + } + else + mData->write (esm, format, mType); +} + +void ESM::Variant::write (std::ostream& stream) const +{ + switch (mType) + { + case VT_Unknown: + + stream << "variant unknown"; + break; + + case VT_None: + + stream << "variant none"; + break; + + case VT_Short: + + stream << "variant short: " << mData->getInteger(); + break; + + case VT_Int: + + stream << "variant int: " << mData->getInteger(); + break; + + case VT_Long: + + stream << "variant long: " << mData->getInteger(); + break; + + case VT_Float: + + stream << "variant float: " << mData->getFloat(); + break; + + case VT_String: + + stream << "variant string: \"" << mData->getString() << "\2"; + break; + } +} + +void ESM::Variant::setType (VarType type) +{ + if (type!=mType) + { + VariantDataBase *newData = 0; + + switch (type) + { + case VT_Unknown: + case VT_None: + + break; // no data + + case VT_Short: + case VT_Int: + case VT_Long: + + newData = new VariantIntegerData (mData); + break; + + case VT_Float: + + newData = new VariantFloatData (mData); + break; + + case VT_String: + + newData = new VariantStringData (mData); + break; + } + + delete mData; + mData = newData; + mType = type; + } +} + +void ESM::Variant::setString (const std::string& value) +{ + if (!mData) + throw std::runtime_error ("can not assign string to empty variant"); + + mData->setString (value); +} + +void ESM::Variant::setInteger (int value) +{ + if (!mData) + throw std::runtime_error ("can not assign integer to empty variant"); + + mData->setInteger (value); +} + +void ESM::Variant::setFloat (float value) +{ + if (!mData) + throw std::runtime_error ("can not assign float to empty variant"); + + mData->setFloat (value); +} + +bool ESM::Variant::isEqual (const Variant& value) const +{ + if (mType!=value.mType) + return false; + + if (!mData) + return true; + + assert (value.mData); + + return mData->isEqual (*value.mData); +} + +std::ostream& ESM::operator<< (std::ostream& stream, const Variant& value) +{ + value.write (stream); + return stream; +} + +bool ESM::operator== (const Variant& left, const Variant& right) +{ + return left.isEqual (right); +} + +bool ESM::operator!= (const Variant& left, const Variant& right) +{ + return !(left==right); +} \ No newline at end of file diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp new file mode 100644 index 000000000..b50bb1d2f --- /dev/null +++ b/components/esm/variant.hpp @@ -0,0 +1,85 @@ +#ifndef OPENMW_ESM_VARIANT_H +#define OPENMW_ESM_VARIANT_H + +#include +#include + +namespace ESM +{ + class ESMReader; + class ESMWriter; + + enum VarType + { + VT_Unknown, + VT_None, + VT_Short, // stored as a float, kinda + VT_Int, + VT_Long, // stored as a float + VT_Float, + VT_String + }; + + class VariantDataBase; + + class Variant + { + VarType mType; + VariantDataBase *mData; + + public: + + enum Format + { + Format_Global, + Format_Gmst + }; + + Variant(); + + ~Variant(); + + Variant& operator= (const Variant& variant); + + Variant (const Variant& variant); + + VarType getType() const; + + std::string toString() const; + ///< Will throw an exception, if value can not be represented as a string. + + int getInteger() const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + + float getFloat() const; + ///< Will throw an exception, if value can not be represented as a float value. + + void read (ESMReader& esm, Format format); + + void write (ESMWriter& esm, Format format) const; + + void write (std::ostream& stream) const; + ///< Write in text format. + + void setType (VarType type); + + void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + + void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + bool isEqual (const Variant& value) const; + }; + + std::ostream& operator<<(std::ostream& stream, const Variant& value); + + bool operator== (const Variant& left, const Variant& right); + bool operator!= (const Variant& left, const Variant& right); +} + +#endif \ No newline at end of file diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp new file mode 100644 index 000000000..e99cc50b5 --- /dev/null +++ b/components/esm/variantimp.cpp @@ -0,0 +1,262 @@ + +#include "variantimp.hpp" + +#include + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +ESM::VariantDataBase::~VariantDataBase() {} + +std::string ESM::VariantDataBase::getString (bool default_) const +{ + if (default_) + return ""; + + throw std::runtime_error ("can not convert variant to string"); +} + +int ESM::VariantDataBase::getInteger (bool default_) const +{ + if (default_) + return 0; + + throw std::runtime_error ("can not convert variant to integer"); +} + +float ESM::VariantDataBase::getFloat (bool default_) const +{ + if (default_) + return 0; + + throw std::runtime_error ("can not convert variant to float"); +} + +void ESM::VariantDataBase::setString (const std::string& value) +{ + throw std::runtime_error ("conversion of string to variant not possible"); +} + +void ESM::VariantDataBase::setInteger (int value) +{ + throw std::runtime_error ("conversion of integer to variant not possible"); +} + +void ESM::VariantDataBase::setFloat (float value) +{ + throw std::runtime_error ("conversion of float to variant not possible"); +} + + + +ESM::VariantStringData::VariantStringData (const VariantDataBase *data) +{ + if (data) + mValue = data->getString (true); +} + +ESM::VariantDataBase *ESM::VariantStringData::clone() const +{ + return new VariantStringData (*this); +} + +std::string ESM::VariantStringData::getString (bool default_) const +{ + return mValue; +} + +void ESM::VariantStringData::setString (const std::string& value) +{ + mValue = value; +} + +void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_String) + throw std::logic_error ("not a string type"); + + if (format==Variant::Format_Global) + esm.fail ("global variables of type string not supported"); + + // GMST + mValue = esm.getHString(); +} + +void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_String) + throw std::logic_error ("not a string type"); + + if (format==Variant::Format_Global) + throw std::runtime_error ("global variables of type string not supported"); + + // GMST + esm.writeHNString ("STRV", mValue); +} + +bool ESM::VariantStringData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} + + + +ESM::VariantIntegerData::VariantIntegerData (const VariantDataBase *data) : mValue (0) +{ + if (data) + mValue = data->getInteger (true); +} + +ESM::VariantDataBase *ESM::VariantIntegerData::clone() const +{ + return new VariantIntegerData (*this); +} + +int ESM::VariantIntegerData::getInteger (bool default_) const +{ + return mValue; +} + +float ESM::VariantIntegerData::getFloat (bool default_) const +{ + return mValue; +} + +void ESM::VariantIntegerData::setInteger (int value) +{ + mValue = value; +} + +void ESM::VariantIntegerData::setFloat (float value) +{ + mValue = static_cast (value); +} + +void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_Short && type!=VT_Long && type!=VT_Int) + throw std::logic_error ("not an integer type"); + + if (format==Variant::Format_Global) + { + float value; + esm.getHNT (value, "FLTV"); + + if (type==VT_Short) + { + if (value!=value) + mValue = 0; // nan + else + mValue = static_cast (value); + } + else if (type==VT_Long) + mValue = static_cast (value); + else + esm.fail ("unsupported global variable integer type"); + } + else // GMST + { + if (type==VT_Int) + esm.fail ("unsupported global variable integer type"); + + esm.getHT (mValue); + } +} + +void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_Short && type!=VT_Long && type!=VT_Int) + throw std::logic_error ("not an integer type"); + + if (format==Variant::Format_Global) + { + if (type==VT_Short || type==VT_Long) + { + float value = mValue; + esm.writeHNString ("FNAM", type==VT_Short ? "s" : "l"); + esm.writeHNT ("FLTV", value); + } + else + throw std::runtime_error ("unsupported global variable integer type"); + } + else // GMST + { + if (type==VT_Int) + throw std::runtime_error ("unsupported global variable integer type"); + + esm.writeHNT ("INTV", mValue); + } +} + +bool ESM::VariantIntegerData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} + + +ESM::VariantFloatData::VariantFloatData (const VariantDataBase *data) : mValue (0) +{ + if (data) + mValue = data->getFloat (true); +} + +ESM::VariantDataBase *ESM::VariantFloatData::clone() const +{ + return new VariantFloatData (*this); +} + +int ESM::VariantFloatData::getInteger (bool default_) const +{ + return static_cast (mValue); +} + +float ESM::VariantFloatData::getFloat (bool default_) const +{ + return mValue; +} + +void ESM::VariantFloatData::setInteger (int value) +{ + mValue = value; +} + +void ESM::VariantFloatData::setFloat (float value) +{ + mValue = value; +} + +void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarType type) +{ + if (type!=VT_Float) + throw std::logic_error ("not a float type"); + + if (format==Variant::Format_Global) + { + esm.getHNT (mValue, "FLTV"); + } + else // GMST + { + esm.getHT (mValue); + } +} + +void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarType type) const +{ + if (type!=VT_Float) + throw std::logic_error ("not a float type"); + + if (format==Variant::Format_Global) + { + esm.writeHNString ("FNAM", "f"); + esm.writeHNT ("FLTV", mValue); + } + else // GMST + { + esm.writeHNT ("INTV", mValue); + } +} + +bool ESM::VariantFloatData::isEqual (const VariantDataBase& value) const +{ + return dynamic_cast (value).mValue==mValue; +} \ No newline at end of file diff --git a/components/esm/variantimp.hpp b/components/esm/variantimp.hpp new file mode 100644 index 000000000..1dc20c21f --- /dev/null +++ b/components/esm/variantimp.hpp @@ -0,0 +1,179 @@ +#ifndef OPENMW_ESM_VARIANTIMP_H +#define OPENMW_ESM_VARIANTIMP_H + +#include + +#include "variant.hpp" + +namespace ESM +{ + class VariantDataBase + { + public: + + virtual ~VariantDataBase(); + + virtual VariantDataBase *clone() const = 0; + + virtual std::string getString (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a string. + /// + /// \note Numeric values are not converted to strings. + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + /// + /// Default-implementation: throw an exception. + + virtual void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + /// + /// Default-implementation: throw an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + /// + /// Default-implementation: throw an exception. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + /// + /// Default-implementation: throw an exception. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type) = 0; + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const = 0; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const = 0; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + + }; + + class VariantStringData : public VariantDataBase + { + std::string mValue; + + public: + + VariantStringData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual std::string getString (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a string. + /// + /// \note Numeric values are not converted to strings. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setString (const std::string& value); + ///< Will throw an exception, if type is not compatible with string. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; + + class VariantIntegerData : public VariantDataBase + { + int mValue; + + public: + + VariantIntegerData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; + + class VariantFloatData : public VariantDataBase + { + float mValue; + + public: + + VariantFloatData (const VariantDataBase *data = 0); + ///< Calling the constructor with an incompatible data type will result in a silent + /// default initialisation. + + virtual VariantDataBase *clone() const; + + virtual int getInteger (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as an integer (implicit + /// casting of float values is permitted). + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual float getFloat (bool default_ = false) const; + ///< Will throw an exception, if value can not be represented as a float value. + /// + /// \param default_ Return a default value instead of throwing an exception. + + virtual void setInteger (int value); + ///< Will throw an exception, if type is not compatible with integer. + + virtual void setFloat (float value); + ///< Will throw an exception, if type is not compatible with float. + + virtual void read (ESMReader& esm, Variant::Format format, VarType type); + ///< If \a type is not supported by \a format, an exception is thrown via ESMReader::fail + + virtual void write (ESMWriter& esm, Variant::Format format, VarType type) const; + ///< If \a type is not supported by \a format, an exception is thrown. + + virtual bool isEqual (const VariantDataBase& value) const; + ///< If the (C++) type of \a value does not match the type of *this, an exception is thrown. + }; +} + +#endif From a1ac20c6f398ef38ff2797a6ab0ba6ed264c0e2e Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 4 Mar 2013 14:32:59 +0100 Subject: [PATCH 4/9] changed global variable records to new variant type --- apps/esmtool/record.cpp | 4 +-- apps/opencs/model/doc/document.cpp | 12 ++++--- apps/opencs/model/world/columns.hpp | 4 +-- apps/openmw/mwworld/globals.cpp | 11 +++---- components/esm/loadglob.cpp | 49 ++++------------------------- components/esm/loadglob.hpp | 4 +-- 6 files changed, 22 insertions(+), 62 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index a732f1938..929201417 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -713,9 +713,7 @@ void Record::print() template<> void Record::print() { - // nothing to print (well, nothing that's correct anyway) - std::cout << " Type: " << mData.mType << std::endl; - std::cout << " Value: " << mData.mValue << std::endl; + std::cout << " " << mData.mValue << std::endl; } template<> diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index b361577be..f6df1f499 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -154,8 +154,7 @@ void CSMDoc::Document::addOptionalGlobals() { ESM::Global global; global.mId = sGlobals[i]; - global.mType = ESM::VT_Int; - global.mValue = 0; + global.mValue.setType (ESM::VT_Int); addOptionalGlobal (global); } } @@ -192,9 +191,14 @@ void CSMDoc::Document::createBase() for (int i=0; sGlobals[i]; ++i) { ESM::Global record; + record.mId = sGlobals[i]; - record.mValue = i==0 ? 1 : 0; - record.mType = ESM::VT_Float; + + record.mValue.setType (i==2 ? ESM::VT_Float : ESM::VT_Int); + + if (i==0) + record.mValue.setInteger (1); + getData().getGlobals().add (record); } } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 2d81a24e9..8855edc46 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -12,13 +12,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return record.get().mValue; + return record.get().mValue.getFloat(); } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mValue = data.toFloat(); + record2.mValue.setFloat (data.toFloat()); record.setModified (record2); } diff --git a/apps/openmw/mwworld/globals.cpp b/apps/openmw/mwworld/globals.cpp index 8742dd892..9e57910ee 100644 --- a/apps/openmw/mwworld/globals.cpp +++ b/apps/openmw/mwworld/globals.cpp @@ -47,27 +47,24 @@ namespace MWWorld char type = ' '; Data value; - switch (iter->mType) + switch (iter->mValue.getType()) { case ESM::VT_Short: type = 's'; - value.mShort = *reinterpret_cast ( - &iter->mValue); + value.mShort = iter->mValue.getInteger(); break; case ESM::VT_Long: type = 'l'; - value.mLong = *reinterpret_cast ( - &iter->mValue); + value.mLong = iter->mValue.getInteger(); break; case ESM::VT_Float: type = 'f'; - value.mFloat = *reinterpret_cast ( - &iter->mValue); + value.mFloat = iter->mValue.getFloat(); break; default: diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 9e20578ce..0cb6d0a41 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -6,60 +6,23 @@ namespace ESM { -void Global::load(ESMReader &esm) -{ - std::string tmp = esm.getHNString("FNAM"); - if (tmp == "s") - mType = VT_Short; - else if (tmp == "l") - mType = VT_Long; - else if (tmp == "f") - mType = VT_Float; - else - esm.fail("Illegal global variable type " + tmp); - - // Note: Both floats and longs are represented as floats. - esm.getHNT(mValue, "FLTV"); - - if (mType==VT_Short) + void Global::load(ESMReader &esm) { - if (mValue!=mValue) - mValue = 0; // nan - else - mValue = static_cast (mValue); + mValue.read (esm, ESM::Variant::Format_Global); } -} -void Global::save(ESMWriter &esm) -{ - switch(mType) + void Global::save(ESMWriter &esm) { - case VT_Short: - esm.writeHNString("FNAM", "s"); - break; - - case VT_Long: - esm.writeHNString("FNAM", "l"); - break; - - case VT_Float: - esm.writeHNString("FNAM", "f"); - break; - - default: - return; + mValue.write (esm, ESM::Variant::Format_Global); } - esm.writeHNT("FLTV", mValue); -} void Global::blank() { - mValue = 0; - mType = VT_Float; + mValue.setType (ESM::VT_None); } bool operator== (const Global& left, const Global& right) { - return left.mId==right.mId && left.mValue==right.mValue && left.mType==right.mType; + return left.mId==right.mId && left.mValue==right.mValue; } } diff --git a/components/esm/loadglob.hpp b/components/esm/loadglob.hpp index 96d2fcaf4..72e16c0ce 100644 --- a/components/esm/loadglob.hpp +++ b/components/esm/loadglob.hpp @@ -3,7 +3,6 @@ #include -#include "defs.hpp" #include "variant.hpp" namespace ESM @@ -19,8 +18,7 @@ class ESMWriter; struct Global { std::string mId; - float mValue; - VarType mType; + Variant mValue; void load(ESMReader &esm); void save(ESMWriter &esm); From ce49ad54a1ef73a557ef0a6d32362d21718ed2e0 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:02:05 +0100 Subject: [PATCH 5/9] some cleanup and fixing --- components/esm/loadglob.cpp | 8 ++------ components/esm/variant.cpp | 37 ++++++++++++++++++++++--------------- components/esm/variant.hpp | 2 +- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp index 0cb6d0a41..ccb519acd 100644 --- a/components/esm/loadglob.cpp +++ b/components/esm/loadglob.cpp @@ -1,17 +1,13 @@ #include "loadglob.hpp" -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { - - void Global::load(ESMReader &esm) + void Global::load (ESMReader &esm) { mValue.read (esm, ESM::Variant::Format_Global); } - void Global::save(ESMWriter &esm) + void Global::save (ESMWriter &esm) { mValue.write (esm, ESM::Variant::Format_Global); } diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index bf8d2069b..98786c20e 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -37,7 +37,7 @@ ESM::VarType ESM::Variant::getType() const return mType; } -std::string ESM::Variant::toString() const +std::string ESM::Variant::getString() const { if (!mData) throw std::runtime_error ("can not convert empty variant to string"); @@ -81,23 +81,30 @@ void ESM::Variant::read (ESMReader& esm, Format format) } else // GMST { - esm.getSubName(); - NAME name = esm.retSubName(); - - if (name=="STRV") + if (!esm.hasMoreSubs()) { - type = VT_String; - } - else if (name=="INTV") - { - type = VT_Int; - } - else if (name=="FLTV") - { - type = VT_Float; + type = VT_None; } else - esm.fail ("invalid subrecord: " + name.toString()); + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="STRV") + { + type = VT_String; + } + else if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } } setType (type); diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index b50bb1d2f..b78d647a8 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -45,7 +45,7 @@ namespace ESM VarType getType() const; - std::string toString() const; + std::string getString() const; ///< Will throw an exception, if value can not be represented as a string. int getInteger() const; From ba4907fbaf7ed8d1dee768569b912bf7ee7641cf Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:02:27 +0100 Subject: [PATCH 6/9] use new Variant type for GMSTs --- apps/esmtool/record.cpp | 18 +----- apps/opencs/model/doc/document.cpp | 10 ++- apps/opencs/model/world/columns.hpp | 31 ++++++--- apps/opencs/model/world/data.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 11 ++-- apps/openmw/mwworld/worldimp.cpp | 14 ++-- components/esm/loadgmst.cpp | 89 ++++---------------------- components/esm/loadgmst.hpp | 10 ++- 8 files changed, 55 insertions(+), 129 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index 929201417..e4de63dd4 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -719,23 +719,7 @@ void Record::print() template<> void Record::print() { - std::cout << " Value: "; - switch (mData.mType) { - case ESM::VT_String: - std::cout << "'" << mData.mStr << "' (std::string)"; - break; - - case ESM::VT_Float: - std::cout << mData.mF << " (float)"; - break; - - case ESM::VT_Int: - std::cout << mData.mI << " (int)"; - break; - - default: - std::cout << "unknown type"; - } + std::cout << " " << mData.mValue << std::endl; } template<> diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index f6df1f499..6a76b0b6c 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -116,8 +116,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sFloats[i]; - gmst.mF = 0; - gmst.mType = ESM::VT_Float; + gmst.mValue.setType (ESM::VT_Float); addOptionalGmst (gmst); } @@ -125,8 +124,7 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sIntegers[i]; - gmst.mI = 0; - gmst.mType = ESM::VT_Long; + gmst.mValue.setType (ESM::VT_Int); addOptionalGmst (gmst); } @@ -134,8 +132,8 @@ void CSMDoc::Document::addOptionalGmsts() { ESM::GameSetting gmst; gmst.mId = sStrings[i]; - gmst.mStr = ""; - gmst.mType = ESM::VT_String; + gmst.mValue.setType (ESM::VT_String); + gmst.mValue.setString (""); addOptionalGmst (gmst); } } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 8855edc46..270987ec1 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -100,13 +100,13 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - return static_cast (record.get().mType); + return static_cast (record.get().mValue.getType()); } virtual void set (Record& record, const QVariant& data) { ESXRecordT record2 = record.get(); - record2.mType = static_cast (data.toInt()); + record2.mValue.setType (static_cast (data.toInt())); record.setModified (record2); } @@ -123,11 +123,11 @@ namespace CSMWorld virtual QVariant get (const Record& record) const { - switch (record.get().mType) + switch (record.get().mValue.getType()) { - case ESM::VT_String: return record.get().mStr.c_str(); break; - case ESM::VT_Int: return record.get().mI; break; - case ESM::VT_Float: return record.get().mF; break; + case ESM::VT_String: return record.get().mValue.getString().c_str(); break; + case ESM::VT_Int: return record.get().mValue.getInteger(); break; + case ESM::VT_Float: return record.get().mValue.getFloat(); break; default: return QVariant(); } @@ -137,11 +137,22 @@ namespace CSMWorld { ESXRecordT record2 = record.get(); - switch (record2.mType) + switch (record2.mValue.getType()) { - case ESM::VT_String: record2.mStr = data.toString().toUtf8().constData(); break; - case ESM::VT_Int: record2.mI = data.toInt(); break; - case ESM::VT_Float: record2.mF = data.toFloat(); break; + case ESM::VT_String: + + record2.mValue.setString (data.toString().toUtf8().constData()); + break; + + case ESM::VT_Int: + + record2.mValue.setInteger (data.toInt()); + break; + + case ESM::VT_Float: + + record2.mValue.setFloat (data.toFloat()); + break; default: break; } diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c59763f51..d4704b0c6 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include "idtable.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1dc11f2c4..efdb86400 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -569,7 +569,7 @@ void WindowManager::messageBox (const std::string& message, const std::vectorcreateMessageBox(message); } - + else { mMessageBoxManager->createInteractiveMessageBox(message, buttons); @@ -592,8 +592,9 @@ std::string WindowManager::getGameSettingString(const std::string &id, const std const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search(id); - if (setting && setting->mType == ESM::VT_String) - return setting->getString(); + if (setting && setting->mValue.getType()==ESM::VT_String) + return setting->mValue.getString(); + return default_; } @@ -774,8 +775,8 @@ void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _r const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().find(tag); - if (setting && setting->mType == ESM::VT_String) - _result = setting->getString(); + if (setting && setting->mValue.getType()==ESM::VT_String) + _result = setting->mValue.getString(); else _result = tag; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 90f26096e..1de0559d9 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -198,7 +198,7 @@ namespace MWWorld for (std::vector::size_type i = 0; i < master.size(); i++, idx++) { boost::filesystem::path masterPath (fileCollections.getCollection (".esm").getPath (master[i])); - + std::cout << "Loading ESM " << masterPath.string() << "\n"; // This parses the ESM file @@ -210,11 +210,11 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } - + for (std::vector::size_type i = 0; i < plugins.size(); i++, idx++) { boost::filesystem::path pluginPath (fileCollections.getCollection (".esp").getPath (plugins[i])); - + std::cout << "Loading ESP " << pluginPath.string() << "\n"; // This parses the ESP file @@ -226,7 +226,7 @@ namespace MWWorld mEsm[idx] = lEsm; mStore.load (mEsm[idx]); } - + mStore.setUp(); mPlayer = new MWWorld::Player (mStore.get().find ("player"), *this); @@ -363,10 +363,8 @@ namespace MWWorld const ESM::GameSetting *setting = MWBase::Environment::get().getWorld()->getStore().get().search("sDefaultCellname"); - if (setting && setting->mType == ESM::VT_String) - name = setting->getString(); - else - name = "Wilderness"; + if (setting && setting->mValue.getType()==ESM::VT_String) + name = setting->mValue.getString(); } } diff --git a/components/esm/loadgmst.cpp b/components/esm/loadgmst.cpp index e9852ec07..fe1cc1b04 100644 --- a/components/esm/loadgmst.cpp +++ b/components/esm/loadgmst.cpp @@ -1,104 +1,39 @@ #include "loadgmst.hpp" -#include - -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { - -void GameSetting::load(ESMReader &esm) -{ - assert(mId != ""); - - // We are apparently allowed to be empty - if (!esm.hasMoreSubs()) + void GameSetting::load (ESMReader &esm) { - mType = VT_None; - return; + mValue.read (esm, ESM::Variant::Format_Gmst); } - // Load some data - esm.getSubName(); - NAME n = esm.retSubName(); - if (n == "STRV") + void GameSetting::save (ESMWriter &esm) { - mStr = esm.getHString(); - mType = VT_String; + mValue.write (esm, ESM::Variant::Format_Gmst); } - else if (n == "INTV") - { - esm.getHT(mI); - mType = VT_Int; - } - else if (n == "FLTV") - { - esm.getHT(mF); - mType = VT_Float; - } - else - esm.fail("Unwanted subrecord type"); -} -void GameSetting::save(ESMWriter &esm) -{ - switch(mType) + int GameSetting::getInt() const { - case VT_String: esm.writeHNString("STRV", mStr); break; - case VT_Int: esm.writeHNT("INTV", mI); break; - case VT_Float: esm.writeHNT("FLTV", mF); break; - default: break; + return mValue.getInteger(); } -} -int GameSetting::getInt() const -{ - switch (mType) + float GameSetting::getFloat() const { - case VT_Float: return static_cast (mF); - case VT_Int: return mI; - default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type"); + return mValue.getFloat(); } -} -float GameSetting::getFloat() const -{ - switch (mType) + std::string GameSetting::getString() const { - case VT_Float: return mF; - case VT_Int: return mI; - default: throw std::runtime_error ("GMST " + mId + " is not of a numeric type"); + return mValue.getString(); } -} - -std::string GameSetting::getString() const -{ - if (mType==VT_String) - return mStr; - - throw std::runtime_error ("GMST " + mId + " is not a string"); -} void GameSetting::blank() { - mStr.clear(); - mI = 0; - mF = 0; - mType = VT_Float; + mValue.setType (ESM::VT_None); } bool operator== (const GameSetting& left, const GameSetting& right) { - if (left.mType!=right.mType) - return false; - - switch (left.mType) - { - case VT_Float: return left.mF==right.mF; - case VT_Int: return left.mI==right.mI; - case VT_String: return left.mStr==right.mStr; - default: return false; - } + return left.mValue==right.mValue; } } diff --git a/components/esm/loadgmst.hpp b/components/esm/loadgmst.hpp index 12f212081..a6e0c2ecb 100644 --- a/components/esm/loadgmst.hpp +++ b/components/esm/loadgmst.hpp @@ -3,7 +3,6 @@ #include -#include "defs.hpp" #include "variant.hpp" namespace ESM @@ -20,14 +19,13 @@ class ESMWriter; struct GameSetting { std::string mId; - // One of these is used depending on the variable type - std::string mStr; - int mI; - float mF; - VarType mType; + + Variant mValue; void load(ESMReader &esm); + /// \todo remove the get* functions (redundant, since mValue as equivalent functions now). + int getInt() const; ///< Throws an exception if GMST is not of type int or float. From 1b19ab6028929cc6384afaf8c634cd84abeb2817 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 08:15:03 +0100 Subject: [PATCH 7/9] fixed gmst integers --- components/esm/variantimp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index e99cc50b5..1b8cf4f87 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -156,8 +156,8 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT } else // GMST { - if (type==VT_Int) - esm.fail ("unsupported global variable integer type"); + if (type!=VT_Int) + esm.fail ("unsupported gmst variable integer type"); esm.getHT (mValue); } From 1489570b097bc31103fa1e03ec49ba2081a61a6c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 09:40:41 +0100 Subject: [PATCH 8/9] change variant in info record to new type --- apps/esmtool/record.cpp | 9 ++--- apps/openmw/mwdialogue/selectwrapper.cpp | 9 +++-- components/esm/loadinfo.cpp | 25 ++----------- components/esm/loadinfo.hpp | 46 ++---------------------- components/esm/variant.cpp | 21 ++++++++++- components/esm/variant.hpp | 3 +- components/esm/variantimp.cpp | 32 +++++++++++++---- 7 files changed, 59 insertions(+), 86 deletions(-) diff --git a/apps/esmtool/record.cpp b/apps/esmtool/record.cpp index e4de63dd4..38fddd6b9 100644 --- a/apps/esmtool/record.cpp +++ b/apps/esmtool/record.cpp @@ -112,14 +112,11 @@ std::string ruleString(ESM::DialInfo::SelectStruct ss) case '5': oper_str = ">="; break; } - std::string value_str = "??"; - if (ss.mType == ESM::VT_Int) - value_str = str(boost::format("%d") % ss.mI); - else if (ss.mType == ESM::VT_Float) - value_str = str(boost::format("%f") % ss.mF); + std::ostringstream stream; + stream << ss.mValue; std::string result = str(boost::format("%-12s %-32s %2s %s") - % type_str % func_str % oper_str % value_str); + % type_str % func_str % oper_str % stream.str()); return result; } diff --git a/apps/openmw/mwdialogue/selectwrapper.cpp b/apps/openmw/mwdialogue/selectwrapper.cpp index 9cc528a11..9d705f6be 100644 --- a/apps/openmw/mwdialogue/selectwrapper.cpp +++ b/apps/openmw/mwdialogue/selectwrapper.cpp @@ -31,14 +31,13 @@ namespace template bool selectCompareImp (const ESM::DialInfo::SelectStruct& select, T value1) { - if (select.mType==ESM::VT_Short || select.mType==ESM::VT_Int || - select.mType==ESM::VT_Long) + if (select.mValue.getType()==ESM::VT_Int) { - return selectCompareImp (select.mSelectRule[4], value1, select.mI); + return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getInteger()); } - else if (select.mType==ESM::VT_Float) + else if (select.mValue.getType()==ESM::VT_Float) { - return selectCompareImp (select.mSelectRule[4], value1, select.mF); + return selectCompareImp (select.mSelectRule[4], value1, select.mValue.getFloat()); } else throw std::runtime_error ( diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp index f237cf780..90f8fcf35 100644 --- a/components/esm/loadinfo.cpp +++ b/components/esm/loadinfo.cpp @@ -84,22 +84,8 @@ void DialInfo::load(ESMReader &esm) SelectStruct ss; ss.mSelectRule = esm.getHString(); - esm.isEmptyOrGetName(); - if (subName.val == REC_INTV) - { - ss.mType = VT_Int; - esm.getHT(ss.mI); - } - else if (subName.val == REC_FLTV) - { - ss.mType = VT_Float; - esm.getHT(ss.mF); - } - else - esm.fail( - "INFO.SCVR must precede INTV or FLTV, not " - + subName.toString()); + ss.mValue.read (esm, Variant::Format_Info); mSelects.push_back(ss); @@ -152,16 +138,11 @@ void DialInfo::save(ESMWriter &esm) for (std::vector::iterator it = mSelects.begin(); it != mSelects.end(); ++it) { esm.writeHNString("SCVR", it->mSelectRule); - switch(it->mType) - { - case VT_Int: esm.writeHNT("INTV", it->mI); break; - case VT_Float: esm.writeHNT("FLTV", it->mF); break; - default: break; - } + it->mValue.write (esm, Variant::Format_Info); } esm.writeHNOString("BNAM", mResultScript); - + switch(mQuestStatus) { case QS_Name: esm.writeHNT("QSTN",'\1'); break; diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp index ca08c3b55..2361ed9eb 100644 --- a/components/esm/loadinfo.hpp +++ b/components/esm/loadinfo.hpp @@ -13,8 +13,6 @@ namespace ESM class ESMReader; class ESMWriter; -// NOT DONE - /* * Dialogue information. A series of these follow after DIAL records, * and form a linked list of dialogue items. @@ -44,9 +42,7 @@ struct DialInfo struct SelectStruct { std::string mSelectRule; // This has a complicated format - float mF; // Only one of 'f' or 'i' is used - int mI; - VarType mType; + Variant mValue; }; // Journal quest indices (introduced with the quest system in Tribunal) @@ -94,8 +90,7 @@ struct DialInfo REC_SNAM = 0x4d414e53, REC_NAME = 0x454d414e, REC_SCVR = 0x52564353, - REC_INTV = 0x56544e49, - REC_FLTV = 0x56544c46, + REC_BNAM = 0x4d414e42, REC_QSTN = 0x4e545351, REC_QSTF = 0x46545351, @@ -107,42 +102,5 @@ struct DialInfo void save(ESMWriter &esm); }; -/* - Some old and unused D code and comments, that might be useful later: - -------- - - // We only need to put each item in ONE list. For if your NPC - // matches this response, then it must match ALL criteria, thus it - // will have to look up itself in all the lists. I think the order - // is well optimized in making the lists as small as possible. - if(this.actor.index != -1) actorDial[this.actor][parent]++; - else if(cell != "") cellDial[cell][parent]++; - else if(this.Class != -1) classDial[this.Class][parent]++; - else if(this.npcFaction != -1) - factionDial[this.npcFaction][parent]++; - else if(this.race != -1) raceDial[this.race][parent]++; - else allDial[parent]++; // Lists dialogues that might - // apply to all npcs. - */ - -// List of dialogue topics (and greetings, voices, etc.) that -// reference other objects. Eg. raceDial is indexed by the indices of -// all races referenced. The value of raceDial is a new AA, which is -// basically used as a map (the int value is just a count and isn't -// used for anything important.) The indices (or elements of the map) -// are the dialogues that reference the given race. I use an AA -// instead of a list or array, since each dialogue can be added lots -// of times. - -/* -int allDial[Dialogue*]; -int classDial[int][Dialogue*]; -int factionDial[int][Dialogue*]; -int actorDial[Item][Dialogue*]; -// If I look up cells on cell load, I don't have to resolve these -// names into anything! -int cellDial[char[]][Dialogue*]; -int raceDial[int][Dialogue*]; -*/ } #endif diff --git a/components/esm/variant.cpp b/components/esm/variant.cpp index 98786c20e..d25072e54 100644 --- a/components/esm/variant.cpp +++ b/components/esm/variant.cpp @@ -79,7 +79,7 @@ void ESM::Variant::read (ESMReader& esm, Format format) else esm.fail ("illegal global variable type " + typeId); } - else // GMST + else if (format==Format_Gmst) { if (!esm.hasMoreSubs()) { @@ -106,6 +106,22 @@ void ESM::Variant::read (ESMReader& esm, Format format) esm.fail ("invalid subrecord: " + name.toString()); } } + else // info + { + esm.getSubName(); + NAME name = esm.retSubName(); + + if (name=="INTV") + { + type = VT_Int; + } + else if (name=="FLTV") + { + type = VT_Float; + } + else + esm.fail ("invalid subrecord: " + name.toString()); + } setType (type); @@ -125,6 +141,9 @@ void ESM::Variant::write (ESMWriter& esm, Format format) const if (format==Format_Global) throw std::runtime_error ("can not serialise variant of type none to global format"); + if (format==Format_Info) + throw std::runtime_error ("can not serialise variant of type none to info format"); + // nothing to do here for GMST format } else diff --git a/components/esm/variant.hpp b/components/esm/variant.hpp index b78d647a8..8c5f3b3d4 100644 --- a/components/esm/variant.hpp +++ b/components/esm/variant.hpp @@ -32,7 +32,8 @@ namespace ESM enum Format { Format_Global, - Format_Gmst + Format_Gmst, + Format_Info }; Variant(); diff --git a/components/esm/variantimp.cpp b/components/esm/variantimp.cpp index 1b8cf4f87..160402aa4 100644 --- a/components/esm/variantimp.cpp +++ b/components/esm/variantimp.cpp @@ -78,6 +78,9 @@ void ESM::VariantStringData::read (ESMReader& esm, Variant::Format format, VarTy if (format==Variant::Format_Global) esm.fail ("global variables of type string not supported"); + if (format==Variant::Format_Info) + esm.fail ("info variables of type string not supported"); + // GMST mValue = esm.getHString(); } @@ -90,6 +93,9 @@ void ESM::VariantStringData::write (ESMWriter& esm, Variant::Format format, VarT if (format==Variant::Format_Global) throw std::runtime_error ("global variables of type string not supported"); + if (format==Variant::Format_Info) + throw std::runtime_error ("info variables of type string not supported"); + // GMST esm.writeHNString ("STRV", mValue); } @@ -154,10 +160,16 @@ void ESM::VariantIntegerData::read (ESMReader& esm, Variant::Format format, VarT else esm.fail ("unsupported global variable integer type"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type!=VT_Int) - esm.fail ("unsupported gmst variable integer type"); + { + std::ostringstream stream; + stream + << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") + << " variable integer type"; + esm.fail (stream.str()); + } esm.getHT (mValue); } @@ -179,10 +191,16 @@ void ESM::VariantIntegerData::write (ESMWriter& esm, Variant::Format format, Var else throw std::runtime_error ("unsupported global variable integer type"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { if (type==VT_Int) - throw std::runtime_error ("unsupported global variable integer type"); + { + std::ostringstream stream; + stream + << "unsupported " <<(format==Variant::Format_Gmst ? "gmst" : "info") + << " variable integer type"; + throw std::runtime_error (stream.str()); + } esm.writeHNT ("INTV", mValue); } @@ -234,7 +252,7 @@ void ESM::VariantFloatData::read (ESMReader& esm, Variant::Format format, VarTyp { esm.getHNT (mValue, "FLTV"); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { esm.getHT (mValue); } @@ -250,9 +268,9 @@ void ESM::VariantFloatData::write (ESMWriter& esm, Variant::Format format, VarTy esm.writeHNString ("FNAM", "f"); esm.writeHNT ("FLTV", mValue); } - else // GMST + else if (format==Variant::Format_Gmst || format==Variant::Format_Info) { - esm.writeHNT ("INTV", mValue); + esm.writeHNT ("FLTV", mValue); } } From 46de45b9a2a70ad4a67995a690a5ed2265f835c9 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 5 Mar 2013 11:37:13 +0100 Subject: [PATCH 9/9] added var type column to globals --- apps/opencs/model/doc/document.cpp | 2 +- apps/opencs/model/world/columnbase.hpp | 3 ++- apps/opencs/model/world/columns.hpp | 20 ++++++++++++++++---- apps/opencs/model/world/data.cpp | 5 +++-- apps/opencs/view/doc/viewmanager.cpp | 6 +++++- apps/opencs/view/world/vartypedelegate.cpp | 2 +- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 6a76b0b6c..e709cc5bf 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -152,7 +152,7 @@ void CSMDoc::Document::addOptionalGlobals() { ESM::Global global; global.mId = sGlobals[i]; - global.mValue.setType (ESM::VT_Int); + global.mValue.setType (ESM::VT_Long); addOptionalGlobal (global); } } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 40581972e..c44abda2b 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -30,7 +30,8 @@ namespace CSMWorld Display_Integer, Display_Float, Display_Var, - Display_VarType + Display_GmstVarType, + Display_GlobalVarType }; std::string mTitle; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 270987ec1..018825831 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -96,7 +96,7 @@ namespace CSMWorld template struct VarTypeColumn : public Column { - VarTypeColumn() : Column ("Type", ColumnBase::Display_VarType) {} + VarTypeColumn (ColumnBase::Display display) : Column ("Type", display) {} virtual QVariant get (const Record& record) const { @@ -125,9 +125,19 @@ namespace CSMWorld { switch (record.get().mValue.getType()) { - case ESM::VT_String: return record.get().mValue.getString().c_str(); break; - case ESM::VT_Int: return record.get().mValue.getInteger(); break; - case ESM::VT_Float: return record.get().mValue.getFloat(); break; + case ESM::VT_String: + + return record.get().mValue.getString().c_str(); break; + + case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: + + return record.get().mValue.getInteger(); break; + + case ESM::VT_Float: + + return record.get().mValue.getFloat(); break; default: return QVariant(); } @@ -145,6 +155,8 @@ namespace CSMWorld break; case ESM::VT_Int: + case ESM::VT_Short: + case ESM::VT_Long: record2.mValue.setInteger (data.toInt()); break; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index d4704b0c6..bbd8667b3 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -27,12 +27,13 @@ CSMWorld::Data::Data() mGlobals.addColumn (new StringIdColumn); mGlobals.addColumn (new RecordStateColumn); mGlobals.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Global)); - mGlobals.addColumn (new FloatValueColumn); + mGlobals.addColumn (new VarTypeColumn (ColumnBase::Display_GlobalVarType)); + mGlobals.addColumn (new VarValueColumn); mGmsts.addColumn (new StringIdColumn); mGmsts.addColumn (new RecordStateColumn); mGmsts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Gmst)); - mGmsts.addColumn (new VarTypeColumn); + mGmsts.addColumn (new VarTypeColumn (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index a8faefb97..718b80728 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -35,8 +35,12 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection; - mDelegateFactories->add (CSMWorld::ColumnBase::Display_VarType, + mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType, new CSVWorld::VarTypeDelegateFactory (ESM::VT_None, ESM::VT_String, ESM::VT_Int, ESM::VT_Float)); + + mDelegateFactories->add (CSMWorld::ColumnBase::Display_GlobalVarType, + new CSVWorld::VarTypeDelegateFactory (ESM::VT_Short, ESM::VT_Long, ESM::VT_Float)); + } CSVDoc::ViewManager::~ViewManager() diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index 3ee759ef2..72cbaae42 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -85,7 +85,7 @@ void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) { { ESM::VT_None, "empty" }, { ESM::VT_Short, "short" }, - { ESM::VT_Int, "long" }, + { ESM::VT_Int, "integer" }, { ESM::VT_Long, "long" }, { ESM::VT_Float, "float" }, { ESM::VT_String, "string" },