Drakous79 Posted September 5, 2014 Share Posted September 5, 2014 :smile: Maybe ... what if another class is extended instead of XComMod? class TestMod extends XComGameInfo; simulated function CacheMods() { local XGStrategy GameCore; super.CacheMods(); GameCore = XComHeadquartersGame(class'Engine'.static.GetCurrentWorldInfo().Game).GetGameCore(); GameCore.HQ().AddResource(0, 100000); return; } And config entry listed in: // DefaultEngine.ini [Engine.ScriptPackages] +NonNativePackages=TestModDoes it work? I don't have UDK installed yet. The first step is compiled script (possible with the correct version of UDK and dummy scripts at the moment). Is the line in DE.ini enough to do the next step and load it to the game? Btw is there a way how to reference functions in new packages from existing code? Link to comment Share on other sites More sharing options...
wghost81 Posted September 5, 2014 Author Share Posted September 5, 2014 (edited) @wghost81: since you referred to your screenshot when talking about the XComMod class, I added it to the tutorial under a CCA-SA license. Please let me know if that's okay with you.Yes, it's OK. And for the any future content too. I wasn't thinking about naming yet, but I agree about creating some sort of naming conventions. UE convention for Mutators is Mutator_ClassName. Drakous79, objects must be created first to work in game. We can't just add a new class or extend any of the existing classes. Mutators are created and activated at special conditions and one of those conditions allows to replace newly created object with any other object, i.e. inject out new class into the game. But, you choose a good example. :wink: GameInfo class is a class which holds game rules. Default GameInfo class is assigned through DefaultGame.ini, section Engine.GameInfo:DefaultGame=XComGame.XComStartupGameInfo Since I can't pass mutator info via command line (as I understand, it only works for Editor, but I may be wrong), I decided to extend XComStartupGameInfo and add a code to work with Mutators via DefaultGame.ini. I will make a new class, say, XComStartupGameInfo_Mod, replace DefaultGame parameter and see what happens. :smile: Since we can't re-cook existing packages ATM, only way to reference objects of a new package is to add those objects into ImportTable. Patcher has this functionality. But the whole idea of Mutators is to create mods without a need to rewrite original code. :wink: Edited September 5, 2014 by wghost81 Link to comment Share on other sites More sharing options...
Drakous79 Posted September 5, 2014 Share Posted September 5, 2014 Ah :) What I'd like to do is to execute some code before or after native function call. So when is the native function called, my code, which contains super.NativeFunction, is executed instead. Link to comment Share on other sites More sharing options...
wghost81 Posted September 5, 2014 Author Share Posted September 5, 2014 (edited) I can confirm that renaming packages is not necessary: XCOM loads .u packages as well. Package extensions are defined in BaseEngine.ini, section Core.System:Extensions=upk Extensions=u Extensions=umap I've also tried to make Editor use existing XCOM script packages, but with no luck. Seems, the problem is as with any other programming language: at least definition of all objects referenced is needed. Separate functions can't be overridden with Mutators. But you can override an entire class, including that particular function. At least, I think so. :smile: Edited September 5, 2014 by wghost81 Link to comment Share on other sites More sharing options...
ellatan Posted September 5, 2014 Share Posted September 5, 2014 I wish I could help with this, it's really exciting. Following this closely. Link to comment Share on other sites More sharing options...
wghost81 Posted September 5, 2014 Author Share Posted September 5, 2014 I'm not an expert on UDK, so any investigation on possible using of existing XCOM packages will be of a great help. I've used only script compiler so far, even one look at the editor main window drives me crazy. :smile: Link to comment Share on other sites More sharing options...
wghost81 Posted September 5, 2014 Author Share Posted September 5, 2014 I had no luck replacing XComStartupGameInfo. DefaultGame is either completely ignored or it simply can't change the fact, that XComHeadquartersGame and XComTacticalGame are not related to my new class at all. :smile: I'll resort to good-old hex-editing then :smile: and try to modify Engine.GameInfo to configure Mutators via DefaultGame.ini. Link to comment Share on other sites More sharing options...
wghost81 Posted September 5, 2014 Author Share Posted September 5, 2014 (edited) I was able to make ini-configurable Mutator enabler. Here's PatcherGUI mod (use v.5.2.1 to install, previous version has a bug with adding some export objects): UPK_FILE=XComGame.upk [ADD_NAME_ENTRY] <%u 11> // Length <%t "AddMutator"> // Name <%u 0x00000000> // flags L <%u 0x00070010> // flags H [ADD_NAME_ENTRY] <%u 13> // Length <%t "MutatorClass"> // Name <%u 0x00000000> // flags L <%u 0x00070010> // flags H [ADD_NAME_ENTRY] <%u 12> // Length <%t "MutatorName"> // Name <%u 0x00000000> // flags L <%u 0x00070010> // flags H [ADD_NAME_ENTRY] <%u 13> // Length <%t "MutatorNames"> // Name <%u 0x00000000> // flags L <%u 0x00070010> // flags H [ADD_EXPORT_ENTRY] <Core.ArrayProperty> // Type <NullRef> // ParentClassRef <Class.XComGameInfo> // OwnerRef <MutatorNames> // NameIdx <NullRef> // ArchetypeRef <% u0x00000000> // flags H <% u0x00070004> // flags L <%u 44> // serial size <%u 0> // serial offset <%u 0> // export flags <%u 0> // net objects count <%u 0> // GUID1 <%u 0> // GUID2 <%u 0> // GUID3 <%u 0> // GUID4 <%u 0> // unknown [ADD_EXPORT_ENTRY] <Core.StrProperty> // Type <NullRef> // ParentClassRef <XComGameInfo.MutatorNames> // OwnerRef <MutatorNames> // NameIdx <NullRef> // ArchetypeRef <% u0x00000000> // flags H <% u0x00070004> // flags L <%u 40> // serial size <%u 0> // serial offset <%u 0> // export flags <%u 0> // net objects count <%u 0> // GUID1 <%u 0> // GUID2 <%u 0> // GUID3 <%u 0> // GUID4 <%u 0> // unknown OBJECT=XComGameInfo.MutatorNames REL_OFFSET=16 // skip PrevObjRef + Empty DefaultProperties List + NextObjRef [MODDED_CODE] <%s 1> // ArrayDim <%s 0> // ElementSize <%u 0x00404000> // flags L: Config + NeedCtorLink <%u 0x00000000> // flags H <None> // CategoryIndex <NullRef> // ArrayEnumRef <XComGameInfo.MutatorNames.MutatorNames> // InnerObjRef OBJECT=XComGameInfo.MutatorNames.MutatorNames REL_OFFSET=16 // skip PrevObjRef + Empty DefaultProperties List + NextObjRef [MODDED_CODE] <%s 1> // ArrayDim <%s 0> // ElementSize <%u 0x00404000> // flags L: Config + NeedCtorLink <%u 0x00000000> // flags H <None> // CategoryIndex <NullRef> // ArrayEnumRef [ADD_EXPORT_ENTRY] <Core.ClassProperty> // Type <NullRef> // ParentClassRef <XComGameInfo.InitGame> // OwnerRef <MutatorClass> // NameIdx <NullRef> // ArchetypeRef <% u0x00000000> // flags H <% u0x00070004> // flags L <%u 48> // serial size <%u 0> // serial offset <%u 0> // export flags <%u 0> // net objects count <%u 0> // GUID1 <%u 0> // GUID2 <%u 0> // GUID3 <%u 0> // GUID4 <%u 0> // unknown OBJECT=XComGameInfo.InitGame.MutatorClass REL_OFFSET=16 // skip PrevObjRef + Empty DefaultProperties List + NextObjRef [MODDED_CODE] <%s 1> // ArrayDim <%s 0> // ElementSize <%u 0x00000000> // flags L <%u 0x00000000> // flags H <None> // CategoryIndex <NullRef> // ArrayEnumRef <Core.Class> // OtherObjRef <Engine.Mutator> // ClassObjRef [ADD_EXPORT_ENTRY] <Core.StrProperty> // Type <NullRef> // ParentClassRef <XComGameInfo.InitGame> // OwnerRef <MutatorName> // NameIdx <NullRef> // ArchetypeRef <% u0x00000000> // flags H <% u0x00070004> // flags L <%u 40> // serial size <%u 0> // serial offset <%u 0> // export flags <%u 0> // net objects count <%u 0> // GUID1 <%u 0> // GUID2 <%u 0> // GUID3 <%u 0> // GUID4 <%u 0> // unknown OBJECT=XComGameInfo.InitGame.MutatorName REL_OFFSET=16 // skip PrevObjRef + Empty DefaultProperties List + NextObjRef [MODDED_CODE] <%s 1> // ArrayDim <%s 0> // ElementSize <%u 0x00400000> // flags L: NeedCtorLink <%u 0x00000000> // flags H <None> // CategoryIndex <NullRef> // ArrayEnumRef OBJECT=XComGameInfo.InitGame:AUTO [BEFORE_CODE] //CacheMods() 1B <CacheMods> 16 [AFTER_CODE] //foreach MutatorNames(MutatorName) 58 01 <@MutatorNames> 00 <.MutatorName> 00 4A [@IP] //MutatorClass = class<Mutator>(DynamicLoadObject(MutatorName, class'Class')) 0F 00 <.MutatorClass> 13 <Engine.Mutator> 1C <Core.Object.DynamicLoadObject> 00 <.MutatorName> 20 <Core.Class> 4A 16 //if(MutatorClass != none) 07 [@IN] 77 00 <.MutatorClass> 2A 16 //AddMutator(MutatorName, true) 1B <AddMutator> 00 <.MutatorName> 27 16 [#IN] 31 [#IP] 30 //CacheMods() 1B <CacheMods> 16 With this mod installed, Mutators can be added via DefaultGame.ini:[XComStrategyGame.XComHeadquartersGame] +MutatorNames=XComMutator.MyMutator [XComGame.XComTacticalGame] +MutatorNames=XComMutator.MyMutator Why two separate sections? Because XComHeadquartersGame and XComTacticalGame are two different games. Both are children of XComGameInfo class, so they share a code, but not variables. There also is MP Game and it's own GameInfo class and Mutators can theoretically affect MP games too, but I haven't yet looked into this matter. So with MutatorEnabler in place, to add a mutator in game one need to create a new package, containing mutator code, add this package to DefaultEngine.ini and enable new mutator via DefaultGame.ini. Piece of cake. :smile: Here's example mutator and configs: https://drive.google.com/file/d/0B5MAcyqYBx4dZUNkSlowVHRqQzg/edit?usp=sharing Enable console and typeMutate 4to speed up animation orMutate 0.1to make it slower. Works same as slomo command. Edited September 5, 2014 by wghost81 Link to comment Share on other sites More sharing options...
wghost81 Posted September 5, 2014 Author Share Posted September 5, 2014 (edited) Seems, my initial analysis of Mutators was somewhat optimistic... I've tried to actually replace XGAIBehavior_Sectoid class with newly created XGAIBehavior_Sectoid_Alt class. And had no success. After XGAIBehavior is spawned, it gets assigned to unit and initialized. After. AFTER. So, by replacing it, I get units with no behavior at all, as I can't figure out what unit this behavior is supposed to belong to at the stage of spawning. Yes, behavior class has a reference to it's unit, but it gets assigned after it was spawned: when Init() function is called. Owner object can't help either, as behavior gets spawned by Player class, not Unit class. I tried to replace XGUnit with XGUnit_Alt and rewrite behavior spawn, but with no luck either. Since replaced units get removed, I immediately win the mission. So, Mutators are good for UT, but not for XCOM. Unfortunately. All we can do with mutators, is inject some code into PostBeginPlay function of an actor, but I can't even think of situations, in which it can be useful. If we had source codes, we could rewrite it to handle XCOM-specific Mutators, but even then it would require a lot of work. Because XCOM is very different from any FPS game. In fact, the more I look into the code, the more I understand that XCOM is not using UE, it's hacking it. :smile: Edited September 5, 2014 by wghost81 Link to comment Share on other sites More sharing options...
dubiousintent Posted September 5, 2014 Share Posted September 5, 2014 Updated the article with this. I realize this is very discouraging, but I wonder if it's not more a matter of the test case you chose? Perhaps if you tried something involving the Player class first, as that is more within the FPS focus of the engine? The use of mutators in XCOM is apparently "not by design" of Firaxis, so we sort of need to establish what the current boundaries are first. -Dubious- Link to comment Share on other sites More sharing options...
Recommended Posts