Jump to content

wghost81

Premium Member
  • Posts

    1186
  • Joined

  • Last visited

Posts posted by wghost81

  1. Randomly here :)

     

    I rarely check the forums, but I do check my mail regularly, so using Nexus PM is an easier way to reach me if needed.

     

    Texture replacement was tested with Batman as I did those for Batman modding team. I've only briefly got back to XCOM to see if they work at all, no extensive testing was done, so I imagine there might indeed be issues with different data types that are not used by Batman. If you notice any, don't hesitate to PM me - I can't promise an immediate fix, but at least I will be aware of it.

     

    PS I'm not working with Pavonis. Still an independent modder with chaotic activity timings :)

  2. Great :thumbsup:

     

    dubiousintent, let me use this opportunity to finally say that you are a pillar of this community. The wiki is a massive work and it's useful not only for XCOM modders but for all the UE3 modders out there. So, from the bottom of my heart - thank you for all these years of making sense of our random posts!

  3. It's been a while :smile:

    I was finally able to finish a project started a very-very long time ago by Drakous79. Thanks to the people from Batman modding community who approached me with the problem of texture modding in that game. I guess, 5 years away give you a broad enough perspective to realize what you've been doing wrong :smile:.

     

    First off, Texture2D export data format. UE3 Texture2D object inheritance looks like this:

    Object <- Surface <- Texture <- Texture2D

    Its serialized data start with PrevObjectRef (same as everything else) followed by DefaultPropertiesList (see my old docs on upk format). Then come its own data as follows:

    an empty bulk data chunk (12 zero bytes + 4 bytes of absolute file offset pointing to the MipMapCount)
    MipMapCount (4 bytes)
    serialized MipMaps array of MipMapCount elements
    unknown data
    

    Unknown data seems to be just a bunch of memory variables someone had forgotten to exclude from serialization.

     

    MipMapCount should correspond to MipTailBaseIdx property defined in DefaultPropertiesList:

    MipTailBaseIdx = MipMapCount - 1

    MipMaps are BulkData with 8 additional bytes of SizeX and SizeY:

    4 bytes of Flags
    4 bytes of ElementCount
    4 bytes of BulkDataSizeOnDisk
    4 bytes of BulkDataOffsetInFile
    BulkDataSizeOnDisk bytes of image data (if Flags do not have StoredInSeparateFile or StoredAsSeparateData bit set)
    4 bytes of SizeX
    4 bytes of SizeY
    

    Possible Flags:

    StoredInSeparateFile = 0x00000001
    StoredAsSeparateData = 0x00000040
    EmptyData = 0x00000020
    CompressedZlib = 0x00000002
    CompressedLzo = 0x00000010
    CompressedLzx = 0x00000080
    

    If StoredInSeparateFile bit is set, the TextureFileCacheName property defined in DefaultPropertiesList is used to obtain the name of the tfc file (texture cache file) - usually it's 'Textures'. Furthermore, externally stored mipmaps are compressed (usually lzo), so expect CompressedLzo bit being set too. For such mipmaps ElementCount corresponds to uncompressed size, BulkDataSizeOnDisk corresponds to compressed size and BulkDataOffsetInFile corresponds to Textures.tfc absolute offset. SizeX and SizeY contain corresponding image dimensions.

     

    If StoredAsSeparateData bit is set, the image data are stored in the same package, but outside of this object serialized data.

     

    If EmptyData bit is set, both BulkDataSizeOnDisk and BulkDataOffsetInFile are set to 0xFFFFFFFF and ElementCount is set to zero.

     

    There are three interesting parameters defined in DefaultPropertiesList: Format, LODBias and NeverStream. Format is always present and defines texture block compression method. XCOM mostly uses BC1 and BC3 (DXT1/DXT5). LODBias is... well... LOD bias. It defines the number of textures to drop, effectively allowing to limit texture resolution. More info on textures and their properties can be found here and here. For modding purposes it's important to know that for, say, 2k texture you should have 12 mips defined, but LODBias set to 2 will limit the resolution to 512 and cause the first two mips to be dropped (the corresponding BulkData will be empty). Adding those mips back won't do anything unless you also mod LODBias to zero. Be careful here, though, as the engine calculates the final LODBias as a sum of several parameters (see the links above), so do not assume the LODBias value based on Texture2D properties only! NeverStream boolean set to true forbids the engine from streaming the texture out of memory. Mipmaps for such textures are usually fully embedded in a startup package (all the mipmaps for all the LOD levels).

     

    So, with this knowledge in mind, what's the problem of modding textures? Well, it's how the cooking is done.

     

    The most frequently used textures are not streamable and embedded into just one startup package. Those are easy enough to mod by just replacing their mipmap data. But lots of textures (map tiles, for example) end up being cooked into a dozen of different packages with low-res mips being embedded directly (usually up to 512) and hi-res ones being kept in an external tfc (Textures.tfc). It's done to speed up the loading process. So if we want to alter such a texture, we need to alter all the packages it resides in, plus its Textures.tfc data. Which is... quite a task at a first glance.

     

    And this is where we made a mistake 5 years ago: making a PatcherGUI patch file to mod just one texture is a pure pain and it becomes unrealistic if we want to change dozens of textures. And no, Drakous79, my friend, upk lists won't help here ;) What we need is a completely new tool.

     

    On the paper the process is simple enough: take an existing texture, export it to a dds file with all the mipmaps, edit and re-import. We can move/resize export object data if needed, we can change default properties, we can even alter the TextureFileCacheName to point at something else (Texture2D is an obvious choice as the property is a NameProperty and thus has to be present in the name table). But we also need to be sure we do it for all the packages that use this texture.

     

    Currently, I'm working on a set of tools that allow mass exporting/importing of textures. The first one, ExportTexturesToDDS, is 99.9% ready and can export individual textures or the whole game into dds file(s) creating an inventory file along the way. The inventory file is a simple csv (comma-separated values) file that holds the full names of all the textures found with the list of packages they were found in. Using this list another tool, ImportTexturesFromDDS, can take all the textures you feed it and import them back into all the corresponding packages. At this point ImportTexturesFromDDS can already work with individual textures and mass-import is what I'm working on.

     

    Since we can potentially go to higher resolutions, re-importing textures into the existing Textures.tfc doesn't seem to be the way here. Using a new custom tfc file is a better solution. But the problem is that we're working with cooked packages and while modding and testing stuff we're doing it one texture at a time, which complicates things due to Textures.tfc being just a bunch of "dumb" data with no additional information on what they belong to. To address the issue I came up with a custom tfc format that stores metadata on embedded mipmaps in a separate field.

     

    Vanilla Textures.tfc format:

    C1 83 2A 9E "magic" followed by lzo compressed blocks
    alignment bytes (zero-padding, not used by xcom, used by batman)
    C1 83 2A 9E "magic" ... etc
    

    Custom Texture2D.tfc format:

    2B 42 91 53 "magic"
    4 bytes of BlockOffset
    4 bytes of BlockSize
    4 bytes of NextBlockOffset
    a list of inventory entries
    C1 83 2A 9E "magic" followed by lzo compressed blocks
    ...
    

    Each inventory entry has the following data:

    4 bytes of BulkDataSizeOnDisk
    4 bytes of BulkDataOffsetInFile
    4 bytes of ObjectNameLength
    ObjectNameLength bytes of FullObjectName
    

    Max block size is 0x8000. When the limit is reached, the tool makes another block and writes its offset to the NextBlockOffset field of the previous block.

     

    The resulting macro-structure of a custom tfc looks like this:

    [metadata block #1]
    [compressed mipmap #1]
    [compressed mipmap #2]
    ...
    [metadata block #2]
    [compressed mipmap #N]...

    Metadata are ignored by the game itself, but are used by the importer to avoid hi-res texture duplication when importing a new texture on a per-texture per-package basis.

     

    That's it. I can't promise I'm back, but I will sure finish my work on texture exporting/importing. Linux/Mac users will finally be able to play with military retexture pack :)

  4. Was this problem resolved for a new site layout? It was bugging me for a long time, because PayPal page for my native language doesn't provide a language switch and I really don't want to focus on donations in comments section, much less on the description page. Not to mention that donation talks are forbidden by the rules.

  5. Zyxpsilon, I don't want to hijack this topic :smile:, so, please, create another one or ask through PM/Steam. Short answer is: rotation angles are actual angles (per second), but they are restricted by interpolation speed. So if you want to change rotation speed, you need to change both CAMERA_ROTATION_SPEED and interpolation speed. Same goes for zoom in/out speed. Also, the mod uses exponential smoothing to calculate per second values for both rotation and zoom, so it will look like "stepping" for the first few seconds, but will rotate/zoom smoothly after all the values stabilize.

  6.  

    There's "Unequip all weapons" code in place now, so no mods are necessary to remove weapons from soldiers. Considering that basically all mods are broken right now, these mods will probably be removing their unequip buttons soon. There's also unequip buttons in the individual soldier screens, so you can do this without being on the squad loadout/selection screen.

    Sadly they've implemented something similar to the first version of Strip Weapons mod and the button simply equips default weapons to all soldiers. So, I won't be taking down my mod, because latest version removes only actually upgraded weapons and leaves customized but not upgraded weapons in place. But I will update it to use native button instead of adding new one.

     

    Also, it looks like ini files are no longer merged, hence the problem with old ini under My Douments containing ModClassOverrides entries. In case of any update it's best to just delete all your ini files and let the game to rebuild them from scratch.

  7. Shame on me, because you did warn me about this. :) But somehow I totally forgot it and ended up going through all the pain myself. :)

     

    In most cases locals do well, I just tried to optimize the code a bit, but ended up adding even more checks after that failure. :)

  8. As some of you might know, I had a problem with Strip Primary Weapons mod: UI was freezing upon returning from a mission. Looks like I fixed it, but I still can't understand what was it.

     

    Current mod script (relevant part):

     

     

    class UIScreenListener_UISquadSelect_StripPrimaryWeapons extends UIScreenListener
        DependsOn(XComGameState_Unit);
    
    event OnInit(UIScreen Screen)
    {
        UISquadSelect(Screen).SetTimer(2.5f, false, nameof(AddStripWeaponsHelp), self);
    }
    
    simulated function AddStripWeaponsHelp()
    {
        local UIScreenStack ScreenStack;
        local UISquadSelect SquadSelect;
        local XComHQPresentationLayer HQPres;
    
        ScreenStack = `SCREENSTACK;
        SquadSelect = UISquadSelect(ScreenStack.GetScreen(class'UISquadSelect'));
    
        if(SquadSelect == none || SquadSelect.bLaunched)
        {
            return;
        }
    
        HQPres = `HQPRES;
    
        if(HQPres != none)
        {
            if(ScreenStack.IsTopScreen(SquadSelect) && HQPres.m_kAvengerHUD.navHelp.m_arrButtonClickDelegates.Find(OnStripWeapons) == -1)
            {
                HQPres.m_kAvengerHUD.NavHelp.AddCenterHelp("MAKE WEAPONS AVAILABLE", "", OnStripWeapons, false, "Remove upgraded primary weapons from all soldiers NOT selected for current mission duty");
            }
            SquadSelect.SetTimer(1.0f, false, nameof(AddStripWeaponsHelp), self);
        }
    }
    
    simulated function OnStripWeapons()
    {
        // ...
    }
    
    defaultProperties
    {
        ScreenClass = UISquadSelect
    }
    

     

    Old code (relevant part):

     

     

    class UIScreenListener_UISquadSelect_StripPrimaryWeapons extends UIScreenListener
        DependsOn(XComGameState_Unit);
    
    var UISquadSelect ParentScreen;
    var UINavigationHelp NavHelp;
    
    event OnInit(UIScreen Screen)
    {
        ParentScreen = UISquadSelect(Screen);
        NavHelp = `HQPRES.m_kAvengerHUD.NavHelp;
        ParentScreen.SetTimer(1.0f, true, nameof(AddStripWeaponsCenterHelp), self);
    }
    
    event OnReceiveFocus(UIScreen Screen)
    {
        ParentScreen.ClearTimer(nameof(AddStripWeaponsCenterHelp), self);
        ParentScreen.SetTimer(1.0f, true, nameof(AddStripWeaponsCenterHelp), self);
    }
    
    event OnLoseFocus(UIScreen Screen)
    {
        ParentScreen.ClearTimer(nameof(AddStripWeaponsCenterHelp), self);
    }
    
    event OnRemoved(UIScreen Screen)
    {
        ParentScreen.ClearTimer(nameof(AddStripWeaponsCenterHelp), self);
    }
    
    simulated function AddStripWeaponsCenterHelp()
    {
        if(ParentScreen.bLaunched)
        {
            ParentScreen.ClearTimer(nameof(AddStripWeaponsCenterHelp), self);
            return;
        }
        if( navHelp.m_arrButtonClickDelegates.Find(OnStripWeapons) == -1 )
        {
            `HQPRES.m_kAvengerHUD.NavHelp.AddCenterHelp("MAKE WEAPONS AVAILABLE", "", OnStripWeapons, false, "Remove upgraded primary weapons from all soldiers NOT selected for current mission duty");
        }
    }
    
    simulated function OnStripWeapons()
    {
        // ...
    }
    
    defaultProperties
    {
        ScreenClass = UISquadSelect
    }
    

     

    Error log:

     

     

    [1521.70] Log: ###### OnlineEventMgr waited 0.00 seconds for saves to complete
    [1521.78] Log: SkeletalMeshActor_2 is attached to XComHumanPawn_549 which is in another level. Using actor's location as collision center.
    [1521.78] Log: SkeletalMeshActor_6 is attached to XComHumanPawn_553 which is in another level. Using actor's location as collision center.
    [1521.79] Log: Bringing up level for play took: 0.017433
    [1521.79] ScriptWarning: Accessed None 'PlayerReplicationInfo'
    XComHeadquartersGame Avenger_Root.TheWorld:PersistentLevel.XComHeadquartersGame_4
    Function Engine.GameInfo:PostSeamlessTravel:0198
    [1521.79] ScriptWarning: Accessed None 'PlayerReplicationInfo'
    XComHeadquartersController Avenger_Root.TheWorld:PersistentLevel.XComHeadquartersController_4
    Function Engine.PlayerController:SeamlessTravelFrom:001F
    [1521.79] ScriptWarning: Accessed None 'PlayerReplicationInfo'
    XComHeadquartersController Avenger_Root.TheWorld:PersistentLevel.XComHeadquartersController_4
    Function Engine.PlayerController:SeamlessTravelFrom:0053
    [1521.79] ScriptWarning: Accessed None 'PlayerReplicationInfo'
    XComHeadquartersController Avenger_Root.TheWorld:PersistentLevel.XComHeadquartersController_4
    Function Engine.PlayerController:SeamlessTravelFrom:00B1
    [1521.82] ScriptWarning: Accessed None 'PlayerReplicationInfo'
    XComTacticalController Avenger_Root.TheWorld:PersistentLevel.XComTacticalController_5
    Function Engine.PlayerController:Dead.EndState:0046
    [1521.85] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.85] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.85] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.85] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.85] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.85] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1521.85] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateEvents:00C8
    [1521.85] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateEvents:00DD
    [1521.89] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0027
    [1521.89] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0098
    [1521.89] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:ShowMouseCursor:004F
    [1521.89] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:ShowMouseCursor:00A7
    [1521.89] ScriptWarning: Accessed None
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:ShowMouseCursor:00BB
    [1521.89] ScriptWarning: Accessed None
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:ShowMouseCursor:00D0
    [1521.89] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0027
    [1521.89] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0098
    [1521.89] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.89] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.89] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.89] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.89] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.89] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1521.91] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.91] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.91] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.91] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.91] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.91] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1521.93] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.93] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.93] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.93] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.93] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.93] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1521.95] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.95] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.95] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.95] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.95] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.95] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1521.96] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.96] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.96] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.96] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.96] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.96] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1521.98] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0027
    [1521.98] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0098
    [1521.98] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1521.98] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1521.98] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1521.98] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1521.98] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1521.98] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1522.00] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1522.00] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1522.00] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1522.00] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1522.00] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1522.00] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1522.01] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1522.01] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1522.01] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1522.01] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1522.01] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1522.01] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1522.03] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1522.03] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1522.03] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1522.03] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1522.03] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1522.03] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1522.05] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1522.05] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1522.05] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1522.05] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1522.05] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1522.05] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1522.07] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0027
    [1522.07] ScriptWarning: Accessed None 'Movie'
    UIMouseCursor Avenger_Root.TheWorld:PersistentLevel.UIMouseCursor_5
    Function XComGame.UIMouseCursor:UpdateMouseLocation:0098
    [1522.07] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1522.07] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1522.07] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1522.07] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3
    [1522.07] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00B1
    [1522.07] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:Tick:00C6
    [1522.09] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:005F
    [1522.09] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:0074
    [1522.09] ScriptWarning: Accessed None 'm_kGameCore'
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01BE
    [1522.09] ScriptWarning: Accessed None
    XGMissionControlUI Avenger_Root.TheWorld:PersistentLevel.XGMissionControlUI_3
    Function XComGame.XGMissionControlUI:UpdateClock:01D3

     

    ... and 30k more of the same line. How it's even related to different UI listener, which wasn't even executed?

     

    Anyway, I tried everything and in the end removing class member variables and sticking to locals seemed to help. I'm puzzled here. Really. I had log outputs literally everywhere and I'm sure my code wasn't even executed.

  9. It will be fully configurable. I mentioned that timers are set as kismet variables in map files on Steam and someone immediately released the mod for this. Brave soul, I should say, as personally I wasn't ready to edit every special mission map. :)

  10. Tested this super hack with tactical layer and was able to access kismet data. But found another funny bug in the process. :)

     

    Here's my tactical hook:

     

     

     

    class UIScreenListener_TacticalHUD_TacticalHook extends UIScreenListener;
    
    event OnInit(UIScreen Screen)
    {
        local WorldInfo wInfo;
        local Sequence mainSequence;
        local array<SequenceObject> SeqObjs;
        local int i;
       
        wInfo = `XWORLDINFO;
        mainSequence = wInfo.GetGameSequence();
    
        `Log("########################################## TacticalHook ##########################################");
        if (mainSequence != None)
        {
            `Log("GameSequence = " $ mainSequence);
            mainSequence.FindSeqObjectsByClass( class'SeqVar_Int', true, SeqObjs);
            if(SeqObjs.Length != 0)
            {
                `Log("Named vars found");
                for(i = 0; i < SeqObjs.Length; i++)
                {
                    if(InStr(string(SequenceVariable(SeqObjs[i]).VarName), "TurnsRemaining") != -1)
                    {
                        `Log("Variable found: " $ SequenceVariable(SeqObjs[i]).VarName);
                        `Log("IntValue = " $ SeqVar_Int(SeqObjs[i]).IntValue);
                    }
                    if(InStr(string(SequenceVariable(SeqObjs[i]).VarName), "DefaultTurns") != -1)
                    {
                        `Log("Variable found: " $ SequenceVariable(SeqObjs[i]).VarName);
                        `Log("IntValue = " $ SeqVar_Int(SeqObjs[i]).IntValue);
                    }
                }
            }
        }
    }
    
    defaultProperties
    {
        // Leaving this assigned to none will cause every screen to trigger its signals on this class
        ScreenClass = UITacticalHUD
    }
    

     

     

     

    So many unnecessary things there because they've named a variable "Timer.TurnsRemaining", but this is actually an illegal value for name variable. :) So an attempt to find it by name freezes the game.

  11. Major mods are free to modify base game packages, small mods are bigger problem.

     

    I was thinking about how to properly make mission timers configurable. I know how to access kismet variables and that's still not a problem in XCOM2. But there's no tactical hook for doing such things and we can't override kismet related classes nor core gameplay classes. Probably something else we can't override either. :smile: So I decided to make a hidden ability and make it a listener to an event. With no luck, as many others, because we can't silently add an ability to soldier. Now I decided to try it with cheater item. :smile: Not that I need timers, but it was a good problem to learn from.

     

    Hex editing was actually easier :smile:

×
×
  • Create New...