Jump to content

How to use four byte integer to store and retrieve up to 4 integer values


Drakous79

Recommended Posts

Inspired by SpazmoJones' magic in Enhanced Soldier Customization (for Long War) mod and XCOM 2 character customization YouTube video, I've started to explore EU/EW customization options again. Here is some info on integers - need to sort it in my head too. Warning, maybe old news for someone.

 

---

 

Quick recap of tokens (Hex values XCOM Modding at Nexus Wiki):

  • 0x25 IntZero (size 1 byte, value 0)
  • 0x26 IntOne (size 1 byte, value 1)
  • 0x2C IntConstByte (size 1 byte, value <= 255)
  • 0x?? IntConstShort (size 2 bytes, value <= 65535)
  • 0x1D IntConst (size 4 bytes, value <= 4294967295)

 

Four byte integer code

1D FF FF FF FF

can hold values like:

  • 1 - 4 integers <= 255 (4x 1 byte)
  • 1 - 2 integers <= 255 and 1 integer <= 65535 (2x 1 byte and 1x 2 bytes)
  • 1 integer <= 255 and 1 integer <= 16777215 (1x 1 byte and 1x 3 bytes)
  • 2 integers <= 65535 (2x 2 bytes)
  • 1 integer <= 4294967295 (1x 4 bytes)

A number of stored integers depends on your needs (amount and size of desired ints).

 

I'd like to store 4 ints <= 255 in NewIdx now, 4 various indexes to one color palette without going crazy with checkpoint records.

 

Setting all four values for the first time is easy. Just set all four bytes.

// PatcherGUI code
0F 00 <.NewIdx> // NewIdx =
1D <%b 10> <%b 20> <%b 30> <%b 40> // 757274895

// Decompiled code
NewIdx = 757274895;

Or alternatively:

// PatcherGUI code
0F 00 <.NewIdx> // NewIdx =
92 92 92 // + + +
94 // << shift left
1D <%u  40> 2C <%b 24> // (40 << 24) 
16
94 // << shift left
1D <%u  30> 2C <%b 16> // (30 << 16)
16 16
94 // << shift left
1D <%u  20> 2C <%b 8> // (20 << 8)
16 16
1D <%u  10> // 10
16

// Decompiled code
NewIdx = (((40 << 24) + (30 << 16)) + (20 << 8)) + 10;

3 of 4 values must be shifted, so they land at the correct byte. How to shift is set by a direction and a number of bits.

  • the 1st byte - no shift
  • the 2nd byte - shift in a direction by 1 byte (8 bits)
  • the 3rd byte - shift in a direction by 2 bytes (16 bits)
  • the 4th byte - shift in a direction by 3 bytes (24 bits)

Tokens:

  • 0x94 LessLess_IntInt - shift left
  • 0x95 GreaterGreater_IntInt - shift right

Shifting is quite fun, because Unreal Engine 3 uses little endian approach (reads a lot of stuff from right to left; backwards). As it may be good and effective for machines, it is confusing and not so comfortable for non-programming human beings.

 

Lets check integer code again so we can understand the magic of bitwise operations:

0A 14 1E 28 // in byte code
10 20 30 40 // decimal values order in byte code
28 1E 14 0A // in the game
40 30 20 10 // decimal values order in the game

// NewIdx shifted by 0 = 10
// NewIdx shifted by 8 = 20
// NewIdx shifted by 16 = 30
// NewIdx shifted by 24 = 40

.

Setting just single value is more tricky. I'll show it on example, where is 10 20 30 40 set in the code. & (and) operator with a mask is used on already set integer and compared with help | (or) operator with new shifted value.

 

In the mask I will FF all values I don't want to change and 00 the value I want to change, the third byte as defined in byte code to 33 in this case. The mask follows byte code values order.

// PatcherGUI code
0F 00 <.NewIdx> // NewIdx =
9E // | OR
9C // & AND
00 <.NewIdx> 1D FF FF 00 FF // (NewIdx & -16711681) the mask
16
94 // << shift left
1D <%u  33> 2C <%b 16> // (33 << 16)
16 16

// Decompiled code
NewIdx = (NewIdx & -16711681) | (33 << 16);

The | (or) operator looks at each bit and returns 1 if the bit is 1 in either of the inputs. In this case I masked 30 with zeros, so the result is:

00000000 | 00100001 = 00100001
// 0 | 33 = 33

Without the mask would happen this:

00011110 | 00100001 = 00111111
// 30 | 33 = 63

Shoud be possible to invert the mask, FF the value to change and use & (and) operator instead, but I haven't tried it. Or to multiply the third value of NewIdx by zero first and then just add the shifted value.

 

Tokens:

  • 0x9C And_IntInt - &
  • 0x9D Xor_IntInt - ^
  • 0x9E Or_IntInt - |

 

Retrieving values is done with help of shifts and masks too. While setting values requires shift to the left, reading values requires shift to the right :smile: If you know Ultima Online, that would be Por Ort Grav words of powah.

 

The mask is simple this time, just FF (255 in decimal).

 

NewInt variable in the next example isn't used in the game, but I used it to demonstrate the retrieval in the code. I'm using LogInternal heavily and checking real time log (Steam's launch parameter -log).

 

Here goes the code:

// PatcherGUI code
0F 00 <.NewInt> // NewInt =
9C // & AND 
00 <.NewIdx> 2C FF // (NewIdx & 255)
16

0F 00 <.NewInt> // NewInt =
9C // & AND 
95 // >> shift right
00 <.NewIdx> 2C <%b 8> 16 2C FF // ((NewIdx >> 8) & 255)
16

0F 00 <.NewInt> // NewInt =
9C // & AND 
95 // >> shift right
00 <.NewIdx> 2C <%b 16> 16 2C FF // ((NewIdx >> 16) & 255)
16

0F 00 <.NewInt> // NewInt =
9C // & AND 
95 // >> shift right
00 <.NewIdx> 2C <%b 24> 16 2C FF // ((NewIdx >> 24) & 255)
16

// Decompiled code
NewInt = (NewIdx & 255);
NewInt = ((NewIdx >> 8) & 255);
NewInt = ((NewIdx >> 16) & 255);
NewInt = ((NewIdx >> 24) & 255);

// ---

// PatcherGUI code
E7 // LogInternal
A8 // Join strings
1F <%t "********** D79 debug ********** XGCustomizeUI.AdvanceArmorTint NewIdx 16 =">
38 53 // IntToString
9C // & AND
95 // >> shift right
00 <.NewIdx> 2C <%b 16> 16 2C <%b 255>
16
16 // Close join strings
16 // Close LogInternal

// Decompiled code
LogInternal("********** D79 debug ********** XGCustomizeUI.AdvanceArmorTint NewIdx 16=" @ string((NewIdx >> 16) & 255));

You can use

2C <%b 255>
// instead of
2C FF 

for better orientation in pseudo code.

 

Well, that would be all. Hopefully I understand it right, but if you see some inaccurate or wrong info, feel free to correct or explain :smile:

 

4 values instead of one, that may be armor's primary, secondary, weapon's and helmet color stored.

 

One link with good explanation of AND, OR and shift operations: Bitwise operation at Wikipedia.

 

---

 

Edit: Corrected speculation part about inverting the mask in Setting just single value section and added Wikipedia link to Bitwise operation.

Edited by Drakous79
Link to comment
Share on other sites

​Hello!

 

I made UE3 compiler and decompiler with a handy utilities set. Part of the utilities are using UPKTools as a backend (thanks to wghost81 for a such good tool set!).

I'll release it soon. So no more problems with integers or floats, etc. anymore. :smile:

 

Example tokens:

 

float: FloatConst(("0.4059738695"))

integer: IntConst(("2325839"))

integer HEX: IntConst((09 0f 04 a0))

string: StringConst(("良いセット Ывдлфо адЦыфо у sljf aeOirJa rfjh "))

auto label: @to_label(35)

named label: @to_label("Script Ret")

 

Code between /*DESCRIPTION_BEGIN*/ and /*DESCRIPTION_END*/ tags is for a dev-helping purposes and ignored by a compiler.

 

Example of formatted code:

Divide_FloatFloat(
    IntToFloat(
        InstanceVariable(
            (IntProperty'XGAbility_Targeted.m_iHitChance')
        )
    ),
    FloatConst(
        ("27.0")
    ), 
    EndFP()
)

Example mod:

 

Using this compiler I made http://www.nexusmods.com/xcom/mods/663/?. You may use it as an example.
Source code you can see and download here:

https://github.com/FI-Mihej/Realistic-Damage-Model-mod-for-Long-War

 

UCB source code files can be highlighted by https://github.com/FI-Mihej/UCB-Source-Code-highlighter

Edited by FieryIce
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...