mirror of
https://github.com/Milxnor/Project-Reboot-3.0.git
synced 2026-01-13 02:42:22 +01:00
it kinda work
This commit is contained in:
@@ -4,6 +4,25 @@
|
|||||||
|
|
||||||
#include "reboot.h"
|
#include "reboot.h"
|
||||||
|
|
||||||
|
bool AActor::IsTearOff()
|
||||||
|
{
|
||||||
|
static auto bTearOffOffset = GetOffset("bTearOff");
|
||||||
|
static auto bTearOffFieldMask = GetFieldMask(GetProperty("bTearOff"));
|
||||||
|
return ReadBitfieldValue(bTearOffOffset, bTearOffFieldMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FORCEINLINE */ ENetDormancy& AActor::GetNetDormancy()
|
||||||
|
{
|
||||||
|
static auto NetDormancyOffset = GetOffset("NetDormancy");
|
||||||
|
return Get<ENetDormancy>(NetDormancyOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32& AActor::GetNetTag()
|
||||||
|
{
|
||||||
|
static auto NetTagOffset = GetOffset("NetTag");
|
||||||
|
return Get<int32>(NetTagOffset);
|
||||||
|
}
|
||||||
|
|
||||||
FTransform AActor::GetTransform()
|
FTransform AActor::GetTransform()
|
||||||
{
|
{
|
||||||
FTransform Ret;
|
FTransform Ret;
|
||||||
@@ -148,6 +167,13 @@ float& AActor::GetMinNetUpdateFrequency()
|
|||||||
return Get<float>(MinNetUpdateFrequencyOffset);
|
return Get<float>(MinNetUpdateFrequencyOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AActor* AActor::GetNetOwner() const
|
||||||
|
{
|
||||||
|
static int GetNetOwnerOffset = 0x448; // 1.11
|
||||||
|
const AActor* (*GetNetOwnerOriginal)(const AActor*) = decltype(GetNetOwnerOriginal)(this->VFTable[GetNetOwnerOffset / 8]);
|
||||||
|
return GetNetOwnerOriginal(this);
|
||||||
|
}
|
||||||
|
|
||||||
bool AActor::IsAlwaysRelevant()
|
bool AActor::IsAlwaysRelevant()
|
||||||
{
|
{
|
||||||
static auto bAlwaysRelevantOffset = GetOffset("bAlwaysRelevant");
|
static auto bAlwaysRelevantOffset = GetOffset("bAlwaysRelevant");
|
||||||
|
|||||||
@@ -2,11 +2,25 @@
|
|||||||
|
|
||||||
#include "Object.h"
|
#include "Object.h"
|
||||||
|
|
||||||
|
enum class ENetDormancy : uint8_t
|
||||||
|
{
|
||||||
|
DORM_Never = 0,
|
||||||
|
DORM_Awake = 1,
|
||||||
|
DORM_DormantAll = 2,
|
||||||
|
DORM_DormantPartial = 3,
|
||||||
|
DORM_Initial = 4,
|
||||||
|
DORN_MAX = 5,
|
||||||
|
ENetDormancy_MAX = 6
|
||||||
|
};
|
||||||
|
|
||||||
class AActor : public UObject
|
class AActor : public UObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct FTransform GetTransform();
|
struct FTransform GetTransform();
|
||||||
|
|
||||||
|
bool IsTearOff();
|
||||||
|
/* FORCEINLINE */ ENetDormancy& GetNetDormancy();
|
||||||
|
int32& GetNetTag();
|
||||||
AActor* GetOwner();
|
AActor* GetOwner();
|
||||||
struct FVector GetActorLocation();
|
struct FVector GetActorLocation();
|
||||||
struct FVector GetActorRightVector();
|
struct FVector GetActorRightVector();
|
||||||
@@ -29,6 +43,13 @@ public:
|
|||||||
bool IsPendingKillPending();
|
bool IsPendingKillPending();
|
||||||
float& GetNetUpdateFrequency();
|
float& GetNetUpdateFrequency();
|
||||||
float& GetMinNetUpdateFrequency();
|
float& GetMinNetUpdateFrequency();
|
||||||
|
const AActor* GetNetOwner() const;
|
||||||
|
|
||||||
|
bool IsRelevancyOwnerFor(const AActor* ReplicatedActor, const AActor* ActorOwner, const AActor* ConnectionActor) const
|
||||||
|
{
|
||||||
|
// we should call virtual function but eh
|
||||||
|
return (ActorOwner == this);
|
||||||
|
}
|
||||||
|
|
||||||
static class UClass* StaticClass();
|
static class UClass* StaticClass();
|
||||||
};
|
};
|
||||||
32
Project Reboot 3.0/ActorChannel.h
Normal file
32
Project Reboot 3.0/ActorChannel.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Channel.h"
|
||||||
|
#include "NetworkGuid.h"
|
||||||
|
|
||||||
|
class UActorChannel : public UChannel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
double& GetLastUpdateTime()
|
||||||
|
{
|
||||||
|
static auto LastUpdateTimeOffset = GetOffset("Actor") + 8 + 4 + 4 + 8; // checked on 4.19
|
||||||
|
return Get<double>(LastUpdateTimeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
double& GetRelevantTime()
|
||||||
|
{
|
||||||
|
static auto RelevantTimeOffset = GetOffset("Actor") + 8 + 4 + 4; // checked on 4.19
|
||||||
|
return Get<double>(RelevantTimeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
AActor*& GetActor()
|
||||||
|
{
|
||||||
|
static auto ActorOffset = GetOffset("Actor");
|
||||||
|
return Get<AActor*>(ActorOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close()
|
||||||
|
{
|
||||||
|
static void (*ActorChannelClose)(UActorChannel*) = decltype(ActorChannelClose)(Addresses::ActorChannelClose);
|
||||||
|
ActorChannelClose(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
25
Project Reboot 3.0/Channel.h
Normal file
25
Project Reboot 3.0/Channel.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Object.h"
|
||||||
|
|
||||||
|
class UChannel : public UObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void StartBecomingDormant()
|
||||||
|
{
|
||||||
|
void (*StartBecomingDormantOriginal)(UChannel* Channel) = decltype(StartBecomingDormantOriginal)(this->VFTable[0x298 / 8]);
|
||||||
|
StartBecomingDormantOriginal(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsPendingDormancy()
|
||||||
|
{
|
||||||
|
static auto BitfieldOffset = GetOffset("Connection") + 8;
|
||||||
|
return ((PlaceholderBitfield*)(__int64(this) + BitfieldOffset))->Seventh;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsDormant()
|
||||||
|
{
|
||||||
|
static auto BitfieldOffset = GetOffset("Connection") + 8;
|
||||||
|
return ((PlaceholderBitfield*)(__int64(this) + BitfieldOffset))->Third;
|
||||||
|
}
|
||||||
|
};
|
||||||
64
Project Reboot 3.0/GenericPlatformMath.h
Normal file
64
Project Reboot 3.0/GenericPlatformMath.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
class FPlatformMath
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr FORCEINLINE int32 TruncToInt(float F)
|
||||||
|
{
|
||||||
|
return (int32)F;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr FORCEINLINE float TruncToFloat(float F)
|
||||||
|
{
|
||||||
|
return (float)TruncToInt(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE int32 FloorToInt(float F)
|
||||||
|
{
|
||||||
|
return TruncToInt(floorf(F));
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T, class U >
|
||||||
|
static FORCEINLINE T Lerp(const T& A, const T& B, const U& Alpha)
|
||||||
|
{
|
||||||
|
return (T)(A + Alpha * (B - A));
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
static constexpr FORCEINLINE T Max(const T A, const T B)
|
||||||
|
{
|
||||||
|
return (A >= B) ? A : B;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE float FloorToFloat(float F)
|
||||||
|
{
|
||||||
|
return floorf(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE double FloorToDouble(double F)
|
||||||
|
{
|
||||||
|
return floor(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE int32 RoundToInt(float F)
|
||||||
|
{
|
||||||
|
return FloorToInt(F + 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE float Fractional(float Value)
|
||||||
|
{
|
||||||
|
return Value - TruncToFloat(Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE double TruncToDouble(double F)
|
||||||
|
{
|
||||||
|
return trunc(F);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE double Fractional(double Value)
|
||||||
|
{
|
||||||
|
return Value - TruncToDouble(Value);
|
||||||
|
}
|
||||||
|
};
|
||||||
25
Project Reboot 3.0/GenericPlatformTime.h
Normal file
25
Project Reboot 3.0/GenericPlatformTime.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
struct FGenericPlatformTime
|
||||||
|
{
|
||||||
|
static FORCEINLINE uint32 Cycles()
|
||||||
|
{
|
||||||
|
struct timeval tv{};
|
||||||
|
FILETIME ft;
|
||||||
|
ULARGE_INTEGER uli{};
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime(&ft); // Get current time
|
||||||
|
uli.LowPart = ft.dwLowDateTime;
|
||||||
|
uli.HighPart = ft.dwHighDateTime;
|
||||||
|
|
||||||
|
// Convert to microseconds
|
||||||
|
uli.QuadPart /= 10;
|
||||||
|
uli.QuadPart -= 11644473600000000ULL;
|
||||||
|
|
||||||
|
tv.tv_sec = (long)(uli.QuadPart / 1000000);
|
||||||
|
tv.tv_usec = (long)(uli.QuadPart % 1000000);
|
||||||
|
return (uint32)((((uint64)tv.tv_sec) * 1000000ULL) + (((uint64)tv.tv_usec)));
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -30,35 +30,122 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename KeyType, typename ValueType> //, typename SetAllocator, typename KeyFuncs>
|
template <typename KeyType, typename ValueType>
|
||||||
class TMapBase
|
class TMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef TPair<KeyType, ValueType> ElementType;
|
typedef TPair<KeyType, ValueType> ElementType;
|
||||||
|
|
||||||
typedef TSet<ElementType/*, KeyFuncs, SetAllocator */> ElementSetType;
|
public:
|
||||||
|
TSet<ElementType> Pairs;
|
||||||
|
|
||||||
ElementSetType Pairs;
|
public:
|
||||||
|
class FBaseIterator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
TMap<KeyType, ValueType>& IteratedMap;
|
||||||
|
TSet<ElementType>::FBaseIterator SetIt;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FBaseIterator(TMap<KeyType, ValueType>& InMap, TSet<ElementType>::FBaseIterator InSet)
|
||||||
|
: IteratedMap(InMap)
|
||||||
|
, SetIt(InSet)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
FORCEINLINE TMap<KeyType, ValueType>::FBaseIterator operator++()
|
||||||
|
{
|
||||||
|
++SetIt;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
FORCEINLINE TMap<KeyType, ValueType>::ElementType& operator*()
|
||||||
|
{
|
||||||
|
return *SetIt;
|
||||||
|
}
|
||||||
|
FORCEINLINE const TMap<KeyType, ValueType>::ElementType& operator*() const
|
||||||
|
{
|
||||||
|
return *SetIt;
|
||||||
|
}
|
||||||
|
FORCEINLINE bool operator==(const TMap<KeyType, ValueType>::FBaseIterator& Other) const
|
||||||
|
{
|
||||||
|
return SetIt == Other.SetIt;
|
||||||
|
}
|
||||||
|
FORCEINLINE bool operator!=(const TMap<KeyType, ValueType>::FBaseIterator& Other) const
|
||||||
|
{
|
||||||
|
return SetIt != Other.SetIt;
|
||||||
|
}
|
||||||
|
FORCEINLINE bool IsElementValid() const
|
||||||
|
{
|
||||||
|
return SetIt.IsElementValid();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FORCEINLINE TMap<KeyType, ValueType>::FBaseIterator begin()
|
||||||
|
{
|
||||||
|
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.begin());
|
||||||
|
}
|
||||||
|
FORCEINLINE const TMap<KeyType, ValueType>::FBaseIterator begin() const
|
||||||
|
{
|
||||||
|
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.begin());
|
||||||
|
}
|
||||||
|
FORCEINLINE TMap<KeyType, ValueType>::FBaseIterator end()
|
||||||
|
{
|
||||||
|
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.end());
|
||||||
|
}
|
||||||
|
FORCEINLINE const TMap<KeyType, ValueType>::FBaseIterator end() const
|
||||||
|
{
|
||||||
|
return TMap<KeyType, ValueType>::FBaseIterator(*this, Pairs.end());
|
||||||
|
}
|
||||||
|
FORCEINLINE ValueType& operator[](const KeyType& Key)
|
||||||
|
{
|
||||||
|
return this->GetByKey(Key);
|
||||||
|
}
|
||||||
|
FORCEINLINE const ValueType& operator[](const KeyType& Key) const
|
||||||
|
{
|
||||||
|
return this->GetByKey(Key);
|
||||||
|
}
|
||||||
|
FORCEINLINE int32 Num() const
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
for (auto Pair : *this)
|
||||||
|
{
|
||||||
|
if (Pair.Key() == Key)
|
||||||
|
{
|
||||||
|
return Pair.Value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
FORCEINLINE ValueType& Find(const KeyType& Key)
|
FORCEINLINE ValueType& Find(const KeyType& Key)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < this->Pairs.Elements.Num(); j++)
|
return GetByKey(Key);
|
||||||
|
}
|
||||||
|
FORCEINLINE ValueType GetByKeyNoRef(const KeyType& Key)
|
||||||
|
{
|
||||||
|
for (auto Pair : *this)
|
||||||
{
|
{
|
||||||
ElementType& Pair = this->Pairs.Elements.operator[](j).ElementData.Value;
|
if (Pair.Key() == Key)
|
||||||
|
{
|
||||||
if (Key == Pair.Key())
|
|
||||||
return Pair.Value();
|
return Pair.Value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
template <typename KeyType, typename ValueType> //, typename SetAllocator, typename KeyFuncs>
|
|
||||||
class TSortableMapBase : public TMapBase<KeyType, ValueType> //, SetAllocator, KeyFuncs>
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename KeyType, typename ValueType> //,typename SetAllocator /*= FDefaultSetAllocator*/, typename KeyFuncs /*= TDefaultMapHashableKeyFuncs<KeyType,ValueType,false>*/>
|
|
||||||
class TMap : public TSortableMapBase<KeyType, ValueType> //, SetAllocator, KeyFuncs>
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
#include "Array.h"
|
||||||
|
#include "Map.h"
|
||||||
|
#include "WeakObjectPtrTemplates.h"
|
||||||
|
#include "ActorChannel.h"
|
||||||
|
|
||||||
class UNetConnection : public UPlayer
|
class UNetConnection : public UPlayer
|
||||||
{
|
{
|
||||||
@@ -11,9 +15,51 @@ public:
|
|||||||
return Get<AActor*>(OwningActorOffset);
|
return Get<AActor*>(OwningActorOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FName& GetClientWorldPackageName() const
|
||||||
|
{
|
||||||
|
static auto ClientWorldPackageNameOffset = 0x337B8;
|
||||||
|
return *(FName*)(__int64(this) + ClientWorldPackageNameOffset);
|
||||||
|
}
|
||||||
|
|
||||||
AActor*& GetViewTarget()
|
AActor*& GetViewTarget()
|
||||||
{
|
{
|
||||||
static auto ViewTargetOffset = GetOffset("ViewTarget");
|
static auto ViewTargetOffset = GetOffset("ViewTarget");
|
||||||
return Get<AActor*>(ViewTargetOffset);
|
return Get<AActor*>(ViewTargetOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TSet<FName>& GetClientVisibleLevelNames()
|
||||||
|
{
|
||||||
|
static auto ClientVisibleLevelNamesOffset = 0x336C8;
|
||||||
|
return *(TSet<FName>*)(__int64(this) + ClientVisibleLevelNamesOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
class UNetDriver*& GetDriver()
|
||||||
|
{
|
||||||
|
static auto DriverOffset = GetOffset("Driver");
|
||||||
|
return Get<UNetDriver*>(DriverOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32& GetTickCount()
|
||||||
|
{
|
||||||
|
static auto TickCountOffset = GetOffset("LastReceiveTime") + 8 + 8 + 8 + 8 + 8 + 4;
|
||||||
|
return Get<int32>(TickCountOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
TMap<TWeakObjectPtr<AActor>, UActorChannel*>& GetActorChannels()
|
||||||
|
{
|
||||||
|
static auto ActorChannelsOffset = 0x33588;
|
||||||
|
return *(TMap<TWeakObjectPtr<AActor>, UActorChannel*>*)(__int64(this) + ActorChannelsOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<AActor*>& GetSentTemporaries()
|
||||||
|
{
|
||||||
|
static auto SentTemporariesOffset = GetOffset("SentTemporaries");
|
||||||
|
return Get<TArray<AActor*>>(SentTemporariesOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClientHasInitializedLevelFor(const AActor* TestActor) const
|
||||||
|
{
|
||||||
|
bool (*ClientHasInitializedLevelForOriginal)(const UNetConnection* Connection, const AActor * TestActor) = decltype(ClientHasInitializedLevelForOriginal)(this->VFTable[0x300 / 8]);
|
||||||
|
return ClientHasInitializedLevelForOriginal(this, TestActor);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -7,15 +7,135 @@
|
|||||||
#include "GameplayStatics.h"
|
#include "GameplayStatics.h"
|
||||||
#include "KismetMathLibrary.h"
|
#include "KismetMathLibrary.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include "GenericPlatformMath.h"
|
||||||
|
#include "ActorChannel.h"
|
||||||
|
#include "KismetSystemLibrary.h"
|
||||||
|
#include "UnrealMathUtility.h"
|
||||||
|
|
||||||
FNetworkObjectList& UNetDriver::GetNetworkObjectList()
|
FNetworkObjectList& UNetDriver::GetNetworkObjectList()
|
||||||
{
|
{
|
||||||
return *(*(TSharedPtr<FNetworkObjectList>*)(__int64(this) + Offsets::NetworkObjectList));
|
return *(*(TSharedPtr<FNetworkObjectList>*)(__int64(this) + Offsets::NetworkObjectList));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct FPacketIdRange
|
||||||
|
{
|
||||||
|
FPacketIdRange(int32 _First, int32 _Last) : First(_First), Last(_Last) { }
|
||||||
|
FPacketIdRange(int32 PacketId) : First(PacketId), Last(PacketId) { }
|
||||||
|
// FPacketIdRange() : First(INDEX_NONE), Last(INDEX_NONE) { }
|
||||||
|
int32 First;
|
||||||
|
int32 Last;
|
||||||
|
|
||||||
|
bool InRange(int32 PacketId)
|
||||||
|
{
|
||||||
|
return (First <= PacketId && PacketId <= Last);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
FActorPriority::FActorPriority(UNetConnection* InConnection, UActorChannel* InChannel, FNetworkObjectInfo* InActorInfo, const std::vector<FNetViewer>& Viewers, bool bLowBandwidth)
|
||||||
|
: ActorInfo(InActorInfo), Channel(InChannel), DestructionInfo(NULL)
|
||||||
|
{
|
||||||
|
float Time = Channel ? (InConnection->GetDriver()->GetTime() - Channel->GetLastUpdateTime()) : InConnection->GetDriver()->GetSpawnPrioritySeconds();
|
||||||
|
// take the highest priority of the viewers on this connection
|
||||||
|
Priority = 0;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < Viewers.size(); i++)
|
||||||
|
{
|
||||||
|
static auto GetNetPriorityOffset = 0x380;
|
||||||
|
float (*GetNetPriorityOriginal)(AActor* Actor, const FVector& ViewPos, const FVector& ViewDir, AActor* Viewer, AActor* ViewTarget, UActorChannel* InChannel, float Time, bool bLowBandwidth)
|
||||||
|
= decltype(GetNetPriorityOriginal)(ActorInfo->Actor->VFTable[GetNetPriorityOffset / 8]);
|
||||||
|
|
||||||
|
Priority = FMath::Max<int32>(Priority, FMath::RoundToInt(65536.0f * GetNetPriorityOriginal(ActorInfo->Actor, Viewers[i].ViewLocation, Viewers[i].ViewDir, Viewers[i].InViewer, Viewers[i].ViewTarget, InChannel, Time, bLowBandwidth)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FActorPriority::FActorPriority(UNetConnection* InConnection, FActorDestructionInfo* Info, const std::vector<FNetViewer>& Viewers)
|
||||||
|
: ActorInfo(NULL), Channel(NULL), DestructionInfo(Info)
|
||||||
|
{
|
||||||
|
Priority = 0;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < Viewers.size(); i++)
|
||||||
|
{
|
||||||
|
float Time = InConnection->GetDriver()->GetSpawnPrioritySeconds();
|
||||||
|
|
||||||
|
FVector Dir = DestructionInfo->DestroyedPosition - Viewers[i].ViewLocation;
|
||||||
|
float DistSq = Dir.SizeSquared();
|
||||||
|
|
||||||
|
// adjust priority based on distance and whether actor is in front of viewer
|
||||||
|
if ((Viewers.at(i).ViewDir | Dir) < 0.f)
|
||||||
|
{
|
||||||
|
if (DistSq > NEARSIGHTTHRESHOLDSQUARED)
|
||||||
|
Time *= 0.2f;
|
||||||
|
else if (DistSq > CLOSEPROXIMITYSQUARED)
|
||||||
|
Time *= 0.4f;
|
||||||
|
}
|
||||||
|
else if (DistSq > MEDSIGHTTHRESHOLDSQUARED)
|
||||||
|
Time *= 0.4f;
|
||||||
|
|
||||||
|
Priority = FMath::Max<int32>(Priority, 65536.0f * Time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetChannelActorForDestroy(UActorChannel* ActorChannel, FActorDestructionInfo* DestructInfo)
|
||||||
|
{
|
||||||
|
static auto ConnectionOffset = ActorChannel->GetOffset("Connection");
|
||||||
|
UNetConnection* Connection = ActorChannel->Get<UNetConnection*>(ConnectionOffset);
|
||||||
|
|
||||||
|
auto State = *(uint8_t*)(__int64(Connection) + 0x12C);
|
||||||
|
|
||||||
|
if (!(State - 2 <= 1)) // this will make sure that it is USOCK_Open or USOCK_Pending
|
||||||
|
return;
|
||||||
|
|
||||||
|
using FOutBunch = __int64;
|
||||||
|
|
||||||
|
static auto PackageMapOffset = Connection->GetOffset("PackageMap");
|
||||||
|
auto PackageMap = Connection->Get(PackageMapOffset);
|
||||||
|
|
||||||
|
FOutBunch* CloseBunch = Alloc(0x200);
|
||||||
|
|
||||||
|
if (!CloseBunch)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static FOutBunch(*FOutBunchConstructor)(FOutBunch* a1, UActorChannel* a2, bool bInClose) = decltype(FOutBunchConstructor)(__int64(GetModuleHandleW(0)) + 0x194E800);
|
||||||
|
/* *CloseBunch = */ FOutBunchConstructor(CloseBunch, ActorChannel, true);
|
||||||
|
|
||||||
|
// we could set bDormant but it's set by default to 0.
|
||||||
|
|
||||||
|
SetBitfield((PlaceholderBitfield*)(__int64(CloseBunch) + 0x30), 4, true); // bReliable
|
||||||
|
|
||||||
|
bool (*UPackageMap_WriteObjectOriginal)(UObject* PackageMap, FOutBunch* Ar, UObject* InOuter, FNetworkGUID NetGUID, FString ObjectName) = decltype(UPackageMap_WriteObjectOriginal)(PackageMap->VFTable[0x238 / 8]);
|
||||||
|
UPackageMap_WriteObjectOriginal(PackageMap, CloseBunch, DestructInfo->ObjOuter.Get(), DestructInfo->NetGUID, DestructInfo->PathName);
|
||||||
|
|
||||||
|
FPacketIdRange (*SendBunchOriginal)(UActorChannel* Channel, FOutBunch* Bunch, bool Merge) = decltype(SendBunchOriginal)(ActorChannel->VFTable[0x288 / 8]);
|
||||||
|
SendBunchOriginal(ActorChannel, CloseBunch, false);
|
||||||
|
|
||||||
|
static void (*FArchiveDeconstructor)(FOutBunch* Ar) = decltype(FArchiveDeconstructor)(__int64(GetModuleHandleW(0)) + 0xC36500);
|
||||||
|
FArchiveDeconstructor(CloseBunch);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSet<FNetworkGUID>& GetConnectionDestroyedStartupOrDormantActors(UNetConnection* Connection)
|
||||||
|
{
|
||||||
|
return *(TSet<FNetworkGUID>*)(__int64(Connection) + 0x33678);
|
||||||
|
}
|
||||||
|
|
||||||
|
TMap<FNetworkGUID, FActorDestructionInfo>& GetDriverDestroyedStartupOrDormantActors(UNetDriver* NetDriver)
|
||||||
|
{
|
||||||
|
return *(TMap<FNetworkGUID, FActorDestructionInfo>*)(__int64(NetDriver) + 0x228);
|
||||||
|
}
|
||||||
|
|
||||||
void UNetDriver::RemoveNetworkActor(AActor* Actor)
|
void UNetDriver::RemoveNetworkActor(AActor* Actor)
|
||||||
{
|
{
|
||||||
GetNetworkObjectList().Remove(Actor);
|
static void (*FNetworkObjectList_Remove)(FNetworkObjectList*, AActor* const a2) = decltype(FNetworkObjectList_Remove)(__int64(GetModuleHandleW(0)) + 0x1AEBB40);
|
||||||
|
FNetworkObjectList_Remove(&GetNetworkObjectList(), Actor);
|
||||||
|
// GetNetworkObjectList().Remove(Actor);
|
||||||
|
|
||||||
// RenamedStartupActors.Remove(Actor->GetFName());
|
// RenamedStartupActors.Remove(Actor->GetFName());
|
||||||
}
|
}
|
||||||
@@ -88,19 +208,10 @@ enum class ENetRole : uint8_t
|
|||||||
ROLE_MAX = 4
|
ROLE_MAX = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ENetDormancy : uint8_t
|
|
||||||
{
|
|
||||||
DORM_Never = 0,
|
|
||||||
DORM_Awake = 1,
|
|
||||||
DORM_DormantAll = 2,
|
|
||||||
DORM_DormantPartial = 3,
|
|
||||||
DORM_Initial = 4,
|
|
||||||
DORN_MAX = 5,
|
|
||||||
ENetDormancy_MAX = 6
|
|
||||||
};
|
|
||||||
|
|
||||||
FORCEINLINE float FRand()
|
FORCEINLINE float FRand()
|
||||||
{
|
{
|
||||||
|
return ReplicationRandStream.FRand();
|
||||||
|
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 gen(rd());
|
std::mt19937 gen(rd());
|
||||||
std::uniform_real_distribution<> dis(0, 1);
|
std::uniform_real_distribution<> dis(0, 1);
|
||||||
@@ -109,44 +220,37 @@ FORCEINLINE float FRand()
|
|||||||
return random_number;
|
return random_number;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define USEOBJECTLIST
|
FORCEINLINE float SRand()
|
||||||
|
{
|
||||||
|
GSRandSeed = (GSRandSeed * 196314165) + 907633515;
|
||||||
|
union { float f; int32 i; } Result;
|
||||||
|
union { float f; int32 i; } Temp;
|
||||||
|
const float SRandTemp = 1.0f;
|
||||||
|
Temp.f = SRandTemp;
|
||||||
|
Result.i = (Temp.i & 0xff800000) | (GSRandSeed & 0x007fffff);
|
||||||
|
auto res = FPlatformMath::Fractional(Result.f);
|
||||||
|
// MILXNOR
|
||||||
|
// res /= 3;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList)
|
void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList)
|
||||||
{
|
{
|
||||||
std::vector<AActor*> ActorsToRemove;
|
std::vector<AActor*> ActorsToRemove;
|
||||||
|
|
||||||
#ifdef USEOBJECTLIST
|
|
||||||
auto& ActiveObjects = GetNetworkObjectList().ActiveNetworkObjects;
|
auto& ActiveObjects = GetNetworkObjectList().ActiveNetworkObjects;
|
||||||
#else
|
|
||||||
TArray<AActor*> Actors = UGameplayStatics::GetAllActorsOfClass(GetWorld(), AActor::StaticClass());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto World = GetWorld();
|
auto World = GetWorld();
|
||||||
|
|
||||||
#ifdef USEOBJECTLIST
|
|
||||||
// for (int i = 0; i < ActiveObjects.Elements.Num(); i++)
|
|
||||||
for (const TSharedPtr<FNetworkObjectInfo>& ActorInfo : ActiveObjects)
|
for (const TSharedPtr<FNetworkObjectInfo>& ActorInfo : ActiveObjects)
|
||||||
{
|
{
|
||||||
// auto& ActorInfo = ActiveObjects.Elements.Data.at(i).ElementData.Value;
|
|
||||||
|
|
||||||
if (!ActorInfo->bPendingNetUpdate && UGameplayStatics::GetTimeSeconds(GetWorld()) <= ActorInfo->NextUpdateTime)
|
if (!ActorInfo->bPendingNetUpdate && UGameplayStatics::GetTimeSeconds(GetWorld()) <= ActorInfo->NextUpdateTime)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (IsBadReadPtr(ActorInfo, 8))
|
|
||||||
// continue;
|
|
||||||
|
|
||||||
auto Actor = ActorInfo->Actor;
|
auto Actor = ActorInfo->Actor;
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
for (int i = 0; i < Actors.Num(); i++)
|
|
||||||
{
|
|
||||||
auto Actor = Actors.at(i);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!Actor)
|
if (!Actor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -171,20 +275,15 @@ void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObj
|
|||||||
|
|
||||||
// We should check the level stuff here.
|
// We should check the level stuff here.
|
||||||
|
|
||||||
static auto NetDormancyOffset = Actor->GetOffset("NetDormancy");
|
if (Actor->GetNetDormancy() == ENetDormancy::DORM_Initial && Actor->IsNetStartupActor()) // IsDormInitialStartupActor
|
||||||
|
|
||||||
if (Actor->Get<ENetDormancy>(NetDormancyOffset) == ENetDormancy::DORM_Initial && Actor->IsNetStartupActor()) // IsDormInitialStartupActor
|
|
||||||
{
|
{
|
||||||
|
ActorsToRemove.push_back(Actor);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should check NeedsLoadForClient here.
|
// We should check NeedsLoadForClient here.
|
||||||
// We should make sure the actor is in the same world here but I don't believe it is needed.
|
// We should make sure the actor is in the same world here but I don't believe it is needed.
|
||||||
|
|
||||||
#ifndef USEOBJECTLIST
|
|
||||||
FNetworkObjectInfo* ActorInfo = new FNetworkObjectInfo;
|
|
||||||
ActorInfo->Actor = Actor;
|
|
||||||
#else
|
|
||||||
auto TimeSeconds = UGameplayStatics::GetTimeSeconds(World); // Can we do this outside of the loop?
|
auto TimeSeconds = UGameplayStatics::GetTimeSeconds(World); // Can we do this outside of the loop?
|
||||||
|
|
||||||
if (ActorInfo->LastNetReplicateTime == 0)
|
if (ActorInfo->LastNetReplicateTime == 0)
|
||||||
@@ -208,10 +307,10 @@ void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObj
|
|||||||
}
|
}
|
||||||
|
|
||||||
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency(); // Don't go faster than NetUpdateFrequency
|
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency(); // Don't go faster than NetUpdateFrequency
|
||||||
const float MaxOptimalDelta = max(1.0f / Actor->GetNetUpdateFrequency(), MinOptimalDelta); // Don't go slower than MinNetUpdateFrequency (or NetUpdateFrequency if it's slower)
|
const float MaxOptimalDelta = FMath::Max(1.0f / Actor->GetNetUpdateFrequency(), MinOptimalDelta); // Don't go slower than MinNetUpdateFrequency (or NetUpdateFrequency if it's slower)
|
||||||
|
|
||||||
const float Alpha = std::clamp((LastReplicateDelta - ScaleDownStartTime) / ScaleDownTimeRange, 0.0f, 1.0f); // should we use fmath?
|
const float Alpha = FMath::Clamp( (LastReplicateDelta - ScaleDownStartTime) / ScaleDownTimeRange, 0.0f, 1.0f);
|
||||||
ActorInfo->OptimalNetUpdateDelta = std::lerp(MinOptimalDelta, MaxOptimalDelta, Alpha); // should we use fmath?
|
ActorInfo->OptimalNetUpdateDelta = FMath::Lerp(MinOptimalDelta, MaxOptimalDelta, Alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ActorInfo->bPendingNetUpdate)
|
if (!ActorInfo->bPendingNetUpdate)
|
||||||
@@ -221,13 +320,11 @@ void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObj
|
|||||||
|
|
||||||
// then set the next update time
|
// then set the next update time
|
||||||
float ServerTickTime = 1.f / 30;
|
float ServerTickTime = 1.f / 30;
|
||||||
ActorInfo->NextUpdateTime = TimeSeconds + FRand() * ServerTickTime + NextUpdateDelta;
|
ActorInfo->NextUpdateTime = TimeSeconds + SRand() * ServerTickTime + NextUpdateDelta;
|
||||||
static auto TimeOffset = GetOffset("Time");
|
ActorInfo->LastNetUpdateTime = GetTime();
|
||||||
ActorInfo->LastNetUpdateTime = Get<float>(TimeOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ActorInfo->bPendingNetUpdate = false;
|
ActorInfo->bPendingNetUpdate = false;
|
||||||
#endif
|
|
||||||
|
|
||||||
OutConsiderList.push_back(ActorInfo.Get());
|
OutConsiderList.push_back(ActorInfo.Get());
|
||||||
|
|
||||||
@@ -235,69 +332,16 @@ void UNetDriver::ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObj
|
|||||||
CallPreReplication(Actor, this);
|
CallPreReplication(Actor, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef USEOBJECTLIST
|
|
||||||
Actors.Free();
|
|
||||||
#else
|
|
||||||
for (auto Actor : ActorsToRemove)
|
for (auto Actor : ActorsToRemove)
|
||||||
{
|
{
|
||||||
if (!Actor)
|
if (!Actor)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* LOG_INFO(LogDev, "Removing actor: {}", Actor ? Actor->GetFullName() : "InvalidObject");
|
|
||||||
RemoveNetworkActor(Actor);
|
RemoveNetworkActor(Actor);
|
||||||
LOG_INFO(LogDev, "Finished removing actor."); */
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using UChannel = UObject;
|
static bool IsActorRelevantToConnection(AActor* Actor, const std::vector<FNetViewer>& ConnectionViewers)
|
||||||
using UActorChannel = UObject;
|
|
||||||
|
|
||||||
static UActorChannel* FindChannel(AActor* Actor, UNetConnection* Connection)
|
|
||||||
{
|
|
||||||
static auto OpenChannelsOffset = Connection->GetOffset("OpenChannels");
|
|
||||||
auto& OpenChannels = Connection->Get<TArray<UChannel*>>(OpenChannelsOffset);
|
|
||||||
|
|
||||||
static auto ActorChannelClass = FindObject<UClass>("/Script/Engine.ActorChannel");
|
|
||||||
|
|
||||||
// LOG_INFO(LogReplication, "OpenChannels.Num(): {}", OpenChannels.Num());
|
|
||||||
|
|
||||||
for (int i = 0; i < OpenChannels.Num(); i++)
|
|
||||||
{
|
|
||||||
auto Channel = OpenChannels.at(i);
|
|
||||||
|
|
||||||
if (!Channel)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// LOG_INFO(LogReplication, "[{}] Class {}", i, Channel->ClassPrivate ? Channel->ClassPrivate->GetFullName() : "InvalidObject");
|
|
||||||
|
|
||||||
if (!Channel->IsA(ActorChannelClass)) // (Channel->ClassPrivate == ActorChannelClass)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
static auto ActorOffset = Channel->GetOffset("Actor");
|
|
||||||
auto ChannelActor = Channel->Get<AActor*>(ActorOffset);
|
|
||||||
|
|
||||||
// LOG_INFO(LogReplication, "[{}] {}", i, ChannelActor->GetFullName());
|
|
||||||
|
|
||||||
if (ChannelActor != Actor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return (UActorChannel*)Channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool IsActorRelevantToConnection(AActor* Actor, std::vector<FNetViewer>& ConnectionViewers)
|
|
||||||
{
|
{
|
||||||
for (int32 viewerIdx = 0; viewerIdx < ConnectionViewers.size(); viewerIdx++)
|
for (int32 viewerIdx = 0; viewerIdx < ConnectionViewers.size(); viewerIdx++)
|
||||||
{
|
{
|
||||||
@@ -310,7 +354,7 @@ static bool IsActorRelevantToConnection(AActor* Actor, std::vector<FNetViewer>&
|
|||||||
|
|
||||||
// if (Actor->IsNetRelevantFor(ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, ConnectionViewers[viewerIdx].ViewLocation))
|
// if (Actor->IsNetRelevantFor(ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, ConnectionViewers[viewerIdx].ViewLocation))
|
||||||
// if (IsNetRelevantFor(Actor, ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, ConnectionViewers[viewerIdx].ViewLocation))
|
// if (IsNetRelevantFor(Actor, ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, ConnectionViewers[viewerIdx].ViewLocation))
|
||||||
if (reinterpret_cast<bool(*)(AActor*, AActor*, AActor*, FVector&)>(Actor->VFTable[index])(
|
if (reinterpret_cast<bool(*)(AActor*, AActor*, AActor*, const FVector&)>(Actor->VFTable[index])(
|
||||||
Actor, ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, ConnectionViewers[viewerIdx].ViewLocation))
|
Actor, ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, ConnectionViewers[viewerIdx].ViewLocation))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -320,6 +364,236 @@ static bool IsActorRelevantToConnection(AActor* Actor, std::vector<FNetViewer>&
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UNetDriver::IsLevelInitializedForActor(const AActor* InActor, const UNetConnection* InConnection) const
|
||||||
|
{
|
||||||
|
const bool bCorrectWorld = (InConnection->GetClientWorldPackageName() == GetWorldPackage()->NamePrivate && InConnection->ClientHasInitializedLevelFor(InActor));
|
||||||
|
const bool bIsConnectionPC = (InActor == InConnection->GetPlayerController());
|
||||||
|
return bCorrectWorld || bIsConnectionPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE bool IsActorDormant(FNetworkObjectInfo* ActorInfo, const TWeakObjectPtr<UNetConnection>& Connection)
|
||||||
|
{
|
||||||
|
// If actor is already dormant on this channel, then skip replication entirely
|
||||||
|
return ActorInfo->DormantConnections.Contains(Connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCEINLINE UNetConnection* IsActorOwnedByAndRelevantToConnection(const AActor* Actor, const std::vector<FNetViewer>& ConnectionViewers, bool& bOutHasNullViewTarget)
|
||||||
|
{
|
||||||
|
const AActor* ActorOwner = Actor->GetNetOwner();
|
||||||
|
|
||||||
|
bOutHasNullViewTarget = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < ConnectionViewers.size(); i++)
|
||||||
|
{
|
||||||
|
UNetConnection* ViewerConnection = ConnectionViewers[i].Connection;
|
||||||
|
|
||||||
|
if (ViewerConnection->GetViewTarget() == nullptr)
|
||||||
|
{
|
||||||
|
bOutHasNullViewTarget = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ActorOwner == ViewerConnection->GetPlayerController() ||
|
||||||
|
(ViewerConnection->GetPlayerController() && ActorOwner == ViewerConnection->GetPlayerController()->GetPawn()) ||
|
||||||
|
(ViewerConnection->GetViewTarget() && ViewerConnection->GetViewTarget()->IsRelevancyOwnerFor(Actor, ActorOwner, ViewerConnection->GetOwningActor())))
|
||||||
|
{
|
||||||
|
return ViewerConnection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct FCompareFActorPriority
|
||||||
|
{
|
||||||
|
FORCEINLINE bool operator()(const FActorPriority& A, const FActorPriority& B) const
|
||||||
|
{
|
||||||
|
return B.Priority < A.Priority;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static FORCEINLINE bool ShouldActorGoDormant(AActor* Actor, const std::vector<FNetViewer>& ConnectionViewers, UActorChannel* Channel, const float Time, const bool bLowNetBandwidth)
|
||||||
|
{
|
||||||
|
using enum ENetDormancy;
|
||||||
|
|
||||||
|
static auto bPendingDormancyOffset = 0x30;
|
||||||
|
static auto bPendingDormancyFieldMask = 0x0;
|
||||||
|
static auto DormantOffset = 0x30;
|
||||||
|
static auto DormantFieldMask = 0x0;
|
||||||
|
|
||||||
|
if (Actor->GetNetDormancy() <= DORM_Awake || !Channel
|
||||||
|
// || ReadBitfield((PlaceholderBitfield*)(__int64(Channel) + bPendingDormancyOffset), bPendingDormancyFieldMask)
|
||||||
|
// || ReadBitfield((PlaceholderBitfield*)(__int64(Channel) + DormantOffset), DormantFieldMask)
|
||||||
|
|| Channel->IsPendingDormancy()
|
||||||
|
|| Channel->IsDormant()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Either shouldn't go dormant, or is already dormant
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Actor->GetNetDormancy() == DORM_DormantPartial)
|
||||||
|
{
|
||||||
|
for (int32 viewerIdx = 0; viewerIdx < ConnectionViewers.size(); viewerIdx++)
|
||||||
|
{
|
||||||
|
// if (!Actor->GetNetDormancy(ConnectionViewers[viewerIdx].ViewLocation, ConnectionViewers[viewerIdx].ViewDir, ConnectionViewers[viewerIdx].InViewer, ConnectionViewers[viewerIdx].ViewTarget, Channel, Time, bLowNetBandwidth))
|
||||||
|
if (!false) // ^ this just returns false soo (atleast AActor implementation)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 UNetDriver::ServerReplicateActors_PrioritizeActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, const std::vector<FNetworkObjectInfo*> ConsiderList, const bool bCPUSaturated, FActorPriority*& OutPriorityList, FActorPriority**& OutPriorityActors)
|
||||||
|
{
|
||||||
|
GetNetTag()++;
|
||||||
|
Connection->GetTickCount()++;
|
||||||
|
|
||||||
|
for (int32 j = 0; j < Connection->GetSentTemporaries().Num(); j++) // Set up to skip all sent temporary actors
|
||||||
|
{
|
||||||
|
Connection->GetSentTemporaries().at(j)->GetNetTag() = GetNetTag();
|
||||||
|
}
|
||||||
|
|
||||||
|
// check( World == Connection->OwningActor->GetWorld() );
|
||||||
|
|
||||||
|
int32 FinalSortedCount = 0;
|
||||||
|
int32 DeletedCount = 0;
|
||||||
|
|
||||||
|
// Make weak ptr once for IsActorDormant call
|
||||||
|
TWeakObjectPtr<UNetConnection> WeakConnection{};
|
||||||
|
WeakConnection.ObjectIndex = Connection->InternalIndex;
|
||||||
|
WeakConnection.ObjectSerialNumber = GetItemByIndex(Connection->InternalIndex)->SerialNumber;
|
||||||
|
|
||||||
|
auto& Connection_DestroyedStartupOrDormantActors = GetConnectionDestroyedStartupOrDormantActors(Connection);
|
||||||
|
|
||||||
|
const int32 MaxSortedActors = ConsiderList.size() + Connection_DestroyedStartupOrDormantActors.Num();
|
||||||
|
|
||||||
|
if (MaxSortedActors > 0)
|
||||||
|
{
|
||||||
|
OutPriorityList = Alloc<FActorPriority>(MaxSortedActors * sizeof(FActorPriority));
|
||||||
|
OutPriorityActors = Alloc<FActorPriority*>(MaxSortedActors * sizeof(FActorPriority*));
|
||||||
|
|
||||||
|
// check( World == Connection->ViewTarget->GetWorld() );
|
||||||
|
|
||||||
|
// AGameNetworkManager* const NetworkManager = World->NetworkManager;
|
||||||
|
const bool bLowNetBandwidth = false; // NetworkManager ? NetworkManager->IsInLowBandwidthMode() : false;
|
||||||
|
|
||||||
|
for (int i = 0; i < ConsiderList.size(); i++)
|
||||||
|
{
|
||||||
|
FNetworkObjectInfo* ActorInfo = ConsiderList.at(i);
|
||||||
|
AActor* Actor = ActorInfo->Actor;
|
||||||
|
|
||||||
|
auto& ActorChannels = Connection->GetActorChannels();
|
||||||
|
UActorChannel* Channel = nullptr;
|
||||||
|
|
||||||
|
// Connection->ActorChannels.FindRef(ActorInfo->WeakActor);
|
||||||
|
|
||||||
|
for (int i = 0; i < ActorChannels.Pairs.Num(); i++)
|
||||||
|
{
|
||||||
|
if (ActorChannels.Pairs[i].First == ActorInfo->WeakActor)
|
||||||
|
{
|
||||||
|
Channel = ActorChannels.Pairs[i].Second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Channel)
|
||||||
|
{
|
||||||
|
if (!IsLevelInitializedForActor(Actor, Connection))
|
||||||
|
{
|
||||||
|
// If the level this actor belongs to isn't loaded on client, don't bother sending
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsActorRelevantToConnection(Actor, ConnectionViewers))
|
||||||
|
{
|
||||||
|
// LOG_INFO(LogDev, "Not relevant!");
|
||||||
|
|
||||||
|
// If not relevant (and we don't have a channel), skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LOG_INFO(LogDev, "Actor->GetNetTag(): {}", Actor->GetNetTag());
|
||||||
|
|
||||||
|
UNetConnection* PriorityConnection = Connection;
|
||||||
|
|
||||||
|
if (Actor->IsOnlyRelevantToOwner())
|
||||||
|
{
|
||||||
|
// This actor should be owned by a particular connection, see if that connection is the one passed in
|
||||||
|
bool bHasNullViewTarget = false;
|
||||||
|
|
||||||
|
PriorityConnection = IsActorOwnedByAndRelevantToConnection(Actor, ConnectionViewers, bHasNullViewTarget);
|
||||||
|
|
||||||
|
if (PriorityConnection == nullptr)
|
||||||
|
{
|
||||||
|
if (!bHasNullViewTarget && Channel != NULL && GetTime() - Channel->GetRelevantTime() >= GetRelevantTimeout())
|
||||||
|
{
|
||||||
|
Channel->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// else if (CVarSetNetDormancyEnabled.GetValueOnGameThread() != 0)
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Skip Actor if dormant
|
||||||
|
if (IsActorDormant(ActorInfo, WeakConnection))
|
||||||
|
{
|
||||||
|
// LOG_INFO(LogDev, "Actor is dormant!");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See of actor wants to try and go dormant
|
||||||
|
if (ShouldActorGoDormant(Actor, ConnectionViewers, Channel, GetTime(), bLowNetBandwidth))
|
||||||
|
{
|
||||||
|
// LOG_INFO(LogDev, "Actor is going dormant!");
|
||||||
|
|
||||||
|
// Channel is marked to go dormant now once all properties have been replicated (but is not dormant yet)
|
||||||
|
Channel->StartBecomingDormant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actor is relevant to this connection, add it to the list
|
||||||
|
// NOTE - We use NetTag to make sure SentTemporaries didn't already mark this actor to be skipped
|
||||||
|
|
||||||
|
if (Actor->GetNetTag() != GetNetTag())
|
||||||
|
{
|
||||||
|
Actor->GetNetTag() = GetNetTag();
|
||||||
|
|
||||||
|
OutPriorityList[FinalSortedCount] = FActorPriority(PriorityConnection, Channel, ActorInfo, ConnectionViewers, bLowNetBandwidth);
|
||||||
|
OutPriorityActors[FinalSortedCount] = OutPriorityList + FinalSortedCount;
|
||||||
|
|
||||||
|
FinalSortedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add in deleted actors
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
for (auto& CurrentGuid : Connection_DestroyedStartupOrDormantActors)
|
||||||
|
{
|
||||||
|
FActorDestructionInfo& DInfo = GetDriverDestroyedStartupOrDormantActors(this).Find(CurrentGuid);
|
||||||
|
OutPriorityList[FinalSortedCount] = FActorPriority(Connection, &DInfo, ConnectionViewers);
|
||||||
|
OutPriorityActors[FinalSortedCount] = OutPriorityList + FinalSortedCount;
|
||||||
|
FinalSortedCount++;
|
||||||
|
DeletedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Sort(OutPriorityActors, FinalSortedCount, FCompareFActorPriority());
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalSortedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define NAME_None 0
|
||||||
|
|
||||||
static FNetViewer ConstructNetViewer(UNetConnection* NetConnection)
|
static FNetViewer ConstructNetViewer(UNetConnection* NetConnection)
|
||||||
{
|
{
|
||||||
FNetViewer newViewer{};
|
FNetViewer newViewer{};
|
||||||
@@ -344,6 +618,143 @@ static FNetViewer ConstructNetViewer(UNetConnection* NetConnection)
|
|||||||
return newViewer;
|
return newViewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32 UNetDriver::ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, FActorPriority** PriorityActors, const int32 FinalSortedCount, int32& OutUpdated)
|
||||||
|
{
|
||||||
|
static UChannel* (*CreateChannel)(UNetConnection*, int, bool, int32_t) = decltype(CreateChannel)(Addresses::CreateChannel);
|
||||||
|
static __int64 (*ReplicateActor)(UActorChannel*) = decltype(ReplicateActor)(Addresses::ReplicateActor);
|
||||||
|
static __int64 (*SetChannelActor)(UActorChannel*, AActor*) = decltype(SetChannelActor)(Addresses::SetChannelActor);
|
||||||
|
|
||||||
|
int32 ActorUpdatesThisConnection = 0;
|
||||||
|
int32 ActorUpdatesThisConnectionSent = 0;
|
||||||
|
int32 FinalRelevantCount = 0;
|
||||||
|
|
||||||
|
for (int32 j = 0; j < FinalSortedCount; j++)
|
||||||
|
{
|
||||||
|
FNetworkObjectInfo* ActorInfo = PriorityActors[j]->ActorInfo;
|
||||||
|
|
||||||
|
// Deletion entry
|
||||||
|
if (ActorInfo == NULL && PriorityActors[j]->DestructionInfo)
|
||||||
|
{
|
||||||
|
// Make sure client has streaming level loaded
|
||||||
|
if (PriorityActors[j]->DestructionInfo->StreamingLevelName.ComparisonIndex.Value != NAME_None && !Connection->GetClientVisibleLevelNames().Contains(PriorityActors[j]->DestructionInfo->StreamingLevelName))
|
||||||
|
{
|
||||||
|
// This deletion entry is for an actor in a streaming level the connection doesn't have loaded, so skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UActorChannel* Channel = (UActorChannel*)CreateChannel(Connection, 2, true, -1);
|
||||||
|
|
||||||
|
if (Channel)
|
||||||
|
{
|
||||||
|
FinalRelevantCount++;
|
||||||
|
|
||||||
|
auto& Connection_DestroyedStartupOrDormantActors = GetConnectionDestroyedStartupOrDormantActors(Connection);
|
||||||
|
|
||||||
|
SetChannelActorForDestroy(Channel, PriorityActors[j]->DestructionInfo); // Send a close bunch on the new channel
|
||||||
|
Connection_DestroyedStartupOrDormantActors.Remove(PriorityActors[j]->DestructionInfo->NetGUID); // Remove from connections to-be-destroyed list (close bunch of reliable, so it will make it there)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normal actor replication
|
||||||
|
UActorChannel* Channel = PriorityActors[j]->Channel;
|
||||||
|
if (!Channel || Channel->GetActor()) //make sure didn't just close this channel
|
||||||
|
{
|
||||||
|
AActor* Actor = ActorInfo->Actor;
|
||||||
|
// Test2(Actor, "Before");
|
||||||
|
|
||||||
|
bool bIsRelevant = false;
|
||||||
|
|
||||||
|
const bool bLevelInitializedForActor = IsLevelInitializedForActor(Actor, Connection);
|
||||||
|
|
||||||
|
// only check visibility on already visible actors every 1.0 + 0.5R seconds
|
||||||
|
// bTearOff actors should never be checked
|
||||||
|
if (bLevelInitializedForActor)
|
||||||
|
{
|
||||||
|
if (!Actor->IsTearOff() && (!Channel || GetTime() - Channel->GetRelevantTime() > 1.f))
|
||||||
|
{
|
||||||
|
if (IsActorRelevantToConnection(Actor, ConnectionViewers))
|
||||||
|
{
|
||||||
|
bIsRelevant = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the actor is now relevant or was recently relevant
|
||||||
|
const bool bIsRecentlyRelevant = bIsRelevant || (Channel && GetTime() - Channel->GetRelevantTime() < GetRelevantTimeout()) || ActorInfo->bForceRelevantNextUpdate;
|
||||||
|
|
||||||
|
// Test2(Actor, std::format("bIsRecentlyRelevant: {} Channel: {} bIsRelevant: {}", (int)bIsRecentlyRelevant, __int64(Channel), (int)bIsRelevant));
|
||||||
|
// Test2(Actor, std::format("bIsRelevant: {} bLevelInitializedForActor: {} Cond: {}", bIsRelevant, bLevelInitializedForActor, !Actor->IsTearOff() && (!Channel || GetTime() - Channel->GetRelevantTime() > 1.f)));
|
||||||
|
// Test2(Actor, std::format("TearOff: {} GetTime(): {} Channel->GetRelevantTime(): {}", !Actor->IsTearOff(), GetTime(), Channel ? Channel->GetRelevantTime() : 99));
|
||||||
|
|
||||||
|
ActorInfo->bForceRelevantNextUpdate = false;
|
||||||
|
|
||||||
|
if (bIsRecentlyRelevant)
|
||||||
|
{
|
||||||
|
FinalRelevantCount++;
|
||||||
|
|
||||||
|
if (Channel == NULL) // && GuidCache->SupportsObject(Actor->GetClass()) && GuidCache->SupportsObject(Actor->IsNetStartupActor() ? Actor : Actor->GetArchetype()))
|
||||||
|
{
|
||||||
|
if (bLevelInitializedForActor)
|
||||||
|
{
|
||||||
|
// Create a new channel for this actor.
|
||||||
|
UActorChannel* Channel = (UActorChannel*)CreateChannel(Connection, 2, true, -1);
|
||||||
|
|
||||||
|
if (Channel)
|
||||||
|
{
|
||||||
|
SetChannelActor(Channel, Actor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we couldn't replicate it for a reason that should be temporary, and this Actor is updated very infrequently, make sure we update it again soon
|
||||||
|
else if (Actor->GetNetUpdateFrequency() < 1.0f)
|
||||||
|
{
|
||||||
|
auto TimeSeconds = UGameplayStatics::GetTimeSeconds(GetWorld()); // Actor->GetWorld()->TimeSeconds
|
||||||
|
ActorInfo->NextUpdateTime = TimeSeconds + 0.2f * FRand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Channel)
|
||||||
|
{
|
||||||
|
// if it is relevant then mark the channel as relevant for a short amount of time
|
||||||
|
if (bIsRelevant)
|
||||||
|
{
|
||||||
|
Channel->GetRelevantTime() = GetTime() + 0.5f * SRand();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ReplicateActor(Channel))
|
||||||
|
{
|
||||||
|
ActorUpdatesThisConnectionSent++;
|
||||||
|
|
||||||
|
// Calculate min delta (max rate actor will upate), and max delta (slowest rate actor will update)
|
||||||
|
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency();
|
||||||
|
const float MaxOptimalDelta = FMath::Max(1.0f / Actor->GetMinNetUpdateFrequency(), MinOptimalDelta);
|
||||||
|
const float DeltaBetweenReplications = (UGameplayStatics::GetTimeSeconds(GetWorld()) - ActorInfo->LastNetReplicateTime);
|
||||||
|
|
||||||
|
// Choose an optimal time, we choose 70% of the actual rate to allow frequency to go up if needed
|
||||||
|
ActorInfo->OptimalNetUpdateDelta = FMath::Clamp(DeltaBetweenReplications * 0.7f, MinOptimalDelta, MaxOptimalDelta);
|
||||||
|
ActorInfo->LastNetReplicateTime = UGameplayStatics::GetTimeSeconds(GetWorld());
|
||||||
|
ReplicatedActors.emplace(Actor->GetFullName());
|
||||||
|
}
|
||||||
|
|
||||||
|
ActorUpdatesThisConnection++;
|
||||||
|
OutUpdated++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!bIsRecentlyRelevant || Actor->IsTearOff()) && Channel != NULL)
|
||||||
|
{
|
||||||
|
if (!bLevelInitializedForActor || !Actor->IsNetStartupActor())
|
||||||
|
{
|
||||||
|
Channel->Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FinalSortedCount;
|
||||||
|
}
|
||||||
|
|
||||||
int32 UNetDriver::ServerReplicateActors()
|
int32 UNetDriver::ServerReplicateActors()
|
||||||
{
|
{
|
||||||
int32 Updated = 0;
|
int32 Updated = 0;
|
||||||
@@ -374,9 +785,7 @@ int32 UNetDriver::ServerReplicateActors()
|
|||||||
|
|
||||||
std::vector<FNetworkObjectInfo*> ConsiderList;
|
std::vector<FNetworkObjectInfo*> ConsiderList;
|
||||||
|
|
||||||
#ifdef USEOBJECTLIST
|
|
||||||
ConsiderList.reserve(GetNetworkObjectList().ActiveNetworkObjects.Num());
|
ConsiderList.reserve(GetNetworkObjectList().ActiveNetworkObjects.Num());
|
||||||
#endif
|
|
||||||
|
|
||||||
// std::cout << "ConsiderList.size(): " << GetNetworkObjectList(NetDriver).ActiveNetworkObjects.Num() << '\n';
|
// std::cout << "ConsiderList.size(): " << GetNetworkObjectList(NetDriver).ActiveNetworkObjects.Num() << '\n';
|
||||||
|
|
||||||
@@ -384,97 +793,110 @@ int32 UNetDriver::ServerReplicateActors()
|
|||||||
|
|
||||||
ServerReplicateActors_BuildConsiderList(ConsiderList);
|
ServerReplicateActors_BuildConsiderList(ConsiderList);
|
||||||
|
|
||||||
for (int32 i = 0; i < this->GetClientConnections().Num(); i++)
|
bool bCPUSaturated = false;
|
||||||
|
|
||||||
|
auto& ClientConnections = GetClientConnections();
|
||||||
|
|
||||||
|
for (int32 i = 0; i < ClientConnections.Num(); i++)
|
||||||
{
|
{
|
||||||
UNetConnection* Connection = this->GetClientConnections().at(i);
|
UNetConnection* Connection = ClientConnections.at(i);
|
||||||
|
|
||||||
if (!Connection)
|
if (!Connection)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// idk some dormancy validate stuff should go here
|
||||||
|
|
||||||
|
// if this client shouldn't be ticked this frame
|
||||||
if (i >= NumClientsToTick)
|
if (i >= NumClientsToTick)
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!Connection->GetViewTarget())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (Connection->GetPlayerController())
|
|
||||||
{
|
{
|
||||||
static void (*SendClientAdjustment)(APlayerController*) = decltype(SendClientAdjustment)(Addresses::SendClientAdjustment);
|
//UE_LOG(LogNet, Log, TEXT("skipping update to %s"),*Connection->GetName());
|
||||||
SendClientAdjustment(Connection->GetPlayerController());
|
// then mark each considered actor as bPendingNetUpdate so that they will be considered again the next frame when the connection is actually ticked
|
||||||
}
|
for (int32 ConsiderIdx = 0; ConsiderIdx < ConsiderList.size(); ConsiderIdx++)
|
||||||
|
|
||||||
for (auto& ActorInfo : ConsiderList)
|
|
||||||
{
|
|
||||||
if (!ActorInfo || !ActorInfo->Actor)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
auto Actor = ActorInfo->Actor;
|
|
||||||
|
|
||||||
auto Channel = FindChannel(Actor, Connection);
|
|
||||||
|
|
||||||
if (Addresses::ActorChannelClose && Offsets::IsNetRelevantFor)
|
|
||||||
{
|
{
|
||||||
static void (*ActorChannelClose)(UActorChannel*) = decltype(ActorChannelClose)(Addresses::ActorChannelClose);
|
AActor* Actor = ConsiderList[ConsiderIdx]->Actor;
|
||||||
|
// if the actor hasn't already been flagged by another connection,
|
||||||
std::vector<FNetViewer> ConnectionViewers;
|
if (Actor != NULL && !ConsiderList[ConsiderIdx]->bPendingNetUpdate)
|
||||||
ConnectionViewers.push_back(ConstructNetViewer(Connection));
|
|
||||||
|
|
||||||
if (!Actor->IsAlwaysRelevant() && !Actor->UsesOwnerRelevancy() && !Actor->IsOnlyRelevantToOwner())
|
|
||||||
{
|
{
|
||||||
if (Connection && Connection->GetViewTarget())
|
// find the channel
|
||||||
|
|
||||||
|
UActorChannel* Channel = nullptr;
|
||||||
|
|
||||||
|
auto& ActorChannels = Connection->GetActorChannels();
|
||||||
|
|
||||||
|
for (int i = 0; i < ActorChannels.Pairs.Num(); i++)
|
||||||
{
|
{
|
||||||
auto Viewer = Connection->GetViewTarget();
|
if (ActorChannels.Pairs[i].First == ConsiderList[ConsiderIdx]->WeakActor)
|
||||||
auto Loc = Viewer->GetActorLocation();
|
|
||||||
|
|
||||||
if (!IsActorRelevantToConnection(Actor, ConnectionViewers))
|
|
||||||
{
|
{
|
||||||
if (Channel)
|
Channel = ActorChannels.Pairs[i].Second;
|
||||||
ActorChannelClose(Channel);
|
break;
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// and if the channel last update time doesn't match the last net update time for the actor
|
||||||
|
if (Channel != NULL && Channel->GetLastUpdateTime() < ConsiderList[ConsiderIdx]->LastNetUpdateTime)
|
||||||
|
{
|
||||||
|
ConsiderList[ConsiderIdx]->bPendingNetUpdate = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static UChannel* (*CreateChannel)(UNetConnection*, int, bool, int32_t) = decltype(CreateChannel)(Addresses::CreateChannel);
|
// Connection->TimeSensitive = false; // TODO Milxnor
|
||||||
static __int64 (*ReplicateActor)(UActorChannel*) = decltype(ReplicateActor)(Addresses::ReplicateActor);
|
}
|
||||||
static __int64 (*SetChannelActor)(UActorChannel*, AActor*) = decltype(SetChannelActor)(Addresses::SetChannelActor);
|
else if (Connection->GetViewTarget())
|
||||||
|
{
|
||||||
|
// Make a list of viewers this connection should consider (this connection and children of this connection)
|
||||||
|
// TArray<FNetViewer>& ConnectionViewers = WorldSettings->ReplicationViewers;
|
||||||
|
|
||||||
if (!Channel)
|
// ConnectionViewers.Reset();
|
||||||
|
std::vector<FNetViewer> ConnectionViewers;
|
||||||
|
// new(ConnectionViewers)FNetViewer(Connection, DeltaSeconds);
|
||||||
|
ConnectionViewers.push_back(ConstructNetViewer(Connection));
|
||||||
|
|
||||||
|
// send ClientAdjustment if necessary
|
||||||
|
// we do this here so that we send a maximum of one per packet to that client; there is no value in stacking additional corrections
|
||||||
|
if (Connection->GetPlayerController())
|
||||||
{
|
{
|
||||||
if (Actor->IsA(APlayerController::StaticClass()) && Actor != Connection->GetPlayerController()) // isnetrelevantfor should handle this iirc
|
static void (*SendClientAdjustment)(APlayerController*) = decltype(SendClientAdjustment)(Addresses::SendClientAdjustment);
|
||||||
continue;
|
SendClientAdjustment(Connection->GetPlayerController());
|
||||||
|
|
||||||
Channel = (UActorChannel*)CreateChannel(Connection, 2, true, -1);
|
|
||||||
|
|
||||||
if (Channel)
|
|
||||||
{
|
|
||||||
SetChannelActor(Channel, Actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USEOBJECTLIST
|
|
||||||
if (Actor->GetNetUpdateFrequency() < 1.0f)
|
|
||||||
{
|
|
||||||
ActorInfo->NextUpdateTime = UGameplayStatics::GetTimeSeconds(GetWorld()) + 0.2f * FRand();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Channel)
|
FActorPriority* PriorityList = NULL;
|
||||||
{
|
FActorPriority** PriorityActors = NULL;
|
||||||
if (ReplicateActor(Channel))
|
|
||||||
{
|
|
||||||
#ifdef USEOBJECTLIST
|
|
||||||
auto TimeSeconds = UGameplayStatics::GetTimeSeconds(World);
|
|
||||||
const float MinOptimalDelta = 1.0f / Actor->GetNetUpdateFrequency();
|
|
||||||
const float MaxOptimalDelta = max(1.0f / Actor->GetMinNetUpdateFrequency(), MinOptimalDelta);
|
|
||||||
const float DeltaBetweenReplications = (TimeSeconds - ActorInfo->LastNetReplicateTime);
|
|
||||||
|
|
||||||
// Choose an optimal time, we choose 70% of the actual rate to allow frequency to go up if needed
|
// LOG_INFO(LogDev, "ConsiderList.size(): {}", ConsiderList.size());
|
||||||
ActorInfo->OptimalNetUpdateDelta = std::clamp(DeltaBetweenReplications * 0.7f, MinOptimalDelta, MaxOptimalDelta); // should we use fmath?
|
|
||||||
ActorInfo->LastNetReplicateTime = TimeSeconds;
|
// Get a sorted list of actors for this connection
|
||||||
#endif
|
const int32 FinalSortedCount = ServerReplicateActors_PrioritizeActors(Connection, ConnectionViewers, ConsiderList, bCPUSaturated, PriorityList, PriorityActors);
|
||||||
|
|
||||||
|
// Process the sorted list of actors for this connection
|
||||||
|
const int32 LastProcessedActor = ServerReplicateActors_ProcessPrioritizedActors(Connection, ConnectionViewers, PriorityActors, FinalSortedCount, Updated);
|
||||||
|
|
||||||
|
// LOG_INFO(LogDev, "LastProcessedActor: {} FinalSortedCount: {} NetTag: {}", LastProcessedActor, FinalSortedCount, GetNetTag());
|
||||||
|
|
||||||
|
// relevant actors that could not be processed this frame are marked to be considered for next frame
|
||||||
|
for (int32 k = LastProcessedActor; k < FinalSortedCount; k++)
|
||||||
|
{
|
||||||
|
if (!PriorityActors[k]->ActorInfo)
|
||||||
|
{
|
||||||
|
// A deletion entry, skip it because we dont have anywhere to store a 'better give higher priority next time'
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AActor* Actor = PriorityActors[k]->ActorInfo->Actor;
|
||||||
|
|
||||||
|
UActorChannel* Channel = PriorityActors[k]->Channel;
|
||||||
|
|
||||||
|
if (Channel != NULL && GetTime() - Channel->GetRelevantTime() <= 1.f)
|
||||||
|
{
|
||||||
|
PriorityActors[k]->ActorInfo->bPendingNetUpdate = true;
|
||||||
|
}
|
||||||
|
else if (IsActorRelevantToConnection(Actor, ConnectionViewers))
|
||||||
|
{
|
||||||
|
PriorityActors[k]->ActorInfo->bPendingNetUpdate = true;
|
||||||
|
if (Channel != NULL)
|
||||||
|
{
|
||||||
|
Channel->GetRelevantTime() = GetTime() + 0.5f * SRand();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,15 +11,17 @@
|
|||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
#include "SharedPointer.h"
|
#include "SharedPointer.h"
|
||||||
#include "Level.h"
|
#include "Level.h"
|
||||||
|
#include "ActorChannel.h"
|
||||||
|
#include "NetworkGuid.h"
|
||||||
|
|
||||||
struct FActorDestructionInfo
|
struct FActorDestructionInfo
|
||||||
{
|
{
|
||||||
TWeakObjectPtr<ULevel> Level;
|
TWeakObjectPtr<ULevel> Level;
|
||||||
TWeakObjectPtr<UObject> ObjOuter;
|
TWeakObjectPtr<UObject> ObjOuter;
|
||||||
FVector DestroyedPosition;
|
FVector DestroyedPosition;
|
||||||
int32 NetGUID;
|
FNetworkGUID NetGUID;
|
||||||
FString PathName;
|
FString PathName;
|
||||||
FName StreamingLevelName;
|
FName StreamingLevelName;
|
||||||
};
|
};
|
||||||
struct FNetworkObjectInfo
|
struct FNetworkObjectInfo
|
||||||
{
|
{
|
||||||
@@ -50,14 +52,18 @@ struct FNetworkObjectInfo
|
|||||||
|
|
||||||
/** List of connections that this actor is dormant on */
|
/** List of connections that this actor is dormant on */
|
||||||
TSet<TWeakObjectPtr<UNetConnection>> DormantConnections;
|
TSet<TWeakObjectPtr<UNetConnection>> DormantConnections;
|
||||||
|
|
||||||
/** A list of connections that this actor has recently been dormant on, but the actor doesn't have a channel open yet.
|
|
||||||
* These need to be differentiated from actors that the client doesn't know about, but there's no explicit list for just those actors.
|
|
||||||
* (this list will be very transient, with connections being moved off the DormantConnections list, onto this list, and then off once the actor has a channel again)
|
|
||||||
*/
|
|
||||||
TSet<TWeakObjectPtr<UNetConnection>> RecentlyDormantConnections;
|
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:
|
||||||
@@ -72,6 +78,23 @@ public:
|
|||||||
void Remove(AActor* const Actor);
|
void Remove(AActor* const Actor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FActorPriority
|
||||||
|
{
|
||||||
|
int32 Priority; // Update priority, higher = more important.
|
||||||
|
|
||||||
|
FNetworkObjectInfo* ActorInfo; // Actor info.
|
||||||
|
UActorChannel* Channel; // Actor channel.
|
||||||
|
|
||||||
|
FActorDestructionInfo* DestructionInfo; // Destroy an actor
|
||||||
|
|
||||||
|
FActorPriority() :
|
||||||
|
Priority(0), ActorInfo(NULL), Channel(NULL), DestructionInfo(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
FActorPriority(UNetConnection* InConnection, UActorChannel* InChannel, FNetworkObjectInfo* InActorInfo, const std::vector<FNetViewer>& Viewers, bool bLowBandwidth);
|
||||||
|
FActorPriority(UNetConnection* InConnection, FActorDestructionInfo* DestructInfo, const std::vector<FNetViewer>& Viewers);
|
||||||
|
};
|
||||||
|
|
||||||
class UWorld;
|
class UWorld;
|
||||||
|
|
||||||
struct FURL // idk where this actually goes
|
struct FURL // idk where this actually goes
|
||||||
@@ -96,16 +119,49 @@ public:
|
|||||||
|
|
||||||
static void TickFlushHook(UNetDriver* NetDriver);
|
static void TickFlushHook(UNetDriver* NetDriver);
|
||||||
|
|
||||||
|
UObject*& GetWorldPackage() const
|
||||||
|
{
|
||||||
|
static auto WorldPackageOffset = GetOffset("WorldPackage");
|
||||||
|
return Get<UObject*>(WorldPackageOffset);
|
||||||
|
}
|
||||||
|
|
||||||
TArray<UNetConnection*>& GetClientConnections()
|
TArray<UNetConnection*>& GetClientConnections()
|
||||||
{
|
{
|
||||||
static auto ClientConnectionsOffset = GetOffset("ClientConnections");
|
static auto ClientConnectionsOffset = GetOffset("ClientConnections");
|
||||||
return Get<TArray<UNetConnection*>>(ClientConnectionsOffset);
|
return Get<TArray<UNetConnection*>>(ClientConnectionsOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float& GetTime()
|
||||||
|
{
|
||||||
|
static auto TimeOffset = GetOffset("Time");
|
||||||
|
return Get<float>(TimeOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
float& GetRelevantTimeout()
|
||||||
|
{
|
||||||
|
static auto RelevantTimeoutOffset = GetOffset("RelevantTimeout");
|
||||||
|
return Get<float>(RelevantTimeoutOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
float& GetSpawnPrioritySeconds()
|
||||||
|
{
|
||||||
|
static auto SpawnPrioritySecondsOffset = GetOffset("SpawnPrioritySeconds");
|
||||||
|
return Get<float>(SpawnPrioritySecondsOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32& GetNetTag()
|
||||||
|
{
|
||||||
|
static auto NetTagOffset = 0x1DC + 4;
|
||||||
|
return Get<int32>(NetTagOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLevelInitializedForActor(const AActor* InActor, const UNetConnection* InConnection) const;
|
||||||
void RemoveNetworkActor(AActor* Actor);
|
void RemoveNetworkActor(AActor* Actor);
|
||||||
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);
|
||||||
void ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList);
|
void ServerReplicateActors_BuildConsiderList(std::vector<FNetworkObjectInfo*>& OutConsiderList);
|
||||||
|
int32 ServerReplicateActors_PrioritizeActors(UNetConnection* Connection, const std::vector<FNetViewer>& ConnectionViewers, const std::vector<FNetworkObjectInfo*> ConsiderList, const bool bCPUSaturated, FActorPriority*& OutPriorityList, FActorPriority**& OutPriorityActors);
|
||||||
FNetworkObjectList& GetNetworkObjectList();
|
FNetworkObjectList& GetNetworkObjectList();
|
||||||
};
|
};
|
||||||
14
Project Reboot 3.0/NetworkGuid.h
Normal file
14
Project Reboot 3.0/NetworkGuid.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
class FNetworkGUID
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32 Value;
|
||||||
|
|
||||||
|
friend bool operator==(const FNetworkGUID& X, const FNetworkGUID& Y)
|
||||||
|
{
|
||||||
|
return (X.Value == Y.Value);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -18,6 +18,44 @@ FName* getFNameOfProp(void* Property)
|
|||||||
return NamePrivate;
|
return NamePrivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void* UObject::GetProperty(const std::string& ChildName, bool bWarnIfNotFound) const
|
||||||
|
{
|
||||||
|
for (auto CurrentClass = ClassPrivate; CurrentClass; CurrentClass = *(UClass**)(__int64(CurrentClass) + Offsets::SuperStruct))
|
||||||
|
{
|
||||||
|
void* Property = *(void**)(__int64(CurrentClass) + Offsets::Children);
|
||||||
|
|
||||||
|
if (Property)
|
||||||
|
{
|
||||||
|
// LOG_INFO(LogDev, "Reading prop name..");
|
||||||
|
|
||||||
|
std::string PropName = getFNameOfProp(Property)->ToString();
|
||||||
|
|
||||||
|
// LOG_INFO(LogDev, "PropName: {}", PropName);
|
||||||
|
|
||||||
|
if (PropName == ChildName)
|
||||||
|
{
|
||||||
|
return Property;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Property)
|
||||||
|
{
|
||||||
|
if (PropName == ChildName)
|
||||||
|
{
|
||||||
|
return Property;
|
||||||
|
}
|
||||||
|
|
||||||
|
Property = Engine_Version >= 425 ? *(void**)(__int64(Property) + 0x20) : ((UField*)Property)->Next;
|
||||||
|
PropName = Property ? getFNameOfProp(Property)->ToString() : "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bWarnIfNotFound)
|
||||||
|
LOG_WARN(LogFinder, "Unable to find0{}", ChildName);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void* UObject::GetProperty(const std::string& ChildName, bool bWarnIfNotFound)
|
void* UObject::GetProperty(const std::string& ChildName, bool bWarnIfNotFound)
|
||||||
{
|
{
|
||||||
for (auto CurrentClass = ClassPrivate; CurrentClass; CurrentClass = *(UClass**)(__int64(CurrentClass) + Offsets::SuperStruct))
|
for (auto CurrentClass = ClassPrivate; CurrentClass; CurrentClass = *(UClass**)(__int64(CurrentClass) + Offsets::SuperStruct))
|
||||||
@@ -66,6 +104,16 @@ int UObject::GetOffset(const std::string& ChildName, bool bWarnIfNotFound)
|
|||||||
return *(int*)(__int64(Property) + Offsets::Offset_Internal);
|
return *(int*)(__int64(Property) + Offsets::Offset_Internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int UObject::GetOffset(const std::string& ChildName, bool bWarnIfNotFound) const
|
||||||
|
{
|
||||||
|
auto Property = GetProperty(ChildName, bWarnIfNotFound);
|
||||||
|
|
||||||
|
if (!Property)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return *(int*)(__int64(Property) + Offsets::Offset_Internal);
|
||||||
|
}
|
||||||
|
|
||||||
bool UObject::ReadBitfieldValue(int Offset, uint8_t FieldMask)
|
bool UObject::ReadBitfieldValue(int Offset, uint8_t FieldMask)
|
||||||
{
|
{
|
||||||
return ReadBitfield(this->GetPtr<PlaceholderBitfield>(Offset), FieldMask);
|
return ReadBitfield(this->GetPtr<PlaceholderBitfield>(Offset), FieldMask);
|
||||||
|
|||||||
@@ -45,10 +45,12 @@ public:
|
|||||||
bool IsA(UClass* Other);
|
bool IsA(UClass* Other);
|
||||||
|
|
||||||
void* GetProperty(const std::string& ChildName, bool bWarnIfNotFound = true);
|
void* GetProperty(const std::string& ChildName, bool bWarnIfNotFound = true);
|
||||||
|
void* GetProperty(const std::string& ChildName, bool bWarnIfNotFound = true) const;
|
||||||
int GetOffset(const std::string& ChildName, bool bWarnIfNotFound = true);
|
int GetOffset(const std::string& ChildName, bool bWarnIfNotFound = true);
|
||||||
|
int GetOffset(const std::string& ChildName, bool bWarnIfNotFound = true) const;
|
||||||
|
|
||||||
template <typename T = UObject*>
|
template <typename T = UObject*>
|
||||||
T& Get(int Offset) { return *(T*)(__int64(this) + Offset); }
|
T& Get(int Offset) const { return *(T*)(__int64(this) + Offset); }
|
||||||
|
|
||||||
bool ReadBitfieldValue(int Offset, uint8_t FieldMask);
|
bool ReadBitfieldValue(int Offset, uint8_t FieldMask);
|
||||||
bool ReadBitfieldValue(const std::string& ChildName, uint8_t FieldMask) { return ReadBitfieldValue(GetOffset(ChildName), FieldMask); }
|
bool ReadBitfieldValue(const std::string& ChildName, uint8_t FieldMask) { return ReadBitfieldValue(GetOffset(ChildName), FieldMask); }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
class UPlayer : public UObject
|
class UPlayer : public UObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
APlayerController*& GetPlayerController()
|
APlayerController*& GetPlayerController() const
|
||||||
{
|
{
|
||||||
static auto PlayerControllerOffset = GetOffset("PlayerController");
|
static auto PlayerControllerOffset = GetOffset("PlayerController");
|
||||||
return Get<APlayerController*>(PlayerControllerOffset);
|
return Get<APlayerController*>(PlayerControllerOffset);
|
||||||
|
|||||||
@@ -228,6 +228,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="AbilitySystemComponent.h" />
|
<ClInclude Include="AbilitySystemComponent.h" />
|
||||||
<ClInclude Include="Actor.h" />
|
<ClInclude Include="Actor.h" />
|
||||||
|
<ClInclude Include="ActorChannel.h" />
|
||||||
<ClInclude Include="ActorComponent.h" />
|
<ClInclude Include="ActorComponent.h" />
|
||||||
<ClInclude Include="addresses.h" />
|
<ClInclude Include="addresses.h" />
|
||||||
<ClInclude Include="ai.h" />
|
<ClInclude Include="ai.h" />
|
||||||
@@ -242,6 +243,7 @@
|
|||||||
<ClInclude Include="BuildingSMActor.h" />
|
<ClInclude Include="BuildingSMActor.h" />
|
||||||
<ClInclude Include="BuildingTrap.h" />
|
<ClInclude Include="BuildingTrap.h" />
|
||||||
<ClInclude Include="calendar.h" />
|
<ClInclude Include="calendar.h" />
|
||||||
|
<ClInclude Include="Channel.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" />
|
||||||
@@ -293,6 +295,8 @@
|
|||||||
<ClInclude Include="GameplayTagContainer.h" />
|
<ClInclude Include="GameplayTagContainer.h" />
|
||||||
<ClInclude Include="GameSession.h" />
|
<ClInclude Include="GameSession.h" />
|
||||||
<ClInclude Include="GameState.h" />
|
<ClInclude Include="GameState.h" />
|
||||||
|
<ClInclude Include="GenericPlatformMath.h" />
|
||||||
|
<ClInclude Include="GenericPlatformTime.h" />
|
||||||
<ClInclude Include="globals.h" />
|
<ClInclude Include="globals.h" />
|
||||||
<ClInclude Include="hooking.h" />
|
<ClInclude Include="hooking.h" />
|
||||||
<ClInclude Include="inc.h" />
|
<ClInclude Include="inc.h" />
|
||||||
@@ -307,6 +311,7 @@
|
|||||||
<ClInclude Include="NameTypes.h" />
|
<ClInclude Include="NameTypes.h" />
|
||||||
<ClInclude Include="NetDriver.h" />
|
<ClInclude Include="NetDriver.h" />
|
||||||
<ClInclude Include="NetSerialization.h" />
|
<ClInclude Include="NetSerialization.h" />
|
||||||
|
<ClInclude Include="NetworkGuid.h" />
|
||||||
<ClInclude Include="Object.h" />
|
<ClInclude Include="Object.h" />
|
||||||
<ClInclude Include="ObjectMacros.h" />
|
<ClInclude Include="ObjectMacros.h" />
|
||||||
<ClInclude Include="OnlineReplStructs.h" />
|
<ClInclude Include="OnlineReplStructs.h" />
|
||||||
@@ -317,6 +322,7 @@
|
|||||||
<ClInclude Include="PlayerController.h" />
|
<ClInclude Include="PlayerController.h" />
|
||||||
<ClInclude Include="PlayerState.h" />
|
<ClInclude Include="PlayerState.h" />
|
||||||
<ClInclude Include="Quat.h" />
|
<ClInclude Include="Quat.h" />
|
||||||
|
<ClInclude Include="RandomStream.h" />
|
||||||
<ClInclude Include="reboot.h" />
|
<ClInclude Include="reboot.h" />
|
||||||
<ClInclude Include="Rotator.h" />
|
<ClInclude Include="Rotator.h" />
|
||||||
<ClInclude Include="ScriptInterface.h" />
|
<ClInclude Include="ScriptInterface.h" />
|
||||||
@@ -329,6 +335,7 @@
|
|||||||
<ClInclude Include="StringAssetReference.h" />
|
<ClInclude Include="StringAssetReference.h" />
|
||||||
<ClInclude Include="Transform.h" />
|
<ClInclude Include="Transform.h" />
|
||||||
<ClInclude Include="Tuple.h" />
|
<ClInclude Include="Tuple.h" />
|
||||||
|
<ClInclude Include="UnrealMathUtility.h" />
|
||||||
<ClInclude Include="UnrealString.h" />
|
<ClInclude Include="UnrealString.h" />
|
||||||
<ClInclude Include="UObjectArray.h" />
|
<ClInclude Include="UObjectArray.h" />
|
||||||
<ClInclude Include="UObjectGlobals.h" />
|
<ClInclude Include="UObjectGlobals.h" />
|
||||||
|
|||||||
@@ -506,6 +506,27 @@
|
|||||||
<ClInclude Include="FortPlayerPawnAthena.h">
|
<ClInclude Include="FortPlayerPawnAthena.h">
|
||||||
<Filter>FortniteGame\Source\FortniteGame\Public\Pawns</Filter>
|
<Filter>FortniteGame\Source\FortniteGame\Public\Pawns</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="GenericPlatformMath.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Core\Public\GenericPlatform</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="ActorChannel.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Engine\Classes\Engine</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Channel.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Engine\Classes\Engine</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="NetworkGuid.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Core\Public\Misc</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="UnrealMathUtility.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Core\Public\Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="GenericPlatformTime.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Core\Public\GenericPlatform</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="RandomStream.h">
|
||||||
|
<Filter>Engine\Source\Runtime\Core\Public\Math</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Filter Include="Engine">
|
<Filter Include="Engine">
|
||||||
@@ -691,6 +712,9 @@
|
|||||||
<Filter Include="Engine\Source\Runtime\Core\Public\Templates">
|
<Filter Include="Engine\Source\Runtime\Core\Public\Templates">
|
||||||
<UniqueIdentifier>{31a7f342-8b7c-4594-a24d-c4dd5c9d230d}</UniqueIdentifier>
|
<UniqueIdentifier>{31a7f342-8b7c-4594-a24d-c4dd5c9d230d}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Engine\Source\Runtime\Core\Public\GenericPlatform">
|
||||||
|
<UniqueIdentifier>{653d6dbf-b361-41ea-a9b8-b85737412d66}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="UnrealEngine.cpp">
|
<None Include="UnrealEngine.cpp">
|
||||||
|
|||||||
76
Project Reboot 3.0/RandomStream.h
Normal file
76
Project Reboot 3.0/RandomStream.h
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "inc.h"
|
||||||
|
|
||||||
|
struct FRandomStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*
|
||||||
|
* The seed should be set prior to use.
|
||||||
|
*/
|
||||||
|
FRandomStream()
|
||||||
|
: InitialSeed(0)
|
||||||
|
, Seed(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and initializes a new random stream from the specified seed value.
|
||||||
|
*
|
||||||
|
* @param InSeed The seed value.
|
||||||
|
*/
|
||||||
|
FRandomStream(int32 InSeed)
|
||||||
|
{
|
||||||
|
Initialize(InSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes this random stream with the specified seed value.
|
||||||
|
*
|
||||||
|
* @param InSeed The seed value.
|
||||||
|
*/
|
||||||
|
void Initialize(int32 InSeed)
|
||||||
|
{
|
||||||
|
InitialSeed = InSeed;
|
||||||
|
Seed = uint32(InSeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GetFraction() const
|
||||||
|
{
|
||||||
|
MutateSeed();
|
||||||
|
|
||||||
|
float Result;
|
||||||
|
|
||||||
|
*(uint32*)&Result = 0x3F800000U | (Seed >> 9);
|
||||||
|
|
||||||
|
return Result - 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE float FRand() const
|
||||||
|
{
|
||||||
|
return GetFraction();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mutates the current seed into the next seed.
|
||||||
|
*/
|
||||||
|
void MutateSeed() const
|
||||||
|
{
|
||||||
|
Seed = (Seed * 196314165U) + 907633515U;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// Holds the initial seed.
|
||||||
|
int32 InitialSeed;
|
||||||
|
|
||||||
|
// Holds the current seed. This should be an uint32 so that any shift to obtain top bits
|
||||||
|
// is a logical shift, rather than an arithmetic shift (which smears down the negative bit).
|
||||||
|
mutable uint32 Seed;
|
||||||
|
};
|
||||||
@@ -166,12 +166,12 @@ public:
|
|||||||
int32 PreviousFreeIndex = -1;
|
int32 PreviousFreeIndex = -1;
|
||||||
int32 NextFreeIndex = -1;
|
int32 NextFreeIndex = -1;
|
||||||
|
|
||||||
if (NumFreeIndices == 0)
|
/* if (NumFreeIndices == 0)
|
||||||
{
|
{
|
||||||
FirstFreeIndex = IndexToRemove;
|
FirstFreeIndex = IndexToRemove;
|
||||||
Data.at(IndexToRemove) = { -1, -1 };
|
Data.at(IndexToRemove) = { -1, -1 };
|
||||||
}
|
}
|
||||||
else
|
else */
|
||||||
{
|
{
|
||||||
for (auto It = AllocationFlags.begin(); It != AllocationFlags.end(); ++It)
|
for (auto It = AllocationFlags.begin(); It != AllocationFlags.end(); ++It)
|
||||||
{
|
{
|
||||||
@@ -189,6 +189,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocationFlags.Set(IndexToRemove, false);
|
AllocationFlags.Set(IndexToRemove, false);
|
||||||
NumFreeIndices++;
|
NumFreeIndices++;
|
||||||
|
|
||||||
|
|||||||
12
Project Reboot 3.0/UnrealMathUtility.h
Normal file
12
Project Reboot 3.0/UnrealMathUtility.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "GenericPlatformMath.h"
|
||||||
|
|
||||||
|
struct FMath : public FPlatformMath
|
||||||
|
{
|
||||||
|
template< class T >
|
||||||
|
static FORCEINLINE T Clamp(const T X, const T Min, const T Max)
|
||||||
|
{
|
||||||
|
return X < Min ? Min : X < Max ? X : Max;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -17,6 +17,16 @@ public:
|
|||||||
return FVector{ this->X - A.X, this->Y - A.Y, this->Z - A.Z };
|
return FVector{ this->X - A.X, this->Y - A.Y, this->Z - A.Z };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCEINLINE float SizeSquared() const
|
||||||
|
{
|
||||||
|
return X * X + Y * Y + Z * Z;
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE float operator|(const FVector& V) const
|
||||||
|
{
|
||||||
|
return X * V.X + Y * V.Y + Z * V.Z;
|
||||||
|
}
|
||||||
|
|
||||||
FVector operator*(const float A)
|
FVector operator*(const float A)
|
||||||
{
|
{
|
||||||
return FVector{ this->X * A, this->Y * A, this->Z * A };
|
return FVector{ this->X * A, this->Y * A, this->Z * A };
|
||||||
|
|||||||
@@ -12,4 +12,9 @@ public:
|
|||||||
{
|
{
|
||||||
return ChunkedObjects ? ChunkedObjects->GetObjectByIndex(ObjectIndex) : UnchunkedObjects ? UnchunkedObjects->GetObjectByIndex(ObjectIndex) : nullptr;
|
return ChunkedObjects ? ChunkedObjects->GetObjectByIndex(ObjectIndex) : UnchunkedObjects ? UnchunkedObjects->GetObjectByIndex(ObjectIndex) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const FWeakObjectPtr& other)
|
||||||
|
{
|
||||||
|
return ObjectIndex == other.ObjectIndex && ObjectSerialNumber == other.ObjectSerialNumber; // i need to check in ue if we check serialnumber
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -13,4 +13,9 @@ struct TWeakObjectPtr : public TWeakObjectPtrBase
|
|||||||
{
|
{
|
||||||
return (T*)TWeakObjectPtrBase::Get();
|
return (T*)TWeakObjectPtrBase::Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const TWeakObjectPtr& other)
|
||||||
|
{
|
||||||
|
return TWeakObjectPtrBase::operator==(other);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
#include "FortPlayerPawn.h"
|
#include "FortPlayerPawn.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
#include "FortInventoryInterface.h"
|
#include "FortInventoryInterface.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include "GenericPlatformTime.h"
|
||||||
|
|
||||||
#include "Map.h"
|
#include "Map.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
@@ -150,6 +152,9 @@ DWORD WINAPI Main(LPVOID)
|
|||||||
Hooking::MinHook::Hook((PVOID)Addresses::GetNetMode, (PVOID)GetNetModeHook, nullptr);
|
Hooking::MinHook::Hook((PVOID)Addresses::GetNetMode, (PVOID)GetNetModeHook, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GSRandSeed = FGenericPlatformTime::Cycles();
|
||||||
|
ReplicationRandStream = FRandomStream(FGenericPlatformTime::Cycles());
|
||||||
|
|
||||||
Hooking::MinHook::Hook((PVOID)Addresses::KickPlayer, (PVOID)AGameSession::KickPlayerHook, (PVOID*)&AGameSession::KickPlayerOriginal);
|
Hooking::MinHook::Hook((PVOID)Addresses::KickPlayer, (PVOID)AGameSession::KickPlayerHook, (PVOID*)&AGameSession::KickPlayerOriginal);
|
||||||
|
|
||||||
LOG_INFO(LogDev, "Size: 0x{:x}", sizeof(TMap<FName, void*>));
|
LOG_INFO(LogDev, "Size: 0x{:x}", sizeof(TMap<FName, void*>));
|
||||||
@@ -723,6 +728,16 @@ DWORD WINAPI Main(LPVOID)
|
|||||||
LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!");
|
LOG_ERROR(LogGame, "Restarting is not supported on chapter 2 and above!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (GetAsyncKeyState(VK_F11) & 1)
|
||||||
|
{
|
||||||
|
std::ofstream stream("Test.log");
|
||||||
|
|
||||||
|
for (auto& Current : ReplicatedActors)
|
||||||
|
{
|
||||||
|
stream << Current << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Sleep(1000 / 30);
|
Sleep(1000 / 30);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,18 @@ extern inline int Engine_Version = 0; // For example, 420, 421, etc. // Prevent
|
|||||||
extern inline double Fortnite_Version = 0; // For example, 4.1, 6.21, etc. // Prevent using this when possible.
|
extern inline double Fortnite_Version = 0; // For example, 4.1, 6.21, etc. // Prevent using this when possible.
|
||||||
extern inline int Fortnite_CL = 0;
|
extern inline int Fortnite_CL = 0;
|
||||||
|
|
||||||
|
struct PlaceholderBitfield
|
||||||
|
{
|
||||||
|
uint8_t First : 1;
|
||||||
|
uint8_t Second : 1;
|
||||||
|
uint8_t Third : 1;
|
||||||
|
uint8_t Fourth : 1;
|
||||||
|
uint8_t Fifth : 1;
|
||||||
|
uint8_t Sixth : 1;
|
||||||
|
uint8_t Seventh : 1;
|
||||||
|
uint8_t Eighth : 1;
|
||||||
|
};
|
||||||
|
|
||||||
#define MS_ALIGN(n) __declspec(align(n))
|
#define MS_ALIGN(n) __declspec(align(n))
|
||||||
#define FORCENOINLINE __declspec(noinline)
|
#define FORCENOINLINE __declspec(noinline)
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
// #include "World.h"
|
// #include "World.h"
|
||||||
|
|
||||||
|
#include "RandomStream.h"
|
||||||
#include "Class.h"
|
#include "Class.h"
|
||||||
#include "globals.h"
|
#include "globals.h"
|
||||||
|
#include <set>
|
||||||
|
|
||||||
/* enum class REBOOT_ERROR : uint8
|
/* enum class REBOOT_ERROR : uint8
|
||||||
{
|
{
|
||||||
@@ -130,18 +132,9 @@ static __forceinline T* Cast(UObject* Object, bool bCheckType = true)
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern inline int AmountOfRestarts = 0; // DO NOT CHANGE
|
extern inline int AmountOfRestarts = 0; // DO NOT CHANGE
|
||||||
|
extern inline FRandomStream ReplicationRandStream = (0);
|
||||||
struct PlaceholderBitfield
|
extern inline int32 GSRandSeed = 0;
|
||||||
{
|
extern inline std::set<std::string> ReplicatedActors = {};
|
||||||
uint8_t First : 1;
|
|
||||||
uint8_t Second : 1;
|
|
||||||
uint8_t Third : 1;
|
|
||||||
uint8_t Fourth : 1;
|
|
||||||
uint8_t Fifth : 1;
|
|
||||||
uint8_t Sixth : 1;
|
|
||||||
uint8_t Seventh : 1;
|
|
||||||
uint8_t Eighth : 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline uint8_t GetFieldMask(void* Property, int additional = 0)
|
inline uint8_t GetFieldMask(void* Property, int additional = 0)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user