Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add medium plugin support (Starfield) (ModOrganizer2#2048)
Browse files Browse the repository at this point in the history
* Add medium plugin support (Starfield)
- Coopt the overlay support for the new 'medium' / ESH plugin flag
- Update various displays to include ESH info
* Rework address display for SF weirdness
* Fix core ESH display
Silarn authored Jun 13, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 3d8bfdd commit 6d08d43
Showing 5 changed files with 109 additions and 71 deletions.
124 changes: 81 additions & 43 deletions src/pluginlist.cpp
Original file line number Diff line number Diff line change
@@ -180,8 +180,8 @@ void PluginList::refresh(const QString& profileName,
auto gamePlugins = m_Organizer.gameFeatures().gameFeature<GamePlugins>();
const bool lightPluginsAreSupported =
gamePlugins ? gamePlugins->lightPluginsAreSupported() : false;
const bool overridePluginsAreSupported =
gamePlugins ? gamePlugins->overridePluginsAreSupported() : false;
const bool mediumPluginsAreSupported =
gamePlugins ? gamePlugins->mediumPluginsAreSupported() : false;
const bool loadOrderMechanismNone =
m_GamePlugin->loadOrderMechanism() == IPluginGame::LoadOrderMechanism::None;

@@ -245,7 +245,7 @@ void PluginList::refresh(const QString& profileName,
m_ESPs.emplace_back(filename, forceLoaded, forceEnabled, forceDisabled,
originName, ToQString(current->getFullPath()), hasIni,
loadedArchives, lightPluginsAreSupported,
overridePluginsAreSupported);
mediumPluginsAreSupported);
m_ESPs.rbegin()->priority = -1;
} catch (const std::exception& e) {
reportError(tr("failed to update esp info for file %1 (source id: %2), error: %3")
@@ -998,23 +998,23 @@ bool PluginList::isMasterFlagged(const QString& name) const
}
}

bool PluginList::isLightFlagged(const QString& name) const
bool PluginList::isMediumFlagged(const QString& name) const
{
auto iter = m_ESPsByName.find(name);
if (iter == m_ESPsByName.end()) {
return false;
} else {
return m_ESPs[iter->second].isLightFlagged;
return m_ESPs[iter->second].isMediumFlagged;
}
}

bool PluginList::isOverlayFlagged(const QString& name) const
bool PluginList::isLightFlagged(const QString& name) const
{
auto iter = m_ESPsByName.find(name);
if (iter == m_ESPsByName.end()) {
return false;
} else {
return m_ESPs[iter->second].isOverlayFlagged;
return m_ESPs[iter->second].isLightFlagged;
}
}

@@ -1082,13 +1082,17 @@ void PluginList::updateIndices()
void PluginList::generatePluginIndexes()
{
int numESLs = 0;
int numESHs = 0;
int numSkipped = 0;

auto gamePlugins = m_Organizer.gameFeatures().gameFeature<GamePlugins>();
const bool lightPluginsSupported =
gamePlugins ? gamePlugins->lightPluginsAreSupported() : false;
const bool overridePluginsSupported =
gamePlugins ? gamePlugins->overridePluginsAreSupported() : false;
const bool mediumPluginsSupported =
gamePlugins ? gamePlugins->mediumPluginsAreSupported() : false;

std::vector<int> coreLightPlugins;
std::vector<int> coreMediumPlugins;

for (int l = 0; l < m_ESPs.size(); ++l) {
int i = m_ESPsByPriority.at(l);
@@ -1097,25 +1101,59 @@ void PluginList::generatePluginIndexes()
++numSkipped;
continue;
}
if (lightPluginsSupported &&
(m_ESPs[i].hasLightExtension || m_ESPs[i].isLightFlagged)) {
if (mediumPluginsSupported && m_ESPs[i].isMediumFlagged) {
if (mediumPluginsSupported && m_ESPs[i].forceLoaded) {
// Starfield core medium plugins are loaded in memory addresses after custom
// medium plugins
coreMediumPlugins.push_back(i);
++numSkipped;
continue;
}
int ESHpos = 253 + ((numESHs + 1) / 256);
m_ESPs[i].index = QString("%1:%2")
.arg(ESHpos, 2, 16, QChar('0'))
.arg(numESHs % 256, 2, 16, QChar('0'))
.toUpper();
++numESHs;

} else if (lightPluginsSupported &&
(m_ESPs[i].hasLightExtension || m_ESPs[i].isLightFlagged)) {
// Starfield core light plugins are loaded in memory addresses after custom light
// plugins
if (mediumPluginsSupported && m_ESPs[i].forceLoaded) {
coreLightPlugins.push_back(i);
++numSkipped;
continue;
}

int ESLpos = 254 + ((numESLs + 1) / 4096);
m_ESPs[i].index = QString("%1:%2")
.arg(ESLpos, 2, 16, QChar('0'))
.arg((numESLs) % 4096, 3, 16, QChar('0'))
.arg(numESLs % 4096, 3, 16, QChar('0'))
.toUpper();
++numESLs;
// This logic may still be used if overlay plugins are fixed to longer consume a
// load order slot
//
//} else if (overridePluginsSupported && m_ESPs[i].isOverlayFlagged) {
// m_ESPs[i].index = QString("XX");
// ++numSkipped;
} else {
m_ESPs[i].index =
QString("%1").arg(l - numESLs - numSkipped, 2, 16, QChar('0')).toUpper();
m_ESPs[i].index = QString("%1")
.arg(l - numESHs - numESLs - numSkipped, 2, 16, QChar('0'))
.toUpper();
}
}
for (auto pluginIndex : coreMediumPlugins) {
int ESHpos = 253 + ((numESHs + 1) / 4096);
m_ESPs[pluginIndex].index = QString("%1:%2")
.arg(ESHpos, 2, 16, QChar('0'))
.arg(numESHs % 256, 2, 16, QChar('0'))
.toUpper();
++numESHs;
}
for (auto pluginIndex : coreLightPlugins) {
int ESLpos = 254 + ((numESLs + 1) / 4096);
m_ESPs[pluginIndex].index = QString("%1:%2")
.arg(ESLpos, 2, 16, QChar('0'))
.arg(numESLs % 4096, 3, 16, QChar('0'))
.toUpper();
++numESLs;
}
emit esplist_changed();
}

@@ -1245,6 +1283,8 @@ QVariant PluginList::fontData(const QModelIndex& modelIndex) const
if (m_ESPs[index].hasMasterExtension || m_ESPs[index].isMasterFlagged ||
m_ESPs[index].hasLightExtension)
result.setWeight(QFont::Bold);
if (m_ESPs[index].isMediumFlagged)
result.setUnderline(true);
if (m_ESPs[index].isLightFlagged || m_ESPs[index].hasLightExtension)
result.setItalic(true);

@@ -1332,24 +1372,22 @@ QVariant PluginList::tooltipData(const QModelIndex& modelIndex) const
"be added to your game settings, overwriting in case of conflicts.");
}

if (esp.isMediumFlagged && esp.hasMasterExtension) {
toolTip += "<br><br>" +
tr("This ESM is flagged as a medium plugin (ESH). It adheres to the ESM "
"load order but loads records in ESH space (FD). You can have 256 "
"medium plugins in addition to other plugin types.");
}

if (esp.isLightFlagged && !esp.hasLightExtension) {
QString type = esp.hasMasterExtension ? "ESM" : "ESP";
toolTip +=
"<br><br>" + tr("This %1 is flagged as an ESL. It will adhere to the %1 load "
"order but the records will be loaded in ESL space.")
.arg(type);
}

// This logic may still be used if overlay plugins are fixed to longer consume a load
// order slot
//
// if (esp.isOverlayFlagged) {
// toolTip +=
// "<br><br>" + tr("This plugin is flagged as an overlay plugin. It contains
// only "
// "modified records and will overlay those changes onto the "
// "existing records in memory. It takes no memory space.");
// }
"<br><br>" +
tr("This %1 is flagged as a light plugin (ESL). It will adhere to the %1 load "
"order but the records will be loaded in ESL space (FE/FF). You can have up "
"to 4096 light plugins in addition to other plugin types.")
.arg(type);
}

if (esp.hasNoRecords) {
toolTip += "<br><br>" + tr("This is a dummy plugin. It contains no records and is "
@@ -1477,6 +1515,10 @@ QVariant PluginList::iconData(const QModelIndex& modelIndex) const
result.append(":/MO/gui/archive_conflict_neutral");
}

if (esp.isMediumFlagged) {
result.append(":/MO/gui/run");
}

if (esp.isLightFlagged && !esp.hasLightExtension) {
result.append(":/MO/gui/awaiting");
}
@@ -1485,10 +1527,6 @@ QVariant PluginList::iconData(const QModelIndex& modelIndex) const
result.append(":/MO/gui/unchecked-checkbox");
}

if (esp.isOverlayFlagged) {
result.append(":/MO/gui/instance_switch");
}

if (info && !info->loot.dirty.empty()) {
result.append(":/MO/gui/edit_clear");
}
@@ -1801,7 +1839,7 @@ PluginList::ESPInfo::ESPInfo(const QString& name, bool forceLoaded, bool forceEn
bool forceDisabled, const QString& originName,
const QString& fullPath, bool hasIni,
std::set<QString> archives, bool lightSupported,
bool overlaySupported)
bool mediumSupported)
: name(name), fullPath(fullPath), enabled(forceLoaded), forceLoaded(forceLoaded),
forceEnabled(forceEnabled), forceDisabled(forceDisabled), priority(0),
loadOrder(-1), originName(originName), hasIni(hasIni),
@@ -1813,9 +1851,9 @@ PluginList::ESPInfo::ESPInfo(const QString& name, bool forceLoaded, bool forceEn
hasMasterExtension = (extension == "esm");
hasLightExtension = (extension == "esl");
isMasterFlagged = file.isMaster();
isOverlayFlagged = overlaySupported && file.isOverlay();
isMediumFlagged = mediumSupported && file.isMedium();
isLightFlagged =
lightSupported && !isOverlayFlagged && file.isLight(overlaySupported);
lightSupported && !isMediumFlagged && file.isLight(mediumSupported);
hasNoRecords = file.isDummy();

author = QString::fromLatin1(file.author().c_str());
@@ -1829,7 +1867,7 @@ PluginList::ESPInfo::ESPInfo(const QString& name, bool forceLoaded, bool forceEn
hasMasterExtension = false;
hasLightExtension = false;
isMasterFlagged = false;
isOverlayFlagged = false;
isMediumFlagged = false;
isLightFlagged = false;
hasNoRecords = false;
}
6 changes: 3 additions & 3 deletions src/pluginlist.h
Original file line number Diff line number Diff line change
@@ -240,8 +240,8 @@ class PluginList : public QAbstractItemModel
bool hasMasterExtension(const QString& name) const;
bool hasLightExtension(const QString& name) const;
bool isMasterFlagged(const QString& name) const;
bool isMediumFlagged(const QString& name) const;
bool isLightFlagged(const QString& name) const;
bool isOverlayFlagged(const QString& name) const;
bool hasNoRecords(const QString& name) const;

boost::signals2::connection onRefreshed(const std::function<void()>& callback);
@@ -317,7 +317,7 @@ public slots:
ESPInfo(const QString& name, bool forceLoaded, bool forceEnabled,
bool forceDisabled, const QString& originName, const QString& fullPath,
bool hasIni, std::set<QString> archives, bool lightSupported,
bool overrideSupported);
bool mediumSupported);

QString name;
QString fullPath;
@@ -333,8 +333,8 @@ public slots:
bool hasMasterExtension;
bool hasLightExtension;
bool isMasterFlagged;
bool isMediumFlagged;
bool isLightFlagged;
bool isOverlayFlagged;
bool hasNoRecords;
bool modSelected;
QString author;
8 changes: 4 additions & 4 deletions src/pluginlistproxy.cpp
Original file line number Diff line number Diff line change
@@ -114,14 +114,14 @@ bool PluginListProxy::isMasterFlagged(const QString& name) const
return m_Proxied->isMasterFlagged(name);
}

bool PluginListProxy::isLightFlagged(const QString& name) const
bool PluginListProxy::isMediumFlagged(const QString& name) const
{
return m_Proxied->isLightFlagged(name);
return m_Proxied->isMediumFlagged(name);
}

bool PluginListProxy::isOverlayFlagged(const QString& name) const
bool PluginListProxy::isLightFlagged(const QString& name) const
{
return m_Proxied->isOverlayFlagged(name);
return m_Proxied->isLightFlagged(name);
}

bool PluginListProxy::hasNoRecords(const QString& name) const
2 changes: 1 addition & 1 deletion src/pluginlistproxy.h
Original file line number Diff line number Diff line change
@@ -32,8 +32,8 @@ class PluginListProxy : public MOBase::IPluginList
bool hasMasterExtension(const QString& name) const override;
bool hasLightExtension(const QString& name) const override;
bool isMasterFlagged(const QString& name) const override;
bool isMediumFlagged(const QString& name) const override;
bool isLightFlagged(const QString& name) const override;
bool isOverlayFlagged(const QString& name) const override;
bool hasNoRecords(const QString& name) const override;

private:
40 changes: 20 additions & 20 deletions src/pluginlistview.cpp
Original file line number Diff line number Diff line change
@@ -56,44 +56,44 @@ QModelIndexList PluginListView::indexViewToModel(const QModelIndexList& index) c

void PluginListView::updatePluginCount()
{
int activeMasterCount = 0;
int activeLightMasterCount = 0;
int activeOverlayCount = 0;
int activeRegularCount = 0;
int masterCount = 0;
int lightMasterCount = 0;
int overlayCount = 0;
int regularCount = 0;
int activeVisibleCount = 0;
int activeMasterCount = 0;
int activeMediumMasterCount = 0;
int activeLightMasterCount = 0;
int activeRegularCount = 0;
int masterCount = 0;
int mediumMasterCount = 0;
int lightMasterCount = 0;
int regularCount = 0;
int activeVisibleCount = 0;

PluginList* list = m_core->pluginList();
QString filter = ui.filter->text();

for (QString plugin : list->pluginNames()) {
bool active = list->isEnabled(plugin);
bool visible = m_sortProxy->filterMatchesPlugin(plugin);
if (list->hasLightExtension(plugin) || list->isLightFlagged(plugin)) {
if (list->isMediumFlagged(plugin)) {
mediumMasterCount++;
activeMediumMasterCount += active;
activeVisibleCount += visible && active;
} else if (list->hasLightExtension(plugin) || list->isLightFlagged(plugin)) {
lightMasterCount++;
activeLightMasterCount += active;
activeVisibleCount += visible && active;
} else if (list->hasMasterExtension(plugin) || list->isMasterFlagged(plugin)) {
masterCount++;
activeMasterCount += active;
activeVisibleCount += visible && active;
} else if (list->isOverlayFlagged(plugin)) {
overlayCount++;
activeOverlayCount += active;
activeVisibleCount += visible && active;
} else {
regularCount++;
activeRegularCount += active;
activeVisibleCount += visible && active;
}
}

int activeCount = activeMasterCount + activeLightMasterCount + activeOverlayCount +
activeRegularCount;
int totalCount = masterCount + lightMasterCount + overlayCount + regularCount;
int activeCount = activeMasterCount + activeMediumMasterCount +
activeLightMasterCount + activeRegularCount;
int totalCount = masterCount + mediumMasterCount + lightMasterCount + regularCount;

ui.counter->display(activeVisibleCount);
ui.counter->setToolTip(
@@ -105,8 +105,8 @@ void PluginListView::updatePluginCount()
"<tr><td>ESPs:</td><td align=right>%7 </td><td align=right>%8</td></tr>"
"<tr><td>ESMs+ESPs:</td><td align=right>%9 </td><td "
"align=right>%10</td></tr>"
"<tr><td>ESHs:</td><td align=right>%11 </td><td align=right>%12</td></tr>"
"<tr><td>ESLs:</td><td align=right>%5 </td><td align=right>%6</td></tr>"
"<tr><td>Overlay:</td><td align=right>%11 </td><td align=right>%12</td></tr>"
"</table>")
.arg(activeCount)
.arg(totalCount)
@@ -118,8 +118,8 @@ void PluginListView::updatePluginCount()
.arg(regularCount)
.arg(activeMasterCount + activeRegularCount)
.arg(masterCount + regularCount)
.arg(activeOverlayCount)
.arg(overlayCount));
.arg(activeMediumMasterCount)
.arg(mediumMasterCount));
}

void PluginListView::onFilterChanged(const QString& filter)

0 comments on commit 6d08d43

Please sign in to comment.