#include "mainwindow.h" #include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); mTypeMap = QMap(); mTypeOrder = QStringList(); mRawFileMap = QMap(); mTreeMap = QMap(); mStrTableMap = QMap>>(); mBSPVersion = 0; mDiskLumpCount = 0; mDiskLumpOrder = QVector(); mLumps = QMap(); mRecentFiles = QQueue(); mSettingsValid = false; mRecentFileActions = QVector(); mRawFilesVec = QVector(); const QString appSettingsPath = QDir::currentPath() + "/appSettings.ini"; QSettings appSettings(appSettingsPath, QSettings::IniFormat); if (appSettings.contains("mRecentFiles")) { mSettingsValid = true; QStringList recentFiles = appSettings.value("mRecentFiles").toStringList(); foreach (QString recentFile, recentFiles) { mRecentFiles.enqueue(recentFile); } } connect(ui->treeWidget_Scripts, &QTreeWidget::itemSelectionChanged, this, &MainWindow::ScriptSelected); connect(ui->comboBox_StringTable, &QComboBox::currentTextChanged, this, &MainWindow::StrTableSelected); // Initialize Asset Index Table ui->tableWidget_Index->setColumnCount(2); ui->tableWidget_Index->setHorizontalHeaderLabels({"Asset Name", "Asset Count"}); ui->tableWidget_Index->verticalHeader()->setVisible(false); ui->tableWidget_Index->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableWidget_Index->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableWidget_Index->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableWidget_Index->setShowGrid(false); ui->tableWidget_Index->setStyleSheet("QTableView {selection-background-color: red;}"); // Initialize Asset Order Table ui->tableWidget_Order->setColumnCount(2); ui->tableWidget_Order->setHorizontalHeaderLabels({"Asset Name", "Asset Count"}); ui->tableWidget_Order->verticalHeader()->setVisible(false); ui->tableWidget_Order->setEditTriggers(QAbstractItemView::NoEditTriggers); ui->tableWidget_Order->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableWidget_Order->setSelectionMode(QAbstractItemView::SingleSelection); ui->tableWidget_Order->setShowGrid(false); ui->tableWidget_Order->setStyleSheet("QTableView {selection-background-color: red;}"); // Initialize Menu table ui->treeWidget_Menus->setHeaderLabels({"Components", "Description"}); ui->treeWidget_Menus->setColumnWidth(0, width() / 4 * 3); // Name column Qt3DExtras::Qt3DWindow *view = new Qt3DExtras::Qt3DWindow(); view->defaultFrameGraph()->setClearColor(QColor(QRgb(0x4d4d4f))); QWidget *container = QWidget::createWindowContainer(view); QSize screenSize = view->screen()->size(); container->setMinimumSize(QSize(200, 100)); container->setMaximumSize(screenSize); QHBoxLayout *hLayout = new QHBoxLayout(ui->frame_Scene); QVBoxLayout *vLayout = new QVBoxLayout(); vLayout->setAlignment(Qt::AlignTop); hLayout->addWidget(container, 1); hLayout->addLayout(vLayout); // Root entity Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity(); // Camera Qt3DRender::QCamera *cameraEntity = view->camera(); cameraEntity->lens()->setPerspectiveProjection(45.0f, 16.0f/9.0f, 0.1f, 1000.0f); cameraEntity->setPosition(QVector3D(0, 0, 50.0f)); // Move farther along Z-axis cameraEntity->setUpVector(QVector3D(0, 1, 0)); cameraEntity->setViewCenter(QVector3D(0, 0, 0)); Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity); Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity); light->setColor("white"); light->setIntensity(1); lightEntity->addComponent(light); Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity); lightTransform->setTranslation(cameraEntity->position()); lightEntity->addComponent(lightTransform); // For camera controls Qt3DExtras::QFirstPersonCameraController *camController = new Qt3DExtras::QFirstPersonCameraController(rootEntity); camController->setCamera(cameraEntity); // Set root object of the scene view->setRootEntity(rootEntity); // Load custom 3D model Qt3DRender::QMesh *customMesh = new Qt3DRender::QMesh(); customMesh->setSource(QUrl::fromLocalFile(":/obj/data/obj/defaultactor_LOD0.obj")); // Adjust the model transformation Qt3DCore::QTransform *customTransform = new Qt3DCore::QTransform(); customTransform->setRotationX(-90); customTransform->setRotationY(-90); // Keep translation if necessary customTransform->setTranslation(QVector3D(0.0f, -100.0f, -200.0f)); Qt3DExtras::QNormalDiffuseMapMaterial *customMaterial = new Qt3DExtras::QNormalDiffuseMapMaterial(); Qt3DRender::QTextureLoader *normalMap = new Qt3DRender::QTextureLoader(); normalMap->setSource(QUrl::fromLocalFile(":/obj/data/obj/normalmap.png")); customMaterial->setNormal(normalMap); Qt3DRender::QTextureLoader *diffuseMap = new Qt3DRender::QTextureLoader(); diffuseMap->setSource(QUrl::fromLocalFile(":/obj/data/obj/diffusemap.png")); customMaterial->setDiffuse(diffuseMap); Qt3DCore::QEntity *m_torusEntity = new Qt3DCore::QEntity(rootEntity); m_torusEntity->addComponent(customMesh); m_torusEntity->addComponent(customMaterial); m_torusEntity->addComponent(customTransform); LoadFile_D3DBSP(":/d3dbsp/data/d3dbsp/barebones.d3dbsp"); Reset(); } MainWindow::~MainWindow() { const QString appSettingsPath = QDir::currentPath() + "/appSettings.ini"; QSettings appSettings(appSettingsPath, QSettings::IniFormat); appSettings.setValue("mRecentFiles", mRecentFiles.toList()); delete ui; } void MainWindow::Reset() { // Reset tabwidget to 'General' tab ui->tabWidget->setCurrentIndex(0); // Reset 'General' tab fields ui->lineEdit_FastFile->clear(); ui->comboBox_Company->setCurrentIndex(0); ui->comboBox_FileType->setCurrentIndex(0); ui->checkBox_Signed->setChecked(false); ui->lineEdit_Magic->clear(); ui->spinBox_Magic->clear(); ui->spinBox_TagCount->clear(); ui->spinBox_FileSize->clear(); ui->spinBox_RecordCount->clear(); // Reset 'Unknowns' tab fields ui->lineEdit_U1->clear(); ui->spinBox_U1->clear(); ui->lineEdit_U2->clear(); ui->spinBox_U2->clear(); ui->lineEdit_U3->clear(); ui->spinBox_U3->clear(); ui->lineEdit_U4->clear(); ui->spinBox_U4->clear(); ui->lineEdit_U5->clear(); ui->spinBox_U5->clear(); ui->lineEdit_U6->clear(); ui->spinBox_U6->clear(); ui->lineEdit_U7->clear(); ui->spinBox_U7->clear(); ui->lineEdit_U8->clear(); ui->spinBox_U8->clear(); ui->lineEdit_U9->clear(); ui->spinBox_U9->clear(); ui->lineEdit_U10->clear(); ui->spinBox_U10->clear(); ui->lineEdit_U11->clear(); ui->spinBox_U11->clear(); // Reset 'Tags' tab fields ui->listWidget_Tags->clear(); // Reset 'Localized Strings' tab fields ui->listWidget_LocalString->clear(); // Reset 'Asset Index/Order' tab fields ui->tableWidget_Index->clear(); ui->tableWidget_Order->clear(); // Reset 'Raw Files' tab fields ui->treeWidget_Scripts->clear(); ui->plainTextEdit_Scripts->clear(); // Reset 'Tech Sets' tab fields ui->listWidget_TechSets->clear(); // Reset 'Zone Dump' tab fields ui->spinBox_DumpIndex->clear(); ui->comboBox_DumpAsset->setCurrentIndex(0); ui->plainTextEdit_ZoneDump->clear(); // Reset 'String Tables' tab fields ui->comboBox_StringTable->setCurrentIndex(0); ui->tableWidget_StringTable->clear(); // Reset '3D Scene' tab fields ui->treeWidget_Models->clear(); // Reset class vars mTypeMap.clear(); mTypeOrder.clear(); mTagCount = 0; mRecordCount = 0; mRawFileMap.clear(); mTreeMap.clear(); mStrTableMap.clear(); // Refresh recent files RefreshRecentFileMenu(); } void MainWindow::StrTableSelected(QString aStrTableName) { ui->tableWidget_StringTable->clear(); ui->tableWidget_StringTable->setColumnCount(2); int entryIndex = 0; for (auto strTableEntry : mStrTableMap[aStrTableName]) { ui->tableWidget_StringTable->insertRow(ui->tableWidget_StringTable->rowCount() + 1); ui->tableWidget_StringTable->setItem(entryIndex, 0, new QTableWidgetItem(strTableEntry.first)); ui->tableWidget_StringTable->setItem(entryIndex, 1, new QTableWidgetItem(strTableEntry.second)); entryIndex++; } } void MainWindow::ScriptSelected() { QTreeWidgetItem *selectedItem = ui->treeWidget_Scripts->selectedItems()[0]; if (!selectedItem) { qDebug() << "Attempted to load invalid tree item!"; return; } const QString itemName = selectedItem->text(0); const QStringList scriptExts = {"gsc", "csc", "atr", "shock", "vision", "rmb"}; if (!scriptExts.contains(itemName.split('.').last())) { qDebug() << QString("Attempted to parse invalid raw file: %1!").arg(itemName); return; } ui->plainTextEdit_Scripts->clear(); for (auto [scriptName, scriptContents] : mRawFileMap.asKeyValueRange()) { if (scriptName.contains(itemName)) { ui->plainTextEdit_Scripts->setPlainText(scriptContents); return; } } } QByteArray MainWindow::DecompressZLIB(QByteArray compressedData) { QByteArray decompressedData; uLongf decompressedSize = compressedData.size() * 4; decompressedData.resize(static_cast(decompressedSize)); Bytef *destination = reinterpret_cast(decompressedData.data()); uLongf *destLen = &decompressedSize; const Bytef *source = reinterpret_cast(compressedData.data()); uLong sourceLen = compressedData.size(); int result = uncompress(destination, destLen, source, sourceLen); if (result == Z_OK) { decompressedData.resize(static_cast(decompressedSize)); } else { decompressedData.clear(); qDebug() << QString("In DecompressZLIB: %1").arg(Utils::ZLibErrorToString(result)).toLatin1(); } return decompressedData; } /* GetFastFilePath() Opens a file dialog in the steam folder, and opens the selected file. */ QString MainWindow::GetFastFilePath() { // Reset dialog before opening new file Reset(); // Open file dialog to steam apps const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; const QString fastFilePath = QFileDialog::getOpenFileName(this, "Open FastFile", steamPath, "FastFile (*.ff);;All Files (*.*)"); if (!QFile::exists(fastFilePath)) { QMessageBox::warning(this, "Warning!", QString("%1 does not exist!.").arg(fastFilePath)); return nullptr; } ui->lineEdit_FastFile->setText(fastFilePath); const QString fastFileStem = fastFilePath.split('/').last(); setWindowTitle(QString("FastFile Wizard - %1").arg(fastFileStem)); return fastFilePath; } /* GetZoneFilePath() Opens a file dialog in the steam folder, and opens the selected file. */ QString MainWindow::GetZoneFilePath() { // Reset dialog before opening new file Reset(); // Open file dialog to steam apps const QString steamPath = "C:/Program Files (x86)/Steam/steamapps/common/Call of Duty World at War/zone/english/"; const QString zoneFilePath = QFileDialog::getOpenFileName(this, "Open ZoneFile", steamPath, "ZoneFile (*.zone);;All Files (*.*)"); if (!QFile::exists(zoneFilePath)) { QMessageBox::warning(this, "Warning!", QString("%1 does not exist!.").arg(zoneFilePath)); return nullptr; } ui->lineEdit_ZoneFile->setText(zoneFilePath); const QString zoneFileStem = zoneFilePath.split('/').last(); setWindowTitle(QString("FastFile Wizard - %1").arg(zoneFileStem)); return zoneFilePath; } QByteArray MainWindow::OpenFastFile(QString aFastFilePath) { Reset(); // Check fastfile can be read QFile *fastFile = new QFile(aFastFilePath); qDebug() << aFastFilePath; if (!fastFile->open(QIODevice::ReadOnly)) { QMessageBox::warning(this, "Warning!", QString("FastFile '%1' could not be read!.").arg(fastFile->fileName())); return QByteArray(); } LogOpenedFile(fastFile->fileName()); ui->lineEdit_FastFile->setText(fastFile->fileName()); // Decompress fastfile and close const QByteArray fastFileData = fastFile->readAll(); // Parse data from fast file header ParseFFHeader(fastFileData.mid(0, 12)); fastFile->close(); // Decompress fastfile and close const QByteArray decompressedData = DecompressZLIB(fastFileData.mid(12)); // ui->plainTextEdit_ZoneDump->setPlainText(decompressedData.toHex()); const QString zoneFilePath = aFastFilePath.replace(".ff", ".zone"); ui->lineEdit_ZoneFile->setText(zoneFilePath); // Open zone file OpenZoneFile(zoneFilePath); // Clean up & return delete fastFile; return fastFileData; } QByteArray MainWindow::OpenZoneFile(QString aZoneFilePath) { Reset(); // Check zone file is writeable QFile *zoneFile = new QFile(aZoneFilePath); if (!zoneFile->open(QIODevice::ReadOnly)) { QMessageBox::warning(this, "Warning!", QString("ZoneFile '%1' could not be read!.").arg(zoneFile->fileName())); return QByteArray(); } LogOpenedFile(zoneFile->fileName()); ui->lineEdit_ZoneFile->setText(zoneFile->fileName()); // Parse & close zone file QByteArray zoneFileData = zoneFile->readAll(); ParseZoneFile(zoneFileData); zoneFile->close(); // Check if corresponding zone file exists const QString fastFilePath = zoneFile->fileName().replace(".zone", ".ff"); if (QFile::exists(fastFilePath)) { ui->lineEdit_FastFile->setText(fastFilePath); LogOpenedFile(fastFilePath); } // Clean up & return delete zoneFile; return zoneFileData; } void MainWindow::ParseFFCompany(QDataStream *afastFileStream) { // Check for null datastream ptr if (!afastFileStream) { return; } // Parse company QByteArray companyData(2, Qt::Uninitialized); afastFileStream->readRawData(companyData.data(), 2); if (companyData == "IW") { qDebug() << "Company found: 'INFINITY_WARD'"; ui->comboBox_Company->setCurrentIndex(1); } else if (companyData == "TA") { qDebug() << "Company found: 'TREYARCH'"; ui->comboBox_Company->setCurrentIndex(2); } else if (companyData == "Sl") { qDebug() << "Company found: 'SLEDGEHAMMER'"; ui->comboBox_Company->setCurrentIndex(3); } else if (companyData == "NX") { qDebug() << "Company found: 'NEVERSOFT'"; ui->comboBox_Company->setCurrentIndex(4); } else { qDebug() << QString("Failed to find company, found '%1'!").arg(companyData); return; } } void MainWindow::ParseFFFileType(QDataStream *afastFileStream) { // Parse filetype QByteArray fileTypeData(2, Qt::Uninitialized); afastFileStream->readRawData(fileTypeData.data(), 2); if (fileTypeData == "ff") { qDebug() << "File type found: 'FAST_FILE'"; ui->comboBox_FileType->setCurrentIndex(1); } else { qDebug() << "Failed to find file type!"; return; } } void MainWindow::ParseFFSignage(QDataStream *afastFileStream) { // Parse filetype QByteArray signedData(1, Qt::Uninitialized); afastFileStream->readRawData(signedData.data(), 1); if (signedData == "u") { qDebug() << "Found valid signage: Unsigned"; ui->checkBox_Signed->setChecked(false); } else if (signedData == "0") { qDebug() << "Found valid signage: Signed"; ui->checkBox_Signed->setChecked(true); } else { qDebug() << "Failed to determine signage of fastfile!"; return; } } void MainWindow::ParseFFMagic(QDataStream *afastFileStream) { // Parse magic QByteArray magicData(3, Qt::Uninitialized); afastFileStream->readRawData(magicData.data(), 3); if (magicData == "100") { qDebug() << QString("Found valid magic: '%1'").arg(magicData); ui->lineEdit_Magic->setText(magicData.toHex()); ui->spinBox_Magic->setValue(magicData.toInt()); } else { qDebug() << "Magic invalid!"; return; } } void MainWindow::ParseFFVersion(QDataStream *afastFileStream) { // Parse version quint32 version; *afastFileStream >> version; qDebug() << "Version:" << version; if (version == 387) { qDebug() << QString("Found valid version: '%1'").arg(version); ui->spinBox_Version->setValue(version); } else { qDebug() << "Version invalid!"; return; } } void MainWindow::ParseFFHeader(QByteArray aFastFileData) { // Open stream to fastfile QDataStream afastFileStream(aFastFileData); afastFileStream.setByteOrder(QDataStream::LittleEndian); ParseFFCompany(&afastFileStream); ParseFFFileType(&afastFileStream); ParseFFSignage(&afastFileStream); ParseFFMagic(&afastFileStream); ParseFFVersion(&afastFileStream); } void MainWindow::ParseAsset_Localize(QDataStream *aZoneFileStream) { Localize localize; *aZoneFileStream >> localize; ui->listWidget_LocalString->addItem(QString("%1 = %2").arg(localize.referenceStr).arg(localize.localizedStr)); } void MainWindow::ParseAsset_RawFile(QDataStream *aZoneFileStream) { RawFile rawFile; *aZoneFileStream >> rawFile; QString rawFilePath = rawFile.rawFilePath; rawFilePath.replace(",", ""); const QStringList pathParts = rawFilePath.split('/'); if (pathParts.size() == 0) { qDebug() << "Failed to parse ff path! " << rawFilePath; exit(-1); } else if (pathParts.size() == 1) { const QString path = pathParts[0]; QTreeWidgetItem *newRootItem = new QTreeWidgetItem(ui->treeWidget_Scripts); newRootItem->setText(0, path); } else { const QString path = pathParts[0]; QTreeWidgetItem *newRootItem; if (mTreeMap.contains(path)) { newRootItem = mTreeMap[path]; } else { newRootItem = new QTreeWidgetItem(ui->treeWidget_Scripts); newRootItem->setText(0, path); mTreeMap[path] = newRootItem; } QTreeWidgetItem *parentItem = newRootItem; for (int i = 1; i < pathParts.size(); i++) { const QString path = pathParts[i]; QTreeWidgetItem *newChildItem; if (mTreeMap.contains(path)) { newChildItem = mTreeMap[path]; } else { newChildItem = new QTreeWidgetItem(); newChildItem->setText(0, path); mTreeMap[path] = newChildItem; } parentItem->addChild(newChildItem); parentItem = newChildItem; } } mRawFileMap[rawFilePath] = (rawFile.rawFileContents.isEmpty()) ? ("EMPTY") : (rawFile.rawFileContents); } void MainWindow::ParseAsset_XModel(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_Material(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_PixelShader(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_TechSet(QDataStream *aZoneFileStream) { aZoneFileStream->skipRawData(4); // Parse techset name QString techSetName; char techSetNameChar; *aZoneFileStream >> techSetNameChar; while (techSetNameChar == 0) { *aZoneFileStream >> techSetNameChar; } while (techSetNameChar != 0) { techSetName += techSetNameChar; *aZoneFileStream >> techSetNameChar; } techSetName.replace(",", ""); ui->listWidget_TechSets->addItem(techSetName); //qDebug() << "Tech Set: " << techSetName; } void MainWindow::ParseAsset_LoadedSound(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_ColMapMP(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_FX(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_Font(QDataStream *aZoneFileStream) { } void MainWindow::ParseAsset_XAnim(QDataStream *aZoneFileStream) { // Read in pointer to x_anim name QByteArray namePtr(4, Qt::Uninitialized); aZoneFileStream->readRawData(namePtr.data(), 4); // Read in counts quint16 dataByteCount, dataShortCount, dataIntCount, randomDataByteCount, randomDataIntCount, numframes; *aZoneFileStream >> dataByteCount >> dataShortCount >> dataIntCount >> randomDataByteCount >> randomDataIntCount >> numframes; // Read bool flags bool isLooped, isDelta; *aZoneFileStream >> isLooped >> isDelta; // Read in more counts quint8 noneRotatedBoneCount, twoDRotatedBoneCount, normalRotatedBoneCount, twoDStaticRotatedBoneCount, normalStaticRotatedBoneCount, normalTranslatedBoneCount, preciseTranslatedBoneCount, staticTranslatedBoneCount, noneTranslatedBoneCount, totalBoneCount, otherBoneCount1, otherBoneCount2; *aZoneFileStream >> noneRotatedBoneCount >> twoDRotatedBoneCount >> normalRotatedBoneCount >> twoDStaticRotatedBoneCount >> normalStaticRotatedBoneCount >> normalTranslatedBoneCount >> preciseTranslatedBoneCount >> staticTranslatedBoneCount >> noneTranslatedBoneCount >> totalBoneCount >> otherBoneCount1 >> otherBoneCount2; // Yet more counts quint8 notifyCount, assetType; *aZoneFileStream >> notifyCount >> assetType; // Read more bool flags bool pad; *aZoneFileStream >> pad; // Yet more more counts unsigned int randomDataShortCount, indexCount; *aZoneFileStream >> randomDataShortCount >> indexCount; // Read in floats float frameRate, frequency; *aZoneFileStream >> frameRate >> frequency; // Read in pointers quint32 boneIDsPtr, dataBytePtr, dataShortPtr, dataIntPtr, randomDataShortPtr, randomDataBytePtr, randomDataIntPtr, longIndiciesPtr, notificationsPtr, deltaPartsPtr; *aZoneFileStream >> boneIDsPtr >> dataBytePtr >> dataShortPtr >> dataIntPtr >> randomDataShortPtr >> randomDataBytePtr >> randomDataIntPtr >> longIndiciesPtr >> notificationsPtr >> deltaPartsPtr; // Read in x_anim file name QString xAnimName; char xAnimNameChar; *aZoneFileStream >> xAnimNameChar; while (xAnimNameChar != 0) { xAnimName += xAnimNameChar; *aZoneFileStream >> xAnimNameChar; } // Parse x_anim index header QVector sectionLengths; for (int i = 0; i < numframes; i++) { quint8 sectionlength; *aZoneFileStream >> sectionlength; sectionLengths.push_back(sectionlength); // Skip padding aZoneFileStream->skipRawData(1); } // Skip unknown section aZoneFileStream->skipRawData(2 * 8); } void MainWindow::ParseAsset_MenuFile(QDataStream *aZoneFileStream) { //MENU_FILE aZoneFileStream->skipRawData(4); // Separator // Parse menu def count quint32 menuDefCount; *aZoneFileStream >> menuDefCount; if (menuDefCount > 1000) { return; } for (int i = 0; i < menuDefCount; i++) { aZoneFileStream->skipRawData(4); // Separator // Read in x_anim file name QString menuFilepath; char menuFilepathChar; *aZoneFileStream >> menuFilepathChar; while (menuFilepathChar != 0) { menuFilepath += menuFilepathChar; *aZoneFileStream >> menuFilepathChar; } qDebug() << "Parsing " << menuFilepath; QTreeWidgetItem *menuFilePathNode = new QTreeWidgetItem(ui->treeWidget_Menus); aZoneFileStream->skipRawData(4); // Separator QByteArray menuNamePtr(4, Qt::Uninitialized); aZoneFileStream->readRawData(menuNamePtr.data(), 4); QTreeWidgetItem *menuNamePtrNode = new QTreeWidgetItem(menuFilePathNode); menuNamePtrNode->setText(0, QString("Menu name ptr: %1").arg(menuNamePtr.toHex().toUpper())); QTreeWidgetItem *menuRectNode = new QTreeWidgetItem(menuFilePathNode); menuRectNode->setText(0, "Menu Rect"); float menuRectX, menuRectY, menuRectWidth, menuRectHeight; *aZoneFileStream >> menuRectX >> menuRectY >> menuRectWidth >> menuRectHeight; QTreeWidgetItem *menuRectXNode = new QTreeWidgetItem(menuRectNode); menuRectXNode->setText(0, QString("X: %1").arg(menuRectX)); QTreeWidgetItem *menuRectYNode = new QTreeWidgetItem(menuRectNode); menuRectYNode->setText(0, QString("Y: %1").arg(menuRectY)); QTreeWidgetItem *menuRectWidthNode = new QTreeWidgetItem(menuRectNode); menuRectWidthNode->setText(0, QString("Width: %1").arg(menuRectWidth)); QTreeWidgetItem *menuRectHeightNode = new QTreeWidgetItem(menuRectNode); menuRectHeightNode->setText(0, QString("Height: %1").arg(menuRectHeight)); MENU_H_ALIGNMENT hAlign; *aZoneFileStream >> hAlign; QTreeWidgetItem *hAlignNode = new QTreeWidgetItem(menuRectNode); QString hAlignStr = Utils::MenuHAlignToStr(hAlign); hAlignNode->setText(0, QString("Horiz. Align: %1").arg(hAlignStr)); MENU_V_ALIGNMENT vAlign; *aZoneFileStream >> vAlign; QTreeWidgetItem *vAlignNode = new QTreeWidgetItem(menuRectNode); QString vAlignStr = Utils::MenuVAlignToStr(vAlign); vAlignNode->setText(0, QString("Vert. Align: %1").arg(vAlignStr)); float rectClientX, rectClientY, rectClientWidth, rectClientHeight; *aZoneFileStream >> rectClientX >> rectClientY >> rectClientWidth >> rectClientHeight; QTreeWidgetItem *menuRectClientNode = new QTreeWidgetItem(menuFilePathNode); menuRectClientNode->setText(0, "Menu Client Rect"); QTreeWidgetItem *menuRectClientXNode = new QTreeWidgetItem(menuRectClientNode); menuRectClientXNode->setText(0, QString("X: %1").arg(rectClientX)); QTreeWidgetItem *menuRectClientYNode = new QTreeWidgetItem(menuRectClientNode); menuRectClientYNode->setText(0, QString("Y: %1").arg(rectClientY)); QTreeWidgetItem *menuRectClientWidthNode = new QTreeWidgetItem(menuRectClientNode); menuRectClientWidthNode->setText(0, QString("Width: %1").arg(rectClientWidth)); QTreeWidgetItem *menuRectClientHeightNode = new QTreeWidgetItem(menuRectClientNode); menuRectClientHeightNode->setText(0, QString("Height: %1").arg(rectClientHeight)); // Client horizontal alignment MENU_H_ALIGNMENT hClientAlign; *aZoneFileStream >> hClientAlign; QTreeWidgetItem *hClientAlignNode = new QTreeWidgetItem(menuRectClientNode); QString hClientAlignStr = Utils::MenuHAlignToStr(hAlign); hClientAlignNode->setText(0, QString("Horiz. Align: %1").arg(hClientAlignStr)); // Client vertical alignment MENU_V_ALIGNMENT vClientAlign; *aZoneFileStream >> vClientAlign; QTreeWidgetItem *vClientAlignNode = new QTreeWidgetItem(menuRectClientNode); QString vClientAlignStr = Utils::MenuVAlignToStr(vAlign); vClientAlignNode->setText(0, QString("Vert. Align: %1").arg(vClientAlignStr)); quint32 groupPtr; // Should be const char * *aZoneFileStream >> groupPtr; MENU_WINDOW_STYLE style; *aZoneFileStream >> style; MENU_WINDOW_BORDER border; *aZoneFileStream >> border; quint32 ownerDraw, ownerDrawFlags; *aZoneFileStream >> ownerDraw >> ownerDrawFlags; float borderSize; *aZoneFileStream >> borderSize; int staticFlags, dynamicFlags, nextTime; *aZoneFileStream >> staticFlags >> dynamicFlags >> nextTime; QTreeWidgetItem *colorsNode = new QTreeWidgetItem(menuFilePathNode); colorsNode->setText(0, "Menu Colors"); float foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA, backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA, borderColorR, borderColorG, borderColorB, borderColorA, outlineColorR, outlineColorG, outlineColorB, outlineColorA; *aZoneFileStream >> foregroundColorR >> foregroundColorG >> foregroundColorB >> foregroundColorA >> backgroundColorR >> backgroundColorG >> backgroundColorB >> backgroundColorA >> borderColorR >> borderColorG >> borderColorB >> borderColorA >> outlineColorR >> outlineColorG >> outlineColorB >> outlineColorA; QTreeWidgetItem *foregroundColorNode = new QTreeWidgetItem(colorsNode); foregroundColorNode->setText(0, QString("Foreground Color: RGBA(%1, %2, %3, %4)") .arg(foregroundColorR).arg(foregroundColorG).arg(foregroundColorB).arg(foregroundColorA)); foregroundColorNode->setBackground(1, Utils::ColorFromNormalized(foregroundColorR, foregroundColorG, foregroundColorB, foregroundColorA)); QTreeWidgetItem *backgroundColorNode = new QTreeWidgetItem(colorsNode); backgroundColorNode->setText(0, QString("Background Color: RGBA(%1, %2, %3, %4)") .arg(backgroundColorR).arg(backgroundColorG).arg(backgroundColorB).arg(backgroundColorA)); backgroundColorNode->setBackground(1, Utils::ColorFromNormalized(backgroundColorR, backgroundColorG, backgroundColorB, backgroundColorA)); QTreeWidgetItem *borderColorNode = new QTreeWidgetItem(colorsNode); borderColorNode->setText(0, QString("Borer Color: RGBA(%1, %2, %3, %4)") .arg(borderColorR).arg(borderColorG).arg(borderColorB).arg(borderColorA)); borderColorNode->setBackground(1, Utils::ColorFromNormalized(borderColorR, borderColorG, borderColorB, borderColorA)); QTreeWidgetItem *outlineColorNode = new QTreeWidgetItem(colorsNode); outlineColorNode->setText(0, QString("Outline Color: RGBA(%1, %2, %3, %4)") .arg(outlineColorR).arg(outlineColorG).arg(outlineColorB).arg(outlineColorA)); outlineColorNode->setBackground(1, Utils::ColorFromNormalized(outlineColorR, outlineColorG, outlineColorB, outlineColorA)); quint32 materialPtr; // Should be Material * *aZoneFileStream >> materialPtr; quint32 fontPtr, fullScreen, itemCount, fontIndex; *aZoneFileStream >> fontPtr >> fullScreen >> itemCount >> fontIndex; quint32 cursorItem, fadeCycle; *aZoneFileStream >> cursorItem >> fadeCycle; float fadeClamp, fadeAmount, fadeInAmount, blurRadius; *aZoneFileStream >> fadeClamp >> fadeAmount >> fadeInAmount >> blurRadius; quint32 onOpenPtr, onFocusPtr, onClosePtr, onESCPtr; // Should be const char * *aZoneFileStream >> onOpenPtr >> onFocusPtr >> onClosePtr >> onESCPtr; quint32 onKeyPtr; // Should be ItemKeyHandler * *aZoneFileStream >> onKeyPtr; quint32 visibleExpCount, expEntryPtr; // components of statement_s *aZoneFileStream >> visibleExpCount >> expEntryPtr; quint32 allowedBindingPtr, soundNamePtr; // Should be const char * *aZoneFileStream >> allowedBindingPtr >> soundNamePtr; quint32 imageTrack; *aZoneFileStream >> imageTrack; float focusColorR, focusColorG, focusColorB, focusColorA; *aZoneFileStream >> focusColorR >> focusColorG >> focusColorB >> focusColorA; QTreeWidgetItem *focusColorNode = new QTreeWidgetItem(colorsNode); focusColorNode->setText(0, QString("Focus Color: RGBA(%1, %2, %3, %4)") .arg(focusColorR).arg(focusColorG).arg(focusColorB).arg(focusColorA)); focusColorNode->setBackground(1, Utils::ColorFromNormalized(focusColorR, focusColorG, focusColorB, focusColorA)); //QTreeWidgetItem *menuDefChildNode = new QTreeWidgetItem(menuDefNode); //menuDefChildNode->setText(0, menuDefName); float disabledColorR, disabledColorG, disabledColorB, disabledColorA; *aZoneFileStream >> disabledColorR >> disabledColorG >> disabledColorB >> disabledColorA; QTreeWidgetItem *disabledColorNode = new QTreeWidgetItem(colorsNode); disabledColorNode->setText(0, QString("Disabled Color: RGBA(%1, %2, %3, %4)") .arg(disabledColorR).arg(disabledColorG).arg(disabledColorB).arg(disabledColorA)); disabledColorNode->setBackground(1, Utils::ColorFromNormalized(disabledColorR, disabledColorG, disabledColorB, disabledColorA)); quint32 rectXExpCount, rectXExpPtr; // components of statement_s *aZoneFileStream >> rectXExpCount >> rectXExpPtr; quint32 rectYExpCount, rectYExpPtr; // components of statement_s *aZoneFileStream >> rectYExpCount >> rectYExpPtr; aZoneFileStream->skipRawData(4); // Separator QString menuDefName; char menuDefNameChar; int menuDefNameLen = 0; *aZoneFileStream >> menuDefNameChar; while (menuDefNameChar != 0 && menuDefNameLen < 30) { menuDefNameLen++; menuDefName += menuDefNameChar; *aZoneFileStream >> menuDefNameChar; } menuFilePathNode->setText(0, QString("%1 - %2").arg(menuDefName).arg(menuFilepath)); QString defString; char defStringChar; int defStringLen = 0; *aZoneFileStream >> defStringChar; while (defStringChar != 0 && defStringLen < 30) { defStringLen++; defString += defStringChar; *aZoneFileStream >> defStringChar; } aZoneFileStream->skipRawData(4 * 10); QTreeWidgetItem *itemsNode = new QTreeWidgetItem(menuFilePathNode); itemsNode->setText(0, "Item Definitions"); quint32 itemWindowDefNamePtr; *aZoneFileStream >> itemWindowDefNamePtr; QTreeWidgetItem *itemRectNode = new QTreeWidgetItem(itemsNode); itemRectNode->setText(0, "Item Text Rect"); float itemRectX, itemRectY, itemRectWidth, itemRectHeight; *aZoneFileStream >> itemRectX >> itemRectY >> itemRectWidth >> itemRectHeight; QTreeWidgetItem *itemRectXNode = new QTreeWidgetItem(itemRectNode); itemRectXNode->setText(0, QString("X: %1").arg(itemRectX)); QTreeWidgetItem *itemRectYNode = new QTreeWidgetItem(itemRectNode); itemRectYNode->setText(0, QString("Y: %1").arg(itemRectY)); QTreeWidgetItem *itemRectWidthNode = new QTreeWidgetItem(itemRectNode); itemRectWidthNode->setText(0, QString("Width: %1").arg(itemRectWidth)); QTreeWidgetItem *itemRectHeightNode = new QTreeWidgetItem(itemRectNode); itemRectHeightNode->setText(0, QString("Height: %1").arg(itemRectHeight)); MENU_H_ALIGNMENT itemHAlignment; *aZoneFileStream >> itemHAlignment; QTreeWidgetItem *hTextAlignNode = new QTreeWidgetItem(itemRectNode); QString hTextAlignStr = Utils::MenuHAlignToStr(itemHAlignment); hTextAlignNode->setText(0, QString("Horiz. Align: %1").arg(hTextAlignStr)); MENU_V_ALIGNMENT itemVAlignment; *aZoneFileStream >> itemVAlignment; QTreeWidgetItem *vTextAlignNode = new QTreeWidgetItem(itemRectNode); QString vTextAlignStr = Utils::MenuVAlignToStr(itemVAlignment); vTextAlignNode->setText(0, QString("Vert. Align: %1").arg(vTextAlignStr)); quint32 itemGroupPtr; // Should be const char* *aZoneFileStream >> itemGroupPtr; MENU_WINDOW_STYLE itemWindowStyle; *aZoneFileStream >> itemWindowStyle; MENU_WINDOW_BORDER itemWindowBorder; *aZoneFileStream >> itemWindowBorder; quint32 itemOwnerDraw, itemOwnerDrawFlags; *aZoneFileStream >> itemOwnerDraw >> itemOwnerDrawFlags; float itemBorderSize; *aZoneFileStream >> itemBorderSize; int itemStaticFlags, itemDynamicFlags, itemNextTime; *aZoneFileStream >> itemStaticFlags >> itemDynamicFlags >> itemNextTime; float itemForegroundColorR, itemForegroundColorG, itemForegroundColorB, itemForegroundColorA, itemBackgroundColorR, itemBackgroundColorG, itemBackgroundColorB, itemBackgroundColorA, itemBorderColorR, itemBorderColorG, itemBorderColorB, itemBorderColorA, itemOutlineColorR, itemOutlineColorG, itemOutlineColorB, itemOutlineColorA; *aZoneFileStream >> itemForegroundColorR >> itemForegroundColorG >> itemForegroundColorB >> itemForegroundColorA >> itemBackgroundColorR >> itemBackgroundColorG >> itemBackgroundColorB >> itemBackgroundColorA >> itemBorderColorR >> itemBorderColorG >> itemBorderColorB >> itemBorderColorA >> itemOutlineColorR >> itemOutlineColorG >> itemOutlineColorB >> itemOutlineColorA; quint32 itemMaterialPtr; // Should be Material * *aZoneFileStream >> itemMaterialPtr; QTreeWidgetItem *itemTextRectNode = new QTreeWidgetItem(itemsNode); itemTextRectNode->setText(0, "Item Text Rect"); float itemTextRectX, itemTextRectY, itemTextRectWidth, itemTextRectHeight; *aZoneFileStream >> itemTextRectX >> itemTextRectY >> itemTextRectWidth >> itemTextRectHeight; QTreeWidgetItem *itemTextRectXNode = new QTreeWidgetItem(itemTextRectNode); itemTextRectXNode->setText(0, QString("X: %1").arg(itemTextRectX)); QTreeWidgetItem *itemTextRectYNode = new QTreeWidgetItem(itemTextRectNode); itemTextRectYNode->setText(0, QString("Y: %1").arg(itemTextRectY)); QTreeWidgetItem *itemTextRectWidthNode = new QTreeWidgetItem(itemTextRectNode); itemTextRectWidthNode->setText(0, QString("Width: %1").arg(itemTextRectWidth)); QTreeWidgetItem *itemTextRectHeightNode = new QTreeWidgetItem(itemTextRectNode); itemTextRectHeightNode->setText(0, QString("Height: %1").arg(itemTextRectHeight)); MENU_H_ALIGNMENT itemText_hAlign; *aZoneFileStream >> itemText_hAlign; QTreeWidgetItem *hItemTextAlignNode = new QTreeWidgetItem(itemTextRectNode); QString hItemTextAlignStr = Utils::MenuHAlignToStr(itemText_hAlign); hItemTextAlignNode->setText(0, QString("Horiz. Align: %1").arg(hItemTextAlignStr)); MENU_V_ALIGNMENT itemText_vAlign; *aZoneFileStream >> itemText_vAlign; QTreeWidgetItem *vItemTextAlignNode = new QTreeWidgetItem(itemTextRectNode); QString vItemTextAlignStr = Utils::MenuVAlignToStr(itemText_vAlign); vItemTextAlignNode->setText(0, QString("Vert. Align: %1").arg(vItemTextAlignStr)); MENU_ITEM_TYPE itemType; *aZoneFileStream >> itemType; quint32 dataType, alignment; *aZoneFileStream >> dataType >> alignment; MENU_FONT_TYPE fontEnum; *aZoneFileStream >> fontEnum; quint32 textAlignMode; *aZoneFileStream >> textAlignMode; float textalignx, textaligny, textscale; *aZoneFileStream >> textalignx >> textaligny >> textscale; MENU_ITEM_TEXTSTYLE textStyle; *aZoneFileStream >> textStyle; int gameMsgWindowIndex, gameMsgWindowMode; *aZoneFileStream >> gameMsgWindowIndex >> gameMsgWindowMode; quint32 testPtr; // const char * *aZoneFileStream >> testPtr; quint32 textSavegameInfo; *aZoneFileStream >> textSavegameInfo; quint32 parentPtr; // menuDef_t * *aZoneFileStream >> parentPtr; quint32 mouseEnterText, mouseExitText, mouseEnter, mouseExit, action, onAccept, onFocus, leaveFocus, dvar, dvarTest; // const char * *aZoneFileStream >> mouseEnterText >> mouseExitText >> mouseEnter >> mouseExit >> action >> onAccept >> onFocus >> leaveFocus >> dvar >> dvarTest; quint32 keyHandlerPtr; // ItemKeyHandler * *aZoneFileStream >> keyHandlerPtr; quint32 enableDvarPtr; // const char * *aZoneFileStream >> enableDvarPtr; quint32 dvarFlags; *aZoneFileStream >> dvarFlags; quint32 focusSoundPtr; // snd_alias_list_t *; *aZoneFileStream >> focusSoundPtr; float special; *aZoneFileStream >> special; quint32 cursorPos; *aZoneFileStream >> cursorPos; // itemDefData_t typeData; // listBoxDef_s *listBox; quint32 startPos, endPos, drawPadding; *aZoneFileStream >> startPos >> endPos >> drawPadding; float elementWidth, elementHeight; *aZoneFileStream >> elementWidth >> elementHeight; quint32 elementStyle, numColumns; *aZoneFileStream >> elementStyle >> numColumns; //columnInfo_s columnInfo[16]; quint32 doubleClickPtr; // const char * *aZoneFileStream >> doubleClickPtr; int notselectable, noScrollBars, usePaging; *aZoneFileStream >> notselectable >> noScrollBars >> usePaging; float itemSelectBorderColorR, itemSelectBorderColorG, itemSelectBorderColorB, itemSelectBorderColorA, itemDisableColorR, itemDisableColorG, itemDisableColorB, itemDisableColorA, itemFocusColor2R, itemFocusColor2G, itemFocusColor2B, itemFocusColor2A; *aZoneFileStream >> itemSelectBorderColorR >> itemSelectBorderColorG >> itemSelectBorderColorB >> itemSelectBorderColorA >> itemDisableColorR >> itemDisableColorG >> itemDisableColorB >> itemDisableColorA >> itemFocusColor2R >> itemFocusColor2G >> itemFocusColor2B >> itemFocusColor2A; quint32 selectIconPtr, backgroundItemListboxPtr, highlightTexturePtr; // Material * *aZoneFileStream >> selectIconPtr >> backgroundItemListboxPtr >> highlightTexturePtr; // editFieldDef_s *editField; float minVal, maxVal, defVal, range; *aZoneFileStream >> minVal >> maxVal >> defVal >> range; int maxChars, maxCharsGotoNext, maxPaintChars, paintOffset; *aZoneFileStream >> maxChars >> maxCharsGotoNext >> maxPaintChars >> paintOffset; // multiDef_s *multi; QVector dvarListPtrs = QVector(32); for (int i = 0; i < 32; i++) { quint32 dvarList; *aZoneFileStream >> dvarList; dvarListPtrs.push_back(dvarList); } QVector dvarStrPtrs = QVector(32); for (int i = 0; i < 32; i++) { quint32 dvarStr; *aZoneFileStream >> dvarStr; dvarStrPtrs.push_back(dvarStr); } QVector dvarValues = QVector(32); for (int i = 0; i < 32; i++) { float dvarValue; *aZoneFileStream >> dvarValue; dvarValues.push_back(dvarValue); } quint32 count, strDef; *aZoneFileStream >> count >> strDef; quint32 enumDvarNamePtr; // const char * *aZoneFileStream >> enumDvarNamePtr; quint32 dataPtr; // void * *aZoneFileStream >> dataPtr; quint32 itemImageTrack; *aZoneFileStream >> itemImageTrack; //statement_s visibleExp; //statement_s textExp; //statement_s materialExp; //statement_s rectXExp; //statement_s rectYExp; //statement_s rectWExp; //statement_s rectHExp; //statement_s foreColorAExp; } } void MainWindow::ParseAsset_Weapon(QDataStream *aZoneFileStream) { //WEAPON_FILE } void MainWindow::ParseAsset_D3DBSP(QDataStream *aZoneFileStream) { //D3DBSP_DUMP } void MainWindow::ParseAsset_StringTable(QDataStream *aZoneFileStream) { aZoneFileStream->skipRawData(4); quint32 columnCount, rowCount; *aZoneFileStream >> columnCount >> rowCount; columnCount = 0; rowCount = 0; aZoneFileStream->skipRawData(4); QString stringTableName; char stringTableNameChar; *aZoneFileStream >> stringTableNameChar; while (stringTableNameChar != 0) { stringTableName += stringTableNameChar; *aZoneFileStream >> stringTableNameChar; } ui->comboBox_StringTable->addItem(stringTableName); QVector tablePointers = QVector(); for (quint32 i = 0; i < rowCount; i++) { QByteArray pointerData(4, Qt::Uninitialized); aZoneFileStream->readRawData(pointerData.data(), 4); tablePointers.push_back(pointerData.toHex()); aZoneFileStream->skipRawData(4); } for (const QString &pointerAddr : tablePointers) { QString leadingContent = ""; if (pointerAddr == "FFFFFFFF") { char leadingContentChar; *aZoneFileStream >> leadingContentChar; while (leadingContentChar != 0) { leadingContent += leadingContentChar; *aZoneFileStream >> leadingContentChar; } } else { leadingContent = pointerAddr; } QString content; char contentChar; *aZoneFileStream >> contentChar; while (contentChar != 0) { content += contentChar; *aZoneFileStream >> contentChar; } QPair tableEntry = QPair(); tableEntry.first = leadingContent; tableEntry.second = content; if (!mStrTableMap.contains(stringTableName)) { mStrTableMap[stringTableName] = QVector>(); } mStrTableMap[stringTableName].push_back(tableEntry); } } void MainWindow::on_pushButton_FastFile_clicked() { // Open fast file QString fastFilePath = GetFastFilePath(); OpenFastFile(fastFilePath); } void MainWindow::on_pushButton_ZoneFile_clicked() { const QString zoneFilePath = GetZoneFilePath(); OpenZoneFile(zoneFilePath); } void MainWindow::LogOpenedFile(QString aFileName) { mRecentFiles.enqueue(aFileName); mRecentFiles.removeDuplicates(); RefreshRecentFileMenu(); } void MainWindow::RefreshRecentFileMenu() { foreach (QAction* action, mRecentFileActions) { ui->menuRecent_Fast_Files->removeAction(action); ui->menuRecent_Zone_Files->removeAction(action); action->deleteLater(); } mRecentFileActions.clear(); foreach (QString recentFileText, mRecentFiles) { if (recentFileText.contains(".ff")) { QAction *recentFastFileAction = new QAction(ui->menuRecent_Fast_Files); recentFastFileAction->setText(recentFileText); mRecentFileActions << recentFastFileAction; ui->menuRecent_Fast_Files->addAction(recentFastFileAction); connect(recentFastFileAction, &QAction::triggered, this, [&, this, recentFileText](bool checked = false) { OpenFastFile(recentFileText); }); } else if (recentFileText.contains(".zone")) { QAction *recentZoneFileAction = new QAction(ui->menuRecent_Zone_Files); recentZoneFileAction->setText(recentFileText); mRecentFileActions << recentZoneFileAction; ui->menuRecent_Zone_Files->addAction(recentZoneFileAction); connect(recentZoneFileAction, &QAction::triggered, this, [&, this, recentFileText](bool checked = false) { OpenZoneFile(recentFileText); }); } } } void MainWindow::ParseZoneFile(QByteArray aDecompressedData) { // Open zone file as little endian stream QDataStream zoneFileStream(aDecompressedData); zoneFileStream.setByteOrder(QDataStream::LittleEndian); zoneFileStream.setFloatingPointPrecision(QDataStream::SinglePrecision); // Parse data from zone file header Zone zone; zoneFileStream >> zone; // Add header data to ui ui->spinBox_FileSize->setValue(zone.zoneFileSize); ui->spinBox_TagCount->setValue(zone.tagCount); ui->spinBox_RecordCount->setValue(zone.recordCount); // Add unknowns to ui ui->lineEdit_U1->setText(QString::number(zone.unknown1, 16).toUpper()); ui->spinBox_U1->setValue(zone.unknown1); ui->lineEdit_U2->setText(QString::number(zone.unknown2, 16).toUpper()); ui->spinBox_U2->setValue(zone.unknown2); ui->lineEdit_U3->setText(QString::number(zone.unknown3, 16).toUpper()); ui->spinBox_U3->setValue(zone.unknown3); ui->lineEdit_U4->setText(QString::number(zone.unknown4, 16).toUpper()); ui->spinBox_U4->setValue(zone.unknown4); ui->lineEdit_U5->setText(QString::number(zone.unknown5, 16).toUpper()); ui->spinBox_U5->setValue(zone.unknown5); ui->lineEdit_U6->setText(QString::number(zone.unknown6, 16).toUpper()); ui->spinBox_U6->setValue(zone.unknown6); ui->lineEdit_U7->setText(QString::number(zone.unknown7, 16).toUpper()); ui->spinBox_U7->setValue(zone.unknown7); ui->lineEdit_U8->setText(QString::number(zone.unknown8, 16).toUpper()); ui->spinBox_U8->setValue(zone.unknown8); ui->lineEdit_U9->setText(QString::number(zone.unknown9, 16).toUpper()); ui->spinBox_U9->setValue(zone.unknown9); ui->lineEdit_U10->setText(QString::number(zone.unknown10, 16).toUpper()); ui->spinBox_U10->setValue(zone.unknown10); ui->lineEdit_U11->setText(QString::number(zone.unknown11, 16).toUpper()); ui->spinBox_U11->setValue(zone.unknown11); // Add tags to ui list foreach (const QString tag, zone.tags) { ui->listWidget_Tags->addItem(tag); } // Track past assets and counts int consecutiveIndex = 0; int consecutiveCount = 0; ASSET_TYPE lastAssetType = ASSET_UNKNOWN; foreach (ASSET_TYPE assetType, zone.assetTypes) { const QString typeStr = Utils::AssetTypeToString(assetType); if (!mTypeMap.contains(assetType)) { mTypeMap[assetType] = 0; } mTypeMap[assetType]++; // Set lastAsset as current if first run if (lastAssetType == ASSET_UNKNOWN) { lastAssetType = assetType; } // Track counts or populate asset order table if (lastAssetType == assetType) { // Count consecutive assets consecutiveCount++; } else { // Insert row and populate for the previous asset type ui->tableWidget_Order->insertRow(consecutiveIndex); ui->tableWidget_Order->setItem(consecutiveIndex, 0, new QTableWidgetItem(Utils::AssetTypeToString(lastAssetType))); ui->tableWidget_Order->setItem(consecutiveIndex, 1, new QTableWidgetItem(QString::number(consecutiveCount))); // Update counts and asset type consecutiveCount = 1; consecutiveIndex++; lastAssetType = assetType; } // qDebug() << "Parsing Asset of Type: " << typeHex; if (typeStr == "ANIMATION") { // aitype ParseAsset_XAnim(&zoneFileStream); } else if (typeStr == "MODEL") { // xmodel ParseAsset_XModel(&zoneFileStream); } else if (typeStr == "MATERIAL") { // material ParseAsset_Material(&zoneFileStream); } else if (typeStr == "TECH SET") { // techset include ParseAsset_TechSet(&zoneFileStream); } else if (typeStr == "SOUND") { // loaded_sound ParseAsset_LoadedSound(&zoneFileStream); } else if (typeStr == "COLLISION MAP") { // col_map_mp ParseAsset_ColMapMP(&zoneFileStream); } else if (typeStr == "SHADER") { // pixelshader ParseAsset_PixelShader(&zoneFileStream); } else if (typeStr == "D3DBSP DUMP") { // string_table ParseAsset_D3DBSP(&zoneFileStream); } else if (typeStr == "FONT") { // font ParseAsset_Font(&zoneFileStream); } else if (typeStr == "MENU") { // string_table ParseAsset_MenuFile(&zoneFileStream); } else if (typeStr == "LOCAL STRING") { // localized string asset ParseAsset_Localize(&zoneFileStream); } else if (typeStr == "WEAPON") { // string_table ParseAsset_Weapon(&zoneFileStream); } else if (typeStr == "EFFECT") { // aitype ParseAsset_FX(&zoneFileStream); } else if (typeStr == "RAW FILE") { // gsc // ParseAsset_RawFile(&zoneFileStream); RawFile rawFile = RawFile(); zoneFileStream >> rawFile; mRawFilesVec << rawFile; } else if (typeStr == "STRING TABLE") { // string_table ParseAsset_StringTable(&zoneFileStream); } else { qDebug() << "Found bad asset type!" << typeStr; } } // Track current and consecutive assets int assetIndex = 0; // Iterate asset types found in index for (auto [assetType, assetCount] : mTypeMap.asKeyValueRange()) { const QString typeStr = Utils::AssetTypeToString(assetType); // Insert row and populate ui->tableWidget_Index->insertRow(assetIndex); ui->tableWidget_Index->setItem(assetIndex, 0, new QTableWidgetItem(typeStr)); ui->tableWidget_Index->setItem(assetIndex, 1, new QTableWidgetItem(QString::number(assetCount))); // Update count assetIndex++; } } int MainWindow::LoadFile_D3DBSP(const QString aFilePath) { QFile file(aFilePath); if (!file.open(QIODevice::ReadOnly)) { qDebug() << "Error: Unable to open file" << aFilePath; return 1; // ERR_FILE_NOT_FOUND } QDataStream stream(&file); stream.setByteOrder(QDataStream::LittleEndian); // Read Magic Value quint32 magicValue; stream >> magicValue; if (magicValue != 'PSBI') { qDebug() << "Error: Not a valid D3DBSP file"; return 2; // ERR_NOT_A_D3DBSP_FILE } // Read BSP Version and Lump Count stream >> mBSPVersion; stream >> mDiskLumpCount; // Assign diskLumpOrderSize mDiskLumpOrder.resize(mDiskLumpCount); qDebug() << "BSP Version:" << mBSPVersion; qDebug() << "Lump Count:" << mDiskLumpCount; // Read Lump Index Entries quint32 lumpOffset = sizeof(quint32) * 3 + sizeof(LumpIndexEntry) * mDiskLumpCount; for (quint32 i = 0; i < mDiskLumpCount; i++) { LumpIndexEntry indexEntry; stream >> indexEntry.type >> indexEntry.length; mDiskLumpOrder[i] = indexEntry.type; Lump &lump = mLumps[indexEntry.type]; lump.size = indexEntry.length; lump.content.resize(indexEntry.length); lump.isEmpty = false; qDebug() << "Lump Type:" << Utils::LumpTypeToString((LUMP_TYPE)indexEntry.type) << "Lump Size:" << indexEntry.length; // Handle offsets and padding qint64 currentPos = file.pos(); file.seek(lumpOffset); file.read(lump.content.data(), lump.size); file.seek(currentPos); lumpOffset += Utils::PadInt4(indexEntry.length); } file.close(); return 0; // Success }