2014-01-16 12:03:23 +01:00
|
|
|
#include "livecellref.hpp"
|
|
|
|
|
2022-06-27 21:32:46 +02:00
|
|
|
#include <sstream>
|
|
|
|
|
2018-08-14 23:05:43 +04:00
|
|
|
#include <components/debug/debuglog.hpp>
|
2022-09-05 19:35:15 +02:00
|
|
|
#include <components/esm3/loadcrea.hpp>
|
|
|
|
#include <components/esm3/loadscpt.hpp>
|
2022-01-22 15:58:41 +01:00
|
|
|
#include <components/esm3/objectstate.hpp>
|
2014-01-16 12:03:23 +01:00
|
|
|
|
2014-03-22 16:39:24 +01:00
|
|
|
#include "../mwbase/environment.hpp"
|
2021-01-29 02:38:09 +01:00
|
|
|
#include "../mwbase/luamanager.hpp"
|
2014-03-22 16:39:24 +01:00
|
|
|
|
2014-01-30 11:50:13 +01:00
|
|
|
#include "class.hpp"
|
2014-03-22 16:39:24 +01:00
|
|
|
#include "esmstore.hpp"
|
2014-01-30 11:50:13 +01:00
|
|
|
#include "ptr.hpp"
|
2023-09-08 22:47:15 +02:00
|
|
|
#include "worldmodel.hpp"
|
2014-01-30 11:50:13 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
namespace MWWorld
|
2014-05-08 13:47:54 +02:00
|
|
|
{
|
2024-06-15 00:31:43 +02:00
|
|
|
LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM::CellRef& cref)
|
|
|
|
: mClass(&Class::get(type))
|
|
|
|
, mRef(cref)
|
|
|
|
, mData(cref)
|
|
|
|
{
|
|
|
|
}
|
2014-05-08 13:47:54 +02:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::Reference& cref)
|
|
|
|
: mClass(&Class::get(type))
|
|
|
|
, mRef(cref)
|
|
|
|
, mData(cref)
|
|
|
|
{
|
|
|
|
}
|
2023-01-23 23:51:45 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
LiveCellRefBase::LiveCellRefBase(unsigned int type, const ESM4::ActorCharacter& cref)
|
|
|
|
: mClass(&Class::get(type))
|
|
|
|
, mRef(cref)
|
|
|
|
, mData(cref)
|
|
|
|
{
|
|
|
|
}
|
2023-07-25 02:17:18 +02:00
|
|
|
|
2024-06-15 00:30:14 +02:00
|
|
|
LiveCellRefBase::LiveCellRefBase(LiveCellRefBase&& other) noexcept
|
|
|
|
: mClass(other.mClass)
|
|
|
|
, mRef(std::move(other.mRef))
|
|
|
|
, mData(std::move(other.mData))
|
|
|
|
, mWorldModel(std::exchange(other.mWorldModel, nullptr))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
LiveCellRefBase::~LiveCellRefBase()
|
|
|
|
{
|
2024-06-15 00:30:14 +02:00
|
|
|
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;
|
2024-06-15 00:31:43 +02:00
|
|
|
}
|
2023-09-08 22:47:15 +02:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
void LiveCellRefBase::loadImp(const ESM::ObjectState& state)
|
|
|
|
{
|
|
|
|
mRef = CellRef(state.mRef);
|
|
|
|
mData = RefData(state, mData.isDeletedByContentFile());
|
2014-03-22 15:00:49 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
Ptr ptr(this);
|
2014-03-22 15:00:49 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
if (state.mHasLocals)
|
2014-05-10 18:14:35 +02:00
|
|
|
{
|
2024-06-15 00:31:43 +02:00
|
|
|
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())
|
2014-05-10 18:14:35 +02:00
|
|
|
{
|
2024-06-15 00:31:43 +02:00
|
|
|
if (const ESM::Script* script
|
|
|
|
= MWBase::Environment::get().getESMStore()->get<ESM::Script>().search(scriptId))
|
2014-09-22 10:12:07 +02:00
|
|
|
{
|
2024-06-15 00:31:43 +02:00
|
|
|
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();
|
|
|
|
}
|
2014-09-22 10:12:07 +02:00
|
|
|
}
|
2014-05-10 18:14:35 +02:00
|
|
|
}
|
|
|
|
}
|
2014-03-22 15:00:49 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
mClass->readAdditionalState(ptr, state);
|
2018-03-08 23:38:04 +00:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
if (!mRef.getSoul().empty()
|
|
|
|
&& !MWBase::Environment::get().getESMStore()->get<ESM::Creature>().search(mRef.getSoul()))
|
|
|
|
{
|
|
|
|
Log(Debug::Warning) << "Soul '" << mRef.getSoul() << "' not found, removing the soul from soul gem";
|
|
|
|
mRef.setSoul(ESM::RefId());
|
|
|
|
}
|
2021-01-29 02:38:09 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
MWBase::Environment::get().getLuaManager()->loadLocalScripts(ptr, state.mLuaScripts);
|
|
|
|
}
|
2014-01-16 12:03:23 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
void LiveCellRefBase::saveImp(ESM::ObjectState& state) const
|
|
|
|
{
|
|
|
|
mRef.writeState(state);
|
2014-03-22 15:00:49 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
ConstPtr ptr(this);
|
2014-03-22 15:00:49 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
mData.write(state, mClass->getScript(ptr));
|
|
|
|
MWBase::Environment::get().getLuaManager()->saveLocalScripts(
|
|
|
|
Ptr(const_cast<LiveCellRefBase*>(this)), state.mLuaScripts);
|
2014-03-22 15:00:49 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
mClass->writeAdditionalState(ptr, state);
|
|
|
|
}
|
2014-01-16 12:03:23 +01:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
bool LiveCellRefBase::checkStateImp(const ESM::ObjectState& state)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2021-10-25 07:08:50 +00:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
unsigned int LiveCellRefBase::getType() const
|
|
|
|
{
|
|
|
|
return mClass->getType();
|
|
|
|
}
|
2022-06-27 21:32:46 +02:00
|
|
|
|
2024-06-15 00:31:43 +02:00
|
|
|
bool LiveCellRefBase::isDeleted() const
|
|
|
|
{
|
|
|
|
return mData.isDeletedByContentFile() || mRef.getCount(false) == 0;
|
|
|
|
}
|
2023-12-31 17:12:46 +00:00
|
|
|
|
2022-06-27 21:32:46 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|