too much stuff

fix s3, fix health + backpack bug on 1.11, change replciation, fix 7.20 & 12.61, fix backpack on >S9, probably some other stuff i forgot
This commit is contained in:
Milxnor
2023-04-03 02:04:29 -04:00
parent ffbba9e9a4
commit cb57a1b843
32 changed files with 1457 additions and 216 deletions

View File

@@ -126,6 +126,28 @@ void AActor::ForceNetUpdate()
this->ProcessEvent(ForceNetUpdateFn);
}
bool AActor::IsNetStartupActor()
{
return IsNetStartup(); // The implementation on this function depends on the version.
}
bool AActor::IsPendingKillPending()
{
return IsActorBeingDestroyed() || !IsValidChecked(this);
}
float& AActor::GetNetUpdateFrequency()
{
static auto NetUpdateFrequencyOffset = GetOffset("NetUpdateFrequency");
return Get<float>(NetUpdateFrequencyOffset);
}
float& AActor::GetMinNetUpdateFrequency()
{
static auto MinNetUpdateFrequencyOffset = GetOffset("MinNetUpdateFrequency");
return Get<float>(MinNetUpdateFrequencyOffset);
}
bool AActor::IsAlwaysRelevant()
{
static auto bAlwaysRelevantOffset = GetOffset("bAlwaysRelevant");

View File

@@ -25,6 +25,10 @@ public:
void SetCanBeDamaged(bool NewValue);
void SetOwner(AActor* Owner);
void ForceNetUpdate();
bool IsNetStartupActor();
bool IsPendingKillPending();
float& GetNetUpdateFrequency();
float& GetMinNetUpdateFrequency();
static class UClass* StaticClass();
};

View File

@@ -2,6 +2,20 @@
#include "ContainerAllocationPolicies.h"
static FORCEINLINE uint32 CountLeadingZeros(uint32 Value)
{
unsigned long Log2;
if (_BitScanReverse(&Log2, Value) != 0)
{
return 31 - Log2;
}
return 32;
}
#define NumBitsPerDWORD ((int32)32)
#define NumBitsPerDWORDLogTwo ((int32)5)
class TBitArray
{
private:
@@ -10,8 +24,308 @@ private:
template <typename SetType>
friend class TSet;
private:
public:
TInlineAllocator<4>::ForElementType<unsigned int> Data;
int NumBits;
int MaxBits;
struct FRelativeBitReference
{
public:
FORCEINLINE explicit FRelativeBitReference(int32 BitIndex)
: DWORDIndex(BitIndex >> NumBitsPerDWORDLogTwo)
, Mask(1 << (BitIndex & ((NumBitsPerDWORD)-1)))
{
}
int32 DWORDIndex;
uint32 Mask;
};
public:
struct FBitReference
{
FORCEINLINE FBitReference(uint32& InData, uint32 InMask)
: Data(InData)
, Mask(InMask)
{
}
FORCEINLINE const FBitReference(const uint32& InData, const uint32 InMask)
: Data(const_cast<uint32&>(InData))
, Mask(InMask)
{
}
FORCEINLINE void SetBit(const bool Value)
{
Value ? Data |= Mask : Data &= ~Mask;
// 10011101 - Data // 10011101 - Data
// 00000010 - Mask - true | // 00000010 - Mask - false
// 10011111 - |= // 11111101 - ~
// // 10011111 - &=
}
FORCEINLINE operator bool() const
{
return (Data & Mask) != 0;
}
FORCEINLINE void operator=(const bool Value)
{
this->SetBit(Value);
}
private:
uint32& Data;
uint32 Mask;
};
public:
class FBitIterator : public FRelativeBitReference
{
private:
int32 Index;
const TBitArray& IteratedArray;
public:
FORCEINLINE const FBitIterator(const TBitArray& ToIterate, const int32 StartIndex) // Begin
: IteratedArray(ToIterate)
, Index(StartIndex)
, FRelativeBitReference(StartIndex)
{
}
FORCEINLINE const FBitIterator(const TBitArray& ToIterate) // End
: IteratedArray(ToIterate)
, Index(ToIterate.NumBits)
, FRelativeBitReference(ToIterate.NumBits)
{
}
FORCEINLINE explicit operator bool() const
{
return Index < IteratedArray.Num();
}
FORCEINLINE FBitIterator& operator++()
{
++Index;
this->Mask <<= 1;
if (!this->Mask)
{
this->Mask = 1;
++this->DWORDIndex;
}
return *this;
}
FORCEINLINE bool operator*() const
{
// Thesis: Once there are more elements in the BitArray than InlineData can hold it'll just allocate all of
// them through SecondaryElements, leaving InlineData all true
if (IteratedArray.NumBits < IteratedArray.Data.NumInlineBits())
{
return (bool)FBitReference(IteratedArray.Data.GetInlineElement(this->DWORDIndex), this->Mask);
}
else
{
return (bool)FBitReference(IteratedArray.Data.GetSecondaryElement(this->DWORDIndex), this->Mask);
}
}
FORCEINLINE bool operator==(const FBitIterator& OtherIt) const
{
return Index == OtherIt.Index;
}
FORCEINLINE bool operator!=(const FBitIterator& OtherIt) const
{
return Index </*=*/ OtherIt.Index;
}
FORCEINLINE bool operator < (const int32 Other) const
{
return Index < Other;
}
FORCEINLINE bool operator > (const int32 Other) const
{
return Index < Other;
}
FORCEINLINE int32 GetIndex() const
{
return Index;
}
};
class FSetBitIterator : public FRelativeBitReference
{
private:
const TBitArray& IteratedArray;
uint32 UnvisitedBitMask;
int32 CurrentBitIndex;
int32 BaseBitIndex;
public:
FORCEINLINE FSetBitIterator(const TBitArray& ToIterate, int32 StartIndex)
: FRelativeBitReference(StartIndex)
, IteratedArray(const_cast<TBitArray&>(ToIterate))
, UnvisitedBitMask((~0U) << (StartIndex & (NumBitsPerDWORD - 1)))
, CurrentBitIndex(StartIndex)
, BaseBitIndex(StartIndex & ~(NumBitsPerDWORD - 1))
{
if (StartIndex != IteratedArray.NumBits)
{
FindNextSetBit();
}
}
FORCEINLINE FSetBitIterator(const TBitArray& ToIterate)
: FRelativeBitReference(ToIterate.NumBits)
, IteratedArray(const_cast<TBitArray&>(ToIterate))
, UnvisitedBitMask(0)
, CurrentBitIndex(ToIterate.NumBits)
, BaseBitIndex(ToIterate.NumBits)
{
}
FORCEINLINE FSetBitIterator& operator++()
{
UnvisitedBitMask &= ~this->Mask;
FindNextSetBit();
return *this;
}
FORCEINLINE bool operator*() const
{
return true;
}
FORCEINLINE bool operator==(const FSetBitIterator& Other) const
{
return CurrentBitIndex == Other.CurrentBitIndex;
}
FORCEINLINE bool operator!=(const FSetBitIterator& Other) const
{
return CurrentBitIndex </*=*/ Other.CurrentBitIndex;
}
FORCEINLINE explicit operator bool() const
{
return CurrentBitIndex < IteratedArray.NumBits;
}
FORCEINLINE int32 GetIndex() const
{
return CurrentBitIndex;
}
private:
void FindNextSetBit()
{
//InlineData is the first 16-bytes of TBitArray
const uint32* ArrayData = (IteratedArray.Data.SecondaryData ? IteratedArray.Data.SecondaryData : (uint32*)&IteratedArray.Data.InlineData);
const int32 ArrayNum = IteratedArray.NumBits;
const int32 LastDWORDIndex = (ArrayNum - 1) / NumBitsPerDWORD;
uint32 RemainingBitMask = ArrayData[this->DWORDIndex] & UnvisitedBitMask;
while (!RemainingBitMask)
{
++this->DWORDIndex;
BaseBitIndex += NumBitsPerDWORD;
if (this->DWORDIndex > LastDWORDIndex)
{
CurrentBitIndex = ArrayNum;
return;
}
RemainingBitMask = ArrayData[this->DWORDIndex];
UnvisitedBitMask = ~0;
}
const uint32 NewRemainingBitMask = RemainingBitMask & (RemainingBitMask - 1);
this->Mask = NewRemainingBitMask ^ RemainingBitMask;
CurrentBitIndex = BaseBitIndex + NumBitsPerDWORD - 1 - CountLeadingZeros(this->Mask);
if (CurrentBitIndex > ArrayNum)
{
CurrentBitIndex = ArrayNum;
}
}
};
public:
FORCEINLINE FBitIterator Iterator(int32 StartIndex)
{
return FBitIterator(*this, StartIndex);
}
FORCEINLINE FSetBitIterator SetBitIterator(int32 StartIndex)
{
return FSetBitIterator(*this, StartIndex);
}
FORCEINLINE FBitIterator begin()
{
return FBitIterator(*this, 0);
}
FORCEINLINE const FBitIterator begin() const
{
return FBitIterator(*this, 0);
}
FORCEINLINE FBitIterator end()
{
return FBitIterator(*this);
}
FORCEINLINE const FBitIterator end() const
{
return FBitIterator(*this);
}
FORCEINLINE FSetBitIterator SetBitsItBegin()
{
return FSetBitIterator(*this, 0);
}
FORCEINLINE const FSetBitIterator SetBitsItBegin() const
{
return FSetBitIterator(*this, 0);
}
FORCEINLINE const FSetBitIterator SetBitsItEnd()
{
return FSetBitIterator(*this);
}
FORCEINLINE const FSetBitIterator SetBitsItEnd() const
{
return FSetBitIterator(*this);
}
FORCEINLINE int32 Num() const
{
return NumBits;
}
FORCEINLINE int32 Max() const
{
return MaxBits;
}
FORCEINLINE bool IsSet(int32 Index) const
{
return *FBitIterator(*this, Index);
}
FORCEINLINE void Set(const int32 Index, const bool Value, bool bIsSettingAllZero = false)
{
const int32 DWORDIndex = (Index >> ((int32)5));
const int32 Mask = (1 << (Index & (((int32)32) - 1)));
if (!bIsSettingAllZero)
NumBits = Index >= NumBits ? Index < MaxBits ? Index + 1 : NumBits : NumBits;
FBitReference(Data[DWORDIndex], Mask).SetBit(Value);
}
FORCEINLINE void ZeroAll()
{
for (int i = 0; i < MaxBits; i++)
{
Set(i, false, true);
}
}
};

View File

@@ -25,5 +25,47 @@ public:
TTypeCompatibleBytes<ElementType> InlineData[NumElements];
ElementType* SecondaryData;
public:
FORCEINLINE int32 NumInlineBytes() const
{
return sizeof(ElementType) * NumElements;
}
FORCEINLINE int32 NumInlineBits() const
{
return NumInlineBytes() * 8;
}
FORCEINLINE ElementType& operator[](int32 Index)
{
return *(ElementType*)(&InlineData[Index]);
}
FORCEINLINE const ElementType& operator[](int32 Index) const
{
return *(ElementType*)(&InlineData[Index]);
}
FORCEINLINE void operator=(void* InElements)
{
SecondaryData = InElements;
}
FORCEINLINE ElementType& GetInlineElement(int32 Index)
{
return *(ElementType*)(&InlineData[Index]);
}
FORCEINLINE const ElementType& GetInlineElement(int32 Index) const
{
return *(ElementType*)(&InlineData[Index]);
}
FORCEINLINE ElementType& GetSecondaryElement(int32 Index)
{
return SecondaryData[Index];
}
FORCEINLINE const ElementType& GetSecondaryElement(int32 Index) const
{
return SecondaryData[Index];
}
};
};

View File

@@ -283,10 +283,12 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
else
{
if (Fortnite_Version >= 4)
{
SetPlaylist(PlaylistToUse, true);
auto CurrentPlaylist = GameState->GetCurrentPlaylist();
LOG_INFO(LogDev, "Set playlist to {}!", CurrentPlaylist->IsValidLowLevel() ? CurrentPlaylist->GetFullName() : "Invalid");
auto CurrentPlaylist = GameState->GetCurrentPlaylist();
LOG_INFO(LogDev, "Set playlist to {}!", CurrentPlaylist->IsValidLowLevel() ? CurrentPlaylist->GetFullName() : "Invalid");
}
}
// if (false)
@@ -424,15 +426,17 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
}
}
auto PlaylistToUse = GetPlaylistToUse();
static auto CurrentPlaylistDataOffset = GameState->GetOffset("CurrentPlaylistData", false);
if (PlaylistToUse)
auto CurrentPlaylist = CurrentPlaylistDataOffset == -1 && Fortnite_Version < 6 ? nullptr : GameState->GetCurrentPlaylist();
if (CurrentPlaylist)
{
static auto AdditionalLevelsOffset = PlaylistToUse->GetOffset("AdditionalLevels", false);
static auto AdditionalLevelsOffset = CurrentPlaylist->GetOffset("AdditionalLevels", false);
if (AdditionalLevelsOffset != -1)
{
auto& AdditionalLevels = PlaylistToUse->Get<TArray<TSoftObjectPtr<UClass>>>(AdditionalLevelsOffset);
auto& AdditionalLevels = CurrentPlaylist->Get<TArray<TSoftObjectPtr<UClass>>>(AdditionalLevelsOffset);
LOG_INFO(LogPlaylist, "Loading {} playlist levels.", AdditionalLevels.Num());
@@ -525,6 +529,10 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
float TimeSeconds = UGameplayStatics::GetTimeSeconds(GetWorld());
LOG_INFO(LogDev, "Initializing!");
if (std::floor(Fortnite_Version) == 3)
SetPlaylist(GetPlaylistToUse(), true);
LOG_INFO(LogDev, "GameMode 0x{:x}", __int64(GameMode));
GameState->Get<float>("WarmupCountdownEndTime") = TimeSeconds + Duration;
@@ -539,26 +547,6 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
GameSession->Get<int>(MaxPlayersOffset) = 100;
/*
auto AllMegaStormManagers = UGameplayStatics::GetAllActorsOfClass(GetWorld(), GameMode->Get<UClass*>("MegaStormManagerClass"));
LOG_INFO(LogDev, "AllMegaStormManagers.Num() {}", AllMegaStormManagers.Num());
if (AllMegaStormManagers.Num())
{
auto MegaStormManager = (AMegaStormManager*)AllMegaStormManagers.at(0); // GameMode->Get<AMegaStormManager*>(MegaStormManagerOffset);
LOG_INFO(LogDev, "MegaStormManager {}", __int64(MegaStormManager));
if (MegaStormManager)
{
LOG_INFO(LogDev, "MegaStormManager->GetMegaStormCircles().Num() {}", MegaStormManager->GetMegaStormCircles().Num());
}
}
*/
// GameState->Get<bool>("bGameModeWillSkipAircraft") = Globals::bGoingToPlayEvent && Fortnite_Version == 17.30;
// if (Engine_Version < 424)
GameState->OnRep_CurrentPlaylistInfo(); // ?
@@ -807,8 +795,8 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
Parts[(int)EFortCustomPartType::Head] = headPart;
Parts[(int)EFortCustomPartType::Body] = bodyPart;
if (Fortnite_Version > 2.5)
Parts[(int)EFortCustomPartType::Backpack] = backpackPart;
// if (Fortnite_Version > 2.5)
Parts[(int)EFortCustomPartType::Backpack] = backpackPart;
static auto OnRep_CharacterPartsFn = FindObject<UFunction>("/Script/FortniteGame.FortPlayerState.OnRep_CharacterParts");
PlayerStateAthena->ProcessEvent(OnRep_CharacterPartsFn);
@@ -865,16 +853,9 @@ void AFortGameModeAthena::Athena_HandleStartingNewPlayerHook(AFortGameModeAthena
{
UClass* AbilityClass = GameplayAbilities->At(i);
// LOG_INFO(LogDev, "AbilityClass {}", __int64(AbilityClass));
if (!AbilityClass)
continue;
// LOG_INFO(LogDev, "AbilityClass Name {}", AbilityClass->GetFullName());
// LOG_INFO(LogDev, "DefaultAbility {}", __int64(DefaultAbility));
// LOG_INFO(LogDev, "DefaultAbility Name {}", DefaultAbility->GetFullName());
PlayerStateAthena->GetAbilitySystemComponent()->GiveAbilityEasy(AbilityClass);
}
}

View File

@@ -23,7 +23,7 @@ std::pair<std::vector<UFortItem*>, std::vector<UFortItem*>> AFortInventory::AddI
if (LoadedAmmo == -1)
{
if (auto WeaponDef = Cast<UFortWeaponItemDefinition>(ItemDefinition))
if (auto WeaponDef = Cast<UFortWeaponItemDefinition>(ItemDefinition)) // bPreventDefaultPreload ?
LoadedAmmo = WeaponDef->GetClipSize();
else
LoadedAmmo = 0;

View File

@@ -229,125 +229,128 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, bool bPrint, int recurs
auto GameFeatureData = Object;
static auto DefaultLootTableDataOffset = GameFeatureData->GetOffset("DefaultLootTableData");
auto DefaultLootTableData = GameFeatureData->GetPtr<FFortGameFeatureLootTableData>(DefaultLootTableDataOffset);
auto LootTierDataTableStr = DefaultLootTableData->LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootTierDataTableIsComposite = LootTierDataTableStr.contains("Composite");
auto LootPackageTableStr = DefaultLootTableData->LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootPackageTableIsComposite = LootPackageTableStr.contains("Composite");
auto LootTierDataPtr = DefaultLootTableData->LootTierData.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : DataTableClass, true);
auto LootPackagePtr = DefaultLootTableData->LootPackageData.Get(LootPackageTableIsComposite ? CompositeDataTableClass : DataTableClass, true);
if (LootPackagePtr)
if (DefaultLootTableDataOffset != -1)
{
LPTables.push_back(LootPackagePtr);
}
auto DefaultLootTableData = GameFeatureData->GetPtr<FFortGameFeatureLootTableData>(DefaultLootTableDataOffset);
if (CurrentPlaylist)
{
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
auto PlaylistOverrideLootTableData = GameFeatureData->GetPtr<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
auto LootTierDataTableStr = DefaultLootTableData->LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto PlaylistOverrideLootTableData_Data = PlaylistOverrideLootTableData->Pairs.Elements.Data;
auto LootTierDataTableIsComposite = LootTierDataTableStr.contains("Composite");
auto LootPackageTableStr = DefaultLootTableData->LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto LootPackageTableIsComposite = LootPackageTableStr.contains("Composite");
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
auto LootTierDataPtr = DefaultLootTableData->LootTierData.Get(LootTierDataTableIsComposite ? CompositeDataTableClass : DataTableClass, true);
auto LootPackagePtr = DefaultLootTableData->LootPackageData.Get(LootPackageTableIsComposite ? CompositeDataTableClass : DataTableClass, true);
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
if (LootPackagePtr)
{
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
LPTables.push_back(LootPackagePtr);
}
for (int j = 0; j < PlaylistOverrideLootTableData_Data.Num(); j++)
if (CurrentPlaylist)
{
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
auto PlaylistOverrideLootTableData = GameFeatureData->GetPtr<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
auto PlaylistOverrideLootTableData_Data = PlaylistOverrideLootTableData->Pairs.Elements.Data;
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
{
auto Value = PlaylistOverrideLootTableData_Data.at(j).ElementData.Value;
auto CurrentOverrideTag = Value.First;
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
if (Tag.TagName == CurrentOverrideTag.TagName)
for (int j = 0; j < PlaylistOverrideLootTableData_Data.Num(); j++)
{
auto OverrideLootPackageTableStr = Value.Second.LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootPackageTableStr.contains("Composite");
auto Value = PlaylistOverrideLootTableData_Data.at(j).ElementData.Value;
auto CurrentOverrideTag = Value.First;
auto ptr = Value.Second.LootPackageData.Get(bOverrideIsComposite ? CompositeDataTableClass : DataTableClass, true);
if (ptr)
if (Tag.TagName == CurrentOverrideTag.TagName)
{
if (bOverrideIsComposite)
auto OverrideLootPackageTableStr = Value.Second.LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootPackageTableStr.contains("Composite");
auto ptr = Value.Second.LootPackageData.Get(bOverrideIsComposite ? CompositeDataTableClass : DataTableClass, true);
if (ptr)
{
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); z++)
if (bOverrideIsComposite)
{
auto ParentTable = ParentTables->At(z);
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
if (ParentTable)
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); z++)
{
LPTables.push_back(ParentTable);
auto ParentTable = ParentTables->At(z);
if (ParentTable)
{
LPTables.push_back(ParentTable);
}
}
}
}
LPTables.push_back(ptr);
LPTables.push_back(ptr);
}
}
}
}
}
}
if (LootTierDataPtr)
{
LTDTables.push_back(LootTierDataPtr);
}
if (CurrentPlaylist)
{
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
auto PlaylistOverrideLootTableData = GameFeatureData->GetPtr<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
auto PlaylistOverrideLootTableData_Data = PlaylistOverrideLootTableData->Pairs.Elements.Data;
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
if (LootTierDataPtr)
{
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
LTDTables.push_back(LootTierDataPtr);
}
for (int j = 0; j < PlaylistOverrideLootTableData_Data.Num(); j++)
if (CurrentPlaylist)
{
static auto PlaylistOverrideLootTableDataOffset = GameFeatureData->GetOffset("PlaylistOverrideLootTableData");
auto PlaylistOverrideLootTableData = GameFeatureData->GetPtr<TMap<FGameplayTag, FFortGameFeatureLootTableData>>(PlaylistOverrideLootTableDataOffset);
auto PlaylistOverrideLootTableData_Data = PlaylistOverrideLootTableData->Pairs.Elements.Data;
static auto GameplayTagContainerOffset = CurrentPlaylist->GetOffset("GameplayTagContainer");
auto GameplayTagContainer = CurrentPlaylist->GetPtr<FGameplayTagContainer>(GameplayTagContainerOffset);
for (int i = 0; i < GameplayTagContainer->GameplayTags.Num(); i++)
{
auto Value = PlaylistOverrideLootTableData_Data.at(j).ElementData.Value;
auto CurrentOverrideTag = Value.First;
auto& Tag = GameplayTagContainer->GameplayTags.At(i);
if (Tag.TagName == CurrentOverrideTag.TagName)
for (int j = 0; j < PlaylistOverrideLootTableData_Data.Num(); j++)
{
auto OverrideLootTierDataStr = Value.Second.LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootTierDataStr.contains("Composite");
auto Value = PlaylistOverrideLootTableData_Data.at(j).ElementData.Value;
auto CurrentOverrideTag = Value.First;
auto ptr = Value.Second.LootTierData.Get(bOverrideIsComposite ? CompositeDataTableClass : DataTableClass, true);
if (ptr)
if (Tag.TagName == CurrentOverrideTag.TagName)
{
if (bOverrideIsComposite)
auto OverrideLootTierDataStr = Value.Second.LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootTierDataStr.contains("Composite");
auto ptr = Value.Second.LootTierData.Get(bOverrideIsComposite ? CompositeDataTableClass : DataTableClass, true);
if (ptr)
{
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); z++)
if (bOverrideIsComposite)
{
auto ParentTable = ParentTables->At(z);
static auto ParentTablesOffset = ptr->GetOffset("ParentTables");
if (ParentTable)
auto ParentTables = ptr->GetPtr<TArray<UDataTable*>>(ParentTablesOffset);
for (int z = 0; z < ParentTables->size(); z++)
{
LTDTables.push_back(ParentTable);
auto ParentTable = ParentTables->At(z);
if (ParentTable)
{
LTDTables.push_back(ParentTable);
}
}
}
}
LTDTables.push_back(ptr);
LTDTables.push_back(ptr);
}
}
}
}

View File

@@ -40,7 +40,7 @@ void AFortPlayerController::ServerExecuteInventoryItemHook(AFortPlayerController
if (Engine_Version <= 420)
{
static auto OverriddenBackpackSizeOffset = PlayerController->GetOffset("OverriddenBackpackSize");
LOG_INFO(LogDev, "PlayerController->Get<int>(OverriddenBackpackSizeOffset): {}", PlayerController->Get<int>(OverriddenBackpackSizeOffset));
// LOG_INFO(LogDev, "PlayerController->Get<int>(OverriddenBackpackSizeOffset): {}", PlayerController->Get<int>(OverriddenBackpackSizeOffset));
// PlayerController->Get<int>(OverriddenBackpackSizeOffset) = 5;
// PlayerController->ForceNetUpdate();
}
@@ -220,7 +220,7 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
auto Vehicle = ReceivingActor;
ServerAttemptInteractOriginal(Context, Stack, Ret);
return;
// return;
auto Pawn = (AFortPlayerPawn*)PlayerController->GetMyFortPawn();
@@ -287,19 +287,6 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
return;
}
/*
else if (ReceivingActor->IsA(FortAthenaSupplyDropClass))
{
auto LootTierGroup = ReceivingActor->IsA(LlamaClass) ? UKismetStringLibrary::Conv_StringToName(L"Loot_AthenaLlama") : UKismetStringLibrary::Conv_StringToName(L"Loot_AthenaSupplyDrop"); // SupplyDrop->GetLootTierGroupOverride();
auto LootDrops = PickLootDrops(LootTierGroup);
for (auto& LootDrop : LootDrops)
{
AFortPickup::SpawnPickup(LootDrop.ItemDefinition, LocationToSpawnLoot, LootDrop.Count, EFortPickupSourceTypeFlag::Other, EFortPickupSpawnSource::SupplyDrop);
}
}
*/
return ServerAttemptInteractOriginal(Context, Stack, Ret);
}

View File

@@ -10,12 +10,29 @@
struct FFortAthenaLoadout
{
static UStruct* GetStruct()
{
static auto Struct = FindObject<UStruct>("/Script/FortniteGame.FortAthenaLoadout");
return Struct;
}
static int GetStructSize()
{
return GetStruct()->GetPropertiesSize();
}
UObject*& GetCharacter()
{
static auto CharacterOffset = FindOffsetStruct("/Script/FortniteGame.FortAthenaLoadout", "Character");
return *(UObject**)(__int64(this) + CharacterOffset);
}
UObject*& GetBackpack()
{
static auto BackpackOffset = FindOffsetStruct("/Script/FortniteGame.FortAthenaLoadout", "Backpack");
return *(UObject**)(__int64(this) + BackpackOffset);
}
UObject*& GetPickaxe()
{
static auto PickaxeOffset = FindOffsetStruct("/Script/FortniteGame.FortAthenaLoadout", "Pickaxe");

View File

@@ -72,12 +72,19 @@ void AFortPlayerControllerAthena::ServerAcknowledgePossessionHook(APlayerControl
auto PawnAsFort = Cast<AFortPlayerPawn>(Pawn);
auto PlayerStateAsFort = Cast<AFortPlayerState>(Pawn->GetPlayerState());
if (Globals::bNoMCP)
return;
if (!PawnAsFort)
return;
if (Globals::bNoMCP)
{
static auto CustomCharacterPartClass = FindObject<UClass>("/Script/FortniteGame.CustomCharacterPart");
static auto backpackPart = LoadObject("/Game/Characters/CharacterParts/Backpacks/NoBackpack.NoBackpack", CustomCharacterPartClass);
// PawnAsFort->ServerChoosePart(EFortCustomPartType::Backpack, backpackPart);
return;
}
static auto UpdatePlayerCustomCharacterPartsVisualizationFn = FindObject<UFunction>("/Script/FortniteGame.FortKismetLibrary.UpdatePlayerCustomCharacterPartsVisualization");
if (!UpdatePlayerCustomCharacterPartsVisualizationFn)
@@ -85,8 +92,41 @@ void AFortPlayerControllerAthena::ServerAcknowledgePossessionHook(APlayerControl
auto CosmeticLoadout = ControllerAsFort->GetCosmeticLoadout();
if (CosmeticLoadout)
{
/* static auto Pawn_CosmeticLoadoutOffset = PawnAsFort->GetOffset("CosmeticLoadout");
if (Pawn_CosmeticLoadoutOffset != -1)
{
CopyStruct(PawnAsFort->GetPtr<__int64>(Pawn_CosmeticLoadoutOffset), CosmeticLoadout, FFortAthenaLoadout::GetStructSize());
} */
ApplyCID(PawnAsFort, CosmeticLoadout->GetCharacter());
auto Backpack = CosmeticLoadout->GetBackpack();
if (Backpack)
{
static auto CharacterPartsOffset = Backpack->GetOffset("CharacterParts");
if (CharacterPartsOffset != -1)
{
auto& BackpackCharacterParts = Backpack->Get<TArray<UObject*>>(CharacterPartsOffset);
for (int i = 0; i < BackpackCharacterParts.Num(); i++)
{
auto BackpackCharacterPart = BackpackCharacterParts.at(i);
if (!BackpackCharacterPart)
continue;
PawnAsFort->ServerChoosePart(EFortCustomPartType::Backpack, BackpackCharacterPart);
}
// UFortKismetLibrary::ApplyCharacterCosmetics(GetWorld(), BackpackCharacterParts, PlayerStateAsFort, &aa);
}
}
}
return;
}

View File

@@ -26,7 +26,8 @@ static void ApplyCID(AFortPlayerPawn* Pawn, UObject* CID)
{
auto& SpecializationSoft = Specializations.at(i);
auto Specialization = SpecializationSoft.Get();
static auto FortHeroSpecializationClass = FindObject<UClass>("/Script/FortniteGame.FortHeroSpecialization");
auto Specialization = SpecializationSoft.Get(FortHeroSpecializationClass, true);
if (Specialization)
{
@@ -40,7 +41,8 @@ static void ApplyCID(AFortPlayerPawn* Pawn, UObject* CID)
for (int z = 0; z < CharacterParts.Num(); z++)
{
auto& CharacterPartSoft = CharacterParts.at(z);
auto CharacterPart = CharacterPartSoft.Get();
static auto CustomCharacterPartClass = FindObject<UClass>("/Script/FortniteGame.CustomCharacterPart");
auto CharacterPart = CharacterPartSoft.Get(CustomCharacterPartClass, true);
CharacterPartsaa.Add(CharacterPart);

View File

@@ -14,7 +14,7 @@ void AFortPlayerPawn::ServerChoosePart(EFortCustomPartType Part, UObject* Chosen
this->ProcessEvent(fn, &AFortPlayerPawn_ServerChoosePart_Params);
}
void AFortPlayerPawn::ForceLaunchPlayerZiplinine() // Thanks android
void AFortPlayerPawn::ForceLaunchPlayerZipline() // Thanks android
{
float ZiplineJumpDampening = -0.5f;
float ZiplineJumpStrength = 1500.f;
@@ -70,7 +70,7 @@ void AFortPlayerPawn::ServerSendZiplineStateHook(AFortPlayerPawn* Pawn, FZipline
{
if ((*(bool*)(__int64(PawnZiplineState) + bJumpedOffset)))
{
Pawn->ForceLaunchPlayerZiplinine();
Pawn->ForceLaunchPlayerZipline();
}
}
}

View File

@@ -23,7 +23,7 @@ class AFortPlayerPawn : public AFortPawn
{
public:
void ServerChoosePart(EFortCustomPartType Part, class UObject* ChosenCharacterPart);
void ForceLaunchPlayerZiplinine(); // Thanks android
void ForceLaunchPlayerZipline(); // Thanks android
static void ServerSendZiplineStateHook(AFortPlayerPawn* Pawn, FZiplinePawnState InZiplineState);
static void ServerHandlePickupHook(AFortPlayerPawn* Pawn, AFortPickup* Pickup, float InFlyTime, FVector InStartDirection, bool bPlayPickupSound);

View File

@@ -0,0 +1,25 @@
#include "Level.h"
UWorld*& ULevel::GetOwningWorld()
{
static auto OwningWorldOffset = GetOffset("OwningWorld");
return Get<UWorld*>(OwningWorldOffset);
}
bool ULevel::HasVisibilityChangeRequestPending()
{
// I believe implementation on this changes depending on the version
auto OwningWorld = GetOwningWorld();
if (!OwningWorld)
return false;
static auto CurrentLevelPendingVisibilityOffset = OwningWorld->GetOffset("CurrentLevelPendingVisibility");
auto CurrentLevelPendingVisibility = OwningWorld->Get<ULevel*>(CurrentLevelPendingVisibilityOffset);
static auto CurrentLevelPendingInvisibilityOffset= OwningWorld->GetOffset("CurrentLevelPendingInvisibility");
auto CurrentLevelPendingInvisibility = OwningWorld->Get<ULevel*>(CurrentLevelPendingInvisibilityOffset);
return this == CurrentLevelPendingVisibility || this == CurrentLevelPendingInvisibility;
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include "World.h"
class ULevel : public UObject
{
public:
UWorld*& GetOwningWorld();
bool HasVisibilityChangeRequestPending();
};

View File

@@ -5,6 +5,20 @@
#include "NetConnection.h"
#include "FortPlayerControllerAthena.h"
#include "GameplayStatics.h"
#include "KismetMathLibrary.h"
#include <random>
FNetworkObjectList& UNetDriver::GetNetworkObjectList()
{
return *(*(TSharedPtr<FNetworkObjectList>*)(__int64(this) + 0x490));
}
void UNetDriver::RemoveNetworkActor(AActor* Actor)
{
GetNetworkObjectList().Remove(Actor);
// RenamedStartupActors.Remove(Actor->GetFName());
}
void UNetDriver::TickFlushHook(UNetDriver* NetDriver)
{
@@ -34,7 +48,7 @@ int32 ServerReplicateActors_PrepConnections(UNetDriver* NetDriver)
for (int32 ConnIdx = 0; ConnIdx < ClientConnections.Num(); ConnIdx++)
{
UNetConnection* Connection = ClientConnections.at(ConnIdx);
// check(Connection);
if (!Connection) continue;
// check(Connection->State == USOCK_Pending || Connection->State == USOCK_Open || Connection->State == USOCK_Closed);
// checkSlow(Connection->GetUChildConnection() == NULL);
@@ -42,13 +56,8 @@ int32 ServerReplicateActors_PrepConnections(UNetDriver* NetDriver)
if (OwningActor != NULL) // && /* Connection->State == USOCK_Open && */ (Connection->Driver->Time - Connection->LastReceiveTime < 1.5f))
{
// check(World == OwningActor->GetWorld());
bFoundReadyConnection = true;
// the view target is what the player controller is looking at OR the owning actor itself when using beacons
// Connection->GetViewTarget() = Connection->GetPlayerController() ? Connection->GetPlayerController()->GetViewTarget() : OwningActor;
AActor* DesiredViewTarget = OwningActor;
if (Connection->GetPlayerController())
@@ -90,42 +99,61 @@ enum class ENetDormancy : uint8_t
ENetDormancy_MAX = 6
};
struct FNetworkObjectInfo
FORCEINLINE float FRand()
{
AActor* Actor;
/* TWeakObjectPtr<AActor> WeakActor;
double NextUpdateTime;
double LastNetReplicateTime;
float OptimalNetUpdateDelta;
float LastNetUpdateTime;
uint32 bPendingNetUpdate : 1;
uint32 bForceRelevantNextUpdate : 1;
TSet<TWeakObjectPtr<UNetConnection>> DormantConnections;
TSet<TWeakObjectPtr<UNetConnection>> RecentlyDormantConnections; */
};
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0, 1);
float random_number = dis(gen);
static void ServerReplicateActors_BuildConsiderList(UNetDriver* NetDriver, std::vector<FNetworkObjectInfo*>& OutConsiderList)
return random_number;
}
#define USEOBJECTLIST
void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList)
{
std::vector<AActor*> ActorsToRemove;
#ifdef USEOBJECTLIST
auto& ActiveObjects = GetNetworkObjectList().ActiveNetworkObjects;
#else
TArray<AActor*> Actors = UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass());
#endif
/* auto& ActiveObjects = GetNetworkObjectList(NetDriver).ActiveNetworkObjects;
auto World = GetWorld();
for (int i = 0; i < ActiveObjects.Num(); i++)
#ifdef USEOBJECTLIST
// for (int i = 0; i < ActiveObjects.Elements.Num(); i++)
for (const TSharedPtr<FNetworkObjectInfo>& ActorInfo : ActiveObjects)
{
auto ActorInfo = ActiveObjects.GetElements().GetData()[i].ElementData.Value.Get();
auto Actor = ActorInfo->Actor; */
// auto& ActorInfo = ActiveObjects.Elements.Data.at(i).ElementData.Value;
if (!ActorInfo->bPendingNetUpdate && UGameplayStatics::GetTimeSeconds(GetWorld()) <= ActorInfo->NextUpdateTime)
{
continue;
}
// if (IsBadReadPtr(ActorInfo, 8))
// continue;
auto Actor = ActorInfo->Actor;
#else
for (int i = 0; i < Actors.Num(); i++)
{
auto Actor = Actors.at(i);
#endif
if (!Actor)
continue;
// if (!Actor->bActorInitialized) continue;
if (Actor->IsActorBeingDestroyed())
if (Actor->IsPendingKillPending())
// if (Actor->IsPendingKill())
{
ActorsToRemove.push_back(Actor);
continue;
}
@@ -133,25 +161,93 @@ static void ServerReplicateActors_BuildConsiderList(UNetDriver* NetDriver, std::
if (Actor->Get<ENetRole>(RemoteRoleOffset) == ENetRole::ROLE_None)
{
ActorsToRemove.push_back(Actor);
continue;
}
// We should add a NetDriverName check but I don't believe it is needed.
// We should check if the actor is initialized here.
// We should check the level stuff here.
static auto NetDormancyOffset = Actor->GetOffset("NetDormancy");
if (Actor->Get<ENetDormancy>(NetDormancyOffset) == ENetDormancy::DORM_Initial && Actor->IsNetStartup())
if (Actor->Get<ENetDormancy>(NetDormancyOffset) == ENetDormancy::DORM_Initial && Actor->IsNetStartupActor()) // IsDormInitialStartupActor
{
continue;
}
static void (*CallPreReplication)(AActor*, UNetDriver*) = decltype(CallPreReplication)(Addresses::CallPreReplication);
CallPreReplication(Actor, NetDriver);
// We should check NeedsLoadForClient here.
// We should make sure the actor is in the same world here but I don't believe it is needed.
#ifndef USEOBJECTLIST
FNetworkObjectInfo* ActorInfo = new FNetworkObjectInfo;
ActorInfo->Actor = Actor;
OutConsiderList.push_back(ActorInfo);
#else
auto TimeSeconds = UGameplayStatics::GetTimeSeconds(World); // Can we do this outside of the loop?
if (ActorInfo->LastNetReplicateTime == 0)
{
ActorInfo->LastNetReplicateTime = UGameplayStatics::GetTimeSeconds(World);
ActorInfo->OptimalNetUpdateDelta = 1.0f / Actor->GetNetUpdateFrequency();
}
const float ScaleDownStartTime = 2.0f;
const float ScaleDownTimeRange = 5.0f;
const float LastReplicateDelta = TimeSeconds - ActorInfo->LastNetReplicateTime;
if (LastReplicateDelta > ScaleDownStartTime)
{
static auto MinNetUpdateFrequencyOffset = Actor->GetOffset("MinNetUpdateFrequency");
if (Actor->Get<float>(MinNetUpdateFrequencyOffset) == 0.0f)
{
Actor->Get<float>(MinNetUpdateFrequencyOffset) = 2.0f;
}
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency(); // Don't go faster than NetUpdateFrequency
const float MaxOptimalDelta = max(1.0f / Actor->GetNetUpdateFrequency(), MinOptimalDelta); // Don't go slower than MinNetUpdateFrequency (or NetUpdateFrequency if it's slower)
const float Alpha = std::clamp((LastReplicateDelta - ScaleDownStartTime) / ScaleDownTimeRange, 0.0f, 1.0f); // should we use fmath?
ActorInfo->OptimalNetUpdateDelta = std::lerp(MinOptimalDelta, MaxOptimalDelta, Alpha); // should we use fmath?
}
if (!ActorInfo->bPendingNetUpdate)
{
constexpr bool bUseAdapativeNetFrequency = false;
const float NextUpdateDelta = bUseAdapativeNetFrequency ? ActorInfo->OptimalNetUpdateDelta : 1.0f / Actor->GetNetUpdateFrequency();
// then set the next update time
float ServerTickTime = 1.f / 30;
ActorInfo->NextUpdateTime = TimeSeconds + FRand() * ServerTickTime + NextUpdateDelta;
static auto TimeOffset = GetOffset("Time");
ActorInfo->LastNetUpdateTime = Get<float>(TimeOffset);
}
ActorInfo->bPendingNetUpdate = false;
#endif
OutConsiderList.push_back(ActorInfo.Get());
static void (*CallPreReplication)(AActor*, UNetDriver*) = decltype(CallPreReplication)(Addresses::CallPreReplication);
CallPreReplication(Actor, this);
}
#ifndef USEOBJECTLIST
Actors.Free();
#else
for (auto Actor : ActorsToRemove)
{
if (!Actor)
continue;
/* LOG_INFO(LogDev, "Removing actor: {}", Actor ? Actor->GetFullName() : "InvalidObject");
RemoveNetworkActor(Actor);
LOG_INFO(LogDev, "Finished removing actor."); */
}
#endif
}
using UChannel = UObject;
@@ -272,16 +368,21 @@ int32 UNetDriver::ServerReplicateActors()
}
else */
{
ServerTickTime = 1.f / ServerTickTime; // 0
ServerTickTime = 1.f / ServerTickTime;
// bCPUSaturated = DeltaSeconds > 1.2f * ServerTickTime;
}
std::vector<FNetworkObjectInfo*> ConsiderList;
// ConsiderList.reserve(GetNetworkObjectList(NetDriver).ActiveNetworkObjects.Num());
#ifdef USEOBJECTLIST
ConsiderList.reserve(GetNetworkObjectList().ActiveNetworkObjects.Num());
#endif
// std::cout << "ConsiderList.size(): " << GetNetworkObjectList(NetDriver).ActiveNetworkObjects.Num() << '\n';
ServerReplicateActors_BuildConsiderList(this, ConsiderList);
auto World = GetWorld();
ServerReplicateActors_BuildConsiderList(ConsiderList);
for (int32 i = 0; i < this->GetClientConnections().Num(); i++)
{
@@ -347,15 +448,35 @@ int32 UNetDriver::ServerReplicateActors()
Channel = (UActorChannel*)CreateChannel(Connection, 2, true, -1);
if (Channel) {
if (Channel)
{
SetChannelActor(Channel, Actor);
// Channel->Connection = Connection;
}
#ifdef USEOBJECTLIST
if (Actor->GetNetUpdateFrequency() < 1.0f)
{
ActorInfo->NextUpdateTime = UGameplayStatics::GetTimeSeconds(GetWorld()) + 0.2f * FRand();
}
#endif
}
if (Channel)
ReplicateActor(Channel);
{
if (ReplicateActor(Channel))
{
#ifdef USEOBJECTLIST
auto TimeSeconds = UGameplayStatics::GetTimeSeconds(World);
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency();
const float MaxOptimalDelta = max(1.0f / Actor->GetMinNetUpdateFrequency(), MinOptimalDelta);
const float DeltaBetweenReplications = (TimeSeconds - ActorInfo->LastNetReplicateTime);
// Choose an optimal time, we choose 70% of the actual rate to allow frequency to go up if needed
ActorInfo->OptimalNetUpdateDelta = std::clamp(DeltaBetweenReplications * 0.7f, MinOptimalDelta, MaxOptimalDelta); // should we use fmath?
ActorInfo->LastNetReplicateTime = TimeSeconds;
#endif
}
}
}
}

View File

@@ -7,6 +7,71 @@
#include "NetConnection.h"
#include "Array.h"
#include "WeakObjectPtrTemplates.h"
#include "Map.h"
#include "SharedPointer.h"
#include "Level.h"
struct FActorDestructionInfo
{
TWeakObjectPtr<ULevel> Level;
TWeakObjectPtr<UObject> ObjOuter;
FVector DestroyedPosition;
int32 NetGUID;
FString PathName;
FName StreamingLevelName;
};
struct FNetworkObjectInfo
{
/** Pointer to the replicated actor. */
AActor* Actor;
/** WeakPtr to actor. This is cached here to prevent constantly constructing one when needed for (things like) keys in TMaps/TSets */
TWeakObjectPtr<AActor> WeakActor;
/** Next time to consider replicating the actor. Based on FPlatformTime::Seconds(). */
double NextUpdateTime;
/** Last absolute time in seconds since actor actually sent something during replication */
double LastNetReplicateTime;
/** Optimal delta between replication updates based on how frequently actor properties are actually changing */
float OptimalNetUpdateDelta;
/** Last time this actor was updated for replication via NextUpdateTime
* @warning: internal net driver time, not related to WorldSettings.TimeSeconds */
float LastNetUpdateTime;
/** Is this object still pending a full net update due to clients that weren't able to replicate the actor at the time of LastNetUpdateTime */
uint32 bPendingNetUpdate : 1;
/** Force this object to be considered relevant for at least one update */
uint32 bForceRelevantNextUpdate : 1;
/** List of connections that this actor is dormant on */
TSet<TWeakObjectPtr<UNetConnection>> DormantConnections;
/** A list of connections that this actor has recently been dormant on, but the actor doesn't have a channel open yet.
* These need to be differentiated from actors that the client doesn't know about, but there's no explicit list for just those actors.
* (this list will be very transient, with connections being moved off the DormantConnections list, onto this list, and then off once the actor has a channel again)
*/
TSet<TWeakObjectPtr<UNetConnection>> RecentlyDormantConnections;
};
class FNetworkObjectList
{
public:
typedef TSet<TSharedPtr<FNetworkObjectInfo>> FNetworkObjectSet;
FNetworkObjectSet AllNetworkObjects;
FNetworkObjectSet ActiveNetworkObjects;
FNetworkObjectSet ObjectsDormantOnAllConnections;
TMap<TWeakObjectPtr<UNetConnection>, int32> NumDormantObjectsPerConnection;
void Remove(AActor* const Actor);
};
class UWorld;
struct FURL // idk where this actually goes
@@ -37,7 +102,10 @@ public:
return Get<TArray<UNetConnection*>>(ClientConnectionsOffset);
}
void RemoveNetworkActor(AActor* Actor);
bool InitListen(FNetworkNotify* InNotify, FURL& ListenURL, bool bReuseAddressAndPort, FString& Error) { return InitListenOriginal(this, InNotify, ListenURL, bReuseAddressAndPort, Error); }
void SetWorld(UWorld* World) { return SetWorldOriginal(this, World); }
int32 ServerReplicateActors();
void ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList);
FNetworkObjectList& GetNetworkObjectList();
};

View File

@@ -0,0 +1,107 @@
#include "NetDriver.h"
void FNetworkObjectList::Remove(AActor* const Actor)
{
if (Actor == nullptr)
{
return;
}
TSharedPtr<FNetworkObjectInfo>* NetworkObjectInfoPtr = nullptr;
for (int i = 0; i < AllNetworkObjects.Num(); i++)
{
auto& CurrentNetworkObject = AllNetworkObjects[i];
if (CurrentNetworkObject->Actor == Actor)
{
NetworkObjectInfoPtr = &CurrentNetworkObject;
break;
}
}
if (NetworkObjectInfoPtr == nullptr)
{
// Sanity check that we're not on the other lists either
// check(!ActiveNetworkObjects.Contains(Actor));
// check(!ObjectsDormantOnAllConnections.Contains(Actor));
// check((ActiveNetworkObjects.Num() + ObjectsDormantOnAllConnections.Num()) == AllNetworkObjects.Num());
return;
}
FNetworkObjectInfo* NetworkObjectInfo = NetworkObjectInfoPtr->Get();
for (int i = 0; i < NetworkObjectInfo->DormantConnections.Num(); i++)
{
auto& ConnectionIt = NetworkObjectInfo->DormantConnections[i];
UNetConnection* Connection = ConnectionIt.Get();
if (Connection == nullptr) // || Connection->State == USOCK_Closed)
{
NetworkObjectInfo->DormantConnections.Remove(i);
// ConnectionIt.RemoveCurrent();
continue;
}
int32* NumDormantObjectsPerConnectionRef = nullptr;
for (int z = 0; z < NumDormantObjectsPerConnection.Pairs.Num(); z++)
{
auto& Pair = NumDormantObjectsPerConnection.Pairs[z];
if (Pair.First.ObjectIndex == Connection->InternalIndex)
{
NumDormantObjectsPerConnectionRef = &Pair.Second;
break;
}
}
if (!NumDormantObjectsPerConnectionRef)
{
// We should add here TODO MILXNOR
}
// check(NumDormantObjectsPerConnectionRef > 0);
if (NumDormantObjectsPerConnectionRef)
(*NumDormantObjectsPerConnectionRef)--;
}
// Remove this object from all lists
for (int i = 0; i < AllNetworkObjects.Num(); i++)
{
auto& CurrentNetworkObject = AllNetworkObjects[i];
if (CurrentNetworkObject->Actor == Actor)
{
AllNetworkObjects.Remove(i);
break;
}
}
for (int i = 0; i < ActiveNetworkObjects.Num(); i++)
{
auto& CurrentActiveNetworkObject = ActiveNetworkObjects[i];
if (CurrentActiveNetworkObject->Actor == Actor)
{
ActiveNetworkObjects.Remove(i);
break;
}
}
for (int i = 0; i < ObjectsDormantOnAllConnections.Num(); i++)
{
auto& CurrentDormantObject = ObjectsDormantOnAllConnections[i];
if (CurrentDormantObject->Actor == Actor)
{
ObjectsDormantOnAllConnections.Remove(i);
break;
}
}
// check((ActiveNetworkObjects.Num() + ObjectsDormantOnAllConnections.Num()) == AllNetworkObjects.Num());
}

View File

@@ -132,4 +132,9 @@ bool UObject::IsValidLowLevel()
return false;
}
return ChunkedObjects ? ChunkedObjects->IsValid(this) : UnchunkedObjects ? UnchunkedObjects->IsValid(this) : false;
}
FORCEINLINE bool UObject::IsPendingKill() const
{
return ChunkedObjects ? ChunkedObjects->GetItemByIndex(InternalIndex)->IsPendingKill() : UnchunkedObjects ? UnchunkedObjects->GetItemByIndex(InternalIndex)->IsPendingKill() : false;
}

View File

@@ -90,6 +90,25 @@ public:
void AddToRoot();
bool IsValidLowLevel();
FORCEINLINE bool IsPendingKill() const;
// static class UClass* StaticClass();
};
};
/* struct FInternalUObjectBaseUtilityIsValidFlagsChecker
{
FORCEINLINE static bool CheckObjectValidBasedOnItsFlags(const UObject* Test)
{
// Here we don't really check if the flags match but if the end result is the same
checkSlow(GUObjectArray.IndexToObject(Test->InternalIndex)->HasAnyFlags(EInternalObjectFlags::PendingKill | EInternalObjectFlags::Garbage) == Test->HasAnyFlags(RF_InternalPendingKill | RF_InternalGarbage));
return !Test->HasAnyFlags(RF_InternalPendingKill | RF_InternalGarbage);
}
}; */
FORCEINLINE bool IsValidChecked(const UObject* Test)
{
// if (!Test)
// return false;
return true; // FInternalUObjectBaseUtilityIsValidFlagsChecker::CheckObjectValidBasedOnItsFlags(Test);
}

View File

@@ -50,6 +50,7 @@ enum class EInternalObjectFlags : int
AsyncLoading = 1 << 27, ///< Object is being asynchronously loaded.
Unreachable = 1 << 28, ///< Object is not reachable on the object graph.
// PendingKill UE_DEPRECATED(5.0, "PendingKill flag should no longer be used. Use Garbage flag instead.") = 1 << 29, ///< Objects that are pending destruction (invalid for gameplay but valid objects). This flag is mirrored in EObjectFlags as RF_PendingKill for performance
PendingKill = 1 << 29,
RootSet = 1 << 30, ///< Object will not be garbage collected, even if unreferenced.
PendingConstruction = 1 << 31 ///< Object didn't have its class constructor called yet (only the UObjectBase one to initialize its most basic members)

View File

@@ -209,10 +209,12 @@
<ClCompile Include="InventoryManagementLibrary.cpp" />
<ClCompile Include="KismetMathLibrary.cpp" />
<ClCompile Include="KismetStringLibrary.cpp" />
<ClCompile Include="Level.cpp" />
<ClCompile Include="LevelActor.cpp" />
<ClCompile Include="NameTypes.cpp" />
<ClCompile Include="NetConnection.h" />
<ClCompile Include="NetDriver.cpp" />
<ClCompile Include="NetworkObjectList.cpp" />
<ClCompile Include="Object.cpp" />
<ClCompile Include="PlayerController.cpp" />
<ClCompile Include="PlayerState.cpp" />
@@ -295,6 +297,7 @@
<ClInclude Include="KismetMathLibrary.h" />
<ClInclude Include="KismetStringLibrary.h" />
<ClInclude Include="KismetSystemLibrary.h" />
<ClInclude Include="Level.h" />
<ClInclude Include="log.h" />
<ClInclude Include="Map.h" />
<ClInclude Include="MegaStormManager.h" />
@@ -315,6 +318,7 @@
<ClInclude Include="Rotator.h" />
<ClInclude Include="ScriptInterface.h" />
<ClInclude Include="Set.h" />
<ClInclude Include="SharedPointer.h" />
<ClInclude Include="SoftObjectPath.h" />
<ClInclude Include="SoftObjectPtr.h" />
<ClInclude Include="SparseArray.h" />
@@ -328,6 +332,7 @@
<ClInclude Include="Vector.h" />
<ClInclude Include="vehicles.h" />
<ClInclude Include="WeakObjectPtr.h" />
<ClInclude Include="WeakObjectPtrTemplates.h" />
<ClInclude Include="World.h" />
</ItemGroup>
<ItemGroup>

View File

@@ -167,6 +167,12 @@
<ClCompile Include="FortPlayerStateAthena.cpp">
<Filter>FortniteGame\Source\FortniteGame\Private\Player</Filter>
</ClCompile>
<ClCompile Include="Level.cpp">
<Filter>Engine\Source\Runtime\Engine\Private</Filter>
</ClCompile>
<ClCompile Include="NetworkObjectList.cpp">
<Filter>Engine\Source\Runtime\Engine\Private</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="log.h" />
@@ -482,6 +488,15 @@
<ClInclude Include="FortQuickBars.h">
<Filter>FortniteGame\Source\FortniteGame\Public\Items</Filter>
</ClInclude>
<ClInclude Include="WeakObjectPtrTemplates.h">
<Filter>Engine\Source\Runtime\CoreUObject\Public\UObject</Filter>
</ClInclude>
<ClInclude Include="SharedPointer.h">
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
</ClInclude>
<ClInclude Include="Level.h">
<Filter>Engine\Source\Runtime\Engine\Classes\Engine</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="Engine">
@@ -628,9 +643,6 @@
<Filter Include="Engine\Source\Runtime\GameplayTags\Classes">
<UniqueIdentifier>{247d4c62-23f7-4964-8879-5a0d65c44a73}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Runtime\Core\Public\Templates">
<UniqueIdentifier>{31a7f342-8b7c-4594-a24d-c4dd5c9d230d}</UniqueIdentifier>
</Filter>
<Filter Include="FortniteGame\Source\FortniteGame\Public\Weapons">
<UniqueIdentifier>{bcb0d983-0b85-4ca6-9fac-6567c7d79921}</UniqueIdentifier>
</Filter>
@@ -667,6 +679,9 @@
<Filter Include="Engine\Source\Runtime\CoreUObject\Public\Misc">
<UniqueIdentifier>{915f7622-6003-445e-a43f-04d5c7e13b49}</UniqueIdentifier>
</Filter>
<Filter Include="Engine\Source\Runtime\Core\Public\Templates">
<UniqueIdentifier>{31a7f342-8b7c-4594-a24d-c4dd5c9d230d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<None Include="UnrealEngine.cpp">

View File

@@ -32,7 +32,173 @@ public:
}
};
template<typename InElementType> //, typename KeyFuncs, typename Allocator>
template <typename SetType>
class TSet
{
private:
friend TSparseArray;
public:
typedef TSetElement<SetType> ElementType;
typedef TSparseArrayElementOrListLink<ElementType> ArrayElementType;
public:
TSparseArray<ElementType> Elements;
mutable TInlineAllocator<1>::ForElementType<int> Hash;
mutable int32 HashSize;
public:
class FBaseIterator
{
private:
TSet<SetType>& IteratedSet;
TSparseArray<ElementType>::FBaseIterator ElementIt;
public:
FORCEINLINE FBaseIterator(const TSet<SetType>& InSet, TSparseArray<TSetElement<SetType>>::FBaseIterator InElementIt)
: IteratedSet(const_cast<TSet<SetType>&>(InSet))
, ElementIt(InElementIt)
{
}
FORCEINLINE explicit operator bool() const
{
return (bool)ElementIt;
}
FORCEINLINE TSet<SetType>::FBaseIterator& operator++()
{
++ElementIt;
return *this;
}
FORCEINLINE bool operator==(const TSet<SetType>::FBaseIterator& OtherIt) const
{
return ElementIt == OtherIt.ElementIt;
}
FORCEINLINE bool operator!=(const TSet<SetType>::FBaseIterator& OtherIt) const
{
return ElementIt != OtherIt.ElementIt;
}
FORCEINLINE TSet<SetType>::FBaseIterator& operator=(TSet<SetType>::FBaseIterator& OtherIt)
{
return ElementIt = OtherIt.ElementIt;
}
FORCEINLINE SetType& operator*()
{
return (*ElementIt).Value;
}
FORCEINLINE const SetType& operator*() const
{
return &((*ElementIt).Value);
}
FORCEINLINE SetType* operator->()
{
return &((*ElementIt).Value);
}
FORCEINLINE const SetType* operator->() const
{
return &(*ElementIt).Value;
}
FORCEINLINE const int32 GetIndex() const
{
return ElementIt.GetIndex();
}
FORCEINLINE ElementType& GetSetElement()
{
return *ElementIt;
}
FORCEINLINE const ElementType& GetSetElement() const
{
return *ElementIt;
}
FORCEINLINE bool IsElementValid() const
{
return ElementIt.IsElementValid();
}
};
public:
FORCEINLINE TSet<SetType>::FBaseIterator begin()
{
return TSet<SetType>::FBaseIterator(*this, Elements.begin());
}
FORCEINLINE const TSet<SetType>::FBaseIterator begin() const
{
return TSet<SetType>::FBaseIterator(*this, Elements.begin());
}
FORCEINLINE TSet<SetType>::FBaseIterator end()
{
return TSet<SetType>::FBaseIterator(*this, Elements.end());
}
FORCEINLINE const TSet<SetType>::FBaseIterator end() const
{
return TSet<SetType>::FBaseIterator(*this, Elements.end());
}
FORCEINLINE SetType& operator[](int Index)
{
return Elements[Index].ElementData.Value;
}
FORCEINLINE int32 Num() const
{
return Elements.Num();
}
FORCEINLINE bool IsValid() const
{
return Elements.Data.Data != nullptr && Elements.AllocationFlags.MaxBits > 0;
}
FORCEINLINE TSparseArray<ElementType>& GetElements()
{
return Elements;
}
FORCEINLINE const TSparseArray<ElementType>& GetElements() const
{
return Elements;
}
FORCEINLINE const TBitArray& GetAllocationFlags() const
{
return Elements.GetAllocationFlags();
}
FORCEINLINE bool IsIndexValid(int32 IndexToCheck) const
{
return Elements.IsIndexValid(IndexToCheck);
}
FORCEINLINE const bool Contains(const SetType& ElementToLookFor) const
{
if (Num() <= 0)
return false;
for (SetType Element : *this)
{
if (Element == ElementToLookFor)
return true;
}
return false;
}
FORCEINLINE const int32 Find(const SetType& ElementToLookFor) const
{
for (auto It = this->begin(); It != this->end(); ++It)
{
if (*It == ElementToLookFor)
{
return It.GetIndex();
}
}
return -1;
}
FORCEINLINE bool Remove(const SetType& ElementToRemove)
{
return Elements.RemoveAt(Find(ElementToRemove));
}
FORCEINLINE bool Remove(int Index)
{
return Elements.RemoveAt(Index);
}
};
/* template<typename InElementType> //, typename KeyFuncs, typename Allocator>
class TSet
{
public:
@@ -43,4 +209,4 @@ public:
mutable TInlineAllocator<1>::ForElementType<int> Hash;
mutable int32 HashSize;
};
}; */

View File

@@ -0,0 +1,36 @@
#pragma once
template< class ObjectType>
class TSharedPtr
{
public:
ObjectType* Object;
int32 SharedReferenceCount;
int32 WeakReferenceCount;
FORCEINLINE ObjectType* Get()
{
return Object;
}
FORCEINLINE ObjectType* Get() const
{
return Object;
}
FORCEINLINE ObjectType& operator*()
{
return *Object;
}
FORCEINLINE const ObjectType& operator*() const
{
return *Object;
}
FORCEINLINE ObjectType* operator->()
{
return Object;
}
FORCEINLINE ObjectType* operator->() const
{
return Object;
}
};

View File

@@ -50,6 +50,86 @@ public:
int32 FirstFreeIndex;
int32 NumFreeIndices;
FORCEINLINE int32 Num() const
{
return Data.Num() - NumFreeIndices;
}
class FBaseIterator
{
private:
TSparseArray<ArrayType>& IteratedArray;
TBitArray::FSetBitIterator BitArrayIt;
public:
FORCEINLINE FBaseIterator(const TSparseArray<ArrayType>& Array, const TBitArray::FSetBitIterator BitIterator)
: IteratedArray(const_cast<TSparseArray<ArrayType>&>(Array))
, BitArrayIt(const_cast<TBitArray::FSetBitIterator&>(BitIterator))
{
}
FORCEINLINE explicit operator bool() const
{
return (bool)BitArrayIt;
}
FORCEINLINE TSparseArray<ArrayType>::FBaseIterator& operator++()
{
++BitArrayIt;
return *this;
}
FORCEINLINE ArrayType& operator*()
{
return IteratedArray[BitArrayIt.GetIndex()].ElementData;
}
FORCEINLINE const ArrayType& operator*() const
{
return IteratedArray[BitArrayIt.GetIndex()].ElementData;
}
FORCEINLINE ArrayType* operator->()
{
return &IteratedArray[BitArrayIt.GetIndex()].ElementData;
}
FORCEINLINE const ArrayType* operator->() const
{
return &IteratedArray[BitArrayIt.GetIndex()].ElementData;
}
FORCEINLINE bool operator==(const TSparseArray<ArrayType>::FBaseIterator& Other) const
{
return BitArrayIt == Other.BitArrayIt;
}
FORCEINLINE bool operator!=(const TSparseArray<ArrayType>::FBaseIterator& Other) const
{
return BitArrayIt != Other.BitArrayIt;
}
FORCEINLINE int32 GetIndex() const
{
return BitArrayIt.GetIndex();
}
FORCEINLINE bool IsElementValid() const
{
return *BitArrayIt;
}
};
public:
FORCEINLINE TSparseArray<ArrayType>::FBaseIterator begin()
{
return TSparseArray<ArrayType>::FBaseIterator(*this, TBitArray::FSetBitIterator(AllocationFlags, 0));
}
FORCEINLINE const TSparseArray<ArrayType>::FBaseIterator begin() const
{
return TSparseArray<ArrayType>::FBaseIterator(*this, TBitArray::FSetBitIterator(AllocationFlags, 0));
}
FORCEINLINE TSparseArray<ArrayType>::FBaseIterator end()
{
return TSparseArray<ArrayType>::FBaseIterator(*this, TBitArray::FSetBitIterator(AllocationFlags));
}
FORCEINLINE const TSparseArray<ArrayType>::FBaseIterator end() const
{
return TSparseArray<ArrayType>::FBaseIterator(*this, TBitArray::FSetBitIterator(AllocationFlags));
}
FORCEINLINE FSparseArrayElement& operator[](uint32 Index)
{
return *(FSparseArrayElement*)&Data.at(Index).ElementData;
@@ -58,9 +138,62 @@ public:
{
return *(const FSparseArrayElement*)&Data.at(Index).ElementData;
}
FORCEINLINE int32 Num() const
FORCEINLINE int32 GetNumFreeIndices() const
{
return Data.Num() - NumFreeIndices;
return NumFreeIndices;
}
FORCEINLINE int32 GetFirstFreeIndex() const
{
return FirstFreeIndex;
}
FORCEINLINE const TArray<FSparseArrayElement>& GetData() const
{
return Data;
}
FORCEINLINE const TBitArray& GetAllocationFlags() const
{
return AllocationFlags;
}
FORCEINLINE bool IsIndexValid(int32 IndexToCheck) const
{
return AllocationFlags.IsSet(IndexToCheck);
}
FORCEINLINE bool RemoveAt(const int32 IndexToRemove)
{
if (IndexToRemove >= 0 && IndexToRemove < Data.Num() && AllocationFlags.IsSet(IndexToRemove))
{
int32 PreviousFreeIndex = -1;
int32 NextFreeIndex = -1;
if (NumFreeIndices == 0)
{
FirstFreeIndex = IndexToRemove;
Data.at(IndexToRemove) = { -1, -1 };
}
else
{
for (auto It = AllocationFlags.begin(); It != AllocationFlags.end(); ++It)
{
if (!It)
{
if (It.GetIndex() < IndexToRemove)
{
Data.at(IndexToRemove).PrevFreeIndex = It.GetIndex();
}
else if (It.GetIndex() > IndexToRemove)
{
Data.at(IndexToRemove).NextFreeIndex = It.GetIndex();
break;
}
}
}
}
AllocationFlags.Set(IndexToRemove, false);
NumFreeIndices++;
return true;
}
return false;
}
};

View File

@@ -12,6 +12,11 @@ struct FUObjectItem
int32 ClusterRootIndex;
int32 SerialNumber;
FORCEINLINE bool IsPendingKill() const
{
return !!(Flags & int32(EInternalObjectFlags::PendingKill));
}
FORCEINLINE void SetFlag(EInternalObjectFlags FlagToSet)
{
// static_assert(sizeof(int32) == sizeof(Flags), "Flags must be 32-bit for atomics.");

View File

@@ -1,8 +1,15 @@
#pragma once
#include "UObjectArray.h"
struct FWeakObjectPtr
{
public:
int ObjectIndex;
int ObjectSerialNumber;
UObject* Get()
{
return ChunkedObjects ? ChunkedObjects->GetObjectByIndex(ObjectIndex) : UnchunkedObjects ? UnchunkedObjects->GetObjectByIndex(ObjectIndex) : nullptr;
}
};

View File

@@ -0,0 +1,16 @@
#pragma once
#include "WeakObjectPtr.h"
#include "Object.h"
template<class T = UObject, class TWeakObjectPtrBase = FWeakObjectPtr>
struct TWeakObjectPtr;
template<class T, class TWeakObjectPtrBase>
struct TWeakObjectPtr : public TWeakObjectPtrBase
{
T* Get()
{
return (T*)TWeakObjectPtrBase::Get();
}
};

View File

@@ -395,7 +395,7 @@ std::vector<uint64> Addresses::GetFunctionsToNull()
if (Fortnite_Version > 2.5 && Engine_Version == 420)
{
toNull.push_back(Memcury::Scanner::FindPattern("48 8B C4 57 48 81 EC ? ? ? ? 4C 8B 82 ? ? ? ? 48 8B F9 0F 29 70 E8 0F 29 78 D8").Get()); // Pawn Overlap
toNull.push_back(Memcury::Scanner::FindPattern("E8 ? ? ? ? EB 26 40 38 3D ? ? ? ?").RelativeOffset(1).Get()); // collectgarbage
// toNull.push_back(Memcury::Scanner::FindPattern("E8 ? ? ? ? EB 26 40 38 3D ? ? ? ?").RelativeOffset(1).Get()); // collectgarbage
}
if (Engine_Version == 421)

View File

@@ -61,6 +61,34 @@ static __int64 DispatchRequestHook(__int64 a1, __int64* a2, int a3)
return DispatchRequestOriginal(a1, a2, 3);
}
void (*ApplyHomebaseEffectsOnPlayerSetupOriginal)(
__int64* GameState,
__int64 a2,
__int64 a3,
__int64 a4,
UObject* Hero,
char a6,
unsigned __int8 a7);
void __fastcall ApplyHomebaseEffectsOnPlayerSetupHook(
__int64* GameState,
__int64 a2,
__int64 a3,
__int64 a4,
UObject* Hero,
char a6,
unsigned __int8 a7)
{
LOG_INFO(LogDev, "Old hero: {}", Hero ? Hero->GetFullName() : "InvalidObject");
auto HeroType = FindObject<UFortItemDefinition>("/Game/Athena/Heroes/HID_030_Athena_Commando_M_Halloween.HID_030_Athena_Commando_M_Halloween");
static auto ItemDefinitionOffset = Hero->GetOffset("ItemDefinition");
Hero->Get<UFortItemDefinition*>(ItemDefinitionOffset) = HeroType;
return ApplyHomebaseEffectsOnPlayerSetupOriginal(GameState, a2, a3, a4, Hero, a6, a7);
}
DWORD WINAPI Main(LPVOID)
{
InitLogger();
@@ -213,6 +241,8 @@ DWORD WINAPI Main(LPVOID)
if (func == 0)
continue;
LOG_INFO(LogDev, "Nulling 0x{:x}", func - __int64(GetModuleHandleW(0)));
DWORD dwProtection;
VirtualProtect((PVOID)func, 1, PAGE_EXECUTE_READWRITE, &dwProtection);
@@ -228,11 +258,16 @@ DWORD WINAPI Main(LPVOID)
// Globals::bAbilitiesEnabled = Engine_Version < 500;
if (Fortnite_Version == 1.11)
{
auto ApplyHomebaseEffectsOnPlayerSetupAddr = Memcury::Scanner::FindPattern("40 55 53 57 41 54 41 56 41 57 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B 05 ? ? ? ? 48 33 C4 48 89 45 00 4C 8B BD ? ? ? ? 49").Get();
Hooking::MinHook::Hook((PVOID)ApplyHomebaseEffectsOnPlayerSetupAddr, ApplyHomebaseEffectsOnPlayerSetupHook, (PVOID*)&ApplyHomebaseEffectsOnPlayerSetupOriginal);
}
Hooking::MinHook::Hook(GameModeDefault, FindObject<UFunction>(L"/Script/Engine.GameMode.ReadyToStartMatch"), AFortGameModeAthena::Athena_ReadyToStartMatchHook,
(PVOID*)&AFortGameModeAthena::Athena_ReadyToStartMatchOriginal, false);
// return false;
Hooking::MinHook::Hook(GameModeDefault, FindObject<UFunction>(L"/Script/Engine.GameModeBase.SpawnDefaultPawnFor"),
AGameModeBase::SpawnDefaultPawnForHook, nullptr, false);
Hooking::MinHook::Hook(GameModeDefault, FindObject<UFunction>(L"/Script/Engine.GameModeBase.HandleStartingNewPlayer"), AFortGameModeAthena::Athena_HandleStartingNewPlayerHook,
@@ -576,6 +611,56 @@ DWORD WINAPI Main(LPVOID)
else if (GetAsyncKeyState(VK_F8) & 1)
{
auto GameMode = (AFortGameMode*)GetWorld()->GetGameMode();
auto GameState = GameMode->GetGameState();
if (Fortnite_Version == 1.11)
{
static auto OverrideBattleBusSkin = FindObject("/Game/Athena/Items/Cosmetics/BattleBuses/BBID_WinterBus.BBID_WinterBus");
LOG_INFO(LogDev, "OverrideBattleBusSkin: {}", __int64(OverrideBattleBusSkin));
if (OverrideBattleBusSkin)
{
static auto AssetManagerOffset = GetEngine()->GetOffset("AssetManager");
auto AssetManager = GetEngine()->Get(AssetManagerOffset);
if (AssetManager)
{
static auto AthenaGameDataOffset = AssetManager->GetOffset("AthenaGameData");
auto AthenaGameData = AssetManager->Get(AthenaGameDataOffset);
if (AthenaGameData)
{
static auto DefaultBattleBusSkinOffset = AthenaGameData->GetOffset("DefaultBattleBusSkin");
AthenaGameData->Get(DefaultBattleBusSkinOffset) = OverrideBattleBusSkin;
}
}
static auto DefaultBattleBusOffset = GameState->GetOffset("DefaultBattleBus");
GameState->Get(DefaultBattleBusOffset) = OverrideBattleBusSkin;
static auto FortAthenaAircraftClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaAircraft");
auto AllAircrafts = UGameplayStatics::GetAllActorsOfClass(GetWorld(), FortAthenaAircraftClass);
for (int i = 0; i < AllAircrafts.Num(); i++)
{
auto Aircraft = AllAircrafts.at(i);
static auto DefaultBusSkinOffset = Aircraft->GetOffset("DefaultBusSkin");
Aircraft->Get(DefaultBusSkinOffset) = OverrideBattleBusSkin;
static auto SpawnedCosmeticActorOffset = Aircraft->GetOffset("SpawnedCosmeticActor");
auto SpawnedCosmeticActor = Aircraft->Get<AActor*>(SpawnedCosmeticActorOffset);
if (SpawnedCosmeticActor)
{
static auto ActiveSkinOffset = SpawnedCosmeticActor->GetOffset("ActiveSkin");
SpawnedCosmeticActor->Get(ActiveSkinOffset) = OverrideBattleBusSkin;
}
}
}
}
float Duration = 0;
float EarlyDuration = Duration;
@@ -583,9 +668,6 @@ DWORD WINAPI Main(LPVOID)
LOG_INFO(LogDev, "Starting bus!");
auto GameMode = (AFortGameMode*)GetWorld()->GetGameMode();
auto GameState = GameMode->GetGameState();
GameState->Get<float>("WarmupCountdownEndTime") = 0;
GameMode->Get<float>("WarmupCountdownDuration") = 0;
@@ -603,30 +685,37 @@ DWORD WINAPI Main(LPVOID)
else if (GetAsyncKeyState(VK_F10) & 1)
{
FString LevelA = Engine_Version < 424
? L"open Athena_Terrain" : Engine_Version >= 500 ? Engine_Version >= 501
? L"open Asteria_Terrain"
: Globals::bCreative ? L"open Creative_NoApollo_Terrain"
: L"open Artemis_Terrain"
: Globals::bCreative ? L"open Creative_NoApollo_Terrain"
: L"open Apollo_Terrain";
static auto BeaconClass = FindObject<UClass>(L"/Script/FortniteGame.FortOnlineBeaconHost");
auto AllFortBeacons = UGameplayStatics::GetAllActorsOfClass(GetWorld(), BeaconClass);
for (int i = 0; i < AllFortBeacons.Num(); i++)
if (Engine_Version < 424)
{
AllFortBeacons.at(i)->K2_DestroyActor();
FString LevelA = Engine_Version < 424
? L"open Athena_Terrain" : Engine_Version >= 500 ? Engine_Version >= 501
? L"open Asteria_Terrain"
: Globals::bCreative ? L"open Creative_NoApollo_Terrain"
: L"open Artemis_Terrain"
: Globals::bCreative ? L"open Creative_NoApollo_Terrain"
: L"open Apollo_Terrain";
static auto BeaconClass = FindObject<UClass>(L"/Script/FortniteGame.FortOnlineBeaconHost");
auto AllFortBeacons = UGameplayStatics::GetAllActorsOfClass(GetWorld(), BeaconClass);
for (int i = 0; i < AllFortBeacons.Num(); i++)
{
AllFortBeacons.at(i)->K2_DestroyActor();
}
AllFortBeacons.Free();
LOG_INFO(LogDev, "Switching!");
((AGameMode*)GetWorld()->GetGameMode())->RestartGame();
// UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), LevelA, nullptr);
// UGameplayStatics::OpenLevel(GetWorld(), UKismetStringLibrary::Conv_StringToName(LevelA), true, FString());
LOG_INFO(LogGame, "Restarting!");
AmountOfRestarts++;
}
else
{
LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!");
}
AllFortBeacons.Free();
LOG_INFO(LogDev, "Switching!");
((AGameMode*)GetWorld()->GetGameMode())->RestartGame();
// UKismetSystemLibrary::ExecuteConsoleCommand(GetWorld(), LevelA, nullptr);
// UGameplayStatics::OpenLevel(GetWorld(), UKismetStringLibrary::Conv_StringToName(LevelA), true, FString());
LOG_INFO(LogDev, "Restarting!");
AmountOfRestarts++;
}
Sleep(1000 / 30);

View File

@@ -325,7 +325,7 @@ static inline uint64 FindGetPlayerViewpoint()
LOG_INFO(LogDev, "GetPlayerViewpoint StringRef: 0x{:x}", __int64(Addrr) - __int64(GetModuleHandleW(0)));
for (int i = 0; i < 1200; i++)
for (int i = 0; i < 1000; i++)
{
if (*(uint8_t*)(uint8_t*)(Addrr - i) == 0x40 && *(uint8_t*)(uint8_t*)(Addrr - i + 1) == 0x55)
{
@@ -337,8 +337,9 @@ static inline uint64 FindGetPlayerViewpoint()
return Addrr - i;
}
if (*(uint8_t*)(uint8_t*)(Addrr - i) == 0xC3) // hmm
if (Fortnite_Version == 7.20 && *(uint8_t*)(uint8_t*)(Addrr - i) == 0xC3) // hmm scuffed lmfao
{
LOG_INFO(LogDev, "Hit C3!");
break;
}
}