Understanding UPK side UI coding - XCOM:EU 2012

From Nexus Mods Wiki
Revision as of 03:40, 17 November 2018 by Dubiousintent (talk | contribs) (Added 'Category:Mod_Creation')
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Overview

The Understanding ... - XCOM:EU 2012 series of articles present information that is an interpretation of Firaxis Games programming practices as discerned by individuals digging through the XCOM:EU 2012 game engine code, to make it easier for mod creators to follow the code logic. As such, it is best guess, good faith only information, and should not be taken as either authoritative or sanctioned by Firaxis Games. Discussion of the information presented here should be directed to the appropriate R&D series of threads on the Mod Talk forum of the Nexus Forums.

This article explains the general mechanism by which the UI is handled in UPK code. The relevant Mod Talk thread where it was initially presented is R&D to Increase Squad Size, with additional contributions from the UI Editing thread.

Programs and Tools

UE Explorer from:

Details

SWF containers

Many (if not most) ActionScript SWF files related to UIs are embedded in these UPK files:

  • Command1.upk
    • \gfxXComIcons\XComIcons.swf has icons. The (extracted) folder \gfxXComIcons is used by a number of icon tag references from:
  • GlobalPersistentCookerData.upk
  • XcomShell.upk
  • UICollection_Strategy_SF.upk (these appear to be copies of icon images from Command1.upk)
  • UICollection_Common_SF.upk (contains Perk icons)

See the wiki article Flash SWF Editing for information about how to extract and edit SWF files. All the EU SWFs from Command1.upk have been put in a file that's hosted under the Long War mod's miscellaneous files. The wiki article explains how these SWF files were extracted.

Structure

The Introduction to SWF article describes the SWF header structure. This is an important document for anyone intending to modify the UI. Amongst other information it says:

Following the header are a series of tagged data blocks. All tags share a common format, so any program parsing a SWF file can skip over blocks it does not understand. Data inside the block can point to offsets within the block, but can never point to an offset in another block. This enables tags to be removed, inserted, or modified by tools that process a SWF file.

and

Extension Mechanism
Currently, many useful block types are defined. Tag numbers 0-511 are reserved for future use. Tag numbers 512-1023 are reserved for use by third party applications.
In order to let applications define their own tag types, it is possible to define an AppExtension tag that contains the name of the application functionality being implemented and a tag range that describe what tags will be used by this extension set. The extension sets should be similar to a MIME type where they take the form of the following string:

<company name>/<extension set>

For the entire file, these tag types will be interpreted in the context of the named extension. Applications should be able to remap the tag range for a particular file to avoid conflicts between two extension sets.
The extension must be in the 512-1023 tag type range.

Name conventions

Firaxis appears to use the following for the UPK UI coding conventions. Each UI functionality is typically broken into two parts:

  • UI<name>: the "driver" class typically has a function called GetMgr() that returns the appropriate manager class (i.e. XG<name>UI) associated with the UI. This class is always the one that contains the actionscript calls, and first handles any callbacks from the UI. Typically little or no data handling.
  • XG<name>UI: referred in the code as the "manager". Handles most data manipulation.

Icons

The icon image data is defined as a Texture2D object contained within \gfxXComIcons. However there is also a UPK object XComIcons which contains a GFX (Flash) file XComIcons. This XComIcons contains a little bit of actionscript but also a MovieClip used to display the Texture2D objects. The objects are imported using a GFX extension (not standard Flash) DefineExternalImage2 command. JPEXS supports this command, but other SWF tools may not. Adobe CS5 requires a plug-in for GFX in order to recognize it (Epic has instructions for installing the plug-in).

The Texture2D icons are imported into the XComIcons GFX object and are then primarily put into one of two MovieClips for display -- there is one used for "Perk" icons and one used for "Ability" icons. A "Perk" icon can be displayed when selecting a new Perk for a unit, while an "Ability" icon can be displayed as a clickable button on the tactical HUD. To make matters more confusing, some icons are available in both (e.g. "battlescanner"), while some are available as Perks only or Ability only.

There are a few other icons used in other ways, such as the class icons, rank icons, promote icons, etc., that are part of the above two MovieClips but are made available in other ways.

So far 21 icons have been identified that look to have been originally defined as Perk/Ability icons, but are not currently in either MovieClip (not sure if they are being imported into XComIcons). Either the original icon imagery created by Firaxis can be used or the image data could be replaced.

Adding new icons would then also require updating of the XComIcons embedded GFX object as well as all of the UPK-side stuff necessary to add new objects.

Use Umodel to extract the game assets (including textures) from the UPKs, if that's what you're after. The imagery used on UI displays are considered icons.

  • Inventory images are referenced via string, which is retrieved from XComGame.upk >> UIUtilities.GetInventoryImagePath.
    A typical example imagepath string is: img://UILibrary_StrategyImages.InventoryIcons.Inv_LaserRifle
  • The imagepath is passed to the Actionscript via:

AS_AddInventoryItem(int Type, string Title, string imgLabel, int numEquipableItems, GFxObject mecIconsArray).

The 3rd parameter imgLabel is the imagepath.
  • Extracted the SoldierLoadout Flash file and traced through, and ended up in SoldierPromotion.ImageContainer with:

Bind.image(register2,this.imgPath,{"onComplete":mx.utils.Delegate.create(this,this.realize),"_visible":true});

  • Bind is another package within SoldierLoadout, with the function image:

static function image(owner, path, props)
  {
     ImageLoader.load(owner,path,props);
  }

  • ImageLoader looks like a pretty low-level Package in SoldierLoadout. It invokes:

ClipLoader.load(container,path,properties);

  • ClipLoader is yet another package which invokes:

register1=new MovieClipLoader();
register1.addListener(ClipLoader);
register1.loadClip(path,container);
register1.path=path;
register1.properties=properties;
if(ClipLoader.loaders==undefined)
  {
     ClipLoader.loaders=new Object();
  }
var register3=String(container);
ClipLoader.loaders[String(register3)]=register1;

Command1.upk Texture2D object contains header, image data and footer. Header contains data seen in UE Explorer. If there are more sizes of an image, each size has own entry in the header. Each image entry can contain size and offset in texture file cache (tfc) file.

This icon data is not particularly compressed, as two of the icons examined (fieldmedic and willtosurvive) are both 64 x 64 pixels, and the raw image data in both cases is 0x1000 = 4096 = 64 * 64 bytes long, so these are using 1 byte per pixel, with sRGB flag = false.

UE Explorer decompiles the objectlist entry / header info as:

begin object name=willtosurvive class=Texture2D
   SizeX=64
   SizeY=64
   OriginalSizeX=64
   OriginalSizeY=64
   Format=EPixelFormat.PF_DXT5
   MipTailBaseIdx=6
   SRGB=false
   NeverStream=true
   LODGroup=TextureGroup.TEXTUREGROUP_UI
object end
// Reference: Texture2D'gfxXComIcons.willtosurvive'

Here are the steps taken to replace the Perk icon for willtosurvive image data as a test case:

  1. Decompress UICollection_Common_SF.upk using Gildor's UPK Decompressor tool.
  2. Open the UPK using UE Explorer and navigate to \gfxXComIcons -- find the icon you wish to modify (e.g. fieldmedic, bringemon, willtosurvive, etc.)
  3. Right-click on the icon name and open the Buffer, then copy the Buffer data to whichever program suits you (Notepad++, HxD, UPKmodder) -- I used UPKmodder for the following since I'm familiar with it.
  4. The first 0x13D bytes of hex are header information. Only the final 12 = 0xC bytes of this need be kept unless the image is being resized (which I haven't tried yet).
  5. The final 0x24 bytes of hex are footer information.
  6. Isolate the image data byte and replace as desired.

GamePad Icons

The gamepad icons (GetButtonName ) aren't stored in \gfxXComIcons but are instead stored in \gfxGamePadIcons.

Image Data Loading

There are two different methods by which image data is specified to be loaded within the various Flash UI components. All of these are defined in XComGame.upk >> UIUtilities, which contains a bunch of different functions to retrieve strings associated with image data.

Firaxis designates the difference by ending the UIUtilities function with either "path" or "label".

Path strings are similar to URLs, such as
  • "img://UILibrary_StrategyImages.InterceptorImages.Inv_InterceptorPlasmaCannon",
  • "img://UILibrary_StrategyImages.InventoryIcons.Inv_AssaultRifleModern", and even
  • "img://UILibrary_StrategyImages.CaptiveIcons.Captive_Sectoid"
  • These conform to how raster image data is labeled within the UDK. See Scaleform Technical Guide, which says (in part):

To load the texture Texture2D'MyPackage.MyGroup.MyTexture', for example, you would set the "source" variable of the UILoader to "img://MyPackage.MyGroup.MyTexture" for bilinear sample scaling, or "imgps://MyPackage.MyGroup.MyTexture" for point sampling.

I'm no expert on UE3, but I think that these are stored/loaded progressively using the usual Unreal Engine mechanics (i.e. stored in a tfc).
Label strings are very much shorter, such as
  • "urbancombat",
  • "rank0",
  • "AlienContainment", and
  • "fieldmedic"
These appear to used exclusively for single color bitmap icon image data, which could suffer from the lossy compression typically applied to UE texture data (my guess, anyhow).
The above only works for images defined via label, which includes :
  • GetAbilityIconLabel
  • GetButtonName (breaking the naming convention)
  • GetClassLabel
  • GetCountryLabel
  • GetEItemType_InfoIcon (breaking the naming convention)
  • GetFacilityLabel
  • GetMECItemToAbilityIconLabel
  • GetMedalLabel
  • GetMedalLabels
  • GetMissionListItemIcon
  • GetOTSImageLabel
  • GetPerkIconLabel
  • GetRankLabel
  • GetShipIconLabel

Examples

For the squad select UI, there is one "manager" and two UI "driver" classes:

  • UISquadSelect ("Driver").
  • UISquadSelect_Squadlist ("Driver"). Appears to handle individual soldier display info, calling the actionscript functions SetAddUnitText, SetSelected, SetUnitHelp, and SetUnitInfo (all of which are defined in the actionscript package Squadlist).
  • XGChooseSquadUI ("Manager").

(They appear to have slightly bent their naming convention here by not using the same core name.)

References

Referred to by this article:



That refer to this article:

  • None as yet