mirror of
https://github.com/redstrate/Novus.git
synced 2025-05-01 15:57:45 +00:00
Decompile Lua bytecode in Data Explorer
The game has *tons* of Lua scripts for event scripting, and are very interesting to explore. I had to do manually call luadec before, but now it should be much easier by automatically decompiling Lua scripts in the Data Explorer.
This commit is contained in:
parent
365d75c754
commit
dab4a698b2
11 changed files with 126 additions and 5 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
||||||
[submodule "extern/dxbc"]
|
[submodule "extern/dxbc"]
|
||||||
path = extern/dxbc
|
path = extern/dxbc
|
||||||
url = ../dxbc
|
url = ../dxbc
|
||||||
|
[submodule "extern/luadec51"]
|
||||||
|
path = extern/luadec51
|
||||||
|
url = ../luadec51
|
||||||
|
|
|
@ -45,6 +45,7 @@ target_link_libraries(novus-sagasu
|
||||||
Novus::TexPart
|
Novus::TexPart
|
||||||
Novus::DicPart
|
Novus::DicPart
|
||||||
Novus::MtrlPart
|
Novus::MtrlPart
|
||||||
|
Novus::LuabPart
|
||||||
Physis::Logger
|
Physis::Logger
|
||||||
Qt6::Concurrent
|
Qt6::Concurrent
|
||||||
Qt6::Network)
|
Qt6::Network)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "filepropertieswindow.h"
|
#include "filepropertieswindow.h"
|
||||||
#include "filetypes.h"
|
#include "filetypes.h"
|
||||||
#include "hexpart.h"
|
#include "hexpart.h"
|
||||||
|
#include "luabpart.h"
|
||||||
#include "mdlpart.h"
|
#include "mdlpart.h"
|
||||||
#include "mtrlpart.h"
|
#include "mtrlpart.h"
|
||||||
#include "shpkpart.h"
|
#include "shpkpart.h"
|
||||||
|
@ -173,6 +174,11 @@ void MainWindow::refreshParts(const QString &path)
|
||||||
mtrlWidget->load(physis_material_parse(file));
|
mtrlWidget->load(physis_material_parse(file));
|
||||||
partHolder->addTab(mtrlWidget, i18nc("@title:tab", "Material"));
|
partHolder->addTab(mtrlWidget, i18nc("@title:tab", "Material"));
|
||||||
} break;
|
} break;
|
||||||
|
case FileType::LuaBytecode: {
|
||||||
|
auto luabWidget = new LuabPart();
|
||||||
|
luabWidget->load(file);
|
||||||
|
partHolder->addTab(luabWidget, i18nc("@title:tab", "Lua"));
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,20 @@
|
||||||
|
|
||||||
#include "novuscommon_export.h"
|
#include "novuscommon_export.h"
|
||||||
|
|
||||||
enum class FileType { Unknown, ExcelList, ExcelHeader, ExcelData, Model, Texture, ShaderPackage, CharaMakeParams, Skeleton, Dictionary, Material };
|
enum class FileType {
|
||||||
|
Unknown,
|
||||||
|
ExcelList,
|
||||||
|
ExcelHeader,
|
||||||
|
ExcelData,
|
||||||
|
Model,
|
||||||
|
Texture,
|
||||||
|
ShaderPackage,
|
||||||
|
CharaMakeParams,
|
||||||
|
Skeleton,
|
||||||
|
Dictionary,
|
||||||
|
Material,
|
||||||
|
LuaBytecode
|
||||||
|
};
|
||||||
|
|
||||||
class NOVUSCOMMON_EXPORT FileTypes
|
class NOVUSCOMMON_EXPORT FileTypes
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,7 +15,8 @@ const static QMap<QString, FileType> extensionToType{{QStringLiteral("exl"), Fil
|
||||||
{QStringLiteral("cmp"), FileType::CharaMakeParams},
|
{QStringLiteral("cmp"), FileType::CharaMakeParams},
|
||||||
{QStringLiteral("sklb"), FileType::Skeleton},
|
{QStringLiteral("sklb"), FileType::Skeleton},
|
||||||
{QStringLiteral("dic"), FileType::Dictionary},
|
{QStringLiteral("dic"), FileType::Dictionary},
|
||||||
{QStringLiteral("mtrl"), FileType::Material}};
|
{QStringLiteral("mtrl"), FileType::Material},
|
||||||
|
{QStringLiteral("luab"), FileType::LuaBytecode}};
|
||||||
|
|
||||||
const static QMap<FileType, QString> typeToName{{FileType::Unknown, i18n("Unknown")},
|
const static QMap<FileType, QString> typeToName{{FileType::Unknown, i18n("Unknown")},
|
||||||
{FileType::ExcelList, i18n("Excel List")},
|
{FileType::ExcelList, i18n("Excel List")},
|
||||||
|
@ -27,7 +28,8 @@ const static QMap<FileType, QString> typeToName{{FileType::Unknown, i18n("Unknow
|
||||||
{FileType::CharaMakeParams, i18n("Chara Make Params")},
|
{FileType::CharaMakeParams, i18n("Chara Make Params")},
|
||||||
{FileType::Skeleton, i18n("Skeleton")},
|
{FileType::Skeleton, i18n("Skeleton")},
|
||||||
{FileType::Dictionary, i18n("Dictionary")},
|
{FileType::Dictionary, i18n("Dictionary")},
|
||||||
{FileType::Material, i18n("Material")}};
|
{FileType::Material, i18n("Material")},
|
||||||
|
{FileType::LuaBytecode, i18n("Lua Bytecode")}};
|
||||||
|
|
||||||
const static QMap<FileType, QString> typeToIcon{{FileType::Unknown, QStringLiteral("unknown")},
|
const static QMap<FileType, QString> typeToIcon{{FileType::Unknown, QStringLiteral("unknown")},
|
||||||
{FileType::ExcelList, QStringLiteral("x-office-spreadsheet")},
|
{FileType::ExcelList, QStringLiteral("x-office-spreadsheet")},
|
||||||
|
@ -39,7 +41,8 @@ const static QMap<FileType, QString> typeToIcon{{FileType::Unknown, QStringLiter
|
||||||
{FileType::CharaMakeParams, QStringLiteral("step_object_SoftBody-symbolic")},
|
{FileType::CharaMakeParams, QStringLiteral("step_object_SoftBody-symbolic")},
|
||||||
{FileType::Skeleton, QStringLiteral("user-symbolic")},
|
{FileType::Skeleton, QStringLiteral("user-symbolic")},
|
||||||
{FileType::Dictionary, QStringLiteral("accessories-dictionary-symbolic")},
|
{FileType::Dictionary, QStringLiteral("accessories-dictionary-symbolic")},
|
||||||
{FileType::Material, QStringLiteral("map-globe-symbolic")}};
|
{FileType::Material, QStringLiteral("map-globe-symbolic")},
|
||||||
|
{FileType::LuaBytecode, QStringLiteral("text-x-lua")}};
|
||||||
|
|
||||||
FileType FileTypes::getFileType(const QString &extension)
|
FileType FileTypes::getFileType(const QString &extension)
|
||||||
{
|
{
|
||||||
|
|
5
extern/CMakeLists.txt
vendored
5
extern/CMakeLists.txt
vendored
|
@ -23,3 +23,8 @@ add_subdirectory(magic_enum EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(tinygltf EXCLUDE_FROM_ALL)
|
add_subdirectory(tinygltf EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(imgui EXCLUDE_FROM_ALL)
|
add_subdirectory(imgui EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(dxbc EXCLUDE_FROM_ALL)
|
add_subdirectory(dxbc EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
# For some reason, FFXIV uses a *32-bit* Lua compiler. We have to build it as 32-bit or else loading the bytecode fails.
|
||||||
|
add_compile_options(-m32)
|
||||||
|
add_link_options(-m32)
|
||||||
|
add_subdirectory(luadec51 EXCLUDE_FROM_ALL)
|
1
extern/luadec51
vendored
Submodule
1
extern/luadec51
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 94a5e2b8e08b2c0fdbefc46239b92f1bdcdac303
|
|
@ -10,4 +10,5 @@ add_subdirectory(mdl)
|
||||||
add_subdirectory(mtrl)
|
add_subdirectory(mtrl)
|
||||||
add_subdirectory(shpk)
|
add_subdirectory(shpk)
|
||||||
add_subdirectory(sklb)
|
add_subdirectory(sklb)
|
||||||
add_subdirectory(tex)
|
add_subdirectory(tex)
|
||||||
|
add_subdirectory(luab)
|
16
parts/luab/CMakeLists.txt
Normal file
16
parts/luab/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
add_library(luabpart STATIC)
|
||||||
|
target_sources(luabpart PRIVATE luabpart.cpp)
|
||||||
|
target_link_libraries(luabpart
|
||||||
|
PUBLIC
|
||||||
|
KF6::I18n
|
||||||
|
Physis::Physis
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Widgets)
|
||||||
|
target_include_directories(luabpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_compile_definitions(luabpart PRIVATE TRANSLATION_DOMAIN="novus")
|
||||||
|
add_dependencies(luabpart luadec)
|
||||||
|
|
||||||
|
add_library(Novus::LuabPart ALIAS luabpart)
|
48
parts/luab/luabpart.cpp
Normal file
48
parts/luab/luabpart.cpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "luabpart.h"
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
#include <QJsonArray>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QTemporaryFile>
|
||||||
|
#include <QTextEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <physis.hpp>
|
||||||
|
|
||||||
|
LuabPart::LuabPart(QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
auto layout = new QVBoxLayout();
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
m_codeEdit = new QTextEdit();
|
||||||
|
m_codeEdit->setReadOnly(true);
|
||||||
|
layout->addWidget(m_codeEdit);
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LuabPart::load(physis_Buffer buffer)
|
||||||
|
{
|
||||||
|
QTemporaryFile temporaryFile;
|
||||||
|
if (temporaryFile.open()) {
|
||||||
|
QFile file(temporaryFile.fileName());
|
||||||
|
file.open(QIODevice::WriteOnly);
|
||||||
|
file.write(reinterpret_cast<const char *>(buffer.data), buffer.size);
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
QProcess luaDecProcess;
|
||||||
|
luaDecProcess.setProgram(QStringLiteral("./luadec"));
|
||||||
|
luaDecProcess.setArguments({temporaryFile.fileName()});
|
||||||
|
luaDecProcess.start();
|
||||||
|
luaDecProcess.waitForFinished();
|
||||||
|
|
||||||
|
m_codeEdit->setText(QString::fromUtf8(luaDecProcess.readAllStandardOutput()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_luabpart.cpp"
|
24
parts/luab/luabpart.h
Normal file
24
parts/luab/luabpart.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QTableWidget>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <physis.hpp>
|
||||||
|
|
||||||
|
class QTextEdit;
|
||||||
|
|
||||||
|
class LuabPart : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit LuabPart(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void load(physis_Buffer file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GameData *data = nullptr;
|
||||||
|
QTextEdit *m_codeEdit = nullptr;
|
||||||
|
};
|
Loading…
Add table
Reference in a new issue