Added rumble file viewer.

This commit is contained in:
= 2025-06-04 22:10:14 -04:00
parent 20964df102
commit 8fe0e02e64
8 changed files with 542 additions and 0 deletions

58
app/rumblefileviewer.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "rumblefileviewer.h"
#include "ui_rumblefileviewer.h"
RumbleFileViewer::RumbleFileViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::RumbleFileViewer)
, mPropertyCount()
, mRumbleFile(nullptr) {
ui->setupUi(this);
ui->tableWidget_Properties->setColumnCount(2);
ui->tableWidget_Properties->setRowCount(0);
ui->tableWidget_Properties->setColumnWidth(0, 200);
ui->tableWidget_Properties->horizontalHeader()->setStretchLastSection(true);
}
RumbleFileViewer::~RumbleFileViewer() {
delete ui;
}
void RumbleFileViewer::SetRumbleFile(std::shared_ptr<RawFile> aRumbleFile) {
mRumbleFile = aRumbleFile;
ui->tableWidget_Properties->clear();
const QString magic = aRumbleFile->contents.left(6);
if (magic != "RUMBLE") {
qDebug() << "Rumble file has invalid magic: " << magic;
return;
}
int firstIndex = 0;
int secondIndex = 0;
int thirdIndex = 0;
int startIndex = 0;
for (int i = 0; i < aRumbleFile->contents.count("\\") / 2; i++) {
ui->tableWidget_Properties->setRowCount(i + 1);
ui->spinBox_Entries->setValue(i + 1);
firstIndex = aRumbleFile->contents.indexOf("\\", startIndex);
secondIndex = aRumbleFile->contents.indexOf("\\", firstIndex + 1);
thirdIndex = aRumbleFile->contents.indexOf("\\", secondIndex + 1);
if (thirdIndex == -1) {
thirdIndex = aRumbleFile->contents.size();
}
const QString keyStr = aRumbleFile->contents.mid(firstIndex + 1, secondIndex - firstIndex - 1);
QTableWidgetItem *keyItem = new QTableWidgetItem(keyStr);
ui->tableWidget_Properties->setItem(i, 0, keyItem);
const QString valStr = aRumbleFile->contents.mid(secondIndex + 1, thirdIndex - secondIndex - 1);
QTableWidgetItem *valueItem = new QTableWidgetItem(valStr);
ui->tableWidget_Properties->setItem(i, 1, valueItem);
startIndex = thirdIndex;
}
}

28
app/rumblefileviewer.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef RUMBLEFILEVIEWER_H
#define RUMBLEFILEVIEWER_H
#include "asset_structs.h"
#include "zonefile.h"
#include <QWidget>
namespace Ui {
class RumbleFileViewer;
}
class RumbleFileViewer : public QWidget
{
Q_OBJECT
public:
explicit RumbleFileViewer(QWidget *parent = nullptr);
~RumbleFileViewer();
void SetRumbleFile(std::shared_ptr<RawFile> aRumbleFile);
private:
Ui::RumbleFileViewer *ui;
quint32 mPropertyCount;
std::shared_ptr<RawFile> mRumbleFile;
};
#endif // RUMBLEFILEVIEWER_H

153
app/rumblefileviewer.ui Normal file
View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RumbleFileViewer</class>
<widget class="QWidget" name="RumbleFileViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>841</width>
<height>457</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>841</width>
<height>457</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_Title">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Rumble File Viewer</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="minimumSize">
<size>
<width>325</width>
<height>398</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>325</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Header</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="2" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1" colspan="2">
<widget class="QSpinBox" name="spinBox_Entries">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Entries:</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_LocalStrViewer">
<property name="minimumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Properties</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTableWidget" name="tableWidget_Properties">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

54
app/rumblegraphviewer.cpp Normal file
View File

@ -0,0 +1,54 @@
#include "rumblegraphviewer.h"
#include "ui_rumblegraphviewer.h"
RumbleGraphViewer::RumbleGraphViewer(QWidget *parent)
: QWidget(parent)
, ui(new Ui::RumbleGraphViewer),
mEntryCount(),
mRumbleGraphFile(nullptr) {
ui->setupUi(this);
ui->tableWidget_Entries->setColumnCount(2);
ui->tableWidget_Entries->setHorizontalHeaderLabels({ "X", "Y" });
ui->tableWidget_Entries->setRowCount(0);
ui->tableWidget_Entries->setColumnWidth(0, 200);
ui->tableWidget_Entries->horizontalHeader()->setStretchLastSection(true);
}
RumbleGraphViewer::~RumbleGraphViewer() {
delete ui;
}
void RumbleGraphViewer::SetRumbleGraphFile(const std::shared_ptr<RawFile> aRawFile) {
mRumbleGraphFile = aRawFile;
QDataStream rawFileStream(mRumbleGraphFile->contents.toLatin1());
QByteArray magic(15, Qt::Uninitialized);
rawFileStream.readRawData(magic.data(), 15);
rawFileStream.skipRawData(4);
char sectionChar;
rawFileStream >> sectionChar;
int sectionCount = sectionChar - '0';
ui->tableWidget_Entries->setRowCount(sectionCount);
ui->spinBox_Entries->setValue(sectionCount);
ui->groupBox_LocalStrViewer->setTitle(QString("Entries (%1)").arg(sectionCount));
rawFileStream.skipRawData(2);
for (int i = 0; i < sectionCount; i++) {
QByteArray xVal(6, Qt::Uninitialized), yVal(6, Qt::Uninitialized);
rawFileStream.readRawData(xVal.data(), 6);
rawFileStream.skipRawData(1);
rawFileStream.readRawData(yVal.data(), 6);
rawFileStream.skipRawData(2);
QTableWidgetItem *xItem = new QTableWidgetItem(xVal);
QTableWidgetItem *yItem = new QTableWidgetItem(yVal);
ui->tableWidget_Entries->setItem(i, 0, xItem);
ui->tableWidget_Entries->setItem(i, 1, yItem);
}
}

30
app/rumblegraphviewer.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef RUMBLEGRAPHVIEWER_H
#define RUMBLEGRAPHVIEWER_H
#include "asset_structs.h"
#include "zonefile.h"
#include <QWidget>
namespace Ui {
class RumbleGraphViewer;
}
class RumbleGraphViewer : public QWidget
{
Q_OBJECT
public:
explicit RumbleGraphViewer(QWidget *parent = nullptr);
~RumbleGraphViewer();
void SetEntryCount(quint32 aCount);
void SetRumbleGraphFile(const std::shared_ptr<RawFile> aRawFile);
void SetZoneFile(std::shared_ptr<ZoneFile> aZoneFile);
private:
Ui::RumbleGraphViewer *ui;
quint32 mEntryCount;
std::shared_ptr<RawFile> mRumbleGraphFile;
};
#endif // RUMBLEGRAPHVIEWER_H

153
app/rumblegraphviewer.ui Normal file
View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RumbleGraphViewer</class>
<widget class="QWidget" name="RumbleGraphViewer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>841</width>
<height>457</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>841</width>
<height>457</height>
</size>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_Title">
<property name="font">
<font>
<family>Roboto</family>
<pointsize>16</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Rumble Graph File </string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="minimumSize">
<size>
<width>325</width>
<height>398</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>325</width>
<height>16777215</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Header</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Entry Count: </string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QSpinBox" name="spinBox_Entries">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>10000</number>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_LocalStrViewer">
<property name="minimumSize">
<size>
<width>400</width>
<height>400</height>
</size>
</property>
<property name="font">
<font>
<family>Roboto</family>
<pointsize>9</pointsize>
</font>
</property>
<property name="title">
<string>Entries</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QTableWidget" name="tableWidget_Entries">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,37 @@
#include "highlighter_rumble.h"
Highlighter_Rumble::Highlighter_Rumble(QTextDocument *parent)
: QSyntaxHighlighter(parent) {
HighlightingRule rule;
// Format for the "RUMBLEGRAPHFILE" header
headerFormat.setForeground(QColor("#569CD6"));
headerFormat.setFontWeight(QFont::Bold);
rule.pattern = QRegularExpression(QStringLiteral("^RUMBLEGRAPHFILE\\b"));
rule.format = headerFormat;
highlightingRules.append(rule);
// Format for line count (second line, typically a single integer)
countFormat.setForeground(QColor("#C586C0"));
rule.pattern = QRegularExpression(QStringLiteral("^\\d+$"));
rule.format = countFormat;
highlightingRules.append(rule);
// Format for floating-point number pairs (e.g. 0.0000 0.4701)
floatPairFormat.setForeground(QColor("#B5CEA8"));
rule.pattern = QRegularExpression(QStringLiteral("^\\s*-?\\d+\\.\\d+\\s+-?\\d+\\.\\d+\\s*$"));
rule.format = floatPairFormat;
highlightingRules.append(rule);
}
void Highlighter_Rumble::highlightBlock(const QString &text) {
for (const HighlightingRule &rule : std::as_const(highlightingRules)) {
QRegularExpressionMatchIterator matchIterator = rule.pattern.globalMatch(text);
while (matchIterator.hasNext()) {
QRegularExpressionMatch match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
setCurrentBlockState(0);
}

View File

@ -0,0 +1,29 @@
#ifndef HIGHLIGHTER_RUMBLE_H
#define HIGHLIGHTER_RUMBLE_H
#include <QSyntaxHighlighter>
#include <QRegularExpression>
class Highlighter_Rumble : public QSyntaxHighlighter
{
Q_OBJECT
public:
Highlighter_Rumble(QTextDocument *parent = nullptr);
protected:
void highlightBlock(const QString &text) override;
private:
struct HighlightingRule {
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
QTextCharFormat headerFormat;
QTextCharFormat countFormat;
QTextCharFormat floatPairFormat;
};
#endif // HIGHLIGHTER_RUMBLE_H