mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 18:35:20 +00:00
20da0892ef
Slowly moving through the open-cs errors Good progress in openCS Very good progress on openCS Getting closer with openCS OpenCS compiles and runs! Didn't have time to test it all though ix openMW everything compiles on windows?? Fix gcc Fix Clang
695 lines
21 KiB
C++
695 lines
21 KiB
C++
#include "actoradapter.hpp"
|
|
|
|
#include <QModelIndex>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
#include <apps/opencs/model/world/columns.hpp>
|
|
#include <apps/opencs/model/world/idcollection.hpp>
|
|
#include <apps/opencs/model/world/record.hpp>
|
|
#include <apps/opencs/model/world/refidcollection.hpp>
|
|
#include <apps/opencs/model/world/universalid.hpp>
|
|
|
|
#include <components/esm3/loadarmo.hpp>
|
|
#include <components/esm3/loadclot.hpp>
|
|
#include <components/esm3/loadcont.hpp>
|
|
#include <components/esm3/loadcrea.hpp>
|
|
#include <components/esm3/loadnpc.hpp>
|
|
#include <components/esm3/loadrace.hpp>
|
|
#include <components/esm3/mappings.hpp>
|
|
#include <components/sceneutil/actorutil.hpp>
|
|
|
|
#include "data.hpp"
|
|
|
|
namespace CSMWorld
|
|
{
|
|
const ESM::RefId& ActorAdapter::RaceData::getId() const
|
|
{
|
|
return mId;
|
|
}
|
|
|
|
bool ActorAdapter::RaceData::isBeast() const
|
|
{
|
|
return mIsBeast;
|
|
}
|
|
|
|
ActorAdapter::RaceData::RaceData()
|
|
{
|
|
mIsBeast = false;
|
|
}
|
|
|
|
bool ActorAdapter::RaceData::handlesPart(ESM::PartReferenceType type) const
|
|
{
|
|
switch (type)
|
|
{
|
|
case ESM::PRT_Skirt:
|
|
case ESM::PRT_Shield:
|
|
case ESM::PRT_RPauldron:
|
|
case ESM::PRT_LPauldron:
|
|
case ESM::PRT_Weapon:
|
|
return false;
|
|
default:
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const ESM::RefId& ActorAdapter::RaceData::getFemalePart(ESM::PartReferenceType index) const
|
|
{
|
|
return mFemaleParts[ESM::getMeshPart(index)];
|
|
}
|
|
|
|
const ESM::RefId& ActorAdapter::RaceData::getMalePart(ESM::PartReferenceType index) const
|
|
{
|
|
return mMaleParts[ESM::getMeshPart(index)];
|
|
}
|
|
|
|
bool ActorAdapter::RaceData::hasDependency(const ESM::RefId& id) const
|
|
{
|
|
return mDependencies.find(id) != mDependencies.end();
|
|
}
|
|
|
|
void ActorAdapter::RaceData::setFemalePart(ESM::BodyPart::MeshPart index, const ESM::RefId& partId)
|
|
{
|
|
mFemaleParts[index] = partId;
|
|
addOtherDependency(partId);
|
|
}
|
|
|
|
void ActorAdapter::RaceData::setMalePart(ESM::BodyPart::MeshPart index, const ESM::RefId& partId)
|
|
{
|
|
mMaleParts[index] = partId;
|
|
addOtherDependency(partId);
|
|
}
|
|
|
|
void ActorAdapter::RaceData::addOtherDependency(const ESM::RefId& id)
|
|
{
|
|
if (!id.empty())
|
|
mDependencies.emplace(id);
|
|
}
|
|
|
|
void ActorAdapter::RaceData::reset_data(const ESM::RefId& id, bool isBeast)
|
|
{
|
|
mId = id;
|
|
mIsBeast = isBeast;
|
|
for (auto& str : mFemaleParts)
|
|
str = ESM::RefId::sEmpty;
|
|
for (auto& str : mMaleParts)
|
|
str = ESM::RefId::sEmpty;
|
|
mDependencies.clear();
|
|
|
|
// Mark self as a dependency
|
|
addOtherDependency(id);
|
|
}
|
|
|
|
ActorAdapter::ActorData::ActorData()
|
|
{
|
|
mCreature = false;
|
|
mFemale = false;
|
|
}
|
|
|
|
const ESM::RefId& ActorAdapter::ActorData::getId() const
|
|
{
|
|
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);
|
|
}
|
|
|
|
std::string_view ActorAdapter::ActorData::getPart(ESM::PartReferenceType index) const
|
|
{
|
|
auto it = mParts.find(index);
|
|
if (it == mParts.end())
|
|
{
|
|
if (mRaceData && mRaceData->handlesPart(index))
|
|
{
|
|
if (mFemale)
|
|
{
|
|
// Note: we should use male parts for females as fallback
|
|
const std::string& femalePart = mRaceData->getFemalePart(index).getRefIdString();
|
|
if (!femalePart.empty())
|
|
return femalePart;
|
|
}
|
|
|
|
return mRaceData->getMalePart(index).getRefIdString();
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
return it->second.first;
|
|
}
|
|
|
|
bool ActorAdapter::ActorData::hasDependency(const ESM::RefId& id) const
|
|
{
|
|
return mDependencies.find(id) != mDependencies.end();
|
|
}
|
|
|
|
void ActorAdapter::ActorData::setPart(ESM::PartReferenceType index, const ESM::RefId& partId, int priority)
|
|
{
|
|
auto it = mParts.find(index);
|
|
if (it != mParts.end())
|
|
{
|
|
if (it->second.second >= priority)
|
|
return;
|
|
}
|
|
|
|
mParts[index] = std::make_pair(partId.getRefIdString(), priority);
|
|
addOtherDependency(partId);
|
|
}
|
|
|
|
void ActorAdapter::ActorData::addOtherDependency(const ESM::RefId& id)
|
|
{
|
|
if (!id.empty())
|
|
mDependencies.emplace(id);
|
|
}
|
|
|
|
void ActorAdapter::ActorData::reset_data(
|
|
const ESM::RefId& id, const std::string& skeleton, bool isCreature, bool isFemale, RaceDataPtr raceData)
|
|
{
|
|
mId = id;
|
|
mCreature = isCreature;
|
|
mFemale = isFemale;
|
|
mSkeletonOverride = skeleton;
|
|
mRaceData = raceData;
|
|
mParts.clear();
|
|
mDependencies.clear();
|
|
|
|
// Mark self and race as a dependency
|
|
addOtherDependency(id);
|
|
if (raceData)
|
|
addOtherDependency(raceData->getId());
|
|
}
|
|
|
|
ActorAdapter::ActorAdapter(Data& data)
|
|
: mReferenceables(data.getReferenceables())
|
|
, mRaces(data.getRaces())
|
|
, mBodyParts(data.getBodyParts())
|
|
{
|
|
// Setup qt slots and signals
|
|
QAbstractItemModel* refModel = data.getTableModel(UniversalId::Type_Referenceable);
|
|
connect(refModel, &QAbstractItemModel::rowsInserted, this, &ActorAdapter::handleReferenceablesInserted);
|
|
connect(refModel, &QAbstractItemModel::dataChanged, this, &ActorAdapter::handleReferenceableChanged);
|
|
connect(refModel, &QAbstractItemModel::rowsAboutToBeRemoved, this,
|
|
&ActorAdapter::handleReferenceablesAboutToBeRemoved);
|
|
|
|
QAbstractItemModel* raceModel = data.getTableModel(UniversalId::Type_Race);
|
|
connect(raceModel, &QAbstractItemModel::rowsInserted, this, &ActorAdapter::handleRacesAboutToBeRemoved);
|
|
connect(raceModel, &QAbstractItemModel::dataChanged, this, &ActorAdapter::handleRaceChanged);
|
|
connect(raceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ActorAdapter::handleRacesAboutToBeRemoved);
|
|
|
|
QAbstractItemModel* partModel = data.getTableModel(UniversalId::Type_BodyPart);
|
|
connect(partModel, &QAbstractItemModel::rowsInserted, this, &ActorAdapter::handleBodyPartsInserted);
|
|
connect(partModel, &QAbstractItemModel::dataChanged, this, &ActorAdapter::handleBodyPartChanged);
|
|
connect(
|
|
partModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &ActorAdapter::handleBodyPartsAboutToBeRemoved);
|
|
}
|
|
|
|
ActorAdapter::ActorDataPtr ActorAdapter::getActorData(const ESM::RefId& id)
|
|
{
|
|
// Return cached actor data if it exists
|
|
ActorDataPtr data = mCachedActors.get(id);
|
|
if (data)
|
|
{
|
|
return data;
|
|
}
|
|
|
|
// Create the actor data
|
|
data = std::make_shared<ActorData>();
|
|
setupActor(id, data);
|
|
mCachedActors.insert(id, data);
|
|
return data;
|
|
}
|
|
|
|
void ActorAdapter::handleReferenceablesInserted(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Only rows added at the top level are pertinent. Others are caught by dataChanged handler.
|
|
if (!parent.isValid())
|
|
{
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto refId = mReferenceables.getId(row);
|
|
markDirtyDependency(refId);
|
|
}
|
|
}
|
|
|
|
// Update affected
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleReferenceableChanged(const QModelIndex& topLeft, const QModelIndex& botRight)
|
|
{
|
|
int start = getHighestIndex(topLeft).row();
|
|
int end = getHighestIndex(botRight).row();
|
|
|
|
// A change to record status (ex. Deleted) returns an invalid botRight
|
|
if (end == -1)
|
|
end = start;
|
|
|
|
// Handle each record
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto refId = mReferenceables.getId(row);
|
|
markDirtyDependency(refId);
|
|
}
|
|
|
|
// Update affected
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleReferenceablesAboutToBeRemoved(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Only rows at the top are pertinent.
|
|
if (!parent.isValid())
|
|
{
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto refId = mReferenceables.getId(row);
|
|
markDirtyDependency(refId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::handleReferenceablesRemoved(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Changes specified in handleReferenceablesAboutToBeRemoved
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleRacesInserted(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Only rows added at the top are pertinent.
|
|
if (!parent.isValid())
|
|
{
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto raceId = mReferenceables.getId(row);
|
|
markDirtyDependency(raceId);
|
|
}
|
|
}
|
|
|
|
// Update affected
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleRaceChanged(const QModelIndex& topLeft, const QModelIndex& botRight)
|
|
{
|
|
int start = getHighestIndex(topLeft).row();
|
|
int end = getHighestIndex(botRight).row();
|
|
|
|
// A change to record status (ex. Deleted) returns an invalid botRight
|
|
if (end == -1)
|
|
end = start;
|
|
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto raceId = mRaces.getId(row);
|
|
markDirtyDependency(raceId);
|
|
}
|
|
|
|
// Update affected
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleRacesAboutToBeRemoved(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Only changes at the top are pertinent.
|
|
if (!parent.isValid())
|
|
{
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto raceId = mRaces.getId(row);
|
|
markDirtyDependency(raceId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::handleRacesRemoved(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Changes specified in handleRacesAboutToBeRemoved
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleBodyPartsInserted(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Only rows added at the top are pertinent.
|
|
if (!parent.isValid())
|
|
{
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
// Race specified by part may need update
|
|
auto& record = mBodyParts.getRecord(row);
|
|
if (!record.isDeleted())
|
|
{
|
|
markDirtyDependency(record.get().mRace);
|
|
}
|
|
|
|
auto partId = mBodyParts.getId(row);
|
|
markDirtyDependency(partId);
|
|
}
|
|
}
|
|
|
|
// Update affected
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleBodyPartChanged(const QModelIndex& topLeft, const QModelIndex& botRight)
|
|
{
|
|
int start = getHighestIndex(topLeft).row();
|
|
int end = getHighestIndex(botRight).row();
|
|
|
|
// A change to record status (ex. Deleted) returns an invalid botRight
|
|
if (end == -1)
|
|
end = start;
|
|
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
// Race specified by part may need update
|
|
auto& record = mBodyParts.getRecord(row);
|
|
if (!record.isDeleted())
|
|
{
|
|
markDirtyDependency(record.get().mRace);
|
|
}
|
|
|
|
// Update entries with a tracked dependency
|
|
auto partId = mBodyParts.getId(row);
|
|
markDirtyDependency(partId);
|
|
}
|
|
|
|
// Update affected
|
|
updateDirty();
|
|
}
|
|
|
|
void ActorAdapter::handleBodyPartsAboutToBeRemoved(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Only changes at the top are pertinent.
|
|
if (!parent.isValid())
|
|
{
|
|
for (int row = start; row <= end; ++row)
|
|
{
|
|
auto partId = mBodyParts.getId(row);
|
|
markDirtyDependency(partId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::handleBodyPartsRemoved(const QModelIndex& parent, int start, int end)
|
|
{
|
|
// Changes specified in handleBodyPartsAboutToBeRemoved
|
|
updateDirty();
|
|
}
|
|
|
|
QModelIndex ActorAdapter::getHighestIndex(QModelIndex index) const
|
|
{
|
|
while (index.parent().isValid())
|
|
index = index.parent();
|
|
return index;
|
|
}
|
|
|
|
bool ActorAdapter::is1stPersonPart(const std::string& name) const
|
|
{
|
|
return name.size() >= 4 && name.find(".1st", name.size() - 4) != std::string::npos;
|
|
}
|
|
|
|
ActorAdapter::RaceDataPtr ActorAdapter::getRaceData(const ESM::RefId& id)
|
|
{
|
|
// Return cached race data if it exists
|
|
RaceDataPtr data = mCachedRaces.get(id);
|
|
if (data)
|
|
return data;
|
|
|
|
// Create the race data
|
|
data = std::make_shared<RaceData>();
|
|
setupRace(id, data);
|
|
mCachedRaces.insert(id, data);
|
|
return data;
|
|
}
|
|
|
|
void ActorAdapter::setupActor(const ESM::RefId& id, ActorDataPtr data)
|
|
{
|
|
int index = mReferenceables.searchId(id);
|
|
if (index == -1)
|
|
{
|
|
// Record does not exist
|
|
data->reset_data(id);
|
|
emit actorChanged(id);
|
|
return;
|
|
}
|
|
|
|
auto& record = mReferenceables.getRecord(index);
|
|
if (record.isDeleted())
|
|
{
|
|
// Record is deleted and therefore not accessible
|
|
data->reset_data(id);
|
|
emit actorChanged(id);
|
|
return;
|
|
}
|
|
|
|
const int TypeColumn = mReferenceables.findColumnIndex(Columns::ColumnId_RecordType);
|
|
int type = mReferenceables.getData(index, TypeColumn).toInt();
|
|
if (type == UniversalId::Type_Creature)
|
|
{
|
|
// Valid creature record
|
|
setupCreature(id, data);
|
|
emit actorChanged(id);
|
|
}
|
|
else if (type == UniversalId::Type_Npc)
|
|
{
|
|
// Valid npc record
|
|
setupNpc(id, data);
|
|
emit actorChanged(id);
|
|
}
|
|
else
|
|
{
|
|
// Wrong record type
|
|
data->reset_data(id);
|
|
emit actorChanged(id);
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::setupRace(const ESM::RefId& id, RaceDataPtr data)
|
|
{
|
|
int index = mRaces.searchId(id);
|
|
if (index == -1)
|
|
{
|
|
// Record does not exist
|
|
data->reset_data(id);
|
|
return;
|
|
}
|
|
|
|
auto& raceRecord = mRaces.getRecord(index);
|
|
if (raceRecord.isDeleted())
|
|
{
|
|
// Record is deleted, so not accessible
|
|
data->reset_data(id);
|
|
return;
|
|
}
|
|
|
|
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)
|
|
{
|
|
auto partId = mBodyParts.getId(i);
|
|
auto& partRecord = mBodyParts.getRecord(i);
|
|
|
|
if (partRecord.isDeleted())
|
|
{
|
|
// Record is deleted, so not accessible.
|
|
continue;
|
|
}
|
|
|
|
auto& part = partRecord.get();
|
|
if (part.mRace == id && part.mData.mType == ESM::BodyPart::MT_Skin && !is1stPersonPart(part.mId.getRefIdString()))
|
|
{
|
|
auto type = (ESM::BodyPart::MeshPart)part.mData.mPart;
|
|
bool female = part.mData.mFlags & ESM::BodyPart::BPF_Female;
|
|
if (female)
|
|
data->setFemalePart(type, part.mId);
|
|
else
|
|
data->setMalePart(type, part.mId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::setupNpc(const ESM::RefId& id, ActorDataPtr data)
|
|
{
|
|
// Common setup, record is known to exist and is not deleted
|
|
int index = mReferenceables.searchId(id);
|
|
auto& npc = dynamic_cast<const Record<ESM::NPC>&>(mReferenceables.getRecord(index)).get();
|
|
|
|
RaceDataPtr raceData = getRaceData(npc.mRace);
|
|
data->reset_data(id, "", false, !npc.isMale(), raceData);
|
|
|
|
// Add head and hair
|
|
data->setPart(ESM::PRT_Head, npc.mHead, 0);
|
|
data->setPart(ESM::PRT_Hair, npc.mHair, 0);
|
|
|
|
// Add inventory items
|
|
for (auto& item : npc.mInventory.mList)
|
|
{
|
|
if (item.mCount <= 0)
|
|
continue;
|
|
auto itemId = item.mItem;
|
|
addNpcItem(itemId, data);
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::addNpcItem(const ESM::RefId& itemId, ActorDataPtr data)
|
|
{
|
|
int index = mReferenceables.searchId(itemId);
|
|
if (index == -1)
|
|
{
|
|
// Item does not exist yet
|
|
data->addOtherDependency(itemId);
|
|
return;
|
|
}
|
|
|
|
auto& record = mReferenceables.getRecord(index);
|
|
if (record.isDeleted())
|
|
{
|
|
// Item cannot be accessed yet
|
|
data->addOtherDependency(itemId);
|
|
return;
|
|
}
|
|
|
|
// Convenience function to add a parts list to actor data
|
|
auto addParts = [&](const std::vector<ESM::PartReference>& list, int priority) {
|
|
for (auto& part : list)
|
|
{
|
|
ESM::RefId partId;
|
|
auto partType = (ESM::PartReferenceType)part.mPart;
|
|
|
|
if (data->isFemale())
|
|
partId = part.mFemale;
|
|
if (partId.empty())
|
|
partId = part.mMale;
|
|
|
|
data->setPart(partType, partId, priority);
|
|
|
|
// An another vanilla quirk: hide hairs if an item replaces Head part
|
|
if (partType == ESM::PRT_Head)
|
|
data->setPart(ESM::PRT_Hair, ESM::RefId::sEmpty, priority);
|
|
}
|
|
};
|
|
|
|
int TypeColumn = mReferenceables.findColumnIndex(Columns::ColumnId_RecordType);
|
|
int type = mReferenceables.getData(index, TypeColumn).toInt();
|
|
if (type == UniversalId::Type_Armor)
|
|
{
|
|
auto& armor = dynamic_cast<const Record<ESM::Armor>&>(record).get();
|
|
addParts(armor.mParts.mParts, 1);
|
|
|
|
// Changing parts could affect what is picked for rendering
|
|
data->addOtherDependency(itemId);
|
|
}
|
|
else if (type == UniversalId::Type_Clothing)
|
|
{
|
|
auto& clothing = dynamic_cast<const Record<ESM::Clothing>&>(record).get();
|
|
|
|
std::vector<ESM::PartReferenceType> parts;
|
|
if (clothing.mData.mType == ESM::Clothing::Robe)
|
|
{
|
|
parts = { ESM::PRT_Groin, ESM::PRT_Skirt, ESM::PRT_RLeg, ESM::PRT_LLeg, ESM::PRT_RUpperarm,
|
|
ESM::PRT_LUpperarm, ESM::PRT_RKnee, ESM::PRT_LKnee, ESM::PRT_RForearm, ESM::PRT_LForearm,
|
|
ESM::PRT_Cuirass };
|
|
}
|
|
else if (clothing.mData.mType == ESM::Clothing::Skirt)
|
|
{
|
|
parts = { ESM::PRT_Groin, ESM::PRT_RLeg, ESM::PRT_LLeg };
|
|
}
|
|
|
|
std::vector<ESM::PartReference> reservedList;
|
|
for (const auto& p : parts)
|
|
{
|
|
ESM::PartReference pr;
|
|
pr.mPart = p;
|
|
reservedList.emplace_back(pr);
|
|
}
|
|
|
|
int priority = parts.size();
|
|
addParts(clothing.mParts.mParts, priority);
|
|
addParts(reservedList, priority);
|
|
|
|
// Changing parts could affect what is picked for rendering
|
|
data->addOtherDependency(itemId);
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::setupCreature(const ESM::RefId& id, ActorDataPtr data)
|
|
{
|
|
// 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();
|
|
|
|
data->reset_data(id, creature.mModel, true);
|
|
}
|
|
|
|
void ActorAdapter::markDirtyDependency(const ESM::RefId& dep)
|
|
{
|
|
for (auto raceIt : mCachedRaces)
|
|
{
|
|
if (raceIt->hasDependency(dep))
|
|
mDirtyRaces.emplace(raceIt->getId());
|
|
}
|
|
for (auto actorIt : mCachedActors)
|
|
{
|
|
if (actorIt->hasDependency(dep))
|
|
mDirtyActors.emplace(actorIt->getId());
|
|
}
|
|
}
|
|
|
|
void ActorAdapter::updateDirty()
|
|
{
|
|
// Handle races before actors, since actors are dependent on race
|
|
for (auto& race : mDirtyRaces)
|
|
{
|
|
RaceDataPtr data = mCachedRaces.get(race);
|
|
if (data)
|
|
{
|
|
setupRace(race, data);
|
|
// Race was changed. Need to mark actor dependencies as dirty.
|
|
// Cannot use markDirtyDependency because that would invalidate
|
|
// the current iterator.
|
|
for (auto actorIt : mCachedActors)
|
|
{
|
|
if (actorIt->hasDependency(race))
|
|
mDirtyActors.emplace(actorIt->getId());
|
|
}
|
|
}
|
|
}
|
|
mDirtyRaces.clear();
|
|
|
|
for (auto& actor : mDirtyActors)
|
|
{
|
|
ActorDataPtr data = mCachedActors.get(actor);
|
|
if (data)
|
|
{
|
|
setupActor(actor, data);
|
|
}
|
|
}
|
|
mDirtyActors.clear();
|
|
}
|
|
}
|