Skip to content

Commit 6ccf3cf

Browse files
committed
Merge branch 'issue_9084_inactive_cell_save_bloat' into 'master'
Bug #9084: Skip refs without custom data in cell rest/recharge/respawn Closes #9084 See merge request OpenMW/openmw!5304
2 parents fc5fa22 + 0c0f127 commit 6ccf3cf

3 files changed

Lines changed: 28 additions & 9 deletions

File tree

apps/openmw/mwworld/cellstore.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,18 +1160,20 @@ namespace MWWorld
11601160
{
11611161
if (mState == State_Loaded)
11621162
{
1163+
// Refs with no custom data are at default dynamic stats — there is nothing to restore,
1164+
// and touching them would force-allocate custom data that then bloats the save file.
11631165
for (MWWorld::LiveCellRef<ESM::Creature>& creature : get<ESM::Creature>().mList)
11641166
{
11651167
Ptr ptr = getCurrentPtr(&creature);
1166-
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
1168+
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0 && ptr.getRefData().hasCustomData())
11671169
{
11681170
MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true);
11691171
}
11701172
}
11711173
for (MWWorld::LiveCellRef<ESM::NPC>& npc : get<ESM::NPC>().mList)
11721174
{
11731175
Ptr ptr = getCurrentPtr(&npc);
1174-
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
1176+
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0 && ptr.getRefData().hasCustomData())
11751177
{
11761178
MWBase::Environment::get().getMechanicsManager()->restoreDynamicStats(ptr, hours, true);
11771179
}
@@ -1186,26 +1188,28 @@ namespace MWWorld
11861188

11871189
if (mState == State_Loaded)
11881190
{
1191+
// Skip refs that have no custom data — they have no container to recharge,
1192+
// and getContainerStore() would force-allocate custom data and bloat the save file.
11891193
for (MWWorld::LiveCellRef<ESM::Creature>& creature : get<ESM::Creature>().mList)
11901194
{
11911195
Ptr ptr = getCurrentPtr(&creature);
1192-
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
1196+
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0 && ptr.getRefData().hasCustomData())
11931197
{
11941198
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
11951199
}
11961200
}
11971201
for (MWWorld::LiveCellRef<ESM::NPC>& npc : get<ESM::NPC>().mList)
11981202
{
11991203
Ptr ptr = getCurrentPtr(&npc);
1200-
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0)
1204+
if (!ptr.isEmpty() && ptr.getCellRef().getCount() > 0 && ptr.getRefData().hasCustomData())
12011205
{
12021206
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
12031207
}
12041208
}
12051209
for (MWWorld::LiveCellRef<ESM::Container>& container : get<ESM::Container>().mList)
12061210
{
12071211
Ptr ptr = getCurrentPtr(&container);
1208-
if (!ptr.isEmpty() && ptr.getRefData().getCustomData() != nullptr && ptr.getCellRef().getCount() > 0
1212+
if (!ptr.isEmpty() && ptr.getRefData().hasCustomData() && ptr.getCellRef().getCount() > 0
12091213
&& ptr.getClass().getContainerStore(ptr).isResolved())
12101214
{
12111215
ptr.getClass().getContainerStore(ptr).rechargeItems(duration);
@@ -1229,27 +1233,35 @@ namespace MWWorld
12291233
it != get<ESM::Container>().mList.end(); ++it)
12301234
{
12311235
Ptr ptr = getCurrentPtr(&*it);
1232-
ptr.getClass().respawn(ptr);
1236+
if (ptr.getRefData().hasCustomData())
1237+
ptr.getClass().respawn(ptr);
12331238
}
12341239
}
12351240

1236-
// Actors need to respawn here even if they've been moved to another cell
1241+
// Skip refs with no custom data: they cannot have been killed, looted, or had their inventory
1242+
// generated, so respawn/clearCorpse have no work to do and would only force-allocate custom
1243+
// data that then bloats the save file. Actors need to respawn here even if they've been moved
1244+
// to another cell.
12371245
for (LiveCellRefBase& base : get<ESM::Creature>().mList)
12381246
{
12391247
Ptr ptr = getCurrentPtr(&base);
1248+
if (!ptr.getRefData().hasCustomData())
1249+
continue;
12401250
clearCorpse(ptr, mStore);
12411251
ptr.getClass().respawn(ptr);
12421252
}
12431253
for (LiveCellRefBase& base : get<ESM::NPC>().mList)
12441254
{
12451255
Ptr ptr = getCurrentPtr(&base);
1256+
if (!ptr.getRefData().hasCustomData())
1257+
continue;
12461258
clearCorpse(ptr, mStore);
12471259
ptr.getClass().respawn(ptr);
12481260
}
12491261
for (LiveCellRefBase& base : get<ESM::CreatureLevList>().mList)
12501262
{
12511263
Ptr ptr = getCurrentPtr(&base);
1252-
if (!ptr.mRef->isDeleted())
1264+
if (!ptr.mRef->isDeleted() && ptr.getRefData().hasCustomData())
12531265
ptr.getClass().respawn(ptr);
12541266
}
12551267
for (const auto& [base, _] : mMovedHere)
@@ -1261,7 +1273,7 @@ namespace MWWorld
12611273
case ESM::CreatureLevList::sRecordId:
12621274
{
12631275
MWWorld::Ptr ptr(base, this);
1264-
if (ptr.mRef->isDeleted())
1276+
if (ptr.mRef->isDeleted() || !ptr.getRefData().hasCustomData())
12651277
continue;
12661278
// Remove actors that have been dead a while, but don't belong here and didn't get hit by the
12671279
// logic above

apps/openmw/mwworld/refdata.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ namespace MWWorld
269269
return mCustomData.get();
270270
}
271271

272+
bool RefData::hasCustomData() const
273+
{
274+
return mCustomData != nullptr;
275+
}
276+
272277
bool RefData::hasChanged() const
273278
{
274279
return mChanged || !mAnimationState.empty();

apps/openmw/mwworld/refdata.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ namespace MWWorld
135135

136136
const CustomData* getCustomData() const;
137137

138+
bool hasCustomData() const;
139+
138140
bool activate();
139141

140142
bool onActivate();

0 commit comments

Comments
 (0)