#include "livecellref.hpp" #include #include #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/luamanager.hpp" #include "class.hpp" #include "esmstore.hpp" #include "ptr.hpp" #include "worldmodel.hpp" namespace MWWorld { LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM::CellRef& cref) : mClass(&Class::get(type)) , mRef(cref) , mData(cref) { } LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::Reference& cref) : mClass(&Class::get(type)) , mRef(cref) , mData(cref) { } LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::ActorCharacter& cref) : mClass(&Class::get(type)) , mRef(cref) , mData(cref) { } LiveCellRefBase::LiveCellRefBase(LiveCellRefBase&& other) noexcept : mClass(other.mClass) , mRef(std::move(other.mRef)) , mData(std::move(other.mData)) , mWorldModel(std::exchange(other.mWorldModel, nullptr)) { } LiveCellRefBase::~LiveCellRefBase() { if (mWorldModel != nullptr) mWorldModel->deregisterLiveCellRef(*this); } LiveCellRefBase& LiveCellRefBase::operator=(LiveCellRefBase&& other) noexcept { mClass = other.mClass; mRef = std::move(other.mRef); mData = std::move(other.mData); mWorldModel = std::exchange(other.mWorldModel, nullptr); return *this; } void LiveCellRefBase::loadImp(const ESM::ObjectState& state) { mRef = CellRef(state.mRef); mData = RefData(state, mData.isDeletedByContentFile()); Ptr ptr(this); if (state.mHasLocals) { const ESM::RefId& scriptId = mClass->getScript(ptr); // Make sure we still have a script. It could have been coming from a content file that is no longer active. if (!scriptId.empty()) { if (const ESM::Script* script = MWBase::Environment::get().getESMStore()->get().search(scriptId)) { try { mData.setLocals(*script); mData.getLocals().read(state.mLocals, scriptId); } catch (const std::exception& exception) { Log(Debug::Error) << "Error: failed to load state for local script " << scriptId << " because an exception has been thrown: " << exception.what(); } } } } mClass->readAdditionalState(ptr, state); if (!mRef.getSoul().empty() && !MWBase::Environment::get().getESMStore()->get().search(mRef.getSoul())) { Log(Debug::Warning) << "Soul '" << mRef.getSoul() << "' not found, removing the soul from soul gem"; mRef.setSoul(ESM::RefId()); } MWBase::Environment::get().getLuaManager()->loadLocalScripts(ptr, state.mLuaScripts); } void LiveCellRefBase::saveImp(ESM::ObjectState& state) const { mRef.writeState(state); ConstPtr ptr(this); mData.write(state, mClass->getScript(ptr)); MWBase::Environment::get().getLuaManager()->saveLocalScripts( Ptr(const_cast(this)), state.mLuaScripts); mClass->writeAdditionalState(ptr, state); } bool LiveCellRefBase::checkStateImp(const ESM::ObjectState& state) { return true; } unsigned int LiveCellRefBase::getType() const { return mClass->getType(); } bool LiveCellRefBase::isDeleted() const { return mData.isDeletedByContentFile() || mRef.getCount(false) == 0; } std::string makeDynamicCastErrorMessage(const LiveCellRefBase* value, std::string_view recordType) { std::stringstream message; message << "Bad LiveCellRef cast to " << recordType << " from "; if (value != nullptr) message << value->getTypeDescription(); else message << "an empty object"; return message.str(); } }