Hi,
I have massive TArrays of data of everything that happened in my game chronologically. Naturally, my arrays are much larger than 256 in size.
Now, I need to compare two large integers from within a widget blueprint.
But, there is no uint64, uint32, uint16(or int variations of any of those) that can be accessed through blueprint. int8(256 values) is not nearly enough.
What can I use to compare large integer types in blueprint? Is there a way to make a custom data type that is usable in C++? Should I make a struct of 8 int8s and do the math myself?
1 Like
Integers in Blueprint are signed 32-bit integers (which gives you +/- 2147483647), not 8-bit integers. If you need larger numbers than that you will have to use 64-bit integers in C++ or use a bignum/bigint library like GMP https://gmplib.org/
If you are doing heavy data processing, especially with large arrays, you should not use Blueprint, as it will be slow and will cause many reallocations.
If you are iterating large arrays in Blueprints you may run into trouble for various reasons, one of which is that Blueprint has a simple infinite loop protection scheme which prevents loop nodes from iterating too many times.
Ah, thank you, I was reading another answer on answerhub about why uint64’s don’t work as UPROPERTY’s, and some answer said I could only use int8s.
As for your advice, don’t worry, I have no idea why I said I was using TArrays, that is not the case. Blueprint has zero access to the arrays. Did not know about the iteration limit though, interesting.
We use the Steam 64 bit ID in our blueprints. It is always passed in an out as a string interger representation.
Not overly efficient but it works.
CSteamID USteamBridge::SteamIDStringToCSteamID(FString s)
{
uint64 i64 = 0;
int convCount = sscanf_s( TCHAR_TO_ANSI(*s), "%llu", &i64 );
if (convCount == 0)
{
UE_LOG(DSS_STEAM, Log, TEXT("SteamIDStringToCSteamID - invalid input string %s"), *s);
return CSteamID((uint64)0);
}
return CSteamID(i64);
}
FString USteamBridge::CSteamIDToString(CSteamID i)
{
sprintf_s( steamidbuf, sizeof(steamidbuf), "%llu", i.ConvertToUint64() );
return FString(steamidbuf);
}
Here is another solution I just did for our game. Your question got me thinking and this is way better.
It is an Object class called UInt64Bits that keeps track of 64 bits unsigned.
It is implemented for blueprint use and such. The internal implementation is two int32 (signed int 32 bits).
It has Make to make a new instance, and comparison operators.
It knows how to convert ot and from decimal and hexadecimal strings.
No Math such as add or subtract.
It is great for Steam’s CSteamID getting exposed out to blueprints and also for SteamInventory item instance IDs.
.h
#pragma once
#include "Object.h"
#include "Int64Bits.generated.h"
/**
*
*/
UCLASS(BlueprintType)
class UNFORTUNATESPACEMEN_API UInt64Bits : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
static UInt64Bits * Make(int32 upper = 0, int32 lower = 0);
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = DSSHelpers)
int32 Lower32;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = DSSHelpers)
int32 Upper32;
// Pretty ugly. Here there be dragons.
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
void SetFromTwoInts(int32 upper, int32 lower);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool IsEqual64(UInt64Bits * other);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool IsLessThan64(UInt64Bits * other);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool IsLessThanOrEqualTo64(UInt64Bits * other);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool IsGreaterThan64(UInt64Bits * other);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool IsGreaterThanOrEqualTo64(UInt64Bits * other);
// Sets the 64 bits from a string of decimal digits. (optional leading - sign)
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool FromString(FString stringDecimalIn);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
bool FromHexString(FString stringHexadecimalIn);
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
FString ToDecimalString();
UFUNCTION(BlueprintCallable, Category = DSSHelpers)
FString ToHexString();
uint64 ToUInt64();
void FromUInt64(uint64 i);
};
.cpp (Probably needs to also include “MyGame.h” to get all teh Unreal Engine includes.)
#include "Int64Bits.h"
char Int64Buf[512];
uint64 UInt64Bits::ToUInt64()
{
return (0x0FFFFFFFF & (uint64)Lower32) | (0xFFFFFFFF00000000 & (((uint64)Upper32) << 32));
}
void UInt64Bits::FromUInt64(uint64 ui64)
{
Lower32 = (int32)(0x00000000FFFFFFFF & ui64);
Upper32 = (int32)(0x00000000FFFFFFFF & (ui64 >> 32));
}
void UInt64Bits::SetFromTwoInts(int32 upper, int32 lower)
{
Upper32 = upper;
Lower32 = lower;
}
UInt64Bits * UInt64Bits::Make(int32 upper, int32 lower)
{
UInt64Bits * i = ConstructObject<UInt64Bits>(UInt64Bits::StaticClass());
i->Upper32 = upper;
i->Lower32 = lower;
return i;
}
bool UInt64Bits::IsEqual64(UInt64Bits * other)
{
return (uint32)Upper32 == (uint32)other->Upper32 && (uint32)Lower32 == (uint32)other->Lower32;
}
bool UInt64Bits::IsLessThan64(UInt64Bits * other)
{
return (uint32)Upper32 < (uint32)other->Upper32 || ((uint32)Upper32 == (uint32)other->Upper32 && (uint32)Lower32 < (uint32)other->Lower32);
}
bool UInt64Bits::IsLessThanOrEqualTo64(UInt64Bits * other)
{
return (uint32)Upper32 < (uint32)other->Upper32 || ((uint32)Upper32 == (uint32)other->Upper32 && (uint32)Lower32 <= (uint32)other->Lower32);
}
bool UInt64Bits::IsGreaterThan64(UInt64Bits * other)
{
return (uint32)Upper32 > (uint32)other->Upper32 || ((uint32)Upper32 == (uint32)other->Upper32 && (uint32)Lower32 >(uint32)other->Lower32);
}
bool UInt64Bits::IsGreaterThanOrEqualTo64(UInt64Bits * other)
{
return (uint32)Upper32 > (uint32)other->Upper32 || ((uint32)Upper32 == (uint32)other->Upper32 && (uint32)Lower32 >= (uint32)other->Lower32);
}
bool UInt64Bits::FromString(FString stringDecimalIn)
{
if (stringDecimalIn.IsEmpty())
{
return false;
}
uint64 ui64 = 0;
int convCount = sscanf_s(TCHAR_TO_ANSI(*stringDecimalIn), "%llu", &ui64);
if (convCount == 0)
{
return false;
}
FromUInt64(ui64);
return true;
}
FString UInt64Bits::ToDecimalString()
{
uint64 ui64 = ToUInt64();
sprintf_s(Int64Buf, sizeof(Int64Buf), "%llu", ui64);
return FString(Int64Buf);
}
bool UInt64Bits::FromHexString(FString stringHexadecimalIn)
{
if (stringHexadecimalIn.IsEmpty())
{
return false;
}
uint64 ui64 = 0;
int convCount = sscanf_s(TCHAR_TO_ANSI(*stringHexadecimalIn), "%llx", &ui64);
if (convCount == 0)
{
return false;
}
FromUInt64(ui64);
return true;
}
FString UInt64Bits::ToHexString()
{
uint64 ui64 = ToUInt64();
sprintf_s(Int64Buf, sizeof(Int64Buf), "%llX", ui64);
return FString(Int64Buf);
}