Jump to content

How to resize and/or move UI elements?


SpazmoJones

Recommended Posts

Cont'd from Show Soldier XP mod page discussion.

 

Ok, I reckon I'm up for this challenge. :smile:


I've had a look at your UFO health mod and it looks like you can simply replace a block of hex (actionscript code) with a larger block of hex code and not have to worry about changing any pointers or mem sizes except for the header section - is that right?

Yes and no. An ActionScript class is embedded in a DoInitAction SWF tag, and as with any tag it has a header section of its own which specifies its total byte size (sans header). On the byte level a DoInitAction tag is typically headed by 6 bytes, the first two of those declaring the tag type and the other 4 specifying the tag size. For instance, FF 0E F7 14 00 00 would be a DoInitAction tag which would be 0x14F7 (body) + 0x6 (header) bytes in size. For more information of Flash file anatomy I can refer you to Adobe's SWF File Format Specification document, the go-to resource if you want to deconstruct Flash files on the binary level.

 

So you cannot simply replace a chunk of code with a larger one without also adjusting the tag header (in addition to the global GFx file header). Thankfully JPEXS does that automatically for you if you use its byte code editing functionality.

 

As for the 'pointers or mem sizes' remark, ActionScript byte code also makes use of absolute jump offsets for control flow statements. So if you change a section of code in isolation you'll invalidate all jump statements after that. Fortunately, again, JPEXS re-calculates offsets automatically (using labels) so you don't have to worry about this.

 

The general rule of thumb when editing ActionScript is to create a hex replacement that encompasses the whole tag from head to toe to capture the changed header as well as any modified jump offsets and other assorted changes on the byte level throughout the whole class.

 

 

Would I just need to keep track of the original function size, subtract this size from the new modded size, then add this difference to the header size?

Basically, yes.

 

 

How would I add new graphics to the SWF file? Does JPEXS have any features that allow for this? How would I patch the new graphics back in? Would it be simpler to create a new SWF file and patch the entire thing back in using an external file if there are a lot of changes? Would this not create problems if other LW devs (like yrself) make changes to the SWF file?

I'll probably have more questions for you soon, hope you're ready. :smile:

While JPEXS has nice editing capabilities for many components of a Flash file it is not really intended for content creation. You can modify existing tags and even create new ones (e.g. new DefineShape and DefineSprite tags), but there's no user-friendly graphical editor to support this, you're going to have to punch in lots of numbers manually and for that you'll need to be intimately familiar with how vector shapes are defined in SWF files. Basically you wouldn't want to edit graphics using JPEXS :smile:

 

What you can do though - and what I have done before - is to create your graphics in a Flash authoring program (Adobe Flash would be the obvious choice if you have access to it) or similar software that can create SWF files and copy over the relevant shapes and sprites. A bit of manual editing (e.g. using JPEXS) still remains necessary to fit the new tags into the existing hierarchy as tags are referred to by unique character IDs and it's very likely your injected tags' IDs would clash with existing ones. I can help with creating Flash-based vector graphics (like the proof-of-concept I posted), if you want.

 

About your remark to patch in a whole SWF file, I'd advise against that as, although technically feasible, it's basically overkill for what you want to do. I think it's better to compartmentalize your changes so you can apply them separately. Still, you'll run into compatibility issues anyway, for instance two size-altering modifications will need to adjust the GFX header and there currently is no automation for that (like there is for UPK objects). Furthermore the issue of unique character IDs remains a stumbling block when multiple mods try to introduce new tags (for new graphics or scripts, for instance), so you'll invariably have to work off of other people's versions to create compatible versions. That's why my UFO health display mod has three separate versions for EU, EW and LW.

Link to comment
Share on other sites

  • Replies 50
  • Created
  • Last Reply

Top Posters In This Topic

Thanks for the info X. I'm trying to make a patch for the SoldierList table but PatcherGUI is telling me it can't find the GFX header

 

Here's a very simple patch file (for beta 15d2) - it doesn't actually change anything but PatcherGUI reports an error locating the data:

MOD_NAME=Test GFX header

UPK_FILE=UICollection_Strategy_SF.upk
OBJECT=gfxSoldierList.SoldierList

[BEFORE_HEX]
d0 7d 01 00 // old size
47 46 58 09 // GFX header
d0 7d 01 00 // old size


[AFTER_HEX]
d0 7d 01 00 // new size
47 46 58 09 // GFX header
d0 7d 01 00 // new size

 

PatcherGUI error:

 

Searching for object named gfxSoldierList.SoldierList ...
Object found!
Searching for specified data chunk ...
Can't find specified data!
Execution stopped at #5 command named [BEFORE_HEX].
Restoring from backup: C:\patchergui/Backup/3734558879/1429832140
uicollection_strategy_sf.upk restored from backup
Restoring from backup completed successfully

If I open UICollection_Strategy_SF.upk with a hex editor I can see the bytes I want to replace in the file:

03 00 00 00 76 00 00 00 45 00 00 00 75 00 00 00 ad 01 00 00 00 00 00 00 
d0 7d 01 00 
47 46 58 09 
d0 7d 01 00 
80 00 03 20 00 00 01 c2 00 00 1e 01 00 1c fa 6e 03 13 00 00 00 0d 00 00 12 41 6e 63 68 6f 72 65 64 4d 65 73 73 61 67 65 4d 67 72 44 11 00 00 00 00 43 02 99 99 99 73 fc 01 00 00 00

Any idea why PatcherGUI doesn't find it?

Edited by SpazmoJones
Link to comment
Share on other sites

Hey I just figured it out. If I look at the SoldierList object using the table view in UE Explorer it shows me completely different bytes in the header:

 

a9 b7 02 00 
47 46 58 08 
a9 b7 02 00 
I guess the UPK file does some sort of compression on the SWF file when it gets stored in the UPK. I was expecting to see the RAW SWF file embedded in the UPK....
Guess I'll use the data from UE explorer then... :)
Link to comment
Share on other sites

There's no explicit compression for the Flash files. I think what you're seeing is caused by the way PatchUPK handles object replacements. Instead of changing the target object directly PatchUPK will create an altered version using the replacement data and append it to the UPK file while also updating the UPK's internal references to point to the new object. This means every time you perform a PatchUPK operation you'll end up with another version of your target object while leaving the original target object intact. This explains why you can still find the original data in the original location with a hex editor, but it's dead weight by now.

Link to comment
Share on other sites

I've been trying to convert the StatusText field to a XComScrollingTextField. There are no other XComScrollingTextFields imported into the SWF so I tried adding one via "others"->ImportAssets2 and giving it a new ID. My patched SWF file looks ok, I apply the patch to the UPK file ok, but when I extract the SWFs from the patched UPK using toolboks I don't see my changes - the ImportAssets2 tag I added is missing.

 

I figured I need to do this before I can change the statustext definition to use the new ID. Is this right?

Link to comment
Share on other sites

Hi X - It looks like modifying the size of an embedded swf with PatcherGUI will cause it to create a "new" instance of the object, so the the SWF "number" of the newly extracted file will be different. In my case it's gone from UICollection_Strategy_SF_45.swf to UICollection_Strategy_SF_58.swf.

 

Now the changes I made are in the modified swf but when I start the game the Status text field is blank. I don't quite understand how the positioning in the "matrix" works either. There are ScaleX/Y, TranslateX/Y values and nTranslateBits/nScaleBits etc

 

How does that relate to the screen location? Is there a special way to initialise these auto scrolling text fields? I think it might be there but maybe lacking formatting info or something, or it's off screen, or I'm not setting the value correctly. Would it be easier to delete the existing statusText reference and create one dynamically in the code, then set its position?

 

Thanks for you help with all of this so far. I appreciate the help.

Edited by SpazmoJones
Link to comment
Share on other sites

I don't quite understand how the positioning in the "matrix" works either. There are ScaleX/Y, TranslateX/Y values and nTranslateBits/nScaleBits etc

 

How does that relate to the screen location?

The translation values are relative to the parent into which an object is placed using a PlaceObject tag. Internally Flash uses twips as unit of measurement, i.e. 'twentieth of a pixel', so by dividing the values by 20 you get the actual pixel dimensions. JPEXS displays the values for the translate fields of PlaceObject tags in twips, ActionScript code however uses pixel measurements directly, although still subject to the 0.05 px grid limitation (i.e. all pixel positions are rounded to the nearest multiple of 0.05 internally).

 

The scaling values used internally are decimal numbers stored in a compacted 16.16 signed fixed-point format, i.e. the nScaleBits value determines how many of the 32 available bits are used, which is usually 18 or larger (16 bits for decimal places, 1+ bits for the integer portion, 1 bit for the sign). Basically this encodes scaling factors that are typically around 1.0, though JPEXS (misleadingly) interprets and displays these values as integers. You can transform them to their intended values by dividing the displayed integers by 65536, so a scaling to ~220% would look like 144179 in JPEXS. ActionScript however handles scales differently, again. There it's defined as a percentage value, i.e. normal scaling is 100, double is 200, etc. Pretty straightforward, really, yet different from how sprites work, mind you.

 

All of the information can be found in the SWF File Format Specification and the ActionScript 2.0 Language Reference. Before JPEXS integrated raw editing capabilities for tags (or before I became aware of that functionality) I did a lot of editing by hand, decoding and re-encoding those bit-packed values to move things around. Quite tedious, I can tell you :smile:

 

I've been trying to convert the StatusText field to a XComScrollingTextField. There are no other XComScrollingTextFields imported into the SWF so I tried adding one via "others"->ImportAssets2 and giving it a new ID.

Is there a special way to initialise these auto scrolling text fields? I think it might be there but maybe lacking formatting info or something, or it's off screen, or I'm not setting the value correctly.

Using an ImportAssets tag to get an XComScrollingTextField sprite into the soldier list is good thinking, I assume you lifted the required url and tagName strings from a different Flash file and replaced the target character ID of the status text field's PlaceObject tag to point to the imported character instead.

 

An XComScrollingTextField is actually a composite sprite that contains an actual text field inside, i.e. it is not a text field itself. As such using the text and htmlText properties to set its contents won't work, but the linked XComScrollingTextField AS class has cover methods for that purpose, setText() and setHTMLText() respectively. This means you'll have to edit the SoldierListItem class to use those methods as they also feature a bit of logic triggering the auto-scrolling behavior.

 

As for formatting the scrolling text fields, the default format of the built-in text field of a standard XComScrollingTextField sprite should already look pretty similar to what the status text field uses. To be really sure you can transfer the text format from an existing text field to the scrolling text field using TextField.getNewTextFormat() and XComScrollingTextField.setNewTextFormat() which is a cover method for TextField.setNewTextFormat().

Edited by XMarksTheSpot
Link to comment
Share on other sites

I'm about ready to give up on this. I can't get the changed field to display anything at all.

 

I've done all of the following:

 

Added an ImportAssets2 tag to to import "..\gfxComponents\components.swf", set the tag to 31 (ID used by statusField), set the name to "XComScrollingTextField"

 

In the DefineSprite bit for SoldierListItem I've changed the PlaceObject for statusField and set these values:

 

hasScale = true

scaleX[nTranslateBits] = 8000

scaleY[nTranslateBits] = 440

 

I didn't change the TranslateX/Y values as I presume they should be correct as is:

scaleX[nTranslateBits] = 16129

scaleY[nTranslateBits] = 363

 

name = statusField

In the SoldierListItem OnLoad function I changed the
this.statusField.htmlText = this.initStatus
call to:
this.statusField.setHTMLText(this.initStatus);
When I check the exported swf after patching everything looks right. Help!
Edited by SpazmoJones
Link to comment
Share on other sites

Those scale values don't look right to me. Why do you change those anyway? Better leave them alone for now until you can figure out the scrolltext importing part.

 

My guess is that having two objects defined using the same character ID (i.e. one using ImportAssets and the other using DefineEditText) is clashing. This happened to me when messing around with sprites and JPEXS does show error messages for that in its log window. So you might want to zero out the DefineEditText tag (so there is only one object with ID 31) or simply use a completely new ID and adjust the status field's PlaceObject tag to target the new ID instead.

 

I can take a look at the Flash file if you upload it somewhere, maybe it's something entirely different you're missing.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...