From 3655ef16af864b7c50c003e2c8905f06b7bb15cf Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Tue, 7 Jul 2015 19:16:32 +0200 Subject: [PATCH 1/4] Explicitly instantiate ESM::StatState --- apps/essimporter/convertplayer.cpp | 2 + apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 1 + apps/openmw/mwgui/inventorywindow.cpp | 2 + apps/openmw/mwgui/mapwindow.cpp | 1 + apps/openmw/mwgui/quickkeysmenu.cpp | 1 + apps/openmw/mwgui/windowmanagerimp.cpp | 3 ++ apps/openmw/mwmechanics/actors.cpp | 2 + apps/openmw/mwmechanics/creaturestats.cpp | 2 + .../mwmechanics/mechanicsmanagerimp.cpp | 1 + apps/openmw/mwmechanics/stat.hpp | 1 + apps/openmw/mwworld/cellstore.cpp | 1 + apps/openmw/mwworld/projectilemanager.cpp | 1 + apps/openmw/mwworld/worldimp.cpp | 3 ++ components/esm/creaturestats.cpp | 2 + components/esm/statstate.cpp | 52 +++++++++++++++++++ components/esm/statstate.hpp | 48 ++--------------- 16 files changed, 78 insertions(+), 45 deletions(-) create mode 100644 components/esm/statstate.cpp diff --git a/apps/essimporter/convertplayer.cpp b/apps/essimporter/convertplayer.cpp index af0119a46..5718201f7 100644 --- a/apps/essimporter/convertplayer.cpp +++ b/apps/essimporter/convertplayer.cpp @@ -1,5 +1,7 @@ #include "convertplayer.hpp" +#include + namespace ESSImport { diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 139862a5a..042267ebe 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 3ecfc64b2..52ff2ee10 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include diff --git a/apps/openmw/mwgui/mapwindow.cpp b/apps/openmw/mwgui/mapwindow.cpp index 3e855c4d0..442fbeb08 100644 --- a/apps/openmw/mwgui/mapwindow.cpp +++ b/apps/openmw/mwgui/mapwindow.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index 01d0a339b..8c919e8bd 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwworld/inventorystore.hpp" diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 515265bd9..9cf957522 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -22,6 +22,9 @@ #include +#include +#include + #include #include diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index f0b47ac7b..5f8b70651 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -4,6 +4,8 @@ #include +#include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index f480efc71..48374c173 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 7bc6a34ae..fef99dc61 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -6,6 +6,7 @@ #include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 64cc66520..0820d2015 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWMECHANICS_STAT_H #define GAME_MWMECHANICS_STAT_H +#include #include #include diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 4e6c6f116..b33a6f8db 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index f083bcb4a..6295ed159 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 4b14ea602..ff82160d1 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -12,6 +12,9 @@ #include #include +#include +#include + #include #include diff --git a/components/esm/creaturestats.cpp b/components/esm/creaturestats.cpp index 89d865c1d..9bdbf9668 100644 --- a/components/esm/creaturestats.cpp +++ b/components/esm/creaturestats.cpp @@ -1,4 +1,6 @@ #include "creaturestats.hpp" +#include "esmreader.hpp" +#include "esmwriter.hpp" void ESM::CreatureStats::load (ESMReader &esm) { diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp new file mode 100644 index 000000000..e95295cc9 --- /dev/null +++ b/components/esm/statstate.cpp @@ -0,0 +1,52 @@ +#include "statstate.hpp" + +#include "esmreader.hpp" +#include "esmwriter.hpp" + +namespace ESM +{ + template + StatState::StatState() : mBase(0), mMod(0), mCurrent(0), mDamage(0), mProgress(0) {} + + template + void StatState::load(ESMReader &esm) + { + esm.getHNT(mBase, "STBA"); + + mMod = 0; + esm.getHNOT(mMod, "STMO"); + mCurrent = 0; + esm.getHNOT(mCurrent, "STCU"); + + // mDamage was changed to a float; ensure backwards compatibility + T oldDamage = 0; + esm.getHNOT(oldDamage, "STDA"); + mDamage = static_cast(oldDamage); + + esm.getHNOT(mDamage, "STDF"); + + mProgress = 0; + esm.getHNOT(mProgress, "STPR"); + } + + template + void StatState::save(ESMWriter &esm) const + { + esm.writeHNT("STBA", mBase); + + if (mMod != 0) + esm.writeHNT("STMO", mMod); + + if (mCurrent) + esm.writeHNT("STCU", mCurrent); + + if (mDamage) + esm.writeHNT("STDF", mDamage); + + if (mProgress) + esm.writeHNT("STPR", mProgress); + } + + template class StatState; + template class StatState; +} diff --git a/components/esm/statstate.hpp b/components/esm/statstate.hpp index f57ba9f30..47aeb0331 100644 --- a/components/esm/statstate.hpp +++ b/components/esm/statstate.hpp @@ -1,11 +1,11 @@ #ifndef OPENMW_ESM_STATSTATE_H #define OPENMW_ESM_STATSTATE_H -#include "esmreader.hpp" -#include "esmwriter.hpp" - namespace ESM { + class ESMReader; + class ESMWriter; + // format 0, saved games only template @@ -23,48 +23,6 @@ namespace ESM void load (ESMReader &esm); void save (ESMWriter &esm) const; }; - - template - StatState::StatState() : mBase (0), mMod (0), mCurrent (0), mDamage (0), mProgress (0) {} - - template - void StatState::load (ESMReader &esm) - { - esm.getHNT (mBase, "STBA"); - - mMod = 0; - esm.getHNOT (mMod, "STMO"); - mCurrent = 0; - esm.getHNOT (mCurrent, "STCU"); - - // mDamage was changed to a float; ensure backwards compatibility - T oldDamage = 0; - esm.getHNOT(oldDamage, "STDA"); - mDamage = static_cast(oldDamage); - - esm.getHNOT (mDamage, "STDF"); - - mProgress = 0; - esm.getHNOT (mProgress, "STPR"); - } - - template - void StatState::save (ESMWriter &esm) const - { - esm.writeHNT ("STBA", mBase); - - if (mMod != 0) - esm.writeHNT ("STMO", mMod); - - if (mCurrent) - esm.writeHNT ("STCU", mCurrent); - - if (mDamage) - esm.writeHNT ("STDF", mDamage); - - if (mProgress) - esm.writeHNT ("STPR", mProgress); - } } #endif From b1cc74dd9a6b05d6bbe728b7601afd0cda972c62 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 14:41:37 +0200 Subject: [PATCH 2/4] Explicity instantiate MWMechanics::Stat --- apps/openmw/mwgui/inventorywindow.cpp | 2 + apps/openmw/mwmechanics/actors.cpp | 1 + apps/openmw/mwmechanics/stat.cpp | 290 ++++++++++++++++++++++++-- apps/openmw/mwmechanics/stat.hpp | 219 +++++-------------- apps/openmw/mwworld/worldimp.cpp | 1 + 5 files changed, 321 insertions(+), 192 deletions(-) diff --git a/apps/openmw/mwgui/inventorywindow.cpp b/apps/openmw/mwgui/inventorywindow.cpp index 52ff2ee10..392a4a84a 100644 --- a/apps/openmw/mwgui/inventorywindow.cpp +++ b/apps/openmw/mwgui/inventorywindow.cpp @@ -16,6 +16,8 @@ #include +#include + #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/soundmanager.hpp" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 5f8b70651..d9a8ce72f 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "../mwworld/esmstore.hpp" #include "../mwworld/class.hpp" diff --git a/apps/openmw/mwmechanics/stat.cpp b/apps/openmw/mwmechanics/stat.cpp index 1b909d579..6eb5e0246 100644 --- a/apps/openmw/mwmechanics/stat.cpp +++ b/apps/openmw/mwmechanics/stat.cpp @@ -1,28 +1,276 @@ - #include "stat.hpp" -void MWMechanics::AttributeValue::writeState (ESM::StatState& state) const -{ - state.mBase = mBase; - state.mMod = mModifier; - state.mDamage = mDamage; -} +#include -void MWMechanics::AttributeValue::readState (const ESM::StatState& state) +namespace MWMechanics { - mBase = state.mBase; - mModifier = state.mMod; - mDamage = state.mDamage; -} + template + Stat::Stat() : mBase (0), mModified (0) {} + template + Stat::Stat(T base) : mBase (base), mModified (base) {} + template + Stat::Stat(T base, T modified) : mBase (base), mModified (modified) {} -void MWMechanics::SkillValue::writeState (ESM::StatState& state) const -{ - AttributeValue::writeState (state); - state.mProgress = mProgress; -} + template + const T& Stat::getBase() const + { + return mBase; + } -void MWMechanics::SkillValue::readState (const ESM::StatState& state) -{ - AttributeValue::readState (state); - mProgress = state.mProgress; + template + T Stat::getModified() const + { + return std::max(static_cast(0), mModified); + } + template + T Stat::getModifier() const + { + return mModified-mBase; + } + template + void Stat::set (const T& value) + { + mBase = mModified = value; + } + template + void Stat::modify(const T& diff) + { + mBase += diff; + if(mBase >= static_cast(0)) + mModified += diff; + else + { + mModified += diff - mBase; + mBase = static_cast(0); + } + } + template + void Stat::setBase (const T& value) + { + T diff = value - mBase; + mBase = value; + mModified += diff; + } + template + void Stat::setModified (T value, const T& min, const T& max) + { + T diff = value - mModified; + + if (mBase+diffmax) + { + value = max + (mModified - mBase); + diff = value - mModified; + } + + mModified = value; + mBase += diff; + } + template + void Stat::setModifier (const T& modifier) + { + mModified = mBase + modifier; + } + + template + void Stat::writeState (ESM::StatState& state) const + { + state.mBase = mBase; + state.mMod = mModified; + } + template + void Stat::readState (const ESM::StatState& state) + { + mBase = state.mBase; + mModified = state.mMod; + } + + + template + DynamicStat::DynamicStat() : mStatic (0), mCurrent (0) {} + template + DynamicStat::DynamicStat(T base) : mStatic (base), mCurrent (base) {} + template + DynamicStat::DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {} + template + DynamicStat::DynamicStat(const Stat &stat, T current) : mStatic(stat), mCurrent (current) {} + + + template + const T& DynamicStat::getBase() const + { + return mStatic.getBase(); + } + template + T DynamicStat::getModified() const + { + return mStatic.getModified(); + } + template + const T& DynamicStat::getCurrent() const + { + return mCurrent; + } + + template + void DynamicStat::set (const T& value) + { + mStatic.set (value); + mCurrent = value; + } + template + void DynamicStat::setBase (const T& value) + { + mStatic.setBase (value); + + if (mCurrent>getModified()) + mCurrent = getModified(); + } + template + void DynamicStat::setModified (T value, const T& min, const T& max) + { + mStatic.setModified (value, min, max); + + if (mCurrent>getModified()) + mCurrent = getModified(); + } + template + void DynamicStat::modify (const T& diff, bool allowCurrentDecreaseBelowZero) + { + mStatic.modify (diff); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); + } + template + void DynamicStat::setCurrent (const T& value, bool allowDecreaseBelowZero) + { + if (value > mCurrent) + { + // increase + mCurrent = value; + + if (mCurrent > getModified()) + mCurrent = getModified(); + } + else if (value > 0 || allowDecreaseBelowZero) + { + // allowed decrease + mCurrent = value; + } + else if (mCurrent > 0) + { + // capped decrease + mCurrent = 0; + } + } + template + void DynamicStat::setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero) + { + T diff = modifier - mStatic.getModifier(); + mStatic.setModifier (modifier); + setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); + } + + template + void DynamicStat::writeState (ESM::StatState& state) const + { + mStatic.writeState (state); + state.mCurrent = mCurrent; + } + template + void DynamicStat::readState (const ESM::StatState& state) + { + mStatic.readState (state); + mCurrent = state.mCurrent; + } + + AttributeValue::AttributeValue() : + mBase(0), mModifier(0), mDamage(0) + { + } + + int AttributeValue::getModified() const + { + return std::max(0, mBase - (int) mDamage + mModifier); + } + int AttributeValue::getBase() const + { + return mBase; + } + int AttributeValue::getModifier() const + { + return mModifier; + } + + void AttributeValue::setBase(int base) + { + mBase = std::max(0, base); + } + + void AttributeValue::setModifier(int mod) + { + mModifier = mod; + } + + void AttributeValue::damage(float damage) + { + mDamage += std::min(damage, (float)getModified()); + } + void AttributeValue::restore(float amount) + { + mDamage -= std::min(mDamage, amount); + } + + float AttributeValue::getDamage() const + { + return mDamage; + } + + void AttributeValue::writeState (ESM::StatState& state) const + { + state.mBase = mBase; + state.mMod = mModifier; + state.mDamage = mDamage; + } + + void AttributeValue::readState (const ESM::StatState& state) + { + mBase = state.mBase; + mModifier = state.mMod; + mDamage = state.mDamage; + } + + SkillValue::SkillValue() : + mProgress(0) + { + } + + float SkillValue::getProgress() const + { + return mProgress; + } + void SkillValue::setProgress(float progress) + { + mProgress = progress; + } + + void SkillValue::writeState (ESM::StatState& state) const + { + AttributeValue::writeState (state); + state.mProgress = mProgress; + } + + void SkillValue::readState (const ESM::StatState& state) + { + AttributeValue::readState (state); + mProgress = state.mProgress; + } } + +template class MWMechanics::Stat; +template class MWMechanics::Stat; +template class MWMechanics::DynamicStat; +template class MWMechanics::DynamicStat; diff --git a/apps/openmw/mwmechanics/stat.hpp b/apps/openmw/mwmechanics/stat.hpp index 0820d2015..c075f5fa7 100644 --- a/apps/openmw/mwmechanics/stat.hpp +++ b/apps/openmw/mwmechanics/stat.hpp @@ -4,7 +4,11 @@ #include #include -#include +namespace ESM +{ + template + struct StatState; +} namespace MWMechanics { @@ -17,87 +21,28 @@ namespace MWMechanics public: typedef T Type; - Stat() : mBase (0), mModified (0) {} - Stat(T base) : mBase (base), mModified (base) {} - Stat(T base, T modified) : mBase (base), mModified (modified) {} - - const T& getBase() const - { - return mBase; - } + Stat(); + Stat(T base); + Stat(T base, T modified); - T getModified() const - { - return std::max(static_cast(0), mModified); - } + const T& getBase() const; - T getModifier() const - { - return mModified-mBase; - } + T getModified() const; + T getModifier() const; /// Set base and modified to \a value. - void set (const T& value) - { - mBase = mModified = value; - } - - void modify(const T& diff) - { - mBase += diff; - if(mBase >= static_cast(0)) - mModified += diff; - else - { - mModified += diff - mBase; - mBase = static_cast(0); - } - } + void set (const T& value); + void modify(const T& diff); /// Set base and adjust modified accordingly. - void setBase (const T& value) - { - T diff = value - mBase; - mBase = value; - mModified += diff; - } + void setBase (const T& value); /// Set modified value an adjust base accordingly. - void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) - { - T diff = value - mModified; - - if (mBase+diffmax) - { - value = max + (mModified - mBase); - diff = value - mModified; - } - - mModified = value; - mBase += diff; - } - - void setModifier (const T& modifier) - { - mModified = mBase + modifier; - } - - void writeState (ESM::StatState& state) const - { - state.mBase = mBase; - state.mMod = mModified; - } - - void readState (const ESM::StatState& state) - { - mBase = state.mBase; - mModified = state.mMod; - } + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()); + void setModifier (const T& modifier); + + void writeState (ESM::StatState& state) const; + void readState (const ESM::StatState& state); }; template @@ -122,98 +67,32 @@ namespace MWMechanics public: typedef T Type; - DynamicStat() : mStatic (0), mCurrent (0) {} - DynamicStat(T base) : mStatic (base), mCurrent (base) {} - DynamicStat(T base, T modified, T current) : mStatic(base, modified), mCurrent (current) {} - DynamicStat(const Stat &stat, T current) : mStatic(stat), mCurrent (current) {} - - const T& getBase() const - { - return mStatic.getBase(); - } - - T getModified() const - { - return mStatic.getModified(); - } + DynamicStat(); + DynamicStat(T base); + DynamicStat(T base, T modified, T current); + DynamicStat(const Stat &stat, T current); - const T& getCurrent() const - { - return mCurrent; - } + const T& getBase() const; + T getModified() const; + const T& getCurrent() const; /// Set base, modified and current to \a value. - void set (const T& value) - { - mStatic.set (value); - mCurrent = value; - } + void set (const T& value); /// Set base and adjust modified accordingly. - void setBase (const T& value) - { - mStatic.setBase (value); - - if (mCurrent>getModified()) - mCurrent = getModified(); - } + void setBase (const T& value); /// Set modified value an adjust base accordingly. - void setModified (T value, const T& min, const T& max = std::numeric_limits::max()) - { - mStatic.setModified (value, min, max); - - if (mCurrent>getModified()) - mCurrent = getModified(); - } + void setModified (T value, const T& min, const T& max = std::numeric_limits::max()); /// Change modified relatively. - void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false) - { - mStatic.modify (diff); - setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); - } - - void setCurrent (const T& value, bool allowDecreaseBelowZero = false) - { - if (value > mCurrent) - { - // increase - mCurrent = value; - - if (mCurrent > getModified()) - mCurrent = getModified(); - } - else if (value > 0 || allowDecreaseBelowZero) - { - // allowed decrease - mCurrent = value; - } - else if (mCurrent > 0) - { - // capped decrease - mCurrent = 0; - } - } - - void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false) - { - T diff = modifier - mStatic.getModifier(); - mStatic.setModifier (modifier); - setCurrent (getCurrent()+diff, allowCurrentDecreaseBelowZero); - } - - void writeState (ESM::StatState& state) const - { - mStatic.writeState (state); - state.mCurrent = mCurrent; - } - - void readState (const ESM::StatState& state) - { - mStatic.readState (state); - mCurrent = state.mCurrent; - } + void modify (const T& diff, bool allowCurrentDecreaseBelowZero=false); + + void setCurrent (const T& value, bool allowDecreaseBelowZero = false); + void setModifier (const T& modifier, bool allowCurrentDecreaseBelowZero=false); + + void writeState (ESM::StatState& state) const; + void readState (const ESM::StatState& state); }; template @@ -237,26 +116,25 @@ namespace MWMechanics float mDamage; // needs to be float to allow continuous damage public: - AttributeValue() : mBase(0), mModifier(0), mDamage(0) {} + AttributeValue(); - int getModified() const { return std::max(0, mBase - (int) mDamage + mModifier); } - int getBase() const { return mBase; } - int getModifier() const { return mModifier; } + int getModified() const; + int getBase() const; + int getModifier() const; - void setBase(int base) { mBase = std::max(0, base); } + void setBase(int base); - void setModifier(int mod) { mModifier = mod; } + void setModifier(int mod); // Maximum attribute damage is limited to the modified value. // Note: I think MW applies damage directly to mModified, since you can also // "restore" drained attributes. We need to rewrite the magic effect system to support this. - void damage(float damage) { mDamage += std::min(damage, (float)getModified()); } - void restore(float amount) { mDamage -= std::min(mDamage, amount); } + void damage(float damage); + void restore(float amount); - float getDamage() const { return mDamage; } + float getDamage() const; void writeState (ESM::StatState& state) const; - void readState (const ESM::StatState& state); }; @@ -264,12 +142,11 @@ namespace MWMechanics { float mProgress; public: - SkillValue() : mProgress(0) {} - float getProgress() const { return mProgress; } - void setProgress(float progress) { mProgress = progress; } + SkillValue(); + float getProgress() const; + void setProgress(float progress); void writeState (ESM::StatState& state) const; - void readState (const ESM::StatState& state); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ff82160d1..3b57e22c5 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include From b3b55a584265b8a7e0a7453ddc3448277633d276 Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 19:22:04 +0200 Subject: [PATCH 3/4] Explicitly instantiate MWWorld::Store --- apps/openmw/mwmechanics/spells.cpp | 1 + apps/openmw/mwscript/globalscripts.cpp | 1 + apps/openmw/mwstate/statemanagerimp.cpp | 2 + apps/openmw/mwworld/cells.cpp | 1 + apps/openmw/mwworld/esmstore.cpp | 1 + apps/openmw/mwworld/esmstore.hpp | 1 + apps/openmw/mwworld/inventorystore.cpp | 1 + apps/openmw/mwworld/scene.cpp | 1 + apps/openmw/mwworld/store.cpp | 1181 +++++++++++++++++++++-- apps/openmw/mwworld/store.hpp | 932 +++--------------- apps/openmw/mwworld/weather.cpp | 1 + apps/openmw/mwworld/worldimp.hpp | 5 + 12 files changed, 1205 insertions(+), 923 deletions(-) diff --git a/apps/openmw/mwmechanics/spells.cpp b/apps/openmw/mwmechanics/spells.cpp index e3646d829..fe0f892db 100644 --- a/apps/openmw/mwmechanics/spells.cpp +++ b/apps/openmw/mwmechanics/spells.cpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwscript/globalscripts.cpp b/apps/openmw/mwscript/globalscripts.cpp index a6ad2cc11..44d96e949 100644 --- a/apps/openmw/mwscript/globalscripts.cpp +++ b/apps/openmw/mwscript/globalscripts.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include "../mwworld/esmstore.hpp" diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 192ad45fb..ac8dc863a 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -6,6 +6,8 @@ #include #include +#include + #include #include diff --git a/apps/openmw/mwworld/cells.cpp b/apps/openmw/mwworld/cells.cpp index 2aa817fa5..b096301fd 100644 --- a/apps/openmw/mwworld/cells.cpp +++ b/apps/openmw/mwworld/cells.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 5d9beecb6..dea468d22 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace MWWorld { diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 05b633956..a14f6368e 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -1,6 +1,7 @@ #ifndef OPENMW_MWWORLD_ESMSTORE_H #define OPENMW_MWWORLD_ESMSTORE_H +#include #include #include diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 3fe86a511..6c283bb3e 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db26b4f2a..8029cb773 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index cdcc00b4d..96c711896 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -2,126 +2,1105 @@ #include "esmstore.hpp" #include +#include -namespace MWWorld { +#include +#include -void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) +#include +#include + +namespace { - //Handling MovedCellRefs, there is no way to do it inside loadcell - while (esm.isNextSub("MVRF")) { - ESM::CellRef ref; - ESM::MovedCellRef cMRef; - cell->getNextMVRF(esm, cMRef); - - ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); - - // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following - // implementation when the oher implementation works as well. - bool deleted = false; - cell->getNextRef(esm, ref, deleted); - - // Add data required to make reference appear in the correct cell. - // We should not need to test for duplicates, as this part of the code is pre-cell merge. - cell->mMovedRefs.push_back(cMRef); - // But there may be duplicates here! - if (!deleted) + template + class GetRecords + { + const std::string mFind; + std::vector *mRecords; + + public: + GetRecords(const std::string &str, std::vector *records) + : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) + { } + + void operator()(const T *item) { - ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); - if (iter == cellAlt->mLeasedRefs.end()) - cellAlt->mLeasedRefs.push_back(ref); - else - *iter = ref; + if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) + mRecords->push_back(item); } - } + }; + + struct Compare + { + bool operator()(const ESM::Land *x, const ESM::Land *y) { + if (x->mX == y->mX) { + return x->mY < y->mY; + } + return x->mX < y->mX; + } + }; } -void Store::load(ESM::ESMReader &esm, const std::string &id) +namespace MWWorld { - // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, - // and we merge all this data into one Cell object. However, we can't simply search for the cell id, - // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they - // are not available until both cells have been loaded at least partially! - - // All cells have a name record, even nameless exterior cells. - std::string idLower = Misc::StringUtils::lowerCase(id); - ESM::Cell cell; - cell.mName = id; - - // Load the (x,y) coordinates of the cell, if it is an exterior cell, - // so we can find the cell we need to merge with - cell.loadData(esm); - - if(cell.mData.mFlags & ESM::Cell::Interior) - { - // Store interior cell by name, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(idLower)); - if (oldcell) { - // merge new cell into old cell - // push the new references on the list of references to manage (saveContext = true) - oldcell->mData = cell.mData; - oldcell->mName = cell.mName; // merge name just to be sure (ID will be the same, but case could have been changed) - oldcell->loadCell(esm, true); - } else + template + IndexedStore::IndexedStore() + { + } + template + typename IndexedStore::iterator IndexedStore::begin() const + { + return mStatic.begin(); + } + template + typename IndexedStore::iterator IndexedStore::end() const + { + return mStatic.end(); + } + template + void IndexedStore::load(ESM::ESMReader &esm) + { + T record; + record.load(esm); + + // Try to overwrite existing record + std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); + if (!ret.second) + ret.first->second = record; + } + template + int IndexedStore::getSize() const + { + return mStatic.size(); + } + template + void IndexedStore::setUp() + { + } + template + const T *IndexedStore::search(int index) const + { + typename Static::const_iterator it = mStatic.find(index); + if (it != mStatic.end()) + return &(it->second); + return NULL; + } + template + const T *IndexedStore::find(int index) const + { + const T *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << T::getRecordType() << " with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + + // Need to instantiate these before they're used + template class IndexedStore; + template class IndexedStore; + + template + Store::Store() + { + } + + template + Store::Store(const Store& orig) + : mStatic(orig.mStatic) + { + } + + template + void Store::clearDynamic() + { + // remove the dynamic part of mShared + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + mDynamic.clear(); + } + + template + const T *Store::search(const std::string &id) const + { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename Dynamic::const_iterator dit = mDynamic.find(item.mId); + if (dit != mDynamic.end()) { + return &dit->second; + } + + typename std::map::const_iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + return &(it->second); + } + + return 0; + } + template + bool Store::isDynamic(const std::string &id) const + { + typename Dynamic::const_iterator dit = mDynamic.find(id); + return (dit != mDynamic.end()); + } + template + const T *Store::searchRandom(const std::string &id) const + { + std::vector results; + std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); + if(!results.empty()) + return results[Misc::Rng::rollDice(results.size())]; + return NULL; + } + template + const T *Store::find(const std::string &id) const + { + const T *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << T::getRecordType() << " '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + template + const T *Store::findRandom(const std::string &id) const + { + const T *ptr = searchRandom(id); + if(ptr == 0) { - // spawn a new cell - cell.loadCell(esm, true); - - mInt[idLower] = cell; - } - } - else - { - // Store exterior cells by grid position, try to merge with existing parent data. - ESM::Cell *oldcell = const_cast(search(cell.getGridX(), cell.getGridY())); - if (oldcell) { - // merge new cell into old cell - oldcell->mData = cell.mData; - oldcell->mName = cell.mName; - oldcell->loadCell(esm, false); - - // handle moved ref (MVRF) subrecords - handleMovedCellRefs (esm, &cell); - - // push the new references on the list of references to manage - oldcell->postLoad(esm); - - // merge lists of leased references, use newer data in case of conflict - for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { - // remove reference from current leased ref tracker and add it to new cell - ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); - if (itold != oldcell->mMovedRefs.end()) { - ESM::MovedCellRef target0 = *itold; - ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); - ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); - wipecell->mLeasedRefs.erase(it_lease); - *itold = *it; + std::ostringstream msg; + msg << T::getRecordType() << " starting with '"< + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::pair inserted = mStatic.insert(std::make_pair(idLower, T())); + if (inserted.second) + mShared.push_back(&inserted.first->second); + + inserted.first->second.mId = idLower; + inserted.first->second.load(esm); + } + template + void Store::setUp() + { + } + + template + typename Store::iterator Store::begin() const + { + return mShared.begin(); + } + template + typename Store::iterator Store::end() const + { + return mShared.end(); + } + + template + size_t Store::getSize() const + { + return mShared.size(); + } + + template + int Store::getDynamicSize() const + { + return mDynamic.size(); + } + template + void Store::listIdentifier(std::vector &list) const + { + list.reserve(list.size() + getSize()); + typename std::vector::const_iterator it = mShared.begin(); + for (; it != mShared.end(); ++it) { + list.push_back((*it)->mId); + } + } + template + T *Store::insert(const T &item) + { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mDynamic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + template + T *Store::insertStatic(const T &item) + { + std::string id = Misc::StringUtils::lowerCase(item.mId); + std::pair result = + mStatic.insert(std::pair(id, item)); + T *ptr = &result.first->second; + if (result.second) { + mShared.push_back(ptr); + } else { + *ptr = item; + } + return ptr; + } + template + bool Store::eraseStatic(const std::string &id) + { + T item; + item.mId = Misc::StringUtils::lowerCase(id); + + typename std::map::iterator it = mStatic.find(item.mId); + + if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { + // delete from the static part of mShared + typename std::vector::iterator sharedIter = mShared.begin(); + typename std::vector::iterator end = sharedIter + mStatic.size(); + + while (sharedIter != mShared.end() && sharedIter != end) { + if((*sharedIter)->mId == item.mId) { + mShared.erase(sharedIter); + break; } + ++sharedIter; + } + mStatic.erase(it); + } + + return true; + } + + template + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + typename Dynamic::iterator it = mDynamic.find(key); + if (it == mDynamic.end()) { + return false; + } + mDynamic.erase(it); + + // have to reinit the whole shared part + assert(mShared.size() >= mStatic.size()); + mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); + for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { + mShared.push_back(&it->second); + } + return true; + } + template + bool Store::erase(const T &item) + { + return erase(item.mId); + } + template + void Store::write (ESM::ESMWriter& writer, Loading::Listener& progress) const + { + for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); + ++iter) + { + writer.startRecord (T::sRecordId); + writer.writeHNString ("NAME", iter->second.mId); + iter->second.save (writer); + writer.endRecord (T::sRecordId); + } + } + template + void Store::read(ESM::ESMReader& reader, const std::string& id) + { + T record; + record.mId = id; + record.load (reader); + insert (record); + } + + + // LandTexture + //========================================================================= + Store::Store() + { + mStatic.push_back(LandTextureList()); + LandTextureList <exl = mStatic[0]; + // More than enough to hold Morrowind.esm. Extra lists for plugins will we + // added on-the-fly in a different method. + ltexl.reserve(128); + } + const ESM::LandTexture *Store::search(size_t index, size_t plugin) const + { + assert(plugin < mStatic.size()); + const LandTextureList <exl = mStatic[plugin]; + + assert(index < ltexl.size()); + return <exl.at(index); + } + const ESM::LandTexture *Store::find(size_t index, size_t plugin) const + { + const ESM::LandTexture *ptr = search(index, plugin); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land texture with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + size_t Store::getSize() const + { + return mStatic.size(); + } + size_t Store::getSize(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].size(); + } + void Store::load(ESM::ESMReader &esm, const std::string &id, size_t plugin) + { + ESM::LandTexture lt; + lt.load(esm); + lt.mId = id; + + // Make sure we have room for the structure + if (plugin >= mStatic.size()) { + mStatic.resize(plugin+1); + } + LandTextureList <exl = mStatic[plugin]; + if(lt.mIndex + 1 > (int)ltexl.size()) + ltexl.resize(lt.mIndex+1); + + // Store it + ltexl[lt.mIndex] = lt; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + load(esm, id, esm.getIndex()); + } + Store::iterator Store::begin(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].begin(); + } + Store::iterator Store::end(size_t plugin) const + { + assert(plugin < mStatic.size()); + return mStatic[plugin].end(); + } + + + // Land + //========================================================================= + Store::~Store() + { + for (std::vector::const_iterator it = + mStatic.begin(); it != mStatic.end(); ++it) + { + delete *it; + } + + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return iterator(mStatic.begin()); + } + Store::iterator Store::end() const + { + return iterator(mStatic.end()); + } + ESM::Land *Store::search(int x, int y) const + { + ESM::Land land; + land.mX = x, land.mY = y; + + std::vector::const_iterator it = + std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); + + if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { + return const_cast(*it); + } + return 0; + } + ESM::Land *Store::find(int x, int y) const + { + ESM::Land *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Land at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::Land *ptr = new ESM::Land(); + ptr->load(esm); + + // Same area defined in multiple plugins? -> last plugin wins + // Can't use search() because we aren't sorted yet - is there any other way to speed this up? + for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) + { + delete *it; + mStatic.erase(it); + break; + } + } + + mStatic.push_back(ptr); + } + void Store::setUp() + { + std::sort(mStatic.begin(), mStatic.end(), Compare()); + } + + + // Cell + //========================================================================= + + const ESM::Cell *Store::search(const ESM::Cell &cell) const + { + if (cell.isExterior()) { + return search(cell.getGridX(), cell.getGridY()); + } + return search(cell.mName); + } + void Store::handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell) + { + //Handling MovedCellRefs, there is no way to do it inside loadcell + while (esm.isNextSub("MVRF")) { + ESM::CellRef ref; + ESM::MovedCellRef cMRef; + cell->getNextMVRF(esm, cMRef); + + ESM::Cell *cellAlt = const_cast(searchOrCreate(cMRef.mTarget[0], cMRef.mTarget[1])); + + // Get regular moved reference data. Adapted from CellStore::loadRefs. Maybe we can optimize the following + // implementation when the oher implementation works as well. + bool deleted = false; + cell->getNextRef(esm, ref, deleted); + + // Add data required to make reference appear in the correct cell. + // We should not need to test for duplicates, as this part of the code is pre-cell merge. + cell->mMovedRefs.push_back(cMRef); + // But there may be duplicates here! + if (!deleted) + { + ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum); + if (iter == cellAlt->mLeasedRefs.end()) + cellAlt->mLeasedRefs.push_back(ref); else - oldcell->mMovedRefs.push_back(*it); + *iter = ref; + } + } + } + const ESM::Cell *Store::search(const std::string &id) const + { + ESM::Cell cell; + cell.mName = Misc::StringUtils::lowerCase(id); + + std::map::const_iterator it = mInt.find(cell.mName); + + if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { + return &(it->second); + } + + DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); + if (dit != mDynamicInt.end()) { + return &dit->second; + } + + return 0; + } + const ESM::Cell *Store::search(int x, int y) const + { + ESM::Cell cell; + cell.mData.mX = x, cell.mData.mY = y; + + std::pair key(x, y); + DynamicExt::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + return 0; + } + const ESM::Cell *Store::searchOrCreate(int x, int y) + { + std::pair key(x, y); + DynamicExt::const_iterator it = mExt.find(key); + if (it != mExt.end()) { + return &(it->second); + } + + DynamicExt::const_iterator dit = mDynamicExt.find(key); + if (dit != mDynamicExt.end()) { + return &dit->second; + } + + ESM::Cell newCell; + newCell.mData.mX = x; + newCell.mData.mY = y; + newCell.mData.mFlags = ESM::Cell::HasWater; + newCell.mAmbi.mAmbient = 0; + newCell.mAmbi.mSunlight = 0; + newCell.mAmbi.mFog = 0; + newCell.mAmbi.mFogDensity = 0; + return &mExt.insert(std::make_pair(key, newCell)).first->second; + } + const ESM::Cell *Store::find(const std::string &id) const + { + const ESM::Cell *ptr = search(id); + if (ptr == 0) { + std::ostringstream msg; + msg << "Interior cell '" << id << "' not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + const ESM::Cell *Store::find(int x, int y) const + { + const ESM::Cell *ptr = search(x, y); + if (ptr == 0) { + std::ostringstream msg; + msg << "Exterior at (" << x << ", " << y << ") not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::setUp() + { + typedef DynamicExt::iterator ExtIterator; + typedef std::map::iterator IntIterator; + + mSharedInt.clear(); + mSharedInt.reserve(mInt.size()); + for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { + mSharedInt.push_back(&(it->second)); + } + + mSharedExt.clear(); + mSharedExt.reserve(mExt.size()); + for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { + mSharedExt.push_back(&(it->second)); + } + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + // Don't automatically assume that a new cell must be spawned. Multiple plugins write to the same cell, + // and we merge all this data into one Cell object. However, we can't simply search for the cell id, + // as many exterior cells do not have a name. Instead, we need to search by (x,y) coordinates - and they + // are not available until both cells have been loaded at least partially! + + // All cells have a name record, even nameless exterior cells. + std::string idLower = Misc::StringUtils::lowerCase(id); + ESM::Cell cell; + cell.mName = id; + + // Load the (x,y) coordinates of the cell, if it is an exterior cell, + // so we can find the cell we need to merge with + cell.loadData(esm); + + if(cell.mData.mFlags & ESM::Cell::Interior) + { + // Store interior cell by name, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(idLower)); + if (oldcell) { + // merge new cell into old cell + // push the new references on the list of references to manage (saveContext = true) + oldcell->mData = cell.mData; + oldcell->mName = cell.mName; // merge name just to be sure (ID will be the same, but case could have been changed) + oldcell->loadCell(esm, true); + } else + { + // spawn a new cell + cell.loadCell(esm, true); + + mInt[idLower] = cell; + } + } + else + { + // Store exterior cells by grid position, try to merge with existing parent data. + ESM::Cell *oldcell = const_cast(search(cell.getGridX(), cell.getGridY())); + if (oldcell) { + // merge new cell into old cell + oldcell->mData = cell.mData; + oldcell->mName = cell.mName; + oldcell->loadCell(esm, false); + + // handle moved ref (MVRF) subrecords + handleMovedCellRefs (esm, &cell); + + // push the new references on the list of references to manage + oldcell->postLoad(esm); + + // merge lists of leased references, use newer data in case of conflict + for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) { + // remove reference from current leased ref tracker and add it to new cell + ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum); + if (itold != oldcell->mMovedRefs.end()) { + ESM::MovedCellRef target0 = *itold; + ESM::Cell *wipecell = const_cast(search(target0.mTarget[0], target0.mTarget[1])); + ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum); + wipecell->mLeasedRefs.erase(it_lease); + *itold = *it; + } + else + oldcell->mMovedRefs.push_back(*it); + } + + // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a + // reference to this cell, so the list for the new cell should be empty. The list for oldcell, + // however, could have leased refs in it and so should be kept. + } else + { + // spawn a new cell + cell.loadCell(esm, false); + + // handle moved ref (MVRF) subrecords + handleMovedCellRefs (esm, &cell); + + // push the new references on the list of references to manage + cell.postLoad(esm); + + mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + } + } + } + Store::iterator Store::intBegin() const + { + return iterator(mSharedInt.begin()); + } + Store::iterator Store::intEnd() const + { + return iterator(mSharedInt.end()); + } + Store::iterator Store::extBegin() const + { + return iterator(mSharedExt.begin()); + } + Store::iterator Store::extEnd() const + { + return iterator(mSharedExt.end()); + } + const ESM::Cell *Store::searchExtByName(const std::string &id) const + { + ESM::Cell *cell = 0; + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mName, id)) { + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } } + } + return cell; + } + const ESM::Cell *Store::searchExtByRegion(const std::string &id) const + { + ESM::Cell *cell = 0; + std::vector::const_iterator it = mSharedExt.begin(); + for (; it != mSharedExt.end(); ++it) { + if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { + if ( cell == 0 || + ( (*it)->mData.mX > cell->mData.mX ) || + ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) + { + cell = *it; + } + } + } + return cell; + } + size_t Store::getSize() const + { + return mSharedInt.size() + mSharedExt.size(); + } + void Store::listIdentifier(std::vector &list) const + { + list.reserve(list.size() + mSharedInt.size()); + + std::vector::const_iterator it = mSharedInt.begin(); + for (; it != mSharedInt.end(); ++it) { + list.push_back((*it)->mName); + } + } + ESM::Cell *Store::insert(const ESM::Cell &cell) + { + if (search(cell) != 0) { + std::ostringstream msg; + msg << "Failed to create "; + msg << ((cell.isExterior()) ? "exterior" : "interior"); + msg << " cell"; + + throw std::runtime_error(msg.str()); + } + ESM::Cell *ptr; + if (cell.isExterior()) { + std::pair key(cell.getGridX(), cell.getGridY()); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicExt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedExt.push_back(ptr); + } else { + std::string key = Misc::StringUtils::lowerCase(cell.mName); + + // duplicate insertions are avoided by search(ESM::Cell &) + std::pair result = + mDynamicInt.insert(std::make_pair(key, cell)); + + ptr = &result.first->second; + mSharedInt.push_back(ptr); + } + return ptr; + } + bool Store::erase(const ESM::Cell &cell) + { + if (cell.isExterior()) { + return erase(cell.getGridX(), cell.getGridY()); + } + return erase(cell.mName); + } + bool Store::erase(const std::string &id) + { + std::string key = Misc::StringUtils::lowerCase(id); + DynamicInt::iterator it = mDynamicInt.find(key); + + if (it == mDynamicInt.end()) { + return false; + } + mDynamicInt.erase(it); + mSharedInt.erase( + mSharedInt.begin() + mSharedInt.size(), + mSharedInt.end() + ); + + for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { + mSharedInt.push_back(&it->second); + } + + return true; + } + bool Store::erase(int x, int y) + { + std::pair key(x, y); + DynamicExt::iterator it = mDynamicExt.find(key); + + if (it == mDynamicExt.end()) { + return false; + } + mDynamicExt.erase(it); + mSharedExt.erase( + mSharedExt.begin() + mSharedExt.size(), + mSharedExt.end() + ); - // We don't need to merge mLeasedRefs of cell / oldcell. This list is filled when another cell moves a - // reference to this cell, so the list for the new cell should be empty. The list for oldcell, - // however, could have leased refs in it and so should be kept. - } else + for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { + mSharedExt.push_back(&it->second); + } + + return true; + } + + + // Pathgrid + //========================================================================= + + Store::Store() + : mCells(NULL) + { + } + + void Store::setCells(Store& cells) + { + mCells = &cells; + } + void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::Pathgrid pathgrid; + pathgrid.load(esm); + + // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. + // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. + // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. + // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. + // A proper fix should be made for future versions of the file format. + bool interior = mCells->search(pathgrid.mCell) != NULL; + + // Try to overwrite existing record + if (interior) + { + std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + else { - // spawn a new cell - cell.loadCell(esm, false); + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + } + } + size_t Store::getSize() const + { + return mInt.size() + mExt.size(); + } + void Store::setUp() + { + } + const ESM::Pathgrid *Store::search(int x, int y) const + { + Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); + if (it != mExt.end()) + return &(it->second); + return NULL; + } + const ESM::Pathgrid *Store::search(const std::string& name) const + { + Interior::const_iterator it = mInt.find(name); + if (it != mInt.end()) + return &(it->second); + return NULL; + } + const ESM::Pathgrid *Store::find(int x, int y) const + { + const ESM::Pathgrid* pathgrid = search(x,y); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << x << " " << y << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + const ESM::Pathgrid* Store::find(const std::string& name) const + { + const ESM::Pathgrid* pathgrid = search(name); + if (!pathgrid) + { + std::ostringstream msg; + msg << "Pathgrid in cell '" << name << "' not found"; + throw std::runtime_error(msg.str()); + } + return pathgrid; + } + const ESM::Pathgrid *Store::search(const ESM::Cell &cell) const + { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return search(cell.mData.mX, cell.mData.mY); + else + return search(cell.mName); + } + const ESM::Pathgrid *Store::find(const ESM::Cell &cell) const + { + if (!(cell.mData.mFlags & ESM::Cell::Interior)) + return find(cell.mData.mX, cell.mData.mY); + else + return find(cell.mName); + } - // handle moved ref (MVRF) subrecords - handleMovedCellRefs (esm, &cell); - // push the new references on the list of references to manage - cell.postLoad(esm); + // Skill + //========================================================================= + + Store::Store() + { + } + + + // Magic effect + //========================================================================= + + Store::Store() + { + } + - mExt[std::make_pair(cell.mData.mX, cell.mData.mY)] = cell; + // Attribute + //========================================================================= + + Store::Store() + { + mStatic.reserve(ESM::Attribute::Length); + } + const ESM::Attribute *Store::search(size_t index) const + { + if (index >= mStatic.size()) { + return 0; } + return &mStatic.at(index); } -} -void Store::load(ESM::ESMReader &esm, const std::string &id) -{ - load(esm, id, esm.getIndex()); -} + const ESM::Attribute *Store::find(size_t index) const + { + const ESM::Attribute *ptr = search(index); + if (ptr == 0) { + std::ostringstream msg; + msg << "Attribute with index " << index << " not found"; + throw std::runtime_error(msg.str()); + } + return ptr; + } + void Store::setUp() + { + for (int i = 0; i < ESM::Attribute::Length; ++i) { + mStatic.push_back( + ESM::Attribute( + ESM::Attribute::sAttributeIds[i], + ESM::Attribute::sGmstAttributeIds[i], + ESM::Attribute::sGmstAttributeDescIds[i] + ) + ); + } + } + size_t Store::getSize() const + { + return mStatic.size(); + } + Store::iterator Store::begin() const + { + return mStatic.begin(); + } + Store::iterator Store::end() const + { + return mStatic.end(); + } + + + // Dialogue + //========================================================================= + + + template<> + inline void Store::setUp() + { + // DialInfos marked as deleted are kept during the loading phase, so that the linked list + // structure is kept intact for inserting further INFOs. Delete them now that loading is done. + for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) + { + ESM::Dialogue& dial = it->second; + dial.clearDeletedInfos(); + } + + mShared.clear(); + mShared.reserve(mStatic.size()); + std::map::iterator it = mStatic.begin(); + for (; it != mStatic.end(); ++it) { + mShared.push_back(&(it->second)); + } + } + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + std::string idLower = Misc::StringUtils::lowerCase(id); + + std::map::iterator it = mStatic.find(idLower); + if (it == mStatic.end()) { + it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; + it->second.mId = id; // don't smash case here, as this line is printed + } + + it->second.load(esm); + } + + // Script + //========================================================================= + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) { + ESM::Script scpt; + scpt.load(esm); + Misc::StringUtils::toLower(scpt.mId); + + std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = scpt; + } + + + // StartScript + //========================================================================= + + template <> + inline void Store::load(ESM::ESMReader &esm, const std::string &id) + { + ESM::StartScript s; + s.load(esm); + s.mId = Misc::StringUtils::toLower(s.mId); + std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); + if (inserted.second) + mShared.push_back(&inserted.first->second); + else + inserted.first->second = s; + } } + +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; +template class MWWorld::Store; + diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 2d73d5312..02fb983cd 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -4,16 +4,18 @@ #include #include #include -#include -#include -#include - -#include +#include "recordcmp.hpp" -#include +namespace ESM +{ + struct Land; +} -#include "recordcmp.hpp" +namespace Loading +{ + class Listener; +} namespace MWWorld { @@ -37,6 +39,30 @@ namespace MWWorld ///< Read into dynamic storage }; + template + class IndexedStore + { + protected: + typedef typename std::map Static; + Static mStatic; + + public: + typedef typename std::map::const_iterator iterator; + + IndexedStore(); + + iterator begin() const; + iterator end() const; + + void load(ESM::ESMReader &esm); + + int getSize() const; + void setUp(); + + const T *search(int index) const; + const T *find(int index) const; + }; + template class SharedIterator { @@ -110,275 +136,54 @@ namespace MWWorld typedef std::map Dynamic; typedef std::map Static; - class GetRecords { - const std::string mFind; - std::vector *mRecords; - - public: - GetRecords(const std::string &str, std::vector *records) - : mFind(Misc::StringUtils::lowerCase(str)), mRecords(records) - { } - - void operator()(const T *item) - { - if(Misc::StringUtils::ciCompareLen(mFind, item->mId, mFind.size()) == 0) - mRecords->push_back(item); - } - }; - - friend class ESMStore; public: - Store() - {} - - Store(const Store &orig) - : mStatic(orig.mData) - {} + Store(); + Store(const Store &orig); typedef SharedIterator iterator; // setUp needs to be called again after - virtual void clearDynamic() - { - // remove the dynamic part of mShared - assert(mShared.size() >= mStatic.size()); - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - mDynamic.clear(); - } - - const T *search(const std::string &id) const { - T item; - item.mId = Misc::StringUtils::lowerCase(id); - - typename Dynamic::const_iterator dit = mDynamic.find(item.mId); - if (dit != mDynamic.end()) { - return &dit->second; - } + virtual void clearDynamic(); + void setUp(); - typename std::map::const_iterator it = mStatic.find(item.mId); - - if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { - return &(it->second); - } - - return 0; - } + const T *search(const std::string &id) const; /** * Does the record with this ID come from the dynamic store? */ - bool isDynamic(const std::string &id) const { - typename Dynamic::const_iterator dit = mDynamic.find(id); - return (dit != mDynamic.end()); - } + bool isDynamic(const std::string &id) const; /** Returns a random record that starts with the named ID, or NULL if not found. */ - const T *searchRandom(const std::string &id) const - { - std::vector results; - std::for_each(mShared.begin(), mShared.end(), GetRecords(id, &results)); - if(!results.empty()) - return results[Misc::Rng::rollDice(results.size())]; - return NULL; - } + const T *searchRandom(const std::string &id) const; - const T *find(const std::string &id) const { - const T *ptr = search(id); - if (ptr == 0) { - std::ostringstream msg; - msg << T::getRecordType() << " '" << id << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } + const T *find(const std::string &id) const; /** Returns a random record that starts with the named ID. An exception is thrown if none * are found. */ - const T *findRandom(const std::string &id) const - { - const T *ptr = searchRandom(id); - if(ptr == 0) - { - std::ostringstream msg; - msg << T::getRecordType() << " starting with '"< inserted = mStatic.insert(std::make_pair(idLower, T())); - if (inserted.second) - mShared.push_back(&inserted.first->second); - - inserted.first->second.mId = idLower; - inserted.first->second.load(esm); - } - - void setUp() { - } - - iterator begin() const { - return mShared.begin(); - } - - iterator end() const { - return mShared.end(); - } - - size_t getSize() const { - return mShared.size(); - } - - int getDynamicSize() const - { - return static_cast (mDynamic.size()); // truncated from unsigned __int64 if _MSC_VER && _WIN64 - } - - void listIdentifier(std::vector &list) const { - list.reserve(list.size() + getSize()); - typename std::vector::const_iterator it = mShared.begin(); - for (; it != mShared.end(); ++it) { - list.push_back((*it)->mId); - } - } - - T *insert(const T &item) { - std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mDynamic.insert(std::pair(id, item)); - T *ptr = &result.first->second; - if (result.second) { - mShared.push_back(ptr); - } else { - *ptr = item; - } - return ptr; - } - - T *insertStatic(const T &item) { - std::string id = Misc::StringUtils::lowerCase(item.mId); - std::pair result = - mStatic.insert(std::pair(id, item)); - T *ptr = &result.first->second; - if (result.second) { - mShared.push_back(ptr); - } else { - *ptr = item; - } - return ptr; - } - - - bool eraseStatic(const std::string &id) { - T item; - item.mId = Misc::StringUtils::lowerCase(id); + const T *findRandom(const std::string &id) const; - typename std::map::iterator it = mStatic.find(item.mId); + iterator begin() const; + iterator end() const; - if (it != mStatic.end() && Misc::StringUtils::ciEqual(it->second.mId, id)) { - // delete from the static part of mShared - typename std::vector::iterator sharedIter = mShared.begin(); - typename std::vector::iterator end = sharedIter + mStatic.size(); - - while (sharedIter != mShared.end() && sharedIter != end) { - if((*sharedIter)->mId == item.mId) { - mShared.erase(sharedIter); - break; - } - ++sharedIter; - } - mStatic.erase(it); - } - - return true; - } - - bool erase(const std::string &id) { - std::string key = Misc::StringUtils::lowerCase(id); - typename Dynamic::iterator it = mDynamic.find(key); - if (it == mDynamic.end()) { - return false; - } - mDynamic.erase(it); + size_t getSize() const; + int getDynamicSize() const; - // have to reinit the whole shared part - assert(mShared.size() >= mStatic.size()); - mShared.erase(mShared.begin() + mStatic.size(), mShared.end()); - for (it = mDynamic.begin(); it != mDynamic.end(); ++it) { - mShared.push_back(&it->second); - } - return true; - } + void listIdentifier(std::vector &list) const; - bool erase(const T &item) { - return erase(item.mId); - } + T *insert(const T &item); + T *insertStatic(const T &item); - void write (ESM::ESMWriter& writer, Loading::Listener& progress) const - { - for (typename Dynamic::const_iterator iter (mDynamic.begin()); iter!=mDynamic.end(); - ++iter) - { - writer.startRecord (T::sRecordId); - writer.writeHNString ("NAME", iter->second.mId); - iter->second.save (writer); - writer.endRecord (T::sRecordId); - } - } + bool eraseStatic(const std::string &id); + bool erase(const std::string &id); + bool erase(const T &item); - void read (ESM::ESMReader& reader, const std::string& id) - { - T record; - record.mId = id; - record.load (reader); - insert (record); - } + void load(ESM::ESMReader &esm, const std::string &id); + void write(ESM::ESMWriter& writer, Loading::Listener& progress) const; + void read(ESM::ESMReader& reader, const std::string& id); }; - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - std::string idLower = Misc::StringUtils::lowerCase(id); - - std::map::iterator it = mStatic.find(idLower); - if (it == mStatic.end()) { - it = mStatic.insert( std::make_pair( idLower, ESM::Dialogue() ) ).first; - it->second.mId = id; // don't smash case here, as this line is printed - } - - it->second.load(esm); - } - - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) { - ESM::Script scpt; - scpt.load(esm); - Misc::StringUtils::toLower(scpt.mId); - - std::pair inserted = mStatic.insert(std::make_pair(scpt.mId, scpt)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = scpt; - } - - template <> - inline void Store::load(ESM::ESMReader &esm, const std::string &id) - { - ESM::StartScript s; - s.load(esm); - s.mId = Misc::StringUtils::toLower(s.mId); - std::pair inserted = mStatic.insert(std::make_pair(s.mId, s)); - if (inserted.second) - mShared.push_back(&inserted.first->second); - else - inserted.first->second = s; - } - template <> class Store : public StoreBase { @@ -387,73 +192,23 @@ namespace MWWorld std::vector mStatic; public: - Store() { - mStatic.push_back(LandTextureList()); - LandTextureList <exl = mStatic[0]; - // More than enough to hold Morrowind.esm. Extra lists for plugins will we - // added on-the-fly in a different method. - ltexl.reserve(128); - } + Store(); typedef std::vector::const_iterator iterator; // Must be threadsafe! Called from terrain background loading threads. // Not a big deal here, since ESM::LandTexture can never be modified or inserted/erased - const ESM::LandTexture *search(size_t index, size_t plugin) const { - assert(plugin < mStatic.size()); - const LandTextureList <exl = mStatic[plugin]; - - assert(index < ltexl.size()); - return <exl.at(index); - } - - const ESM::LandTexture *find(size_t index, size_t plugin) const { - const ESM::LandTexture *ptr = search(index, plugin); - if (ptr == 0) { - std::ostringstream msg; - msg << "Land texture with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - size_t getSize() const { - return mStatic.size(); - } - - size_t getSize(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].size(); - } + const ESM::LandTexture *search(size_t index, size_t plugin) const; + const ESM::LandTexture *find(size_t index, size_t plugin) const; - void load(ESM::ESMReader &esm, const std::string &id, size_t plugin) { - ESM::LandTexture lt; - lt.load(esm); - lt.mId = id; - - // Make sure we have room for the structure - if (plugin >= mStatic.size()) { - mStatic.resize(plugin+1); - } - LandTextureList <exl = mStatic[plugin]; - if(lt.mIndex + 1 > (int)ltexl.size()) - ltexl.resize(lt.mIndex+1); - - // Store it - ltexl[lt.mIndex] = lt; - } + size_t getSize() const; + size_t getSize(size_t plugin) const; + void load(ESM::ESMReader &esm, const std::string &id, size_t plugin); void load(ESM::ESMReader &esm, const std::string &id); - iterator begin(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].begin(); - } - - iterator end(size_t plugin) const { - assert(plugin < mStatic.size()); - return mStatic[plugin].end(); - } + iterator begin(size_t plugin) const; + iterator end(size_t plugin) const; }; template <> @@ -461,88 +216,22 @@ namespace MWWorld { std::vector mStatic; - struct Compare - { - bool operator()(const ESM::Land *x, const ESM::Land *y) { - if (x->mX == y->mX) { - return x->mY < y->mY; - } - return x->mX < y->mX; - } - }; - public: typedef SharedIterator iterator; - virtual ~Store() - { - for (std::vector::const_iterator it = - mStatic.begin(); it != mStatic.end(); ++it) - { - delete *it; - } + virtual ~Store(); - } - - size_t getSize() const { - return mStatic.size(); - } - - iterator begin() const { - return iterator(mStatic.begin()); - } - - iterator end() const { - return iterator(mStatic.end()); - } + size_t getSize() const; + iterator begin() const; + iterator end() const; // Must be threadsafe! Called from terrain background loading threads. // Not a big deal here, since ESM::Land can never be modified or inserted/erased - ESM::Land *search(int x, int y) const { - ESM::Land land; - land.mX = x, land.mY = y; - - std::vector::const_iterator it = - std::lower_bound(mStatic.begin(), mStatic.end(), &land, Compare()); - - if (it != mStatic.end() && (*it)->mX == x && (*it)->mY == y) { - return const_cast(*it); - } - return 0; - } + ESM::Land *search(int x, int y) const; + ESM::Land *find(int x, int y) const; - ESM::Land *find(int x, int y) const{ - ESM::Land *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Land at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Land *ptr = new ESM::Land(); - ptr->load(esm); - - // Same area defined in multiple plugins? -> last plugin wins - // Can't use search() because we aren't sorted yet - is there any other way to speed this up? - for (std::vector::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - if ((*it)->mX == ptr->mX && (*it)->mY == ptr->mY) - { - delete *it; - mStatic.erase(it); - break; - } - } - - mStatic.push_back(ptr); - } - - void setUp() { - std::sort(mStatic.begin(), mStatic.end(), Compare()); - } + void load(ESM::ESMReader &esm, const std::string &id); + void setUp(); }; template <> @@ -576,261 +265,44 @@ namespace MWWorld DynamicInt mDynamicInt; DynamicExt mDynamicExt; - const ESM::Cell *search(const ESM::Cell &cell) const { - if (cell.isExterior()) { - return search(cell.getGridX(), cell.getGridY()); - } - return search(cell.mName); - } - + const ESM::Cell *search(const ESM::Cell &cell) const; void handleMovedCellRefs(ESM::ESMReader& esm, ESM::Cell* cell); public: typedef SharedIterator iterator; - const ESM::Cell *search(const std::string &id) const { - ESM::Cell cell; - cell.mName = Misc::StringUtils::lowerCase(id); - - std::map::const_iterator it = mInt.find(cell.mName); - - if (it != mInt.end() && Misc::StringUtils::ciEqual(it->second.mName, id)) { - return &(it->second); - } - - DynamicInt::const_iterator dit = mDynamicInt.find(cell.mName); - if (dit != mDynamicInt.end()) { - return &dit->second; - } - - return 0; - } + const ESM::Cell *search(const std::string &id) const; + const ESM::Cell *search(int x, int y) const; + const ESM::Cell *searchOrCreate(int x, int y); - const ESM::Cell *search(int x, int y) const { - ESM::Cell cell; - cell.mData.mX = x, cell.mData.mY = y; + const ESM::Cell *find(const std::string &id) const; + const ESM::Cell *find(int x, int y) const; - std::pair key(x, y); - DynamicExt::const_iterator it = mExt.find(key); - if (it != mExt.end()) { - return &(it->second); - } - - DynamicExt::const_iterator dit = mDynamicExt.find(key); - if (dit != mDynamicExt.end()) { - return &dit->second; - } - - return 0; - } - - const ESM::Cell *searchOrCreate(int x, int y) { - std::pair key(x, y); - DynamicExt::const_iterator it = mExt.find(key); - if (it != mExt.end()) { - return &(it->second); - } + void setUp(); - DynamicExt::const_iterator dit = mDynamicExt.find(key); - if (dit != mDynamicExt.end()) { - return &dit->second; - } - - ESM::Cell newCell; - newCell.mData.mX = x; - newCell.mData.mY = y; - newCell.mData.mFlags = ESM::Cell::HasWater; - newCell.mAmbi.mAmbient = 0; - newCell.mAmbi.mSunlight = 0; - newCell.mAmbi.mFog = 0; - newCell.mAmbi.mFogDensity = 0; - return &mExt.insert(std::make_pair(key, newCell)).first->second; - } - - const ESM::Cell *find(const std::string &id) const { - const ESM::Cell *ptr = search(id); - if (ptr == 0) { - std::ostringstream msg; - msg << "Interior cell '" << id << "' not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - const ESM::Cell *find(int x, int y) const { - const ESM::Cell *ptr = search(x, y); - if (ptr == 0) { - std::ostringstream msg; - msg << "Exterior at (" << x << ", " << y << ") not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - - void setUp() { - typedef DynamicExt::iterator ExtIterator; - typedef std::map::iterator IntIterator; - - mSharedInt.clear(); - mSharedInt.reserve(mInt.size()); - for (IntIterator it = mInt.begin(); it != mInt.end(); ++it) { - mSharedInt.push_back(&(it->second)); - } - - mSharedExt.clear(); - mSharedExt.reserve(mExt.size()); - for (ExtIterator it = mExt.begin(); it != mExt.end(); ++it) { - mSharedExt.push_back(&(it->second)); - } - } - - // HACK: Method implementation had to be moved to a separate cpp file, as we would otherwise get - // errors related to the compare operator used in std::find for ESM::MovedCellRefTracker::find. - // There some nasty three-way cyclic header dependency involved, which I could only fix by moving - // this method. void load(ESM::ESMReader &esm, const std::string &id); - iterator intBegin() const { - return iterator(mSharedInt.begin()); - } - - iterator intEnd() const { - return iterator(mSharedInt.end()); - } - - iterator extBegin() const { - return iterator(mSharedExt.begin()); - } - - iterator extEnd() const { - return iterator(mSharedExt.end()); - } + iterator intBegin() const; + iterator intEnd() const; + iterator extBegin() const; + iterator extEnd() const; // Return the northernmost cell in the easternmost column. - const ESM::Cell *searchExtByName(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mName, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) - { - cell = *it; - } - } - } - return cell; - } + const ESM::Cell *searchExtByName(const std::string &id) const; // Return the northernmost cell in the easternmost column. - const ESM::Cell *searchExtByRegion(const std::string &id) const { - ESM::Cell *cell = 0; - std::vector::const_iterator it = mSharedExt.begin(); - for (; it != mSharedExt.end(); ++it) { - if (Misc::StringUtils::ciEqual((*it)->mRegion, id)) { - if ( cell == 0 || - ( (*it)->mData.mX > cell->mData.mX ) || - ( (*it)->mData.mX == cell->mData.mX && (*it)->mData.mY > cell->mData.mY ) ) - { - cell = *it; - } - } - } - return cell; - } - - size_t getSize() const { - return mSharedInt.size() + mSharedExt.size(); - } + const ESM::Cell *searchExtByRegion(const std::string &id) const; - void listIdentifier(std::vector &list) const { - list.reserve(list.size() + mSharedInt.size()); - - std::vector::const_iterator it = mSharedInt.begin(); - for (; it != mSharedInt.end(); ++it) { - list.push_back((*it)->mName); - } - } - - ESM::Cell *insert(const ESM::Cell &cell) { - if (search(cell) != 0) { - std::ostringstream msg; - msg << "Failed to create "; - msg << ((cell.isExterior()) ? "exterior" : "interior"); - msg << " cell"; - - throw std::runtime_error(msg.str()); - } - ESM::Cell *ptr; - if (cell.isExterior()) { - std::pair key(cell.getGridX(), cell.getGridY()); + size_t getSize() const; - // duplicate insertions are avoided by search(ESM::Cell &) - std::pair result = - mDynamicExt.insert(std::make_pair(key, cell)); + void listIdentifier(std::vector &list) const; - ptr = &result.first->second; - mSharedExt.push_back(ptr); - } else { - std::string key = Misc::StringUtils::lowerCase(cell.mName); + ESM::Cell *insert(const ESM::Cell &cell); - // duplicate insertions are avoided by search(ESM::Cell &) - std::pair result = - mDynamicInt.insert(std::make_pair(key, cell)); + bool erase(const ESM::Cell &cell); + bool erase(const std::string &id); - ptr = &result.first->second; - mSharedInt.push_back(ptr); - } - return ptr; - } - - bool erase(const ESM::Cell &cell) { - if (cell.isExterior()) { - return erase(cell.getGridX(), cell.getGridY()); - } - return erase(cell.mName); - } - - bool erase(const std::string &id) { - std::string key = Misc::StringUtils::lowerCase(id); - DynamicInt::iterator it = mDynamicInt.find(key); - - if (it == mDynamicInt.end()) { - return false; - } - mDynamicInt.erase(it); - mSharedInt.erase( - mSharedInt.begin() + mSharedInt.size(), - mSharedInt.end() - ); - - for (it = mDynamicInt.begin(); it != mDynamicInt.end(); ++it) { - mSharedInt.push_back(&it->second); - } - - return true; - } - - bool erase(int x, int y) { - std::pair key(x, y); - DynamicExt::iterator it = mDynamicExt.find(key); - - if (it == mDynamicExt.end()) { - return false; - } - mDynamicExt.erase(it); - mSharedExt.erase( - mSharedExt.begin() + mSharedExt.size(), - mSharedExt.end() - ); - - for (it = mDynamicExt.begin(); it != mDynamicExt.end(); ++it) { - mSharedExt.push_back(&it->second); - } - - return true; - } + bool erase(int x, int y); }; template <> @@ -847,165 +319,33 @@ namespace MWWorld public: - Store() - : mCells(NULL) - { - } - - void setCells(Store& cells) - { - mCells = &cells; - } - - void load(ESM::ESMReader &esm, const std::string &id) { - ESM::Pathgrid pathgrid; - pathgrid.load(esm); - - // Unfortunately the Pathgrid record model does not specify whether the pathgrid belongs to an interior or exterior cell. - // For interior cells, mCell is the cell name, but for exterior cells it is either the cell name or if that doesn't exist, the cell's region name. - // mX and mY will be (0,0) for interior cells, but there is also an exterior cell with the coordinates of (0,0), so that doesn't help. - // Check whether mCell is an interior cell. This isn't perfect, will break if a Region with the same name as an interior cell is created. - // A proper fix should be made for future versions of the file format. - bool interior = mCells->search(pathgrid.mCell) != NULL; - - // Try to overwrite existing record - if (interior) - { - std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - else - { - std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); - if (!ret.second) - ret.first->second = pathgrid; - } - } + Store(); - size_t getSize() const { - return mInt.size() + mExt.size(); - } - - void setUp() { - } - - const ESM::Pathgrid *search(int x, int y) const { - Exterior::const_iterator it = mExt.find(std::make_pair(x,y)); - if (it != mExt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *search(const std::string& name) const { - Interior::const_iterator it = mInt.find(name); - if (it != mInt.end()) - return &(it->second); - return NULL; - } - - const ESM::Pathgrid *find(int x, int y) const { - const ESM::Pathgrid* pathgrid = search(x,y); - if (!pathgrid) - { - std::ostringstream msg; - msg << "Pathgrid in cell '" << x << " " << y << "' not found"; - throw std::runtime_error(msg.str()); - } - return pathgrid; - } + void setCells(Store& cells); + void load(ESM::ESMReader &esm, const std::string &id); + size_t getSize() const; - const ESM::Pathgrid* find(const std::string& name) const { - const ESM::Pathgrid* pathgrid = search(name); - if (!pathgrid) - { - std::ostringstream msg; - msg << "Pathgrid in cell '" << name << "' not found"; - throw std::runtime_error(msg.str()); - } - return pathgrid; - } + void setUp(); - const ESM::Pathgrid *search(const ESM::Cell &cell) const { - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - return search(cell.mData.mX, cell.mData.mY); - else - return search(cell.mName); - } - - const ESM::Pathgrid *find(const ESM::Cell &cell) const { - if (!(cell.mData.mFlags & ESM::Cell::Interior)) - return find(cell.mData.mX, cell.mData.mY); - else - return find(cell.mName); - } + const ESM::Pathgrid *search(int x, int y) const; + const ESM::Pathgrid *search(const std::string& name) const; + const ESM::Pathgrid *find(int x, int y) const; + const ESM::Pathgrid* find(const std::string& name) const; + const ESM::Pathgrid *search(const ESM::Cell &cell) const; + const ESM::Pathgrid *find(const ESM::Cell &cell) const; }; - template - class IndexedStore - { - protected: - typedef typename std::map Static; - Static mStatic; - - public: - typedef typename std::map::const_iterator iterator; - - IndexedStore() {} - - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } - - void load(ESM::ESMReader &esm) { - T record; - record.load(esm); - - // Try to overwrite existing record - std::pair ret = mStatic.insert(std::make_pair(record.mIndex, record)); - if (!ret.second) - ret.first->second = record; - } - - int getSize() const { - return mStatic.size(); - } - - void setUp() { - } - - const T *search(int index) const { - typename Static::const_iterator it = mStatic.find(index); - if (it != mStatic.end()) - return &(it->second); - return NULL; - } - - const T *find(int index) const { - const T *ptr = search(index); - if (ptr == 0) { - std::ostringstream msg; - msg << T::getRecordType() << " with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } - }; template <> struct Store : public IndexedStore { - Store() {} + Store(); }; template <> struct Store : public IndexedStore { - Store() {} + Store(); }; template <> @@ -1016,70 +356,18 @@ namespace MWWorld public: typedef std::vector::const_iterator iterator; - Store() { - mStatic.reserve(ESM::Attribute::Length); - } + Store(); - const ESM::Attribute *search(size_t index) const { - if (index >= mStatic.size()) { - return 0; - } - return &mStatic.at(index); - } - - const ESM::Attribute *find(size_t index) const { - const ESM::Attribute *ptr = search(index); - if (ptr == 0) { - std::ostringstream msg; - msg << "Attribute with index " << index << " not found"; - throw std::runtime_error(msg.str()); - } - return ptr; - } + const ESM::Attribute *search(size_t index) const; + const ESM::Attribute *find(size_t index) const; - void setUp() { - for (int i = 0; i < ESM::Attribute::Length; ++i) { - mStatic.push_back( - ESM::Attribute( - ESM::Attribute::sAttributeIds[i], - ESM::Attribute::sGmstAttributeIds[i], - ESM::Attribute::sGmstAttributeDescIds[i] - ) - ); - } - } - - size_t getSize() const { - return mStatic.size(); - } + void setUp(); - iterator begin() const { - return mStatic.begin(); - } - - iterator end() const { - return mStatic.end(); - } + size_t getSize() const; + iterator begin() const; + iterator end() const; }; - template<> - inline void Store::setUp() - { - // DialInfos marked as deleted are kept during the loading phase, so that the linked list - // structure is kept intact for inserting further INFOs. Delete them now that loading is done. - for (Static::iterator it = mStatic.begin(); it != mStatic.end(); ++it) - { - ESM::Dialogue& dial = it->second; - dial.clearDeletedInfos(); - } - - mShared.clear(); - mShared.reserve(mStatic.size()); - std::map::iterator it = mStatic.begin(); - for (; it != mStatic.end(); ++it) { - mShared.push_back(&(it->second)); - } - } } //end namespace diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 70d6f1b36..f51cfd59b 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -5,6 +5,7 @@ #include +#include #include #include "../mwbase/environment.hpp" diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7964edf45..5251427c5 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -52,6 +52,11 @@ namespace MWRender class Camera; } +namespace ToUTF8 +{ + class Utf8Encoder; +} + struct ContentLoader; namespace MWWorld From 2bebfea38da9d1cdfa0613a96a4d5d18bc2c33ee Mon Sep 17 00:00:00 2001 From: "Alexander \"Ace\" Olofsson" Date: Thu, 9 Jul 2015 22:45:25 +0200 Subject: [PATCH 4/4] Instantiate struct as a struct --- components/esm/statstate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/esm/statstate.cpp b/components/esm/statstate.cpp index e95295cc9..c17bedd81 100644 --- a/components/esm/statstate.cpp +++ b/components/esm/statstate.cpp @@ -46,7 +46,7 @@ namespace ESM if (mProgress) esm.writeHNT("STPR", mProgress); } - - template class StatState; - template class StatState; } + +template struct ESM::StatState; +template struct ESM::StatState;