Dude 💀

This commit is contained in:
Gray
2024-03-20 21:45:38 -04:00
parent 138d3cc668
commit b3d9ab9e8b
46 changed files with 2846 additions and 1608 deletions

View File

@@ -4,6 +4,7 @@
#include "reboot.h" #include "reboot.h"
#include "GameplayStatics.h" #include "GameplayStatics.h"
#include "Level.h"
bool AActor::HasAuthority() bool AActor::HasAuthority()
{ {
@@ -11,6 +12,11 @@ bool AActor::HasAuthority()
return Get<uint8_t>(RoleOffset) == 3; return Get<uint8_t>(RoleOffset) == 3;
} }
bool AActor::GetNetDormancy(const FVector& ViewPos, const FVector& ViewDir, AActor* Viewer, AActor* ViewTarget, class UActorChannel* InChannel, float Time, bool bLowBandwidth) // T(REP)
{
return false;
}
bool AActor::IsTearOff() bool AActor::IsTearOff()
{ {
static auto bTearOffOffset = GetOffset("bTearOff"); static auto bTearOffOffset = GetOffset("bTearOff");
@@ -18,7 +24,12 @@ bool AActor::IsTearOff()
return ReadBitfieldValue(bTearOffOffset, bTearOffFieldMask); return ReadBitfieldValue(bTearOffOffset, bTearOffFieldMask);
} }
/* FORCEINLINE */ ENetDormancy& AActor::GetNetDormancy() ULevel* AActor::GetLevel() const
{
return GetTypedOuter<ULevel>();
}
/* FORCEINLINE */ ENetDormancy& AActor::NetDormancy()
{ {
static auto NetDormancyOffset = GetOffset("NetDormancy"); static auto NetDormancyOffset = GetOffset("NetDormancy");
return Get<ENetDormancy>(NetDormancyOffset); return Get<ENetDormancy>(NetDormancyOffset);
@@ -38,15 +49,6 @@ FTransform AActor::GetTransform()
return Ret; return Ret;
} }
/*
UWorld* AActor::GetWorld()
{
return GetWorld(); // for real
}
*/
void AActor::SetNetDormancy(ENetDormancy Dormancy) void AActor::SetNetDormancy(ENetDormancy Dormancy)
{ {
static auto SetNetDormancyFn = FindObject<UFunction>(L"/Script/Engine.Actor.SetNetDormancy"); static auto SetNetDormancyFn = FindObject<UFunction>(L"/Script/Engine.Actor.SetNetDormancy");
@@ -63,6 +65,18 @@ AActor* AActor::GetOwner()
return Owner; return Owner;
} }
FName& AActor::GetNetDriverName()
{
static auto NetDriverNameOffset = GetOffset("NetDriverName");
return Get<FName>(NetDriverNameOffset);
}
ENetRole& AActor::GetRemoteRole()
{
static auto RemoteRoleOffset = GetOffset("RemoteRole");
return Get<ENetRole>(RemoteRoleOffset);
}
void AActor::K2_DestroyActor() void AActor::K2_DestroyActor()
{ {
static auto DestroyActorFn = FindObject<UFunction>("/Script/Engine.Actor.K2_DestroyActor"); static auto DestroyActorFn = FindObject<UFunction>("/Script/Engine.Actor.K2_DestroyActor");
@@ -195,12 +209,12 @@ void AActor::ForceNetUpdate()
this->ProcessEvent(ForceNetUpdateFn); this->ProcessEvent(ForceNetUpdateFn);
} }
bool AActor::IsNetStartupActor() bool AActor::IsNetStartupActor() // T(REP)
{ {
return IsNetStartup(); // The implementation on this function depends on the version. return IsNetStartup(); // The implementation on this function depends on the version.
} }
bool AActor::IsPendingKillPending() bool AActor::IsPendingKillPending() // T(REP)
{ {
return IsActorBeingDestroyed() || !IsValidChecked(this); return IsActorBeingDestroyed() || !IsValidChecked(this);
} }
@@ -246,6 +260,11 @@ const AActor* AActor::GetNetOwner() const
return GetNetOwnerOriginal(this); return GetNetOwnerOriginal(this);
} }
bool AActor::IsActorInitialized() // T(REP)
{
return true;
}
void AActor::GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const void AActor::GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const
{ {
static auto GetActorEyesViewPointFn = FindObject<UFunction>(L"/Script/Engine.Actor.GetActorEyesViewPoint"); static auto GetActorEyesViewPointFn = FindObject<UFunction>(L"/Script/Engine.Actor.GetActorEyesViewPoint");

View File

@@ -2,6 +2,7 @@
#include "Object.h" #include "Object.h"
#include "anticheat.h" #include "anticheat.h"
#include "Vector.h"
enum class ENetDormancy : uint8_t enum class ENetDormancy : uint8_t
{ {
@@ -17,15 +18,19 @@ enum class ENetDormancy : uint8_t
class AActor : public UObject class AActor : public UObject
{ {
public: public:
static inline void (*originalCallPreReplication)(AActor*, class UNetDriver*);
struct FTransform GetTransform(); struct FTransform GetTransform();
// class UWorld* GetWorld(); bool GetNetDormancy(const FVector& ViewPos, const FVector& ViewDir, AActor* Viewer, AActor* ViewTarget, class UActorChannel* InChannel, float Time, bool bLowBandwidth);
bool HasAuthority(); bool HasAuthority();
bool IsTearOff(); bool IsTearOff();
/* FORCEINLINE */ ENetDormancy& GetNetDormancy(); class ULevel* GetLevel() const;
/* FORCEINLINE */ ENetDormancy& NetDormancy();
int32& GetNetTag(); int32& GetNetTag();
void SetNetDormancy(ENetDormancy Dormancy); void SetNetDormancy(ENetDormancy Dormancy);
AActor* GetOwner(); AActor* GetOwner();
FName& GetNetDriverName();
ENetRole& GetRemoteRole();
struct FVector GetActorScale3D(); struct FVector GetActorScale3D();
struct FVector GetActorLocation(); struct FVector GetActorLocation();
struct FVector GetActorForwardVector(); struct FVector GetActorForwardVector();
@@ -52,12 +57,12 @@ public:
float& GetNetUpdateFrequency(); float& GetNetUpdateFrequency();
float& GetMinNetUpdateFrequency(); float& GetMinNetUpdateFrequency();
const AActor* GetNetOwner() const; const AActor* GetNetOwner() const;
bool IsActorInitialized();
void GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const; void GetActorEyesViewPoint(FVector* OutLocation, FRotator* OutRotation) const;
AActor* GetClosestActor(UClass* ActorClass, float DistMax, std::function<bool(AActor*)> AdditionalCheck = [&](AActor*) { return true; }); AActor* GetClosestActor(UClass* ActorClass, float DistMax, std::function<bool(AActor*)> AdditionalCheck = [&](AActor*) { return true; });
bool IsRelevancyOwnerFor(const AActor* ReplicatedActor, const AActor* ActorOwner, const AActor* ConnectionActor) const bool IsRelevancyOwnerFor(const AActor* ReplicatedActor, const AActor* ActorOwner, const AActor* ConnectionActor) const // T(REP)
{ {
// we should call virtual function but eh
// return (ActorOwner == this); // return (ActorOwner == this);
static auto IsRelevancyOwnerForOffset = 0x428; static auto IsRelevancyOwnerForOffset = 0x428;

View File

@@ -3,9 +3,29 @@
#include "Channel.h" #include "Channel.h"
#include "NetworkGuid.h" #include "NetworkGuid.h"
enum ESetChannelActorFlags
{
None1 = 0, // Bro compiler what
SkipReplicatorCreation = (1 << 0),
SkipMarkActive = (1 << 1),
};
class UActorChannel : public UChannel class UActorChannel : public UChannel
{ {
public: public:
static inline void (*originalSetChannelActor)(UActorChannel*, AActor*);
static inline __int64 (*originalReplicateActor)(UActorChannel*);
void SetChannelActor(AActor* Actor, ESetChannelActorFlags Flags)
{
originalSetChannelActor(this, Actor); // T(REP) ADD FLAGS FOR NEWER BUILDS
}
__int64 ReplicateActor() // Returns how many bits were replicated (does not include non-bunch packet overhead)
{
return originalReplicateActor(this);
}
double& GetLastUpdateTime() double& GetLastUpdateTime()
{ {
static auto LastUpdateTimeOffset = GetOffset("Actor") + 8 + 4 + 4 + 8; // checked on 4.19 static auto LastUpdateTimeOffset = GetOffset("Actor") + 8 + 4 + 4 + 8; // checked on 4.19

View File

@@ -5,17 +5,7 @@
#include "MemoryOps.h" #include "MemoryOps.h"
#include "ContainerAllocationPolicies.h" #include "ContainerAllocationPolicies.h"
#include "IsPointer.h"
struct FMemory
{
static inline void* (*Realloc)(void* Original, SIZE_T Count, uint32_t Alignment /* = DEFAULT_ALIGNMENT */);
};
template <typename T = __int64>
static T* AllocUnreal(size_t Size)
{
return (T*)FMemory::Realloc(0, Size, 0);
}
template<typename InElementType> //, typename InAllocatorType> template<typename InElementType> //, typename InAllocatorType>
class TArray class TArray
@@ -26,6 +16,7 @@ public:
using ElementAllocatorType = InElementType*; using ElementAllocatorType = InElementType*;
using SizeType = int32; using SizeType = int32;
typedef InElementType ElementType;
ElementAllocatorType Data = nullptr; // AllocatorInstance; ElementAllocatorType Data = nullptr; // AllocatorInstance;
SizeType ArrayNum; SizeType ArrayNum;
@@ -33,14 +24,46 @@ public:
public: public:
#if TARRAY_RANGED_FOR_CHECKS
typedef TCheckedPointerIterator< ElementType, SizeType> RangedForIteratorType;
typedef TCheckedPointerIterator<const ElementType, SizeType> RangedForConstIteratorType;
#else
typedef ElementType* RangedForIteratorType;
typedef const ElementType* RangedForConstIteratorType;
#endif
#if TARRAY_RANGED_FOR_CHECKS
FORCEINLINE friend RangedForIteratorType begin(TArray& Array) { return RangedForIteratorType(Array.ArrayNum, Array.GetData()); }
FORCEINLINE friend RangedForConstIteratorType begin(const TArray& Array) { return RangedForConstIteratorType(Array.ArrayNum, Array.GetData()); }
FORCEINLINE friend RangedForIteratorType end(TArray& Array) { return RangedForIteratorType(Array.ArrayNum, Array.GetData() + Array.Num()); }
FORCEINLINE friend RangedForConstIteratorType end(const TArray& Array) { return RangedForConstIteratorType(Array.ArrayNum, Array.GetData() + Array.Num()); }
#else
FORCEINLINE friend RangedForIteratorType begin(TArray& Array) { return Array.GetData(); }
FORCEINLINE friend RangedForConstIteratorType begin(const TArray& Array) { return Array.GetData(); }
FORCEINLINE friend RangedForIteratorType end(TArray& Array) { return Array.GetData() + Array.Num(); }
FORCEINLINE friend RangedForConstIteratorType end(const TArray& Array) { return Array.GetData() + Array.Num(); }
#endif
inline InElementType& At(int i, size_t Size = sizeof(InElementType)) const { return *(InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); } inline InElementType& At(int i, size_t Size = sizeof(InElementType)) const { return *(InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); }
inline InElementType& at(int i, size_t Size = sizeof(InElementType)) const { return *(InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); } inline InElementType& at(int i, size_t Size = sizeof(InElementType)) const { return *(InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); }
inline InElementType* AtPtr(int i, size_t Size = sizeof(InElementType)) const { return (InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); } inline InElementType* AtPtr(int i, size_t Size = sizeof(InElementType)) const { return (InElementType*)(__int64(Data) + (static_cast<long long>(Size) * i)); }
bool IsValidIndex(int i) { return i > 0 && i < ArrayNum; } bool IsValidIndex(int i) { return i > 0 && i < ArrayNum; }
ElementAllocatorType& GetData() const { return Data; } InElementType* GetData()
ElementAllocatorType& GetData() { return Data; } {
return (InElementType*)Data;
}
/**
* Helper function for returning a typed pointer to the first array entry.
*
* @returns Pointer to first array entry or nullptr if ArrayMax == 0.
*/
const InElementType* GetData() const
{
return (const InElementType*)Data;
}
void Reserve(int Number, size_t Size = sizeof(InElementType)) void Reserve(int Number, size_t Size = sizeof(InElementType))
{ {

View File

@@ -1,237 +1,202 @@
#pragma once #pragma once
#include "ContainerAllocationPolicies.h" #include "ContainerAllocationPolicies.h"
#include "UnrealMathUtility.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 NumBitsPerDWORD ((int32)32)
#define NumBitsPerDWORDLogTwo ((int32)5) #define NumBitsPerDWORDLogTwo ((int32)5)
template<typename Allocator = FDefaultBitArrayAllocator>
class TBitArray;
template<typename Allocator = FDefaultBitArrayAllocator>
class TConstSetBitIterator;
template<typename Allocator /*= FDefaultBitArrayAllocator*/>
class TBitArray class TBitArray
{ {
public: public:
TInlineAllocator<4>::ForElementType<unsigned int> Data; /**
int NumBits; * Move constructor.
int MaxBits; */
FORCEINLINE TBitArray(TBitArray&& Other)
struct FRelativeBitReference
{ {
public: MoveOrCopy(*this, Other);
}
FORCEINLINE int32 Num() const { return NumBits; }
/**
* Copy constructor.
*/
FORCEINLINE TBitArray(const TBitArray& Copy)
: NumBits(0)
, MaxBits(0)
{
*this = Copy;
}
FORCEINLINE const uint32* GetData() const
{
return (uint32*)AllocatorInstance.GetAllocation();
}
FORCEINLINE uint32* GetData()
{
return (uint32*)AllocatorInstance.GetAllocation();
}
/**
* Move assignment.
*/
FORCEINLINE TBitArray& operator=(TBitArray&& Other)
{
if (this != &Other)
{
MoveOrCopy(*this, Other);
}
return *this;
}
private:
typedef typename Allocator::template ForElementType<uint32> AllocatorType;
AllocatorType AllocatorInstance;
int32 NumBits;
int32 MaxBits;
template <typename BitArrayType>
static FORCEINLINE typename TEnableIf<TContainerTraits<BitArrayType>::MoveWillEmptyContainer>::Type MoveOrCopy(BitArrayType& ToArray, BitArrayType& FromArray)
{
ToArray.AllocatorInstance.MoveToEmpty(FromArray.AllocatorInstance);
ToArray.NumBits = FromArray.NumBits;
ToArray.MaxBits = FromArray.MaxBits;
FromArray.NumBits = 0;
FromArray.MaxBits = 0;
}
template <typename BitArrayType>
static FORCEINLINE typename TEnableIf<!TContainerTraits<BitArrayType>::MoveWillEmptyContainer>::Type MoveOrCopy(BitArrayType& ToArray, BitArrayType& FromArray)
{
ToArray = FromArray;
}
FORCENOINLINE void Realloc(int32 PreviousNumBits)
{
const int32 PreviousNumDWORDs = FMath::DivideAndRoundUp(PreviousNumBits, NumBitsPerDWORD);
const int32 MaxDWORDs = FMath::DivideAndRoundUp(MaxBits, NumBitsPerDWORD);
AllocatorInstance.ResizeAllocation(PreviousNumDWORDs, MaxDWORDs, sizeof(uint32));
if (MaxDWORDs)
{
// Reset the newly allocated slack DWORDs.
FMemory::Memzero((uint32*)AllocatorInstance.GetAllocation() + PreviousNumDWORDs, (MaxDWORDs - PreviousNumDWORDs) * sizeof(uint32));
}
}
public:
};
class FRelativeBitReference
{
public:
FORCEINLINE explicit FRelativeBitReference(int32 BitIndex) FORCEINLINE explicit FRelativeBitReference(int32 BitIndex)
: DWORDIndex(BitIndex >> NumBitsPerDWORDLogTwo) : DWORDIndex(BitIndex >> NumBitsPerDWORDLogTwo)
, Mask(1 << (BitIndex & (NumBitsPerDWORD -1))) , Mask(1 << (BitIndex & (NumBitsPerDWORD - 1)))
{ {
} }
int32 DWORDIndex; int32 DWORDIndex;
uint32 Mask; uint32 Mask;
}; };
template<typename Allocator>
class TConstSetBitIterator : public FRelativeBitReference
{
public: 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) /** Constructor. */
{ TConstSetBitIterator(const TBitArray<Allocator>& InArray, int32 StartIndex = 0)
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) : FRelativeBitReference(StartIndex)
, IteratedArray(const_cast<TBitArray&>(ToIterate)) , Array(InArray)
, UnvisitedBitMask((~0U) << (StartIndex & (NumBitsPerDWORD - 1))) , UnvisitedBitMask((~0U) << (StartIndex & (NumBitsPerDWORD - 1)))
, CurrentBitIndex(StartIndex) , CurrentBitIndex(StartIndex)
, BaseBitIndex(StartIndex & ~(NumBitsPerDWORD - 1)) , BaseBitIndex(StartIndex & ~(NumBitsPerDWORD - 1))
{ {
if (StartIndex != IteratedArray.NumBits) // check(StartIndex >= 0 && StartIndex <= Array.Num());
if (StartIndex != Array.Num())
{ {
FindNextSetBit(); FindFirstSetBit();
} }
} }
FORCEINLINE FSetBitIterator(const TBitArray& ToIterate)
: FRelativeBitReference(ToIterate.NumBits)
, IteratedArray(const_cast<TBitArray&>(ToIterate))
, UnvisitedBitMask(0)
, CurrentBitIndex(ToIterate.NumBits)
, BaseBitIndex(ToIterate.NumBits)
{
}
FORCEINLINE FSetBitIterator& operator++() /** Forwards iteration operator. */
FORCEINLINE TConstSetBitIterator& operator++()
{ {
// Mark the current bit as visited.
UnvisitedBitMask &= ~this->Mask; UnvisitedBitMask &= ~this->Mask;
FindNextSetBit(); // Find the first set bit that hasn't been visited yet.
FindFirstSetBit();
return *this; return *this;
} }
FORCEINLINE bool operator*() const
FORCEINLINE friend bool operator==(const TConstSetBitIterator& Lhs, const TConstSetBitIterator& Rhs)
{ {
return true; // We only need to compare the bit index and the array... all the rest of the state is unobservable.
return Lhs.CurrentBitIndex == Rhs.CurrentBitIndex && &Lhs.Array == &Rhs.Array;
} }
FORCEINLINE bool operator==(const FSetBitIterator& Other) const FORCEINLINE friend bool operator!=(const TConstSetBitIterator& Lhs, const TConstSetBitIterator& Rhs)
{ {
return CurrentBitIndex == Other.CurrentBitIndex; return !(Lhs == Rhs);
}
FORCEINLINE bool operator!=(const FSetBitIterator& Other) const
{
return CurrentBitIndex </*=*/ Other.CurrentBitIndex;
} }
/** conversion to "bool" returning true if the iterator is valid. */
FORCEINLINE explicit operator bool() const FORCEINLINE explicit operator bool() const
{ {
return CurrentBitIndex < IteratedArray.NumBits; return CurrentBitIndex < Array.Num();
}
/** inverse of the "bool" operator */
FORCEINLINE bool operator !() const
{
return !(bool)*this;
} }
/** Index accessor. */
FORCEINLINE int32 GetIndex() const FORCEINLINE int32 GetIndex() const
{ {
return CurrentBitIndex; return CurrentBitIndex;
} }
private: private:
void FindNextSetBit() const TBitArray<Allocator>& Array;
uint32 UnvisitedBitMask;
int32 CurrentBitIndex;
int32 BaseBitIndex;
/** Find the first set bit starting with the current bit, inclusive. */
void FindFirstSetBit()
{ {
//InlineData is the first 16-bytes of TBitArray const uint32* ArrayData = Array.GetData();
const uint32* ArrayData = (IteratedArray.Data.SecondaryData ? IteratedArray.Data.SecondaryData : (uint32*)&IteratedArray.Data.InlineData); const int32 ArrayNum = Array.Num();
if (!ArrayData)
return;
const int32 ArrayNum = IteratedArray.NumBits;
const int32 LastDWORDIndex = (ArrayNum - 1) / NumBitsPerDWORD; const int32 LastDWORDIndex = (ArrayNum - 1) / NumBitsPerDWORD;
// Advance to the next non-zero uint32.
uint32 RemainingBitMask = ArrayData[this->DWORDIndex] & UnvisitedBitMask; uint32 RemainingBitMask = ArrayData[this->DWORDIndex] & UnvisitedBitMask;
while (!RemainingBitMask) while (!RemainingBitMask)
{ {
++this->DWORDIndex; ++this->DWORDIndex;
BaseBitIndex += NumBitsPerDWORD; BaseBitIndex += NumBitsPerDWORD;
if (this->DWORDIndex > LastDWORDIndex) if (this->DWORDIndex > LastDWORDIndex)
{ {
// We've advanced past the end of the array.
CurrentBitIndex = ArrayNum; CurrentBitIndex = ArrayNum;
return; return;
} }
@@ -240,90 +205,21 @@ public:
UnvisitedBitMask = ~0; UnvisitedBitMask = ~0;
} }
// This operation has the effect of unsetting the lowest set bit of BitMask
const uint32 NewRemainingBitMask = RemainingBitMask & (RemainingBitMask - 1); const uint32 NewRemainingBitMask = RemainingBitMask & (RemainingBitMask - 1);
// This operation XORs the above mask with the original mask, which has the effect
// of returning only the bits which differ; specifically, the lowest bit
this->Mask = NewRemainingBitMask ^ RemainingBitMask; this->Mask = NewRemainingBitMask ^ RemainingBitMask;
CurrentBitIndex = BaseBitIndex + NumBitsPerDWORD - 1 - CountLeadingZeros(this->Mask); // If the Nth bit was the lowest set bit of BitMask, then this gives us N
CurrentBitIndex = BaseBitIndex + NumBitsPerDWORD - 1 - FMath::CountLeadingZeros(this->Mask);
// If we've accidentally iterated off the end of an array but still within the same DWORD
// then set the index to the last index of the array
if (CurrentBitIndex > ArrayNum) if (CurrentBitIndex > ArrayNum)
{ {
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

@@ -2,10 +2,26 @@
#include "Object.h" #include "Object.h"
enum EChannelType
{
CHTYPE_None = 0,
CHTYPE_Control = 1,
CHTYPE_Actor = 2,
CHTYPE_File = 3,
CHTYPE_Voice = 4,
CHTYPE_MAX = 8,
};
enum EChannelCreateFlags
{
None = (1 << 0),
OpenedLocally = (1 << 1),
};
class UChannel : public UObject class UChannel : public UObject
{ {
public: public:
void StartBecomingDormant() void StartBecomingDormant() // T(REP)
{ {
void (*StartBecomingDormantOriginal)(UChannel* Channel) = decltype(StartBecomingDormantOriginal)(this->VFTable[0x298 / 8]); void (*StartBecomingDormantOriginal)(UChannel* Channel) = decltype(StartBecomingDormantOriginal)(this->VFTable[0x298 / 8]);
StartBecomingDormantOriginal(this); StartBecomingDormantOriginal(this);

View File

@@ -0,0 +1,9 @@
#pragma once
#include "NetConnection.h"
class UChildConnection : public UNetConnection
{
public:
};

View File

@@ -0,0 +1,18 @@
#pragma once
template<bool Predicate, typename TrueClass, typename FalseClass>
class TChooseClass;
template<typename TrueClass, typename FalseClass>
class TChooseClass<true, TrueClass, FalseClass>
{
public:
typedef TrueClass Result;
};
template<typename TrueClass, typename FalseClass>
class TChooseClass<false, TrueClass, FalseClass>
{
public:
typedef FalseClass Result;
};

View File

@@ -68,8 +68,8 @@ public:
for (int i = 0; i < Names->Num(); ++i) for (int i = 0; i < Names->Num(); ++i)
{ {
auto& Pair = Names->At(i); auto& Pair = Names->At(i);
auto& Name = Pair.Key(); auto& Name = Pair.Key;
auto Value = Pair.Value(); auto Value = Pair.Value;
if (Name.ComparisonIndex.Value) if (Name.ComparisonIndex.Value)
{ {

View File

@@ -1,95 +1,48 @@
#pragma once #pragma once
#include "NumericLimits.h" #include "NumericLimits.h"
#include "UnrealTemplate.h"
#include "TypeCompatibleBytes.h"
template <int NumElements> struct FMemory // so real place
class TInlineAllocator
{ {
private: static inline void* (*Realloc)(void* Original, SIZE_T Count, uint32_t Alignment /* = DEFAULT_ALIGNMENT */);
template <int Size, int Alignment>
struct alignas(Alignment) TAlignedBytes static void Free(void* Data)
{ {
unsigned char Pad[Size]; // We could use actual free..
};
template <typename ElementType> Realloc(Data, 0, 0);
struct TTypeCompatibleBytes : public TAlignedBytes<sizeof(ElementType), alignof(ElementType)>
{
};
public:
template <typename ElementType>
class ForElementType
{
friend class TBitArray;
private:
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) static size_t QuantizeSize(size_t Count, uint32 Alignment) // T(R)
{ {
return *(ElementType*)(&InlineData[Index]); return Count;
}
FORCEINLINE const ElementType& operator[](int32 Index) const
{
return *(ElementType*)(&InlineData[Index]);
} }
FORCEINLINE void operator=(void* InElements) static void* Memmove(void* Dest, const void* Src, SIZE_T Count)
{ {
SecondaryData = InElements; memmove(Dest, Src, Count);
} }
FORCEINLINE ElementType& GetInlineElement(int32 Index) static FORCEINLINE void* Memzero(void* Dest, SIZE_T Count)
{ {
return *(ElementType*)(&InlineData[Index]); // return FPlatformMemory::Memzero(Dest, Count);
return RtlSecureZeroMemory(Dest, Count);
} }
FORCEINLINE const ElementType& GetInlineElement(int32 Index) const
template< class T >
static FORCEINLINE void Memzero(T& Src)
{ {
return *(ElementType*)(&InlineData[Index]); static_assert(!TIsPointer<T>::Value, "For pointers use the two parameters function");
Memzero(&Src, sizeof(T));
} }
FORCEINLINE ElementType& GetSecondaryElement(int32 Index)
{
return SecondaryData[Index];
}
FORCEINLINE const ElementType& GetSecondaryElement(int32 Index) const
{
return SecondaryData[Index];
}
ElementType* GetInlineElements() const
{
return (ElementType*)InlineData;
}
FORCEINLINE ElementType* GetAllocation() const
{
return IfAThenAElseB<ElementType>(SecondaryData, GetInlineElements());
}
};
}; };
template <typename T = __int64>
FORCEINLINE /*FMEMORY_INLINE_FUNCTION_DECORATOR*/ size_t /*FMemory::*/QuantizeSize(SIZE_T Count, uint32 Alignment) static T* AllocUnreal(size_t Size)
{ {
return Count; return (T*)FMemory::Realloc(0, Size, 0);
/*
if (!FMEMORY_INLINE_GMalloc)
{
return Count;
}
return FMEMORY_INLINE_GMalloc->QuantizeSize(Count, Alignment); */
} }
enum enum
@@ -97,21 +50,467 @@ enum
DEFAULT_ALIGNMENT = 0 DEFAULT_ALIGNMENT = 0
}; };
template <typename SizeType> // 4.19
FORCEINLINE SizeType DefaultCalculateSlackReserve(SizeType NumElements, SIZE_T BytesPerElement, bool bAllowQuantize, uint32 Alignment = DEFAULT_ALIGNMENT)
template <typename DestinationElementType, typename SourceElementType, typename SizeType>
FORCEINLINE void RelocateConstructItems(void* Dest, const SourceElementType* Source, SizeType Count)
{ {
SizeType Retval = NumElements; FMemory::Memmove(Dest, Source, sizeof(SourceElementType) * Count);
/*
if constexpr (UE::Core::Private::MemoryOps::TCanBitwiseRelocate<DestinationElementType, SourceElementType>::Value)
{
FMemory::Memmove(Dest, Source, sizeof(SourceElementType) * Count);
}
else
{
while (Count)
{
// We need a typedef here because VC won't compile the destructor call below if SourceElementType itself has a member called SourceElementType
typedef SourceElementType RelocateConstructItemsElementTypeTypedef;
new (Dest) DestinationElementType(*Source);
++(DestinationElementType*&)Dest;
(Source++)->RelocateConstructItemsElementTypeTypedef::~RelocateConstructItemsElementTypeTypedef();
--Count;
}
}
*/
}
class FDefaultAllocator;
template <uint32 NumInlineElements, typename SecondaryAllocator = FDefaultAllocator>
class TInlineAllocator
{
public:
enum { NeedsElementType = true };
enum { RequireRangeCheck = true };
template<typename ElementType>
class ForElementType
{
public:
ForElementType()
{
}
FORCEINLINE void MoveToEmpty(ForElementType& Other)
{
// checkSlow(this != &Other);
if (!Other.SecondaryData.GetAllocation())
{
RelocateConstructItems<ElementType>((void*)InlineData, Other.GetInlineElements(), NumInlineElements);
}
// Move secondary storage in any case.
// This will move secondary storage if it exists but will also handle the case where secondary storage is used in Other but not in *this.
SecondaryData.MoveToEmpty(Other.SecondaryData);
}
// FContainerAllocatorInterface
FORCEINLINE ElementType* GetAllocation() const
{
return IfAThenAElseB<ElementType>(SecondaryData.GetAllocation(), GetInlineElements());
}
void ResizeAllocation(int32 PreviousNumElements, int32 NumElements, SIZE_T NumBytesPerElement)
{
// Check if the new allocation will fit in the inline data area.
if (NumElements <= NumInlineElements)
{
// If the old allocation wasn't in the inline data area, relocate it into the inline data area.
if (SecondaryData.GetAllocation())
{
RelocateConstructItems<ElementType>((void*)InlineData, (ElementType*)SecondaryData.GetAllocation(), PreviousNumElements);
// Free the old indirect allocation.
SecondaryData.ResizeAllocation(0, 0, NumBytesPerElement);
}
}
else
{
if (!SecondaryData.GetAllocation())
{
// Allocate new indirect memory for the data.
SecondaryData.ResizeAllocation(0, NumElements, NumBytesPerElement);
// Move the data out of the inline data area into the new allocation.
RelocateConstructItems<ElementType>((void*)SecondaryData.GetAllocation(), GetInlineElements(), PreviousNumElements);
}
else
{
// Reallocate the indirect data for the new size.
SecondaryData.ResizeAllocation(PreviousNumElements, NumElements, NumBytesPerElement);
}
}
}
FORCEINLINE int32 CalculateSlackReserve(int32 NumElements, SIZE_T NumBytesPerElement) const
{
// If the elements use less space than the inline allocation, only use the inline allocation as slack.
return NumElements <= NumInlineElements ?
NumInlineElements :
SecondaryData.CalculateSlackReserve(NumElements, NumBytesPerElement);
}
FORCEINLINE int32 CalculateSlackShrink(int32 NumElements, int32 NumAllocatedElements, int32 NumBytesPerElement) const
{
// If the elements use less space than the inline allocation, only use the inline allocation as slack.
return NumElements <= NumInlineElements ?
NumInlineElements :
SecondaryData.CalculateSlackShrink(NumElements, NumAllocatedElements, NumBytesPerElement);
}
FORCEINLINE int32 CalculateSlackGrow(int32 NumElements, int32 NumAllocatedElements, int32 NumBytesPerElement) const
{
// If the elements use less space than the inline allocation, only use the inline allocation as slack.
return NumElements <= NumInlineElements ?
NumInlineElements :
SecondaryData.CalculateSlackGrow(NumElements, NumAllocatedElements, NumBytesPerElement);
}
SIZE_T GetAllocatedSize(int32 NumAllocatedElements, SIZE_T NumBytesPerElement) const
{
return SecondaryData.GetAllocatedSize(NumAllocatedElements, NumBytesPerElement);
}
bool HasAllocation()
{
return SecondaryData.HasAllocation();
}
private:
ForElementType(const ForElementType&);
ForElementType& operator=(const ForElementType&);
/** The data is stored in this array if less than NumInlineElements is needed. */
TTypeCompatibleBytes<ElementType> InlineData[NumInlineElements];
/** The data is allocated through the indirect allocation policy if more than NumInlineElements is needed. */
typename SecondaryAllocator::template ForElementType<ElementType> SecondaryData;
/** @return the base of the aligned inline element data */
ElementType* GetInlineElements() const
{
return (ElementType*)InlineData;
}
};
typedef void ForAnyElementType;
};
struct FScriptContainerElement
{
};
FORCEINLINE int32 DefaultCalculateSlackShrink(int32 NumElements, int32 NumAllocatedElements, SIZE_T BytesPerElement, bool bAllowQuantize, uint32 Alignment = DEFAULT_ALIGNMENT)
{
int32 Retval;
// checkSlow(NumElements < NumAllocatedElements);
const uint32 CurrentSlackElements = NumAllocatedElements - NumElements;
const SIZE_T CurrentSlackBytes = (NumAllocatedElements - NumElements) * BytesPerElement;
const bool bTooManySlackBytes = CurrentSlackBytes >= 16384;
const bool bTooManySlackElements = 3 * NumElements < 2 * NumAllocatedElements;
if ((bTooManySlackBytes || bTooManySlackElements) && (CurrentSlackElements > 64 || !NumElements)) // hard coded 64 :-(
{
Retval = NumElements;
if (Retval > 0)
{
if (bAllowQuantize)
{
Retval = FMemory::QuantizeSize(Retval * BytesPerElement, Alignment) / BytesPerElement;
}
}
}
else
{
Retval = NumAllocatedElements;
}
return Retval;
}
FORCEINLINE int32 DefaultCalculateSlackGrow(int32 NumElements, int32 NumAllocatedElements, SIZE_T BytesPerElement, bool bAllowQuantize, uint32 Alignment = DEFAULT_ALIGNMENT)
{
int32 Retval;
// checkSlow(NumElements > NumAllocatedElements && NumElements > 0);
SIZE_T Grow = 4;
if (NumAllocatedElements || SIZE_T(NumElements) > Grow)
{
// Allocate slack for the array proportional to its size.
Grow = SIZE_T(NumElements) + 3 * SIZE_T(NumElements) / 8 + 16;
}
if (bAllowQuantize)
{
Retval = FMemory::QuantizeSize(Grow * BytesPerElement, Alignment) / BytesPerElement;
}
else
{
Retval = Grow;
}
if (NumElements > Retval)
{
Retval = MAX_int32;
}
return Retval;
}
FORCEINLINE int32 DefaultCalculateSlackReserve(int32 NumElements, SIZE_T BytesPerElement, bool bAllowQuantize, uint32 Alignment = DEFAULT_ALIGNMENT)
{
int32 Retval = NumElements;
// checkSlow(NumElements > 0); // checkSlow(NumElements > 0);
if (bAllowQuantize) if (bAllowQuantize)
{ {
auto Count = SIZE_T(Retval) * SIZE_T(BytesPerElement); Retval = FMemory::QuantizeSize(SIZE_T(Retval) * SIZE_T(BytesPerElement), Alignment) / BytesPerElement;
Retval = (SizeType)(QuantizeSize(Count, Alignment) / BytesPerElement);
// NumElements and MaxElements are stored in 32 bit signed integers so we must be careful not to overflow here. // NumElements and MaxElements are stored in 32 bit signed integers so we must be careful not to overflow here.
if (NumElements > Retval) if (NumElements > Retval)
{ {
Retval = TNumericLimits<SizeType>::Max(); Retval = MAX_int32;
} }
} }
return Retval; return Retval;
} }
class FHeapAllocator
{
public:
enum { NeedsElementType = false };
enum { RequireRangeCheck = true };
class ForAnyElementType
{
public:
/** Default constructor. */
ForAnyElementType()
: Data(nullptr)
{}
FORCEINLINE void MoveToEmpty(ForAnyElementType& Other)
{
// checkSlow(this != &Other);
if (Data)
{
FMemory::Free(Data);
}
Data = Other.Data;
Other.Data = nullptr;
}
/** Destructor. */
FORCEINLINE ~ForAnyElementType()
{
if (Data)
{
FMemory::Free(Data);
}
}
// FContainerAllocatorInterface
FORCEINLINE FScriptContainerElement* GetAllocation() const
{
return Data;
}
FORCEINLINE void ResizeAllocation(int32 PreviousNumElements, int32 NumElements, SIZE_T NumBytesPerElement)
{
// Avoid calling FMemory::Realloc( nullptr, 0 ) as ANSI C mandates returning a valid pointer which is not what we want.
if (Data || NumElements)
{
//checkSlow(((uint64)NumElements*(uint64)ElementTypeInfo.GetSize() < (uint64)INT_MAX));
Data = (FScriptContainerElement*)FMemory::Realloc(Data, NumElements * NumBytesPerElement, DEFAULT_ALIGNMENT);
}
}
FORCEINLINE int32 CalculateSlackReserve(int32 NumElements, int32 NumBytesPerElement) const
{
return DefaultCalculateSlackReserve(NumElements, NumBytesPerElement, true);
}
FORCEINLINE int32 CalculateSlackShrink(int32 NumElements, int32 NumAllocatedElements, int32 NumBytesPerElement) const
{
return DefaultCalculateSlackShrink(NumElements, NumAllocatedElements, NumBytesPerElement, true);
}
FORCEINLINE int32 CalculateSlackGrow(int32 NumElements, int32 NumAllocatedElements, int32 NumBytesPerElement) const
{
return DefaultCalculateSlackGrow(NumElements, NumAllocatedElements, NumBytesPerElement, true);
}
SIZE_T GetAllocatedSize(int32 NumAllocatedElements, SIZE_T NumBytesPerElement) const
{
return NumAllocatedElements * NumBytesPerElement;
}
bool HasAllocation()
{
return !!Data;
}
private:
ForAnyElementType(const ForAnyElementType&);
ForAnyElementType& operator=(const ForAnyElementType&);
/** A pointer to the container's elements. */
FScriptContainerElement* Data;
};
template<typename ElementType>
class ForElementType : public ForAnyElementType
{
public:
/** Default constructor. */
ForElementType()
{}
FORCEINLINE ElementType* GetAllocation() const
{
return (ElementType*)ForAnyElementType::GetAllocation();
}
};
};
class FDefaultAllocator;
class FDefaultBitArrayAllocator;
/** Encapsulates the allocators used by a sparse array in a single type. */
template<typename InElementAllocator = FDefaultAllocator, typename InBitArrayAllocator = FDefaultBitArrayAllocator>
class TSparseArrayAllocator
{
public:
typedef InElementAllocator ElementAllocator;
typedef InBitArrayAllocator BitArrayAllocator;
};
/** An inline sparse array allocator that allows sizing of the inline allocations for a set number of elements. */
template<
uint32 NumInlineElements,
typename SecondaryAllocator = TSparseArrayAllocator<FDefaultAllocator, FDefaultAllocator>
>
class TInlineSparseArrayAllocator
{
private:
/** The size to allocate inline for the bit array. */
enum { InlineBitArrayDWORDs = (NumInlineElements + NumBitsPerDWORD - 1) / NumBitsPerDWORD };
public:
typedef TInlineAllocator<NumInlineElements, typename SecondaryAllocator::ElementAllocator> ElementAllocator;
typedef TInlineAllocator<InlineBitArrayDWORDs, typename SecondaryAllocator::BitArrayAllocator> BitArrayAllocator;
};
#define DEFAULT_NUMBER_OF_ELEMENTS_PER_HASH_BUCKET 2
#define DEFAULT_BASE_NUMBER_OF_HASH_BUCKETS 8
#define DEFAULT_MIN_NUMBER_OF_HASHED_ELEMENTS 4
static FORCEINLINE uint32 CountLeadingZeros(uint32 Value)
{
unsigned long Log2;
if (_BitScanReverse(&Log2, Value) != 0)
{
return 31 - Log2;
}
return 32;
}
static /* constexpr */ FORCEINLINE uint32 CeilLogTwo(uint32 Arg) // Milxnor: really in FPlatformMath
{
Arg = Arg ? Arg : 1;
return 32 - CountLeadingZeros(Arg - 1);
}
static /* constexpr */ FORCEINLINE uint32 RoundUpToPowerOfTwo(uint32 Arg) // Milxnor: really in FPlatformMath
{
return 1 << CeilLogTwo(Arg);
}
template<
typename InSparseArrayAllocator = TSparseArrayAllocator<>,
typename InHashAllocator = TInlineAllocator<1, FDefaultAllocator>,
uint32 AverageNumberOfElementsPerHashBucket = DEFAULT_NUMBER_OF_ELEMENTS_PER_HASH_BUCKET,
uint32 BaseNumberOfHashBuckets = DEFAULT_BASE_NUMBER_OF_HASH_BUCKETS,
uint32 MinNumberOfHashedElements = DEFAULT_MIN_NUMBER_OF_HASHED_ELEMENTS
>
class TSetAllocator
{
public:
/** Computes the number of hash buckets to use for a given number of elements. */
static FORCEINLINE uint32 GetNumberOfHashBuckets(uint32 NumHashedElements)
{
if (NumHashedElements >= MinNumberOfHashedElements)
{
return RoundUpToPowerOfTwo(NumHashedElements / AverageNumberOfElementsPerHashBucket + BaseNumberOfHashBuckets);
}
return 1;
}
typedef InSparseArrayAllocator SparseArrayAllocator;
typedef InHashAllocator HashAllocator;
};
class FDefaultAllocator;
/** An inline set allocator that allows sizing of the inline allocations for a set number of elements. */
template<
uint32 NumInlineElements,
typename SecondaryAllocator = TSetAllocator<TSparseArrayAllocator<FDefaultAllocator, FDefaultAllocator>, FDefaultAllocator>,
uint32 AverageNumberOfElementsPerHashBucket = DEFAULT_NUMBER_OF_ELEMENTS_PER_HASH_BUCKET,
uint32 MinNumberOfHashedElements = DEFAULT_MIN_NUMBER_OF_HASHED_ELEMENTS
>
class TInlineSetAllocator
{
private:
enum { NumInlineHashBuckets = (NumInlineElements + AverageNumberOfElementsPerHashBucket - 1) / AverageNumberOfElementsPerHashBucket };
static_assert(!(NumInlineHashBuckets& (NumInlineHashBuckets - 1)), "Number of inline buckets must be a power of two");
public:
/** Computes the number of hash buckets to use for a given number of elements. */
static FORCEINLINE uint32 GetNumberOfHashBuckets(uint32 NumHashedElements)
{
const uint32 NumDesiredHashBuckets = RoundUpToPowerOfTwo(NumHashedElements / AverageNumberOfElementsPerHashBucket);
if (NumDesiredHashBuckets < NumInlineHashBuckets)
{
return NumInlineHashBuckets;
}
if (NumHashedElements < MinNumberOfHashedElements)
{
return NumInlineHashBuckets;
}
return NumDesiredHashBuckets;
}
typedef TInlineSparseArrayAllocator<NumInlineElements, typename SecondaryAllocator::SparseArrayAllocator> SparseArrayAllocator;
typedef TInlineAllocator<NumInlineHashBuckets, typename SecondaryAllocator::HashAllocator> HashAllocator;
};
/**
* 'typedefs' for various allocator defaults.
*
* These should be replaced with actual typedefs when Core.h include order is sorted out, as then we won't need to
* 'forward' these TAllocatorTraits specializations below.
*/
class FDefaultAllocator : public FHeapAllocator { public: typedef FHeapAllocator Typedef; };
class FDefaultSetAllocator : public TSetAllocator<> { public: typedef TSetAllocator<> Typedef; };
class FDefaultBitArrayAllocator : public TInlineAllocator<4> { public: typedef TInlineAllocator<4> Typedef; };
class FDefaultSparseArrayAllocator : public TSparseArrayAllocator<> { public: typedef TSparseArrayAllocator<> Typedef; };

View File

@@ -14,11 +14,11 @@ class UDataTable : public UObject
{ {
public: public:
template <typename RowDataType = uint8_t> template <typename RowDataType = uint8_t>
TMap<FName, RowDataType*>& GetRowMap() TMap<FName, RowDataType>& GetRowMap()
{ {
static auto RowStructOffset = FindOffsetStruct("/Script/Engine.DataTable", "RowStruct"); static auto RowStructOffset = FindOffsetStruct("/Script/Engine.DataTable", "RowStruct");
return *(TMap<FName, RowDataType*>*)(__int64(this) + (RowStructOffset + sizeof(UObject*))); // because after rowstruct is rowmap return *(TMap<FName, RowDataType>*)(__int64(this) + (RowStructOffset + sizeof(UObject*))); // because after rowstruct is rowmap
} }
static UClass* StaticClass() static UClass* StaticClass()

View File

@@ -78,9 +78,9 @@ public:
for (auto& AwardEntry : AwardEntriesAtElimMap) for (auto& AwardEntry : AwardEntriesAtElimMap)
{ {
if (AwardEntry.First == Value) if (AwardEntry.Key == Value)
{ {
return AwardEntry.Second; return AwardEntry.Value;
} }
} }
} }

View File

@@ -109,8 +109,8 @@ FName AFortGameModeAthena::RedirectLootTier(const FName& LootTier)
for (auto& Pair : RedirectAthenaLootTierGroups) for (auto& Pair : RedirectAthenaLootTierGroups)
{ {
auto& Key = Pair.Key(); auto& Key = Pair.Key;
auto& Value = Pair.Value(); auto& Value = Pair.Value;
// LOG_INFO(LogDev, "[{}] {} {}", i, Key.ComparisonIndex.Value ? Key.ToString() : "NULL", Key.ComparisonIndex.Value ? Value.ToString() : "NULL"); // LOG_INFO(LogDev, "[{}] {} {}", i, Key.ComparisonIndex.Value ? Key.ToString() : "NULL", Key.ComparisonIndex.Value ? Value.ToString() : "NULL");
@@ -428,6 +428,7 @@ bool AFortGameModeAthena::Athena_ReadyToStartMatchHook(AFortGameModeAthena* Game
else else
{ {
auto OldPlaylist = GetPlaylistForOldVersion(); auto OldPlaylist = GetPlaylistForOldVersion();
SetupEverythingAI();
} }
auto Fortnite_Season = std::floor(Fortnite_Version); auto Fortnite_Season = std::floor(Fortnite_Version);

View File

@@ -41,9 +41,9 @@ float UFortItemDefinition::GetMaxStackSize()
for (auto& Pair : RowMap) for (auto& Pair : RowMap)
{ {
if (Pair.Key() == ScalableFloat.Curve.RowName) if (Pair.Key == ScalableFloat.Curve.RowName)
{ {
Curve = (FSimpleCurve*)Pair.Value(); Curve = (FSimpleCurve*)Pair.Value;
break; break;
} }
} }

View File

@@ -22,10 +22,10 @@ int UFortLootLevel::GetItemLevel(const FDataTableCategoryHandle& LootLevelData,
for (auto& LootLevelDataPair : LootLevelData.DataTable->GetRowMap<FFortLootLevelData>()) for (auto& LootLevelDataPair : LootLevelData.DataTable->GetRowMap<FFortLootLevelData>())
{ {
if (LootLevelDataPair.Second->Category != LootLevelData.RowContents) if (LootLevelDataPair.Value.Category != LootLevelData.RowContents)
continue; continue;
OurLootLevelDatas.push_back(LootLevelDataPair.Second); OurLootLevelDatas.push_back(&LootLevelDataPair.Value);
} }
if (OurLootLevelDatas.size() > 0) if (OurLootLevelDatas.size() > 0)

View File

@@ -47,14 +47,16 @@ void CollectDataTablesRows(const std::vector<UDataTable*>& DataTables, LOOTING_M
DataTablesToIterate.push_back(DataTable); DataTablesToIterate.push_back(DataTable);
} }
return; // T(1)
for (auto CurrentDataTable : DataTablesToIterate) for (auto CurrentDataTable : DataTablesToIterate)
{ {
for (TPair<FName, uint8_t*>& CurrentPair : CurrentDataTable->GetRowMap()) for (auto& CurrentPair : CurrentDataTable->GetRowMap())
{ {
if (Check(CurrentPair.Key(), (RowStructType*)CurrentPair.Value())) if (Check(CurrentPair.Key, (RowStructType*)CurrentPair.Value))
{ {
// LOG_INFO(LogDev, "Setting key with {} comp {} num: {} then iterating through map!", CurrentPair.Key().ToString(), CurrentPair.Key().ComparisonIndex.Value, CurrentPair.Key().Number); // LOG_INFO(LogDev, "Setting key with {} comp {} num: {} then iterating through map!", CurrentPair.Key().ToString(), CurrentPair.Key().ComparisonIndex.Value, CurrentPair.Key().Number);
(*OutMap)[CurrentPair.Key()] = (RowStructType*)CurrentPair.Value(); (*OutMap)[CurrentPair.Key] = (RowStructType*)CurrentPair.Value;
/* for (auto PairInOutMap : *OutMap) /* for (auto PairInOutMap : *OutMap)
{ {
@@ -503,14 +505,14 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
for (auto& Value : PlaylistOverrideLootTableData) for (auto& Value : PlaylistOverrideLootTableData)
{ {
auto CurrentOverrideTag = Value.First; auto CurrentOverrideTag = Value.Key;
if (Tag.TagName == CurrentOverrideTag.TagName) if (Tag.TagName == CurrentOverrideTag.TagName)
{ {
auto OverrideLootPackageTableStr = Value.Second.LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString(); auto OverrideLootPackageTableStr = Value.Value.LootPackageData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootPackageTableStr.contains("Composite"); auto bOverrideIsComposite = OverrideLootPackageTableStr.contains("Composite");
auto ptr = Value.Second.LootPackageData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true); auto ptr = Value.Value.LootPackageData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (ptr) if (ptr)
{ {
@@ -557,14 +559,14 @@ std::vector<LootDrop> PickLootDrops(FName TierGroupName, int WorldLevel, int For
for (auto& Value : PlaylistOverrideLootTableData) for (auto& Value : PlaylistOverrideLootTableData)
{ {
auto CurrentOverrideTag = Value.First; auto CurrentOverrideTag = Value.Key;
if (Tag.TagName == CurrentOverrideTag.TagName) if (Tag.TagName == CurrentOverrideTag.TagName)
{ {
auto OverrideLootTierDataStr = Value.Second.LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString(); auto OverrideLootTierDataStr = Value.Value.LootTierData.SoftObjectPtr.ObjectID.AssetPathName.ToString();
auto bOverrideIsComposite = OverrideLootTierDataStr.contains("Composite"); auto bOverrideIsComposite = OverrideLootTierDataStr.contains("Composite");
auto ptr = Value.Second.LootTierData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true); auto ptr = Value.Value.LootTierData.Get(bOverrideIsComposite ? CompositeDataTableClass : UDataTable::StaticClass(), true);
if (ptr) if (ptr)
{ {

View File

@@ -567,6 +567,10 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
FWeaponUpgradeItemRow* FoundRow = nullptr; FWeaponUpgradeItemRow* FoundRow = nullptr;
/*
T(3)
for (int i = 0; i < LootPackagesRowMap.Pairs.Elements.Data.Num(); i++) for (int i = 0; i < LootPackagesRowMap.Pairs.Elements.Data.Num(); i++)
{ {
auto& Pair = LootPackagesRowMap.Pairs.Elements.Data.at(i).ElementData.Value; auto& Pair = LootPackagesRowMap.Pairs.Elements.Data.at(i).ElementData.Value;
@@ -580,6 +584,8 @@ void AFortPlayerController::ServerAttemptInteractHook(UObject* Context, FFrame*
} }
} }
*/
if (!FoundRow) if (!FoundRow)
{ {
LOG_WARN(LogGame, "Failed to find row!"); LOG_WARN(LogGame, "Failed to find row!");

View File

@@ -17,6 +17,10 @@ int UFortWeaponItemDefinition::GetClipSize()
void* Row = nullptr; void* Row = nullptr;
/*
T(1)
for (int i = 0; i < RowMap.Pairs.Elements.Data.Num(); ++i) for (int i = 0; i < RowMap.Pairs.Elements.Data.Num(); ++i)
{ {
auto& Pair = RowMap.Pairs.Elements.Data.at(i).ElementData.Value; auto& Pair = RowMap.Pairs.Elements.Data.at(i).ElementData.Value;
@@ -28,6 +32,8 @@ int UFortWeaponItemDefinition::GetClipSize()
} }
} }
*/
if (!Row) if (!Row)
return 0; return 0;

View File

@@ -1,4 +1,5 @@
#include "Level.h" #include "Level.h"
#include "reboot.h"
UWorld*& ULevel::GetOwningWorld() UWorld*& ULevel::GetOwningWorld()
{ {
@@ -6,7 +7,7 @@ UWorld*& ULevel::GetOwningWorld()
return Get<UWorld*>(OwningWorldOffset); return Get<UWorld*>(OwningWorldOffset);
} }
bool ULevel::HasVisibilityChangeRequestPending() bool ULevel::HasVisibilityChangeRequestPending() // T(REP)
{ {
// I believe implementation on this changes depending on the version // I believe implementation on this changes depending on the version
@@ -24,6 +25,11 @@ bool ULevel::HasVisibilityChangeRequestPending()
return this == CurrentLevelPendingVisibility || this == CurrentLevelPendingInvisibility; return this == CurrentLevelPendingVisibility || this == CurrentLevelPendingInvisibility;
} }
bool ULevel::IsAssociatingLevel() // T(REP)
{
return false;
}
AWorldSettings* ULevel::GetWorldSettings(bool bChecked) const AWorldSettings* ULevel::GetWorldSettings(bool bChecked) const
{ {
if (bChecked) if (bChecked)
@@ -34,3 +40,9 @@ AWorldSettings* ULevel::GetWorldSettings(bool bChecked) const
static auto WorldSettingsOffset = GetOffset("WorldSettings"); static auto WorldSettingsOffset = GetOffset("WorldSettings");
return Get<AWorldSettings*>(WorldSettingsOffset); return Get<AWorldSettings*>(WorldSettingsOffset);
} }
UClass* ULevel::StaticClass()
{
static auto Class = FindObject<UClass>(L"/Script/Engine.Level");
return Class;
}

View File

@@ -7,5 +7,8 @@ class ULevel : public UObject
public: public:
UWorld*& GetOwningWorld(); UWorld*& GetOwningWorld();
bool HasVisibilityChangeRequestPending(); bool HasVisibilityChangeRequestPending();
bool IsAssociatingLevel();
AWorldSettings* GetWorldSettings(bool bChecked = true) const; AWorldSettings* GetWorldSettings(bool bChecked = true) const;
static class UClass* StaticClass();
}; };

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "Set.h" #include "Set.h"
#include "UnrealTemplate.h"
#include "ChooseClass.h"
// template <typename KeyType, typename ValueType> // template <typename KeyType, typename ValueType>
// using TPair = TTuple<KeyType, ValueType>; // using TPair = TTuple<KeyType, ValueType>;
@@ -9,151 +11,370 @@ template <typename KeyType, typename ValueType>
class TPair class TPair
{ {
public: public:
KeyType First; KeyType Key;
ValueType Second; ValueType Value;
};
FORCEINLINE KeyType& Key() template <typename KeyInitType, typename ValueInitType>
class TPairInitializer
{
public:
typename TRValueToLValueReference<KeyInitType >::Type Key;
typename TRValueToLValueReference<ValueInitType>::Type Value;
/** Initialization constructor. */
FORCEINLINE TPairInitializer(KeyInitType InKey, ValueInitType InValue)
: Key(InKey)
, Value(InValue)
{ {
return First;
} }
FORCEINLINE const KeyType& Key() const
/** Implicit conversion to pair initializer. */
template <typename KeyType, typename ValueType>
FORCEINLINE TPairInitializer(const TPair<KeyType, ValueType>& Pair)
: Key(Pair.Key)
, Value(Pair.Value)
{ {
return First;
} }
FORCEINLINE ValueType& Value()
template <typename KeyType, typename ValueType>
operator TPair<KeyType, ValueType>() const
{ {
return Second; #define StaticCast static_cast // Milxnor: ??
} return TPair<KeyType, ValueType>(StaticCast<KeyInitType>(Key), StaticCast<ValueInitType>(Value));
FORCEINLINE const ValueType& Value() const
{
return Second;
} }
}; };
template <typename KeyType, typename ValueType> template<typename KeyType, typename ValueType, bool bInAllowDuplicateKeys>
class TMap struct TDefaultMapKeyFuncs : BaseKeyFuncs<TPair<KeyType, ValueType>, KeyType, bInAllowDuplicateKeys>
{ {
typedef typename TTypeTraits<KeyType>::ConstPointerType KeyInitType;
typedef const TPairInitializer<typename TTypeTraits<KeyType>::ConstInitType, typename TTypeTraits<ValueType>::ConstInitType>& ElementInitType;
static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
{
return Element.Key;
}
static FORCEINLINE bool Matches(KeyInitType A, KeyInitType B)
{
return A == B;
}
static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
{
return GetTypeHash(Key);
}
};
template<typename KeyType, typename ValueType, bool bInAllowDuplicateKeys>
struct TDefaultMapHashableKeyFuncs : TDefaultMapKeyFuncs<KeyType, ValueType, bInAllowDuplicateKeys>
{
// static_assert(THasGetTypeHash<KeyType>::Value, "TMap must have a hashable KeyType unless a custom key func is provided."); // T(R)
};
template <typename KeyType, typename ValueType, typename SetAllocator, typename KeyFuncs>
class TMapBase
{
template <typename OtherKeyType, typename OtherValueType, typename OtherSetAllocator, typename OtherKeyFuncs>
friend class TMapBase;
friend struct TContainerTraits<TMapBase>;
public: public:
typedef typename TTypeTraits<KeyType >::ConstPointerType KeyConstPointerType;
typedef typename TTypeTraits<KeyType >::ConstInitType KeyInitType;
typedef typename TTypeTraits<ValueType>::ConstInitType ValueInitType;
typedef TPair<KeyType, ValueType> ElementType; typedef TPair<KeyType, ValueType> ElementType;
public: protected:
TSet<ElementType> Pairs; TMapBase() = default;
TMapBase(TMapBase&&) = default;
TMapBase(const TMapBase&) = default;
TMapBase& operator=(TMapBase&&) = default;
TMapBase& operator=(const TMapBase&) = default;
public: typedef TSet<ElementType, KeyFuncs, SetAllocator> ElementSetType;
class FBaseIterator
/** The base of TMapBase iterators. */
template<bool bConst, bool bRangedFor = false>
class TBaseIterator
{ {
public:
typedef typename TChooseClass<
bConst,
typename TChooseClass<bRangedFor, typename ElementSetType::TRangedForConstIterator, typename ElementSetType::TConstIterator>::Result,
typename TChooseClass<bRangedFor, typename ElementSetType::TRangedForIterator, typename ElementSetType::TIterator >::Result
>::Result PairItType;
private: private:
TMap<KeyType, ValueType>& IteratedMap; typedef typename TChooseClass<bConst, const TMapBase, TMapBase>::Result MapType;
TSet<ElementType>::FBaseIterator SetIt; typedef typename TChooseClass<bConst, const KeyType, KeyType>::Result ItKeyType;
typedef typename TChooseClass<bConst, const ValueType, ValueType>::Result ItValueType;
typedef typename TChooseClass<bConst, const typename ElementSetType::ElementType, typename ElementSetType::ElementType>::Result PairType;
public: public:
FBaseIterator(TMap<KeyType, ValueType>& InMap, TSet<ElementType>::FBaseIterator InSet) FORCEINLINE TBaseIterator(const PairItType& InElementIt)
: IteratedMap(InMap) : PairIt(InElementIt)
, SetIt(InSet)
{ {
} }
FORCEINLINE TMap<KeyType, ValueType>::FBaseIterator operator++()
FORCEINLINE TBaseIterator& operator++()
{
++PairIt;
return *this;
}
/** conversion to "bool" returning true if the iterator is valid. */
FORCEINLINE explicit operator bool() const
{
return !!PairIt;
}
/** inverse of the "bool" operator */
FORCEINLINE bool operator !() const
{
return !(bool)*this;
}
FORCEINLINE friend bool operator==(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.PairIt == Rhs.PairIt; }
FORCEINLINE friend bool operator!=(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.PairIt != Rhs.PairIt; }
FORCEINLINE ItKeyType& Key() const { return PairIt->Key; }
FORCEINLINE ItValueType& Value() const { return PairIt->Value; }
FORCEINLINE PairType& operator* () const { return *PairIt; }
FORCEINLINE PairType* operator->() const { return &*PairIt; }
protected:
PairItType PairIt;
};
/** The base type of iterators that iterate over the values associated with a specified key. */
template<bool bConst>
class TBaseKeyIterator
{
private:
typedef typename TChooseClass<bConst, typename ElementSetType::TConstKeyIterator, typename ElementSetType::TKeyIterator>::Result SetItType;
typedef typename TChooseClass<bConst, const KeyType, KeyType>::Result ItKeyType;
typedef typename TChooseClass<bConst, const ValueType, ValueType>::Result ItValueType;
public:
/** Initialization constructor. */
FORCEINLINE TBaseKeyIterator(const SetItType& InSetIt)
: SetIt(InSetIt)
{
}
FORCEINLINE TBaseKeyIterator& operator++()
{ {
++SetIt; ++SetIt;
return *this; return *this;
} }
FORCEINLINE TMap<KeyType, ValueType>::ElementType& operator*()
/** conversion to "bool" returning true if the iterator is valid. */
FORCEINLINE explicit operator bool() const
{ {
return *SetIt; return !!SetIt;
} }
FORCEINLINE const TMap<KeyType, ValueType>::ElementType& operator*() const /** inverse of the "bool" operator */
FORCEINLINE bool operator !() const
{ {
return *SetIt; return !(bool)*this;
} }
FORCEINLINE bool operator==(const TMap<KeyType, ValueType>::FBaseIterator& Other) const
FORCEINLINE ItKeyType& Key() const { return SetIt->Key; }
FORCEINLINE ItValueType& Value() const { return SetIt->Value; }
protected:
SetItType SetIt;
};
/** A set of the key-value pairs in the map. */
ElementSetType Pairs;
public:
/** Map iterator. */
class TIterator : public TBaseIterator<false>
{
public:
/** Initialization constructor. */
FORCEINLINE TIterator(TMapBase& InMap, bool bInRequiresRehashOnRemoval = false)
: TBaseIterator<false>(InMap.Pairs.CreateIterator())
, Map(InMap)
, bElementsHaveBeenRemoved(false)
, bRequiresRehashOnRemoval(bInRequiresRehashOnRemoval)
{ {
return SetIt == Other.SetIt;
} }
FORCEINLINE bool operator!=(const TMap<KeyType, ValueType>::FBaseIterator& Other) const
/** Destructor. */
FORCEINLINE ~TIterator()
{ {
return SetIt != Other.SetIt; if (bElementsHaveBeenRemoved && bRequiresRehashOnRemoval)
{
Map.Pairs.Relax();
} }
FORCEINLINE bool IsElementValid() const }
/** Removes the current pair from the map. */
FORCEINLINE void RemoveCurrent()
{
TBaseIterator<false>::PairIt.RemoveCurrent();
bElementsHaveBeenRemoved = true;
}
private:
TMapBase& Map;
bool bElementsHaveBeenRemoved;
bool bRequiresRehashOnRemoval;
};
/** Const map iterator. */
class TConstIterator : public TBaseIterator<true>
{
public:
FORCEINLINE TConstIterator(const TMapBase& InMap)
: TBaseIterator<true>(InMap.Pairs.CreateConstIterator())
{ {
return SetIt.IsElementValid();
} }
}; };
FORCEINLINE TMap<KeyType, ValueType>::FBaseIterator begin() using TRangedForIterator = TBaseIterator<false, true>;
using TRangedForConstIterator = TBaseIterator<true, true>;
/** Iterates over values associated with a specified key in a const map. */
class TConstKeyIterator : public TBaseKeyIterator<true>
{ {
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.begin()); public:
} FORCEINLINE TConstKeyIterator(const TMapBase& InMap, KeyInitType InKey)
FORCEINLINE const TMap<KeyType, ValueType>::FBaseIterator begin() const : TBaseKeyIterator<true>(typename ElementSetType::TConstKeyIterator(InMap.Pairs, InKey))
{}
};
/** Iterates over values associated with a specified key in a map. */
class TKeyIterator : public TBaseKeyIterator<false>
{ {
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.begin()); public:
} FORCEINLINE TKeyIterator(TMapBase& InMap, KeyInitType InKey)
FORCEINLINE TMap<KeyType, ValueType>::FBaseIterator end() : TBaseKeyIterator<false>(typename ElementSetType::TKeyIterator(InMap.Pairs, InKey))
{}
/** Removes the current key-value pair from the map. */
FORCEINLINE void RemoveCurrent()
{ {
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.end()); TBaseKeyIterator<false>::SetIt.RemoveCurrent();
} }
FORCEINLINE const TMap<KeyType, ValueType>::FBaseIterator end() const };
/** Creates an iterator over all the pairs in this map */
FORCEINLINE TIterator CreateIterator()
{ {
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.end()); return TIterator(*this);
} }
FORCEINLINE ValueType& operator[](const KeyType& Key)
/** Creates a const iterator over all the pairs in this map */
FORCEINLINE TConstIterator CreateConstIterator() const
{ {
return this->GetByKey(Key); return TConstIterator(*this);
} }
FORCEINLINE const ValueType& operator[](const KeyType& Key) const
/** Creates an iterator over the values associated with a specified key in a map */
FORCEINLINE TKeyIterator CreateKeyIterator(KeyInitType InKey)
{ {
return this->GetByKey(Key); return TKeyIterator(*this, InKey);
} }
/** Creates a const iterator over the values associated with a specified key in a map */
FORCEINLINE TConstKeyIterator CreateConstKeyIterator(KeyInitType InKey) const
{
return TConstKeyIterator(*this, InKey);
}
FORCEINLINE ValueType* Find(KeyConstPointerType Key)
{
if (auto* Pair = Pairs.Find(Key))
{
return &Pair->Value;
}
return nullptr;
}
FORCEINLINE const ValueType& FindChecked(KeyConstPointerType Key) const
{
const auto* Pair = Pairs.Find(Key);
// check(Pair != nullptr);
return Pair->Value;
}
/**
* Find a reference to the value associated with a specified key.
*
* @param Key The key to search for.
* @return The value associated with the specified key, or triggers an assertion if the key does not exist.
*/
FORCEINLINE ValueType& FindChecked(KeyConstPointerType Key)
{
auto* Pair = Pairs.Find(Key);
// check(Pair != nullptr);
return Pair->Value;
}
FORCEINLINE ValueType FindRef(KeyConstPointerType Key) const
{
if (const auto* Pair = Pairs.Find(Key))
{
return Pair->Value;
}
return ValueType();
}
FORCEINLINE int32 Num() const FORCEINLINE int32 Num() const
{ {
return Pairs.Num(); return Pairs.Num();
} }
FORCEINLINE bool IsValid() const
{
return Pairs.IsValid();
}
FORCEINLINE bool IsIndexValid(int32 IndexToCheck) const
{
return Pairs.IsIndexValid(IndexToCheck);
}
FORCEINLINE bool Contains(const KeyType& ElementToLookFor) const
{
for (auto& Element : *this)
{
if (Element.Key() == ElementToLookFor)
return true;
}
return false;
}
FORCEINLINE ValueType& GetByKey(const KeyType& Key, bool* wasSuccessful = nullptr)
{
for (auto& Pair : *this)
{
if (Pair.Key() == Key)
{
if (wasSuccessful)
*wasSuccessful = true;
return Pair.Value(); private:
} /**
} * DO NOT USE DIRECTLY
* STL-like iterators to enable range-based for loop support.
// LOG_INFO(LogDev, "Failed to find Key!!!"); */
FORCEINLINE friend TRangedForIterator begin(TMapBase& MapBase) { return TRangedForIterator(begin(MapBase.Pairs)); }
if (wasSuccessful) FORCEINLINE friend TRangedForConstIterator begin(const TMapBase& MapBase) { return TRangedForConstIterator(begin(MapBase.Pairs)); }
*wasSuccessful = false; FORCEINLINE friend TRangedForIterator end(TMapBase& MapBase) { return TRangedForIterator(end(MapBase.Pairs)); }
} FORCEINLINE friend TRangedForConstIterator end(const TMapBase& MapBase) { return TRangedForConstIterator(end(MapBase.Pairs)); }
FORCEINLINE ValueType& Find(const KeyType& Key, bool* wasSuccessful = nullptr) };
{
return GetByKey(Key, wasSuccessful); template <typename KeyType, typename ValueType, typename SetAllocator, typename KeyFuncs>
} class TSortableMapBase : public TMapBase<KeyType, ValueType, SetAllocator, KeyFuncs>
FORCEINLINE ValueType GetByKeyNoRef(const KeyType& Key) {
{ // friend struct TContainerTraits<TSortableMapBase>;
for (auto& Pair : *this)
{ protected:
if (Pair.Key() == Key) typedef TMapBase<KeyType, ValueType, SetAllocator, KeyFuncs> Super;
{
return Pair.Value(); TSortableMapBase() = default;
} TSortableMapBase(TSortableMapBase&&) = default;
} TSortableMapBase(const TSortableMapBase&) = default;
} TSortableMapBase& operator=(TSortableMapBase&&) = default;
TSortableMapBase& operator=(const TSortableMapBase&) = default;
};
template<typename KeyType, typename ValueType, typename SetAllocator = FDefaultSetAllocator, typename KeyFuncs = TDefaultMapHashableKeyFuncs<KeyType,ValueType,false>>
class TMap : public TSortableMapBase<KeyType, ValueType, SetAllocator, KeyFuncs>
{
public:
typedef TSortableMapBase<KeyType, ValueType, SetAllocator, KeyFuncs> Super;
typedef typename Super::KeyInitType KeyInitType;
typedef typename Super::KeyConstPointerType KeyConstPointerType;
typedef TPair<KeyType, ValueType> ElementType;
public:
typedef TSet<ElementType, KeyFuncs, SetAllocator> ElementSetType;
public:
TMap() = default;
TMap(TMap&&) = default;
TMap(const TMap&) = default;
TMap& operator=(TMap&&) = default;
TMap& operator=(const TMap&) = default;
}; };

View File

@@ -77,3 +77,10 @@ struct FName
return GetComparisonIndexFast() < Rhs.GetComparisonIndexFast(); return GetComparisonIndexFast() < Rhs.GetComparisonIndexFast();
} }
}; };
inline uint32 GetTypeHash(const FName N)
{
return N.ComparisonIndex.Value + N.GetNumber();
}
#define NAME_None FName(0);

View File

@@ -6,10 +6,37 @@
#include "WeakObjectPtrTemplates.h" #include "WeakObjectPtrTemplates.h"
#include "ActorChannel.h" #include "ActorChannel.h"
#include <memcury.h> #include <memcury.h>
#include "KismetStringLibrary.h"
class UNetConnection : public UPlayer class UNetConnection : public UPlayer
{ {
public: public:
static inline UChannel* (*originalCreateChannel)(UNetConnection*, int, bool, int32_t);
static inline UChannel* (*originalCreateChannelByName)(UNetConnection* Connection, FName* ChName, EChannelCreateFlags CreateFlags, int32_t ChannelIndex);
TSet<FNetworkGUID>& GetDestroyedStartupOrDormantActors() // T(REP)
{
static int off = Fortnite_Version == 1.11 ? 0x33678 : 0;
return *(TSet<FNetworkGUID>*)(__int64(this) + off);
}
UChannel* CreateChannel(EChannelType ChannelType, bool bOpenedLocally, EChannelCreateFlags CreateFlags, int32 ChannelIndex = INDEX_NONE)
{
if (Engine_Version >= 422)
{
FString ActorStr = L"Actor";
FName ActorName = UKismetStringLibrary::Conv_StringToName(ActorStr);
int ChannelIndex = -1; // 4294967295
return (UActorChannel*)originalCreateChannelByName(this, &ActorName, CreateFlags, ChannelIndex);
}
else
{
return (UActorChannel*)originalCreateChannel(this, ChannelType, bOpenedLocally, ChannelIndex);
}
}
AActor*& GetOwningActor() AActor*& GetOwningActor()
{ {
static auto OwningActorOffset = GetOffset("OwningActor"); static auto OwningActorOffset = GetOffset("OwningActor");
@@ -22,13 +49,24 @@ public:
return *(FName*)(__int64(this) + ClientWorldPackageNameOffset); return *(FName*)(__int64(this) + ClientWorldPackageNameOffset);
} }
AActor*& GetViewTarget() inline AActor*& GetViewTarget()
{ {
static auto ViewTargetOffset = GetOffset("ViewTarget"); static auto ViewTargetOffset = GetOffset("ViewTarget");
return Get<AActor*>(ViewTargetOffset); return Get<AActor*>(ViewTargetOffset);
} }
int32 IsNetReady(bool Saturate) bool& GetTimeSensitive() // T(REP)
{
return *(bool*)(0);
}
TArray<class UChildConnection*>& GetChildren()
{
static auto ChildrenOffset = GetOffset("Children");
return Get<TArray<class UChildConnection*>>(ChildrenOffset);
}
int32 IsNetReady(bool Saturate) // T(REP)
{ {
static auto IsNetReadyOffset = 0x298; // 1.11 static auto IsNetReadyOffset = 0x298; // 1.11
int32 (*IsNetReadyOriginal)(UNetConnection* Connection, bool Saturate) = decltype(IsNetReadyOriginal)(this->VFTable[IsNetReadyOffset / 8]); int32 (*IsNetReadyOriginal)(UNetConnection* Connection, bool Saturate) = decltype(IsNetReadyOriginal)(this->VFTable[IsNetReadyOffset / 8]);

File diff suppressed because it is too large Load Diff

View File

@@ -56,15 +56,6 @@ struct FNetworkObjectInfo
TSet<TWeakObjectPtr<UNetConnection>> RecentlyDormantConnections; TSet<TWeakObjectPtr<UNetConnection>> RecentlyDormantConnections;
}; };
struct FNetViewer
{
UNetConnection* Connection; // 0x0000(0x0008) (ZeroConstructor, IsPlainOldData)
AActor* InViewer; // 0x0008(0x0008) (ZeroConstructor, IsPlainOldData)
AActor* ViewTarget; // 0x0010(0x0008) (ZeroConstructor, IsPlainOldData)
FVector ViewLocation; // 0x0018(0x000C) (IsPlainOldData)
FVector ViewDir;
};
class FNetworkObjectList class FNetworkObjectList
{ {
public: public:
@@ -77,6 +68,7 @@ public:
TMap<TWeakObjectPtr<UNetConnection>, int32> NumDormantObjectsPerConnection; TMap<TWeakObjectPtr<UNetConnection>, int32> NumDormantObjectsPerConnection;
void Remove(AActor* const Actor); void Remove(AActor* const Actor);
const FNetworkObjectSet& GetActiveObjects() const { return ActiveNetworkObjects; }
}; };
struct FActorPriority struct FActorPriority
@@ -130,6 +122,13 @@ public:
static void TickFlushHook(UNetDriver* NetDriver); static void TickFlushHook(UNetDriver* NetDriver);
TMap<FNetworkGUID, FActorDestructionInfo>& GetDestroyedStartupOrDormantActors() // T(REP)
{
static int off = Fortnite_Version == 1.11 ? 0x228 : 0; // 0x240
return *(TMap<FNetworkGUID, FActorDestructionInfo>*)(__int64(this) + off);
}
int& GetMaxInternetClientRate() int& GetMaxInternetClientRate()
{ {
static auto MaxInternetClientRateOffset = GetOffset("MaxInternetClientRate"); static auto MaxInternetClientRateOffset = GetOffset("MaxInternetClientRate");
@@ -142,13 +141,19 @@ public:
return Get<int>(MaxClientRateOffset); return Get<int>(MaxClientRateOffset);
} }
FName& GetNetDriverName()
{
static auto NetDriverNameOffset = GetOffset("NetDriverName");
return Get<FName>(NetDriverNameOffset);
}
FNetGUIDCache* GetGuidCache() FNetGUIDCache* GetGuidCache()
{ {
static auto GuidCacheOffset = GetOffset("WorldPackage") + 8; // checked for 1.11 static auto GuidCacheOffset = GetOffset("WorldPackage") + 8; // checked for 1.11
return GetPtr<FNetGUIDCache>(GuidCacheOffset); return GetPtr<FNetGUIDCache>(GuidCacheOffset);
} }
UWorld*& GetNetDriverWorld() const UWorld*& World() const
{ {
static auto WorldOffset = GetOffset("World"); static auto WorldOffset = GetOffset("World");
return Get<UWorld*>(WorldOffset); return Get<UWorld*>(WorldOffset);
@@ -195,8 +200,9 @@ public:
bool InitListen(FNetworkNotify* InNotify, FURL& ListenURL, bool bReuseAddressAndPort, FString& Error) { return InitListenOriginal(this, InNotify, ListenURL, bReuseAddressAndPort, Error); } 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); } void SetWorld(UWorld* World) { return SetWorldOriginal(this, World); }
int32 ServerReplicateActors(); int32 ServerReplicateActors();
int32 ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, FActorPriority** PriorityActors, const int32 FinalSortedCount, int32& OutUpdated); int32 ServerReplicateActors_PrepConnections();
int32 ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, std::vector<FActorPriority*>& PriorityActors, const int32 FinalSortedCount, int32& OutUpdated);
void ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList, const float ServerTickTime); void ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList, const float ServerTickTime);
int32 ServerReplicateActors_PrioritizeActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, const std::vector<FNetworkObjectInfo*> ConsiderList, const bool bCPUSaturated, FActorPriority*& OutPriorityList, FActorPriority**& OutPriorityActors); int32 ServerReplicateActors_PrioritizeActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, const std::vector<FNetworkObjectInfo*>& ConsiderList, const bool bCPUSaturated, std::vector<FActorPriority>& OutPriorityList, std::vector<FActorPriority*>& OutPriorityActors);
FNetworkObjectList& GetNetworkObjectList(); FNetworkObjectList& GetNetworkObjectList();
}; };

View File

@@ -1,7 +1,8 @@
#include "NetDriver.h" #include "NetDriver.h"
void FNetworkObjectList::Remove(AActor* const Actor) void FNetworkObjectList::Remove(AActor* const Actor) // T(REP)
{ {
#if 0
if (Actor == nullptr) if (Actor == nullptr)
{ {
return; return;
@@ -103,5 +104,7 @@ void FNetworkObjectList::Remove(AActor* const Actor)
} }
} }
#endif
// check((ActiveNetworkObjects.Num() + ObjectsDormantOnAllConnections.Num()) == AllNetworkObjects.Num()); // check((ActiveNetworkObjects.Num() + ObjectsDormantOnAllConnections.Num()) == AllNetworkObjects.Num());
} }

View File

@@ -0,0 +1,11 @@
#pragma once
// magic number distances used by AI/networking
#define CLOSEPROXIMITY 500.f
#define NEARSIGHTTHRESHOLD 2000.f
#define MEDSIGHTTHRESHOLD 3162.f
#define FARSIGHTTHRESHOLD 8000.f
#define CLOSEPROXIMITYSQUARED (CLOSEPROXIMITY*CLOSEPROXIMITY)
#define NEARSIGHTTHRESHOLDSQUARED (NEARSIGHTTHRESHOLD*NEARSIGHTTHRESHOLD)
#define MEDSIGHTTHRESHOLDSQUARED (MEDSIGHTTHRESHOLD*MEDSIGHTTHRESHOLD)
#define FARSIGHTTHRESHOLDSQUARED (FARSIGHTTHRESHOLD*FARSIGHTTHRESHOLD)

View File

@@ -7,6 +7,21 @@
#include "UObjectArray.h" #include "UObjectArray.h"
#include "Package.h" #include "Package.h"
UObject* UObject::GetTypedOuter(UClass* Target) const
{
// ensureMsgf(Target != UPackage::StaticClass(), TEXT("Calling GetTypedOuter to retrieve a package is now invalid, you should use GetPackage() instead."));
UObject* Result = NULL;
for (UObject* NextOuter = GetOuter(); Result == NULL && NextOuter != NULL; NextOuter = NextOuter->GetOuter())
{
if (NextOuter->IsA(Target))
{
Result = NextOuter;
}
}
return Result;
}
void* UObject::GetProperty(const std::string& ChildName, bool bWarnIfNotFound) const void* UObject::GetProperty(const std::string& ChildName, bool bWarnIfNotFound) const
{ {
for (auto CurrentClass = ClassPrivate; CurrentClass; CurrentClass = *(UClass**)(__int64(CurrentClass) + Offsets::SuperStruct)) for (auto CurrentClass = ClassPrivate; CurrentClass; CurrentClass = *(UClass**)(__int64(CurrentClass) + Offsets::SuperStruct))

View File

@@ -78,6 +78,14 @@ public:
void SetBitfieldValue(int Offset, uint8_t FieldMask, bool NewValue); void SetBitfieldValue(int Offset, uint8_t FieldMask, bool NewValue);
void SetBitfieldValue(const std::string& ChildName, uint8_t FieldMask, bool NewValue) { return SetBitfieldValue(GetOffset(ChildName), FieldMask, NewValue); } void SetBitfieldValue(const std::string& ChildName, uint8_t FieldMask, bool NewValue) { return SetBitfieldValue(GetOffset(ChildName), FieldMask, NewValue); }
UObject* GetTypedOuter(UClass* Target) const;
template<typename T>
T* GetTypedOuter() const
{
return (T*)GetTypedOuter(T::StaticClass());
}
/* template <typename T = UObject*> /* template <typename T = UObject*>
T& GetCached(const std::string& ChildName) T& GetCached(const std::string& ChildName)
{ {

View File

@@ -10,6 +10,8 @@
class APlayerController : public AController class APlayerController : public AController
{ {
public: public:
static inline void (*originalSendClientAdjustment)(APlayerController*);
UCheatManager*& GetCheatManager() UCheatManager*& GetCheatManager()
{ {
static auto CheatManagerOffset = this->GetOffset("CheatManager"); static auto CheatManagerOffset = this->GetOffset("CheatManager");

View File

@@ -308,6 +308,8 @@
<ClInclude Include="BuildingTrap.h" /> <ClInclude Include="BuildingTrap.h" />
<ClInclude Include="Channel.h" /> <ClInclude Include="Channel.h" />
<ClInclude Include="CheatManager.h" /> <ClInclude Include="CheatManager.h" />
<ClInclude Include="ChildConnection.h" />
<ClInclude Include="ChooseClass.h" />
<ClInclude Include="Class.h" /> <ClInclude Include="Class.h" />
<ClInclude Include="commands.h" /> <ClInclude Include="commands.h" />
<ClInclude Include="ContainerAllocationPolicies.h" /> <ClInclude Include="ContainerAllocationPolicies.h" />
@@ -446,6 +448,7 @@
<ClInclude Include="NetDriver.h" /> <ClInclude Include="NetDriver.h" />
<ClInclude Include="NetSerialization.h" /> <ClInclude Include="NetSerialization.h" />
<ClInclude Include="NetworkGuid.h" /> <ClInclude Include="NetworkGuid.h" />
<ClInclude Include="NetworkingDistanceConstants.h" />
<ClInclude Include="NumericLimits.h" /> <ClInclude Include="NumericLimits.h" />
<ClInclude Include="Object.h" /> <ClInclude Include="Object.h" />
<ClInclude Include="ObjectMacros.h" /> <ClInclude Include="ObjectMacros.h" />
@@ -499,6 +502,7 @@
<ClInclude Include="WeakObjectPtr.h" /> <ClInclude Include="WeakObjectPtr.h" />
<ClInclude Include="WeakObjectPtrTemplates.h" /> <ClInclude Include="WeakObjectPtrTemplates.h" />
<ClInclude Include="World.h" /> <ClInclude Include="World.h" />
<ClInclude Include="WorldSettings.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="DelegateSignatureImpl.inl" /> <None Include="DelegateSignatureImpl.inl" />

View File

@@ -987,6 +987,18 @@
<ClInclude Include="botnames.h"> <ClInclude Include="botnames.h">
<Filter>Reboot\Public</Filter> <Filter>Reboot\Public</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ChildConnection.h">
<Filter>Engine\Source\Runtime\Engine\Classes\Engine</Filter>
</ClInclude>
<ClInclude Include="WorldSettings.h">
<Filter>Engine\Source\Runtime\Engine\Classes\GameFramework</Filter>
</ClInclude>
<ClInclude Include="ChooseClass.h">
<Filter>Engine\Source\Runtime\Core\Public\Templates</Filter>
</ClInclude>
<ClInclude Include="NetworkingDistanceConstants.h">
<Filter>Engine\Source\Runtime\Engine\Public</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Engine"> <Filter Include="Engine">

View File

@@ -1,6 +1,10 @@
// Copied from 4.19
#pragma once #pragma once
#include "SparseArray.h" #include "SparseArray.h"
#include "ChooseClass.h"
#include "UnrealTypeTraits.h"
template <typename ElementType> template <typename ElementType>
class TSetElement class TSetElement
@@ -32,112 +36,434 @@ public:
} }
}; };
template <typename SetType> /** Either NULL or an identifier for an element of a set. */
class FSetElementId
{
public:
template<typename, typename, typename>
friend class TSet;
friend class FScriptSet;
/** Default constructor. */
FORCEINLINE FSetElementId() :
Index(INDEX_NONE)
{}
/** @return a boolean value representing whether the id is NULL. */
FORCEINLINE bool IsValidId() const
{
return Index != INDEX_NONE;
}
/** Comparison operator. */
FORCEINLINE friend bool operator==(const FSetElementId& A, const FSetElementId& B)
{
return A.Index == B.Index;
}
FORCEINLINE int32 AsInteger() const
{
return Index;
}
FORCEINLINE static FSetElementId FromInteger(int32 Integer)
{
return FSetElementId(Integer);
}
private:
/** The index of the element in the set's element array. */
int32 Index;
/** Initialization constructor. */
FORCEINLINE FSetElementId(int32 InIndex) :
Index(InIndex)
{}
/** Implicit conversion to the element index. */
FORCEINLINE operator int32() const
{
return Index;
}
};
template<typename ElementType, typename InKeyType, bool bInAllowDuplicateKeys = false>
struct BaseKeyFuncs
{
typedef InKeyType KeyType;
typedef typename TCallTraits<InKeyType>::ParamType KeyInitType;
typedef typename TCallTraits<ElementType>::ParamType ElementInitType;
enum { bAllowDuplicateKeys = bInAllowDuplicateKeys };
};
/**
* A default implementation of the KeyFuncs used by TSet which uses the element as a key.
*/
template<typename ElementType, bool bInAllowDuplicateKeys = false>
struct DefaultKeyFuncs : BaseKeyFuncs<ElementType, ElementType, bInAllowDuplicateKeys>
{
typedef typename TCallTraits<ElementType>::ParamType KeyInitType;
typedef typename TCallTraits<ElementType>::ParamType ElementInitType;
/**
* @return The key used to index the given element.
*/
static FORCEINLINE KeyInitType GetSetKey(ElementInitType Element)
{
return Element;
}
/**
* @return True if the keys match.
*/
static FORCEINLINE bool Matches(KeyInitType A, KeyInitType B)
{
return A == B;
}
/** Calculates a hash index for a key. */
static FORCEINLINE uint32 GetKeyHash(KeyInitType Key)
{
return GetTypeHash(Key);
}
};
template<
typename InElementType,
typename KeyFuncs = DefaultKeyFuncs<InElementType>,
typename Allocator = FDefaultSetAllocator
>
class TSet;
template<
typename InElementType,
typename KeyFuncs /*= DefaultKeyFuncs<ElementType>*/,
typename Allocator /*= FDefaultSetAllocator*/
>
class TSet class TSet
{ {
private: private:
friend TSparseArray; friend TSparseArray;
public: public:
typedef TSetElement<SetType> ElementType; typedef typename KeyFuncs::KeyInitType KeyInitType;
typedef TSparseArrayElementOrListLink<ElementType> ArrayElementType; typedef typename KeyFuncs::ElementInitType ElementInitType;
typedef TSetElement<InElementType> SetElementType;
typedef InElementType ElementType;
public: public:
TSparseArray<ElementType> Elements; typedef TSparseArray<SetElementType, typename Allocator::SparseArrayAllocator> ElementArrayType;
typedef typename Allocator::HashAllocator::template ForElementType<FSetElementId> HashType;
mutable TInlineAllocator<1>::ForElementType<int> Hash; ElementArrayType Elements;
mutable HashType Hash;
mutable int32 HashSize; mutable int32 HashSize;
FORCEINLINE FSetElementId& GetTypedHash(int32 HashIndex) const
{
return ((FSetElementId*)Hash.GetAllocation())[HashIndex & (HashSize - 1)];
}
public: public:
class FBaseIterator FORCEINLINE ElementType* Find(KeyInitType Key)
{
FSetElementId ElementId = FindId(Key);
if (ElementId.IsValidId())
{
return &Elements[ElementId].Value;
}
else
{
return NULL;
}
}
/**
* Finds an element with the given key in the set.
* @param Key - The key to search for.
* @return A const pointer to an element with the given key. If no element in the set has the given key, this will return NULL.
*/
FORCEINLINE const ElementType* Find(KeyInitType Key) const
{
FSetElementId ElementId = FindId(Key);
if (ElementId.IsValidId())
{
return &Elements[ElementId].Value;
}
else
{
return NULL;
}
}
/** Adds an element to the hash. */
FORCEINLINE void HashElement(FSetElementId ElementId, const SetElementType& Element) const
{
// Compute the hash bucket the element goes in.
Element.HashIndex = KeyFuncs::GetKeyHash(KeyFuncs::GetSetKey(Element.Value)) & (HashSize - 1);
// Link the element into the hash bucket.
Element.HashNextId = GetTypedHash(Element.HashIndex);
GetTypedHash(Element.HashIndex) = ElementId;
}
/**
* Checks if the hash has an appropriate number of buckets, and if not resizes it.
* @param NumHashedElements - The number of elements to size the hash for.
* @param bAllowShrinking - true if the hash is allowed to shrink.
* @return true if the set was rehashed.
*/
bool ConditionalRehash(int32 NumHashedElements, bool bAllowShrinking = false) const
{
// Calculate the desired hash size for the specified number of elements.
const int32 DesiredHashSize = Allocator::GetNumberOfHashBuckets(NumHashedElements);
// If the hash hasn't been created yet, or is smaller than the desired hash size, rehash.
if (NumHashedElements > 0 &&
(!HashSize ||
HashSize < DesiredHashSize ||
(HashSize > DesiredHashSize && bAllowShrinking)))
{
HashSize = DesiredHashSize;
Rehash();
return true;
}
else
{
return false;
}
}
/** Resizes the hash. */
void Rehash() const
{
// Free the old hash.
Hash.ResizeAllocation(0, 0, sizeof(FSetElementId));
int32 LocalHashSize = HashSize;
if (LocalHashSize)
{
// Allocate the new hash.
// checkSlow(FMath::IsPowerOfTwo(HashSize));
Hash.ResizeAllocation(0, LocalHashSize, sizeof(FSetElementId));
for (int32 HashIndex = 0; HashIndex < LocalHashSize; ++HashIndex)
{
GetTypedHash(HashIndex) = FSetElementId();
}
// Add the existing elements to the new hash.
for (typename ElementArrayType::TConstIterator ElementIt(Elements); ElementIt; ++ElementIt)
{
HashElement(FSetElementId(ElementIt.GetIndex()), *ElementIt);
}
}
}
template<bool bConst, bool bRangedFor = false>
class TBaseIterator
{ {
private: private:
TSet<SetType>& IteratedSet; friend class TSet;
TSparseArray<ElementType>::FBaseIterator ElementIt;
typedef typename TChooseClass<bConst, const ElementType, ElementType>::Result ItElementType;
public: public:
FORCEINLINE FBaseIterator(const TSet<SetType>& InSet, TSparseArray<TSetElement<SetType>>::FBaseIterator InElementIt) typedef typename TChooseClass<
: IteratedSet(const_cast<TSet<SetType>&>(InSet)) bConst,
, ElementIt(InElementIt) typename TChooseClass<bRangedFor, typename ElementArrayType::TRangedForConstIterator, typename ElementArrayType::TConstIterator>::Result,
typename TChooseClass<bRangedFor, typename ElementArrayType::TRangedForIterator, typename ElementArrayType::TIterator >::Result
>::Result ElementItType;
FORCEINLINE TBaseIterator(const ElementItType& InElementIt)
: ElementIt(InElementIt)
{ {
} }
FORCEINLINE explicit operator bool() const /** Advances the iterator to the next element. */
{ FORCEINLINE TBaseIterator& operator++()
return (bool)ElementIt;
}
FORCEINLINE TSet<SetType>::FBaseIterator& operator++()
{ {
++ElementIt; ++ElementIt;
return *this; return *this;
} }
FORCEINLINE bool operator==(const TSet<SetType>::FBaseIterator& OtherIt) const
/** conversion to "bool" returning true if the iterator is valid. */
FORCEINLINE explicit operator bool() const
{ {
return ElementIt == OtherIt.ElementIt; return !!ElementIt;
} }
FORCEINLINE bool operator!=(const TSet<SetType>::FBaseIterator& OtherIt) const /** inverse of the "bool" operator */
FORCEINLINE bool operator !() const
{ {
return ElementIt != OtherIt.ElementIt; return !(bool)*this;
} }
FORCEINLINE TSet<SetType>::FBaseIterator& operator=(TSet<SetType>::FBaseIterator& OtherIt)
// Accessors.
FORCEINLINE FSetElementId GetId() const
{ {
return ElementIt = OtherIt.ElementIt; return TSet::IndexToId(ElementIt.GetIndex());
} }
FORCEINLINE SetType& operator*() FORCEINLINE ItElementType* operator->() const
{ {
return (*ElementIt).Value; return &ElementIt->Value;
} }
FORCEINLINE const SetType& operator*() const FORCEINLINE ItElementType& operator*() const
{ {
return &((*ElementIt).Value); return ElementIt->Value;
} }
FORCEINLINE SetType* operator->()
FORCEINLINE friend bool operator==(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.ElementIt == Rhs.ElementIt; }
FORCEINLINE friend bool operator!=(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.ElementIt != Rhs.ElementIt; }
ElementItType ElementIt;
};
/** The base type of whole set iterators. */
template<bool bConst>
class TBaseKeyIterator
{ {
return &((*ElementIt).Value); private:
typedef typename TChooseClass<bConst, const TSet, TSet>::Result SetType;
typedef typename TChooseClass<bConst, const ElementType, ElementType>::Result ItElementType;
public:
/** Initialization constructor. */
FORCEINLINE TBaseKeyIterator(SetType& InSet, KeyInitType InKey)
: Set(InSet)
, Key(InKey)
, Id()
{
// The set's hash needs to be initialized to find the elements with the specified key.
Set.ConditionalRehash(Set.Elements.Num());
if (Set.HashSize)
{
NextId = Set.GetTypedHash(KeyFuncs::GetKeyHash(Key));
++(*this);
} }
FORCEINLINE const SetType* operator->() const /* // Milxnor: This is only on newer builds?
else
{ {
return &(*ElementIt).Value; NextIndex = INDEX_NONE;
} }
FORCEINLINE const int32 GetIndex() const */
{
return ElementIt.GetIndex();
} }
FORCEINLINE ElementType& GetSetElement()
/** Advances the iterator to the next element. */
FORCEINLINE TBaseKeyIterator& operator++()
{ {
return *ElementIt; Id = NextId;
while (Id.IsValidId())
{
NextId = Set.GetInternalElement(Id).HashNextId;
// checkSlow(Id != NextId);
if (KeyFuncs::Matches(KeyFuncs::GetSetKey(Set[Id]), Key))
{
break;
} }
FORCEINLINE const ElementType& GetSetElement() const
{ Id = NextId;
return *ElementIt;
} }
FORCEINLINE bool IsElementValid() const return *this;
}
/** conversion to "bool" returning true if the iterator is valid. */
FORCEINLINE explicit operator bool() const
{
return Id.IsValidId();
}
/** inverse of the "bool" operator */
FORCEINLINE bool operator !() const
{
return !(bool)*this;
}
// Accessors.
FORCEINLINE ItElementType* operator->() const
{
return &Set[Id];
}
FORCEINLINE ItElementType& operator*() const
{
return Set[Id];
}
protected:
SetType& Set;
typename TTypeTraits<typename KeyFuncs::KeyType>::ConstPointerType Key;
FSetElementId Id;
FSetElementId NextId;
};
FORCEINLINE const SetElementType& GetInternalElement(FSetElementId Id) const
{
return Elements[Id];
}
FORCEINLINE SetElementType& GetInternalElement(FSetElementId Id)
{
return Elements[Id];
}
public:
class TConstIterator : public TBaseIterator<true>
{
friend class TSet;
public:
FORCEINLINE TConstIterator(const TSet& InSet)
: TBaseIterator<true>(begin(InSet.Elements))
{ {
return ElementIt.IsElementValid();
} }
}; };
public: class TIterator : public TBaseIterator<false>
FORCEINLINE TSet<SetType>::FBaseIterator begin()
{ {
return TSet<SetType>::FBaseIterator(*this, Elements.begin()); friend class TSet;
}
FORCEINLINE const TSet<SetType>::FBaseIterator begin() const public:
FORCEINLINE TIterator(TSet& InSet)
: TBaseIterator<false>(begin(InSet.Elements))
, Set(InSet)
{ {
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) /** Removes the current element from the set. */
/* // T(R)
FORCEINLINE void RemoveCurrent()
{ {
return Elements[Index].ElementData.Value; Set.Remove(TBaseIterator<false>::GetId());
}
*/
private:
TSet& Set;
};
using TRangedForConstIterator = TBaseIterator<true, true>;
using TRangedForIterator = TBaseIterator<false, true>;
static FORCEINLINE FSetElementId IndexToId(int32 Index)
{
return FSetElementId(Index);
}
/** Creates an iterator for the contents of this set */
FORCEINLINE TIterator CreateIterator()
{
return TIterator(*this);
}
/** Creates a const iterator for the contents of this set */
FORCEINLINE TConstIterator CreateConstIterator() const
{
return TConstIterator(*this);
} }
FORCEINLINE int32 Num() const FORCEINLINE int32 Num() const
@@ -156,65 +482,39 @@ public:
{ {
return Elements; return Elements;
} }
FORCEINLINE const TBitArray& GetAllocationFlags() const
{
return Elements.GetAllocationFlags();
}
FORCEINLINE bool IsIndexValid(int32 IndexToCheck) const FORCEINLINE bool IsIndexValid(int32 IndexToCheck) const
{ {
return Elements.IsIndexValid(IndexToCheck); return Elements.IsIndexValid(IndexToCheck);
} }
FORCEINLINE const bool Contains(const SetType& ElementToLookFor) const FSetElementId FindId(KeyInitType Key) const
{ {
if (Num() <= 0) if (Elements.Num())
return false;
for (SetType Element : *this)
{ {
if (Element == ElementToLookFor) for (FSetElementId ElementId = GetTypedHash(KeyFuncs::GetKeyHash(Key));
return true; ElementId.IsValidId();
ElementId = Elements[ElementId].HashNextId)
{
if (KeyFuncs::Matches(KeyFuncs::GetSetKey(Elements[ElementId].Value), Key))
{
return ElementId;
} }
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 FSetElementId();
} }
return -1; FORCEINLINE bool Contains(KeyInitType Key) const
}
FORCEINLINE bool Remove(const SetType& ElementToRemove)
{ {
auto Idx = Find(ElementToRemove); return FindId(Key).IsValidId();
if (Idx == -1)
return false;
Elements.RemoveAt(Idx);
return true;
}
FORCEINLINE bool Remove(int Index)
{
Elements.RemoveAt(Index);
return true;
} }
private:
/**
* DO NOT USE DIRECTLY
* STL-like iterators to enable range-based for loop support.
*/
FORCEINLINE friend TRangedForIterator begin(TSet& Set) { return TRangedForIterator(begin(Set.Elements)); }
FORCEINLINE friend TRangedForConstIterator begin(const TSet& Set) { return TRangedForConstIterator(begin(Set.Elements)); }
FORCEINLINE friend TRangedForIterator end(TSet& Set) { return TRangedForIterator(end(Set.Elements)); }
FORCEINLINE friend TRangedForConstIterator end(const TSet& Set) { return TRangedForConstIterator(end(Set.Elements)); }
}; };
/* template<typename InElementType> //, typename KeyFuncs, typename Allocator>
class TSet
{
public:
typedef TSetElement<InElementType> ElementType;
typedef TSparseArrayElementOrListLink<ElementType> ArrayElementType;
TSparseArray<ElementType> Elements;
mutable TInlineAllocator<1>::ForElementType<int> Hash;
mutable int32 HashSize;
}; */

View File

@@ -2,259 +2,229 @@
#include "Array.h" #include "Array.h"
#include "BitArray.h" #include "BitArray.h"
#include "ChooseClass.h"
#include "log.h" #include "log.h"
#include "TypeCompatibleBytes.h"
#define INDEX_NONE -1 #define INDEX_NONE -1
template <typename ElementType> template<typename ElementType>
union TSparseArrayElementOrListLink union TSparseArrayElementOrFreeListLink
{ {
TSparseArrayElementOrListLink(ElementType& InElement)
: ElementData(InElement)
{
}
TSparseArrayElementOrListLink(ElementType&& InElement)
: ElementData(InElement)
{
}
TSparseArrayElementOrListLink(int32 InPrevFree, int32 InNextFree)
: PrevFreeIndex(InPrevFree)
, NextFreeIndex(InNextFree)
{
}
TSparseArrayElementOrListLink<ElementType> operator=(const TSparseArrayElementOrListLink<ElementType>& Other)
{
return TSparseArrayElementOrListLink(Other.NextFreeIndex, Other.PrevFreeIndex);
}
/** If the element is allocated, its value is stored here. */ /** If the element is allocated, its value is stored here. */
ElementType ElementData; ElementType ElementData;
struct struct
{ {
/** If the element isn't allocated, this is a link to the previous element in the array's free list. */ /** If the element isn't allocated, this is a link to the previous element in the array's free list. */
int PrevFreeIndex; int32 PrevFreeIndex;
/** If the element isn't allocated, this is a link to the next element in the array's free list. */ /** If the element isn't allocated, this is a link to the next element in the array's free list. */
int NextFreeIndex; int32 NextFreeIndex;
}; };
}; };
template <typename ArrayType> template<typename ElementType, typename Allocator = FDefaultSparseArrayAllocator >
class TSparseArray;
template<typename InElementType, typename Allocator>
class TSparseArray class TSparseArray
{ {
public: using ElementType = InElementType;
typedef TSparseArrayElementOrListLink<ArrayType> FSparseArrayElement;
TArray<FSparseArrayElement> Data; public:
TBitArray AllocationFlags; typedef TSparseArrayElementOrFreeListLink<
TAlignedBytes<sizeof(ElementType), alignof(ElementType)>
> FElementOrFreeListLink;
typedef TArray<FElementOrFreeListLink/*, typename Allocator::ElementAllocator*/> DataType;
DataType Data;
typedef TBitArray<typename Allocator::BitArrayAllocator> AllocationBitArrayType;
AllocationBitArrayType AllocationFlags;
/** The index of an unallocated element in the array that currently contains the head of the linked list of free elements. */
int32 FirstFreeIndex; int32 FirstFreeIndex;
/** The number of elements in the free list. */
int32 NumFreeIndices; int32 NumFreeIndices;
FORCEINLINE int32 Num() const FORCEINLINE int32 Num() const
{ {
return Data.Num() - NumFreeIndices; return Data.Num() - NumFreeIndices;
} }
template<bool bConst>
class FBaseIterator class TBaseIterator
{ {
public:
typedef TConstSetBitIterator<typename Allocator::BitArrayAllocator> BitArrayItType;
private: private:
TSparseArray<ArrayType>& IteratedArray; typedef typename TChooseClass<bConst, const TSparseArray, TSparseArray>::Result ArrayType;
TBitArray::FSetBitIterator BitArrayIt; typedef typename TChooseClass<bConst, const ElementType, ElementType>::Result ItElementType;
public: public:
FORCEINLINE FBaseIterator(const TSparseArray<ArrayType>& Array, const TBitArray::FSetBitIterator BitIterator) explicit TBaseIterator(ArrayType& InArray, const BitArrayItType& InBitArrayIt)
: IteratedArray(const_cast<TSparseArray<ArrayType>&>(Array)) : Array(InArray)
, BitArrayIt(const_cast<TBitArray::FSetBitIterator&>(BitIterator)) , BitArrayIt(InBitArrayIt)
{ {
} }
FORCEINLINE explicit operator bool() const FORCEINLINE TBaseIterator& operator++()
{
return (bool)BitArrayIt;
}
FORCEINLINE TSparseArray<ArrayType>::FBaseIterator& operator++()
{ {
// Iterate to the next set allocation flag.
++BitArrayIt; ++BitArrayIt;
return *this; return *this;
} }
FORCEINLINE ArrayType& operator*()
FORCEINLINE int32 GetIndex() const { return BitArrayIt.GetIndex(); }
FORCEINLINE friend bool operator==(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.BitArrayIt == Rhs.BitArrayIt && &Lhs.Array == &Rhs.Array; }
FORCEINLINE friend bool operator!=(const TBaseIterator& Lhs, const TBaseIterator& Rhs) { return Lhs.BitArrayIt != Rhs.BitArrayIt || &Lhs.Array != &Rhs.Array; }
/** conversion to "bool" returning true if the iterator is valid. */
FORCEINLINE explicit operator bool() const
{ {
return IteratedArray[BitArrayIt.GetIndex()].ElementData; return !!BitArrayIt;
}
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 /** inverse of the "bool" operator */
FORCEINLINE bool operator !() const
{ {
return BitArrayIt.GetIndex(); return !(bool)*this;
}
FORCEINLINE bool IsElementValid() const
{
return *BitArrayIt;
} }
FORCEINLINE ItElementType& operator*() const { return Array[GetIndex()]; }
FORCEINLINE ItElementType* operator->() const { return &Array[GetIndex()]; }
FORCEINLINE const FRelativeBitReference& GetRelativeBitReference() const { return BitArrayIt; }
protected:
ArrayType& Array;
BitArrayItType BitArrayIt;
}; };
public: public:
FORCEINLINE TSparseArray<ArrayType>::FBaseIterator begin()
/** Iterates over all allocated elements in a sparse array. */
class TIterator : public TBaseIterator<false>
{ {
return TSparseArray<ArrayType>::FBaseIterator(*this, TBitArray::FSetBitIterator(AllocationFlags, 0)); public:
} TIterator(TSparseArray& InArray)
FORCEINLINE const TSparseArray<ArrayType>::FBaseIterator begin() const : TBaseIterator<false>(InArray, TConstSetBitIterator<typename Allocator::BitArrayAllocator>(InArray.AllocationFlags))
{ {
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) TIterator(TSparseArray& InArray, const typename TBaseIterator<false>::BitArrayItType& InBitArrayIt)
: TBaseIterator<false>(InArray, InBitArrayIt)
{ {
return *(FSparseArrayElement*)&Data.at(Index).ElementData;
} }
FORCEINLINE const FSparseArrayElement& operator[](uint32 Index) const
/** Safely removes the current element from the array. */
/*
void RemoveCurrent()
{ {
return *(const FSparseArrayElement*)&Data.at(Index).ElementData; this->Array.RemoveAt(this->GetIndex());
} }
FORCEINLINE int32 GetNumFreeIndices() const */
};
/** Iterates over all allocated elements in a const sparse array. */
class TConstIterator : public TBaseIterator<true>
{
public:
TConstIterator(const TSparseArray& InArray)
: TBaseIterator<true>(InArray, TConstSetBitIterator<typename Allocator::BitArrayAllocator>(InArray.AllocationFlags))
{ {
return NumFreeIndices;
} }
FORCEINLINE int32 GetFirstFreeIndex() const
TConstIterator(const TSparseArray& InArray, const typename TBaseIterator<true>::BitArrayItType& InBitArrayIt)
: TBaseIterator<true>(InArray, InBitArrayIt)
{ {
return FirstFreeIndex;
} }
FORCEINLINE const TArray<FSparseArrayElement>& GetData() const };
#if TSPARSEARRAY_RANGED_FOR_CHECKS // T(R) Milxnor: Check this
class TRangedForIterator : public TIterator
{
public:
TRangedForIterator(TSparseArray& InArray, const typename TBaseIterator<false>::BitArrayItType& InBitArrayIt)
: TIterator(InArray, InBitArrayIt)
, InitialNum(InArray.Num())
{ {
return Data;
} }
FSparseArrayElement& GetData(int32 Index)
private:
int32 InitialNum;
friend FORCEINLINE bool operator!=(const TRangedForIterator& Lhs, const TRangedForIterator& Rhs)
{ {
return *(FSparseArrayElement*)&Data.at(Index).ElementData; // We only need to do the check in this operator, because no other operator will be
// return ((FSparseArrayElement*)Data.Data)[Index]; // called until after this one returns.
//
// Also, we should only need to check one side of this comparison - if the other iterator isn't
// even from the same array then the compiler has generated bad code.
ensureMsgf(Lhs.Array.Num() == Lhs.InitialNum, TEXT("Container has changed during ranged-for iteration!"));
return *(TIterator*)&Lhs != *(TIterator*)&Rhs;
}
};
class TRangedForConstIterator : public TConstIterator
{
public:
TRangedForConstIterator(const TSparseArray& InArray, const typename TBaseIterator<true>::BitArrayItType& InBitArrayIt)
: TConstIterator(InArray, InBitArrayIt)
, InitialNum(InArray.Num())
{
}
private:
int32 InitialNum;
friend FORCEINLINE bool operator!=(const TRangedForConstIterator& Lhs, const TRangedForConstIterator& Rhs)
{
// We only need to do the check in this operator, because no other operator will be
// called until after this one returns.
//
// Also, we should only need to check one side of this comparison - if the other iterator isn't
// even from the same array then the compiler has generated bad code.
ensureMsgf(Lhs.Array.Num() == Lhs.InitialNum, TEXT("Container has changed during ranged-for iteration!"));
return *(TIterator*)&Lhs != *(TIterator*)&Rhs;
}
};
#else
using TRangedForIterator = TIterator;
using TRangedForConstIterator = TConstIterator;
#endif
public:
ElementType& operator[](int32 Index)
{
// checkSlow(Index >= 0 && Index < Data.Num() && Index < AllocationFlags.Num());
//checkSlow(AllocationFlags[Index]); // Disabled to improve loading times -BZ
return *(ElementType*)&GetData(Index).ElementData;
}
const ElementType& operator[](int32 Index) const
{
// checkSlow(Index >= 0 && Index < Data.Num() && Index < AllocationFlags.Num());
//checkSlow(AllocationFlags[Index]); // Disabled to improve loading times -BZ
return *(ElementType*)&GetData(Index).ElementData;
}
FElementOrFreeListLink& GetData(int32 Index)
{
return ((FElementOrFreeListLink*)Data.GetData())[Index];
} }
/** Accessor for the element or free list data. */ /** Accessor for the element or free list data. */
const FSparseArrayElement& GetData(int32 Index) const const FElementOrFreeListLink& GetData(int32 Index) const
{ {
return *(const FSparseArrayElement*)&Data.at(Index).ElementData; return ((FElementOrFreeListLink*)Data.GetData())[Index];
// return ((FSparseArrayElement*)Data.Data)[Index];
}
FORCEINLINE const TBitArray& GetAllocationFlags() const
{
return AllocationFlags;
}
FORCEINLINE bool IsIndexValid(int32 IndexToCheck) const
{
return AllocationFlags.IsSet(IndexToCheck);
} }
void RemoveAt(int32 Index, int32 Count = 1) FORCEINLINE friend TRangedForIterator begin(TSparseArray& Array) { return TRangedForIterator(Array, TConstSetBitIterator<typename Allocator::BitArrayAllocator>(Array.AllocationFlags)); }
{ FORCEINLINE friend TRangedForConstIterator begin(const TSparseArray& Array) { return TRangedForConstIterator(Array, TConstSetBitIterator<typename Allocator::BitArrayAllocator>(Array.AllocationFlags)); }
/* if (!TIsTriviallyDestructible<ElementType>::Value) FORCEINLINE friend TRangedForIterator end(TSparseArray& Array) { return TRangedForIterator(Array, TConstSetBitIterator<typename Allocator::BitArrayAllocator>(Array.AllocationFlags, Array.AllocationFlags.Num())); }
{ FORCEINLINE friend TRangedForConstIterator end(const TSparseArray& Array) { return TRangedForConstIterator(Array, TConstSetBitIterator<typename Allocator::BitArrayAllocator>(Array.AllocationFlags, Array.AllocationFlags.Num())); }
for (int32 It = Index, ItCount = Count; ItCount; ++It, --ItCount)
{
((ElementType&)GetData(It).ElementData).~ElementType();
}
} */
RemoveAtUninitialized(Index, Count);
}
/** Removes Count elements from the array, starting from Index, without destructing them. */
void RemoveAtUninitialized(int32 Index, int32 Count = 1)
{
for (; Count; --Count)
{
// check(AllocationFlags[Index]);
// Mark the element as free and add it to the free element list.
if (NumFreeIndices)
{
GetData(FirstFreeIndex).PrevFreeIndex = Index;
}
auto& IndexData = GetData(Index);
IndexData.PrevFreeIndex = -1;
IndexData.NextFreeIndex = NumFreeIndices > 0 ? FirstFreeIndex : INDEX_NONE;
FirstFreeIndex = Index;
++NumFreeIndices;
AllocationFlags.Set(Index, false);
// AllocationFlags[Index] = false;
++Index;
}
}
/*
FORCEINLINE bool RemoveAt(const int32 IndexToRemove)
{
LOG_INFO(LogDev, "IndexToRemove: {}", IndexToRemove);
LOG_INFO(LogDev, "AllocationFlags.IsSet(IndexToRemove): {}", AllocationFlags.IsSet(IndexToRemove));
LOG_INFO(LogDev, "Data.Num(): {}", Data.Num());
if (IndexToRemove >= 0 && IndexToRemove < Data.Num() && AllocationFlags.IsSet(IndexToRemove))
{
int32 PreviousFreeIndex = -1;
int32 NextFreeIndex = -1;
LOG_INFO(LogDev, "NumFreeIndices: {}", NumFreeIndices);
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

@@ -16,7 +16,7 @@ struct FTimerUnifiedDelegate
TFunction<void(void)> FuncCallback; TFunction<void(void)> FuncCallback;
FTimerUnifiedDelegate() {}; FTimerUnifiedDelegate() {};
FTimerUnifiedDelegate(FTimerDelegate const& D) : FuncDelegate(D) {}; // FTimerUnifiedDelegate(FTimerDelegate const& D) : FuncDelegate(D) {}; // T(R)
}; };
class FTimerManager // : public FNoncopyable class FTimerManager // : public FNoncopyable
@@ -27,6 +27,6 @@ public:
static void (*InternalSetTimerOriginal)(__int64 TimerManager, FTimerHandle& InOutHandle, FTimerUnifiedDelegate&& InDelegate, float InRate, bool InbLoop, float InFirstDelay) = static void (*InternalSetTimerOriginal)(__int64 TimerManager, FTimerHandle& InOutHandle, FTimerUnifiedDelegate&& InDelegate, float InRate, bool InbLoop, float InFirstDelay) =
decltype(InternalSetTimerOriginal)(Addresses::SetTimer); decltype(InternalSetTimerOriginal)(Addresses::SetTimer);
InternalSetTimerOriginal(__int64(this), InOutHandle, FTimerUnifiedDelegate(InDelegate), InRate, InbLoop, InFirstDelay); // InternalSetTimerOriginal(__int64(this), InOutHandle, FTimerUnifiedDelegate(InDelegate), InRate, InbLoop, InFirstDelay); // T(R)
} }
}; };

View File

@@ -16,6 +16,93 @@ struct FMath : public FGenericPlatformMath
return A * A; return A * A;
} }
static float SRand() // T(REP)
{
return rand();
}
static FORCEINLINE uint32 FloorLog2(uint32 Value)
{
/* // reference implementation
// 1500ms on test data
uint32 Bit = 32;
for (; Bit > 0;)
{
Bit--;
if (Value & (1<<Bit))
{
break;
}
}
return Bit;
*/
// same output as reference
// see http://codinggorilla.domemtech.com/?p=81 or http://en.wikipedia.org/wiki/Binary_logarithm but modified to return 0 for a input value of 0
// 686ms on test data
uint32 pos = 0;
if (Value >= 1 << 16) { Value >>= 16; pos += 16; }
if (Value >= 1 << 8) { Value >>= 8; pos += 8; }
if (Value >= 1 << 4) { Value >>= 4; pos += 4; }
if (Value >= 1 << 2) { Value >>= 2; pos += 2; }
if (Value >= 1 << 1) { pos += 1; }
return (Value == 0) ? 0 : pos;
// even faster would be method3 but it can introduce more cache misses and it would need to store the table somewhere
// 304ms in test data
/*int LogTable256[256];
void prep()
{
LogTable256[0] = LogTable256[1] = 0;
for (int i = 2; i < 256; i++)
{
LogTable256[i] = 1 + LogTable256[i / 2];
}
LogTable256[0] = -1; // if you want log(0) to return -1
}
int _forceinline method3(uint32 v)
{
int r; // r will be lg(v)
uint32 tt; // temporaries
if ((tt = v >> 24) != 0)
{
r = (24 + LogTable256[tt]);
}
else if ((tt = v >> 16) != 0)
{
r = (16 + LogTable256[tt]);
}
else if ((tt = v >> 8 ) != 0)
{
r = (8 + LogTable256[tt]);
}
else
{
r = LogTable256[v];
}
return r;
}*/
}
static FORCEINLINE uint32 CountLeadingZeros(uint32 Value)
{
if (Value == 0) return 32;
return 31 - FloorLog2(Value);
}
template <class T>
static constexpr FORCEINLINE T DivideAndRoundUp(T Dividend, T Divisor)
{
return (Dividend + Divisor - 1) / Divisor;
}
static FORCEINLINE int32 Rand() { return rand(); }
static FORCEINLINE float FRand() { return Rand() / (float)RAND_MAX; }
#define FASTASIN_HALF_PI (1.5707963050f) #define FASTASIN_HALF_PI (1.5707963050f)
/** /**
* Computes the ASin of a scalar value. * Computes the ASin of a scalar value.

View File

@@ -26,6 +26,14 @@ struct TCallTraitsParamTypeHelper<T*, true>
typedef const T* ConstParamType; typedef const T* ConstParamType;
}; };
template<typename T> struct TContainerTraitsBase
{
// This should be overridden by every container that supports emptying its contents via a move operation.
enum { MoveWillEmptyContainer = false };
};
template<typename T> struct TContainerTraits : public TContainerTraitsBase<T> {};
template <typename T> template <typename T>
struct TCallTraitsBase struct TCallTraitsBase
{ {

View File

@@ -2,6 +2,12 @@
#include "inc.h" #include "inc.h"
enum EForceInit
{
ForceInit,
ForceInitToZero
};
struct FVector struct FVector
{ {
public: public:
@@ -62,4 +68,10 @@ public:
{ {
*this = *this - A; *this = *this - A;
} }
explicit FORCEINLINE FVector(EForceInit)
: X(0.0f), Y(0.0f), Z(0.0f)
{
// DiagnosticCheckNaN();
}
}; };

View File

@@ -13,6 +13,19 @@ public:
return ChunkedObjects ? ChunkedObjects->GetObjectByIndex(ObjectIndex) : UnchunkedObjects ? UnchunkedObjects->GetObjectByIndex(ObjectIndex) : nullptr; return ChunkedObjects ? ChunkedObjects->GetObjectByIndex(ObjectIndex) : UnchunkedObjects ? UnchunkedObjects->GetObjectByIndex(ObjectIndex) : nullptr;
} }
FORCEINLINE bool operator==(const FWeakObjectPtr& Other) const
{
return
(ObjectIndex == Other.ObjectIndex && ObjectSerialNumber == Other.ObjectSerialNumber)
// || (!IsValid() && !Other.IsValid())
;
}
friend uint32 GetTypeHash(const FWeakObjectPtr& WeakObjectPtr)
{
return uint32(WeakObjectPtr.ObjectIndex ^ WeakObjectPtr.ObjectSerialNumber);
}
bool operator==(const FWeakObjectPtr& other) bool operator==(const FWeakObjectPtr& other)
{ {
return ObjectIndex == other.ObjectIndex && ObjectSerialNumber == other.ObjectSerialNumber; return ObjectIndex == other.ObjectIndex && ObjectSerialNumber == other.ObjectSerialNumber;

View File

@@ -2,6 +2,7 @@
#include "WeakObjectPtr.h" #include "WeakObjectPtr.h"
#include "Object.h" #include "Object.h"
#include "PointerIsConvertibleFromTo.h"
template<class T = UObject, class TWeakObjectPtrBase = FWeakObjectPtr> template<class T = UObject, class TWeakObjectPtrBase = FWeakObjectPtr>
struct TWeakObjectPtr; struct TWeakObjectPtr;
@@ -14,8 +15,48 @@ struct TWeakObjectPtr : public TWeakObjectPtrBase
return (T*)TWeakObjectPtrBase::Get(); return (T*)TWeakObjectPtrBase::Get();
} }
/*
bool operator==(const TWeakObjectPtr& other) bool operator==(const TWeakObjectPtr& other)
{ {
return TWeakObjectPtrBase::operator==(other); return TWeakObjectPtrBase::operator==(other);
} }
*/
TWeakObjectPtr() {}
}; };
template <typename LhsT, typename RhsT, typename OtherTWeakObjectPtrBase>
FORCENOINLINE bool operator==(const TWeakObjectPtr<LhsT, OtherTWeakObjectPtrBase>& Lhs, const RhsT* Rhs)
{
// It's also possible that these static_asserts may fail for valid conversions because
// one or both of the types have only been forward-declared.
static_assert(TPointerIsConvertibleFromTo<RhsT, UObject>::Value, "TWeakObjectPtr can only be compared with UObject types");
static_assert(TPointerIsConvertibleFromTo<LhsT, RhsT>::Value || TPointerIsConvertibleFromTo<RhsT, LhsT>::Value, "Unable to compare TWeakObjectPtr with raw pointer - types are incompatible");
// NOTE: this constructs a TWeakObjectPtrBase, which has some amount of overhead, so this may not be an efficient operation
return (const OtherTWeakObjectPtrBase&)Lhs == OtherTWeakObjectPtrBase(Rhs);
}
template <typename LhsT, typename RhsT, typename OtherTWeakObjectPtrBase>
FORCENOINLINE bool operator==(const LhsT* Lhs, const TWeakObjectPtr<RhsT, OtherTWeakObjectPtrBase>& Rhs)
{
// It's also possible that these static_asserts may fail for valid conversions because
// one or both of the types have only been forward-declared.
static_assert(TPointerIsConvertibleFromTo<LhsT, UObject>::Value, "TWeakObjectPtr can only be compared with UObject types");
static_assert(TPointerIsConvertibleFromTo<LhsT, RhsT>::Value || TPointerIsConvertibleFromTo<RhsT, LhsT>::Value, "Unable to compare TWeakObjectPtr with raw pointer - types are incompatible");
// NOTE: this constructs a TWeakObjectPtrBase, which has some amount of overhead, so this may not be an efficient operation
return OtherTWeakObjectPtrBase(Lhs) == (const OtherTWeakObjectPtrBase&)Rhs;
}
template <typename LhsT, typename OtherTWeakObjectPtrBase>
FORCENOINLINE bool operator==(const TWeakObjectPtr<LhsT, OtherTWeakObjectPtrBase>& Lhs, TYPE_OF_NULLPTR)
{
return !Lhs.IsValid();
}
template <typename RhsT, typename OtherTWeakObjectPtrBase>
FORCENOINLINE bool operator==(TYPE_OF_NULLPTR, const TWeakObjectPtr<RhsT, OtherTWeakObjectPtrBase>& Rhs)
{
return !Rhs.IsValid();
}

View File

@@ -6,17 +6,14 @@
#include "Rotator.h" #include "Rotator.h"
#include "Actor.h" #include "Actor.h"
#include "GameInstance.h" #include "GameInstance.h"
#include "WorldSettings.h"
#include "GameplayStatics.h"
struct FNetworkNotify struct FNetworkNotify
{ {
}; };
class AWorldSettings : public AActor
{
public:
};
struct FActorSpawnParameters struct FActorSpawnParameters
{ {
FName Name = FName(0); FName Name = FName(0);
@@ -228,6 +225,11 @@ public:
return this->Get<class UNetDriver*>(NetDriverOffset); return this->Get<class UNetDriver*>(NetDriverOffset);
} }
float GetTimeSeconds() // T(REP)
{
return UGameplayStatics::GetTimeSeconds(this);
}
UGameInstance* GetOwningGameInstance() UGameInstance* GetOwningGameInstance()
{ {
static auto OwningGameInstanceOffset = GetOffset("OwningGameInstance"); static auto OwningGameInstanceOffset = GetOffset("OwningGameInstance");

View File

@@ -0,0 +1,35 @@
#pragma once
#include "Actor.h"
#include "NetConnection.h"
#include "Array.h"
struct FNetViewer
{
UNetConnection* Connection;
AActor* InViewer;
AActor* ViewTarget;
FVector ViewLocation;
FVector ViewDir;
FNetViewer()
: Connection(NULL)
, InViewer(NULL)
, ViewTarget(NULL)
, ViewLocation(ForceInit)
, ViewDir(ForceInit)
{
}
FNetViewer(UNetConnection* InConnection, float DeltaSeconds);
};
class AWorldSettings : public AActor
{
public:
TArray<struct FNetViewer>& GetReplicationViewers()
{
static auto ReplicationViewersOffset = GetOffset("ReplicationViewers");
return Get<TArray<struct FNetViewer>>(ReplicationViewersOffset);
}
};

View File

@@ -553,6 +553,12 @@ void Addresses::Init()
NavSystemCleanUpOriginal = decltype(NavSystemCleanUpOriginal)(Addresses::NavSystemCleanUp); NavSystemCleanUpOriginal = decltype(NavSystemCleanUpOriginal)(Addresses::NavSystemCleanUp);
LoadPlaysetOriginal = decltype(LoadPlaysetOriginal)(Addresses::LoadPlayset); LoadPlaysetOriginal = decltype(LoadPlaysetOriginal)(Addresses::LoadPlayset);
AFortGameModeAthena::SetZoneToIndexOriginal = decltype(AFortGameModeAthena::SetZoneToIndexOriginal)(Addresses::SetZoneToIndex); AFortGameModeAthena::SetZoneToIndexOriginal = decltype(AFortGameModeAthena::SetZoneToIndexOriginal)(Addresses::SetZoneToIndex);
AActor::originalCallPreReplication = decltype(AActor::originalCallPreReplication)(Addresses::CallPreReplication);
APlayerController::originalSendClientAdjustment = decltype(APlayerController::originalSendClientAdjustment)(Addresses::SendClientAdjustment);
UActorChannel::originalReplicateActor = decltype(UActorChannel::originalReplicateActor)(Addresses::ReplicateActor);
UActorChannel::originalSetChannelActor = decltype(UActorChannel::originalSetChannelActor)(Addresses::SetChannelActor);
UNetConnection::originalCreateChannel = decltype(UNetConnection::originalCreateChannel)(Addresses::CreateChannel);
UNetConnection::originalCreateChannelByName = decltype(UNetConnection::originalCreateChannelByName)(Addresses::CreateChannel);
if (Engine_Version >= 421) ChunkedObjects = decltype(ChunkedObjects)(ObjectArray); if (Engine_Version >= 421) ChunkedObjects = decltype(ChunkedObjects)(ObjectArray);
else UnchunkedObjects = decltype(UnchunkedObjects)(ObjectArray); else UnchunkedObjects = decltype(UnchunkedObjects)(ObjectArray);

View File

@@ -110,11 +110,29 @@ static inline AFortAthenaMutator_Bots* SpawnBotMutator() //sets up all the class
auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState()); auto GameState = Cast<AFortGameStateAthena>(GetWorld()->GetGameState());
auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode()); auto GameMode = Cast<AFortGameModeAthena>(GetWorld()->GetGameMode());
auto MutatorBotsClass = FindObject<UClass>("/Script/FortniteGame.FortAthenaMutator_Bots");
if (!MutatorBotsClass)
{
return nullptr;
}
static auto BGAClass = FindObject<UClass>(L"/Script/Engine.BlueprintGeneratedClass"); static auto BGAClass = FindObject<UClass>(L"/Script/Engine.BlueprintGeneratedClass");
static auto PhoebeMutatorClass = LoadObject<UClass>(L"/Game/Athena/AI/Phoebe/BP_Phoebe_Mutator.BP_Phoebe_Mutator_C", BGAClass); static auto PhoebeMutatorClass = LoadObject<UClass>(L"/Game/Athena/AI/Phoebe/BP_Phoebe_Mutator.BP_Phoebe_Mutator_C", BGAClass);
if (!PhoebeMutatorClass)
{
return nullptr;
}
auto BotMutator = GetWorld()->SpawnActor<AFortAthenaMutator_Bots>(PhoebeMutatorClass); auto BotMutator = GetWorld()->SpawnActor<AFortAthenaMutator_Bots>(PhoebeMutatorClass);
if (!BotMutator)
{
LOG_WARN(LogAI, "Failed to spawn Bot Mutator!");
return nullptr;
}
static auto CachedGameModeOffset = BotMutator->GetOffset("CachedGameMode"); static auto CachedGameModeOffset = BotMutator->GetOffset("CachedGameMode");
BotMutator->Get(CachedGameModeOffset) = GameMode; BotMutator->Get(CachedGameModeOffset) = GameMode;

View File

@@ -5,6 +5,16 @@
#include <format> #include <format>
#include <string> #include <string>
/*
T(REP): Todo replication
T(R): Todo random (every commented check, checkslow is automatically this)
T(1-5): 1, being most important, 5 being least important to fix.
*/
decltype(nullptr) typedef TYPE_OF_NULLPTR;
typedef unsigned short uint16; typedef unsigned short uint16;
typedef unsigned char uint8; typedef unsigned char uint8;
typedef char int8; typedef char int8;
@@ -25,6 +35,8 @@ extern inline int Fortnite_CL = 0;
// #define ABOVE_S20 // #define ABOVE_S20
#define INDEX_NONE -1
struct PlaceholderBitfield struct PlaceholderBitfield
{ {
uint8_t First : 1; uint8_t First : 1;
@@ -62,6 +74,15 @@ inline bool IsRestartingSupported()
return Engine_Version >= 419 && Engine_Version < 424; return Engine_Version >= 419 && Engine_Version < 424;
} }
enum ENetRole
{
ROLE_None,
ROLE_SimulatedProxy,
ROLE_AutonomousProxy,
ROLE_Authority,
ROLE_MAX,
};
/* /*
enum class AllocatorType enum class AllocatorType

View File

@@ -80,8 +80,9 @@ static inline UEngine* GetEngine()
return Engine; return Engine;
} }
static inline class UWorld* GetWorld() namespace {
{ static inline class UWorld* GetWorld()
{
static UObject* Engine = GetEngine(); static UObject* Engine = GetEngine();
static auto GameViewportOffset = Engine->GetOffset("GameViewport"); static auto GameViewportOffset = Engine->GetOffset("GameViewport");
auto GameViewport = Engine->Get<UObject*>(GameViewportOffset); auto GameViewport = Engine->Get<UObject*>(GameViewportOffset);
@@ -89,6 +90,7 @@ static inline class UWorld* GetWorld()
static auto WorldOffset = GameViewport->GetOffset("World"); static auto WorldOffset = GameViewport->GetOffset("World");
return GameViewport->Get<class UWorld*>(WorldOffset); return GameViewport->Get<class UWorld*>(WorldOffset);
}
} }
static TArray<UObject*>& GetLocalPlayers() static TArray<UObject*>& GetLocalPlayers()
@@ -406,7 +408,8 @@ namespace MemberOffsets
} }
} }
static inline float GetMaxTickRateHook() { return 30.f; } inline float ServerTickRate = 30.f;
static inline float GetMaxTickRateHook() { return ServerTickRate; }
#define VALIDATEOFFSET(offset) if (!offset) LOG_WARN(LogDev, "[{}] Invalid offset", __FUNCTIONNAME__); #define VALIDATEOFFSET(offset) if (!offset) LOG_WARN(LogDev, "[{}] Invalid offset", __FUNCTIONNAME__);