Skip to content
Open
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
1 change: 1 addition & 0 deletions code/components/devtools-five/include/TimecycleEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class TimecycleEditor
char m_detailDropDownBuffer[kMaxBufferSize]{};

bool m_applySelectedTimecycle = false;
bool m_replaceInteriorTimecycle = true;
tinyxml2::XMLPrinter g_timecycleXmlOutput;

public:
Expand Down
69 changes: 54 additions & 15 deletions code/components/devtools-five/src/TimecycleEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ void TimecycleEditor::Draw()

if (auto scriptData = TimecycleManager::GetScriptData())
{
auto selected = m_selectedModifier.GetModifier();
int selectedIndex = selected ? TheTimecycleManager->GetTimecycleIndex(*selected) : -1;
int interiorIndex = m_replaceInteriorTimecycle ? selectedIndex : -1;

if (scriptData->m_primaryModifierIndex != -1)
{
auto modifier = TheTimecycleManager->GetTimecycleByIndex(scriptData->m_primaryModifierIndex);
Expand All @@ -233,6 +237,7 @@ void TimecycleEditor::Draw()
if (ImGui::Button("Clear"))
{
scriptData->m_primaryModifierIndex = -1;
m_applySelectedTimecycle = false;
}
}
else
Expand Down Expand Up @@ -286,16 +291,59 @@ void TimecycleEditor::Draw()

ImGui::Separator();

if (interiorIndex != -1)
{
auto modifier = TheTimecycleManager->GetTimecycleByIndex(interiorIndex);
auto tcName = modifier ? TheTimecycleManager->GetTimecycleName(*modifier).c_str() : "INVALID";
ImGui::Text("Interior modifier: %s", tcName);
}
else
{
ImGui::Text("Interior modifier: NONE");
}

ImGui::Separator();

if (ImGui::Checkbox("Apply selected", &m_applySelectedTimecycle))
{
if (m_applySelectedTimecycle)
{
if (auto modifier = m_selectedModifier.GetModifier())
{
scriptData->m_primaryModifierIndex = TheTimecycleManager->GetTimecycleIndex(*modifier);
}
m_replaceInteriorTimecycle = false;
}
else
{
scriptData->m_primaryModifierIndex = -1;
}
}

if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Applies the selected timecycle globally, the way a script would.\n"
"Inside an MLO this stacks on top of the interiors own timecycle.");
}

if (m_applySelectedTimecycle && selectedIndex != -1)
{
scriptData->m_primaryModifierIndex = selectedIndex;
}

if (ImGui::Checkbox("Replace interior timecycle", &m_replaceInteriorTimecycle))
{
if (m_replaceInteriorTimecycle)
{
m_applySelectedTimecycle = false;
scriptData->m_primaryModifierIndex = -1;
}
}

if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Makes the room you are standing in use the selected timecycle instead of its\n"
"own, so you see it on its own rather than stacked on the interiors.\n"
"Only does anything while you are inside an MLO.");
}

TheTimecycleManager->SetInteriorModifierOverride(m_replaceInteriorTimecycle ? selectedIndex : -1);
}

if (ImGui::BeginChild("list", ImVec2(-1.0f, -1.0f), false))
Expand Down Expand Up @@ -330,17 +378,6 @@ void TimecycleEditor::Draw()
TheTimecycleManager->EnsureTimecycleBackup(*modifier);
m_selectedModifier.SetModifier(modifier);
strcpy(m_detailNameBuffer, modifierName.c_str());

if (m_applySelectedTimecycle)
{
auto modifier = m_selectedModifier.GetModifier();
auto scriptData = TimecycleManager::GetScriptData();

if (scriptData != nullptr && modifier != nullptr)
{
scriptData->m_primaryModifierIndex = TheTimecycleManager->GetTimecycleIndex(*modifier);
}
}
}

ImGui::TreePop();
Expand Down Expand Up @@ -831,6 +868,8 @@ void TimecycleEditor::Reset()

m_editorEnabled = false;
m_applySelectedTimecycle = false;
m_replaceInteriorTimecycle = true;
TheTimecycleManager->SetInteriorModifierOverride(-1);
g_timecycleXmlOutput.ClearBuffer();
m_searchCache.clear();
}
Expand Down
3 changes: 3 additions & 0 deletions code/components/gta-game-five/include/Timecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ class GAME_COMPONENT_EXPORT TimecycleManager
{
private:
bool m_activateEditor; // hack...
int m_interiorModifierOverride = -1; // modifier the room the player is in should use instead of its own
std::map<uint32_t, std::string> m_originalNames; // names that were gathered from data files
std::map<uint32_t, std::string> m_customNames; // names of custom timecycles that were created in code
std::map<uint32_t, rage::tcModifier*> m_modifiersBackup; // backups of original modifiers
Expand Down Expand Up @@ -142,6 +143,8 @@ class GAME_COMPONENT_EXPORT TimecycleManager
void HandleTimecycleUnloaded(uint32_t hash);
void SetActivateEditor(bool flag);
bool ShouldActivateEditor();
void SetInteriorModifierOverride(int index);
int GetInteriorModifierOverride();

static rage::tcManager* GetGameManager(); // get pointer to instance of RAGE timecycle manager
static TimecycleScriptData* GetScriptData(); // get "script" data, seems to be struct that is used in natives
Expand Down
59 changes: 59 additions & 0 deletions code/components/gta-game-five/src/Timecycle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,16 @@ bool TimecycleManager::ShouldActivateEditor()
return m_activateEditor;
}

void TimecycleManager::SetInteriorModifierOverride(int index)
{
m_interiorModifierOverride = index;
}

int TimecycleManager::GetInteriorModifierOverride()
{
return m_interiorModifierOverride;
}

#if IS_RDR3
void TimecycleManager::StoreVarInfoName(const std::string& name)
{
Expand Down Expand Up @@ -761,6 +771,45 @@ static uint32_t TimecycleComputeHashLoad(int ns, char* name)
return hash;
}

#if GTA_FIVE
struct CPortalModifierData
{
float portalBoundSphere[4]; // rage::spdSphere
float strength;
int mainModifier;
int secondaryModifier;
float blendWeight;
};

struct CPortalModifierQueryResults
{
CPortalModifierData m_entries[20];
int m_count;
};

static void (*g_origFindModifiersForInteriors)(const void*, void*, uint32_t, CPortalModifierQueryResults*);
static void FindModifiersForInteriors(const void* viewport, void* interiorInst, uint32_t roomId, CPortalModifierQueryResults* results)
{
g_origFindModifiersForInteriors(viewport, interiorInst, roomId, results);

int index = TCManager.GetInteriorModifierOverride();
if (index < 0)
{
return;
}

for (int i = 0; i < results->m_count; i++)
{
// -1 entries are portals looking out of the interior, they should stay exterior
if (results->m_entries[i].mainModifier != -1)
{
results->m_entries[i].mainModifier = index;
results->m_entries[i].secondaryModifier = -1;
}
}
}
#endif

static uint32_t (*g_origTimecycleComputeHashUnload)(int, char*);
static uint32_t TimecycleComputeHashUnload(int ns, char* name)
{
Expand Down Expand Up @@ -792,6 +841,7 @@ static HookFunction hookFunction([]()
OnKillNetworkDone.Connect([=]()
{
TCManager.SetActivateEditor(false);
TCManager.SetInteriorModifierOverride(-1);
TCManager.RevertChanges();
});

Expand Down Expand Up @@ -854,6 +904,15 @@ static HookFunction hookFunction([]()
hook::call(location, TimecycleComputeHashUnload);
}

#if GTA_FIVE
{
auto location = hook::get_pattern("4C 8D 0D ? ? ? ? 44 8B ? 48 8B ? 48 8B ? E8 ? ? ? ? 8B 05", 16);

hook::set_call(&g_origFindModifiersForInteriors, location);
hook::call(location, FindModifiersForInteriors);
}
#endif

#if IS_RDR3
// RDR3 doesn't store variable names inside rage::tcVarInfo anymore, so hacking around to get bring names back.
static struct : jitasm::Frontend
Expand Down
Loading