You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Parameters must be registered with the UOL module in much the same way as fragment types. Tidied up globals into a singleton Registry class. Added a function to FUniversalObjectLocator that allows manual addition of fragments. Also removed the defunct IActorLocatorFragmentResolver interface in favor of supplying these parameters externally. Corrected Anim Instance locators being always used when trying to address skeletal mesh components. #rb david.bromberg [CL 29890178 by andrew rodham in ue5-main branch]
187 lines
6.1 KiB
C++
187 lines
6.1 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "UniversalObjectLocatorResolveParams.h"
|
|
|
|
namespace UE::UniversalObjectLocator
|
|
{
|
|
|
|
|
|
template<typename T, typename ...ArgTypes>
|
|
T* FResolveParameterBuffer::AddParameter(TParameterTypeHandle<T> ParameterTypeHandle, ArgTypes&&... InArgs)
|
|
{
|
|
const UScriptStruct* ParameterStruct = ParameterTypeHandle.Resolve();
|
|
if (!ensureMsgf(ParameterStruct, TEXT("Parameter struct is no longer registered!")))
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
const uint8 ParameterIndex = ParameterTypeHandle.GetIndex();
|
|
|
|
const uint32 ParameterBit = 1 << ParameterIndex;
|
|
return static_cast<T*>(AddParameterImpl<T>(ParameterBit, Forward<ArgTypes>(InArgs)...));
|
|
}
|
|
|
|
|
|
template<typename ParameterType, typename ...ArgTypes>
|
|
ParameterType* FResolveParameterBuffer::AddParameterImpl(uint32 ParameterBit, ArgTypes&&... InArgs)
|
|
{
|
|
checkf((AllParameters & ParameterBit) == 0, TEXT("Parameter already exists!"));
|
|
|
|
// Add the enum entry
|
|
AllParameters |= ParameterBit;
|
|
|
|
// Find the index of the new Parameter by counting how many bits are set before it
|
|
// For example, given ParameterBit=0b00010000 and AllParameters=0b00011011:
|
|
// (ParameterBit-1) = 0b00001111
|
|
// AllParameters & (ParameterBit-1) = 0b00001011
|
|
// CountBits(0b00001011) = 3
|
|
const int32 NewParameterIndex = static_cast<int32>(FMath::CountBits(AllParameters & (ParameterBit-1u)));
|
|
|
|
FResolveParameterHeader* ExistingHeaders = reinterpret_cast<FResolveParameterHeader*>(Memory);
|
|
|
|
uint64 RequiredAlignment = FMath::Max(alignof(ParameterType), alignof(FResolveParameterHeader));
|
|
|
|
const int32 ExistingNum = static_cast<int32>(Num);
|
|
|
|
// Compute our required alignment for the allocation
|
|
{
|
|
for (int32 Index = 0; Index < ExistingNum; ++Index)
|
|
{
|
|
RequiredAlignment = FMath::Max(RequiredAlignment, (uint64)ExistingHeaders[Index].Alignment);
|
|
}
|
|
}
|
|
|
|
uint64 RequiredSizeof = 0u;
|
|
|
|
// Compute the required size of our allocation
|
|
{
|
|
// Allocate space for headers
|
|
RequiredSizeof += (ExistingNum+1) * sizeof(FResolveParameterHeader);
|
|
|
|
int32 Index = 0;
|
|
|
|
// Count up the sizes and alignments of pre-existing parameters that exist before this new entry
|
|
for (; Index < NewParameterIndex; ++Index)
|
|
{
|
|
RequiredSizeof = Align(RequiredSizeof, (uint64)ExistingHeaders[Index].Alignment);
|
|
RequiredSizeof += ExistingHeaders[Index].Sizeof;
|
|
}
|
|
|
|
// Count up the size and alignment for the new parameter
|
|
RequiredSizeof = Align(RequiredSizeof, alignof(ParameterType));
|
|
RequiredSizeof += sizeof(ParameterType);
|
|
++Index;
|
|
|
|
// Now count up the sizes and alignments of pre-existing parameters that exist after this new entry
|
|
for (; Index < ExistingNum+1; ++Index)
|
|
{
|
|
RequiredSizeof = Align(RequiredSizeof, (uint64)ExistingHeaders[Index-1].Alignment);
|
|
RequiredSizeof += ExistingHeaders[Index-1].Sizeof;
|
|
}
|
|
}
|
|
|
|
check( RequiredAlignment <= 0XFF );
|
|
|
|
/// ----------------------------------------
|
|
|
|
uint8* OldAllocation = Memory;
|
|
|
|
const bool bShouldFreeMemory = bCanFreeMemory;
|
|
|
|
// Make a new allocation if necessary
|
|
const bool bNeedsReallocation = !IsAligned(Memory, RequiredAlignment) || RequiredSizeof > Capacity;
|
|
if (bNeedsReallocation)
|
|
{
|
|
const uint64 RequiredCapacity = FMath::Max(RequiredSizeof, uint64(Capacity)*2);
|
|
check(RequiredCapacity <= std::numeric_limits<uint16>::max());
|
|
|
|
// Use the greater of the required size or double the current size to allow some additional capcity
|
|
Capacity = static_cast<uint16>(FMath::Max(RequiredSizeof, uint64(Capacity)*2));
|
|
Memory = reinterpret_cast<uint8*>(FMemory::Malloc(Capacity, RequiredAlignment));
|
|
|
|
bCanFreeMemory = true;
|
|
}
|
|
|
|
// We now have an extra entry
|
|
++Num;
|
|
|
|
uint8* ParameterPtr = Memory + RequiredSizeof;
|
|
|
|
auto RelocateParameter = [this, ExistingHeaders, OldAllocation, &ParameterPtr](int32 OldIndex)
|
|
{
|
|
// Go back
|
|
ParameterPtr -= ExistingHeaders[OldIndex].Sizeof;
|
|
ParameterPtr = AlignDown(ParameterPtr, ExistingHeaders[OldIndex].Alignment);
|
|
|
|
void* OldParameter = ExistingHeaders[OldIndex].Resolve(OldAllocation);
|
|
FMemory::Memmove(ParameterPtr, OldParameter, ExistingHeaders[OldIndex].Sizeof);
|
|
|
|
// Overwrite the old header with its new position for error checking when we write the new header
|
|
ExistingHeaders[OldIndex].ParameterOffset = static_cast<uint16>(ParameterPtr-Memory);
|
|
};
|
|
|
|
// Relocate old structs that proceed the new index
|
|
for (int32 Index = static_cast<int32>(Num) - 1; Index > NewParameterIndex; --Index)
|
|
{
|
|
RelocateParameter(Index-1);
|
|
}
|
|
|
|
// Make the new entry
|
|
{
|
|
ParameterPtr -= sizeof(ParameterType);
|
|
ParameterPtr = AlignDown(ParameterPtr, alignof(ParameterType));
|
|
|
|
ParameterType* NewParameterPtr = reinterpret_cast<ParameterType*>(ParameterPtr);
|
|
|
|
// Allocate the new type
|
|
new (NewParameterPtr) ParameterType { Forward<ArgTypes>(InArgs)... };
|
|
|
|
static_assert(alignof(ParameterType) < 0x7F, "Required alignment of parameter must fit in 7 bytes");
|
|
}
|
|
|
|
FResolveParameterHeader NewHeader = {
|
|
static_cast<uint16>(ParameterPtr-Memory),
|
|
sizeof(ParameterType),
|
|
alignof(ParameterType)
|
|
};
|
|
|
|
// Relocate the entries that are before the new one
|
|
for (int32 Index = NewParameterIndex-1; Index >= 0; --Index)
|
|
{
|
|
RelocateParameter(Index);
|
|
}
|
|
|
|
// Check that we have enough space before for the headers (this should always be the case)
|
|
check(ParameterPtr >= Memory + sizeof(FResolveParameterHeader)*Num);
|
|
|
|
FResolveParameterHeader* NewHeaders = reinterpret_cast<FResolveParameterHeader*>(Memory);
|
|
|
|
for (int32 Index = static_cast<int32>(Num)-1; Index > NewParameterIndex; --Index)
|
|
{
|
|
new (&NewHeaders[Index]) FResolveParameterHeader(ExistingHeaders[Index-1]);
|
|
};
|
|
|
|
{
|
|
new (&NewHeaders[NewParameterIndex]) FResolveParameterHeader(NewHeader);
|
|
}
|
|
|
|
if (Memory != OldAllocation)
|
|
{
|
|
for (int32 Index = NewParameterIndex-1; Index >= 0; --Index)
|
|
{
|
|
new (&NewHeaders[Index]) FResolveParameterHeader(ExistingHeaders[Index]);
|
|
};
|
|
}
|
|
|
|
// Tidy up the old allocation. We do not call destructors here because we relocated everything.
|
|
if (bNeedsReallocation && OldAllocation && bShouldFreeMemory)
|
|
{
|
|
FMemory::Free(OldAllocation);
|
|
}
|
|
|
|
return static_cast<ParameterType*>(NewHeaders[NewParameterIndex].Resolve(Memory));
|
|
}
|
|
|
|
} // namespace UE::UniversalObjectLocator
|