godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.17k stars 98 forks source link

Add support for 64-bit unsigned integers (for Steam ID support) #9740

Open hislittlecuzin opened 6 months ago

hislittlecuzin commented 6 months ago

Describe the project you are working on

I am making a game that uses Steamworks and uses Steam IDs for identifying players. Clients don't have "connection ids" for all the players. So clients are telling the server who they're talking to by Steam ID. The server knows the "connection IDs" and can relay the messages based on the Steam ID to the correct client. With Steam Matchmaking (now sometimes called Steam Lobbies) you can access the Steam ID of other players which is a "ulong" in C#.

Describe the problem or limitation you are having in your project

Right now I am limited to 9,223,372,036,854,775,807 instead of the real maximum value of 18,446,744,073,709,551,615 because the 64 bit integer is signed in GD Script. C# can use unsigned long or ulong to get that larger number.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The new unsigned integer will allow larger unsigned numbers for when Steam games have players with a steam ID higher than 50% of the maximum steam account value, there will be no issues.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

I don't know how to create a new variable in GD Script. I suppose uint would be acceptable.

If this enhancement will not be used often, can it be worked around with a few lines of script?

Right now I'm hoping that rolling over into negative values won't cause an issue. But if I need to access a steam account by exact ID, it will likely provide a failed result.

Is there a reason why this should be core and not an add-on in the asset library?

Unsigned 64 bit whole numbers have become standard in many languages.

dalexeev commented 6 months ago

I guess this is not necessary since int64 and uint64 have the same size and differ only in how the data is treated. You can use String.num_uint64() to display an int as if it were uint.

hislittlecuzin commented 6 months ago

I guess this is not necessary since int64 and uint64 have the same size and differ only in how the data is treated. You can use String.num_uint64() to display an int as if it were uint.

No. With netcode, it'll be slow to continually parse data types especially when converting to strings. Data should stay binary.

dalexeev commented 6 months ago

You don't need to convert int from/to String unless you want to display the ID for the user or store it as text. I think you can use int instead of uint without any problems. This won't corrupt the data because int64 and uint64 are the same size. It's unlikely that ID involves any complex operations or comparisons.

hislittlecuzin commented 6 months ago

You don't need to convert int from/to String unless you want to display the ID for the user or store it as text. I think you can use int instead of uint without any problems. This won't corrupt the data because int64 and uint64 are the same size. It's unlikely that ID involves any complex operations or comparisons.

You cannot use uint, because GD Script does not have a uint data type - hence the purpose of this issue.

CsloudX commented 6 months ago

You don't need to convert int from/to String unless you want to display the ID for the user or store it as text. I think you can use int instead of uint without any problems. This won't corrupt the data because int64 and uint64 are the same size. It's unlikely that ID involves any complex operations or comparisons.

You cannot use uint, because GD Script does not have a uint data type - hence the purpose of this issue.

image

CsloudX commented 6 months ago

You cannot use uint, because GD Script does not have a uint data type - hence the purpose of this issue.

You don't need uint, just use int. everyting will be OK. you see the id was negative, just it display on the screen was negative, in the memory, there was right data. for display, if you don't like negative, you can use String.num_uint64() just like @dalexeev say.

BenLubar commented 4 months ago

The top 7 bits are never set in a SteamID outside of Valve's internal network. Even within Valve's internal network, the top 5 bits are never set.

zaddok commented 1 month ago

GDScript should support unsigned integers. For type safety, it should be possible to declare a data type that should never be negative. I literally just had to fix a bug where a negative number appeared in a variable, where it should not be possible in the first place. What is the rationale for not supporting unsigned integers anyway?

Calinou commented 1 month ago

What is the rationale for not supporting unsigned integers anyway?

I believe it simplifies the language design and implementation a fair bit, which is why most high-level scripting languages don't support unsigned integers either.

You can use assert() to make sure a number is positive when needed. assert() is skipped in release builds (the expression isn't even evaluated), so it won't have a performance impact where it matters most.

RudyFisher7 commented 1 week ago

I know the OP's use case is network code. I wanted to add that uint type us necessary for other common use cases, such as encoding Ids for a lookup function. My case is for encoding ids for graph nodes of large graphs. Ids are encoded based on the maximum possible spatial size in 3d and each axis of a node's position (x, y, z) (basically a hash lookup function). Int64 limits the domain space quite significantly compared to uint64.

Also, in response to proposing to just store unsigned values in the signed datatype, may I ask how this is possible with GDScript without a type conversation operation occurring? Many languages have different ways to cast between numeric datatypes. For example, static_cast and reinterpret_cast in c++ do different things with the underlying bits, possibly losing data depending on the context. I don't believe GDScript exposes a reinterpret_cast equivalent or other mechanism to ensure binary data integrity through a type cast, no?

dalexeev commented 1 week ago

Also, in response to proposing to just store unsigned values in the signed datatype, may I ask how this is possible with GDScript without a type conversation operation occurring? [...] I don't believe GDScript exposes a reinterpret_cast equivalent or other mechanism to ensure binary data integrity through a type cast, no?

As long as you don't manipulate the data, you can be sure that nothing will break. If you just need to store a uint64 identifier as the author wants, there should be no problem, you can just use int. If you need to display the identifier to the user and you care that it is displayed in the original representation, then you can use String.num_uint64().

The difficulty arises if you want to perform any operations. For example, comparisons, abs(), min(), max(), etc. In some cases, you can add/subtract 2 ** 63 and/or use bitwise operations to compensate for the difference.

const INT64_MIN = 2 ** 63
const INT64_MAX = 2 ** 63 - 1
prints(INT64_MIN, INT64_MIN - INT64_MIN, String.num_uint64(INT64_MIN - INT64_MIN))
prints(0, 0 - INT64_MIN, String.num_uint64(0 - INT64_MIN))
prints(INT64_MAX, INT64_MAX - INT64_MIN, String.num_uint64(INT64_MAX - INT64_MIN))
-9223372036854775808 0 0
0 -9223372036854775808 9223372036854775808
9223372036854775807 -1 18446744073709551615