remove s18+ storm effect, fix teams on all versions, fix a crash, fix 1.11 restarting
This commit is contained in:
Milxnor
2023-04-23 11:04:06 -04:00
parent 5da8485485
commit 58bd340501
24 changed files with 500 additions and 99 deletions

View File

@@ -10,8 +10,7 @@ void ABuildingFoundation::SetDynamicFoundationTransformHook(UObject* Context, FF
LOG_INFO(LogDev, "Bruh: {}", BuildingFoundation->GetName());
static auto DynamicFoundationTransformOffset = BuildingFoundation->GetOffset("DynamicFoundationTransform");
BuildingFoundation->Get<FTransform>(DynamicFoundationTransformOffset) = NewTransform;
SetFoundationTransform(BuildingFoundation, NewTransform);
return SetDynamicFoundationTransformOriginal(Context, Stack, Ret);
}

View File

@@ -44,19 +44,26 @@ public:
return Get<TArray<FItemLoadoutContainer>>(InventoryLoadoutsOffset);
}
TArray<FItemLoadoutTeamMap>& GetTeamLoadouts()
TArray<FItemLoadoutTeamMap>* GetTeamLoadouts()
{
static auto TeamLoadoutsOffset = GetOffset("TeamLoadouts");
return Get<TArray<FItemLoadoutTeamMap>>(TeamLoadoutsOffset);
static auto TeamLoadoutsOffset = GetOffset("TeamLoadouts", false);
if (TeamLoadoutsOffset == -1)
return nullptr;
return GetPtr<TArray<FItemLoadoutTeamMap>>(TeamLoadoutsOffset);
}
FItemLoadoutTeamMap GetLoadoutTeamForTeamIndex(uint8_t TeamIndex)
{
auto& TeamLoadouts = GetTeamLoadouts();
auto TeamLoadouts = GetTeamLoadouts();
for (int i = 0; i < TeamLoadouts.Num(); i++)
if (!TeamLoadouts)
return FItemLoadoutTeamMap();
for (int i = 0; i < TeamLoadouts->Num(); i++)
{
auto& TeamLoadout = TeamLoadouts.at(i);
auto& TeamLoadout = TeamLoadouts->at(i);
if (TeamLoadout.TeamIndex == TeamIndex)
return TeamLoadout;

View File

@@ -25,6 +25,7 @@
#include "BGA.h"
#include "vendingmachine.h"
#include "FortAthenaMutator.h"
#include "calendar.h"
static UFortPlaylist* GetPlaylistToUse()
{
@@ -221,11 +222,18 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
{
if (Fortnite_Version == 7.30)
{
auto PleasantParkIdk = FindObject<AActor>(("/Game/Athena/Maps/Athena_POI_Foundations.Athena_POI_Foundations.PersistentLevel.PleasentParkFestivus"));
ShowFoundation(PleasantParkIdk);
// should be automatic..
auto PleasantParkGround = FindObject<AActor>("/Game/Athena/Maps/Athena_POI_Foundations.Athena_POI_Foundations.PersistentLevel.PleasentParkDefault");
ShowFoundation(PleasantParkGround);
if (true)
{
auto PleasantParkIdk = FindObject<AActor>(("/Game/Athena/Maps/Athena_POI_Foundations.Athena_POI_Foundations.PersistentLevel.PleasentParkFestivus"));
ShowFoundation(PleasantParkIdk);
}
else
{
auto PleasantParkGround = FindObject<AActor>("/Game/Athena/Maps/Athena_POI_Foundations.Athena_POI_Foundations.PersistentLevel.PleasentParkDefault");
ShowFoundation(PleasantParkGround);
}
}
ShowFoundation(FindObject<AActor>("/Game/Athena/Maps/Athena_POI_Foundations.Athena_POI_Foundations.PersistentLevel.LF_Athena_POI_25x36")); // Polar Peak
@@ -246,9 +254,6 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
ShowFoundation(Island);
}
}
auto TheBlock = FindObject<AActor>("/Game/Athena/Maps/Athena_POI_Foundations.Athena_POI_Foundations.PersistentLevel.SLAB_2"); // SLAB_3 is blank
ShowFoundation(TheBlock);
}
if (Fortnite_Version == 17.50) {
@@ -402,6 +407,9 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
}
SetBitfield(GameMode->GetPtr<PlaceholderBitfield>("bWorldIsReady"), 1, true); // idk when we actually set this
// Calendar::SetSnow(1000);
Globals::bInitializedPlaylist = true;
}
@@ -649,10 +657,13 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
static int DefaultFirstTeam = 3;
bool bShouldSpreadTeams = false;
if (Playlist)
{
static auto bIsLargeTeamGameOffset = Playlist->GetOffset("bIsLargeTeamGame");
bool bIsLargeTeamGame = Playlist->Get<bool>(bIsLargeTeamGameOffset);
bShouldSpreadTeams = bIsLargeTeamGame;
}
static int CurrentTeamMembers = 0; // bad
@@ -673,8 +684,6 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
int MaxSquadSize = 1;
int TeamsNum = 0;
bool bShouldSpreadTeams = false;
if (bVersionHasPlaylist)
{
if (!Playlist)
@@ -691,7 +700,9 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
static auto bShouldSpreadTeamsOffset = Playlist->GetOffset("bShouldSpreadTeams", false);
if (bShouldSpreadTeamsOffset != -1)
bShouldSpreadTeams = Playlist->Get<bool>(bShouldSpreadTeamsOffset);
{
// bShouldSpreadTeams = Playlist->Get<bool>(bShouldSpreadTeamsOffset);
}
static auto MaxTeamCountOffset = Playlist->GetOffset("MaxTeamCount", false);
@@ -710,18 +721,6 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
}
static int NextTeamIndex = DefaultFirstTeam;
static int LastTeamIndex = NextTeamIndex;
static int LastNum1 = 1;
if (AmountOfRestarts != LastNum1)
{
LastNum1 = AmountOfRestarts;
NextTeamIndex = DefaultFirstTeam;
}
LastTeamIndex = NextTeamIndex;
if (!bShouldSpreadTeams)
{
@@ -748,7 +747,7 @@ int AFortGameModeAthena::Athena_PickTeamHook(AFortGameModeAthena* GameMode, uint
}
}
LOG_INFO(LogTeams, "Player is going on team {} with {} members.", NextTeamIndex, CurrentTeamMembers);
LOG_INFO(LogTeams, "Spreading Teams {} Player is going on team {} with {} members.", bShouldSpreadTeams, NextTeamIndex, CurrentTeamMembers);
CurrentTeamMembers++;
@@ -888,7 +887,7 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
}
}
if (Engine_Version >= 423 && Fortnite_Version <= 12.41) // 423+ we need to spawn manually and vehicle sync doesn't work on >S13.
if (Engine_Version >= 423 && Fortnite_Version <= 12.61) // 423+ we need to spawn manually and vehicle sync doesn't work on >S13.
{
static int LastNum420 = 1;

View File

@@ -41,6 +41,42 @@ struct FAircraftFlightInfo
}
};
static void SetFoundationTransform(AActor* BuildingFoundation, const FTransform& Transform)
{
static auto DynamicFoundationRepDataOffset = BuildingFoundation->GetOffset("DynamicFoundationRepData", false);
static auto Enabled = 1;
static auto Disabled = 2;
static auto DynamicFoundationTransformOffset = BuildingFoundation->GetOffset("DynamicFoundationTransform", false);
if (DynamicFoundationTransformOffset != -1) // needed check?
{
auto DynamicFoundationTransform = BuildingFoundation->GetPtr<FTransform>(DynamicFoundationTransformOffset);
*DynamicFoundationTransform = Transform;
}
if (DynamicFoundationRepDataOffset != -1)
{
auto DynamicFoundationRepData = BuildingFoundation->GetPtr<void>(DynamicFoundationRepDataOffset);
static auto RotationOffset = FindOffsetStruct("/Script/FortniteGame.DynamicBuildingFoundationRepData", "Rotation");
static auto TranslationOffset = FindOffsetStruct("/Script/FortniteGame.DynamicBuildingFoundationRepData", "Translation");
if (DynamicFoundationTransformOffset != -1) // needed check?
{
auto DynamicFoundationTransform = BuildingFoundation->GetPtr<FTransform>(DynamicFoundationTransformOffset);
*(FRotator*)(__int64(DynamicFoundationRepData) + RotationOffset) = DynamicFoundationTransform->Rotation.Rotator();
*(FVector*)(__int64(DynamicFoundationRepData) + TranslationOffset) = DynamicFoundationTransform->Translation;
}
static auto OnRep_DynamicFoundationRepDataFn = FindObject<UFunction>("/Script/FortniteGame.BuildingFoundation.OnRep_DynamicFoundationRepData");
BuildingFoundation->ProcessEvent(OnRep_DynamicFoundationRepDataFn);
}
}
static void ShowFoundation(AActor* BuildingFoundation, bool bShow = true)
{
if (!BuildingFoundation)
@@ -74,13 +110,13 @@ static void ShowFoundation(AActor* BuildingFoundation, bool bShow = true)
static auto DynamicFoundationTypeOffset = BuildingFoundation->GetOffset("DynamicFoundationType");
BuildingFoundation->Get<uint8_t>(DynamicFoundationTypeOffset) = bShow ? Static : StartDisabled;
static auto bShowHLODWhenDisabledOffset = BuildingFoundation->GetOffset("bShowHLODWhenDisabled", false);
/* static auto bShowHLODWhenDisabledOffset = BuildingFoundation->GetOffset("bShowHLODWhenDisabled", false);
if (bShowHLODWhenDisabledOffset != -1)
{
static auto bShowHLODWhenDisabledFieldMask = GetFieldMask(BuildingFoundation->GetProperty("bShowHLODWhenDisabled"));
BuildingFoundation->SetBitfieldValue(bShowHLODWhenDisabledOffset, bShowHLODWhenDisabledFieldMask, true);
}
} */
static auto OnRep_ServerStreamedInLevelFn = FindObject<UFunction>("/Script/FortniteGame.BuildingFoundation.OnRep_ServerStreamedInLevel");
BuildingFoundation->ProcessEvent(OnRep_ServerStreamedInLevelFn);
@@ -90,17 +126,6 @@ static void ShowFoundation(AActor* BuildingFoundation, bool bShow = true)
static auto Enabled = 1;
static auto Disabled = 2;
static auto DynamicFoundationTransformOffset = BuildingFoundation->GetOffset("DynamicFoundationTransform", false);
if (DynamicFoundationTransformOffset != -1) // needed check?
{
auto DynamicFoundationTransform = BuildingFoundation->GetPtr<FTransform>(DynamicFoundationTransformOffset);
DynamicFoundationTransform->Rotation = BuildingFoundation->GetActorRotation().Quaternion();
DynamicFoundationTransform->Translation = BuildingFoundation->GetActorLocation();
DynamicFoundationTransform->Scale3D = BuildingFoundation->GetActorScale3D();
}
if (DynamicFoundationRepDataOffset != -1)
{
auto DynamicFoundationRepData = BuildingFoundation->GetPtr<void>(DynamicFoundationRepDataOffset);
@@ -111,10 +136,6 @@ static void ShowFoundation(AActor* BuildingFoundation, bool bShow = true)
*(uint8_t*)(__int64(DynamicFoundationRepData) + EnabledStateOffset) = bShow ? Enabled : Disabled;
// hmm
*(FRotator*)(__int64(DynamicFoundationRepData) + RotationOffset) = BuildingFoundation->GetActorRotation();
*(FVector*)(__int64(DynamicFoundationRepData) + TranslationOffset) = BuildingFoundation->GetActorLocation();
static auto OnRep_DynamicFoundationRepDataFn = FindObject<UFunction>("/Script/FortniteGame.BuildingFoundation.OnRep_DynamicFoundationRepData");
BuildingFoundation->ProcessEvent(OnRep_DynamicFoundationRepDataFn);
}
@@ -124,6 +145,8 @@ static void ShowFoundation(AActor* BuildingFoundation, bool bShow = true)
if (FoundationEnabledStateOffset != -1)
BuildingFoundation->Get<uint8_t>(FoundationEnabledStateOffset) = bShow ? Enabled : Disabled;
SetFoundationTransform(BuildingFoundation, BuildingFoundation->GetTransform()); // idk
static auto LevelToStreamOffset = BuildingFoundation->GetOffset("LevelToStream");
auto& LevelToStream = BuildingFoundation->Get<FName>(LevelToStreamOffset);

View File

@@ -565,7 +565,7 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController* PC, FRotator ClientRotation)
{
auto PlayerController = Cast<AFortPlayerController>(Engine_Version < 424 ? PC : ((UActorComponent*)PC)->GetOwner());
auto PlayerController = Cast<AFortPlayerControllerAthena>(Engine_Version < 424 ? PC : ((UActorComponent*)PC)->GetOwner());
if (Engine_Version < 424 && !Globals::bLateGame.load())
return ServerAttemptAircraftJumpOriginal(PC, ClientRotation);
@@ -595,6 +595,13 @@ void AFortPlayerController::ServerAttemptAircraftJumpHook(AFortPlayerController*
auto NewPawnAsFort = Cast<AFortPawn>(NewPawn);
if (Fortnite_Version >= 18)
{
static auto StormEffectClass = FindObject<UClass>("/Game/Athena/SafeZone/GE_OutsideSafeZoneDamage.GE_OutsideSafeZoneDamage_C");
auto PlayerState = PlayerController->GetPlayerStateAthena();
PlayerState->GetAbilitySystemComponent()->RemoveActiveGameplayEffectBySourceEffect(StormEffectClass, 1, PlayerState->GetAbilitySystemComponent());
}
if (NewPawnAsFort)
{
NewPawnAsFort->SetHealth(100);

View File

@@ -24,7 +24,9 @@ void AFortPlayerControllerAthena::StartGhostModeHook(UObject* Context, FFrame* S
// if (!Controller->HasAuthority) return StartGhostModeOriginal(Context, Stack, Ret);
// if (Controller->GhostModeRepData.bInGhostMode) return StartGhostModeOriginal(Context, Stack, Ret);
auto GhostModeRepData = Controller->GetGhostModeRepData();
if (GhostModeRepData->IsInGhostMode()) return StartGhostModeOriginal(Context, Stack, Ret);
auto WorldInventory = Controller->GetWorldInventory();
@@ -217,6 +219,16 @@ void AFortPlayerControllerAthena::EnterAircraftHook(UObject* PC, AActor* Aircraf
WorldInventory->Update();
// Should we equip the pickaxe for older builds here?
if (Fortnite_Version < 2.5) // idk
{
/* auto PickaxeInstance = WorldInventory->GetPickaxeInstance();
if (!PickaxeInstance)
return;
AFortPlayerController::ServerExecuteInventoryItemHook(PlayerController, PickaxeInstance->GetItemEntry()->GetItemGuid()); */
}
}
void AFortPlayerControllerAthena::ServerRequestSeatChangeHook(AFortPlayerControllerAthena* PlayerController, int TargetSeatIndex)

View File

@@ -4,6 +4,6 @@
void AGameMode::RestartGame()
{
static auto fn = FindObject<UFunction>("/Script/Engine.GameMode.RestartGame");
this->ProcessEvent(fn);
static auto RestartGameFn = FindObject<UFunction>("/Script/Engine.GameMode.RestartGame");
this->ProcessEvent(RestartGameFn);
}

View File

@@ -79,13 +79,6 @@ APawn* AGameModeBase::SpawnDefaultPawnForHook(AGameModeBase* GameMode, AControll
CurrentPlaylist->ApplyModifiersToActor(PlayerStateAthena); // We need to move this!
}
/* if (Fortnite_Version >= 18)
{
static auto StormEffectClass = FindObject<UClass>("/Game/Athena/SafeZone/GE_OutsideSafeZoneDamage.GE_OutsideSafeZoneDamage_C");
auto PlayerState = NewPlayerAsAthena->GetPlayerStateAthena();
PlayerState->GetAbilitySystemComponent()->RemoveActiveGameplayEffectBySourceEffect(StormEffectClass, 1, PlayerState->GetAbilitySystemComponent());
} */
if (NewPlayerAsAthena)
{
auto WorldInventory = NewPlayerAsAthena->GetWorldInventory();

View File

@@ -0,0 +1,73 @@
#include "GenericPlatformMath.h"
#include "UnrealMathUtility.h"
#define PI (3.1415926535897932f)
/*FORCENOINLINE*/ float FGenericPlatformMath::Fmod(float X, float Y)
{
if (fabsf(Y) <= 1.e-8f)
{
// FmodReportError(X, Y);
return 0.f;
}
const float Div = (X / Y);
// All floats where abs(f) >= 2^23 (8388608) are whole numbers so do not need truncation, and avoid overflow in TruncToFloat as they get even larger.
const float Quotient = fabsf(Div) < 8388608.f ? TruncToFloat(Div) : Div;
float IntPortion = Y * Quotient;
// Rounding and imprecision could cause IntPortion to exceed X and cause the result to be outside the expected range.
// For example Fmod(55.8, 9.3) would result in a very small negative value!
if (fabsf(IntPortion) > fabsf(X))
{
IntPortion = X;
}
const float Result = X - IntPortion;
return Result;
}
float FGenericPlatformMath::Atan2(float Y, float X)
{
//return atan2f(Y,X);
// atan2f occasionally returns NaN with perfectly valid input (possibly due to a compiler or library bug).
// We are replacing it with a minimax approximation with a max relative error of 7.15255737e-007 compared to the C library function.
// On PC this has been measured to be 2x faster than the std C version.
const float absX = FMath::Abs(X);
const float absY = FMath::Abs(Y);
const bool yAbsBigger = (absY > absX);
float t0 = yAbsBigger ? absY : absX; // Max(absY, absX)
float t1 = yAbsBigger ? absX : absY; // Min(absX, absY)
if (t0 == 0.f)
return 0.f;
float t3 = t1 / t0;
float t4 = t3 * t3;
static const float c[7] = {
+7.2128853633444123e-03f,
-3.5059680836411644e-02f,
+8.1675882859940430e-02f,
-1.3374657325451267e-01f,
+1.9856563505717162e-01f,
-3.3324998579202170e-01f,
+1.0f
};
t0 = c[0];
t0 = t0 * t4 + c[1];
t0 = t0 * t4 + c[2];
t0 = t0 * t4 + c[3];
t0 = t0 * t4 + c[4];
t0 = t0 * t4 + c[5];
t0 = t0 * t4 + c[6];
t3 = t0 * t3;
t3 = yAbsBigger ? (0.5f * PI) - t3 : t3;
t3 = (X < 0.0f) ? PI - t3 : t3;
t3 = (Y < 0.0f) ? -t3 : t3;
return t3;
}

View File

@@ -2,7 +2,7 @@
#include "inc.h"
class FPlatformMath
class FGenericPlatformMath
{
public:
static constexpr FORCEINLINE int32 TruncToInt(float F)
@@ -21,6 +21,8 @@ public:
return (A <= B) ? A : B;
}
static FORCENOINLINE float Fmod(float X, float Y);
static FORCEINLINE int32 FloorToInt(float F)
{
return TruncToInt(floorf(F));
@@ -40,6 +42,23 @@ public:
return (A >= B) ? A : B;
}
static FORCEINLINE float Sin(float Value) { return sinf(Value); }
static FORCEINLINE float Asin(float Value) { return asinf((Value < -1.f) ? -1.f : ((Value < 1.f) ? Value : 1.f)); }
static FORCEINLINE float Sinh(float Value) { return sinhf(Value); }
static FORCEINLINE float Cos(float Value) { return cosf(Value); }
static FORCEINLINE float Acos(float Value) { return acosf((Value < -1.f) ? -1.f : ((Value < 1.f) ? Value : 1.f)); }
static FORCEINLINE float Tan(float Value) { return tanf(Value); }
static FORCEINLINE float Atan(float Value) { return atanf(Value); }
static float Atan2(float Y, float X);
static FORCEINLINE float Sqrt(float Value) { return sqrtf(Value); }
static FORCEINLINE float Pow(float A, float B) { return powf(A, B); }
template< class T >
static constexpr FORCEINLINE T Abs(const T A)
{
return (A >= (T)0) ? A : -A;
}
static FORCEINLINE float FloorToFloat(float F)
{
return floorf(F);

View File

@@ -22,16 +22,19 @@ void UNetDriver::RemoveNetworkActor(AActor* Actor)
void UNetDriver::TickFlushHook(UNetDriver* NetDriver)
{
static auto ReplicationDriverOffset = NetDriver->GetOffset("ReplicationDriver", false);
if (Globals::bStartedListening)
{
static auto ReplicationDriverOffset = NetDriver->GetOffset("ReplicationDriver", false);
if (ReplicationDriverOffset == -1)
{
NetDriver->ServerReplicateActors();
}
else
{
if (auto ReplicationDriver = NetDriver->Get(ReplicationDriverOffset))
reinterpret_cast<void(*)(UObject*)>(ReplicationDriver->VFTable[Offsets::ServerReplicateActors])(ReplicationDriver);
if (ReplicationDriverOffset == -1)
{
NetDriver->ServerReplicateActors();
}
else
{
if (auto ReplicationDriver = NetDriver->Get(ReplicationDriverOffset))
reinterpret_cast<void(*)(UObject*)>(ReplicationDriver->VFTable[Offsets::ServerReplicateActors])(ReplicationDriver);
}
}
return TickFlushOriginal(NetDriver);
@@ -300,7 +303,7 @@ static bool IsActorRelevantToConnection(AActor * Actor, std::vector<FNetViewer>&
return false;
}
static FNetViewer ConstructNetViewer(UNetConnection * NetConnection)
static FNetViewer ConstructNetViewer(UNetConnection* NetConnection)
{
FNetViewer newViewer{};
newViewer.Connection = NetConnection;

View File

@@ -183,6 +183,7 @@
<ClCompile Include="BuildingStructuralSupportSystem.cpp" />
<ClCompile Include="BuildingTrap.cpp" />
<ClCompile Include="BuildingWeapons.cpp" />
<ClCompile Include="calendar.h" />
<ClCompile Include="CheatManager.cpp" />
<ClCompile Include="Class.cpp" />
<ClCompile Include="Controller.cpp" />
@@ -229,6 +230,7 @@
<ClCompile Include="GameModeBase.cpp" />
<ClCompile Include="GameplayStatics.cpp" />
<ClCompile Include="GameState.cpp" />
<ClCompile Include="GenericPlatformMath.cpp" />
<ClCompile Include="InventoryManagementLibrary.cpp" />
<ClCompile Include="KismetMathLibrary.cpp" />
<ClCompile Include="KismetStringLibrary.cpp" />

View File

@@ -245,6 +245,12 @@
<ClCompile Include="FortAthenaMutator_Barrier.cpp">
<Filter>FortniteGame\Source\FortniteGame\Private\Mutators</Filter>
</ClCompile>
<ClCompile Include="GenericPlatformMath.cpp">
<Filter>Engine\Source\Runtime\Core\Private\GenericPlatform</Filter>
</ClCompile>
<ClCompile Include="calendar.h">
<Filter>Reboot\Public</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="log.h" />
@@ -1033,6 +1039,9 @@
<Filter Include="Engine\Source\Runtime\Engine\Public">
<UniqueIdentifier>{3d909143-220c-44b3-819f-79d282c3fc0f}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Runtime\Core\Private\GenericPlatform">
<UniqueIdentifier>{c04eb59f-e186-49a3-a145-1fd3dc1dcd3d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="UnrealEngine.cpp">

View File

@@ -17,4 +17,6 @@ public:
/** The quaternion's W-component. */
float W;
struct FRotator Rotator() const;
};

View File

@@ -3,6 +3,8 @@
#include "Quat.h"
#include "Vector.h"
#include "UnrealMathUtility.h"
struct FRotator
{
float Pitch;
@@ -12,4 +14,35 @@ struct FRotator
FQuat Quaternion();
FVector Vector() const;
static float NormalizeAxis(float Angle);
static float ClampAxis(float Angle);
};
FORCEINLINE float FRotator::ClampAxis(float Angle)
{
// returns Angle in the range (-360,360)
Angle = FMath::Fmod(Angle, 360.f);
if (Angle < 0.f)
{
// shift to [0,360) range
Angle += 360.f;
}
return Angle;
}
FORCEINLINE float FRotator::NormalizeAxis(float Angle)
{
// returns Angle in the range [0,360)
Angle = ClampAxis(Angle);
if (Angle > 180.f)
{
// shift to (-180,180]
Angle -= 360.f;
}
return Angle;
}

View File

@@ -1,4 +1,6 @@
#include "Rotator.h"
#include "Quat.h"
#include "UnrealMathUtility.h"
#define INV_PI (0.31830988618f)
#define HALF_PI (1.57079632679f)
@@ -47,7 +49,6 @@ static FORCEINLINE void SinCos(float* ScalarSin, float* ScalarCos, float Value)
struct FQuat FRotator::Quaternion()
{
#if PLATFORM_ENABLE_VECTORINTRINSICS
const VectorRegister Angles = MakeVectorRegister(Rotator.Pitch, Rotator.Yaw, Rotator.Roll, 0.0f);
const VectorRegister HalfAngles = VectorMultiply(Angles, DEG_TO_RAD_HALF);
@@ -112,3 +113,42 @@ FVector FRotator::Vector() const
return V;
}
FRotator FQuat::Rotator() const
{
const float SingularityTest = Z * X - W * Y;
const float YawY = 2.f * (W * Z + X * Y);
const float YawX = (1.f - 2.f * (FMath::Square(Y) + FMath::Square(Z)));
// reference
// http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/
// this value was found from experience, the above websites recommend different values
// but that isn't the case for us, so I went through different testing, and finally found the case
// where both of world lives happily.
const float SINGULARITY_THRESHOLD = 0.4999995f;
const float RAD_TO_DEG = (180.f) / PI;
FRotator RotatorFromQuat;
if (SingularityTest < -SINGULARITY_THRESHOLD)
{
RotatorFromQuat.Pitch = -90.f;
RotatorFromQuat.Yaw = FMath::Atan2(YawY, YawX) * RAD_TO_DEG;
RotatorFromQuat.Roll = FRotator::NormalizeAxis(-RotatorFromQuat.Yaw - (2.f * FMath::Atan2(X, W) * RAD_TO_DEG));
}
else if (SingularityTest > SINGULARITY_THRESHOLD)
{
RotatorFromQuat.Pitch = 90.f;
RotatorFromQuat.Yaw = FMath::Atan2(YawY, YawX) * RAD_TO_DEG;
RotatorFromQuat.Roll = FRotator::NormalizeAxis(RotatorFromQuat.Yaw - (2.f * FMath::Atan2(X, W) * RAD_TO_DEG));
}
else
{
RotatorFromQuat.Pitch = FMath::FastAsin(2.f * (SingularityTest)) * RAD_TO_DEG;
RotatorFromQuat.Yaw = FMath::Atan2(YawY, YawX) * RAD_TO_DEG;
RotatorFromQuat.Roll = FMath::Atan2(-2.f * (W * X + Y * Z), (1.f - 2.f * (FMath::Square(X) + FMath::Square(Y)))) * RAD_TO_DEG;
}
return RotatorFromQuat;
}

View File

@@ -2,11 +2,43 @@
#include "GenericPlatformMath.h"
struct FMath : public FPlatformMath
struct FMath : public FGenericPlatformMath
{
template< class T >
static FORCEINLINE T Clamp(const T X, const T Min, const T Max)
{
return X < Min ? Min : X < Max ? X : Max;
}
template< class T >
static FORCEINLINE T Square(const T A)
{
return A * A;
}
#define FASTASIN_HALF_PI (1.5707963050f)
/**
* Computes the ASin of a scalar value.
*
* @param Value input angle
* @return ASin of Value
*/
static FORCEINLINE float FastAsin(float Value)
{
// Clamp input to [-1,1].
bool nonnegative = (Value >= 0.0f);
float x = FMath::Abs(Value);
float omx = 1.0f - x;
if (omx < 0.0f)
{
omx = 0.0f;
}
float root = FMath::Sqrt(omx);
// 7-degree minimax approximation
float result = ((((((-0.0012624911f * x + 0.0066700901f) * x - 0.0170881256f) * x + 0.0308918810f) * x - 0.0501743046f) * x + 0.0889789874f) * x - 0.2145988016f) * x + FASTASIN_HALF_PI;
result *= root; // acos(|x|)
// acos(x) = pi - acos(-x) when x < 0, asin(x) = pi/2 - acos(x)
return (nonnegative ? FASTASIN_HALF_PI - result : result - FASTASIN_HALF_PI);
}
#undef FASTASIN_HALF_PI
};

View File

@@ -98,6 +98,8 @@ void Addresses::SetupVersion()
Fortnite_Version = 1.8;
if (Fortnite_CL == 3870737)
Fortnite_Version = 2.42;
toFree.Free();
}
void Addresses::FindAll()

View File

@@ -0,0 +1,53 @@
#pragma once
#include "reboot.h"
#include "GameplayStatics.h"
#include "FortGameStateAthena.h"
namespace Calendar
{
static inline bool HasSnowModification()
{
return Fortnite_Version == 7.30;
}
static inline UObject* GetSnowSetup()
{
auto Class = FindObject<UClass>("/Game/Athena/Environments/Landscape/Blueprints/BP_SnowSetup.BP_SnowSetup_C");
auto Actors = UGameplayStatics::GetAllActorsOfClass(GetWorld(), Class);
return Actors.Num() > 0 ? Actors.at(0) : nullptr;
}
static inline float GetFullSnowMapValue()
{
if (Fortnite_Version == 7.30)
{
std::vector<std::pair<float, float>> TimeAndValues = { { 0, 1.2f}, { 0.68104035f, 4.6893263f }, { 0.9632137f, 10.13335f }, { 1.0f, 15.0f } };
// 1.2
// 4.6893263
// 10.13335
// 15;
return TimeAndValues[3].first;
}
return -1;
}
static inline void SetSnow(float NewValue)
{
static auto SetSnowFn = FindObject<UFunction>("/Game/Athena/Environments/Landscape/Blueprints/BP_SnowSetup.BP_SnowSetup_C.SetSnow");
auto SnowSetup = GetSnowSetup();
LOG_INFO(LogDev, "SnowSetup: {}", SnowSetup->IsValidLowLevel() ? SnowSetup->GetFullName() : "BadRead");
if (SnowSetup)
{
static auto OnReady_347B1F4D45630C357605FCB417D749A3Fn = FindObject<UFunction>("/Game/Athena/Environments/Landscape/Blueprints/BP_SnowSetup.BP_SnowSetup_C.OnReady_347B1F4D45630C357605FCB417D749A3");
auto GameState = GetWorld()->GetGameState();
SnowSetup->ProcessEvent(OnReady_347B1F4D45630C357605FCB417D749A3Fn, &GameState);
SnowSetup->ProcessEvent(SetSnowFn, &NewValue);
}
}
}

View File

@@ -4,6 +4,7 @@
#include "FortPlayerControllerAthena.h"
#include "KismetSystemLibrary.h"
#include "AthenaBarrierObjective.h"
#include "FortAthenaMutator_Barrier.h"
bool IsOperator(APlayerState* PlayerState, AFortPlayerController* PlayerController)
{
@@ -478,6 +479,24 @@ void ServerCheatHook(AFortPlayerControllerAthena* PlayerController, FString Msg)
Pawn->TeleportTo(FVector(X, Y, Z), Pawn->GetActorRotation());
SendMessageToConsole(PlayerController, L"Teleported!");
}
else if (Command == "test")
{
auto SpawnBigWall = [&](AFortAthenaMutator* Mutator) {
if (auto BarrierMutator = Cast<AFortAthenaMutator_Barrier>(Mutator))
{
auto BigBaseWallClass = BarrierMutator->GetBigBaseWallClass();
LOG_INFO(LogDev, "BigBaseWallClass: {}", BigBaseWallClass->IsValidLowLevel() ? BigBaseWallClass->GetFullName() : "BadRead");
if (BigBaseWallClass->IsValidLowLevel())
{
BarrierMutator->GetBigBaseWall() = GetWorld()->SpawnActor<AAthenaBigBaseWall>(BigBaseWallClass, FVector(0, 0, 0));
}
}
};
LoopMutators(SpawnBigWall);
}
else { bSendHelpMessage = true; };
}
else { bSendHelpMessage = true; };

View File

@@ -482,10 +482,9 @@ DWORD WINAPI Main(LPVOID)
// Hooking::MinHook::Hook(FortPlayerStateAthenaDefault, FindObject<UFunction>(L"/Script/FortniteGame.FortPlayerStateAthena.ServerSetInAircraft"),
// AFortPlayerStateAthena::ServerSetInAircraftHook, (PVOID*)&AFortPlayerStateAthena::ServerSetInAircraftOriginal, false, true); // We could use second method but eh
if (FortOctopusVehicleDefault)
if (false && FortOctopusVehicleDefault) // hooking broken on 19.10 i cant figure it out for the life of me
{
static auto ServerUpdateTowhookFn = FindObject<UFunction>("/Script/FortniteGame.FortOctopusVehicle.ServerUpdateTowhook");
Hooking::MinHook::Hook(FortOctopusVehicleDefault, ServerUpdateTowhookFn, AFortOctopusVehicle::ServerUpdateTowhookHook, nullptr, false);
}

View File

@@ -1313,7 +1313,7 @@ static inline uint64 FindPickTeam()
else if (Engine_Version >= 427) // different start
return Memcury::Scanner::FindPattern("48 89 5C 24 ? 88 54 24 10 55 56 57 41 54 41 55 41 56 41 57 48 8B EC 48 83 EC 70 4C 8B A1").Get();
if (Fortnite_Version == 7.20)
if (Fortnite_Version == 7.20 || Fortnite_Version == 7.30)
return Memcury::Scanner::FindPattern("89 54 24 10 53 56 41 54 41 55 41 56 48 81 EC").Get();
auto Addr = Memcury::Scanner::FindStringRef(L"PickTeam for [%s] used beacon value [%d]", false, 0, Engine_Version >= 427); // todo check if its just s18+ but this doesn't matter for now cuz we hardcode sig

View File

@@ -428,9 +428,22 @@ void MainUI()
AllFortBeacons.Free();
Globals::bInitializedPlaylist = false;
Globals::bStartedListening = false;
Globals::bHitReadyToStartMatch = false;
bStartedBus = false;
AmountOfRestarts++;
LOG_INFO(LogDev, "Switching!");
((AGameMode*)GetWorld()->GetGameMode())->RestartGame();
// UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), LevelA, nullptr);
if (Fortnite_Version >= 3) // idk what ver
{
((AGameMode*)GetWorld()->GetGameMode())->RestartGame();
}
else
{
UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), LevelA, nullptr);
}
/*
@@ -444,18 +457,13 @@ void MainUI()
// UGameplayStatics::OpenLevel(GetWorld(), UKismetStringLibrary::Conv_StringToName(LevelA), true, FString());
LOG_INFO(LogGame, "Restarting!");
Globals::bInitializedPlaylist = false;
Globals::bStartedListening = false;
Globals::bHitReadyToStartMatch = false;
bStartedBus = false;
AmountOfRestarts++;
}
else
{
LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!");
}
}
/*
if (ImGui::Button("TEST"))
{
auto GameMode = (AFortGameMode*)GetWorld()->GetGameMode();
@@ -493,6 +501,7 @@ void MainUI()
}
}
}
*/
if (!bStartedBus)
{
@@ -805,13 +814,46 @@ void MainUI()
if (ImGui::Button("Print Class VFT"))
{
auto ClassToDump = FindObject<UClass>(ClassNameToDump)->CreateDefaultObject();
auto Class = FindObject<UClass>(ClassNameToDump);
if (ClassToDump)
if (Class)
{
LOG_INFO(LogDev, "{} VFT: 0x{:x}", ClassToDump->GetName(), __int64(ClassToDump->VFTable) - __int64(GetModuleHandleW(0)));
auto ClassToDump = Class->CreateDefaultObject();
if (ClassToDump)
{
LOG_INFO(LogDev, "{} VFT: 0x{:x}", ClassToDump->GetName(), __int64(ClassToDump->VFTable) - __int64(GetModuleHandleW(0)));
}
}
}
/*
ImGui::Text(std::format("Amount of hooks {}", AllFunctionHooks.size()).c_str());
for (auto& FunctionHook : AllFunctionHooks)
{
if (ImGui::Button(std::format("{} {} (0x{:x})", (FunctionHook.IsHooked ? "Unhook" : "Hook"), FunctionHook.Name, (__int64(FunctionHook.Original) - __int64(GetModuleHandleW(0)))).c_str()))
{
if (FunctionHook.IsHooked)
{
if (!FunctionHook.VFT || FunctionHook.Index == -1)
{
Hooking::MinHook::Unhook(FunctionHook.Original);
}
else
{
VirtualSwap(FunctionHook.VFT, FunctionHook.Index, FunctionHook.Original);
}
}
else
{
Hooking::MinHook::Hook(FunctionHook.Original, FunctionHook.Detour, nullptr, FunctionHook.Name);
}
FunctionHook.IsHooked = !FunctionHook.IsHooked;
}
}
*/
}
else if (Tab == SETTINGS_TAB)
{

View File

@@ -6,6 +6,18 @@
#include "memcury.h"
#include "Class.h"
struct FunctionHooks
{
void* Original;
void* Detour;
bool IsHooked;
std::string Name;
int Index = -1;
void** VFT = nullptr;
};
static inline std::vector<FunctionHooks> AllFunctionHooks;
inline __int64 GetFunctionIdxOrPtr2(UFunction* Function)
{
auto NativeAddr = __int64(Function->GetFunc());
@@ -131,7 +143,7 @@ inline __int64 GetFunctionIdxOrPtr(UFunction* Function, bool bBreakWhenHitRet =
for (int i = 0; i < 2000; i++)
{
// LOG_INFO(LogDev, "0x{:x}", *(uint8_t*)(NativeAddr + i));
// LOG_INFO(LogDev, "0x{:x} {}", *(uint8_t*)(NativeAddr + i), bFoundValidate);
if (Fortnite_Version >= 19) // We should NOT do this, instead, if we expect a validate and we don't find before C3, then search for 0x41 0xFF.
{
@@ -205,6 +217,8 @@ inline __int64 GetFunctionIdxOrPtr(UFunction* Function, bool bBreakWhenHitRet =
__int64 functionAddy = 0;
// LOG_INFO(LogDev, "not virtgual");
if (RetAddr)
{
// LOG_INFO(LogDev, "RetAddr 0x{:x}", RetAddr - __int64(GetModuleHandleW(0)));
@@ -233,17 +247,26 @@ namespace Hooking
{
namespace MinHook
{
static bool Hook(void* Addr, void* Detour, void** Original = nullptr)
static bool Hook(void* Addr, void* Detour, void** Original = nullptr, std::string OptionalName = "Undefined")
{
LOG_INFO(LogDev, "Hooking 0x{:x}", __int64(Addr) - __int64(GetModuleHandleW(0)));
auto ret1 = MH_CreateHook(Addr, Detour, Original);
void* Og;
auto ret1 = MH_CreateHook(Addr, Detour, &Og);
auto ret2 = MH_EnableHook(Addr);
return ret1 == MH_OK && ret2 == MH_OK;
if (Original)
*Original = Og;
bool wasHookSuccessful = ret1 == MH_OK && ret2 == MH_OK;
if (wasHookSuccessful)
AllFunctionHooks.push_back(FunctionHooks(Og, Detour, true, OptionalName));
return wasHookSuccessful;
}
static bool PatchCall(void* Addr, void* Detour/*, void** Original = nullptr*/)
{
// int64_t delta = targetAddr - (instrAddr + 5);
// *(int32_t*)(instrAddr + 1) = static_cast<int32_t>(delta);
}
@@ -256,9 +279,11 @@ namespace Hooking
if (!Function)
return false;
auto FunctionName = Function->GetName();
if (!DefaultClass || !DefaultClass->VFTable)
{
LOG_WARN(LogHook, "DefaultClass or the vtable for function {} is null! ({})", Function->GetName(), __int64(DefaultClass));
LOG_WARN(LogHook, "DefaultClass or the vtable for function {} is null! ({})", FunctionName, __int64(DefaultClass));
return false;
}
@@ -266,7 +291,7 @@ namespace Hooking
if (bHookExec)
{
LOG_INFO(LogDev, "Hooking Exec {} at 0x{:x}", Function->GetName(), __int64(Exec) - __int64(GetModuleHandleW(0)));
LOG_INFO(LogDev, "Hooking Exec {} at 0x{:x}", FunctionName, __int64(Exec) - __int64(GetModuleHandleW(0)));
if (Original)
*Original = Exec;
@@ -279,7 +304,7 @@ namespace Hooking
if (AddrOrIdx == -1)
{
LOG_ERROR(LogInit, "Failed to find anything for {}.", Function->GetName());
LOG_ERROR(LogInit, "Failed to find anything for {}.", FunctionName);
return false;
}
@@ -287,22 +312,30 @@ namespace Hooking
{
auto Idx = AddrOrIdx / 8;
AllFunctionHooks.push_back(FunctionHooks(DefaultClass->VFTable[Idx], Detour, true, FunctionName, Idx, DefaultClass->VFTable));
if (Original)
*Original = DefaultClass->VFTable[Idx];
LOG_INFO(LogDev, "Hooking {} with Idx 0x{:x}", Function->GetName(), AddrOrIdx);
LOG_INFO(LogDev, "Hooking {} with Idx 0x{:x}", FunctionName, AddrOrIdx);
VirtualSwap(DefaultClass->VFTable, Idx, Detour);
return true;
}
return Hook((PVOID)AddrOrIdx, Detour, Original);
return Hook((PVOID)AddrOrIdx, Detour, Original, FunctionName);
}
static bool Unhook(void* Addr)
{
return MH_DisableHook((PVOID)Addr) == MH_OK;
}
/* static bool Unhook(void** Addr, void* Original) // I got brain damaged
{
Unhook(Addr);
*Addr = Original;
} */
}
}