Jump to content

Scripting with UDK


wghost81

Recommended Posts

: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=TestMod

Does 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

  • Replies 61
  • Created
  • Last Reply

Top Posters In This Topic

@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 by wghost81
Link to comment
Share on other sites

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

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 by wghost81
Link to comment
Share on other sites

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

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 type

Mutate 4
to speed up animation or

Mutate 0.1
to make it slower. Works same as slomo command. Edited by wghost81
Link to comment
Share on other sites

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 by wghost81
Link to comment
Share on other sites

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

  • Recently Browsing   0 members

    • No registered users viewing this page.

×
×
  • Create New...