Jump to content

UPK Utils


wghost81

Recommended Posts

I've done some "extreme variable makeovers" myself, although nothing quite as extreme as your example.

 

Just to make clear to anyone else reading this it's also possible to alter the parameters and the ReturnValue type in the same way. To change the type of the ReturnValue you'd reference it like:

OBJECT=XGDeployAI.GetPossibleSpawns.ReturnValue

using the traditional nomenclature.

 

Parameters are referenced using their parameter name in the same way as local variables.

 

I'd come across the result that dynamic arrays are actually two objects when I wanted to convert a regular value into a static array -- the goal was to convert a config variable to a dynamic array to be able to better import config data, but it doesn't work because such a conversion requires an additional object which wasn't available.

Link to comment
Share on other sites

  • Replies 235
  • Created
  • Last Reply

Top Posters In This Topic

You can often free one or two variables, if you really need it. Loop counters are the best candidates: if you have I and J integers, you can convert I to static array I[2] and use J for your own purposes. Like relink it to other variable and make dynamic array. Edited by wghost81
Link to comment
Share on other sites

Got tired of rewriting a hex code and finally added a functionality I always dreamed of. :smile:

OBJECT=XGStrategyAI.GetNumOutsiders:AUTO
[REPLACEMENT_CODE]
// if(Game().GetDifficulty() >= 2)
07 [@label1] 99 19 1B <Game> 16 0A 00 <XGStrategy.GetDifficulty.ReturnValue> 00 1B <GetDifficulty> 16 2C <%b2> 16
	// return 2
	04 2C 02
// goto (else)
06 [@label2]
	[#label1]
	// return 1
	04 26
[#label2]
// return ReturnValue
04 3A <.ReturnValue>
// EOS
53
It's an example of pseudo-code I've added to PatchUPK. This one, called REPLACEMENT_CODE, is aimed to fully rewrite functions: it can auto-expand (or shrink) functions, calculate memory and serial size and jump offsets (using labels). And, of course, it's fully reference-independent, as it uses name, not hex code, to reference an object.

 

I'm still testing this new functionality and will release PatchUPK v.3.0 with full documentation on new features soon. Stay tuned! :wink:

Link to comment
Share on other sites

Thank you :thumbsup:

 

I bet more people dreamed of this.

 

Can be labels used in FIND_HEX too?

 

Have you implemented an ability to patch multiple files with the same code yet? :)

 

I'd like a label, that can write absolute file offset (4 bytes) of following byte. Like 01 01 01 01 05, where 01 01 01 01 is absolute offset of 05. It is seen in Texture2D object, but I will confirm, if it is really needed, if correct offset matters or not.

Link to comment
Share on other sites

FIND_HEX (FIND_CODE, actually) can use named references, but not labels. Correct memory offsets can be calculated for complete code only, so labels are only allowed inside REPLACEMENT_CODE.

 

I haven't implemented multiple upk feature yet. Implementing pseudo-codes was actually not too hard, as I already had all functions necessary. But multiple upk feature will require a lot more work, as PatchUPK wasn't build with this in mind.

Link to comment
Share on other sites

UPKUtils updated to v.3.0:

http://www.nexusmods.com/xcom/mods/448

Sources:

https://github.com/wghost/UPKUtils

 

For new features description see the readme files.

 

 

UPD I'm working on supplemental mod for Random Pods, which will randomize number of pods for each mission, as long as number of aliens, and will support larger pods. 4 complex functions rewritten with a new PatchUPK and everything seems to work as intended so far. Crossing my fingers. :smile: Rewriting a functions is a LOT quicker if you don't need to care about jumps and sizes.

Edited by wghost81
Link to comment
Share on other sites

Cool! My bad, had named references, not labels on my mind, so I'm happy :)

 

Patching multiple files is still doable with copy paste approach, and when it could ease mod file creation for patching textures, I think it can wait.

Link to comment
Share on other sites

That's a nice implementation for handling the jump offset issue.

 

I've been thinking recently about adding some more "partways" re-compilation features, and the two big ones I think are the automatic computation of offsets (both line-based and relative).

 

For example in your line :

07 [@label1] 99 19 1B <Game> 16 0A 00 <XGStrategy.GetDifficulty.ReturnValue> 00 1B <GetDifficulty> 16 2C <%b2> 16

the 0A 00 2-byte integer (generally) has to be the memory size of the "referenced" object -- in this case GetDifficulty() (which is 0A bytes).

 

Anyhow, I've been thinking about how to try and translate something like :

Game().GetDifficulty()

into the correct hex line, without the need for manually looking up hex.

 

The first issue is that the <objectname1>.<objectname2> operator is overloaded in unrealscript, as the . operator can be either a 0x19 class element reference or a 0x35 struct element reference.

 

I think that this would have to be resolved by looking up the names for object1 and object2 and checking their types.

 

For a class context reference the format is :

19 <object1Hex> <object2HexSize> <object2HexReturn> 00 <object2Hex>

 

For a struct context reference the format is :

35 <object2Hex> <object2HexOwner> 00 00 <object1Hex>

 

In both cases the context of the second object generally has to be resolved. For a virtual function (as in the example) it's not too difficult, but even so the Return Value has to be identified. In this example case the type of the function "Game()" has to be identified.

 

I think that the following steps would have to be taken to identify the proper function "Game()"

1) Search the current class XGStrategyAI -- it has no member function Game()

2) Search the parent class XGStrategyActor -- it has no member function Game()

3) Search the parent class XGStrategyActorNativeBase -- it has the member function Game()

 

Once the function Game() has been found, the type of its return value is checked, which is of type XGStrategy. This means that object2 must reside in XGStrategy or a parent class of XGStrategy, or else it is a compile-time error (e.g. "member not found"). This means that the <object2HexReturn> should be based on the lookup of "XGStrategy.GetDifficulty.ReturnValue". However if the second object was a class variable (the string is not followed by a '(' character), then the return value would instead be "XGStrategy.GetDifficulty" as the "return value" for class variables is the class variable itself.

Link to comment
Share on other sites

Virtual functions are, actually, the most difficult ones, as determining which function to call from which object could be a bit tricky (and compiler-dependent). The whole idea of virtual functions is that they're identified run-time, not compile-time. I don't know how UE works with virtual functions, as I never actually payed attention to return value reference of overridden functions (just used the one from original call). Here are name lookup rules for C++, for example:

http://en.cppreference.com/w/cpp/language/lookup

http://en.cppreference.com/w/cpp/language/virtual

May be UE uses base function return value for all calls, I don't know. It has to be examined. Resolving scopes is a headache.

 

BTW, manual virtual size calculation is easy with pseudo-codes, as each name/object token is 8 bytes long. Less bytes to count. :smile:

Edited by wghost81
Link to comment
Share on other sites

Another example of crazy variables relink/rename with PatchUPK 3.0 :smile:

// relink, convert and rename XComAlienPodManager.GetPodCharArray.arrAltWeapon.arrAltWeapon
// to integer XGBattleDesc.InitAlienLoadoutInfos.iAlienCount
EXPORT_ENTRY=XComAlienPodManager.GetPodCharArray.arrAltWeapon.arrAltWeapon
[MODDED_CODE]
<Core.IntProperty> // new type
00 00 00 00        // ParentClassRef
<XGBattleDesc.InitAlienLoadoutInfos> // new owner
<iAlienCount>      // new name
00 00 00 00        // ArchetypeRef
<x00000000>     // ObjectFlagsH
<x00070004>     // ObjectFlagsL
< % u 40 >             // new serial size
// link new local var to XGBattleDesc.InitAlienLoadoutInfos
OBJECT=XGBattleDesc.InitAlienLoadoutInfos.iAlienPods
REL_OFFSET=12
OBJIDX=XGBattleDesc.InitAlienLoadoutInfos.iAlienCount // NextRef

// convert and rename XComAlienPodManager.GetPodCharArray.arrAltWeapon dynamic array
// to integer XComAlienPodManager.GetPodCharArray.iAlienCount
EXPORT_ENTRY=XComAlienPodManager.GetPodCharArray.arrAltWeapon
[MODDED_CODE]
<Core.IntProperty> // new type
00 00 00 00        // ParentClassRef
<XComAlienPodManager.GetPodCharArray> // OwnerRef
<iAlienCount>      // new name
00 00 00 00        // ArchetypeRef
<x00000000>     // ObjectFlagsH
<x00070004>     // ObjectFlagsL
< % u 40 >             // new serial size
// convert XComAlienPodManager.GetPodCharArray.iAlienCount from function param to local var
OBJECT=XComAlienPodManager.GetPodCharArray.iAlienCount
REL_OFFSET=20
UNSIGNED=0x00000000 // clear Parm flag to turn iAlienCount into a local var
Edit: forum engine mistakes my code for some evil script :smile: so I added spaces to "< % u 40 >" to make it display correctly. Edited by wghost81
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...