mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-22 20:17:46 +00:00
Add explorer tool
This is similar to FFXIVExplorer, where you can view a list of known files in a nice tree view.
This commit is contained in:
parent
de2b6f6307
commit
1c77a0b06e
7 changed files with 207 additions and 3 deletions
|
@ -37,4 +37,5 @@ endif()
|
|||
|
||||
add_subdirectory(renderer)
|
||||
add_subdirectory(exdviewer)
|
||||
add_subdirectory(mdlviewer)
|
||||
add_subdirectory(mdlviewer)
|
||||
add_subdirectory(explorer)
|
12
README.md
12
README.md
|
@ -45,4 +45,14 @@ You must pass the path to your `sqpack` directory as the first argument.
|
|||
The viewport uses Vulkan, so it must be supported on your system in order to work.
|
||||
|
||||
If you're running mdlviewer on macOS (where Qt builds usually don't ship with MoltenVK unfortunatey)
|
||||
mdlviewer will automatically reconfigure itself to use a standalone SDL2 window.
|
||||
mdlviewer will automatically reconfigure itself to use a standalone SDL2 window.
|
||||
|
||||
## explorer
|
||||
|
||||
This tool can list known files by libxiv, such as excel sheets.
|
||||
|
||||
### Usage
|
||||
|
||||
You must pass the path to your `sqpack` directory as the first argument.
|
||||
|
||||
`explorer.exe C:\Program Files (x86)\SquareEnix\Final Fantasy XIV\game\sqpack`
|
||||
|
|
24
explorer/CMakeLists.txt
Normal file
24
explorer/CMakeLists.txt
Normal file
|
@ -0,0 +1,24 @@
|
|||
add_executable(explorer
|
||||
src/main.cpp
|
||||
src/mainwindow.cpp)
|
||||
target_include_directories(explorer
|
||||
PUBLIC
|
||||
include)
|
||||
target_link_libraries(explorer PUBLIC libxiv ${LIBRARIES} Qt5::Core Qt5::Widgets)
|
||||
|
||||
install(TARGETS explorer
|
||||
DESTINATION "${INSTALL_BIN_PATH}")
|
||||
|
||||
if(WIN32)
|
||||
get_target_property(QMAKE_EXE Qt5::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(QT_BIN_DIR "${QMAKE_EXE}" DIRECTORY)
|
||||
|
||||
find_program(WINDEPLOYQT_ENV_SETUP qtenv2.bat HINTS "${QT_BIN_DIR}")
|
||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${QT_BIN_DIR}")
|
||||
|
||||
# Run windeployqt immediately after build
|
||||
add_custom_command(TARGET explorer
|
||||
POST_BUILD
|
||||
COMMAND "${WINDEPLOYQT_ENV_SETUP}" && "${WINDEPLOYQT_EXECUTABLE}" \"$<TARGET_FILE:explorer>\"
|
||||
)
|
||||
endif()
|
31
explorer/include/mainwindow.h
Normal file
31
explorer/include/mainwindow.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMap>
|
||||
#include <QTreeWidget>
|
||||
|
||||
struct PathPart {
|
||||
uint32_t crcHash;
|
||||
QMap<QString, PathPart> children;
|
||||
};
|
||||
|
||||
class GameData;
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
public:
|
||||
MainWindow(GameData& data);
|
||||
|
||||
private:
|
||||
void addPath(QString path);
|
||||
void addUnknownPath(QString knownDirectory, uint32_t crcHash);
|
||||
void traversePart(QList<QString> tokens, PathPart& part, QString pathSoFar);
|
||||
std::tuple<bool, QString> traverseUnknownPath(uint32_t crcHash, PathPart& part, QString pathSoFar);
|
||||
|
||||
QMap<QString, PathPart> rootParts;
|
||||
|
||||
GameData& data;
|
||||
|
||||
void addPaths(QTreeWidget *pWidget);
|
||||
|
||||
QTreeWidgetItem* addPartAndChildren(const QString& qString, const PathPart& part);
|
||||
};
|
15
explorer/src/main.cpp
Normal file
15
explorer/src/main.cpp
Normal file
|
@ -0,0 +1,15 @@
|
|||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "gamedata.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
|
||||
GameData data(argv[1]);
|
||||
|
||||
MainWindow w(data);
|
||||
w.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
123
explorer/src/mainwindow.cpp
Normal file
123
explorer/src/mainwindow.cpp
Normal file
|
@ -0,0 +1,123 @@
|
|||
#include "mainwindow.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QTableWidget>
|
||||
#include <QTreeWidget>
|
||||
#include <QDebug>
|
||||
|
||||
#include "gamedata.h"
|
||||
#include "exhparser.h"
|
||||
#include "exdparser.h"
|
||||
|
||||
MainWindow::MainWindow(GameData& data) : data(data) {
|
||||
setWindowTitle("explorer");
|
||||
|
||||
addPath("exd/root.exl");
|
||||
|
||||
for(auto sheetName : data.getAllSheetNames()) {
|
||||
auto nameLowercase = QString(sheetName.c_str()).toLower().toStdString();
|
||||
|
||||
addPath("exd/" + QString(nameLowercase.c_str()) + ".exh");
|
||||
|
||||
auto exh = *data.readExcelSheet(sheetName);
|
||||
for(auto page : exh.pages) {
|
||||
for(auto language : exh.language) {
|
||||
std::string path;
|
||||
if (language == Language::None) {
|
||||
path = getEXDFilename(exh, nameLowercase, "", page);
|
||||
} else {
|
||||
path = getEXDFilename(exh, nameLowercase, getLanguageCode(language), page);
|
||||
}
|
||||
|
||||
addPath(("exd/" + path).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addPath("common/font/AXIS_12.fdt");
|
||||
|
||||
auto commonIndex = data.getIndexListing("common");
|
||||
for(auto entry : commonIndex.entries) {
|
||||
addUnknownPath("common", entry.hash);
|
||||
}
|
||||
|
||||
auto dummyWidget = new QWidget();
|
||||
setCentralWidget(dummyWidget);
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
dummyWidget->setLayout(layout);
|
||||
|
||||
auto treeWidget = new QTreeWidget();
|
||||
treeWidget->setHeaderLabel("Name");
|
||||
|
||||
addPaths(treeWidget);
|
||||
|
||||
layout->addWidget(treeWidget);
|
||||
}
|
||||
|
||||
void MainWindow::addPath(QString path) {
|
||||
auto tokens = path.split('/');
|
||||
auto nextToken = tokens[0];
|
||||
tokens.pop_front();
|
||||
|
||||
traversePart(tokens, rootParts[nextToken], nextToken);
|
||||
}
|
||||
|
||||
void MainWindow::traversePart(QList<QString> tokens, PathPart& part, QString pathSoFar) {
|
||||
if(tokens.empty())
|
||||
return;
|
||||
|
||||
auto nextToken = tokens[0];
|
||||
tokens.pop_front();
|
||||
|
||||
pathSoFar = pathSoFar + "/" + nextToken;
|
||||
part.children[nextToken].crcHash = data.calculateHash(pathSoFar.toStdString());
|
||||
|
||||
traversePart(tokens, part.children[nextToken], pathSoFar);
|
||||
}
|
||||
|
||||
void MainWindow::addPaths(QTreeWidget *pWidget) {
|
||||
for(const auto& name : rootParts.keys()) {
|
||||
auto item = addPartAndChildren(name, rootParts.value(name));
|
||||
pWidget->addTopLevelItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
QTreeWidgetItem* MainWindow::addPartAndChildren(const QString& qString, const PathPart& part) {
|
||||
auto item = new QTreeWidgetItem();
|
||||
item->setText(0, qString);
|
||||
|
||||
for(const auto& name : part.children.keys()) {
|
||||
auto childItem = addPartAndChildren(name, part.children.value(name));
|
||||
item->addChild(childItem);
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
void MainWindow::addUnknownPath(QString knownDirectory, uint32_t crcHash) {
|
||||
auto [found, path] = traverseUnknownPath(crcHash, rootParts[knownDirectory], knownDirectory);
|
||||
if(found)
|
||||
addPath(path);
|
||||
else
|
||||
addPath(knownDirectory + "/Unknown File Hash " + QString::number(crcHash));
|
||||
}
|
||||
|
||||
std::tuple<bool, QString> MainWindow::traverseUnknownPath(uint32_t crcHash, PathPart &part, QString pathSoFar) {
|
||||
if(part.crcHash == crcHash)
|
||||
return {true, pathSoFar};
|
||||
|
||||
bool found = false;
|
||||
QString childPath = pathSoFar;
|
||||
for(auto path : part.children.keys()) {
|
||||
if(path.contains("Unknown"))
|
||||
continue;
|
||||
|
||||
auto [childFound, newPath] = traverseUnknownPath(crcHash, part.children[path], pathSoFar + "/" + path);
|
||||
found |= childFound;
|
||||
if(childFound)
|
||||
childPath = newPath;
|
||||
}
|
||||
|
||||
return {found, childPath};
|
||||
}
|
2
libxiv
2
libxiv
|
@ -1 +1 @@
|
|||
Subproject commit a7751a50bb71fdce2c3db9ba2d18f49f3d754300
|
||||
Subproject commit ce7c99c3de4853758bd37d46b3e582b27681797a
|
Loading…
Add table
Reference in a new issue