Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(redm/script): add patch for overriding train tracks and trolley cables from resource #2432

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions code/components/citizen-resources-gta/src/ResourcesTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ namespace streaming
void RemoveDataFileFromLoadList(const std::string& type, const std::string& path);

void SetNextLevelPath(const std::string& path);

#if defined(IS_RDR3)
void SetTrainTrackFilePath(const std::string& path);
void SetTrolleyCableFilePath(const std::string& path);
#endif
}
#endif

Expand Down Expand Up @@ -188,6 +193,18 @@ static InitFunction initFunction([] ()
streaming::SetNextLevelPath(resourceRoot + meta.second);
}

#if defined(IS_RDR3)
for (auto& meta : metaData->GetEntries("replace_traintrack_file"))
{
streaming::SetTrainTrackFilePath(resourceRoot + meta.second);
}

for (auto& meta : metaData->GetEntries("replace_trolley_cable_file"))
{
streaming::SetTrolleyCableFilePath(resourceRoot + meta.second);
}
#endif

if (!RangeLengthMatches(metaData->GetEntries("data_file"), metaData->GetEntries("data_file_extra")))
{
GlobalError("data_file entry count mismatch in resource %s", resource->GetName());
Expand Down
76 changes: 76 additions & 0 deletions code/components/gta-core-rdr3/src/PatchTrainTrackFileOverride.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include <StdInc.h>
#include <Hooking.h>
#include <Hooking.Stubs.h>
#include <Hooking.Patterns.h>
#include <GameInit.h>

//
// The tracks that vehicles like trains and the Saint Denis trolley follow, as well as the cables dangling
// above the trolley's route, are defined in a plain-text format stored in several *.dat files. These files
// are in turn referenced by filepath by an XML file - traintracks.xml for vehicles, trolleyCableTracks.xml for the cables.
//
// There is currently no way to fully replace the track data within the *.dat files, nor to modify or override the XML files.
// This patch introduces a way to replace the XML files, allowing for fully custom rail (and trolley cable?) networks.
// We intercept all calls to LoadTrackXML(), and if one of the override filepaths is valid, we use it instead of the default
// path. To set these override filenames, the resource must define either (or both) of the following statements:
//
// * replace_traintrack_file 'path/to/traintracks.xml'
//
// * replace_trolley_cable_file 'path/to/trolleyCableTracks.xml'
//

#define DEFAULT_TRACK_FILE "common:/data/levels/rdr3/traintracks.xml"
#define DEFAULT_CABLES_FILE "common:/data/levels/rdr3/trolleyCableTracks.xml"

static std::string g_overrideTrainTrackFilePath = "";
static std::string g_overrideTrolleyCableFilePath = "";

namespace streaming
{
// Sets a resource override for traintracks.xml and enables train track replacement.
void DLL_EXPORT SetTrainTrackFilePath(const std::string& path)
{
g_overrideTrainTrackFilePath = path;
}

// Sets a resource override for trolleyCableTracks.xml and enables trolley cable replacement.
void DLL_EXPORT SetTrolleyCableFilePath(const std::string& path)
{
g_overrideTrolleyCableFilePath = path;
}
}

typedef __int64 CTrainTrackPool; // Typedef for clarity on LoadTrackXML()'s parameters.

static void (*g_origLoadTrackXML)(const char*, CTrainTrackPool*);
static void LoadTrackXML(const char* origXmlFileName, CTrainTrackPool* dstPool)
{
if (!g_overrideTrainTrackFilePath.empty() && strcmp(origXmlFileName, DEFAULT_TRACK_FILE) == 0)
{
trace("Replacing default traintracks.xml with %s\n", g_overrideTrainTrackFilePath.data());
g_origLoadTrackXML(g_overrideTrainTrackFilePath.data(), dstPool);
}
else if (!g_overrideTrolleyCableFilePath.empty() && strcmp(origXmlFileName, DEFAULT_CABLES_FILE) == 0)
{
trace("Replacing default trolleyCableTracks.xml with %s\n", g_overrideTrolleyCableFilePath.data());
g_origLoadTrackXML(g_overrideTrolleyCableFilePath.data(), dstPool);
}
else
{
g_origLoadTrackXML(origXmlFileName, dstPool);
}
}

static HookFunction hookFunction([]()
{
{
auto location = hook::get_call(hook::get_pattern("E8 ? ? ? ? 48 8D 0D ? ? ? ? E8 ? ? ? ? EB 44"));
g_origLoadTrackXML = hook::trampoline(location, LoadTrackXML);
}

OnKillNetworkDone.Connect([]()
{
g_overrideTrainTrackFilePath.clear();
g_overrideTrolleyCableFilePath.clear();
});
});
Loading