Skip to content

Commit

Permalink
add separate combo box for selecting flag in db's comparison, change …
Browse files Browse the repository at this point in the history
…`themeNameOfOffset` so it returns QString since it was always converted to it anyway
  • Loading branch information
Mr-Auto committed May 24, 2024
1 parent dd13c2c commit 77ff4ea
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 46 deletions.
7 changes: 5 additions & 2 deletions include/QtHelpers/WidgetDatabaseView.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ namespace S2Plugin
void fieldUpdated(int row, QStandardItem* parrent);
void fieldExpanded(const QModelIndex& index);
void comparisonFieldChosen();
void comparisonFlagChosen(const QString& text);
void compareGroupByCheckBoxClicked(int state);
void comparisonCellClicked(int row, int column);
void groupedComparisonItemClicked(QTreeWidgetItem* item);
Expand All @@ -73,14 +74,16 @@ namespace S2Plugin
QLineEdit* mSearchLineEdit;
TreeViewMemoryFields* mMainTreeView;
QTableWidget* mCompareTableWidget;
bool mFieldChoosen{false};

private:
QTabWidget* mMainTabWidget;
QComboBox* mCompareFieldComboBox;
QComboBox* mCompareFlagComboBox;
QTreeWidget* mCompareTreeWidget;

void populateComparisonTableWidget();
void populateComparisonTreeWidget();
void populateComparisonTableWidget(const QVariant& fieldData);
void populateComparisonTreeWidget(const QVariant& fieldData);
size_t populateComparisonCombobox(const std::vector<MemoryField>& fields, size_t offset = 0, std::string prefix = {});
static std::pair<QString, QVariant> valueForField(const QVariant& data, uintptr_t addr);
};
Expand Down
4 changes: 2 additions & 2 deletions include/Spelunky2.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
#include "Data/StringsTable.h"
#include "Data/TextureDB.h"
#include "Data/VirtualTableLookup.h"
#include <QString>
#include <cstdint>
#include <string>

namespace S2Plugin
{
Expand Down Expand Up @@ -54,7 +54,7 @@ namespace S2Plugin
uintptr_t find(const char* pattern, uintptr_t start = 0, size_t size = 0) const;
uintptr_t find_between(const char* pattern, uintptr_t start = 0, uintptr_t end = 0) const;

std::string themeNameOfOffset(uintptr_t offset) const;
const QString& themeNameOfOffset(uintptr_t offset) const;

private:
static Spelunky2* ptr;
Expand Down
15 changes: 7 additions & 8 deletions src/QtHelpers/TreeViewMemoryFields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ QStandardItem* S2Plugin::TreeViewMemoryFields::addMemoryField(const MemoryField&
auto itemFieldType = new QStandardItem();
itemFieldType->setEditable(false);

QString typeName = field.isPointer ? "<b>P</b>: " : ""; // TODO: add color?
QString typeName = field.isPointer ? "<b>P</b>: " : ""; // add color?
if (field.type == MemoryFieldType::EntitySubclass || field.type == MemoryFieldType::DefaultStructType)
typeName += QString::fromStdString(field.jsonName);
else if (auto str = Configuration::getTypeDisplayName(field.type); !str.empty())
Expand Down Expand Up @@ -1688,14 +1688,14 @@ void S2Plugin::TreeViewMemoryFields::updateRow(int row, std::optional<uintptr_t>
if (valueMemoryOffset == 0)
itemValue->setData("n/a", Qt::DisplayRole);
else
itemValue->setData(QString::fromStdString(Spelunky2::get()->themeNameOfOffset(valueMemoryOffset)), Qt::DisplayRole);
itemValue->setData(Spelunky2::get()->themeNameOfOffset(valueMemoryOffset), Qt::DisplayRole);

if (comparisonActive)
{
if (valueComparisonMemoryOffset == 0)
itemComparisonValue->setData("n/a", Qt::DisplayRole);
else
itemComparisonValue->setData(QString::fromStdString(Spelunky2::get()->themeNameOfOffset(valueMemoryOffset)), Qt::DisplayRole);
itemComparisonValue->setData(Spelunky2::get()->themeNameOfOffset(valueMemoryOffset), Qt::DisplayRole);

itemComparisonValue->setBackground(itemComparisonValueHex->background());
}
Expand All @@ -1720,7 +1720,7 @@ void S2Plugin::TreeViewMemoryFields::updateRow(int row, std::optional<uintptr_t>
if (comparisonActive)
{
// we can't show comparison version since it's a tab, not a new window
// TODO: maybe add comparison in the show rooms tab?
// maybe add comparison in the show rooms tab?
itemComparisonValue->setData({}, Qt::DisplayRole);
itemComparisonValue->setData(0, gsRoleMemoryAddress);

Expand Down Expand Up @@ -1825,7 +1825,6 @@ void S2Plugin::TreeViewMemoryFields::updateRow(int row, std::optional<uintptr_t>
{
std::optional<size_t> value;
// we use the size to check if it was changed
// TODO: don't use updateField, make struct with two size_t values for comparison and hold (will also be needed for std::list)
value = updateField<size_t>(itemField, valueMemoryOffset == 0 ? 0 : valueMemoryOffset + 0x8, itemValue, nullptr, nullptr, true, nullptr, true, !pointerUpdate, highlightColor);
if (value.has_value())
{
Expand All @@ -1842,7 +1841,7 @@ void S2Plugin::TreeViewMemoryFields::updateRow(int row, std::optional<uintptr_t>
{
itemComparisonValue->setData("<font color='blue'><u>Show contents</u></font>", Qt::DisplayRole);
}
// TODO maybe it should be based on the pointer not size?
// maybe it should be based on the pointer not size?
itemComparisonValue->setBackground(value != comparisonValue ? comparisonDifferenceColor : Qt::transparent);
if (isPointer == false)
itemComparisonValueHex->setBackground(value != comparisonValue ? comparisonDifferenceColor : Qt::transparent);
Expand All @@ -1858,7 +1857,7 @@ void S2Plugin::TreeViewMemoryFields::updateRow(int row, std::optional<uintptr_t>
}
case MemoryFieldType::Skip:
{
// TODO
// TODO when setting for skip is done
break;
}
case MemoryFieldType::EntitySubclass:
Expand Down Expand Up @@ -2146,7 +2145,7 @@ void S2Plugin::TreeViewMemoryFields::cellClicked(const QModelIndex& index)
auto rawValue = clickedItem->data(gsRoleMemoryAddress).toULongLong();
if (rawValue != 0)
{
// TODO: maybe use the "entity interpret as" for vtable? (it's doable)
// maybe use the "entity interpret as" for vtable? (it's doable)
auto vftType = qvariant_cast<std::string>(getDataFrom(index, gsColField, gsRoleRefName));
if (vftType == "Entity") // in case of Entity, we have to see what the entity is interpreted as, and show those functions
{
Expand Down
120 changes: 91 additions & 29 deletions src/QtHelpers/WidgetDatabaseView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ namespace std
};
} // namespace std

struct ComparisonField
{
S2Plugin::MemoryFieldType type{S2Plugin::MemoryFieldType::None};
size_t offset{0};
std::string refName; // for flags
uint8_t flag_index;
};
Q_DECLARE_METATYPE(ComparisonField)

S2Plugin::WidgetDatabaseView::WidgetDatabaseView(MemoryFieldType type, QWidget* parent) : QWidget(parent)
{
setWindowIcon(getCavemanIcon());
Expand Down Expand Up @@ -93,6 +102,11 @@ S2Plugin::WidgetDatabaseView::WidgetDatabaseView(MemoryFieldType type, QWidget*
QObject::connect(mCompareFieldComboBox, &QComboBox::currentTextChanged, this, &WidgetDatabaseView::comparisonFieldChosen);
topLayout->addWidget(mCompareFieldComboBox);

mCompareFlagComboBox = new QComboBox();
QObject::connect(mCompareFlagComboBox, &QComboBox::currentTextChanged, this, &WidgetDatabaseView::comparisonFlagChosen);
mCompareFlagComboBox->hide();
topLayout->addWidget(mCompareFlagComboBox);

auto groupCheckbox = new QCheckBox("Group by value", this);
QObject::connect(groupCheckbox, &QCheckBox::stateChanged, this, &WidgetDatabaseView::compareGroupByCheckBoxClicked);
topLayout->addWidget(groupCheckbox);
Expand Down Expand Up @@ -185,25 +199,93 @@ void S2Plugin::WidgetDatabaseView::compareGroupByCheckBoxClicked(int state)

void S2Plugin::WidgetDatabaseView::comparisonFieldChosen()
{
mFieldChoosen = true;
mCompareTableWidget->clearContents();
mCompareTreeWidget->clear();

auto comboIndex = mCompareFieldComboBox->currentIndex();
if (comboIndex == 0)
return;

auto comboboxData = mCompareFieldComboBox->currentData();
if (!comboboxData.isValid())
return;

auto type = comboboxData.value<ComparisonField>().type;
uint8_t flagsCount = 0;
if (type == MemoryFieldType::Flags8)
flagsCount = 8;
else if (type == MemoryFieldType::Flags16)
flagsCount = 16;
else if (type == MemoryFieldType::Flags32)
flagsCount = 32;

if (flagsCount != 0)
{
mCompareFlagComboBox->clear();
mCompareFlagComboBox->addItem("");
std::string refName = comboboxData.value<ComparisonField>().refName;
for (uint8_t x = 1; x <= flagsCount; ++x)
{
auto flagName = Configuration::get()->flagTitle(refName, x);
// TODO: don't show unknown unless it was chosen in settings
QString realFlagName = QString("%1: ").arg(x) + QString::fromStdString(flagName.empty() ? Configuration::get()->flagTitle("unknown", x) : flagName);
mCompareFlagComboBox->addItem(realFlagName, x - 1);
}
mCompareFlagComboBox->show();
}
else
{
mCompareFlagComboBox->clear();
mCompareFlagComboBox->hide();
}

populateComparisonTableWidget(comboboxData);
populateComparisonTreeWidget(comboboxData);
mFieldChoosen = false;
}

void S2Plugin::WidgetDatabaseView::comparisonFlagChosen(const QString& text)
{
// protect againts infinite loops since this slot is called when adding firts element to combo box
if (mFieldChoosen)
return;

mCompareTableWidget->clearContents();
mCompareTreeWidget->clear();

if (text.isEmpty())
{
auto comboboxData = mCompareFieldComboBox->currentData();
if (!comboboxData.isValid())
return;

populateComparisonTableWidget(comboboxData);
populateComparisonTreeWidget(comboboxData);

return;
}

populateComparisonTableWidget();
populateComparisonTreeWidget();
auto fieldData = mCompareFieldComboBox->currentData();
if (!fieldData.isValid())
return;
auto flagData = mCompareFlagComboBox->currentData();
if (!flagData.isValid())
return;

ComparisonField comparisonData = fieldData.value<ComparisonField>();
comparisonData.type = MemoryFieldType::Flag;
comparisonData.flag_index = flagData.value<uint8_t>();
auto newData = QVariant::fromValue(comparisonData);

populateComparisonTableWidget(newData);
populateComparisonTreeWidget(newData);
}

void S2Plugin::WidgetDatabaseView::populateComparisonTableWidget()
void S2Plugin::WidgetDatabaseView::populateComparisonTableWidget(const QVariant& fieldData)
{
mCompareTableWidget->setSortingEnabled(false);

auto comboboxData = mCompareFieldComboBox->currentData();

int row = 0;
for (ID_type x = 0; x <= highestRecordID(); ++x)
{
Expand All @@ -216,7 +298,7 @@ void S2Plugin::WidgetDatabaseView::populateComparisonTableWidget()
const auto name = recordNameForID(x);
mCompareTableWidget->setItem(row, 1, new QTableWidgetItem(QString("<font color='blue'><u>%1</u></font>").arg(name)));

auto [caption, value] = valueForField(comboboxData, addressOfRecordID(x));
auto [caption, value] = valueForField(fieldData, addressOfRecordID(x));
auto item = new TableWidgetItemNumeric(caption);
item->setData(Qt::UserRole, value);
mCompareTableWidget->setItem(row, 2, item);
Expand All @@ -227,19 +309,18 @@ void S2Plugin::WidgetDatabaseView::populateComparisonTableWidget()
mCompareTableWidget->sortItems(0);
}

void S2Plugin::WidgetDatabaseView::populateComparisonTreeWidget()
void S2Plugin::WidgetDatabaseView::populateComparisonTreeWidget(const QVariant& fieldData)
{
mCompareTreeWidget->setSortingEnabled(false);

auto comboboxData = mCompareFieldComboBox->currentData();
std::unordered_map<QString, QVariant> rootValues;
std::unordered_map<QString, std::vector<ID_type>> groupedValues; // valueString -> vector<character id's>
for (ID_type x = 0; x <= highestRecordID(); ++x)
{
if (!isValidRecordID(x))
continue;

auto [caption, value] = valueForField(comboboxData, addressOfRecordID(x));
auto [caption, value] = valueForField(fieldData, addressOfRecordID(x));
rootValues[caption] = value;

if (auto it = groupedValues.find(caption); it != groupedValues.end())
Expand Down Expand Up @@ -290,16 +371,6 @@ void S2Plugin::WidgetDatabaseView::groupedComparisonItemClicked(QTreeWidgetItem*
}
}

// TODO: instead of adding all the flags as separate options, add flags and when selected, show another combo box with the flags

struct ComparisonField
{
S2Plugin::MemoryFieldType type{S2Plugin::MemoryFieldType::None};
size_t offset;
uint8_t flag_index;
};
Q_DECLARE_METATYPE(ComparisonField)

size_t S2Plugin::WidgetDatabaseView::populateComparisonCombobox(const std::vector<MemoryField>& fields, size_t offset, std::string prefix)
{
for (const auto& field : fields)
Expand All @@ -322,17 +393,8 @@ size_t S2Plugin::WidgetDatabaseView::populateComparisonCombobox(const std::vecto
ComparisonField parrentFlag;
parrentFlag.type = field.type;
parrentFlag.offset = offset;
parrentFlag.refName = field.firstParameterType;
mCompareFieldComboBox->addItem(QString::fromStdString(prefix + field.name), QVariant::fromValue(parrentFlag));
uint8_t flagCount = (field.type == MemoryFieldType::Flags16 ? 16 : (field.type == MemoryFieldType::Flags8 ? 8 : 32));
for (uint8_t x = 1; x <= flagCount; ++x)
{
ComparisonField flag;
flag.type = MemoryFieldType::Flag;
flag.offset = offset;
flag.flag_index = x - 1;
// TODO: use flag name?
mCompareFieldComboBox->addItem(QString::fromStdString(prefix + field.name + ".flag_" + std::to_string(x)), QVariant::fromValue(flag));
}
break;
}
case MemoryFieldType::DefaultStructType:
Expand Down
10 changes: 5 additions & 5 deletions src/Spelunky2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,21 @@ uintptr_t S2Plugin::Spelunky2::get_SaveDataPtr()
return heapBaseAddr + heapOffsetSaveGame;
}

std::string S2Plugin::Spelunky2::themeNameOfOffset(uintptr_t offset) const // TODO use QString?
const QString& S2Plugin::Spelunky2::themeNameOfOffset(uintptr_t offset) const
{
auto config = Configuration::get();
uintptr_t firstThemeOffset = config->offsetForField(MemoryFieldType::LevelGen, "theme_dwelling", get_LevelGenPtr());

const static auto themeNames = {
static const QStringList themeNames = {
"DWELLING", "JUNGLE", "VOLCANA", "OLMEC", "TIDE POOL", "TEMPLE", "ICE CAVES", "NEO BABYLON", "SUNKEN CITY",
"COSMIC OCEAN", "CITY OF GOLD", "DUAT", "ABZU", "TIAMAT", "EGGPLANT WORLD", "HUNDUN", "BASE CAMP", "ARENA",
};
for (uint8_t idx = 0; idx < themeNames.size(); ++idx)
{
uintptr_t testPtr = Script::Memory::ReadQword(firstThemeOffset + idx * 0x8ull);
if (testPtr == offset)
return *(themeNames.begin() + idx);
return themeNames.at(idx);
}

return "UNKNOWN THEME";
static const QString unknown{"UNKNOWN THEME"};
return unknown;
}

0 comments on commit 77ff4ea

Please sign in to comment.