Jump to content

How to resize and/or move UI elements?


SpazmoJones

Recommended Posts

I have an idea for a mod but for best results it will require some text fields to be resized and possibly moved. Take for example the Soldier selection table that appears when you click on 'View Soldiers' via the barracks menu. The "count" text field displays the number of available soldiers out of the total (e.g. 38/40). I'd like to add some extra info to this field but it's just wide enough to display soldier counts. How would I go about widening this field? Any help would be appreciated.

 

 

Link to comment
Share on other sites

  • Replies 50
  • Created
  • Last Reply

Top Posters In This Topic

You mean the count display at the top of the barracks soldier list?

 

http://guides.gamepressure.com/xcomenemyunknown/gfx/word/-1778070937.jpg

 

From the looks of it this is a plain text field, albeit one which does not have its autoSize property set, so it won't grow automatically to accomodate different contents.

 

To take a step back and explain a bit more, XCOM uses the Scaleform middleware for its UI, which basically allows embedding and interacting with Flash files in the game. Thankfully it is quite possible to extract these Flash-derived files from the game packages so you can have a look at them. Making changes to them is a bit more complicated though and ranges from single-byte edits to having to replace and/or resize large sections, depending on what you want to do. Fortunately enabling auto-sizing falls into the former category :smile:

 

Generally you'll want to extract the Flash files from the relevant *.upk files, either by excising them manually or by using Toolboks, which can do that automatically for you. After extracting you can view the contents of the resulting Flash files using decompilers like JPEXS Free Flash Compiler. JPEXS also has limited editing capabilities which come in handy for making small to medium-sized adjustments.

 

In the specific case of the barracks list you'll want to extract the corresponding Flash menu file from the UI_Collection_Strategy_SF.upk package file. If you used Toolboks to extract the Flash files you'll have to manually look through them to find the right one since Toolboks names the resulting files using only a number index corresponding to where the Flash file is located in the parent UPK file. The SoldierList file should be number 45, if I'm not mistaken.

 

The soldier list menu itself is a composite of various sprites that serve different purposes - some provide (semi-)interactive elements (like text fields and scrollbars), others are purely visual (like borders and backgrounds). Some of those sprites are named which typically means that they are in some way connected to some ActionScript code (the Flash-specific scripting language). If you look through the sprites you'll notice one named SoldierList which makes up the bulk of the menu. Inside that sprite you'll see different objects being placed, one of which labeled soldierCount - that's the text field you're looking for.

 

Going up the hierarchy again in JPEXS' tree view you'll see a different branch named texts under which all text fields used throughout the menu. The soldierList sprite references the text field with the numerical identifer 65 (the text field itself doesn't have a name identifier, only its instances when placed in a sprite). Selecting that text field entry in the tree will show a list of its properties, stuff like color #ff67e8ed or align left. However, JPEXS only displays the properties whose values differ from the default state (I think), that's why the autoSize property is nowhere to be found in the list. Nevertheless, you can edit the property via right-clicking the tree entry and choosing Raw Edit from the context menu which will display a more detailed tree view of the object properties. Sure enough, looking through that view you'll notice an entry labeled autoSize = false. Hitting the Edit button at the bottom of the screen let's you change that property (by way of a checkbox) after which you'll want to hit the Save button (where the Edit button was before) and finally save the whole file via the Save (or Save As... if you're so inclined) button in the File section of the ribbon menu around the top of the application window.

 

The way text fields are defined in Flash files means that changing that autoSize property only changes a single byte in the whole file (a single bit even, to be more precise). So all that's left is to open the original Flash file and the JPEXS-altered one in a hex editor, finding that single changed byte (pro tip: search for the placeholder text which is set as the initialText property of the text field, i.e. that HTML-formatted stuff at the bottom of the basic properties view) and create a mod file for your preferred patcher tool (PatchUPK/PatcherGUI, I'm guessing) from the surrounding bytes.

 

So, all in all a very straightforward one-byte fix to enable (horizontal) auto-sizing of a text field. Sorry for the wall of text, there is a bit of information about Flash editing on the wiki, but it's a bit outdated and doesn't go into details like text fields, so I tried to be comprehensive :smile:

Edited by XMarksTheSpot
Link to comment
Share on other sites

Yes that's the field I want to change, thanks for the info. :) Ideally I'd like to make this field multiline and able to handle html formatting so I can change font sizes and colours. Is that possible? Also, if the modified swf file has a different size, how would you patch it back into the parent upk? If you have any examples or guides available it would sure help UI modding noobs like me.
Link to comment
Share on other sites

There's a multiline property for that purpose, but from what I remember this'll make the text field fixed-width, so you'll want to enlarge its horizontal bounds along with it.

To make use of HTML formatting the html property of the text field needs to be set to true and the htmlText property needs to be used for setting text instead of the plain text property. The latter means that you'll need to go into the SoldierList ActionScript class and modify the SetSoldierCountLabel() method which only makes use of the text property:

   function SetSoldierCountLabel(label)
   {
      this.soldierCount.text = label;
      this.soldierCount._visible = true;
   }


A few notes about editing ActionScript code using JPEXS:

 

First off, while JPEXS displays a nice decompiled view of the ActionScript code its actually reconstructed from pre-compiled byte code (similar to UnrealScript) and as such some measure of information got lost in the process. Most notably among that is that local variables have lost their names and are only referred to by numbered local memory registers (displayed as _loc3_, _loc4_ and so on in the ActionScript source view), some of which often typically fulfill special purposes, e.g. registers 1 and 2 refer to the keywords this and super respectively.

 

Second, even though there's an Edit button for the ActionScript source view I highly advise against using it (as does JPEXS itself by popping up a warning dialog). The main strength of the tool lies in decompiling ActionScript byte code, not recompiling, and more often than not editing like this will fail. The most reliable option is to edit the byte code directly which is displayed in an ASM-like readable format in a separate editor pane next to the ActionScript source view. Editing the byte code source takes some getting used to due to its stack-based nature. Simple alterations like changing a numerical value or a string are straightforward enough though.

 

On the topic of introducing size changes, there's basically two operations that need to be performed to get those working.

 

On the UPK side the Flash file as a whole is wrapped in a so-called SwfMovie object which typically has the same name as the Flash file itself and is put into a package that also has the same name but with a "gfx" prefix. As an example the SoldierList movie object would be found inside the gfxSoldierList package (in turn being inside UICollection_Strategy_SF.upk). As with UnrealScript objects the UPK file needs to know about the total size of such a SwfMovie object and therefore the same resize patching rules apply (i.e. you can use PatchUPK's auto-resize feature to take care of that).

 

The second operation requires a manual replacement, there's no automation for that. Basically a Flash file contains a short header section that always looks like this:

First three bytes are the characters G F X, fourth byte holds miscellaneous bit flags and bytes 5 through 8 encode the total byte size of the Flash file in little endian format. Note that Toolboks replaces the first 3 bytes with the characters F W S in an attempt to make the file look like a standard Shockwave Flash file, but it's really a Scaleform-specific extension of the format, hence the GFX references throughout (as in Scaleform GFx like it's also called). Anyway, the SwfMovie object which wraps the Flash file also repeats these 4 size bytes right before the GFX header section. So, in addition to the automatic object resize you'll also need to add a secondary replacement that adjust the total Flash file size in those two places (which fortunately are spaced apart only by 4 bytes).

 

As an example (in what basically amounts to a bit of hex math), if your original GFX file was 0x1234 = 4660 bytes in total the area around the header would likely look something similar to this:

… 34 12 00 00 84 5F 07 00 34 12 00 00 …
  <  size1  > <  "GFX"  > <  size2  >

If, through edits, you enlarged the file by, say, 0x56 = 86 bytes you'd end up with 0x1234 + 0x56 = 0x128A = 4746 bytes and your resulting AFTER block would need to look like:

… 8A 12 00 00 84 5F 07 00 8A 12 00 00 …
  <  size1  > <  "GFX"  > <  size2  >

That's basically the gist of resizing the GFX file as a whole. If you keep using JPEXS for editing the contents that's pretty much all you need to take care of, in addition to finding the before/after byte sequences corresponding to your changes - you wouldn't want to have the whole SwfMovie binary object in a PatchUPK mod file, though PatchUPK allows referencing separate binary files for replacements, at least for installation, the auto-generated uninstall file is a text file, as far as I remember, and that's pretty unwieldy for large objects.

 

 

For a more involved example you can look at my Interception UFO Damage Display mod which modifies the Interception GFX file by introducing new sprite definitions and rewriting some ActionScript logic. Also feel free to keep asking about UI stuff, I'm always eager to help out prospective UI modders :smile: Also, sorry for yet another wall of text :sweat:

Edited by XMarksTheSpot
Link to comment
Share on other sites

I've updated the swf file and I've located the hex differences. What object name should I use when creating the PatcherGUI file?

 

I have this so far:

 

UPK_FILE=UI_Collection_Strategy_SF.upk
OBJECT=gfxSoldierList ???????????
[BEFORE_HEX]
41 00 67 ec 29 f7 ec 13 a0 8d 33 3f 00 b8 01 67 e8 ed ff 00 00 00 00 00 00 00 28 00 00 3c 70 20 61 6c 69 67 6e 3d 22 6c 65 66 74 22 3e 3c 66 6f 6e 74 20 66 61 63 65 3d 22 24 54 69 74 6c 65 46 6f 6e 74 22 20 73 69 7a 65 3d 22 32 32 22 20 63 6f 6c 6f 72 3d 22 23 36 37 65 38 65 64 22 20 6c 65 74 74 65 72 53 70 61 63 69 6e 67 3d 22 30 2e 30 30 30 30 30 30 22 20 6b 65 72 6e 69 6e 67 3d 22 31 22 3e 39 39 2f 39 39 3c 2f 66 6f 6e 74 3e
[AFTER_HEX]
41 00 67 ec 29 f7 ec 13 a0 ad f3 3f 00 00 b8 01 67 e8 ed ff 00 00 00 00 00 00 00 28 00 00 3c 70 20 61 6c 69 67 6e 3d 22 6c 65 66 74 22 3e 3c 66 6f 6e 74 20 66 61 63 65 3d 22 24 54 69 74 6c 65 46 6f 6e 74 22 20 73 69 7a 65 3d 22 32 32 22 20 63 6f 6c 6f 72 3d 22 23 36 37 65 38 65 64 22 20 6c 65 74 74 65 72 53 70 61 63 69 6e 67 3d 22 30 2e 30 30 30 30 30 30 22 20 6b 65 72 6e 69 6e 67 3d 22 31 22 3e 39 39 2f 39 3c 2f 66 6f 6e 74 3e
Link to comment
Share on other sites

Ahhhhh -- the magic of proper SWF files editing (with their tricky Functions & Scripts & Sprites & Text Fields & a bunch of other stuff)... all of it sounds a lot more familiar to me now, thanks to our own local UI programmer and his precious skills!! :wink:

 

I once had various troubles with HTML Font colors... but - as they say - i got soooooooo lucky.

 

PS; Please refer to my Re-CoLoRing thread for further details and samples of such results.

Edited by Zyxpsilon
Link to comment
Share on other sites

Hmm, ok first question already! :) To change this function:

 

 function SetSoldierCountLabel(label)
   {
      this.soldierCount.text = label;
      this.soldierCount._visible = true;
   }

which has these hex codes:

SetMember
; 96 04 00 04 02 08 4a
Push register2 "SetSoldierCountLabel"
; 8e 0f 00 00 01 00 03 29 00 02 6c 61 62 65 6c 00 20 00
DefineFunction2 "" 1 3 false false true false true false false true false 2 "label"  {
; 96 04 00 04 01 08 0c
Push register1 "soldierCount"
; 4e
GetMember
; 96 04 00 08 47 04 02
Push "text" register2
; 4f
SetMember
; 96 04 00 04 01 08 0c
Push register1 "soldierCount"
; 4e
GetMember
; 96 04 00 08 0b 05 01
Push "_visible" true
; 4f
SetMember
; 4f
}
to this:
 function SetSoldierCountLabel(label)
   {
      this.soldierCount.htmlText = label;
      this.soldierCount._visible = true;
   }

How would I know which hex codes to use to replace the ".text" with ".htmlText" ? Is there a hex code guide similar to the one for UnrealScript somewhere?

 

Also in this particular example, would the object name still be "gfxSoldierList.SoldierList"? Does that object name encapsulate the entire swf file?

Link to comment
Share on other sites

How would I know which hex codes to use to replace the ".text" with ".htmlText" ?

You don't. Rather you use the Edit function of JPEXS' byte code editor and simply change the line

Push "text" register2

to

Push "htmlText" register2

Upon hitting Save JPEXS will do the necessary byte code re-compilation (which includes automatically adjusting jump offsets among a few other things).

 

I think your question stems from the observation that even though the byte code editor displays string literals to reference class/function/variable names the accompanying byte code doesn't show any string data for the most part. This is because these string literals are (as a result of the original export/compilation process) defined once at the beginning of the script (the very first line preceded by the ConstantPool opcode) and later on are referenced via an index into that list.

 

The implication of this is that you could change that index variable to reference a different string (and by extension a different class/function/variable), but this approach is overcomplicating things as JPEXS can determine that automatically. The only limitation there is that if no matching string is defined in the constant pool JPEXS will introduce an actual string literal in place of an index lookup. Which is not a bad thing at all, since adding a new string to the constant pool would amount to pretty much the same result.

 

The general rule of thumb when trying to keep file size increases minimal is to add new names to the constant pool for elements that you intend to use multiple times, whereas if you only want to use a new string identifier only once you simply inline it.

 

Also in this particular example, would the object name still be "gfxSoldierList.SoldierList"? Does that object name encapsulate the entire swf file?

Yes, PatchUPK only cares about Unreal objects, it is not aware about any script class hierarchies inside SwfMovie objects (which would require a completely different parsing approach as those files are a separate type of document altogether).

Edited by XMarksTheSpot
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...