1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-01 16:45:35 +00:00

Centralize actor data, simplify logic

This commit is contained in:
Kyle Cooley 2018-09-08 02:06:48 -04:00 committed by Andrei Kortunov
parent c1ec926f43
commit f43b70d77b
5 changed files with 116 additions and 143 deletions

View file

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

View file

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

View file

@ -18,15 +18,15 @@ namespace CSVRender
{ {
const std::string Actor::MeshPrefix = "meshes\\"; 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) : mId(id)
, mInitialized(false)
, mType(type)
, mData(data) , mData(data)
, mBaseNode(new osg::Group()) , mBaseNode(new osg::Group())
, mSkeleton(nullptr) , mSkeleton(nullptr)
{ {
mActorData = mData.getActorAdapter()->getActorData(mId); mActorData = mData.getActorAdapter()->getActorData(mId);
connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)),
this, SLOT(handleActorChanged(const std::string&)));
} }
osg::Group* Actor::getBaseNode() osg::Group* Actor::getBaseNode()
@ -35,26 +35,34 @@ namespace CSVRender
} }
void Actor::update() void Actor::update()
{
try
{ {
mBaseNode->removeChildren(0, mBaseNode->getNumChildren()); mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
if (mType == CSMWorld::UniversalId::Type_Npc) // Load skeleton
updateNpc(); std::string skeletonModel = mActorData->getSkeleton();
else if (mType == CSMWorld::UniversalId::Type_Creature) skeletonModel = Misc::ResourceHelpers::correctActorModelPath(skeletonModel, mData.getResourceSystem()->getVFS());
updateCreature(); loadSkeleton(skeletonModel);
}
catch (std::exception& e) if (!mActorData->isCreature())
{ {
Log(Debug::Info) << "Exception in Actor::update(): " << e.what(); // Get rid of the extra attachments
SceneUtil::CleanObjectRootVisitor cleanVisitor;
mSkeleton->accept(cleanVisitor);
cleanVisitor.remove();
// Attach parts to skeleton
loadBodyParts();
}
else
{
SceneUtil::RemoveTriBipVisitor removeTriBipVisitor;
mSkeleton->accept(removeTriBipVisitor);
removeTriBipVisitor.remove();
} }
if (!mInitialized) // Post setup
{ mSkeleton->markDirty();
mInitialized = true; mSkeleton->setActive(SceneUtil::Skeleton::Active);
connect(mData.getActorAdapter(), SIGNAL(actorChanged(const std::string&)), this, SLOT(handleActorChanged(const std::string&)));
}
} }
void Actor::handleActorChanged(const std::string& refId) 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) void Actor::loadSkeleton(const std::string& model)
{ {
auto sceneMgr = mData.getResourceSystem()->getSceneManager(); 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) for (int i = 0; i < ESM::PRT_Count; ++i)
{ {

View file

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

View file

@ -83,28 +83,26 @@ void CSVRender::Object::update()
{ {
clear(); 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 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 index = referenceables.searchId (mReferenceableId);
int recordType = -1;
const ESM::Light* light = NULL; const ESM::Light* light = NULL;
if (index==-1) mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
error = 1;
else if (index == -1)
{ {
mBaseNode->addChild(createErrorCube());
return;
}
/// \todo check for Deleted state (error 1) /// \todo check for Deleted state (error 1)
model = referenceables.getData (index, int recordType = referenceables.getData(index, TypeIndex).toInt();
referenceables.findColumnIndex (CSMWorld::Columns::ColumnId_Model)). std::string model = referenceables.getData(index, ModelIndex).toString().toUtf8().constData();
toString().toUtf8().constData();
recordType =
referenceables.getData (index,
referenceables.findColumnIndex(CSMWorld::Columns::ColumnId_RecordType)).toInt();
if (recordType == CSMWorld::UniversalId::Type_Light) if (recordType == CSMWorld::UniversalId::Type_Light)
{ {
light = &dynamic_cast<const CSMWorld::Record<ESM::Light>& >(referenceables.getRecord(index)).get(); light = &dynamic_cast<const CSMWorld::Record<ESM::Light>& >(referenceables.getRecord(index)).get();
@ -118,24 +116,11 @@ void CSVRender::Object::update()
model = "marker_creature.nif"; model = "marker_creature.nif";
} }
if (recordType != CSMWorld::UniversalId::Type_Npc && model.empty())
error = 2;
}
mBaseNode->removeChildren(0, mBaseNode->getNumChildren());
if (error)
{
mBaseNode->addChild(createErrorCube());
}
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) if (!mActor) mActor.reset(new Actor(mReferenceableId, mData));
mActor.reset(new Actor(mReferenceableId, recordType, mData));
mActor->update(); mActor->update();
mBaseNode->addChild(mActor->getBaseNode()); mBaseNode->addChild(mActor->getBaseNode());
} }
@ -147,9 +132,8 @@ void CSVRender::Object::update()
} }
catch (std::exception& e) catch (std::exception& e)
{ {
// TODO: use error marker mesh
Log(Debug::Error) << e.what(); Log(Debug::Error) << e.what();
mBaseNode->addChild(createErrorCube());
}
} }
if (light) if (light)