Calling functions without adding package dependancy.

Get some cool tips about how to tweak your UT graphic, gameplay, and much more!
Post Reply
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Calling functions without adding package dependancy.

Post by Higor »

Mods, anticheats, addons...
One can't guarantee his own addition to UT will be compatible with all of these, and sometimes, there's just no way to do it without making said addition force loading these mods.

There's 2 ways to avoid this:
- The ugly way: used a second folder with hacked packages to build your mod.
- My way: create small precompiled utils to merge with the final release.

==== Planning
So, let's get started, this guide will use an example to better show how things work.
First before anything, what do you need to call? What does your mod need to know? Is there a cleaner way to do it without adding dependancy?
If all you're trying to get is a simple variable, you're better off with GetPropertyText.

My util will check if a certain Pawn can reach a destination, but I have found that there's 1 pawn type that uses a whole set of functions in order to find a path.
FerBotz.Botz > uses SearchAPath( actor PathTarget) in order to properly set a MoveTarget, that function does special treatment of bot-only hardcoded JumpSpots and TranslocEnds among other things.
I will need to: call this function if the pawn i'm checking is a Botz, or simply call FindPathToward() otherwise.


==== Merging basics
We now need to know how to merge a package into a final build, most already know this... but I bet most didn't know you can merge packages with code into a build as well.
This works like the precompiled headers you'll find in a c++ project, it's not like i'm recommending the usage of precompiled code prior to building a mod, but some already do it with pre-packaged textures, sounds so it's the same as code.
The way to do this is the OBJ LOAD command, this command can be written in the editor or executed in compilation, this command should be used once in the build.
#exec OBJ LOAD FILE="Subfolder\FileName.ext" PACKAGE=Name_used_after_load
If you specify PACKAGE= with the same name as your final build, then instead of being loaded it's merged into it, we will use this directive to merge the utils we create in order to ensure compatibility.
PD: If you don't specify PACKAGE=, then the FILENAME is used by default.

My util will be named Botz_FindPath.u, and I will merge it by placing it on the mod folder (above folder 'classes') and I will insert this line in one of the UC's.
#exec OBJ LOAD FILE="Botz_FindPath.u" PACKAGE=MyMod



==== Getting the environment ready
You're going to need to do a few ugly things with Unreal Editor so get ready and open it.
You have to find the Botz's SuperClass, the Super class is the class a certain class is subclass from, in english: the class above in the hierarchy.
If you don't know which is the superclass of your target mod, load it in a second editor instance to take a look at it.
Be sure to pick the appropiate superclass, it has to belong to a standard package (Botpack, Engine, etc) and has to fit your needs the best.
Once done, edit the script of said class, add a declaration (!) of the function you want to call, it must be identical to the original function the class from the mod you're targeting has.
Once edited the code, (LOAD LADRSTATIC.UTX) and rebuild the changed scripts, do not save anything.

We already know Botz's super classes are: Pawn > Actor > Object.
Pawn and Actor belong to Engine, Object to Core so they're pretty much all standard packages.
My needs dictate that I must do path finding, so Pawn would be the ideal class to edit the code on.
I'll edit Pawn's code and add this function declaration somewhere:
>>> function SearchAPath(actor PathTarget);
I will then load LadrStatic.utx to avoid Botpack.u from wasting my time asking me to load the UTX file, then BUILD the changed scripts.


==== Making your Util
Now create a subclass from Object, use reasonable naming conventions here because you'll be writing those names a LOT.
In this class, add a static function with the appropiate parameters and return value that fits your needs, then insert the code that MUST DO:
- STATIC MODIFIER, you won't be instancing this object, so pass that actor you're checking on as a parameter to it.
- CLASS DIFFER CHECKS, because you can't call inexistant functions in the vanilla package, only the subclassed package, you must check if this actor is the one of the targeted mod, or a basic one!.
- CASE SENSITIVE NAMES, keep your names identical to the original mod, or you'll break your main mod if it's a native package.
Add to this function(s) the hacked function if you know the actor belongs to the mod and has said function.
Once finished, recompile the changed scripts and if all goes well, save your util.

I subclassed from Object: Package = Botz_FindPath, Name = Botz_FindPath_util
Then added the function:

Code: Select all

static function bool PawnCanReach( pawn aPawn, actor Other)
{
	local actor oldM;
	local bool result;
	if ( aPawn.IsA('Botz') )   //Keep Botz case sensitivity... or It'll crash if I load the native version.
	{	//SearchAPath doesn't return anything, it sets MoveTarget instead
		oldM = aPawn.MoveTarget;
		aPawn.MoveTarget = none;
		aPawn.SearchAPath( Other);
		result = aPawn.MoveTarget != none;
		aPawn.MoveTarget = oldM;
		return result;
	}
	else
		return aPawn.FindPathToward( Other) != none;
}
After rebuilding and saving, I have my Botz_FindPath.u util ready!.[/i][/b][/color]

==== Implementation
Now you just need to call the static function from wherever you need it.
In order to do it, you just have to call it like this:
class'UtilClass'.static.UtilFunction();
We won't need to crate an UC for this class in our mod, it will come by it's own when we merge the util package!

MyMod needed to see if a pawn can reach a certain actor, maybe for objective checking, or special items that attract bots.
So we'll implement this function everytime we have to check for 'reachability':

Code: Select all

if ( class'Botz_FindPath_util'.static.PawnCanReach( Pawn, Objective) )
[/color][/i][/b]


If your build fails due to not finding the util class, try doing the merger in a different place... like on the class you're actually calling said functions, because I really don't know which UC's get parsed first.


PD: If you're trying to access the ViewRotation in UTPure players...
Use Pawn as subclass, call return GR(); if pawn IsA('bbPlayer'), otherwise return Pawn.ViewRotation;
I did this in Siege and worked.
User avatar
Feralidragon
Godlike
Posts: 5493
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Calling functions without adding package dependancy.

Post by Feralidragon »

So, in conclusion, if I understood it right: all you have to do is to declare the same functions in the superclasses, compile the a package with them, and then in the code itself check the class you're going to call it from to avoid a massive GPF.
And the way you do it is by building a middleware of your own to interface between your real mod and the stuff you want to call the functions dynamically from (your Utils class basically).

Very nice :mrgreen:
This may indeed help a lot in some things in my project, thanks for sharing :rock:
Post Reply