Jump to content

UPK file format


wghost81

Recommended Posts

  • Replies 111
  • Created
  • Last Reply

Top Posters In This Topic

Just FYI UDefaultProperty is quite made up by my library it's not really a thing ;D Also Version and LicenseeVersion are written as one packet of 4 bytes(Little/Big Endian matter). There's a lot more but hey, good enough I guess.

Link to comment
Share on other sites

Thanks.

 

Yes, document is not perfect and may contain an errors. But I'm constantly working on improving my knowledge by looking into XCOM packages. :smile: And UE Explorer is of immense help. BTW, almost all flags are taken from there. :smile:

 

Default properties are different from UProperty objects, I needed some type name to use anyway. :smile: I will look into Version/Licensee version info, thanks.

 

And, please, feel free to post any thoughts on this document and UPK format. I'm open to suggestions and corrections. :smile:

Link to comment
Share on other sites

I've been wondering about the default properties, as UE Explorer clearly seems to read them but doesn't provide any hooks to read out the hex portions for each default value assignment (the best I've found is the Default Properties buffer from the context menu of the class, which display the entire contents of the class's default properties in one big chunk).

 

I sometimes have to mod the default properties, so any insights here would be most useful. Currently after I dig through the full Default Properties buffer I'm having to do raw hex replacements which will almost certainly break with a patch.

Link to comment
Share on other sites

Yes, I will write about default properties format, I just don't have time to do it right now.

 

Default properties are different for structures an for classes: for structures they are embedded in object itself and for classes they are a different object, linked to class.

Edited by wghost81
Link to comment
Share on other sites

I took a little break from New Year holidays and made a slight update to UPK format document. Still nothing on properties, though. Sorry, don't have much time right now.

 

[attachment deleted]

Edited by wghost81
Link to comment
Share on other sites

Default Properties:

 

While working on the EW-version of the ammo mod (which is pretty crazy as it has to circumvent a native function to native function call, indirectly), I've had occasion to play with some of the default properties settings, although I still don't quite understand the structure (it works, but I'm not entirely sure why...)

 

So my goal was to change a default value in XGWeapon, from :

fFiringRate = 1.50

to

m_iTurnFired = 100

So changing not only the value but also the variable and type. (m_iTurnFired is the new class variable I'm using to store the weapon's actual ammo)

 

For EW patch 1, the following hex does this (applied to Default__XGWeapon object) :

[BEFORE_HEX]
// name                 //??                    //size                  //value
82 32 00 00 00 00 00 00 ED 33 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 C0 3F 
[/BEFORE_HEX]


[AFTER_HEX]
// name                 // ??                   //size                  //value
42 55 00 00 00 00 00 00 A9 42 00 00 00 00 00 00 04 00 00 00 00 00 00 00 64 00 00 00 
[/AFTER_HEX]

The first 8 bytes are a long, index into the namelist. The above change redirects from the name index for "fFiringRate" to "m_iTurnFired".

 

The last bits are the value and the size of the value in bytes. Note that neither of them use the unrealscript precursors tokens (e.g. 1D for ints and 1E for floats).

 

What still has me a bit stumped is the 2nd word. This appears to be related to the type of the variable, as ED 33 00 00 appears to be consistently used for all float-type default properties throughout the upk, and A9 42 00 00 appears to be consistently used for all int-type default properties through the upk. However the particular values changed from EU patch 4 to EW patch 1, so the values aren't intrinsic the unreal bytecode. However they also aren't import list indices point the Core::IntProperty and Core::FloatProperty as is used in in the first integer in object entries.

 

So by comparing values I'm able to create a non-patch-safe change to the properties (including variable and type), but not understanding the 2nd value means that I can't algorithmically do this in a patch-safe manner.

Edited by Amineri
Link to comment
Share on other sites

Another crazy thing that I had to do to get the Ammo mod to work : altering the elements of a CheckpointRecord structure.

 

The CheckpointRecord is the structure that is used to determine which variables are saved as part of a savefile.

 

In XGWeapon the vanilla CheckpointRecord is:

struct CheckpointRecord_XGWeapon extends CheckpointRecord_XGInventoryItem
{
    var int iAmmo;
    var int iOverheadChance;
};

I discovered (through trial and error) that there is native code that checks the iOverheatChance value and inhibits ability activation if it is too high, so I wasn't able to use that variable, forcing me to use another XGWeapon class variable m_iTurnFired (see the above post for setting it's default value).

 

As a structure, XGWeapon.CheckpointRecord contains two objects of its own, XGWeapon.CheckpointRecord.iAmmo and XGWeapon.CheckpointRecord.iOverheatChance.

 

My challenge was to alter this so that the m_iTurnFired variable that I'm using to store ammo was saved as a part of the checkpoint (else saving and reloading during a mission caused ammo to automatically reload).

 

I discovered that I could do this by altering the Object Table Entry of XGWeapon.CheckpointRecord.iOverheatChance. The trick is to change the 4th integer parameter (the name index) from "iOverheatChance" to "m_iTurnFired". This changes the structure to :

struct CheckpointRecord_XGWeapon extends CheckpointRecord_XGInventoryItem
{
    var int iAmmo;
    var int m_iTurnFired;
};

But more than just a name change, this actually does make m_iTurnFired be saved and reloaded properly.

 

---------

 

However it poses an interesting dilemma when performing object-oriented hex editing (regardless of relative offset or S&R).

 

Both methods use the full name of the object in order to find the start position of the object to be changed. The above change, however, actually changes the name of the object, from:

XGWeapon.CheckpointRecord.iOverheadChance

to

XGWeapon.CheckpointRecord.m_iTurnFired

This means that searching for the object again (to revert the change, or to apply a different change) results in failure as the original object name has been altered.

 

For now the way I've gotten around this is to build the searched-for object name dynamically --

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=5B 06 B8 18 67 22 12 44 85 9B A8 5B 9D 57 1D 4B // XComGame_EW_patch1.upk
FUNCTION=CheckpointRecord_XGWeapon@XGWeapon
ACTION=genericObjectTableChange

//iOverheatChance@CheckpointRecord_XGWeapon@XGWeapon
//alter CheckpointRecord_XGWeapon so that m_iTurnFired is the member, not iOverheatChance

[BEFORE_HEX]
OBJECT_NAMEIDX=iOverheatChance
[/BEFORE_HEX]


[AFTER_HEX]
OBJECT_NAMEIDX=m_iTurnFired
[/AFTER_HEX]

The base object name being looked for is the parent object, CheckpointRecord_XGWeapon@XGWeapon. I had to develop code that checks for the existence of the OBJECT_NAMEIDX field and, if present, prepends that name to the search string.

 

In both BEFORE and AFTER cases searching the name table for iOverheatChance and m_iTurnFired is successful.

 

To apply the change, the search object name is constructed by prepending the BEFORE OBJECT_NAMEIDX to the root name, forming iOverheatChance@CheckpointRecord_XGWeapon@XGWeapon.

 

To revert the change, the search object name is constructed by prepending the AFTER OBJECT_NAMEIDX to the root name, forming m_iTurnFired@CheckpointRecord_XGWeapon@XGWeapon.

 

When testing to see which is applied, two different searches for the two different objects above are performed.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...