Jump to content

R&D - New Modding Tools


Amineri

Recommended Posts

Amineri, thanks! Yes, I was converting to names as an intermediate step. I didn't realized it can update hex-references directly.

 

I didn't realized, UPKFILE can point to some third upk copy. :smile: I assumed, I have to set correct value for reference update to work, but then I found that I need to specify upk files anyway and then things got messed up completely inside my head. :smile: So yes, it works perfectly. :smile:

Link to comment
Share on other sites

  • Replies 211
  • Created
  • Last Reply

Top Posters In This Topic

Some minor issues:

1. Copy/paste replace is working normally with usual text, but is behaving strange with highlighted code.

2. Highlight is not working until I type in some GUID. It doesn't actually use this GUID, apparently, as it works with incorrect GUID perfectly.

3. When I accidentally pointed reference lookup to compressed upk it did nothing. IMO, should at least show some error message about package being incorrect/compressed.

 

Sorry for not posting it at project home: too much work (IRL) to little time...

Link to comment
Share on other sites

 

Sorry for not posting it at project home: too much work (IRL) to little time...

 

No worries, this forum is perfectly fine. :)

 

 

1. Copy/paste replace is working normally with usual text, but is behaving strange with highlighted code.

 

I've put in an issue ticket on this, and will look into it. We never actually implemented copy/paste functionality explicitly, we just took advantage of what was built into the Java components used.

 

 

2. Highlight is not working until I type in some GUID. It doesn't actually use this GUID, apparently, as it works with incorrect GUID perfectly.

 

Actually I have it set up so that it doesn't attempt to parse any data unless it has a fully filled-out header (version, upkfile, guid, and function). The original purpose of this was to allow it act as a general-purpose text editor that would allow the user to manipulate text without trying to highlight garbage, but subsequent design decisions have made that less relevant.

 

 

3. When I accidentally pointed reference lookup to compressed upk it did nothing. IMO, should at least show some error message about package being incorrect/compressed.

 

That's an interesting find -- I hadn't ever had that happen. I'm not sure whether our upk parser knows how to check if the upk it's trying to decode is compressed. We didn't explicitly put such a check in. It may be scanning through the compressed file locations and getting garbage data, which could potentially cause problems.

 

 

Thanks again for the feedback :)

Link to comment
Share on other sites

Another note: I'm experiencing considerable slowdowns when highlighting long code lines.

 

Some of my mods are raw in-place hex editing, so I updated them by copying/pasting an entire code from HxD as one long line. This resulted in considerable slowdown of the entire program.

Link to comment
Share on other sites

I've noticed, that only project which have been opened via "Open Project" are saved in project view (leftmost window). If you create project and then close UPKModder, new project will not be displayed after reopening it. But after you manually open project and close UPKModder, it will be displayed after reopening.
Link to comment
Share on other sites

  • 2 weeks later...

I haven't made much headway in figuring out how to fix the various slowdowns for large files, but I've made headway in handling non-function hex changes in a way that is fairly patch-agnostic yet doesn't require me to build separate parsers for each type of structure in the upk (e.g. enums, variables).

 

Basically I've fixed a small bug that was preventing the direct use of name/object strings within "raw" hex. By raw hex I mean hex code that isn't parse-able as unrealscript. I'm still doing some bug-testing on a new v0.82 that will allow this, but thought I'd post up some examples of how it's working so far.

 

Changing default properties:

MODFILEVERSION=4
UPKFILE=XComStrategyGame.upk 
GUID=UNSPECIFIED // no hex references in file
FUNCTION=Default__XGStrategyAI
KEYWORD=Sets default of m_bFirstMission (used to set hard missions) to false


[BEFORE_HEX]
<|m_bFirstMission|> 00 00 00 00 // name m_bFirstMission
<|BoolProperty|> 00 00 00 00 // name BoolProperty
00 00 00 00 00 00 00 00 // no size for Bool
01 						// bool value true
[/BEFORE_HEX]

[AFTER_HEX]
<|m_bFirstMission|> 00 00 00 00 // name m_bFirstMission
<|BoolProperty|> 00 00 00 00 // name BoolProperty
00 00 00 00 00 00 00 00 // no size for Bool
00 						// bool value false
[/AFTER_HEX]

Extending an enumeration (combined with a RESIZE operation) :

MODFILEVERSION=4
UPKFILE=XComStrategyGame.upk
GUID=UNSPECIFIED // no hex references in file
FUNCTION=EAlienObjective@XGStrategyActorNativeBase
RESIZE=10

[BEFORE_HEX]
[HEADER]
//8F 00 00 00 E6 25 00 00 00 00 00 00 8F 00 00 00 
09 00 00 00 //length
[/HEADER]

<|eObjective_Recon|> 00 00 00 00 // eObjective_Recon
<|eObjective_Scout|> 00 00 00 00 // eObjective_Scout
<|eObjective_Harvest|> 00 00 00 00 // eObjective_Harvest
<|eObjective_Flyby|> 00 00 00 00 // eObjective_Flyby
<|eObjective_Hunt|> 00 00 00 00 // eObjective_Hunt
<|eObjective_Abduct|> 00 00 00 00 // eObjective_Abduct
<|eObjective_Terrorize|> 00 00 00 00 // eObjective_Terrorize
<|eObjective_Infiltrate|> 00 00 00 00 // eObjective_Infiltrate
<|eObjective_MAX|> 00 00 00 00 // eObjective_MAX
[/BEFORE_HEX]


[AFTER_HEX]
[HEADER]
//8F 00 00 00 E6 25 00 00 00 00 00 00 8F 00 00 00 
0b 00 00 00 
[/HEADER]

<|eObjective_Recon|> 00 00 00 00 // eObjective_Recon
<|eObjective_Scout|> 00 00 00 00 // eObjective_Scout
<|eObjective_Harvest|> 00 00 00 00 // eObjective_Harvest
<|eObjective_Flyby|> 00 00 00 00 // eObjective_Flyby
<|eObjective_Hunt|> 00 00 00 00 // eObjective_Hunt
<|eObjective_Abduct|> 00 00 00 00 // eObjective_Abduct
<|eObjective_Terrorize|> 00 00 00 00 // eObjective_Terrorize
<|eObjective_Infiltrate|> 00 00 00 00 // eObjective_Infiltrate
<|eObjective_Infiltrate|> 01 00 00 00 // eObjective_Infiltrate_1
<|eObjective_Infiltrate|> 02 00 00 00 // eObjective_Infiltrate_2
<|eObjective_MAX|> 00 00 00 00 //eObjective_MAX
[/AFTER_HEX]

Changing a variable definition :

MODFILEVERSION=4
UPKFILE=XComStrategyGame.upk
GUID=UNSPECIFIED // no hex references in file
FUNCTION=m_arrObjectiveNames@XGStrategyAI

//increase size of static array and remove enum link

[BEFORE_HEX]
{|CheckpointRecord@XGStrategyAI|} // last?
<|None|> 00 00 00 00              // unknown
{|CheckpointRecord@XGStrategyAI|} // next
08 00 00 00                       // array size
02 80 40 00 00 00 00 00           // flags
<|None|> 00 00 00 00              // unknown
{|EAlienObjective@XGStrategyActorNativeBase|}  // Enum
[/BEFORE_HEX]


[AFTER_HEX]
{|CheckpointRecord@XGStrategyAI|} // last?
<|None|> 00 00 00 00              // unknown
{|CheckpointRecord@XGStrategyAI|} // next
0B 00 00 00                       // array size
02 80 40 00 00 00 00 00           // flags
<|None|> 00 00 00 00              // unknown
00 00 00 00                       // Enum
[/AFTER_HEX]

Note that the GUID is now unspecified since there aren't any hex references remaining in the file.

Link to comment
Share on other sites

I currently use virtual function token to update default properties with UPKModder. :smile: I just enclose 8-byte name indexes into 1B - 16 and run update references. Works perfect. And again, thanks for the great tool! Updated all my mods for patch 3 in a matter of hours. That's fantastic!
Link to comment
Share on other sites

I do a similar thing to convert both function names and import/export objects from references to names.

 

For example, I copied out all of the raw XGItemLibrary default properties raw hex into a UPKmodder document and separated it into bits, then wrapped the name references with 1B ... 16 tokens and prefixed the object references with 00 and ran the reference updater to convert them all to names :

 

 

 

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=UNSPECIFIED // no hex references in file
FUNCTION=Default__XGItemLibrary

[BEFORE_HEX]

<|m_arrItems|> 00 00 00 00     // variable name
<|ArrayProperty|> 00 00 00 00  // variable type
70 03 00 00 00 00 00 00        // size in bytes?
DB 00 00 00                    // array length ?
00 00 00 00                           // item 0 eItem_NONE
00 00 00 00                           // item 1 eItem_BEGIN_WEAPONS
{|XGWeapon_Pistol|}                   // item 2
{|XGWeapon_AssaultRifle|}             // item 3
{|XGWeapon_Shotgun|}                  // item 4
{|XGWeapon_Minigun|}                  // item 5
{|XGWeapon_SniperRifle|}              // item 6
{|XGWeapon_RocketLauncher|}           // item 7
{|XGWeapon_LaserPistol|}              // item 8
{|XGWeapon_LaserAssaultRifle|}        // item 9
{|XGWeapon_LaserAssaultGun|}          //item 10
{|XGWeapon_HeavyLaser|}               //item 11
{|XGWeapon_LaserSniperRifle|}         //item 12
{|XGWeapon_PlasmaPistol|}             //item 13
{|XGWeapon_PlasmaLightRifle|}         //item 14
{|XGWeapon_PlasmaAssaultRifle|}       //item 15
{|XGWeapon_AlloyCannon|}              //item 16
{|XGWeapon_HeavyPlasma|}              //item 17
{|XGWeapon_PlasmaSniperRifle|}        //item 18
{|XGWeapon_BlasterLauncher|}          //item 19
{|XGWeapon_MechtoidPlasmaCannon|}     //item 20
{|XGWeapon_SeekerPlasmaPistol|}       //item 21
{|XGWeapon_MEC_KineticStrike|}        //item 22
{|XGWeapon_MEC_FlameThrower|}         //item 23
{|XGWeapon_MEC_GrenadeLauncher|}      //item 24
{|XGWeapon_MEC_RestorativeMist|}      //item 25
{|XGWeapon_MEC_Electropulse|}         //item 26
{|XGWeapon_MEC_ProximityMine|}        //item 27
{|XGWeapon_Chaingun|}                 //item 28
{|XGWeapon_Railgun|}                  //item 29
{|XGWeapon_ParticleBeam|}             //item 30
00 00 00 00                           //item 31 eItem_BEGIN_SPECIAL_WEAPONS
{|XGWeapon_SectopodArm|}              //item 32
{|XGWeapon_SectopodCannon|}           //item 33
00 00 00 00                           //item 34 eItem_SectopodHeatRay
{|XGWeapon_ChryssalidClaw|}           //item 35
{|XGWeapon_DroneBeam|}                //item 36
{|XGWeapon_PsiAmp|}                   //item 37
{|XGWeapon_Grapple|}                  //item 38
{|XGWeapon_Cyberdisc|}                //item 39
00 00 00 00                           //item 40 eItem_BEGIN_ALIEN_SHARED_WEAPONS
{|XGWeapon_PlasmaPistolSectoid|}      //item 41
{|XGWeapon_PlasmaLightRifle_ThinMan|} //item 42
{|XGWeapon_PlasmaLightRifle_Floater|} //item 43
{|XGWeapon_PlasmaLightRifle_Muton|}   //item 44
{|XGWeapon_PlasmaAssaultRifle_Muton|} //item 45
{|XGWeapon_HeavyPlasma_Floater|}      //item 46
{|XGWeapon_HeavyPlasma_Muton|}        //item 47
00 00 00 00                           //item 48 eItem_END_ALIEN_SHARED_WEAPONS
{|XGWeapon_ZombieFist|}               //item 49
{|XGWeapon_EtherealWeapon|}           //item 50
{|XGWeapon_MutonBlade|}               //item 51
{|XGWeapon_OutsiderWeapon|}           //item 52
{|XGWeapon_SoldierNoWeapon|}          //item 53
{|XGWeapon_Plague|}                   //item 54
{|XGWeapon_SectopodClusterBomb|}      //item 55
{|XGWeapon_SeekerTentacles|}          //item 56
00 00 00 00                           //item 57 eItem_END_WEAPONS
00 00 00 00                           //item 58 eItem_BEGIN_ARMOR
00 00 00 00                           //item 59 eItem_ArmorKevlar
00 00 00 00                           //item 60 eItem_ArmorCarapace
00 00 00 00                           //item 61 eItem_ArmorSkeleton
00 00 00 00                           //item 62 eItem_ArmorTitan
00 00 00 00                           //item 63 eItem_ArmorArchangel
00 00 00 00                           //item 64 eItem_ArmorGhost
00 00 00 00                           //item 65 eItem_ArmorPsi
00 00 00 00                           //item 66 eItem_ArmorCovertOps
00 00 00 00                           //item 67 eItem_END_ARMOR
00 00 00 00                           //item 68 eItem_BEGIN_ITEMS
{|XGWeapon_Medikit|}                  //item 69
{|XGWeapon_CombatStims|}              //item 70
{|XGWeapon_MindShield|}               //item 71
{|XGWeapon_ChitinPlating|}            //item 72
{|XGWeapon_ArcThrower|}               //item 73
{|XGWeapon_TargetingModule|}          //item 74
{|XGWeapon_ReinforcedArmor|}          //item 75
{|XGWeapon_RespiratorImplant|}        //item 76
00 00 00 00                           //item 77 eItem_BallisticModule
{|XGWeapon_ReaperRounds|}             //item 78
00 00 00 00                           //item 79 eItem_END_ITEMS
00 00 00 00                           //item 80 eItem_BEGIN_GRENADES
{|XGWeapon_FragGrenade|}              //item 81 
{|XGWeapon_SmokeGrenade|}             //item 82 
{|XGWeapon_FlashBang|}                //item 83 
{|XGWeapon_AlienGrenade|}             //item 84 
{|XGWeapon_GhostGrenade|}             //item 85 
{|XGWeapon_GasGrenade|}               //item 86 
{|XGWeapon_NeedleGrenade|}            //item 87 
{|XGWeapon_MimicBeacon|}              //item 88 
00 00 00 00                           //item 89 eItem_BEGIN_ALIEN_GRENADES
{|XGWeapon_SectoidGrenade|}           //item 90 
{|XGWeapon_FloaterGrenade|}           //item 91 
{|XGWeapon_MutonGrenade|}             //item 92 
{|XGWeapon_CyberdiscGrenade|}         //item 93 
{|XGWeapon_ThinManGrenade|}           //item 94 
00 00 00 00                           //item 95 eItem_END_ALIEN_GRENADES
{|XGWeapon_PsiGrenade|}               //item 96
{|XGWeapon_BattleScanner|}            //item 97
00 00 00 00                           //item 98 eItem_END_GRENADES
00 00 00 00                           //item 99 eItem_BEGIN_VEHICLES
00 00 00 00                           //item 100 eItem_SHIV
00 00 00 00                           //item 101 eItem_SHIV_Alloy
00 00 00 00                           //item 102 eItem_SHIV_Hover
00 00 00 00                           //item 103 eItem_Interceptor
00 00 00 00                           //item 104 eItem_Firestorm
00 00 00 00                           //item 105 eItem_Skyranger
00 00 00 00                           //item 106 eItem_Satellite
00 00 00 00                           //item 107 eItem_END_VEHICLES
00 00 00 00                           //item 108 eItem_BEGIN_VEHICLE_UPGRADES
{|XGWeapon_Shiv_Minigun|}             //item 109 
{|XGWeapon_Shiv_Sentry|}              //item 110 
{|XGWeapon_Shiv_Laser|}               //item 111 
{|XGWeapon_Shiv_Plasma|}              //item 112 
00 00 00 00                           //item 113 eItem_SHIVDeck_I
00 00 00 00                           //item 114 eItem_SHIVDeck_II
00 00 00 00                           //item 115 eItem_SHIVDeck_III
00 00 00 00                           //item 116 eItem_BEGIN_SHIP_WEAPONS
00 00 00 00                           //item 117 eItem_IntWeap_I
00 00 00 00                           //item 118 eItem_IntWeap_II
00 00 00 00                           //item 119 eItem_IntWeap_III
00 00 00 00                           //item 120 eItem_IntWeap_IV
00 00 00 00                           //item 121 eItem_IntWeap_V
00 00 00 00                           //item 122 eItem_IntWeap_VI
00 00 00 00                           //item 123 eItem_END_SHIP_WEAPONS
00 00 00 00                           //item 124 eItem_BEGIN_INTERCEPTOR_CONSUMABLES
00 00 00 00                           //item 125 eItem_IntConsumable_Dodge
00 00 00 00                           //item 126 eItem_IntConsumable_Boost
00 00 00 00                           //item 127 eItem_IntConsumable_Hit
00 00 00 00                           //item 128 eItem_END_INTERCEPTOR_CONSUMABLES
00 00 00 00                           //item 129 eItem_END_VEHICLE_UPGRADES
00 00 00 00                           //item 130 eItem_BEGIN_CORPSES
00 00 00 00                           //item 131 eItem_CivilianCorpse
00 00 00 00                           //item 132 eItem_TankCorpse
00 00 00 00                           //item 133 eItem_SoldierCorpse
00 00 00 00                           //item 134 eItem_SectoidCorpse
00 00 00 00                           //item 135 eItem_SectoidCommanderCorpse
00 00 00 00                           //item 136 eItem_FloaterCorpse
00 00 00 00                           //item 137 eItem_FloaterHeavyCorpse
00 00 00 00                           //item 138 eItem_ThinManCorpse
00 00 00 00                           //item 139 eItem_MutonCorpse
00 00 00 00                           //item 140 eItem_MutonEliteCorpse
00 00 00 00                           //item 141 eItem_BerserkerCorpse
00 00 00 00                           //item 142 eItem_CyberdiscCorpse
00 00 00 00                           //item 143 eItem_EtherealCorpse
00 00 00 00                           //item 144 eItem_CryssalidCorpse
00 00 00 00                           //item 145 eItem_ZombieCorpse
00 00 00 00                           //item 146 eItem_SectopodCorpse
00 00 00 00                           //item 147 eItem_DroneCorpse
00 00 00 00                           //item 148 eItem_END_CORPSES
00 00 00 00                           //item 149 eItem_BEGIN_CAPTIVES
00 00 00 00                           //item 150 eItem_SectoidCaptive
00 00 00 00                           //item 151 eItem_SectoidCommanderCaptive
00 00 00 00                           //item 152 eItem_FloaterCaptive
00 00 00 00                           //item 153 eItem_FloaterHeavyCaptive
00 00 00 00                           //item 154 eItem_ThinManCaptive
00 00 00 00                           //item 155 eItem_MutonCaptive
00 00 00 00                           //item 156 eItem_MutonEliteCaptive
00 00 00 00                           //item 157 eItem_BerserkerCaptive
00 00 00 00                           //item 158 eItem_EtherealCaptive
00 00 00 00                           //item 159 eItem_END_CAPTIVES
00 00 00 00                           //item 160 eItem_BEGIN_COLLECTIBLES
00 00 00 00                           //item 161 eItem_Elerium115
00 00 00 00                           //item 162 eItem_AlienAlloys
00 00 00 00                           //item 163 eItem_WeaponFragment
00 00 00 00                           //item 164 eItem_Meld
00 00 00 00                           //item 165 eItem_AlienEntertainment
00 00 00 00                           //item 166 eItem_AlienFood
00 00 00 00                           //item 167 eItem_AlienStasisTank
00 00 00 00                           //item 168 eItem_UFONavigation
00 00 00 00                           //item 169 eItem_AlienSurgery
00 00 00 00                           //item 170 eItem_UFOPowerSource
00 00 00 00                           //item 171 eItem_HyperwaveBeacon
00 00 00 00                           //item 172 eItem_DamagedAlienEntertainment
00 00 00 00                           //item 173 eItem_DamagedAlienFood
00 00 00 00                           //item 174 eItem_DamagedAlienStasisTank
00 00 00 00                           //item 175 eItem_DamagedUFONavigation
00 00 00 00                           //item 176 eItem_DamagedAlienSurgery
00 00 00 00                           //item 177 eItem_DamagedUFOPowerSource
00 00 00 00                           //item 178 eItem_DamagedHyperwaveBeacon
00 00 00 00                           //item 179 eItem_UFOFusionLauncher
00 00 00 00                           //item 180 eItem_PsiLink
00 00 00 00                           //item 181 eItem_ExaltIntel
00 00 00 00                           //item 182 eItem_END_COLLECTIBLES
00 00 00 00                           //item 183 eItem_Base_Shard
00 00 00 00                           //item 184 eItem_Skeleton_Key
{|XGWeapon_SectopodChestCannon|}      //iyrm 185
00 00 00 00                           //item 186 eItem_XPACK_BEGIN_CORPSES
00 00 00 00                           //item 187 eItem_MechtoidCore
00 00 00 00                           //item 188 eItem_SeekerCorpse
00 00 00 00                           //item 189 eItem_CorpsePlaceholder2
00 00 00 00                           //item 190 eItem_XPACK_END_CORPSES
00 00 00 00                           //item 191 eItem_BEGIN_MEC_ARMOR
00 00 00 00                           //item 192 eItem_MecCivvies
00 00 00 00                           //item 193 eItem_MecArmor1
00 00 00 00                           //item 194 eItem_MecArmor2
00 00 00 00                           //item 195 eItem_MecArmor3
00 00 00 00                           //item 196 eItem_MecArmor1_Kinetic
00 00 00 00                           //item 197 eItem_MecArmor1_Flamethrower
00 00 00 00                           //item 198 eItem_MecArmor2_Kinetic_Grenade
00 00 00 00                           //item 199 eItem_MecArmor2_Kinetic_Mist
00 00 00 00                           //item 200 eItem_MecArmor2_Flamethrower_Grenade
00 00 00 00                           //item 201 eItem_MecArmor2_Flamethrower_Mist
00 00 00 00                           //item 202 eItem_MecArmor3_Kinetic_Grenade_Electro
00 00 00 00                           //item 203 eItem_MecArmor3_Kinetic_Grenade_ProximityMine
00 00 00 00                           //item 204 eItem_MecArmor3_Kinetic_Mist_Electro
00 00 00 00                           //item 205 eItem_MecArmor3_Kinetic_Mist_ProximityMine
00 00 00 00                           //item 206 eItem_MecArmor3_Flamethrower_Grenade_Electro
00 00 00 00                           //item 207 eItem_MecArmor3_Flamethrower_Grenade_ProximityMine
00 00 00 00                           //item 208 eItem_MecArmor3_Flamethrower_Mist_Electro
00 00 00 00                           //item 209 eItem_MecArmor3_Flamethrower_Mist_ProximityMine
00 00 00 00                           //item 210 eItem_END_MEC_ARMOR
00 00 00 00                           //item 211 eItem_BEGIN_EXALT_WEAPONS
{|XGWeapon_ExaltAssaultRifle|}        //item 212
{|XGWeapon_ExaltSniperRifle|}         //item 213
{|XGWeapon_ExaltMinigun|}             //item 214
{|XGWeapon_ExaltLaserAssaultRifle|}   //item 215
{|XGWeapon_ExaltLaserSniperRifle|}    //item 216
{|XGWeapon_ExaltHeavyLaser|}          //item 217
{|XGWeapon_ExaltRocketLauncher|}      //item 218

[/BEFORE_HEX] 

 

 

 

I had to insert the item values / enums manually, though (with a bit of cut/paste from the enum reverse lookup).

Link to comment
Share on other sites

UPKmodder v0.82 has been uploaded : http://code.google.com/p/upk-modder

 

This has only a single fix :

- Fixed bug preventing processing of embedded names in hex.

This fix allows embedding of namelist entries using <| ... |> delimiters,
and embedding of import/export object entries using {| ... |} delimiters.
The ReferenceUpdater tool built into UPKmodder can convert hex references to valid names using the correct delimiters with the "convert to names" option.
The user can also manually enter names.
Link to comment
Share on other sites

  • 4 weeks later...

I'd typed up some additional information regarding how to change object table entries for johnnylump, so I thought I'd post them here as well for anyone that is interested. Object table data is what is accessed with UE Explorer in the "Table Buffer". The actual object's hex itself is accessed via the "Buffer".

 

 

Does this mean changing the first 48 bytes that comes out when you do a buffer dump?

What if I want to change something that appears in the "table buffer" hex instead?
Right, each object has information stored in two different places.
The UE Explorer "Table Buffer" is the a table entry for the object (which has some basic descriptive information about the object, including the file position and file size of the object within the upk). Typically each of the table entries is 68 bytes long. UPKmodder automatically parses the entire object table for each upk it deals with. That's how it builds the reference ID-to-number mapping. The reference number is just the index within this table. XComGame.upk for EW has about 55,000 (= D6D8) entries in the table, so that's why the numbers grow around that big.
UPKmodder extracts the "useful" information from each object using (this is pasted directly out of the Java source code for UPKmodder) :
   private void parseData(int[] data) {
        this.iType = data[0];
        this.iParent = data[1];
        this.iOuter = data[2];
        this.iNamePtr = data[3];
        this.iHighFlags = data[6];
        this.iLowFlags = data[7];
        this.iUpkSize = data[8];
        this.iUpkPos = data[9];
        // TODO: parse/store other values, create getters and other convenience methods (e.g. getNameListIndex(), etc.)
   }

UPKmodder reads the object table data as 4-byte words instead of at the byte-level. Most entries contain 17 4-byte words, although the specifier at position 11 specifies additional 4 byte-words (this value is only non-zero for non-script objects, in my experience).

 

The stuff at the back end of each isn't of use for scripting (e.g. variables, enumerations, functions), and appears to be used to define art asset object info (e.g. 3D meshes, animations, textures, sound files). I'm not sure what the 64 bits of flags all do, either.

 

When you include a RESIZE= command for an object it automatically updates the UpkSize of the current object and the UpkPos of all subsequent objects (all objects that have a position later than the current one).

 

---------------

 

In UE Explorer the regular hex "Buffer" displays the hex for the object itself. The position and size of this object within the upk file is defined via the UpkSize and UpkPos entries within the table entry for the object (i.e. if you looked up the table buffer, read words 8 and 9, opened the upk with HxD and went to that position you'd find the object hex).

 

Functions contain both the run-time "byte-code" bytes as well as 48 bytes of header and 15 bytes of footer information. Typically the only bytes in the header/footer that are changed are the last two words, which contain the memory/file size of the byte-code. The preceding 40 bytes do contain some useful things, including some references (import, object, and/or name). This means that listing the full raw header hex isn't patch-safe, since those values may be updated. However, you can use the name of the object which UPKmodder will attempt to convert to hex at apply/revert-time, which does make it patch-safe. (e.g. {|iType@GetPossibleSpawns@XGDeployAI|})

 

I'm just not sure what the different header/footer bytes do specifically. I'm pretty sure that there are flags defining the function type (e.g. private, static, native, virtual) in the footer. And that some of the header information is used to in creating the linked list of local variables/parameters/return value for the function. Wghost is ahead of me in decoding that stuff.

 

--------------

By default UPKmodder changes the object entry itself (the "buffer dump"). It can change any bytes within the object hex, which is how we make changes to enumerations and variables, for example. For functions this includes the full function header (48 bytes) and footer (15 bytes).

 

UPKmodder will only change hex in the object table when using special commands. For example the RESIZE= command alters size/position of many object table entries.

 

Other commands include:

ACTION=typechange -- a specific command that requires changing both the iType and UpkSize fields of the object table entry. These are specified using OBJECT_TYPE= and SIZE=, for example :

ACTION=typechange

//change object type parameter into int type

[BEFORE_HEX]
OBJECT_TYPE=Core:ObjectProperty@Core
SIZE=2C // hexadecimal
[/BEFORE_HEX]

[AFTER_HEX]
OBJECT_TYPE=Core:IntProperty@Core
SIZE=28 // hexadecimal
[/AFTER_HEX]

For more general-purpose changes to the object table entry for an object, there is the

- ACTION=genericObjectTableChange

 

This allows you to manually change most any entry within the object table entry. Note that this can easily corrupt the upk, in particular if the size/position values are changed incorrectly.

 

For this command new values are specified via keywords, instead of via generic hex changes. This is because UPKmodder has to store copies of most of the table entry data in order to properly decode things, so changing these things is a little trickier and has to be under tighter control. Fortunately there aren't many 'useful' table values, so they can all be specified directly.

 

This command could actually supercede the "typechange" command, as it's more flexible. It allows any or all entries below to be changed --not all values have to be specified.

 

The keywords that allow changes to the object table entry are :

  • OBJECT_TYPE : bytes 0-3 in the table buffer
  • OBJECT_PARENT : bytes 4-7 in the table buffer
  • OBJECT_OUTER : bytes 8-11 in the table buffer
  • OBJECT_NAMEIDX : bytes 12-15 in the table buffer
  • OBJECT_HIGHFLAGS : bytes 20-23 in the table buffer
  • OBJECT_LOWFLAGS : bytes 24-27 in the table buffer
  • OBJECT_SIZE : bytes 28-31 in the table buffer
  • OBJECT_POSITION : bytes 32-35 in the table buffer

 

A few notes about these.

  • OBJECT_TYPE is almost always an import object (reference value is negative), so in UPKmodder would be specified in a patch-safe manner as something like Core:IntProperty@Core, or Core:FunctionProperty@Core.
  • OBJECT_PARENT is only used for classes, and indicates the parent of a class (e.g. XGWeapon is the parent of XGWeapon_AssaultRifle) This is typically a regular object reference
  • OBJECT_OUTER indicates hierarchical ownership. For example in iType@GetPossibleSpawns@XGDeployAI, the iType object has as OUTER the GetPossibleSpawns object, while GetPossibleSpawns has as OUTER the XGDeployAI object. XGDeployAI has a null OUTER
  • OBJECT_NAMEIDX is a reference to a name entry (an index into the name table). This is effectively how each object is named. Objects with the same name reference the same name entry without problem.

UPKmodder expects certain type values in each field :

  • OBJECT_TYPE : must be a valid object (import or export) name (e.g. Core:Function@Core or Core:IntProperty@Core)
  • OBJECT_PARENT : must be a valid object (import of export) name
  • OBJECT_OUTER : must be a valid object (import of export) name
  • OBJECT_NAMEIDX : must be a valid name on the namelist
  • OBJECT_HIGHFLAGS : must be an integer, specified in hexadecimal
  • OBJECT_LOWFLAGS : must be an integer, specifed in hexadecimal
  • OBJECT_SIZE : must be an integer, specifed in hexadecimal
  • OBJECT_POSITION : must be an integer, specifed in hexadecimal

Changing the OBJECT_NAMEIDX for an object is problematic since the name is how the object is referenced in the first place. So changing the name results in UPKmodder being unable to properly locate the object after the change (to verify correct install and to be able to revert the change).

 

IMPORTANT!!!

When changing the NAMEIDX, leave the name of the current object out of the FUNCTION= (alternative usage OBJECT_ENTRY=) specifier.

 

For example :

MODFILEVERSION=4
UPKFILE=XComGame.upk
GUID=1C 18 A1 1A 2B C3 34 4E 8B 2C 72 33 CD 16 7E 3E // XComGame_EW_patch3.upk
OBJECT_ENTRY=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]

In this case the object iOverheatChance@CheckpointRecord_XGWeapon@XGWeapon is being transformed into the object m_iTurnFired@CheckpointRecord_XGWeapon@XGWeapon.

 

The CheckpointRecord_XGWeapon@XGWeapon object itself is not being changed. Instead if UPKmodder sees that the OBJECT_NAMEIDX= field is being changed, it automatically prepends the value to what is specified in the OBJECT_ENTRY field.

 

So when applying the change, it locates the object with the name "iOverheatChance@CheckpointRecord_XGWeapon@XGWeapon"

When reverting the change is locates the object with the name "m_iTurnFired@CheckpointRecord_XGWeapon@XGWeapon"

Then testing for apply/revert status, it tests both.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...