A lot of times in the ue4 code I have seem bool decalred as a uint32…
e.g.
/** Set by character movement to specify that this Character is currently crouched. */
UPROPERTY(BlueprintReadOnly, replicatedUsing=OnRep_IsCrouched, Category=Character)
uint32 bIsCrouched:1;
Why is it done so? Doesn’t a bool take less space than an uint32? So why is it used like that?
The :1 at the end means this is a bitfield. If there are multiple consecutive bitfield members, they will be packed into the same space (so 1 to 32 of these variables declared in a row still only take up the space of a single uint32). If there is anything in between them, that breaks the run, and it’ll end up using multiple variables.
Not all uses of this in the engine are necessary / making things smaller though; to some degree it’s a matter of personal habit from who wrote the code.
/** Set by character movement to specify that this Character is currently crouched. */
UPROPERTY(BlueprintReadOnly, replicatedUsing=OnRep_IsCrouched, Category=Character)
uint32 bIsCrouched:1;
/** Handle Crouching replicated from server */
UFUNCTION()
virtual void OnRep_IsCrouched();
/** When true, player wants to jump */
UPROPERTY(BlueprintReadOnly, Category="Pawn|Character")
uint32 bPressedJump:1;
/** When true, applying updates to network client (replaying saved moves for a locally controlled character) */
UPROPERTY(Transient)
uint32 bClientUpdating:1;
/** True if Pawn was initially falling when started to replay network moves. */
UPROPERTY(Transient)
uint32 bClientWasFalling:1;
/** If server disagrees with root motion track position, client has to resimulate root motion from last AckedMove. */
UPROPERTY(Transient)
uint32 bClientResimulateRootMotion:1;
/** Disable simulated gravity (set when character encroaches geometry on client, to keep him from falling through floors) */
UPROPERTY()
uint32 bSimGravityDisabled:1;
Thanks… I didn’t know that so that’s why they are all declared in a straight row… I assume the function in the between doesn’t break the pattern.
Whoa, that’s really weird. I had no idea that’s what was happening.
I always used enums which had values increasing by a power of 2 and would use the logical or operator to create bitfields (similar to how windows does it).
If you want to move around a set of flags as a single unit, the single value with masks is the way to go (as in order to copy these values you have to copy each one individually), but if you’ve got a bunch of basically independent Booleans then this approach works fairly well.
Sorry to dig up an old thread, but on this topic, will the uint32:1 approach reduce network bandwidth if the variables are replicated over the network? eg. If I have a class with 64 replicated bools vs 64 replicated uint32:1s, should I expect to see 256 bytes vs 2 bytes sent over the network if all the values are resent?
I haven’t looked at the code for this, but 95% sure it would make no difference. The replication system works on the property level, it has to copy out the property value from wherever it’s stored and then serialize it into a state for sending over the network. Undoubtedly this code will be packing things together as efficiently as it can based on property type and should pay no attention to in what way the properties are stored on the container struct/class.
A single uint32 : 1 versus a single bool won’t make a difference for replication, but if you have a bunch of bits that frequently change, a uint8 or uint16 or uint32 manually created bitfield will be more efficient to replicate than 8 or 16 or 32 individual properties (there’s some per-property overhead since you have to send an indicator of which property you are sending data for). It really depends on the situation and how often things change though.