// Copyright (c) 2026 Unreal Directive. Licensed under the MIT License. #pragma once #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "Net/Core/PushModel/PushModel.h" #include "DirectiveUtilArrayFunctionLibrary.generated.h" /** * UDirectiveUtilArrayFunctionLibrary * A collection of array utility functions that improve the usability of arrays in Blueprints. */ UCLASS() class DIRECTIVEUTILITIESRUNTIME_API UDirectiveUtilArrayFunctionLibrary : public UBlueprintFunctionLibrary { GENERATED_BODY() public: /** * Returns the next index in the array. * If the next index is greater than the last array index and bLoop is enabled, the index will loop back to the start of the array. * Otherwise, the last index will be returned. * Returns INDEX_NONE for an empty array. * @param TargetArray - The array to get the next index for. * @param Index - The current index. * @param bLoop - If true, the index will loop back to the beginning of the array when the next index is greater than the last array index. * Otherwise, the last index will be returned. * @returns The next index in the array. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Next Index", CompactNodeTitle = "NEXT INDEX", ArrayParm = "TargetArray", BlueprintThreadSafe), Category="Directive Utilities|Array") static int32 Array_NextIndex(const TArray& TargetArray, const int32 Index, const bool bLoop); /** * Returns the previous index in the array. * If the previous index is less than 0 and bLoop is enabled, the index will loop back to the end of the array. * Otherwise, 0 will be returned. * Returns INDEX_NONE for an empty array. * @param TargetArray - The array to get the previous index for. * @param Index - The current index. * @param bLoop - If the next index is greater than the last array index and bLoop is enabled, the index will loop back to the start of the array. * Otherwise, the last index will be returned. * @returns The previous index in the array. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Previous Index", CompactNodeTitle = "PREV INDEX", ArrayParm = "TargetArray", BlueprintThreadSafe), Category="Directive Utilities|Array") static int32 Array_PreviousIndex(const TArray& TargetArray, const int32 Index, const bool bLoop); /** * Removes duplicate elements from the array in-place. * @param TargetArray - The array to remove duplicates from. */ UFUNCTION(BlueprintCallable, CustomThunk, meta=(DisplayName = "Remove Duplicates", CompactNodeTitle = "REMOVE DUPLICATES", ArrayParm = "TargetArray"), Category="Directive Utilities|Array") static void Array_RemoveDuplicates(const TArray& TargetArray); /** * Returns a copy of the first element of the array. * @param TargetArray - The array to read from. * @param OutItem - [out] A copy of the first element, or the default value if the array is empty. * @returns True if the array contained a valid first element. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Get Valid First Array Item (Copy)", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem", BlueprintThreadSafe), Category="Directive Utilities|Array") static bool Array_GetValidFirstItemCopy(const TArray& TargetArray, int32& OutItem); /** * Returns a copy of the last element of the array. * @param TargetArray - The array to read from. * @param OutItem - [out] A copy of the last element, or the default value if the array is empty. * @returns True if the array contained a valid last element. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Get Valid Last Array Item (Copy)", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem", BlueprintThreadSafe), Category="Directive Utilities|Array") static bool Array_GetValidLastItemCopy(const TArray& TargetArray, int32& OutItem); /** * Returns a copy of the element at the given index, if the index is valid. * @param TargetArray - The array to read from. * @param Index - The index to read. * @param OutItem - [out] A copy of the element, or the default value if the index is invalid. * @returns True if the index was valid. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Get Valid Array Item From Index (Copy)", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem", BlueprintThreadSafe), Category="Directive Utilities|Array") static bool Array_GetValidItemFromIndexCopy(const TArray& TargetArray, const int32 Index, int32& OutItem); /** * Returns a copy of a random element from the array. * @param TargetArray - The array to read from. * @param OutItem - [out] A copy of the randomly selected element, or the default value if the array is empty. * @param OutIndex - [out] The index of the selected element, or INDEX_NONE if the array is empty. * @returns True if a valid element was selected. */ UFUNCTION(BlueprintCallable, CustomThunk, meta=(DisplayName = "Get Random Valid Array Item", CompactNodeTitle = "RANDOM", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem"), Category="Directive Utilities|Array") static bool Array_GetRandomItem(const TArray& TargetArray, int32& OutItem, int32& OutIndex); /** * Returns a copy of the last element of the array without removing it. * @param TargetArray - The array to read from. * @param OutItem - [out] A copy of the last element, or the default value if the array is empty. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Last Value", CompactNodeTitle = "LAST", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem", BlueprintThreadSafe), Category="Directive Utilities|Array") static void Array_LastValue(const TArray& TargetArray, int32& OutItem); /** * Removes the last element of the array and returns a copy of it. * @param TargetArray - The array to pop from. * @param OutItem - [out] A copy of the removed element, or the default value if the array is empty. * @returns True if an element was removed. */ UFUNCTION(BlueprintCallable, CustomThunk, meta=(DisplayName = "Pop", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem"), Category="Directive Utilities|Array") static bool Array_Pop(const TArray& TargetArray, int32& OutItem); /** * Removes the first element of the array and returns a copy of it. * @param TargetArray - The array to pop from. * @param OutItem - [out] A copy of the removed element, or the default value if the array is empty. * @returns True if an element was removed. */ UFUNCTION(BlueprintCallable, CustomThunk, meta=(DisplayName = "Pop First", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem"), Category="Directive Utilities|Array") static bool Array_PopFirst(const TArray& TargetArray, int32& OutItem); /** * Removes the element at the given index by swapping it with the last element (does not preserve order). * This is O(1) but changes the position of the previously-last element. * @param TargetArray - The array to remove from. * @param Index - The index to remove. * @returns True if the index was valid and an element was removed. */ UFUNCTION(BlueprintCallable, CustomThunk, meta=(DisplayName = "Remove At Swap", ArrayParm = "TargetArray"), Category="Directive Utilities|Array") static bool Array_RemoveAtSwap(const TArray& TargetArray, const int32 Index); /** * Returns a copy of a contiguous range of the array. The range is clamped to the array bounds. * @param TargetArray - The array to slice. * @param StartIndex - The index to start copying from (clamped to [0, Length]). * @param Count - The number of elements to copy. Values <= 0 produce an empty array. * @param OutArray - [out] The sliced copy. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Slice", ArrayParm = "TargetArray,OutArray", ArrayTypeDependentParams = "OutArray", BlueprintThreadSafe), Category="Directive Utilities|Array") static void Array_Slice(const TArray& TargetArray, const int32 StartIndex, const int32 Count, TArray& OutArray); /** * Cyclically rotates the elements of the array in place. * @param TargetArray - The array to rotate. * @param Shift - The number of positions to rotate. Positive rotates toward the end; negative toward the start. */ UFUNCTION(BlueprintCallable, CustomThunk, meta=(DisplayName = "Rotate", ArrayParm = "TargetArray"), Category="Directive Utilities|Array") static void Array_Rotate(const TArray& TargetArray, const int32 Shift); /** * Returns a copy of the array with duplicates removed, keeping the first occurrence and preserving order. * Unlike Remove Duplicates, this does not modify the input array. * @param TargetArray - The array to read from. * @param OutArray - [out] The de-duplicated copy. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Get Distinct (Copy)", ArrayParm = "TargetArray,OutArray", ArrayTypeDependentParams = "OutArray", BlueprintThreadSafe), Category="Directive Utilities|Array") static void Array_GetDistinct(const TArray& TargetArray, TArray& OutArray); /** * Counts how many times an item appears in the array. * @param TargetArray - The array to search. * @param ItemToCount - The item to count. * @returns The number of occurrences. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Count Occurrences", ArrayParm = "TargetArray", ArrayTypeDependentParams = "ItemToCount", AutoCreateRefTerm = "ItemToCount", BlueprintThreadSafe), Category="Directive Utilities|Array") static int32 Array_CountOccurrences(const TArray& TargetArray, const int32& ItemToCount); /** * Returns the most frequently occurring element of the array (ties resolve to the earliest such element). * @param TargetArray - The array to read from. * @param OutItem - [out] A copy of the most common element, or the default value if the array is empty. * @param OutCount - [out] The number of times the most common element occurs. * @returns True if the array was non-empty. */ UFUNCTION(BlueprintPure, CustomThunk, meta=(DisplayName = "Get Most Common", ArrayParm = "TargetArray", ArrayTypeDependentParams = "OutItem", BlueprintThreadSafe), Category="Directive Utilities|Array") static bool Array_GetMostCommon(const TArray& TargetArray, int32& OutItem, int32& OutCount); /*~ * Native functions that will be called by the below custom thunk layers, which read off the property address and call the appropriate native handler. * Based off UKismetArrayLibrary implementation ~*/ static int32 GenericArray_NextIndex(const void* TargetArray, const FArrayProperty* ArrayProperty, int32 Index, bool bLoop); static int32 GenericArray_PreviousIndex(const void* TargetArray, const FArrayProperty* ArrayProperty, int32 Index, bool bLoop); static void GenericArray_RemoveDuplicates(void* TargetArray, const FArrayProperty* ArrayProperty); static bool GenericArray_GetItemAtIndex(const void* TargetArray, const FArrayProperty* ArrayProperty, int32 Index, void* OutItemPtr); static bool GenericArray_GetFirstItem(const void* TargetArray, const FArrayProperty* ArrayProperty, void* OutItemPtr); static bool GenericArray_GetLastItem(const void* TargetArray, const FArrayProperty* ArrayProperty, void* OutItemPtr); static bool GenericArray_GetRandomItem(const void* TargetArray, const FArrayProperty* ArrayProperty, void* OutItemPtr, int32* OutIndex); static bool GenericArray_Pop(void* TargetArray, const FArrayProperty* ArrayProperty, void* OutItemPtr); static bool GenericArray_PopFirst(void* TargetArray, const FArrayProperty* ArrayProperty, void* OutItemPtr); static bool GenericArray_RemoveAtSwap(void* TargetArray, const FArrayProperty* ArrayProperty, int32 Index); static void GenericArray_Slice(const void* TargetArray, const FArrayProperty* TargetArrayProperty, int32 StartIndex, int32 Count, void* OutArray, const FArrayProperty* OutArrayProperty); static void GenericArray_Rotate(void* TargetArray, const FArrayProperty* ArrayProperty, int32 Shift); static void GenericArray_GetDistinct(const void* TargetArray, const FArrayProperty* TargetArrayProperty, void* OutArray, const FArrayProperty* OutArrayProperty); static int32 GenericArray_CountOccurrences(const void* TargetArray, const FArrayProperty* ArrayProperty, const void* ItemToCount); static bool GenericArray_GetMostCommon(const void* TargetArray, const FArrayProperty* ArrayProperty, void* OutItemPtr, int32* OutCount); /*~ * Custom thunk layers that read off the property address and call the appropriate native handler. * Based off UKismetArrayLibrary implementation ~*/ DECLARE_FUNCTION(execArray_NextIndex) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } P_GET_PROPERTY(FIntProperty, Index); P_GET_UBOOL(bLoop); P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_NextIndex(ArrayAddr, ArrayProperty, Index, bLoop); P_NATIVE_END; } DECLARE_FUNCTION(execArray_PreviousIndex) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } P_GET_PROPERTY(FIntProperty, Index); P_GET_UBOOL(bLoop); P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_PreviousIndex(ArrayAddr, ArrayProperty, Index, bLoop); P_NATIVE_END; } DECLARE_FUNCTION(execArray_RemoveDuplicates) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* ArrayAddr = Stack.MostRecentPropertyAddress; FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } P_FINISH; P_NATIVE_BEGIN; MARK_PROPERTY_DIRTY(Stack.Object, ArrayProperty); GenericArray_RemoveDuplicates(ArrayAddr, ArrayProperty); P_NATIVE_END; } DECLARE_FUNCTION(execArray_GetValidFirstItemCopy) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_GetFirstItem(ArrayAddr, ArrayProperty, ItemPtr); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_GetValidLastItemCopy) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_GetLastItem(ArrayAddr, ArrayProperty, ItemPtr); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_GetValidItemFromIndexCopy) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } P_GET_PROPERTY(FIntProperty, Index); const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_GetItemAtIndex(ArrayAddr, ArrayProperty, Index, ItemPtr); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_GetRandomItem) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } Stack.MostRecentProperty = nullptr; Stack.MostRecentPropertyAddress = nullptr; Stack.StepCompiledIn(nullptr); int32* OutIndex = reinterpret_cast(Stack.MostRecentPropertyAddress); P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_GetRandomItem(ArrayAddr, ArrayProperty, ItemPtr, OutIndex); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_LastValue) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } P_FINISH; P_NATIVE_BEGIN; GenericArray_GetLastItem(ArrayAddr, ArrayProperty, ItemPtr); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_Pop) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* ArrayAddr = Stack.MostRecentPropertyAddress; FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } P_FINISH; P_NATIVE_BEGIN; MARK_PROPERTY_DIRTY(Stack.Object, ArrayProperty); *static_cast(RESULT_PARAM) = GenericArray_Pop(ArrayAddr, ArrayProperty, ItemPtr); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_PopFirst) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* ArrayAddr = Stack.MostRecentPropertyAddress; FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } P_FINISH; P_NATIVE_BEGIN; MARK_PROPERTY_DIRTY(Stack.Object, ArrayProperty); *static_cast(RESULT_PARAM) = GenericArray_PopFirst(ArrayAddr, ArrayProperty, ItemPtr); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_RemoveAtSwap) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* ArrayAddr = Stack.MostRecentPropertyAddress; FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } P_GET_PROPERTY(FIntProperty, Index); P_FINISH; P_NATIVE_BEGIN; MARK_PROPERTY_DIRTY(Stack.Object, ArrayProperty); *static_cast(RESULT_PARAM) = GenericArray_RemoveAtSwap(ArrayAddr, ArrayProperty, Index); P_NATIVE_END; } DECLARE_FUNCTION(execArray_Slice) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* SourceArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* SourceArrayProperty = CastField(Stack.MostRecentProperty); if (!SourceArrayProperty) { Stack.bArrayContextFailed = true; return; } P_GET_PROPERTY(FIntProperty, StartIndex); P_GET_PROPERTY(FIntProperty, Count); Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* OutArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* OutArrayProperty = CastField(Stack.MostRecentProperty); if (!OutArrayProperty) { Stack.bArrayContextFailed = true; return; } P_FINISH; P_NATIVE_BEGIN; GenericArray_Slice(SourceArrayAddr, SourceArrayProperty, StartIndex, Count, OutArrayAddr, OutArrayProperty); P_NATIVE_END; } DECLARE_FUNCTION(execArray_Rotate) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* ArrayAddr = Stack.MostRecentPropertyAddress; FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } P_GET_PROPERTY(FIntProperty, Shift); P_FINISH; P_NATIVE_BEGIN; MARK_PROPERTY_DIRTY(Stack.Object, ArrayProperty); GenericArray_Rotate(ArrayAddr, ArrayProperty, Shift); P_NATIVE_END; } DECLARE_FUNCTION(execArray_GetDistinct) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* SourceArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* SourceArrayProperty = CastField(Stack.MostRecentProperty); if (!SourceArrayProperty) { Stack.bArrayContextFailed = true; return; } Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); void* OutArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* OutArrayProperty = CastField(Stack.MostRecentProperty); if (!OutArrayProperty) { Stack.bArrayContextFailed = true; return; } P_FINISH; P_NATIVE_BEGIN; GenericArray_GetDistinct(SourceArrayAddr, SourceArrayProperty, OutArrayAddr, OutArrayProperty); P_NATIVE_END; } DECLARE_FUNCTION(execArray_CountOccurrences) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_CountOccurrences(ArrayAddr, ArrayProperty, StorageSpace); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } DECLARE_FUNCTION(execArray_GetMostCommon) { Stack.MostRecentProperty = nullptr; Stack.StepCompiledIn(nullptr); const void* ArrayAddr = Stack.MostRecentPropertyAddress; const FArrayProperty* ArrayProperty = CastField(Stack.MostRecentProperty); if (!ArrayProperty) { Stack.bArrayContextFailed = true; return; } const FProperty* InnerProp = ArrayProperty->Inner; const int32 PropertySize = InnerProp->GetElementSize() * InnerProp->ArrayDim; void* StorageSpace = FMemory_Alloca(PropertySize); InnerProp->InitializeValue(StorageSpace); Stack.MostRecentPropertyAddress = nullptr; Stack.MostRecentPropertyContainer = nullptr; Stack.StepCompiledIn(StorageSpace); void* ItemPtr; if (Stack.MostRecentPropertyAddress != nullptr && Stack.MostRecentProperty != nullptr && PropertySize == Stack.MostRecentProperty->GetElementSize() * Stack.MostRecentProperty->ArrayDim && (Stack.MostRecentProperty->GetClass()->IsChildOf(InnerProp->GetClass()) || InnerProp->GetClass()->IsChildOf(Stack.MostRecentProperty->GetClass()))) { ItemPtr = Stack.MostRecentPropertyAddress; } else { ItemPtr = StorageSpace; } Stack.MostRecentProperty = nullptr; Stack.MostRecentPropertyAddress = nullptr; Stack.StepCompiledIn(nullptr); int32* OutCount = reinterpret_cast(Stack.MostRecentPropertyAddress); P_FINISH; P_NATIVE_BEGIN; *static_cast(RESULT_PARAM) = GenericArray_GetMostCommon(ArrayAddr, ArrayProperty, ItemPtr, OutCount); P_NATIVE_END; InnerProp->DestroyValue(StorageSpace); } };