Jump to content

TexMod == SwapImg ! (Code Breakthrough)


Zyxpsilon

Recommended Posts

It might be early in the concept process but with some help (again) from InfectedM, i was able to determine that swapping (almost any) default textures for custom versions of our own is as easy as creating a dedicated UIMCController override.

 

While i was trying to further enhance the qUIck_RCP mod by providing GTS upgrade images to match with their corresponding Classes Icons... this tiny variation of a previous code did everything necessary in one big swoop of direct processing that i nick-named "SwapImg";

class UIMCController_qUIckRG4 extends UIMCController;

simulated function QueueString(string Param)
{
    Param = Repl(Param, "img:///UILibrary_StrategyImages.GTS.", "img:///qUIck_GTS4_UILibrary.GTS.");
    Param = Repl(Param, "img:///UILibrary_Common.rank_", "img:///qUIck_RCP_UILibrary.rank_");
    Param = Repl(Param, "img:///UILibrary_Common.psirank_", "img:///qUIck_RCP_UILibrary.psirank_");
    super.QueueString(Param);
}

I won't (have to, i guess) go into much more complex details, but frankly to me.. it simply & swiftly does the right job!

 

-- As long as you can identify the correct Pathing of targeted objects (mostly declared in any given UC scripts that transfer such assets to the GFX/Flash infra-structure) and would programmatically fiddle with the actual trajectory (or various principles as need be) of such files... your tiny MCController stack of instructions will just super.Queue whatever Images (found and Repl_aced) in its symbiotic looped tasks.

 

http://s32.postimg.org/7katyqq1h/Example_Swap_Img.png

 

-- Tadaam, done !!!

 

Enjoy your very own favorite HUD+UI variations... and get those creativity neurones running wildly on my behalf. :D

Link to comment
Share on other sites

1) You mean like "Model textures".. not sure how these are handled by the tactical Engine but if they all have a proper referencing pattern that can point at a steady path and the MC process can still control both the default-file & whatever else is being invoked in its place, i think it might work. The core UIMCController UC_script has a few more types of instructions that can deal with different assets although there isn't any simple ways to verify if the data flow (for Models or other stuff) would somehow react as intended.

 

2) Dunno yet.. but i suspect that if some indirect MOD generic component is created to stand as a placeholder for various HUD-UI elements (basicly the newest LWS-Toolbox principles and/or with Tuple's transit values structure). That impervious solution might still need to be designed though.. as we all know, a common device with upwards compatibilty features would become essential in the long-term. Again, Batista (or RyanMcFall) would be much more trustworthy of positive facts than i could ever decipher in their coded intentions. The trick here i guess... is to convince people like Amineri or TrackTwo to extrapolate furthermore on the real (rational) potential of this wacky stuff. That takes minimal skills which i just don't have, sorry.

 

I can still smell the burning magic oven that tiny code would trigger though. :wink:

Edited by Zyxpsilon
Link to comment
Share on other sites

Veerrry interesting idea. Basically intercepting/overriding the interface between the UScript and the Flash code to intercept imagepath string and replace them.

 

I don't believe that this will for for retexturing 3D models, though. 3D models don't use imagepaths, and by default their textures support multiple LOD. Typically to change a model texture at run-time you have to get into the MIC (material instance constant) and change the appropriate parameter with a command like :

MIC.SetTextureParameterValue('FacePaintDiffuse', FacePaintContent.texture);

Textures on materials are incredibly optimized by the cooking process, with everything above 64x64 (I think) pixels being stripped from the package and being placed into a Texture File Cache (tfc). The TFC is optimized for streaming from linear media (e.g. BD/DVD). Textures get pulled at run-time from the TFC via an offset table into the TFC.

 

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

 

This method as demonstrated for replacing paths works, but it may come at a heavy performance cost -- I don't think it will scale well.

 

It is intercepting *every* QueueString call to the Flash. This includes every plain-old text and HTML formatted string being passed to display as actual text, as well as imagepaths that the Flash uses to load the image from the Unreal package. Then as the number of replacements grows, each possible replacement has to be tested against every QueueString call. Finally, this is doing a Repl operation on a (potentially) long string, which is not a constant-time operation either.

 

Overall I'd say this is somewhere between O(n^2) and O(n^3).

 

Another issue is enabling this for multiple mods. Since this relies on a class override, only one mod could do this. It is possible to address using tracktwo's Tuple class and a TriggerEvent, however.

 

So I'd recommend the following :

1) Do an initial filter with an equivalent of StartsWith to check if the string begins with "img:///" which will identify it as an imagepath or not more quickly, before having to go through the Repl operation.

2) Add a TriggerEvent inside the filter to allow other mods to hook up to the same functionality.

Something like the code:

struct StringReplacement
{
    var string SearchFor;
    var string ReplaceWith;
};

var config array<StringReplacement> PathReplacements;

simulated function QueueString(string Param)
{
    local StringReplacement Path;
    local LWTuple StringTuple;

    if(Param.Left(4) == "img:")
    {
        foreach default.PathReplacements(Path)
        {
            Repl(Param, Path.SearchFor, Path.ReplaceWith);
        }
        StringTuple = new class'LWTuple';
        InitTuple(StringTuple, Param);
        `XEVENTMGR.TriggerEvent('OnOverrideImagePath', StringTuple, self);
        Param = StringTuple.Data[0].s;
    }
    super.QueueString(Param);
}

simulated function InitTuple(out LWTuple StringTuple, string Param)
{
    StringTuple.Id = 'OverrideImagePath';
    StringTuple.Data.Add(1);
    StringTuple.Data[0].kind = LWTVString;
    StringTuple.Data[0].s = Param;
}

With this, any other mod that wanted to replace imagepaths could set up a listener via RegisterForEvent, and do a similar set of Repl operations on the Data[0].s value of the Tuple.

 

Anyhow, my thoughts on this -- it looks promising!

Link to comment
Share on other sites

Thanks for the heads-up Amineri.

 

This is the kind of technical explanation that InfectedM could certainly seek his teeth into and possibly exploit much better than i would.

 

The need for the above version was dictated by having two different pathways to individual "groups" of images; Rank-Icons & GTS-Upgrades --- in the same MOD structure and files (qUIck_RCP).

InfectedM made it clear that only one custom MCController trick can be used within *A* mod. Makes senses and i also presumed the exclusivity trick you are referring to.

 

To me, the essential stands in a single reason; as long as it does what my mod(s) require, it's good and fairplay unless proven unstable or tragically incompatible with too many other modding situations by community stuff. I'd certainly be willing to absorb and comply with some optimal code alternative (like what you're suggesting). Trick is.. it would probably prove to be too challenging for my skillset (UC programming, etc).

 

Sooooo.. if "Interception" methods are too risky -- we'll have to find better ways, that's a given. Yet, the current state of the mod -- works fine! Unless InfectedM (( Nexus member=mbleichner )) can come up with some code that follows up on your theory (and would still.. work fine), i'll just be happy to bend over to such best programming principles.

Link to comment
Share on other sites

  • 2 weeks later...

Sorry for the late bump, but i seriously need to get this off my mind to rationalize current plans for (much) more Swapping later.

 

@Amineri please (or anyone else that could explain or inform)...

 

Referring to that rather simplistic line from the initial UIMCController above;

Param = Repl(Param, "img:///UILibrary_StrategyImages.GTS.", "img:///qUIck_GTS4_UILibrary.GTS.");

If i were to just create a new entry into that generic mini-loop like this (or even in some entirely new Class from within another Mod)..

Param = Repl("img:///UILibrary_Common.Head_Shen", "img:///qUIck_FIX_UILibrary.Head_Shen");

http://s32.postimg.org/ec7pvoe1d/Head_Shen.png ... default "Purplish" version replaced with that one!

 

Would it actually grab that single IMG file without considerations to whatever extra param if not there??

It's a weird technical instruction that i just can't find any coding reference for.

 

Next would be that too -- if possible anyway;

 

 

 

http://s32.postimg.org/om010or9x/SAVE_Screen_Test_w_Logo_Stack.png

 

** Instead of the greyish Logo file "Xcom_default".

 

 

 

A dream to have, task(s) to work at.. AFAIC. :D

Edited by Zyxpsilon
Link to comment
Share on other sites

Well.. finally after some careful thoughts and a quick Chat session with InfectedM earlier this afternoon, i think i (ahem' .. HE & we) will heed your advice (as suggested by your example above) on creating the TriggerEvent + Tuple + Hook(s) combo solution, Amineri.

 

He was sharing the overall perspective of your "principles" and how that stuff should potentially solve various issues with other mods while neatly offering compatible assets (or reserved features) for the long-term. Although i'm not heavily skilled like you both, i have to agree the stable concept (of such interacting hybrid-dispatch methods) is very appealing if not important.

 

With that many custom Images (etc) to swap somewhat & almost anywhere at will... i'd say it's far better to have solid (versatile) code from the get-go.

 

Stay-tuned.. we'll get there. And, thanks again. :wink:

Edited by Zyxpsilon
Link to comment
Share on other sites

PS... @Amineri,

 

InfectedM has just completed the whole scripts for the above. Two of them.. 1) Base UIMCController generic receiver code & 2) Various customizable transmitter(s) that supply pathing data for necessary Image(s) swapping -- at will.

 

I'll PM you these files to get some feedback and/or opinions, suggestions, hints, etc. I feel we're onto something important here and i certainly don't want to wreck it all with silly mistakes or lack of extra (necessary) components.

Link to comment
Share on other sites

  • 2 weeks later...

Not sure yet, since i haven't explored the whole variety of Flash components in this game and their various dependencies.

 

These are all assembled in relatively complex manners while a few should be compatible with SwappImg (even if with a sub-function assigned to such strict input flows) since it does make use of a Super.QueueString (param) call.

 

We do that in a Base + Extension combo Mod.

 

Here's the first Base-code;

// SwappImgBase = Allows some indirect "TexMod" capabilities via MC-Hooks defined by
//                  pathing Extension(s) declared in any given external UIListener(s) Script
// Author == InfectedM (Adapted by Zyxpsilon)
//
class SwappImg_UIMCController_Base extends UIMCController;

simulated function QueueString(string Param)
{
    local WebApplication Helper;

    if (Left(Param, 4) == "img:") {
        Helper = new class'WebApplication';
        Helper.Path = Param;
        
        `XEVENTMGR.TriggerEvent('ProcessImageOverrides', Helper, self);
        Param = Helper.Path;
        `Log("After Replacement:" @ Param);
    }
    
    super.QueueString(Param);
}

And some early test Extension-code (Listener) i've adapted from InfectedM's source to put my fleshy LilyShen & it worked fine (It's a called popup too, btw...)

class SwappImgFIX_UIScreenListener_Extension extends UIScreenListener;

event OnInit(UIScreen Screen)
{
    local Object ThisObj;
    ThisObj = self;
    `XEVENTMGR.RegisterForEvent(ThisObj, 'ProcessImageOverrides', ApplyImageOverrides);
}

simulated function EventListenerReturn ApplyImageOverrides(Object EventData, Object EventSource, XComGameState GameState, Name EventID)
{
    local WebApplication Helper;
    Helper = WebApplication(EventData);
    
    Helper.Path = Repl(Helper.Path, "img:///UILibrary_Common.Head_Shen", "img:///qUIck_FIX_UILibrary.Head_Shen");
    Helper.Path = Repl(Helper.Path, "img:///UILibrary_Common.Xcom_default", "img:///qUIck_FIX_UILibrary.Xcom_default");
//  Helper.Path = Repl(Helper.Path, "img:///gfxComponents.XCOM2_Logo_small", "img:///qUIck_FIX_gfxComponents.XCOM2_Logo_small");
    
    return ELR_NoInterrupt;
}

Xcom_default -- an alternate "Saves/Box" failed.. but that might be from the Layer/Stacks gimmick i've mentionned in another thread.

 

The XCOM2_Logo_small attempt was directed at a gfxComponents upk.. i expected that to somehow skip the ARC referencing snatch. But i'm 75% sure a different Event could serve as indirect Objects' tagger in that case for a weird reason; it's just the opening title screen/menu pulled from Shell assets including gfx scripts & a gauntlet of sprites, etc. :wink:

Making the rational connection, yet? :geek:

 

The minimal principle is that the core class method (( SwappImgBase )) mod '''must''' run in the background as a generic receiver while (( SwappImg???_UIScreenListener_Extension )) transmits the custom Library of Repl-aceable Target-Paths + CustomImage-Paths.

 

In terms of specific Flash resources, the trick would be to "fool" the engine into MC'ing from a controllable virtual space -- i think.

AFAIC.. entirely possible.

 

PS; qUIck_RCP is currently using that combo model during my games & everything is flawless -- from Rank-Icons to GTS custom images. I haven't released it yet to the Workshop because i would need a tricky "analysis report" from Amineri while a formal document/readme still has to be written up -- correctly. :D

Edited by Zyxpsilon
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...