Skip to content

Commit

Permalink
Initial support for Starfield. It is able to decompile everything, th…
Browse files Browse the repository at this point in the history
…ough the syntax for locking and unlocking guards is obviously not correct.
  • Loading branch information
Orvid committed Sep 2, 2023
1 parent 3475c2e commit aa4d9c0
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 29 deletions.
17 changes: 17 additions & 0 deletions Decompiler/PscCoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ void Decompiler::PscCoder::writeObject(const Pex::Object &object, const Pex::Bin
writeVariables(object, pex);
}

if (object.getGuards().size()) {
write("");
write(";-- Guards ------------------------------------------");
writeGuards(object, pex);
}

if (object.getProperties().size()) {
write("");
write(";-- Properties --------------------------------------");
Expand Down Expand Up @@ -406,6 +412,17 @@ void Decompiler::PscCoder::writeVariables(const Pex::Object &object, const Pex::
}
}

/**
* @brief Write the guards contained in the object.
* @param object Object containing the guards.
* @param pex Binary to decompile.
*/
void Decompiler::PscCoder::writeGuards(const Pex::Object& object, const Pex::Binary& pex) {
for (auto& guard : object.getGuards()) {
auto name = guard.getName().asString();
write("Guard " + name);
}
}

/**
* @brief Write the states contained in the object.
Expand Down
1 change: 1 addition & 0 deletions Decompiler/PscCoder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class PscCoder :
void writeProperties(const Pex::Object& object, const Pex::Binary& pex);
void writeProperty(int i, const Pex::Property& prop, const Pex::Object &object, const Pex::Binary& pex);
void writeVariables(const Pex::Object& object, const Pex::Binary& pex);
void writeGuards(const Pex::Object& object, const Pex::Binary& pex);
void writeStates(const Pex::Object& object, const Pex::Binary& pex);
void writeFunctions(int i, const Pex::State& state, const Pex::Object &object, const Pex::Binary& pex);
void writeFunction(int i, const Pex::Function& function, const Pex::Object &object, const Pex::Binary& pex, const std::string& name = "");
Expand Down
69 changes: 47 additions & 22 deletions Decompiler/PscDecompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ Decompiler::PscDecompiler::PscDecompiler( const Pex::Function &function,
m_TempTable.push_back("remove");
m_TempTable.push_back("clear");
m_TempTable.push_back("getallmatchingstructs");
m_TempTable.push_back("lock");
m_TempTable.push_back("unlock");
m_TempTable.push_back("trylock");

//findReplacedVars();
findVarTypes();
Expand Down Expand Up @@ -403,8 +406,7 @@ void Decompiler::PscDecompiler::createNodesForBlocks(size_t block)
auto& varargs = ins.getVarArgs();

Node::BasePtr node;
switch(ins.getOpCode())
{
switch (ins.getOpCode()) {
case Pex::OpCode::NOP:
//do nothing
break;
Expand Down Expand Up @@ -456,15 +458,11 @@ void Decompiler::PscDecompiler::createNodesForBlocks(size_t block)
}
case Pex::OpCode::CAST:
{
if(args[1].getType() == Pex::ValueType::None)
{
if (args[1].getType() == Pex::ValueType::None) {
node = std::make_shared<Node::Copy>(ip, args[0].getId(), fromValue(ip, args[1]));
}
else if (args[1].getType() != Pex::ValueType::Identifier || (typeOfVar(args[0].getId()) != typeOfVar(args[1].getId()) && args[1].getId() != m_NoneVar) )
{
} else if (args[1].getType() != Pex::ValueType::Identifier || (typeOfVar(args[0].getId()) != typeOfVar(args[1].getId()) && args[1].getId() != m_NoneVar)) {
node = std::make_shared<Node::Cast>(ip, args[0].getId(), fromValue(ip, args[1]), typeOfVar(args[0].getId()));
}
else // two variables of the same type, equivalent to an assign
} else // two variables of the same type, equivalent to an assign
{
node = std::make_shared<Node::Copy>(ip, args[0].getId(), fromValue(ip, args[1]));
}
Expand Down Expand Up @@ -504,19 +502,17 @@ void Decompiler::PscDecompiler::createNodesForBlocks(size_t block)
{
auto callNode = std::make_shared<Node::CallMethod>(ip, args[2].getId(), fromValue(ip, args[1]), args[0].getId());
auto argNode = callNode->getParameters();
for (auto varg : varargs)
{
for (auto varg : varargs) {
*argNode << fromValue(ip, varg);
}
}
node = callNode;
break;
}
case Pex::OpCode::CALLPARENT:
{
auto callNode = std::make_shared<Node::CallMethod>(ip, args[1].getId(), std::make_shared<Node::IdentifierString>(ip, "Parent"), args[0].getId());
auto argNode = callNode->getParameters();
for (auto varg : varargs)
{
for (auto varg : varargs) {
*argNode << fromValue(ip, varg);
}
node = callNode;
Expand All @@ -526,21 +522,17 @@ void Decompiler::PscDecompiler::createNodesForBlocks(size_t block)
{
auto callNode = std::make_shared<Node::CallMethod>(ip, args[2].getId(), fromValue(ip, args[0]), args[1].getId());
auto argNode = callNode->getParameters();
for (auto varg : varargs)
{
for (auto varg : varargs) {
*argNode << fromValue(ip, varg);
}
node = callNode;
break;
}
case Pex::OpCode::RETURN:
{
if(m_ReturnNone)
{
if (m_ReturnNone) {
node = std::make_shared<Node::Return>(ip, nullptr);
}
else
{
} else {
node = std::make_shared<Node::Return>(ip, fromValue(ip, args[0]));
}
break;
Expand Down Expand Up @@ -693,7 +685,40 @@ void Decompiler::PscDecompiler::createNodesForBlocks(size_t block)
node = callNode;
break;
}

case Pex::OpCode::LOCK_GUARDS:
{
auto callNode = std::make_shared<Node::CallMethod>(ip, Pex::StringTable::Index(), std::make_shared<Node::IdentifierString>(ip, "lfunc"), m_TempTable.findIdentifier("lock"));
auto argNode = callNode->getParameters();
for (auto varg : varargs) {
*argNode << fromValue(ip, varg);
}
node = callNode;
break;
}
case Pex::OpCode::UNLOCK_GUARDS:
{
auto callNode = std::make_shared<Node::CallMethod>(ip, Pex::StringTable::Index(), std::make_shared<Node::IdentifierString>(ip, "lfunc"), m_TempTable.findIdentifier("unlock"));
auto argNode = callNode->getParameters();
for (auto varg : varargs) {
*argNode << fromValue(ip, varg);
}
node = callNode;
break;
}
case Pex::OpCode::TRY_LOCK_GUARDS:
{
auto callNode = std::make_shared<Node::CallMethod>(ip, args[0].getId(), std::make_shared<Node::IdentifierString>(ip, "lfunc"), m_TempTable.findIdentifier("trylock"));
auto argNode = callNode->getParameters();
for (auto varg : varargs) {
*argNode << fromValue(ip, varg);
}
node = callNode;
break;
}
default:
{
throw std::exception("Unsupported opcode");
}
}
if (node)
{
Expand Down
20 changes: 17 additions & 3 deletions Pex/FileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void Pex::FileReader::read(Pex::Binary &binary)
m_StringTable = & binary.getStringTable();
read(binary.getDebugInfo());
read(binary.getUserFlags());
read(binary.getObjects());
read(binary.getHeader(), binary.getObjects());
}

/**
Expand All @@ -88,7 +88,6 @@ void Pex::FileReader::readHeader(Pex::Header &header)
} else {
m_endianness = LITTLE_ENDIAN;
}

header.setMajorVersion(getUint8());
header.setMinorVersion(getUint8());
header.setGameID(getUint16());
Expand Down Expand Up @@ -201,7 +200,7 @@ void Pex::FileReader::read(Pex::UserFlags &userFlags)
* @brief Reads the Objects definitions from the file.
* @param[in] objects Object collection to fill in.
*/
void Pex::FileReader::read(Pex::Objects &objects)
void Pex::FileReader::read(const Pex::Header &header, Pex::Objects &objects)
{
auto count = getUint16();
objects.resize(count);
Expand All @@ -224,6 +223,9 @@ void Pex::FileReader::read(Pex::Objects &objects)
read(object.getStructInfos());
}
read(object.getVariables());
if (header.getMajorVersion() > 3 || (header.getMajorVersion() == 3 && header.getMinorVersion() >= 12)) {
read(object.getGuards());
}
read(object.getProperties());
read(object.getStates());
}
Expand Down Expand Up @@ -326,6 +328,18 @@ void Pex::FileReader::read(Pex::States &states)
}
}

/**
* @brief Reads the Guards definition for an object
* @param[in] guards collection to fill in.
*/
void Pex::FileReader::read(Pex::Guards& guards) {
auto guardCount = getUint16();
guards.resize(guardCount);
for (auto& guard : guards) {
guard.setName(getStringIndex());
}
}

/**
* @brief Reads the Functions definition for a state
* @param[in] functions collection to fill in.
Expand Down
3 changes: 2 additions & 1 deletion Pex/FileReader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ class FileReader
void read(StringTable& stringTable);
void read(DebugInfo& debugInfo);
void read(UserFlags& userFlags);
void read(Objects& objects);
void read(const Pex::Header& header, Objects& objects);
void read(StructInfos& structInfos);
void read(Variables& variables);
void read(Properties& properties);
void read(States& states);
void read(Guards& guards);
void read(Functions& functions);
void read(Function& function);
void read(TypedNames& typednames);
Expand Down
25 changes: 25 additions & 0 deletions Pex/Guard.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <cstdint>
#include <vector>

#include "StringTable.hpp"
#include "NamedItem.hpp"

namespace Pex {

/**
* @brief Guard definition
*
* This class contains the names guard.
*
*/
class Guard :
public NamedItem {
public:
Guard() = default;
~Guard() = default;
};

typedef std::vector<Guard> Guards;
}
5 changes: 4 additions & 1 deletion Pex/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ static const OpCodeInfo OPCODES[int(Pex::OpCode::MAX_OPCODE)] = {
{"array_removelast", 1, false},
{"array_remove", 3, false},
{"array_clear", 1, false},
{"array_getallmatchingstructs", 6, false},
{"array_getallmatchingstructs", 6, false},
{"lock_guards", 0, true},
{"unlock_guards", 0, true},
{"try_lock_guards", 1, true},
};

/**
Expand Down
6 changes: 5 additions & 1 deletion Pex/Instruction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ enum class OpCode {
ARRAY_REMOVELAST,
ARRAY_REMOVE,
ARRAY_CLEAR,
//New in Fallout 76
// New in Fallout 76
ARRAY_GETALLMATCHINGSTRUCTS,
// New in Starfield
LOCK_GUARDS,
UNLOCK_GUARDS,
TRY_LOCK_GUARDS,
MAX_OPCODE
};

Expand Down
16 changes: 16 additions & 0 deletions Pex/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,19 @@ Pex::States &Pex::Object::getStates()
{
return m_States;
}

/**
* @brief Get the guards list
* @return The const guards list
*/
const Pex::Guards& Pex::Object::getGuards() const {
return m_Guards;
}

/**
* @brief Get the guards list
* @return The const guards list
*/
Pex::Guards& Pex::Object::getGuards() {
return m_Guards;
}
6 changes: 5 additions & 1 deletion Pex/Object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Variable.hpp"
#include "Property.hpp"
#include "State.hpp"
#include "Guard.hpp"

namespace Pex {

Expand Down Expand Up @@ -52,6 +53,9 @@ class Object :
const States& getStates() const;
States& getStates();

const Guards& getGuards() const;
Guards& getGuards();

private:
StringTable::Index m_ParentClassName;
StringTable::Index m_AutoStateName;
Expand All @@ -61,7 +65,7 @@ class Object :
Variables m_Variables;
Properties m_Properties;
States m_States;

Guards m_Guards;
};

typedef std::vector<Object> Objects;
Expand Down

0 comments on commit aa4d9c0

Please sign in to comment.