From d6ef444272e031ae38376787f6057ba0fd6e2c01 Mon Sep 17 00:00:00 2001 From: Gray <84999745+Milxnor@users.noreply.github.com> Date: Thu, 21 Mar 2024 21:44:13 -0400 Subject: [PATCH] Thank you logic teacher (rep is almost done) --- Project Reboot 3.0/BitArray.h | 108 +++++++++++++ Project Reboot 3.0/CoreNet.h | 17 ++ Project Reboot 3.0/IsTriviallyDestructible.h | 9 ++ Project Reboot 3.0/NameTypes.h | 2 +- Project Reboot 3.0/NetConnection.h | 4 +- Project Reboot 3.0/NetDriver.cpp | 72 +++++++-- Project Reboot 3.0/Project Reboot 3.0.vcxproj | 2 + .../Project Reboot 3.0.vcxproj.filters | 6 + Project Reboot 3.0/Set.h | 148 ++++++++++++++---- Project Reboot 3.0/SparseArray.h | 37 +++++ 10 files changed, 359 insertions(+), 46 deletions(-) create mode 100644 Project Reboot 3.0/CoreNet.h create mode 100644 Project Reboot 3.0/IsTriviallyDestructible.h diff --git a/Project Reboot 3.0/BitArray.h b/Project Reboot 3.0/BitArray.h index dc51d3d..16717c0 100644 --- a/Project Reboot 3.0/BitArray.h +++ b/Project Reboot 3.0/BitArray.h @@ -12,6 +12,97 @@ class TBitArray; template class TConstSetBitIterator; +class FBitReference +{ +public: + + FORCEINLINE FBitReference(uint32& InData, uint32 InMask) + : Data(InData) + , Mask(InMask) + {} + + FORCEINLINE operator bool() const + { + return (Data & Mask) != 0; + } + FORCEINLINE void operator=(const bool NewValue) + { + if (NewValue) + { + Data |= Mask; + } + else + { + Data &= ~Mask; + } + } + /* + FORCEINLINE void AtomicSet(const bool NewValue) + { + if (NewValue) + { + if (!(Data & Mask)) + { + while (1) + { + uint32 Current = Data; + uint32 Desired = Current | Mask; + if (Current == Desired || FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&Data, (int32)Desired, (int32)Current) == (int32)Current) + { + return; + } + } + } + } + else + { + if (Data & Mask) + { + while (1) + { + uint32 Current = Data; + uint32 Desired = Current & ~Mask; + if (Current == Desired || FPlatformAtomics::InterlockedCompareExchange((volatile int32*)&Data, (int32)Desired, (int32)Current) == (int32)Current) + { + return; + } + } + } + } + } + */ + FORCEINLINE FBitReference& operator=(const FBitReference& Copy) + { + // As this is emulating a reference, assignment should not rebind, + // it should write to the referenced bit. + *this = (bool)Copy; + return *this; + } + +private: + uint32& Data; + uint32 Mask; +}; + +class FConstBitReference +{ +public: + + FORCEINLINE FConstBitReference(const uint32& InData, uint32 InMask) + : Data(InData) + , Mask(InMask) + {} + + FORCEINLINE operator bool() const + { + return (Data & Mask) != 0; + } + +private: + const uint32& Data; + uint32 Mask; +}; + template class TBitArray { @@ -36,6 +127,23 @@ public: *this = Copy; } + FORCEINLINE FBitReference operator[](int32 Index) + { + // check(Index >= 0 && Index < NumBits); + return FBitReference( + GetData()[Index / NumBitsPerDWORD], + 1 << (Index & (NumBitsPerDWORD - 1)) + ); + } + FORCEINLINE const FConstBitReference operator[](int32 Index) const + { + // check(Index >= 0 && Index < NumBits); + return FConstBitReference( + GetData()[Index / NumBitsPerDWORD], + 1 << (Index & (NumBitsPerDWORD - 1)) + ); + } + FORCEINLINE const uint32* GetData() const { return (uint32*)AllocatorInstance.GetAllocation(); diff --git a/Project Reboot 3.0/CoreNet.h b/Project Reboot 3.0/CoreNet.h new file mode 100644 index 0000000..0614f6a --- /dev/null +++ b/Project Reboot 3.0/CoreNet.h @@ -0,0 +1,17 @@ +#pragma once + +#include "inc.h" + +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) const + { + return (First <= PacketId && PacketId <= Last); + } +}; \ No newline at end of file diff --git a/Project Reboot 3.0/IsTriviallyDestructible.h b/Project Reboot 3.0/IsTriviallyDestructible.h new file mode 100644 index 0000000..9103c83 --- /dev/null +++ b/Project Reboot 3.0/IsTriviallyDestructible.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +template +struct TIsTriviallyDestructible +{ + enum { Value = std::is_trivially_destructible_v }; +}; \ No newline at end of file diff --git a/Project Reboot 3.0/NameTypes.h b/Project Reboot 3.0/NameTypes.h index ce24c12..97de9d0 100644 --- a/Project Reboot 3.0/NameTypes.h +++ b/Project Reboot 3.0/NameTypes.h @@ -83,4 +83,4 @@ inline uint32 GetTypeHash(const FName N) return N.ComparisonIndex.Value + N.GetNumber(); } -#define NAME_None FName(0); \ No newline at end of file +#define NAME_None FName(0) \ No newline at end of file diff --git a/Project Reboot 3.0/NetConnection.h b/Project Reboot 3.0/NetConnection.h index 339e523..c03bed3 100644 --- a/Project Reboot 3.0/NetConnection.h +++ b/Project Reboot 3.0/NetConnection.h @@ -79,11 +79,11 @@ public: return Get(LastReceiveTimeOffset); } - /* TSet& GetClientVisibleLevelNames() + TSet& GetClientVisibleLevelNames() { static auto ClientVisibleLevelNamesOffset = 0x336C8; return *(TSet*)(__int64(this) + ClientVisibleLevelNamesOffset); - } */ + } class UNetDriver*& GetDriver() { diff --git a/Project Reboot 3.0/NetDriver.cpp b/Project Reboot 3.0/NetDriver.cpp index a9b2903..2b6259e 100644 --- a/Project Reboot 3.0/NetDriver.cpp +++ b/Project Reboot 3.0/NetDriver.cpp @@ -9,6 +9,7 @@ #include #include "Package.h" #include "AssertionMacros.h" +#include "CoreNet.h" #include "ChildConnection.h" #include "bots.h" #include "NetworkingDistanceConstants.h" @@ -131,13 +132,6 @@ bool UNetDriver::IsLevelInitializedForActor(const AActor* InActor, const UNetCon return true; } - /* #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) // (Milxnor) This is on some ue versions and others not. - if (!InActor || !InConnection) - return false; - - // check(World == InActor->GetWorld()); - #endif */ - bool bFirstWorldCheck = Engine_Version == 416 ? (InConnection->GetClientWorldPackageName() == GetWorld()->GetOutermost()->GetFName()) : (InConnection->GetClientWorldPackageName() == GetWorldPackage()->NamePrivate); @@ -155,7 +149,7 @@ FNetViewer::FNetViewer(UNetConnection* InConnection, float DeltaSeconds) : ViewDir(ForceInit) { if (!InConnection->GetOwningActor()) return; - if (InConnection->GetPlayerController() || (InConnection->GetPlayerController() != InConnection->GetOwningActor())) return; + if (InConnection->GetPlayerController() && (InConnection->GetPlayerController() != InConnection->GetOwningActor())) return; APlayerController* ViewingController = InConnection->GetPlayerController(); @@ -163,7 +157,7 @@ FNetViewer::FNetViewer(UNetConnection* InConnection, float DeltaSeconds) : if (ViewingController) { FRotator ViewRotation = ViewingController->GetControlRotation(); - ViewingController->GetActorEyesViewPoint(&ViewLocation, &ViewRotation); // T(REP) + ViewingController->GetActorEyesViewPoint(&ViewLocation, &ViewRotation); ViewDir = ViewRotation.Vector(); } } @@ -542,6 +536,58 @@ int32 UNetDriver::ServerReplicateActors_PrioritizeActors(UNetConnection* Connect return FinalSortedCount; } +using FArchive = void; + +__declspec(noinline) void SetChannelActorForDestroy(UActorChannel* Channel, FActorDestructionInfo* DestructInfo) +{ + auto Connection = Channel->GetConnection(); + + // check(Connection->Channels[ChIndex]==Channel); + + if ( + true + // T(REP) + ) + { + + // You can get size by searching "Making partial bunch from content bunch. bitsThisBunch: %d bitsLeft: %d", there is a new call. + struct FOutBunch + { + char pad[0x110]; + }; + + LOG_INFO(LogDev, "SetChannelActorForDestroy PathName: {}", DestructInfo->PathName.ToString()); + + FOutBunch(*ConstructorFOutBunch)(FOutBunch*, UChannel*, bool) = decltype(ConstructorFOutBunch)(__int64(GetModuleHandleW(0)) + 0x194E800); + FOutBunch CloseBunch{}; + auto Helloooo = ConstructorFOutBunch(&CloseBunch, Channel, 1); + // check(!CloseBunch.IsError()); + // check(CloseBunch.bClose); + + LOG_INFO(LogDev, "Called Constructor!"); + + // https://imgur.com/a/EtKFkrD + + *(bool*)(__int64(&CloseBunch) + 0xE8) = 1; // bReliable + *(bool*)(__int64(&CloseBunch) + 0xE6) = 0; // bDormant + + // NET_CHECKSUM(CloseBunch); // This is to mirror the Checksum in UPackageMapClient::SerializeNewActor + + using UPackageMap = UObject; + + reinterpret_cast(Connection->GetPackageMap()->VFTable[0x238 / 8]) + (Connection->GetPackageMap(), CloseBunch, DestructInfo->ObjOuter.Get(), DestructInfo->NetGUID, DestructInfo->PathName); // WriteObject + + // 0x196E9C0 + reinterpret_cast(Channel->VFTable[0x288 / 8])(Channel, &CloseBunch, false); // SendBunch + + // TODO FARCHIVE::~FARHCIVE + } +} + int32 UNetDriver::ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* Connection, const std::vector& ConnectionViewers, std::vector& PriorityActors, const int32 FinalSortedCount, int32& OutUpdated) { int32 ActorUpdatesThisConnection = 0; @@ -557,12 +603,11 @@ int32 UNetDriver::ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* { FNetworkObjectInfo* ActorInfo = PriorityActors[j]->ActorInfo; - // Deletion entry if (ActorInfo == NULL && PriorityActors[j]->DestructionInfo) { /* - if (PriorityActors[j]->DestructionInfo->StreamingLevelName != NAME_None && - !Connection->GetClientVisibleLevelNames().Contains(PriorityActors[j]->DestructionInfo->StreamingLevelName) + if (PriorityActors[j]->DestructionInfo->StreamingLevelName != NAME_None + && !Connection->GetClientVisibleLevelNames().Contains(PriorityActors[j]->DestructionInfo->StreamingLevelName) ) { continue; @@ -573,7 +618,7 @@ int32 UNetDriver::ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* { FinalRelevantCount++; - Channel->SetChannelActorForDestroy(PriorityActors[j]->DestructionInfo); + SetChannelActorForDestroy(Channel, PriorityActors[j]->DestructionInfo); Connection->GetDestroyedStartupOrDormantActors().Remove(PriorityActors[j]->DestructionInfo->NetGUID); } @@ -621,6 +666,7 @@ int32 UNetDriver::ServerReplicateActors_ProcessPrioritizedActors(UNetConnection* Channel = (UActorChannel*)Connection->CreateChannel(CHTYPE_Actor, 1, EChannelCreateFlags::OpenedLocally); if (Channel) { + LOG_INFO(LogDev, "Replicating: {}", Actor->GetFullName()); Channel->SetChannelActor(Actor, ESetChannelActorFlags::None1); } } diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj b/Project Reboot 3.0/Project Reboot 3.0.vcxproj index c63bb84..9c646e2 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj @@ -315,6 +315,7 @@ + @@ -431,6 +432,7 @@ + diff --git a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters index 7ab69b4..938b27a 100644 --- a/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters +++ b/Project Reboot 3.0/Project Reboot 3.0.vcxproj.filters @@ -999,6 +999,12 @@ Engine\Source\Runtime\Engine\Public + + Engine\Source\Runtime\CoreUObject\Public\UObject + + + Engine\Source\Runtime\Core\Public\Templates + diff --git a/Project Reboot 3.0/Set.h b/Project Reboot 3.0/Set.h index 4616693..5d12c28 100644 --- a/Project Reboot 3.0/Set.h +++ b/Project Reboot 3.0/Set.h @@ -5,38 +5,9 @@ #include "SparseArray.h" #include "ChooseClass.h" #include "UnrealTypeTraits.h" +#include "UnrealTemplate.h" -template -class TSetElement -{ -public: - ElementType Value; - mutable int32 HashNextId; - mutable int32 HashIndex; - TSetElement(ElementType InValue, int32 InHashNextId, int32 InHashIndex) - : Value(InValue) - , HashNextId(InHashNextId) - , HashIndex(InHashIndex) - { - } - - FORCEINLINE TSetElement& operator=(const TSetElement& Other) - { - Value = Other.Value; - } - - FORCEINLINE bool operator==(const TSetElement& Other) const - { - return Value == Other.Value; - } - FORCEINLINE bool operator!=(const TSetElement& Other) const - { - return Value != Other.Value; - } -}; - -/** Either NULL or an identifier for an element of a set. */ class FSetElementId { public: @@ -90,6 +61,45 @@ private: } }; +template +class TSetElement +{ +public: + typedef InElementType ElementType; + + ElementType Value; + mutable FSetElementId HashNextId; + mutable int32 HashIndex; + + FORCEINLINE TSetElement() + {} + + /** Initialization constructor. */ + // template ::Type>::Value>::Type> explicit FORCEINLINE TSetElement(InitType&& InValue) : Value/////(Forward(InValue)) {} // T(R) + + FORCEINLINE TSetElement(const TSetElement& Rhs) : Value(Rhs.Value), HashNextId(Rhs.HashNextId), HashIndex(Rhs.HashIndex) {} + FORCEINLINE TSetElement(TSetElement&& Rhs) : Value(MoveTempIfPossible(Rhs.Value)), HashNextId(MoveTemp(Rhs.HashNextId)), HashIndex(Rhs.HashIndex) {} + + FORCEINLINE TSetElement& operator=(const TSetElement& Rhs) { Value = Rhs.Value; HashNextId = Rhs.HashNextId; HashIndex = Rhs.HashIndex; return *this; } + FORCEINLINE TSetElement& operator=(TSetElement&& Rhs) { Value = MoveTempIfPossible(Rhs.Value); HashNextId = MoveTemp(Rhs.HashNextId); HashIndex = Rhs.HashIndex; return *this; } + + /* + FORCEINLINE friend FArchive & operator<<(FArchive & Ar, TSetElement & Element) + { + return Ar << Element.Value; + } + */ + + FORCEINLINE bool operator==(const TSetElement& Other) const + { + return Value == Other.Value; + } + FORCEINLINE bool operator!=(const TSetElement& Other) const + { + return Value != Other.Value; + } +}; + template struct BaseKeyFuncs { @@ -152,6 +162,9 @@ private: public: typedef typename KeyFuncs::KeyInitType KeyInitType; typedef typename KeyFuncs::ElementInitType ElementInitType; + // using SizeType = typename Allocator::SparseArrayAllocator::ElementAllocator::SizeType; // Milxnor: Bruh idk + using SizeType = int32; + static_assert(std::is_same_v, "TSet currently only supports 32-bit allocators"); typedef TSetElement SetElementType; @@ -170,7 +183,82 @@ public: return ((FSetElementId*)Hash.GetAllocation())[HashIndex & (HashSize - 1)]; } +private: + template + FORCEINLINE int32 RemoveImpl(uint32 KeyHash, const ComparableKey& Key) + { + int32 NumRemovedElements = 0; + + FSetElementId* NextElementId = &GetTypedHash(KeyHash); + while (NextElementId->IsValidId()) + { + SetElementType& Element = Elements[NextElementId->Index]; + + if (KeyFuncs::Matches(KeyFuncs::GetSetKey(Element.Value), Key)) + { + // This element matches the key, remove it from the set. Note that Remove sets *NextElementId to point to the next + // element after the removed element in the hash bucket. + RemoveByIndex(NextElementId->Index); + NumRemovedElements++; + + if (!KeyFuncs::bAllowDuplicateKeys) + { + // If the hash disallows duplicate keys, we're done removing after the first matched key. + break; + } + } + else + { + NextElementId = &Element.HashNextId; + } + } + + return NumRemovedElements; + } + public: + void RemoveByIndex(SizeType ElementIndex) + { + // checkf(Elements.IsValidIndex(ElementIndex), TEXT("Invalid ElementIndex passed to TSet::RemoveByIndex")); + + const SetElementType& ElementBeingRemoved = Elements[ElementIndex]; + + // Remove the element from the hash. + FSetElementId* HashPtr = Hash.GetAllocation(); + SizeType* NextElementIndexIter = &HashPtr[ElementBeingRemoved.HashIndex].Index; + for (;;) + { + SizeType NextElementIndex = *NextElementIndexIter; + // checkf(NextElementIndex != INDEX_NONE, TEXT("Corrupt hash")); + + if (NextElementIndex == ElementIndex) + { + *NextElementIndexIter = ElementBeingRemoved.HashNextId.Index; + break; + } + + NextElementIndexIter = &Elements[NextElementIndex].HashNextId.Index; + } + + // Remove the element from the elements array. + Elements.RemoveAt(ElementIndex); + } + + void Remove(FSetElementId ElementId) + { + RemoveByIndex(ElementId.Index); + } + + int32 Remove(KeyInitType Key) + { + if (Elements.Num()) + { + return RemoveImpl(KeyFuncs::GetKeyHash(Key), Key); + } + + return 0; + } + FORCEINLINE ElementType* Find(KeyInitType Key) { FSetElementId ElementId = FindId(Key); diff --git a/Project Reboot 3.0/SparseArray.h b/Project Reboot 3.0/SparseArray.h index c3ead16..0d3d8bb 100644 --- a/Project Reboot 3.0/SparseArray.h +++ b/Project Reboot 3.0/SparseArray.h @@ -5,6 +5,7 @@ #include "ChooseClass.h" #include "log.h" #include "TypeCompatibleBytes.h" +#include "IsTriviallyDestructible.h" #define INDEX_NONE -1 @@ -53,6 +54,42 @@ public: { return Data.Num() - NumFreeIndices; } + void RemoveAt(int32 Index, int32 Count = 1) + { + if (!TIsTriviallyDestructible::Value) + { + 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[Index] = false; + + ++Index; + } + } + template class TBaseIterator {