Centralize actor data, simplify logic

pull/541/head
Kyle Cooley 6 years ago committed by Andrei Kortunov
parent c1ec926f43
commit f43b70d77b

@ -6,6 +6,7 @@
#include <components/esm/loadnpc.hpp>
#include <components/esm/loadrace.hpp>
#include <components/esm/mappings.hpp>
#include <components/sceneutil/actorutil.hpp>
#include "data.hpp"
@ -16,6 +17,11 @@ namespace CSMWorld
return mId;
}
bool ActorAdapter::RaceData::isBeast() const
{
return mIsBeast;
}
bool ActorAdapter::RaceData::handlesPart(ESM::PartReferenceType type) const
{
switch (type)
@ -63,9 +69,10 @@ namespace CSMWorld
if (!id.empty()) mDependencies.emplace(id);
}
void ActorAdapter::RaceData::reset(const std::string& id)
void ActorAdapter::RaceData::reset_data(const std::string& id, bool isBeast)
{
mId = id;
mIsBeast = isBeast;
for (auto& str : mFemaleParts)
str.clear();
for (auto& str : mMaleParts)
@ -82,11 +89,28 @@ namespace CSMWorld
return mId;
}
bool ActorAdapter::ActorData::isCreature() const
{
return mCreature;
}
bool ActorAdapter::ActorData::isFemale() const
{
return mFemale;
}
std::string ActorAdapter::ActorData::getSkeleton() const
{
if (mCreature || !mSkeletonOverride.empty())
return "meshes\\" + mSkeletonOverride;
bool firstPerson = false;
bool beast = mRaceData ? mRaceData->isBeast() : false;
bool werewolf = false;
return SceneUtil::getActorSkeleton(firstPerson, mFemale, beast, werewolf);
}
const std::string& ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
{
if (mParts[index].empty() && mRaceData && mRaceData->handlesPart(index))
@ -112,10 +136,12 @@ namespace CSMWorld
if (!id.empty()) mDependencies.emplace(id);
}
void ActorAdapter::ActorData::reset(const std::string& id, bool isFemale, RaceDataPtr raceData)
void ActorAdapter::ActorData::reset_data(const std::string& id, const std::string& skeleton, bool isCreature, bool isFemale, RaceDataPtr raceData)
{
mId = id;
mCreature = isCreature;
mFemale = isFemale;
mSkeletonOverride = skeleton;
mRaceData = raceData;
for (auto& str : mParts)
str.clear();
@ -383,7 +409,7 @@ namespace CSMWorld
if (index == -1)
{
// Record does not exist
data->reset(id);
data->reset_data(id);
emit actorChanged(id);
return;
}
@ -392,7 +418,7 @@ namespace CSMWorld
if (record.isDeleted())
{
// Record is deleted and therefore not accessible
data->reset(id);
data->reset_data(id);
emit actorChanged(id);
return;
}
@ -414,20 +440,18 @@ namespace CSMWorld
else
{
// Wrong record type
data->reset(id);
data->reset_data(id);
emit actorChanged(id);
}
}
void ActorAdapter::setupRace(const std::string& id, RaceDataPtr data)
{
// Common setup
data->reset(id);
int index = mRaces.searchId(id);
if (index == -1)
{
// Record does not exist
data->reset_data(id);
return;
}
@ -435,10 +459,12 @@ namespace CSMWorld
if (raceRecord.isDeleted())
{
// Record is deleted, so not accessible
data->reset_data(id);
return;
}
// TODO move stuff in actor related to race here
auto& race = raceRecord.get();
data->reset_data(id, race.mData.mFlags & ESM::Race::Beast);
// Setup body parts
for (int i = 0; i < mBodyParts.getSize(); ++i)
@ -470,7 +496,7 @@ namespace CSMWorld
auto& npc = dynamic_cast<const Record<ESM::NPC>&>(mReferenceables.getRecord(index)).get();
RaceDataPtr raceData = getRaceData(npc.mRace);
data->reset(id, !npc.isMale(), raceData);
data->reset_data(id, "", false, !npc.isMale(), raceData);
// Add inventory items
for (auto& item : npc.mInventory.mList)
@ -541,9 +567,11 @@ namespace CSMWorld
void ActorAdapter::setupCreature(const std::string& id, ActorDataPtr data)
{
data->reset(id);
// Record is known to exist and is not deleted
int index = mReferenceables.searchId(id);
auto& creature = dynamic_cast<const Record<ESM::Creature>&>(mReferenceables.getRecord(index)).get();
// TODO move stuff from Actor here
data->reset_data(id, creature.mModel, true);
}
void ActorAdapter::markDirtyDependency(const std::string& dep)

@ -44,6 +44,8 @@ namespace CSMWorld
public:
/// Retrieves the id of the race represented
const std::string& getId() const;
/// Checks if it's a beast race
bool isBeast() const;
/// Checks if a part could exist for the given type
bool handlesPart(ESM::PartReferenceType type) const;
/// Retrieves the associated body part
@ -60,11 +62,12 @@ namespace CSMWorld
/// Marks an additional dependency
void addOtherDependency(const std::string& id);
/// Clears parts and dependencies
void reset(const std::string& raceId);
void reset_data(const std::string& raceId, bool isBeast=false);
private:
bool handles(ESM::PartReferenceType type) const;
std::string mId;
bool mIsBeast;
RacePartList mFemaleParts;
RacePartList mMaleParts;
StringSet mDependencies;
@ -78,8 +81,12 @@ namespace CSMWorld
public:
/// Retrieves the id of the actor represented
const std::string& getId() const;
/// Checks if the actor is a creature
bool isCreature() const;
/// Checks if the actor is female
bool isFemale() const;
/// Returns the skeleton the actor should use for attaching parts to
std::string getSkeleton() const;
/// Retrieves the associated actor part
const std::string& getPart(ESM::PartReferenceType index) const;
/// Checks if the actor has a data dependency
@ -90,11 +97,13 @@ namespace CSMWorld
/// Marks an additional dependency for the actor
void addOtherDependency(const std::string& id);
/// Clears race, parts, and dependencies
void reset(const std::string& actorId, bool female=true, RaceDataPtr raceData=nullptr);
void reset_data(const std::string& actorId, const std::string& skeleton="", bool isCreature=false, bool female=true, RaceDataPtr raceData=nullptr);
private:
std::string mId;
bool mCreature;
bool mFemale;
std::string mSkeletonOverride;
RaceDataPtr mRaceData;
ActorPartList mParts;
StringSet mDependencies;

@ -18,15 +18,15 @@ namespace CSVRender
{
const std::string Actor::MeshPrefix = "meshes\\";
Actor::Actor(const std::string& id, int type, CSMWorld::Data& data)
Actor::Actor(const std::string& id, CSMWorld::Data& data)
: mId(id)
, mInitialized(false)
, mType(type)
, mData(data)
, mBaseNode(new osg::Group())
, mSkeleton(nullptr)
{
mActorData = mData.getActorAdapter()->getActorData(mId);
connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)),
this, SLOT(handleActorChanged(const std::string&)));
}
osg::Group* Actor::getBaseNode()
@ -36,25 +36,33 @@ namespace CSVRender
void Actor::update()
{
try
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
// Load skeleton
std::string skeletonModel = mActorData->getSkeleton();
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
loadSkeleton(skeletonModel);
if (!mActorData->isCreature())
{
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
// Get rid of the extra attachments
SceneUtil::CleanObjectRootVisitor cleanVisitor;
mSkeleton->accept(cleanVisitor);
cleanVisitor.remove();
if (mType == CSMWorld::UniversalId::Type_Npc)
updateNpc();
else if (mType == CSMWorld::UniversalId::Type_Creature)
updateCreature();
// Attach parts to skeleton
loadBodyParts();
}
catch (std::exception& e)
else
{
Log(Debug::Info) << "Exception in Actor::update(): " << e.what();
SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
mSkeleton->accept(removeTriBipVisitor);
removeTriBipVisitor.remove();
}
if (!mInitialized)
{
mInitialized = true;
connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), this, SLOT(handleActorChanged(const std::string&)));
}
// Post setup
mSkeleton->markDirty();
mSkeleton->setActive(SceneUtil::Skeleton::Active);
}
void Actor::handleActorChanged(const std::string& refId)
@ -65,57 +73,6 @@ namespace CSVRender
}
}
void Actor::updateCreature()
{
auto& referenceables = mData.getReferenceables();
auto& creature = dynamic_cast<const CSMWorld::Record<ESM::Creature>& >(referenceables.getRecord(mId)).get();
// Load skeleton with meshes
std::string skeletonModel = MeshPrefix + creature.mModel;
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
loadSkeleton(skeletonModel);
SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
mSkeleton->accept(removeTriBipVisitor);
removeTriBipVisitor.remove();
// Post setup
mSkeleton->markDirty();
mSkeleton->setActive(SceneUtil::Skeleton::Active);
}
void Actor::updateNpc()
{
auto& races = mData.getRaces();
auto& referenceables = mData.getReferenceables();
auto& npc = dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(referenceables.getRecord(mId)).get();
auto& race = dynamic_cast<const CSMWorld::Record<ESM::Race>& >(races.getRecord(npc.mRace)).get();
bool is1stPerson = false;
bool isFemale = !npc.isMale();
bool isBeast = race.mData.mFlags & ESM::Race::Beast;
bool isWerewolf = false;
// Load skeleton
std::string skeletonModel = SceneUtil::getActorSkeleton(is1stPerson, isFemale, isBeast, isWerewolf);
skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
loadSkeleton(skeletonModel);
// Get rid of the extra attachments
SceneUtil::CleanObjectRootVisitor cleanVisitor;
mSkeleton->accept(cleanVisitor);
cleanVisitor.remove();
// Attach parts to skeleton
loadBodyParts(npc.mId);
// Post setup
mSkeleton->markDirty();
mSkeleton->setActive(SceneUtil::Skeleton::Active);
}
void Actor::loadSkeleton(const std::string& model)
{
auto sceneMgr = mData.getResourceSystem()->getSceneManager();
@ -136,7 +93,7 @@ namespace CSVRender
}
void Actor::loadBodyParts(const std::string& actorId)
void Actor::loadBodyParts()
{
for (int i = 0; i < ESM::PRT_Count; ++i)
{

@ -38,7 +38,7 @@ namespace CSVRender
/// \param id The referenceable id
/// \param type The record type
/// \param data The data store
Actor(const std::string& id, int type, CSMWorld::Data& data);
Actor(const std::string& id, CSMWorld::Data& data);
/// Retrieves the base node that meshes are attached to
osg::Group* getBaseNode();
@ -50,11 +50,8 @@ namespace CSVRender
void handleActorChanged(const std::string& refId);
private:
void updateCreature();
void updateNpc();
void loadSkeleton(const std::string& model);
void loadBodyParts(const std::string& actorId);
void loadBodyParts();
void attachBodyPart(ESM::PartReferenceType, const std::string& mesh);
std::string getBodyPartMesh(const std::string& bodyPartId);
@ -62,8 +59,6 @@ namespace CSVRender
static const std::string MeshPrefix;
std::string mId;
bool mInitialized;
int mType;
CSMWorld::Data& mData;
CSMWorld::ActorAdapter::ActorDataPtr mActorData;

@ -83,74 +83,58 @@ void CSVRender::Object::update()
{
clear();
std::string model;
int error = 0; // 1 referenceable does not exist, 2 referenceable does not specify a mesh
const CSMWorld::RefIdCollection& referenceables = mData.getReferenceables();
const int TypeIndex = referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType);
const int ModelIndex = referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model);
int index = referenceables.searchId (mReferenceableId);
int recordType = -1;
const ESM::Light* light = NULL;
if (index==-1)
error = 1;
else
{
/// \todo check for Deleted state (error 1)
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
model = referenceables.getData (index,
referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)).
toString().toUtf8().constData();
if (index == -1)
{
mBaseNode->addChild(createErrorCube());
return;
}
recordType =
referenceables.getData (index,
referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType)).toInt();
if (recordType == CSMWorld::UniversalId::Type_Light)
{
light = &dynamic_cast<const CSMWorld::Record<ESM::Light>& >(referenceables.getRecord(index)).get();
if (model.empty())
model = "marker_light.nif";
}
/// \todo check for Deleted state (error 1)
if (recordType == CSMWorld::UniversalId::Type_CreatureLevelledList)
{
if (model.empty())
model = "marker_creature.nif";
}
int recordType = referenceables.getData(index, TypeIndex).toInt();
std::string model = referenceables.getData(index, ModelIndex).toString().toUtf8().constData();
if (recordType != CSMWorld::UniversalId::Type_Npc && model.empty())
error = 2;
if (recordType == CSMWorld::UniversalId::Type_Light)
{
light = &dynamic_cast<const CSMWorld::Record<ESM::Light>& >(referenceables.getRecord(index)).get();
if (model.empty())
model = "marker_light.nif";
}
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
if (error)
if (recordType == CSMWorld::UniversalId::Type_CreatureLevelledList)
{
mBaseNode->addChild(createErrorCube());
if (model.empty())
model = "marker_creature.nif";
}
else
try
{
try
if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature)
{
if (recordType == CSMWorld::UniversalId::Type_Npc || recordType == CSMWorld::UniversalId::Type_Creature)
{
if (!mActor)
mActor.reset(new Actor(mReferenceableId, recordType, mData));
mActor->update();
mBaseNode->addChild(mActor->getBaseNode());
}
else
{
std::string path = "meshes\\" + model;
mResourceSystem->getSceneManager()->getInstance(path, mBaseNode);
}
if (!mActor) mActor.reset(new Actor(mReferenceableId, mData));
mActor->update();
mBaseNode->addChild(mActor->getBaseNode());
}
catch (std::exception& e)
else
{
Log(Debug::Error) << e.what();
mBaseNode->addChild(createErrorCube());
std::string path = "meshes\\" + model;
mResourceSystem->getSceneManager()->getInstance(path, mBaseNode);
}
}
catch (std::exception& e)
{
// TODO: use error marker mesh
Log(Debug::Error) << e.what();
}
if (light)
{

Loading…
Cancel
Save