mirror of
https://github.com/Milxnor/Project-Reboot-3.0.git
synced 2026-01-13 19:02:21 +01:00
disable rebooting again
fixed looting bug, fixed parachute not auto deploying on some builds
This commit is contained in:
@@ -35,6 +35,7 @@ void UAthenaMarkerComponent::ServerAddMapMarkerHook(UAthenaMarkerComponent* Mark
|
||||
MarkerData->GetMarkerType() = MarkerRequestPtr->GetMarkerType();
|
||||
MarkerData->GetOwner() = PlayerState;
|
||||
MarkerData->GetWorldNormal() = MarkerRequestPtr->GetWorldNormal();
|
||||
|
||||
if (WorldPositionOffset != -1)
|
||||
MarkerData->GetWorldPosition() = MarkerRequestPtr->GetWorldPosition();
|
||||
if (WorldPositionOffset != -1)
|
||||
@@ -54,30 +55,6 @@ void UAthenaMarkerComponent::ServerAddMapMarkerHook(UAthenaMarkerComponent* Mark
|
||||
((TSoftObjectPtr<UObject>*)(__int64(MarkerData->GetCustomDisplayInfo()) + IconOffset))->SoftObjectPtr.WeakPtr.ObjectSerialNumber = 0;
|
||||
*(FText*)(__int64(MarkerData->GetCustomDisplayInfo()) + DisplayNameOffset) = UKismetTextLibrary::Conv_StringToText(L"");
|
||||
|
||||
/* if (MarkerRequest.MarkedActor)
|
||||
{
|
||||
MarkerData.MarkedActor.WeakPtr.ObjectIndex = MarkerRequest.MarkedActor->InternalIndex;
|
||||
MarkerData.MarkedActor.WeakPtr.ObjectSerialNumber = 0;
|
||||
|
||||
MarkerData.MarkedActorClass.WeakPtr.ObjectIndex = MarkerRequest.MarkedActor->Class->InternalIndex;
|
||||
MarkerData.MarkedActorClass.WeakPtr.ObjectSerialNumber = 0;
|
||||
|
||||
char (*WtfSkidda)(UAthenaMarkerComponent * a1, AActor * a2, FFortWorldMarkerData & MarkerData) = decltype(WtfSkidda)(__int64(GetModuleHandleW(0)) + 0x1297E00);
|
||||
(int)WtfSkidda(PlayerController->MarkerComponent, MarkerRequest.MarkedActor, MarkerData);
|
||||
// std::cout << "WtfSkidda: " << (int)WtfSkidda(PlayerController->MarkerComponent, MarkerRequest.MarkedActor, MarkerData) << '\n';
|
||||
}
|
||||
|
||||
if (MarkerData.MarkerType == EFortWorldMarkerType::Item)
|
||||
{
|
||||
if (auto Pickup = Cast<AFortPickup>(MarkerRequest.MarkedActor))
|
||||
{
|
||||
MarkerData.ItemDefinition = Pickup->PrimaryPickupItemEntry.ItemDefinition;
|
||||
MarkerData.ItemCount = Pickup->PrimaryPickupItemEntry.Count;
|
||||
}
|
||||
} */
|
||||
|
||||
// static void (*Idk)(UAthenaMarkerComponent* MarkerComponent, FFortWorldMarkerData MarkerData) = decltype(Idk)(__int64(GetModuleHandleW(0)) + 0x12A8990);
|
||||
|
||||
static auto PlayerTeamOffset = PlayerState->GetOffset("PlayerTeam");
|
||||
auto PlayerTeam = PlayerState->Get<UObject*>(PlayerTeamOffset);
|
||||
|
||||
@@ -124,8 +101,8 @@ void UAthenaMarkerComponent::ServerAddMapMarkerHook(UAthenaMarkerComponent* Mark
|
||||
((FFastArraySerializerItem*)MarkerData)->ReplicationID = -1;
|
||||
((FFastArraySerializerItem*)MarkerData)->ReplicationKey = -1;
|
||||
|
||||
auto& Markers = *(TArray<FFortWorldMarkerData>*)(__int64(MarkerStream) + MarkersOffset);
|
||||
Markers.AddPtr(MarkerData, FFortWorldMarkerData::GetStructSize());
|
||||
auto Markers = (TArray<FFortWorldMarkerData>*)(__int64(MarkerStream) + MarkersOffset);
|
||||
Markers->AddPtr(MarkerData, FFortWorldMarkerData::GetStructSize());
|
||||
MarkerStream->MarkArrayDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ struct FFortWorldMarkerData
|
||||
{
|
||||
static UStruct* GetStruct()
|
||||
{
|
||||
static auto Struct = FindObject<UStruct>("/Script/FortniteGame.FortWorldMarkerData");
|
||||
static auto Struct = FindObject<UStruct>(L"/Script/FortniteGame.FortWorldMarkerData");
|
||||
return Struct;
|
||||
}
|
||||
|
||||
|
||||
55
Project Reboot 3.0/AthenaPlayerMatchReport.h
Normal file
55
Project Reboot 3.0/AthenaPlayerMatchReport.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include "reboot.h"
|
||||
|
||||
struct FAthenaMatchTeamStats
|
||||
{
|
||||
static UStruct* GetStruct()
|
||||
{
|
||||
static auto Struct = FindObject<UStruct>(L"/Script/FortniteGame.AthenaMatchTeamStats");
|
||||
return Struct;
|
||||
}
|
||||
|
||||
static auto GetStructSize() { return GetStruct()->GetPropertiesSize(); }
|
||||
|
||||
int Place; // 0x0000(0x0004) (Edit, BlueprintVisible, BlueprintReadOnly, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
int TotalPlayers; // 0x0004(0x0004) (Edit, BlueprintVisible, BlueprintReadOnly, ZeroConstructor, IsPlainOldData, NoDestructor, HasGetValueTypeHash, NativeAccessSpecifierPublic)
|
||||
|
||||
int& GetPlace()
|
||||
{
|
||||
return Place;
|
||||
}
|
||||
|
||||
int& GetTotalPlayers()
|
||||
{
|
||||
return TotalPlayers;
|
||||
}
|
||||
};
|
||||
|
||||
class UAthenaPlayerMatchReport : public UObject
|
||||
{
|
||||
public:
|
||||
bool& HasTeamStats()
|
||||
{
|
||||
static auto bHasTeamStatsOffset = GetOffset("bHasTeamStats");
|
||||
return Get<bool>(bHasTeamStatsOffset);
|
||||
}
|
||||
|
||||
bool& HasMatchStats()
|
||||
{
|
||||
static auto bHasMatchStatsOffset = GetOffset("bHasMatchStats");
|
||||
return Get<bool>(bHasMatchStatsOffset);
|
||||
}
|
||||
|
||||
FAthenaMatchTeamStats* GetTeamStats()
|
||||
{
|
||||
static auto TeamStatsOffset = GetOffset("TeamStats");
|
||||
return GetPtr<FAthenaMatchTeamStats>(TeamStatsOffset);
|
||||
}
|
||||
|
||||
static UClass* StaticClass()
|
||||
{
|
||||
static auto Class = FindObject<UClass>("/Script/FortniteGame.AthenaPlayerMatchReport");
|
||||
return Class;
|
||||
}
|
||||
};
|
||||
@@ -538,10 +538,18 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
|
||||
}
|
||||
|
||||
static auto bWorldIsReadyOffset = GameMode->GetOffset("bWorldIsReady");
|
||||
SetBitfield(GameMode->GetPtr<PlaceholderBitfield>(bWorldIsReadyOffset), 1, true); // idk when we actually set this (probably after we listen)
|
||||
SetBitfield(GameMode->GetPtr<PlaceholderBitfield>(bWorldIsReadyOffset), 1, true); // idk when we actually set this
|
||||
|
||||
// Calendar::SetSnow(1000);
|
||||
|
||||
static auto DefaultRebootMachineHotfixOffset = GameState->GetOffset("DefaultRebootMachineHotfix", false);
|
||||
|
||||
if (DefaultRebootMachineHotfixOffset != -1)
|
||||
{
|
||||
LOG_INFO(LogDev, "before: {}", GameState->Get<float>(DefaultRebootMachineHotfixOffset));
|
||||
GameState->Get<float>(DefaultRebootMachineHotfixOffset) = 1; // idk i dont think we need to set
|
||||
}
|
||||
|
||||
Globals::bInitializedPlaylist = true;
|
||||
}
|
||||
|
||||
@@ -790,12 +798,9 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
|
||||
|
||||
AllRebootVans.Free();
|
||||
|
||||
static auto DefaultRebootMachineHotfixOffset = GameState->GetOffset("DefaultRebootMachineHotfix", false);
|
||||
|
||||
if (DefaultRebootMachineHotfixOffset != -1)
|
||||
if (Engine_Version >= 500)
|
||||
{
|
||||
// LOG_INFO(LogDev, "Beraau: {}", GameState->Get<float>(DefaultRebootMachineHotfixOffset));
|
||||
GameState->Get<float>(DefaultRebootMachineHotfixOffset) = 1; // idk i dont think we need to set
|
||||
GameState->Get<float>("DefaultParachuteDeployTraceForGroundDistance") = 10000;
|
||||
}
|
||||
|
||||
if (AmountOfBotsToSpawn != 0)
|
||||
@@ -1294,6 +1299,8 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
|
||||
}
|
||||
}
|
||||
|
||||
NewPlayer->GetMatchReport() = (UAthenaPlayerMatchReport*)UGameplayStatics::SpawnObject(UAthenaPlayerMatchReport::StaticClass(), NewPlayer); // idk when to do this
|
||||
|
||||
static auto SquadIdOffset = PlayerStateAthena->GetOffset("SquadId", false);
|
||||
|
||||
if (SquadIdOffset != -1)
|
||||
|
||||
@@ -6,12 +6,25 @@
|
||||
#include "OnlineReplStructs.h"
|
||||
#include "gui.h"
|
||||
|
||||
uint8 AFortGameSessionDedicatedAthena::GetSquadIdForCurrentPlayerHook(AFortGameSessionDedicatedAthena* GameSessionDedicated, __int64 UniqueId)
|
||||
uint8 AFortGameSessionDedicatedAthena::GetSquadIdForCurrentPlayerHook(AFortGameSessionDedicatedAthena* GameSessionDedicated, void* UniqueId)
|
||||
{
|
||||
LOG_INFO(LogDev, "GetSquadIdForCurrentPlayerHook!");
|
||||
|
||||
TArray<AActor*> CONTRTOLLERS = UGameplayStatics::GetAllActorsOfClass(GetWorld(), AFortPlayerControllerAthena::StaticClass());
|
||||
|
||||
auto OwnerUniqueId = (FUniqueNetIdRepl*)UniqueId;
|
||||
|
||||
LOG_INFO(LogDev, "OwnerUniqueId->GetReplicationBytes().Num(): {}", OwnerUniqueId->GetReplicationBytes().Num());
|
||||
|
||||
/*
|
||||
|
||||
for (int i = 0; i < OwnerUniqueId->GetReplicationBytes().Num(); i++)
|
||||
{
|
||||
LOG_INFO(LogDev, "[{}] Byte: 0x{:x}", i, OwnerUniqueId->GetReplicationBytes().at(i));
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
for (int i = 0; i < CONTRTOLLERS.Num(); i++)
|
||||
{
|
||||
auto Controller = (AFortPlayerControllerAthena*)CONTRTOLLERS.at(i);
|
||||
@@ -24,12 +37,14 @@ uint8 AFortGameSessionDedicatedAthena::GetSquadIdForCurrentPlayerHook(AFortGameS
|
||||
|
||||
static auto UniqueIdOffset = PlayerState->GetOffset("UniqueId");
|
||||
|
||||
if (IsBadReadPtr(PlayerState->GetPtr<FUniqueNetIdRepl>(UniqueIdOffset)))
|
||||
continue;
|
||||
// if (IsBadReadPtr(PlayerState->GetPtr<FUniqueNetIdRepl>(UniqueIdOffset)))
|
||||
// continue;
|
||||
|
||||
if (PlayerState->GetPtr<FUniqueNetIdRepl>(UniqueIdOffset)->IsIdentical((FUniqueNetIdRepl*)&UniqueId))
|
||||
LOG_INFO(LogDev, "PS PlayerState->GetPtr<FUniqueNetIdRepl>(UniqueIdOffset)->GetReplicationBytes().Num(): {}", PlayerState->GetPtr<FUniqueNetIdRepl>(UniqueIdOffset)->GetReplicationBytes().Num());
|
||||
|
||||
if (PlayerState->GetPtr<FUniqueNetIdRepl>(UniqueIdOffset)->IsIdentical(OwnerUniqueId))
|
||||
{
|
||||
LOG_INFO(LogDev, "Found!");
|
||||
LOG_INFO(LogDev, "Found {}!", PlayerState->GetPlayerName().ToString());
|
||||
return PlayerState->GetTeamIndex() - NumToSubtractFromSquadId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
class AFortGameSessionDedicatedAthena : public AActor
|
||||
{
|
||||
public:
|
||||
static uint8 GetSquadIdForCurrentPlayerHook(AFortGameSessionDedicatedAthena* GameSessionDedicated, __int64 UniqueId);
|
||||
static uint8 GetSquadIdForCurrentPlayerHook(AFortGameSessionDedicatedAthena* GameSessionDedicated, void* UniqueId);
|
||||
};
|
||||
@@ -294,8 +294,8 @@ void AFortGameStateAthena::OnRep_PlayersLeft()
|
||||
|
||||
TeamsArrayContainer* AFortGameStateAthena::GetTeamsArrayContainer()
|
||||
{
|
||||
// if (!bEnableRebooting) // todo (milxnor) remove when safer
|
||||
// return nullptr;
|
||||
if (true)
|
||||
return nullptr;
|
||||
|
||||
if (Fortnite_Version < 8.0) // I'm pretty sure it got added on 7.40 but idk if it is structured differently.
|
||||
return nullptr;
|
||||
|
||||
@@ -154,7 +154,7 @@ float GetAmountOfLootPackagesToDrop(FFortLootTierData* LootTierData, int Origina
|
||||
FFortLootTierData* PickLootTierData(const std::vector<UDataTable*>& LTDTables, FName LootTierGroup, int ForcedLootTier = -1, FName* OutRowName = nullptr) // Fortnite returns the row name and then finds the tier data again, but I really don't see the point of this.
|
||||
{
|
||||
float LootTier = ForcedLootTier;
|
||||
float IdkForcedWeightorsomething = 1;
|
||||
float IdkForcedWeightorsomething = -1;
|
||||
|
||||
if (LootTier == -1)
|
||||
{
|
||||
|
||||
@@ -1436,27 +1436,60 @@ void AFortPlayerController::ClientOnPawnDiedHook(AFortPlayerController* PlayerCo
|
||||
UFortWeaponItemDefinition* KillerWeaponDef = nullptr;
|
||||
|
||||
static auto FortProjectileBaseClass = FindObject<UClass>(L"/Script/FortniteGame.FortProjectileBase");
|
||||
LOG_INFO(LogDev, "FortProjectileBaseClass: {}", __int64(FortProjectileBaseClass));
|
||||
|
||||
if (DamageCauser)
|
||||
{
|
||||
if (DamageCauser->IsA(FortProjectileBaseClass))
|
||||
{
|
||||
// LOG_INFO(LogDev, "From a projectile!");
|
||||
auto Owner = Cast<AFortWeapon>(DamageCauser->GetOwner());
|
||||
KillerWeaponDef = Owner->IsValidLowLevel() ? Owner->GetWeaponData() : nullptr; // I just added the IsValidLowLevel check because what if the weapon destroys?
|
||||
}
|
||||
if (auto Weapon = Cast<AFortWeapon>(DamageCauser))
|
||||
{
|
||||
// LOG_INFO(LogDev, "From a weapon!");
|
||||
KillerWeaponDef = Weapon->GetWeaponData();
|
||||
}
|
||||
}
|
||||
|
||||
// LOG_INFO(LogDev, "KillerWeaponDef: {}", KillerWeaponDef ? KillerWeaponDef->GetFullName() : "InvalidObject");
|
||||
|
||||
RemoveFromAlivePlayers(GameMode, PlayerController, KillerPlayerState == DeadPlayerState ? nullptr : KillerPlayerState, KillerPawn, KillerWeaponDef, DeathCause, 0);
|
||||
|
||||
/*
|
||||
|
||||
STATS:
|
||||
|
||||
Note: This isn't the exact order relative to other functions.
|
||||
|
||||
ClientSendMatchStatsForPlayer
|
||||
ClientSendTeamStatsForPlayer
|
||||
ClientSendEndBattleRoyaleMatchForPlayer
|
||||
|
||||
*/
|
||||
|
||||
// FAthenaMatchStats.Stats[ERewardSource] // hmm
|
||||
|
||||
/*
|
||||
|
||||
// We need to check if their entire team is dead then I think we send it????
|
||||
|
||||
auto DeadControllerAthena = Cast<AFortPlayerControllerAthena>(PlayerController);
|
||||
|
||||
if (DeadControllerAthena && FAthenaMatchTeamStats::GetStruct())
|
||||
{
|
||||
auto MatchReport = DeadControllerAthena->GetMatchReport();
|
||||
|
||||
LOG_INFO(LogDev, "MatchReport: {}", __int64(MatchReport));
|
||||
|
||||
if (MatchReport)
|
||||
{
|
||||
MatchReport->GetTeamStats()->GetPlace() = DeadPlayerState->GetPlace();
|
||||
MatchReport->GetTeamStats()->GetTotalPlayers() = AmountOfPlayersWhenBusStart; // hmm
|
||||
MatchReport->HasTeamStats() = true;
|
||||
|
||||
DeadControllerAthena->ClientSendTeamStatsForPlayer(MatchReport->GetTeamStats());
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
LOG_INFO(LogDev, "Removed!");
|
||||
|
||||
if (Fortnite_Version < 6) // Spectating
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "FortKismetLibrary.h"
|
||||
#include "AthenaMarkerComponent.h"
|
||||
#include "FortVolume.h"
|
||||
#include "AthenaPlayerMatchReport.h"
|
||||
|
||||
static void ApplyHID(AFortPlayerPawn* Pawn, UObject* HeroDefinition, bool bUseServerChoosePart = false)
|
||||
{
|
||||
@@ -191,6 +192,25 @@ public:
|
||||
this->ProcessEvent(ClientClearDeathNotificationFn);
|
||||
}
|
||||
|
||||
UAthenaPlayerMatchReport*& GetMatchReport()
|
||||
{
|
||||
static auto MatchReportOffset = GetOffset("MatchReport");
|
||||
return Get<UAthenaPlayerMatchReport*>(MatchReportOffset);
|
||||
}
|
||||
|
||||
void ClientSendTeamStatsForPlayer(FAthenaMatchTeamStats* TeamStats)
|
||||
{
|
||||
static auto ClientSendTeamStatsForPlayerFn = FindObject<UFunction>("/Script/FortniteGame.FortPlayerControllerAthena.ClientSendTeamStatsForPlayer");
|
||||
static auto ParamSize = ClientSendTeamStatsForPlayerFn->GetPropertiesSize();
|
||||
auto Params = malloc(ParamSize);
|
||||
|
||||
memcpy_s(Params, ParamSize, TeamStats, TeamStats->GetStructSize());
|
||||
|
||||
this->ProcessEvent(ClientSendTeamStatsForPlayerFn, Params);
|
||||
|
||||
free(Params);
|
||||
}
|
||||
|
||||
void RespawnPlayerAfterDeath(bool bEnterSkydiving)
|
||||
{
|
||||
static auto RespawnPlayerAfterDeathFn = FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerControllerAthena.RespawnPlayerAfterDeath");
|
||||
|
||||
@@ -24,31 +24,13 @@ struct FUniqueNetIdRepl // : public FUniqueNetIdWrapper
|
||||
return *(TArray<uint8>*)(__int64(this) + ReplicationBytesOffset);
|
||||
}
|
||||
|
||||
bool IsIdentical(FUniqueNetIdRepl* OtherUniqueId)
|
||||
FORCEINLINE int GetSize() { return GetReplicationBytes().Num(); } // LITERLALY IDK IF THIS IS RIGHT CUZ I CANT FIND IMPL
|
||||
FORCEINLINE uint8* GetBytes() { return GetReplicationBytes().Data; } // ^^^
|
||||
|
||||
FORCENOINLINE bool IsIdentical(FUniqueNetIdRepl* OtherUniqueId)
|
||||
{
|
||||
// idk if this is right but whatever
|
||||
|
||||
bool bTest = true;
|
||||
|
||||
if (this->GetReplicationBytes().Num() >= OtherUniqueId->GetReplicationBytes().Num())
|
||||
{
|
||||
for (int i = 0; i < this->GetReplicationBytes().Num(); i++)
|
||||
{
|
||||
if (this->GetReplicationBytes().at(i) != OtherUniqueId->GetReplicationBytes().at(i))
|
||||
{
|
||||
bTest = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bTest = false;
|
||||
}
|
||||
|
||||
// LOG_INFO(LogDev, "btest: {}", bTest);
|
||||
|
||||
return bTest;
|
||||
return (GetSize() == OtherUniqueId->GetSize()) &&
|
||||
(memcmp(GetBytes(), OtherUniqueId->GetBytes(), GetSize()) == 0);
|
||||
}
|
||||
|
||||
void CopyFromAnotherUniqueId(FUniqueNetIdRepl* OtherUniqueId)
|
||||
|
||||
@@ -11,4 +11,10 @@ public:
|
||||
static auto PlayerControllerOffset = GetOffset("PlayerController");
|
||||
return Get<APlayerController*>(PlayerControllerOffset);
|
||||
}
|
||||
|
||||
int& GetCurrentNetSpeed()
|
||||
{
|
||||
static auto CurrentNetSpeedOffset = GetOffset("CurrentNetSpeed");
|
||||
return Get<int>(CurrentNetSpeedOffset);
|
||||
}
|
||||
};
|
||||
@@ -16,6 +16,12 @@ public:
|
||||
return this->Get<UCheatManager*>(CheatManagerOffset);
|
||||
}
|
||||
|
||||
class UNetConnection*& GetNetConnection()
|
||||
{
|
||||
static auto NetConnectionOffset = GetOffset("NetConnection");
|
||||
return Get<class UNetConnection*>(NetConnectionOffset);
|
||||
}
|
||||
|
||||
void SetPlayerIsWaiting(bool NewValue);
|
||||
void ServerChangeName(FString& S);
|
||||
UCheatManager*& SpawnCheatManager(UClass* CheatManagerClass);
|
||||
|
||||
@@ -253,6 +253,7 @@
|
||||
<ClCompile Include="NetDriver.cpp" />
|
||||
<ClCompile Include="NetworkObjectList.cpp" />
|
||||
<ClCompile Include="Object.cpp" />
|
||||
<ClCompile Include="objectviewer.cpp" />
|
||||
<ClCompile Include="PlayerController.cpp" />
|
||||
<ClCompile Include="PlayerState.cpp" />
|
||||
<ClCompile Include="reboot.cpp" />
|
||||
@@ -279,6 +280,7 @@
|
||||
<ClInclude Include="AthenaBarrierObjective.h" />
|
||||
<ClInclude Include="AthenaBigBaseWall.h" />
|
||||
<ClInclude Include="AthenaMarkerComponent.h" />
|
||||
<ClInclude Include="AthenaPlayerMatchReport.h" />
|
||||
<ClInclude Include="AthenaResurrectionComponent.h" />
|
||||
<ClInclude Include="AttributeSet.h" />
|
||||
<ClInclude Include="BGA.h" />
|
||||
|
||||
@@ -295,6 +295,9 @@
|
||||
<ClCompile Include="finder.cpp">
|
||||
<Filter>Reboot\Private</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="objectviewer.cpp">
|
||||
<Filter>Reboot\Private</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="log.h" />
|
||||
@@ -945,6 +948,9 @@
|
||||
<ClInclude Include="objectviewer.h">
|
||||
<Filter>Reboot\Public</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AthenaPlayerMatchReport.h">
|
||||
<Filter>FortniteGame\Source\FortniteGame\Public\Stats</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Engine">
|
||||
@@ -1211,6 +1217,9 @@
|
||||
<Filter Include="FortniteGame\Source\FortniteGame\Private\Vehicle">
|
||||
<UniqueIdentifier>{702a4ab1-e5e1-46e1-b8cd-2fab1c4fb48c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="FortniteGame\Source\FortniteGame\Public\Stats">
|
||||
<UniqueIdentifier>{3c8e3f87-8a4c-4220-b952-39b0e0315e85}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="UnrealEngine.cpp">
|
||||
|
||||
@@ -489,6 +489,7 @@ void Offsets::Print()
|
||||
LOG_INFO(LogDev, "ServerReplicateActors: 0x{:x}", ServerReplicateActors);
|
||||
LOG_INFO(LogDev, "ReplicationFrame: 0x{:x}", ReplicationFrame);
|
||||
LOG_INFO(LogDev, "Script: 0x{:x}", Script);
|
||||
LOG_INFO(LogDev, "PropertyClass: 0x{:x}", PropertyClass);
|
||||
}
|
||||
|
||||
void Addresses::Init()
|
||||
|
||||
@@ -97,6 +97,7 @@ namespace Offsets
|
||||
extern inline uint64 NetworkObjectList = 0;
|
||||
extern inline uint64 ClientWorldPackageName = 0;
|
||||
extern inline uint64 Script = 0;
|
||||
extern inline uint64 PropertyClass = 0;
|
||||
|
||||
void FindAll();
|
||||
void Print();
|
||||
|
||||
@@ -16,41 +16,42 @@ static inline void SetZoneToIndexHook(AFortGameModeAthena* GameModeAthena, int O
|
||||
: std::floor(Fortnite_Version) >= 18 ? 0x248
|
||||
: 0x1F8; // S13-S14
|
||||
|
||||
LOG_INFO(LogDev, "SetZoneToIndexHook!");
|
||||
static auto GameMode_SafeZonePhaseOffset = GameModeAthena->GetOffset("SafeZonePhase");
|
||||
LOG_INFO(LogDev, "Old SafeZonePhase: {}", GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset));
|
||||
|
||||
auto GameState = Cast<AFortGameStateAthena>(GameModeAthena->GetGameState());
|
||||
|
||||
if (!GameState)
|
||||
return SetZoneToIndexOriginal(GameModeAthena, OverridePhaseMaybeIDFK);
|
||||
|
||||
LOG_INFO(LogDev, "GamePhaseStep: {}", (int)GameState->GetGamePhaseStep());
|
||||
|
||||
if (Globals::bLateGame)
|
||||
if (false)
|
||||
{
|
||||
static auto GameMode_SafeZonePhaseOffset = GameModeAthena->GetOffset("SafeZonePhase");
|
||||
static auto GameState_SafeZonePhaseOffset = GameState->GetOffset("SafeZonePhase");
|
||||
|
||||
static int ahaaSafeZonePhase = 4;
|
||||
int NewSafeZonePhase = ahaaSafeZonePhase; // GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset);
|
||||
|
||||
const int OriginalOldSafeZonePhase = GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset);
|
||||
|
||||
if (NewSafeZonePhase < 4)
|
||||
if (Globals::bLateGame)
|
||||
{
|
||||
NewSafeZonePhase = 4;
|
||||
static auto GameMode_SafeZonePhaseOffset = GameModeAthena->GetOffset("SafeZonePhase");
|
||||
static auto GameState_SafeZonePhaseOffset = GameState->GetOffset("SafeZonePhase");
|
||||
|
||||
static int ahaaSafeZonePhase = 4;
|
||||
int NewSafeZonePhase = ahaaSafeZonePhase; // GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset);
|
||||
|
||||
const int OriginalOldSafeZonePhase = GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset);
|
||||
|
||||
if (NewSafeZonePhase < 4)
|
||||
{
|
||||
NewSafeZonePhase = 4;
|
||||
}
|
||||
|
||||
LOG_INFO(LogDev, "Setting zone to: {} ({})", NewSafeZonePhase, OriginalOldSafeZonePhase);
|
||||
|
||||
GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset) = NewSafeZonePhase;
|
||||
GameState->Get<int>(GameState_SafeZonePhaseOffset) = NewSafeZonePhase;
|
||||
ahaaSafeZonePhase++;
|
||||
}
|
||||
|
||||
LOG_INFO(LogDev, "Setting zone to: {} ({})", NewSafeZonePhase, OriginalOldSafeZonePhase);
|
||||
|
||||
GameModeAthena->Get<int>(GameMode_SafeZonePhaseOffset) = NewSafeZonePhase;
|
||||
GameState->Get<int>(GameState_SafeZonePhaseOffset) = NewSafeZonePhase;
|
||||
ahaaSafeZonePhase++;
|
||||
}
|
||||
|
||||
if (Fortnite_Version < 13)
|
||||
{
|
||||
SetZoneToIndexOriginal(GameModeAthena, OverridePhaseMaybeIDFK);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GameState)
|
||||
return SetZoneToIndexOriginal(GameModeAthena, OverridePhaseMaybeIDFK);
|
||||
|
||||
static auto SafeZoneIndicatorOffset = GameModeAthena->GetOffset("SafeZoneIndicator");
|
||||
|
||||
@@ -378,7 +378,7 @@ DWORD WINAPI Main(LPVOID)
|
||||
Addresses::Init();
|
||||
Addresses::Print();
|
||||
|
||||
bEnableRebooting = Addresses::RebootingDelegate && Addresses::FinishResurrection;
|
||||
bEnableRebooting = Addresses::RebootingDelegate && Addresses::FinishResurrection && Addresses::GetSquadIdForCurrentPlayer && false;
|
||||
|
||||
LOG_INFO(LogDev, "Fortnite_CL: {}", Fortnite_CL);
|
||||
LOG_INFO(LogDev, "Fortnite_Version: {}", Fortnite_Version);
|
||||
|
||||
@@ -199,7 +199,7 @@ static inline uint64 FindFinishResurrection()
|
||||
|
||||
static inline uint64 FindGetSquadIdForCurrentPlayer()
|
||||
{
|
||||
auto Addrr = Memcury::Scanner::FindStringRef(L"GetSquadIdForCurrentPlayer failed to find a squad id for player %s").Get();
|
||||
auto Addrr = Memcury::Scanner::FindStringRef(L"GetSquadIdForCurrentPlayer failed to find a squad id for player %s", true, 0, Fortnite_Version >= 19).Get();
|
||||
|
||||
if (!Addrr)
|
||||
return 0;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <fstream>
|
||||
#include <olectl.h>
|
||||
|
||||
#include "objectviewer.h"
|
||||
#include "FortAthenaMutator_Disco.h"
|
||||
#include "globals.h"
|
||||
#include "Fonts/ruda-bold.h"
|
||||
@@ -62,6 +63,7 @@
|
||||
#define LOADOUT_PLAYERTAB 4
|
||||
#define FUN_PLAYERTAB 5
|
||||
|
||||
extern inline int AmountOfPlayersWhenBusStart = 0;
|
||||
extern inline bool bHandleDeath = true;
|
||||
extern inline bool bUseCustomMap = false;
|
||||
extern inline std::string CustomMapName = "";
|
||||
@@ -514,6 +516,23 @@ static inline void MainUI()
|
||||
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), cmd, nullptr);
|
||||
}
|
||||
|
||||
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
|
||||
|
||||
if (GameState)
|
||||
{
|
||||
static auto DefaultGliderRedeployCanRedeployOffset = FindOffsetStruct("/Script/FortniteGame.FortGameStateAthena", "DefaultGliderRedeployCanRedeploy");
|
||||
|
||||
if (DefaultGliderRedeployCanRedeployOffset != -1)
|
||||
{
|
||||
bool EnableGliderRedeploy = (bool)GameState->Get<float>(DefaultGliderRedeployCanRedeployOffset);
|
||||
|
||||
if (ImGui::Checkbox("Enable Glider Redeploy", &EnableGliderRedeploy))
|
||||
{
|
||||
GameState->Get<float>(DefaultGliderRedeployCanRedeployOffset) = EnableGliderRedeploy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if (ImGui::Button("Spawn BGAs"))
|
||||
{
|
||||
SpawnBGAs();
|
||||
@@ -615,7 +634,9 @@ static inline void MainUI()
|
||||
bStartedBus = true;
|
||||
|
||||
auto GameMode = (AFortGameModeAthena*)GetWorld()->GetGameMode();
|
||||
auto GameState = GameMode->GetGameState();
|
||||
auto GameState = Cast<AFortGameStateAthena>(GameMode->GetGameState());
|
||||
|
||||
AmountOfPlayersWhenBusStart = GameState->GetPlayersLeft();
|
||||
|
||||
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), L"startaircraft", nullptr);
|
||||
|
||||
@@ -846,7 +867,9 @@ static inline void MainUI()
|
||||
bStartedBus = true;
|
||||
|
||||
auto GameMode = (AFortGameMode*)GetWorld()->GetGameMode();
|
||||
auto GameState = GameMode->GetGameState();
|
||||
auto GameState = Cast<AFortGameStateAthena>(GameMode->GetGameState());
|
||||
|
||||
AmountOfPlayersWhenBusStart = GameState->GetPlayersLeft(); // scuffed!!!!
|
||||
|
||||
if (Fortnite_Version == 1.11)
|
||||
{
|
||||
@@ -1159,14 +1182,20 @@ static inline void MainUI()
|
||||
{
|
||||
static std::string ClassNameToDump;
|
||||
static std::string FunctionNameToDump;
|
||||
static std::string ObjectToDump;
|
||||
static std::string FileNameToSaveTo;
|
||||
static bool bExcludeUnhandled = true;
|
||||
|
||||
ImGui::Checkbox("Handle Death", &bHandleDeath);
|
||||
ImGui::Checkbox("Fill Vending Machines", &Globals::bFillVendingMachines);
|
||||
ImGui::Checkbox("Enable Bot Tick", &bEnableBotTick);
|
||||
ImGui::Checkbox("Enable Rebooting", &bEnableRebooting);
|
||||
ImGui::Checkbox("Enable Combine Pickup", &bEnableCombinePickup);
|
||||
ImGui::Checkbox("Exclude unhandled", &bExcludeUnhandled);
|
||||
ImGui::InputInt("Amount To Subtract Index", &AmountToSubtractIndex);
|
||||
ImGui::InputText("Class Name to mess with", &ClassNameToDump);
|
||||
ImGui::InputText("Object to dump", &ObjectToDump);
|
||||
ImGui::InputText("File to save to", &FileNameToSaveTo);
|
||||
|
||||
ImGui::InputText("Function Name to mess with", &FunctionNameToDump);
|
||||
|
||||
@@ -1180,6 +1209,42 @@ static inline void MainUI()
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Dump Object Info"))
|
||||
{
|
||||
ObjectViewer::DumpContentsToFile(ObjectToDump, FileNameToSaveTo, bExcludeUnhandled);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Print all instances of class"))
|
||||
{
|
||||
auto ClassToScuff = FindObject<UClass>(ClassNameToDump);
|
||||
|
||||
if (ClassToScuff)
|
||||
{
|
||||
auto ObjectNum = ChunkedObjects ? ChunkedObjects->Num() : UnchunkedObjects ? UnchunkedObjects->Num() : 0;
|
||||
|
||||
for (int i = 0; i < ObjectNum; i++)
|
||||
{
|
||||
auto CurrentObject = GetObjectByIndex(i);
|
||||
|
||||
if (!CurrentObject)
|
||||
continue;
|
||||
|
||||
if (!CurrentObject->IsA(ClassToScuff))
|
||||
continue;
|
||||
|
||||
LOG_INFO(LogDev, "Object Name: {}", CurrentObject->GetPathName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui::Button("Load BGA Class"))
|
||||
{
|
||||
static auto BlueprintGeneratedClassClass = FindObject<UClass>(L"/Script/Engine.BlueprintGeneratedClass");
|
||||
auto Class = LoadObject(ClassNameToDump, BlueprintGeneratedClassClass);
|
||||
|
||||
LOG_INFO(LogDev, "New Class: {}", __int64(Class));
|
||||
}
|
||||
|
||||
if (ImGui::Button("Find all classes that inherit"))
|
||||
{
|
||||
auto ClassToScuff = FindObject<UClass>(ClassNameToDump);
|
||||
|
||||
@@ -86,6 +86,7 @@ inline void InitLogger()
|
||||
MakeLogger("LogCosmetics");
|
||||
MakeLogger("LogMatchmaker");
|
||||
MakeLogger("LogRebooting");
|
||||
MakeLogger("LogObjectViewer");
|
||||
}
|
||||
|
||||
#define LOG_DEBUG(loggerName, ...) \
|
||||
|
||||
175
Project Reboot 3.0/objectviewer.cpp
Normal file
175
Project Reboot 3.0/objectviewer.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "objectviewer.h"
|
||||
|
||||
void ObjectViewer::DumpContentsToFile(UObject* Object, const std::string& FileName, bool bExcludeUnhandled)
|
||||
{
|
||||
if (!Object->IsValidLowLevel())
|
||||
{
|
||||
LOG_ERROR(LogObjectViewer, "Invalid object passed into DumpContentsToFile!");
|
||||
return;
|
||||
}
|
||||
|
||||
static auto ClassClass = FindObject<UClass>(L"/Script/CoreUObject.Class");
|
||||
|
||||
if (Object->IsA(ClassClass))
|
||||
{
|
||||
LOG_ERROR(LogObjectViewer, "Object passed into DumpContentsToFile was a class!");
|
||||
return;
|
||||
}
|
||||
|
||||
static auto BytePropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ByteProperty");
|
||||
static auto ObjectPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ObjectProperty");
|
||||
static auto ClassPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ClassProperty");
|
||||
static auto DoublePropertyClass = FindObject<UClass>(L"/Script/CoreUObject.DoubleProperty");
|
||||
static auto FloatPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.FloatProperty");
|
||||
static auto Int8PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.Int8Property");
|
||||
static auto EnumPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.EnumProperty");
|
||||
static auto ArrayPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.ArrayProperty");
|
||||
static auto Int64PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.Int64Property");
|
||||
static auto UInt16PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.UInt16Property");
|
||||
static auto BoolPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.BoolProperty");
|
||||
static auto NamePropertyClass = FindObject<UClass>(L"/Script/CoreUObject.NameProperty");
|
||||
static auto UInt32PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.UInt32Property");
|
||||
static auto FunctionClass = FindObject<UClass>(L"/Script/CoreUObject.Function");
|
||||
static auto IntPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.IntProperty");
|
||||
static auto UInt64PropertyClass = FindObject<UClass>(L"/Script/CoreUObject.UInt64Property");
|
||||
static auto StrPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.StrProperty");
|
||||
static auto SoftObjectPropertyClass = FindObject<UClass>(L"/Script/CoreUObject.SoftObjectProperty");
|
||||
|
||||
std::ofstream Stream(FileName);
|
||||
|
||||
if (!FileName.empty() && !Stream.is_open())
|
||||
{
|
||||
LOG_ERROR(LogObjectViewer, "Failed to open file {}!", FileName);
|
||||
return;
|
||||
}
|
||||
|
||||
auto log = [&](const std::string& str) {
|
||||
if (FileName.empty())
|
||||
{
|
||||
LOG_INFO(LogObjectViewer, "{}", str);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream << str;
|
||||
}
|
||||
};
|
||||
|
||||
for (auto CurrentClass = Object->ClassPrivate; CurrentClass; CurrentClass = (UClass*)CurrentClass->GetSuperStruct())
|
||||
{
|
||||
void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children);
|
||||
|
||||
while (Property)
|
||||
{
|
||||
std::string PropertyName = GetFNameOfProp(Property)->ToString();
|
||||
int Offset = *(int*)(__int64(Property) + Offsets::Offset_Internal);
|
||||
|
||||
// log(std::format("Handling prop {}\n", PropertyName));
|
||||
|
||||
if (Offsets::PropertyClass)
|
||||
{
|
||||
if (IsPropertyA(Property, ObjectPropertyClass))
|
||||
{
|
||||
auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass);
|
||||
|
||||
if (PropertyClass->IsValidLowLevel())
|
||||
log(std::format("{} Object: {}\n", PropertyName, PropertyClass->GetPathName()));
|
||||
}
|
||||
|
||||
/*
|
||||
else if (IsPropertyA(Property, SoftObjectPropertyClass))
|
||||
{
|
||||
auto PropertyClass = *(UClass**)(__int64(Property) + Offsets::PropertyClass);
|
||||
|
||||
if (PropertyClass->IsValidLowLevel())
|
||||
{
|
||||
auto SoftObjectPtr = *(TSoftObjectPtr<UObject>*)(__int64(Object) + Offset);
|
||||
auto SoftObjectPtrObject = SoftObjectPtr.Get(PropertyClass);
|
||||
log(std::format("{} SoftObjectPtr (type: {}): {}\n", PropertyName, PropertyClass->GetName(), SoftObjectPtrObject ? SoftObjectPtrObject->GetPathName() : "BadRead"));
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (IsPropertyA(Property, BytePropertyClass))
|
||||
{
|
||||
log(std::format("uint8 {} = {}\n", PropertyName, *(uint8*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, DoublePropertyClass))
|
||||
{
|
||||
log(std::format("double {} = {}\n", PropertyName, *(double*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, UInt16PropertyClass))
|
||||
{
|
||||
log(std::format("uint16 {} = {}\n", PropertyName, *(uint16*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, Int8PropertyClass))
|
||||
{
|
||||
log(std::format("int8 {} = {}\n", PropertyName, *(int8*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, NamePropertyClass))
|
||||
{
|
||||
log(std::format("FName {} = {}\n", PropertyName, (*(FName*)(__int64(Object) + Offset)).ToString()));
|
||||
}
|
||||
else if (IsPropertyA(Property, StrPropertyClass))
|
||||
{
|
||||
auto string = (FString*)(__int64(Object) + Offset);
|
||||
|
||||
log(std::format("FString {} = {}\n", PropertyName, string->Data.Data ? string->ToString() : ""));
|
||||
}
|
||||
else if (IsPropertyA(Property, FloatPropertyClass))
|
||||
{
|
||||
log(std::format("float {} = {}\n", PropertyName, *(float*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, BoolPropertyClass))
|
||||
{
|
||||
auto FieldMask = GetFieldMask(Property);
|
||||
|
||||
log(std::format("bool {} = {}\n", PropertyName, ReadBitfield((PlaceholderBitfield*)(__int64(Object) + Offset), FieldMask)));
|
||||
}
|
||||
else if (IsPropertyA(Property, IntPropertyClass))
|
||||
{
|
||||
log(std::format("int32 {} = {}\n", PropertyName, *(int*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, UInt32PropertyClass))
|
||||
{
|
||||
log(std::format("uint32 {} = {}\n", PropertyName, *(uint32*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, UInt64PropertyClass))
|
||||
{
|
||||
log(std::format("uint64 {} = {}\n", PropertyName, *(uint64*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, Int64PropertyClass))
|
||||
{
|
||||
log(std::format("int64 {} = {}\n", PropertyName, *(int64*)(__int64(Object) + Offset)));
|
||||
}
|
||||
else if (IsPropertyA(Property, ArrayPropertyClass))
|
||||
{
|
||||
log(std::format("{} Array\n", PropertyName));
|
||||
}
|
||||
/*
|
||||
else if (IsPropertyA(Property, EnumPropertyClass))
|
||||
{
|
||||
using UNumericProperty = UObject;
|
||||
|
||||
auto EnumValueIg = *(uint8*)(__int64(Property) + Offset);
|
||||
auto UnderlyingType = *(UNumericProperty**)(__int64(Property) + Offsets::UnderlyingType);
|
||||
// log(std::format("{} Enum: {}\n", PropertyName, (int)EnumValueIg));
|
||||
log(std::format("{} Enum\n", PropertyName));
|
||||
}
|
||||
*/
|
||||
else if (IsPropertyA(Property, FunctionClass))
|
||||
{
|
||||
|
||||
}
|
||||
else if (!bExcludeUnhandled)
|
||||
{
|
||||
// log(std::format("{}: {}\n", PropertyName, "UNHANDLED");
|
||||
log(std::format("{}: {} {}\n", PropertyName, "UNHANDLED", ""/*, ((UObject*)Property)->GetName()*/));
|
||||
}
|
||||
|
||||
Property = GetNext(Property);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1,2 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "reboot.h"
|
||||
#include <fstream>
|
||||
|
||||
static inline bool IsPropertyA(void* Property, UClass* Class)
|
||||
{
|
||||
if (Fortnite_Version < 12.10)
|
||||
{
|
||||
if (((UField*)Property)->IsA(Class))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace ObjectViewer
|
||||
{
|
||||
void DumpContentsToFile(UObject* Object, const std::string& FileName = "", bool bExcludeUnhandled = false);
|
||||
|
||||
static inline void DumpContentsToFile(const std::string& ObjectName, const std::string& FileName = "", bool bExcludeUnhandled = false) { return DumpContentsToFile(FindObject(ObjectName), FileName, bExcludeUnhandled); }
|
||||
}
|
||||
Reference in New Issue
Block a user