Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
7.1 kB · 278 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279#include "variant.hpp"
#include <stdexcept>
#include "esmreader.hpp"#include "variantimp.hpp"
namespace ESM{ namespace { constexpr uint32_t STRV = fourCC("STRV"); constexpr uint32_t INTV = fourCC("INTV"); constexpr uint32_t FLTV = fourCC("FLTV"); constexpr uint32_t STTV = fourCC("STTV");
template <typename T, bool orDefault = false> struct GetValue { constexpr T operator()(int32_t value) const { return static_cast<T>(value); }
constexpr T operator()(float value) const { return static_cast<T>(value); }
template <typename V> constexpr T operator()(const V&) const { if constexpr (orDefault) return T{}; else throw std::runtime_error("cannot convert variant"); } };
template <typename T> struct SetValue { T mValue;
explicit SetValue(T value) : mValue(value) { }
void operator()(int32_t& value) const { value = static_cast<int32_t>(mValue); }
void operator()(float& value) const { value = static_cast<float>(mValue); }
template <typename V> void operator()(V&) const { throw std::runtime_error("cannot convert variant"); } }; }
const std::string& Variant::getString() const { return std::get<std::string>(mData); }
int32_t Variant::getInteger() const { return std::visit(GetValue<int32_t>{}, mData); }
float Variant::getFloat() const { return std::visit(GetValue<float>{}, mData); }
void 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 if (format == Format_Gmst) { if (!esm.hasMoreSubs()) { type = VT_None; } else { 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()); } } else if (format == Format_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()); } else if (format == Format_Local) { esm.getSubName(); NAME name = esm.retSubName();
if (name == INTV) { type = VT_Int; } else if (name == FLTV) { type = VT_Float; } else if (name == STTV) { type = VT_Short; } else esm.fail("invalid subrecord: " + name.toString()); }
setType(type);
std::visit(ReadESMVariantValue{ esm, format, mType }, mData); }
void 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");
if (format == Format_Info) throw std::runtime_error("can not serialise variant of type none to info format");
if (format == Format_Local) throw std::runtime_error("can not serialise variant of type none to local format");
// nothing to do here for GMST format } else std::visit(WriteESMVariantValue{ esm, format, mType }, mData); }
void 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: " << std::get<int32_t>(mData); break;
case VT_Int:
stream << "variant int: " << std::get<int32_t>(mData); break;
case VT_Long:
stream << "variant long: " << std::get<int32_t>(mData); break;
case VT_Float:
stream << "variant float: " << std::get<float>(mData); break;
case VT_String:
stream << "variant string: \"" << std::get<std::string>(mData) << "\""; break; } }
void Variant::setType(VarType type) { if (type != mType) { switch (type) { case VT_Unknown: case VT_None: mData = std::monostate{}; break;
case VT_Short: case VT_Int: case VT_Long: mData = std::visit(GetValue<int, true>{}, mData); break;
case VT_Float: mData = std::visit(GetValue<float, true>{}, mData); break;
case VT_String: mData = std::string{}; break; }
mType = type; } }
void Variant::setString(const std::string& value) { std::get<std::string>(mData) = value; }
void Variant::setString(std::string&& value) { std::get<std::string>(mData) = std::move(value); }
void Variant::setInteger(int32_t value) { std::visit(SetValue(value), mData); }
void Variant::setFloat(float value) { std::visit(SetValue(value), mData); }
std::ostream& operator<<(std::ostream& stream, const Variant& value) { value.write(stream); return stream; }
}