• Register
Post tutorial Report RSS Unreal Learning #2: UT3 Configurable Mutators

This second tutorial will teach you how to write a mutator with configurable properties, and how to create and set up a user interface scene for it.

Posted by on - Basic Server Side Coding

If you haven't done so already - you should probably check out the mutator basics in Unreal Learning #1: My First Unreal Tournament 3 Mutator, and do a bit of extra learning yourself based on that tutorial.

So we can write a mutator, that's great! We're well on our way to becoming Unreal Programming gurus. But wait? What if we want to let the players choose what they want instead of us? For this we need to use a mutator with a Configuration Menu. Configuration Menus are the menus that pop up when we select a mutator, and hit the configuration button in the mutator selection screen. They allow us to set predefined properties to what we want them to be for the particular game we're about to play.

By now, you should already have a good idea of how to set up your mutators, getting the right directory layout and how to create new classes - so we won't go over that again just yet.

Create the folders and a new mutator class just like you would for any other mutator, and don't forget to add it to the ModPackages in the ini files. This time I decided to call my folder PlayerTweak and the mutator PlayerTweakMutator. It always helps to have descriptive folder and class names - it helps you and the user know what they are, and helps prevent them from clashing with anyone elses mutators. Why PlayerTweak? Because that's what we're going to be doing - we're going to let the mutator customise some player statistics.

Writing the Mutator

Time to do some scripting! Let's open up our new class file and set it up properly just like we did before. We're going to also want to create some variables. I chose to modify the player speed, jumping height and health values.

uscript code:
class PlayerTweakMutator extends UTMutator
config(PlayerTweak);

var config float Speed;
var config float JumpHeight;
var config int StartHealth;
var config int MaxHealth;

DefaultProperties
{
}

Notice something different from the way variables are normally declared? That's right - we've declared our variables as config variables. This means that their values can be modified by our configuration. It also means that instead of having their DefaultProperties defined by the mutator, we put them in the ini file instead. We will do this later. You'll also notice we've declared our class in a new way, we've added the config keyword to that too. We've also told it that the file it should put the configuration variables in for us is called PlayerTweak - or UTPlayerTweak.ini.

Now, we've been using the CheckReplacement technique to swap in and out our objects up until now. We could do it again, by creating a new type of UTPawn and changing what we want - but there's a better way! Instead, we're going to use a ModifyPlayer function instead. The ModifyPlayer function is useful, as it allows us to change a few properties without the need to create a new class for a new type of Pawn and overcomplicate things.

uscript code:
class PlayerTweakMutator extends UTMutator;

var config float Speed;
var config float JumpHeight;
var config int StartHealth;
var config int MaxHealth;

function ModifyPlayer(Pawn Other)
{
Other.GroundSpeed *= (Speed/100);
Other.JumpZ*= (JumpHeight/100);
Other.Health*= StartHealth;
Other.HealthMax*= MaxHealth;

Super.ModifyPlayer(Other);
}  

DefaultProperties
{
}

So what's going on? Well, we're going through every Pawn in the game, and resetting a few of their default variables. If we wanted to change some other features, we could go into Pawn.uc, and take a look and add them in. For now we'll stick with what we've got. Why are we dividing the Speed and JumpHeights by 100? Well that's because we're going to let the player specify a percentage of the speed and jump, rather than hard-setting an actual numerical value.

Now for the tricky, new bit.

Writing a new Interface Class

This is where things start to get more difficult and our programming expertise are going to be stretched. In order for our configuration menu to appear in the mutators menu, we need to actually create the menu. This involves not only a bit of code, but we also need to use UnrealEd to make out menu scene. Don't worry, we'll be learning how to do all of that in good time. Create a new class for our interface. We will be extending the class UTUIFrontEnd - which is the basic class for all Unreal Tournament 3 menu systems.

uscript code:
class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

DefaultProperties
{
}

Ok, so what do we need to put in it? Let's think. We're going to need to be able to set our player statistics. Seeing as they're all statistics that have a lot of values, we'll use a slider. You could spend some time looking at what other types of widgets there are (hint, use UnrealEd and create a new UIScene in the Generic Browser, and see what's on offer). The sliders are useful because we can set a minimum value, a maximum value and our player can select anything between that minimum and maximum. Let's create some sliders - we can declare them just like variables. We are also going to make them transient. This means that the variables will carry over between things like level changes, which is a useful feature.

uscript code:
class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

var transient UTUISlider PlayerSpeed;
var transient UTUISlider PlayerJumpHeight;
var transient UTUISlider PlayerStartHealth;
var transient UTUISlider PlayerMaxHealth;

DefaultProperties
{
}

Fantastic, we're on our way. Now that we have these sliders, we need to determine what values they'll actually have. If we go into the class UTUISlider.uc, we'll find out that they have a variable in there called SliderValue (it's a UIRangeData). UIRangeData is a special variable that contains other variables - just like a struct in many programming languages. We don't need to worry about how these are made, but you can take a look at them by reading through the unrealscript source now if you like, as they aren't very complicated.

We will set our values when the player opens the configuration menu - for that we can use the SceneActivated event. This means we will tell our sliders what the sliders in the menu scene are called so that we can find them, and we will also tell them what our minimums and maximums are.

uscript code:
class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

var transient UTUISlider PlayerSpeed;
var transient UTUISlider PlayerJumpHeight;
var transient UTUISlider PlayerStartHealth;
var transient UTUISlider PlayerMaxHealth;

event SceneActivated(bool bInitialActivation)
{
Super.SceneActivated(bInitialActivation);

if (bInitialActivation)
{
PlayerSpeed = UTUISlider(FindChild('sliSpeed', true));
PlayerJumpHeight = UTUISlider(FindChild('sliJumpHeight', true));
PlayerStartHealth = UTUISlider(FindChild('sliStartHealth', true));
PlayerMaxHealth = UTUISlider(FindChild('sliMaxHealth', true));

PlayerSpeed.SliderValue.CurrentValue = 100.f;
PlayerSpeed.SliderValue.MinValue = 25.f;
PlayerSpeed.SliderValue.MaxValue = 200.f;
PlayerSpeed.SliderValue.NudgeValue = 25.f;
PlayerSpeed.SliderValue.bIntRange = true;

PlayerJumpHeight.SliderValue.CurrentValue = 100.f;
PlayerJumpHeight.SliderValue.MinValue = 0.f;
PlayerJumpHeight.SliderValue.MaxValue = 400.f;
PlayerJumpHeight.SliderValue.NudgeValue = 25.f;
PlayerJumpHeight.SliderValue.bIntRange = true;

PlayerStartHealth.SliderValue.CurrentValue = 100;
PlayerStartHealth.SliderValue.MinValue = 25f;
PlayerStartHealth.SliderValue.MaxValue = 250f;
PlayerStartHealth.SliderValue.NudgeValue = 25;
PlayerStartHealth.SliderValue.bIntRange = true;

PlayerMaxHealth.SliderValue.CurrentValue = 199;
PlayerMaxHealth.SliderValue.MinValue = 25;
PlayerMaxHealth.SliderValue.MaxValue = 500;
PlayerMaxHealth.SliderValue.NudgeValue = 25;
PlayerMaxHealth.SliderValue.bIntRange = true;
}
}  

DefaultProperties
{
}

Wow, that's a lot! We can actually cut a lot of that into less code, but for now we'll keep it easy and simple to understand. It shouldn't make a difference to how the unrealscript compiler handles the code anyway. You'll notice how we told our code what our sliders are called - we need to use the FindChild function to find the slider (e.g sliSpeed). In order for the FindChild function to work, we need to cast it into the correct type of class - UTUISlider. If you don't know how type casting works, then don't worry about it just yet, we'll cover that in an advanced unrealscript tutorial - for now we just want to know how to get configuration menus working.

Ok, so we have sliders. But now we have new problems to solve - we can play with the sliders all we like, but we'll never get anywhere without a button to tell the game that we're finished choosing our player statistics. For that we look at the ButtonBar .

The ButtonBar appears in many UT menu scenes. It is the set of buttons that will appear at the bottom of almost every menu in the game. We will want one of these to set our variable values for use in the game and we'll want one to get out of the menu. We might as well make the same button do both jobs for us, so we'll use the SetupButtonBar function that's been given to use by UTUIFrontEnd and tell it to make us a button.

uscript code:
class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

var transient UTUISlider PlayerSpeed;
var transient UTUISlider PlayerJumpHeight;
var transient UTUISlider PlayerStartHealth;
var transient UTUISlider PlayerMaxHealth;

event SceneActivated(bool bInitialActivation)
{
Super.SceneActivated(bInitialActivation);

if (bInitialActivation)
{
PlayerSpeed = UTUISlider(FindChild('sliSpeed', true));
PlayerJumpHeight = UTUISlider(FindChild('sliJumpHeight', true));
PlayerStartHealth = UTUISlider(FindChild('sliStartHealth', true));
PlayerMaxHealth = UTUISlider(FindChild('sliMaxHealth', true));

PlayerSpeed.SliderValue.CurrentValue = 100.f;
PlayerSpeed.SliderValue.MinValue = 25.f;
PlayerSpeed.SliderValue.MaxValue = 200.f;
PlayerSpeed.SliderValue.NudgeValue = 25.f;
PlayerSpeed.SliderValue.bIntRange = true;

PlayerJumpHeight.SliderValue.CurrentValue = 100.f;
PlayerJumpHeight.SliderValue.MinValue = 0.f;
PlayerJumpHeight.SliderValue.MaxValue = 400.f;
PlayerJumpHeight.SliderValue.NudgeValue = 25.f;
PlayerJumpHeight.SliderValue.bIntRange = true;

PlayerStartHealth.SliderValue.CurrentValue = 100;
PlayerStartHealth.SliderValue.MinValue = 25f;
PlayerStartHealth.SliderValue.MaxValue = 250f;
PlayerStartHealth.SliderValue.NudgeValue = 25;
PlayerStartHealth.SliderValue.bIntRange = true;

PlayerMaxHealth.SliderValue.CurrentValue = 199;
PlayerMaxHealth.SliderValue.MinValue = 25;
PlayerMaxHealth.SliderValue.MaxValue = 500;
PlayerMaxHealth.SliderValue.NudgeValue = 25;
PlayerMaxHealth.SliderValue.bIntRange = true;
}
}  

function SetupButtonBar()
{
ButtonBar.AppendButton("", OnButtonBar_Back);
}

Wow, that was easy! But how does it know what to do? The Button Bar is actually going to be already there in the menu scene ready for us, all we had to do was add a button using the AppendButton function. We told it which string to use (in this case we used the already existing 'Back' string). We also needed to tell it what function to call when we press it. This is the OnButtonBar_Back function that we're about to write - and the already existing scripts will handle the rest of the complicated stuff for us.

uscript code:
class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

var transient UTUISlider PlayerSpeed;
var transient UTUISlider PlayerJumpHeight;
var transient UTUISlider PlayerStartHealth;
var transient UTUISlider PlayerMaxHealth;

event SceneActivated(bool bInitialActivation)
{
Super.SceneActivated(bInitialActivation);

if (bInitialActivation)
{
PlayerSpeed = UTUISlider(FindChild('sliSpeed', true));
PlayerJumpHeight = UTUISlider(FindChild('sliJumpHeight', true));
PlayerStartHealth = UTUISlider(FindChild('sliStartHealth', true));
PlayerMaxHealth = UTUISlider(FindChild('sliMaxHealth', true));

PlayerSpeed.SliderValue.CurrentValue = 100.f;
PlayerSpeed.SliderValue.MinValue = 25.f;
PlayerSpeed.SliderValue.MaxValue = 200.f;
PlayerSpeed.SliderValue.NudgeValue = 25.f;
PlayerSpeed.SliderValue.bIntRange = true;

PlayerJumpHeight.SliderValue.CurrentValue = 100.f;
PlayerJumpHeight.SliderValue.MinValue = 0.f;
PlayerJumpHeight.SliderValue.MaxValue = 400.f;
PlayerJumpHeight.SliderValue.NudgeValue = 25.f;
PlayerJumpHeight.SliderValue.bIntRange = true;

PlayerStartHealth.SliderValue.CurrentValue = 100;
PlayerStartHealth.SliderValue.MinValue = 25f;
PlayerStartHealth.SliderValue.MaxValue = 250f;
PlayerStartHealth.SliderValue.NudgeValue = 25;
PlayerStartHealth.SliderValue.bIntRange = true;

PlayerMaxHealth.SliderValue.CurrentValue = 199;
PlayerMaxHealth.SliderValue.MinValue = 25;
PlayerMaxHealth.SliderValue.MaxValue = 500;
PlayerMaxHealth.SliderValue.NudgeValue = 25;
PlayerMaxHealth.SliderValue.bIntRange = true;
}
}  

function SetupButtonBar()
{
ButtonBar.AppendButton("", OnButtonBar_Back);
}

function bool OnButtonBar_Back(UIScreenObject InButton, int InPlayerIndex)
{
class'PlayerTweak.PlayerTweakMutator'.default.Speed = PlayerSpeed.GetValue();
class'PlayerTweak.PlayerTweakMutator'.default.JumpHeight = PlayerJumpHeight.GetValue();
class'PlayerTweak.PlayerTweakMutator'.default.StartHealth = PlayerStartHealth.GetValue();
class'PlayerTweak.PlayerTweakMutator'.default.MaxHealth = PlayerMaxHealth.GetValue();

class'PlayerTweak.PlayerTweakMutator'.static.StaticSaveConfig();

CloseScene(self);

return true;
}  

DefaultProperties
{
}

We're now finished with code. There certainly was a lot of it, wasn't there? So what does this new function do? Well, let's take a good look at it. To keep the unrealscript compiler happy, our OnButtonBar_Back function has to return a bool - so we just returned true because the function (probably!) worked. We also wrote code to found out what values the player chose to play with, and used them to set the variables in our mutator, so that it can use them in the ModifyPlayer function - we did this by getting the value of the slider with the GetValue function - then set the default value of our mutator class for each variable. Very clever, very clever indeed. If you're not very sure what is going on, now is a very good time to step back and read through all this code we've been writing. It's not actually all that complicated, it just looks that way!

With the code out of the way, there's just one big thing left to do - we need to create a fancy new menu for the mutator! We should be able to build our scripts now in the unrealscript compiler - do that now, and if it doesn't work, step back and take a look at the errors.

No errors? Great! Menu time!

Creating a new Menu Scene

Now we need to open the Unreal Editor. We can find that in our start menu - or we can create a new shortcut with the editor command switch just like we did when we created a short cut to make our scripts. The first thing we see is the Generic Browser - handy, because that's exactly what we're looking for.

Back click in the window of the Generic Browser, and select the New UIScene Option. What is a UIScene? It's a special type of object - it's a menu in the game, or any other type of 2d interface in fact. You should now be faced with this window:

New UI Scene Menu

Ok, we need to create a new package to put our UIScene in. Naughty, yes, we could do it with just one package for our entire mutator - but we won't worry about that just yet. We want to get it working now and we can worry about that when we have learnt more about Unreal. Call the package UTUI_Scenes_PlayerTweak. If we wanted to put it in a folder inside the package, we could give it a group name, but since our package is going to be very empty, we won't bother with unecessary organisation. Give the menu the name PlayerTweakConfigMenu. Now we need to tell the editor that our UIScene isn't just a UIScene, but it's also a UTUIFrontEnd_PlayerTweakMenu. Go into the UISceneClass drop down list in the options and look for our UTUIFrontEnd_PlayerTweakMenu class. We're ready to create it now, so we'll hit the OK button.

Ok, we should now be looking at this rather daunting UIScene Editor. Fortunately, it's very easy to work with and we'll be done in no time at all!

UIScene Editor

We need to create a background. I just created a plain black one with a title in Paint, but you could make yours as fancy as you please. We also need to import it - so minimise the UIScene Editor, and back to the Generic Browser. Go into the File Menu in the top left. Once we've found what we want to import, we hit OK and it's another menu like we had when we had to create something! Great, we can import the image to our menu scene package file that we created. Make sure to select TEXTUREGROUP_UI from the LODGroup options. We don't want any funny visual artifacts on our nice 2d interfaces. Remember that any texture you import must be in a power of two size (512x512, 1024x1024, 512x2048 etc) - otherwise UnrealEd cannot import it for you. If you're lazy, you can just use mine if you want:
Sheelabs.gamemod.net

Back to the UIscene Editor!

We can create our background from our newly imported texture by creating a widget. A widget is any kind of object we can put in our UIScene. All we have to do is back click in our currently rather empty grey area (this is where we draw our menu scene) and go into Place Widget and select an Image widget. It will magically create a new widget - but yuck! It's a horrible green square. Never fear - use the red squares in the corners to stretch it out to cover the scene - I'll cover the whole of the blue area for now - the blue area is the dimension of the screen at the chosen resolution - I'm not worry about that, so I'll leave it to 1024x768. Then we need to look in the properties on the right hand side. With your image selected in the Generic Browser, go into the properties and find the ImageRef property. You will need to expand the Image section and then the StyleOverride sections in order to find it. When you hit the little green arrow, it should turn that nasty green block into your background. Hurray!

UI Background

Now we're going to add those sliders we need to let the player choose what stats they want in their game. Let's place some more widgets. This time, let's create a UTUISlider and call it sliSpeed - just what we called it in our code - it's all linking together now! Make sure you click in the grey area in the window, otherwise it will create the widgets as 'children' of your background, which is wrong, and the code might not find what it is looking for. Resize it using the red squares once more and move it somewhere useful. Once you've done that, we're going to need three more sliders - sliJumpHeight, sliHeath and sliMaxHealth. Got them all resized and aligned? Great! We also need to let the player know what each slider is. We've got a widget for that too - the label widget. Create yourself a label widget and move it somewhere near one of the sliders. We want to change the text, so we'll find the MarkupString property in DataSource section of the Data category. Change it to something useful, and create three more labels for the other remaining sliders.

UI Widgets

Getting better? Good. We have only a few things left to do. We need to create that button bar. This is also nice and easy. Let's create yet another widget - this time it's a UTUIButtonBar. We have to call it pnlButtonBar, because this is what the unrealscript source written by Epic calls it - just like the way we named our sliders. Very cleverly, it has put it at the bottom of the menu scene for us already, just like in all the other Unreal Tournament 3 menus. If you expand it in the Scene Tools on the left hand side, you'll see it automatically creates and positions all the buttons for it too. Score!

We're going to do one quick last thing before we finish our scene. We're going to add some UISafeRegionPanel widgets. We will use these to enforce the correct aspect ratio on our menu scene, and if we give them names that the unrealscript source written by Epic recognises, it will automatically apply the same menu animations to the menu scene as all the other Unreal Tournament 3 menus. Add two of these widgets. We will call one of them pnlSafeRegion, and the other pnlSafeRegionLong. Both of these widgets are also automatically positioned and scaled.

Clearing up the scene, we're going to make our widgets children of the UISafeRegionPanels. We can do this because the code will be able to determine where our widgets are when they children of these. In the Scene Tools, select the pnlButtonBar and drag it into pnlSafeRegionLong. Then we need to one by one drag all the remaining widgets into the pnlSafeRegion. If any of your sliders and labels disappear behind your background, don't worry! When you have finished dragging all the widgets in, you can back click on your background, and go into Reorder Widget and select Send to Bottom.

Finished Scene

Close the Unreal Editor, and when it prompts you, save your new package file in your My Documents/My Games/Unreal Tournament 3/ UTGame/Unpublished/CookedPC directory, in a new directory called Packages.

All we need to do is tie our finished menu scene and mutator to the localisation and configuration (the int and ini) files .

Ok, let's create that int file. Go into your My Documents/My Games/Unreal Tournament 3/ UTGame/Unpublished/CookedPC/Localization folder and create a new file called PlayerTweak.int (or modify it if you already have it). We don't need a lot in here, just a couple of lines, which you should be able to guess, because you've done it before.

uscript code:
[PlayerTweakMutator UTUIDataProvider_Mutator]
FriendlyName="Player Tweak"
Description="Change player statistics"

Final step, go into your
My Documents/My Games/Unreal Tournament 3/ UTGame/Config directory and create a new ini file called UTPlayerTweak.ini (or modify it if you already have it). You might notice that the Unreal Editor has alreayd created a UTUI_Scenes_PlayerTweak.ini for us, which is nifty and one less thing to worry about. Your UTPlayerTweak.ini file should look like this:

[PlayerTweakMutator UTUIDataProvider_Mutator]
ClassName=PlayerTweak.PlayerTweakMutator
FriendlyName=Player Tweak
Description=Allows you to custom set player stats
GroupNames=
UIConfigScene=UI_Scenes_PlayerTweak.PlayerTweakConfigMenu
bStandaloneOnly=False
bRemoveOn360=False
bRemoveOnPC=False
bRemoveOnPS3=False

[PlayerTweak.PlayerTweakMutator]
Speed=100.000000
JumpHeight=100.000000
StartHealth=100
MaxHealth=199  

And that's it, we're done! All you should need to do now is run the game using that short cut you made before (with the -useunpublished command switch) and the mutator should appear in game. Go ahead, try giving yourself super jump, hardly any speed and different health. When you start the game, you should immediately notice the difference!

If you have problems at this point, it is always a good idea to consult the log files. These are generated every time you run the game, and are normally found in the Program Files/Unreal Tournament 3/UTGame/Logs directory. Opening them up with a text editor will help show you what errors have been caused.

Have fun with your spiffy new player statistics! By request, the source code and assets can now be downloaded from here.

Post comment Comments  (0 - 50 of 57)
myles
myles

That's great thanks Amber, please keep these tutorials coming, there so good!

Reply Good karma Bad karma+1 vote
P4R4.be
P4R4.be

nice work!

Reply Good karma Bad karma+1 vote
Dark[NSF]
Dark[NSF]

wow, that ui editor is klunky............. i wish there was another way to design UI :(

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Yeah, it's not exactly my favourite tool either.

Reply Good karma+1 vote
igoat
igoat

great tutorials!

i have one question if anyone has the answer. i'd like to prepopulate my sliders with values from UTPlayerTweak.ini but I cant figure out how to access those config variables in an arbitrary class file.

i am using the config(PlayerTweak) line to tell the class to load that ini but I'm not sure form there how to get my variables.

when i use:

var config int MyVarFromIni;

MyVarFromIni defaults to 0 instead of the value in the .ini file. Can anyone help?

Reply Good karma Bad karma+1 vote
igoat
igoat

well i decided to go another route. i got rid of the config(PlayerTweak) line and the config variable declarations and tried calling the default values directly.

the following snippet was supposed to grab the current value stored in the .ini but it didn't seem to work either:
class'PlayerTweak.PlayerTweakMutator'.default.var

any help is greatly appreciated. thx again for the great tutorials amber!

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Yeah, I'm aware of the problem. UT3 doesn't seem to load in config variables properly between games, including in the default mutators. This leads me to believe it's a problem inherent in the game itself.

Reply Good karma+1 vote
ambershee Author
ambershee

Thanks for that. When I'm back from Polygons, I'll certainly look into it!

Reply Good karma+1 vote
cybran
cybran

Hi,

where you said on page 3:
"Now we need to tell the editor that our UIScene isn't just a UIScene, but it's also a UTUIFrontEnd_PlayerTweakMenu. Go into the UISceneClass drop down list in the options and look for our UTUIFrontEnd_PlayerTweakMenu class."

i can't find the UTUIFrontEnd_PlayerTweakMenu class from the drop-down list. I've built the PlayerTweak package with the 2 classes in it. I've also made a copy of the .u file and placed it in the CookedPC folder. Then i loaded up Unreal Ed and followed your instructions but it's still not there.

any ideas?

Thanks!

Cybran

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Hi Cybran - I'm not entirely sure where you have gone wrong and am away from my development machine until January. I'd double check your naming conventions and ensure you're looking in the right lists. I'll take a closer look for you as soon as I'm back in business.

Reply Good karma+1 vote
cybran
cybran

Thanks ambershee,

i'll restart the tutorial from scratch just in case and let you know my findings

Cybran

Reply Good karma Bad karma+1 vote
cybran
cybran

i restarted from scratch, didn't really do anything different apart from create a folder called 'UTUI_Scenes_PlayerTweak'. It picked it up now :)

however, when i click on OK it doesn't seem to display the UIScence Editor - it just takes me back to the greneric browser

any ideas how to bring up the UIScene Editor and load the UIScene package i just created?

thanks

Cybran

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

In the generic browser, you can find the package you just created. Double clicking on the scene in the browser should bring up the editor.

Reply Good karma+1 vote
cybran
cybran

right, i've found the problem:

where you said "Back click in the window of the Generic Browser, and select the New UIScene Option." i didn't know what back click was (i'm guessing thats a typo?) so instead i clicked on new and then selected UIScene from the Factory drop down list (doing it this way does not load up the UIScene editor).

I'm guessing you meant right click > New UIScene (this method does load up the UIScene editor)

thanks ambershee!

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

No problems - and yes, a back click is a right click, haha.

Reply Good karma+1 vote
peterfaj
peterfaj

Please help!
After all is done, nothing happened when clicking configure in the mutator menu. Then I changed the package name from UTUI_Scenes_PlayerTweak.upk to UI_Scenes_PlayerTweak.upk (like in the mods I downloaded).
Then I got into the configuration menu and the speed and jump height sliders were set right as default, but the number said 0 and the health sliders both had the max limit 100. And there were no buttons on the bottom of the menu.

And when I tried everything again, I got:
"X:\ Program Files\ Unreal Tournament 3\ Development\ Src\ PlayerTweak\ Classes\ PlayerTweakMutator(18) : Error, Classes with config/ globalconfig member variables need to specify config file." when compiling.

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Hi peterfaj,

Your first error sounds like you made several small mistakes at some point - I'd double check that you are using the correct class for your UIScene, that the button bar is indeed set correctly (and the widgets in the scene aren't covering them up), and that you haven't made any small name errors, such as the sliders in the UIScene having a different name to the ones you're looking for in the code.

The second error is more simple. You have configuration variables but probably haven't declared your class properly - you need to declare it as;

class PlayerTweakMutator
config(FileName);

Where FileName is the name of the ini configuration file that will hold your config settings (UTFileName.ini).

Hope it helps!

Reply Good karma+1 vote
howelett
howelett

hi. i've got the problem where nothing happens when i click on the configure button. the log reports that it's "Unable to find scene 'UI_Scenes_PlayerTweak.PlayerTweakConfigMenu'". i noticed that a file called UTUTUI_Scenes_PlayerTweak.ini was created by the editor in the Config directory which suggested to me that the scene's package name should be UI_Scenes_PlayerTweak instead of UTUI_Scenes_PlayerTweak (what the tutorial recommended). i tried renaming the package and have also tried recreating it with the name UI_Scenes_PlayerTweak but i don't get anything different in the logs. any idea what i'm missing?

Reply Good karma Bad karma+1 vote
Sentientv2
Sentientv2

I had this same problem with mine. The tutorial instructs you to name it UTUI_Scenes_PlayerTweak, but my log files fired off errors that it couldn't find UI_Scenes_PlayerTweak. I simply renamed the package to UI_Scenes_PlayerTweak (less the "UT" prefix) and it worked fine. I think the ini file is what is driving that request. I know that in many cases that UT extension is something that is added in, but in this case putting it in there yourself and not specifying it in your code causes some problems.

I also had quadruple checked myself on my errors before posting this and was only able to fix it by changing the package name from the UT prefixed version. Thank you for the great tutorial. It will no doubt help me. Take care.

Reply Good karma Bad karma+1 vote
peterfaj
peterfaj

btw, what do these f's do, for example in "PlayerSpeed.SliderValue.CurrentValue = 100.f;"?

And why do we call the spawn health "sliStartHealth" in UTUIFrontEnd_PlayerTweakMenu.uc file and "sliHeath" in the package file?

And should the button bar be visible at least in the UT3 editor?
Or is it normal for it to be invisible in the UT3 editor?

Reply Good karma Bad karma+1 vote
cybran
cybran

f just means floating point variable if i'm not mistaken...

"a digital representation of a number with a specified number decimal places, or fractional part, used to represent real numbers; contrast with integer"

sli is short for slider

yeah i couldn't see the button bar in the UT3 editor either - i think that's just hte way it is (not sure)

Reply Good karma Bad karma+1 vote
peterfaj
peterfaj

No I meant why is it called different. In the source file it's called "sliStartHealth" and in the package file it's called "sliHeath".

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

I may have made a mistake - or if you're looking at the source code and assets I posted, then it's probably because I did it differently to how it is set up in the tutorial when I originally did it to work it out myself.

Reply Good karma+1 vote
ambershee Author
ambershee

Cybran is correct on both scores. Ending a decimal with 'f' just means it's a floating point number. I could use 1.f or 1.0f, or whatever. It means the same thing.

The button bar never shows in the UI Editor, because it is set up purely by code.

Reply Good karma+1 vote
MulleDK19
MulleDK19

Hi... Nice tutorial...

I've done it 3 times now (from scratch), and it works perfectly, but there is no button in the config menu -.-

And I've tripple checked the code each time -.-

Reply Good karma Bad karma+1 vote
peterfaj
peterfaj

I have the same problem, now did it again from scratch and it didn't help. Though, I've fixed other problems, except for sliders showing 0 as their number as default, but the handle is at the right position. This seems like a game's bug, but it doesn't happen in other configurable mutators (that I've downloaded).

I've done everything same as it says here, except for naming the spawn health "sliStartHealth" in the editor too, instead of "sliHealth", to match with the source file, and it works fine. And I didn't make any background for my mutator configuration menu.

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

This slider 0 bug is because I had not worked it out - at the time this was the first config mutator other than Epics, which have the same problems. There is however a solution which I have been made aware of, and will update the tutorial accordingly when I get time.

It should definitely be sliStartHealth on all accounts.

Reply Good karma+1 vote
peterfaj
peterfaj

what about missing button bar in the game?
I've done averything as the tutorial says, has anyone got a solution?

Reply Good karma Bad karma+1 vote
peterfaj
peterfaj

After removing the button bar, I've found out that it actually was visible, just a small bit of a button on the right side that's not clickable, which disappeared when removing the button bar widget.
After moving the button bar a bit to the left, there is a small non-clickable button without any text.

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Sounds like something is definitely not right with your button bar. Try posting your source and asking for help at utforums.epicgames.com or forums.beyondunreal.com - hopefully there'll be someone there with time to look at it properly for you =]

Reply Good karma+1 vote
MavisPuford
MavisPuford

I had the EXACT same problem. What I did to fix it was:

ButtonBar.AppendButton("Back", OnButtonBar_Back);

You have to add text in those quotes. I couldn't figure it out for a while but the solution ended up being so simple and right in front of me.

Anyway, ambershee, great tutorial! I learned a lot from it. Just one suggestion, you might wanna put "Back" or "Accept" in between those quotes in your example code, otherwise beginners won't know how to get text in those buttons.

Also, do you know how I could update the sliders/check boxes with the last saved values every time I load the config menu rather than resetting them each time?

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

You should specify localised strings, not put text in them - otherwise it always appear in English, which is useless for anyone else ;)

Go down to the last comment, and read through that link quickly - the answer is within.

Reply Good karma+1 vote
MavisPuford
MavisPuford

Thanks ambershee, I didn't know that. I will have to give it a shot. Good to know. :)

Reply Good karma Bad karma+1 vote
MavisPuford
MavisPuford

Okay ambershee, I got it working the right way (I think! lol). But I still say you should update the example code so it doesn't read "" in the tutorial just so people don't have to go digging around or think they did it wrong. Here's my code:

function SetupButtonBar()
{
ButtonBar.AppendButton("<Strings:UTGameUI.ButtonCallouts.Accept>", OnButtonBar_Accept);
ButtonBar.AppendButton("<Strings:UTGameUI.ButtonCallouts.Back>", OnButtonBar_Back);
}

Is this correct?

Thanks for your help and for the awesome tutorial. I would have never figured this out on my own, being a newbie and all. :P

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Sounds right. I do admittedly really need to update the tutorial. I'm just really, really busy at the moment.

Reply Good karma+1 vote
cybran
cybran

its a typo

Reply Good karma Bad karma+1 vote
peterfaj
peterfaj

I've found a magic solution for the sliders' numbers showing 0 at first problem.
As I've been changing the UI package file, I made several versions of that file. And the problem's gone in all versions except for the original one. In one version, everything is exactly the same as the original version, but that problem is gone in there too.
So, the solution is:
Change anything (and then undo it manually) and save.
OR:
Change anything, save, then undo, then save again.

I don't know, I've saved another version of the file after any change.

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

The actual solution, is here, if you care to read through the thread:
Utforums.epicgames.com

Reply Good karma+1 vote
SimonBar
SimonBar

Hi ambershee, I've got a problem with the compiling.

Like peterfaj I have a "C:\Program Files\Unreal Tournament 3\Development\Src\ PlayerTweak\Classes\PlayerTweakMutator.uc(18) : Error, Classes with config/ globalconfig member variables need to specify config file."

So I changed the beginning of the file to:

class PlayerTweakMutator extends UTMutator
config(UTPlayerTweak.ini);

Now I'm getting a new compile error,
"C:\Program Files\Unreal Tournament 3\Development\Src\ PlayerTweak\Classes\PlayerTweakMutator.uc(2) : Error, Missing ')' in config"

Reply Good karma Bad karma+1 vote
SimonBar
SimonBar

Well I changed the "config(UTPlayerTweak.ini)" to "config(UTPlayerTweak)" and now it works!

So nevermind.

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

Nice to know you got it sorted =]

Reply Good karma+1 vote
ScottyBoi
ScottyBoi

Fantastic tutorial!

I've encountered a few problems along the way, but all the above comments have helped tremendously.

I have one problem tho; the mutator doesn't save my values when I press back on the configure menu. They just revert back to the default values. Any idea why this is or what I can do to fix this?

Reply Good karma Bad karma+1 vote
ambershee Author
ambershee

There should be a solution - IIRC, this link should help:
Utforums.epicgames.com

Reply Good karma+1 vote
xmai
xmai

This comment has two parts:
FIRST PART:

Make sure your files look like this to be able to save/load default values to/from the configuration file.

For PlayerTweakMutator.uc

class PlayerTweakMutator extends UTMutator config(PlayerTweak);

the rest exactly like in Ambershee code

For UTUIFrontEnd_PlayerTweakMenu.uc

class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

var transient ... like in Ambershee code

event SceneActivated(bool bInitialActivation)
{
Super.SceneActivated(bInitialActivation);

if (bInitialActivation)
{
PlayerSpeed = ... like in Ambershee code

//PlayerSpeed.SliderValue.CurrentValue = 100.f;
PlayerSpeed.SliderValue.MinValue ... like in Ambershee code

//PlayerJumpHeight.SliderValue.CurrentValue = 100.f;
PlayerJumpHeight.SliderValue.MinValue ... like in Ambershee code

//PlayerStartHealth.SliderValue.CurrentValue = 100;
PlayerStartHealth.SliderValue.MinValue ... like in Ambershee code

//PlayerMaxHealth.SliderValue.CurrentValue = 199;
PlayerMaxHealth.SliderValue.MinValue ... like in Ambershee code

END OF FIRST PART

Reply Good karma Bad karma+2 votes
xmai
xmai

This comment has two parts:

SECOND PART

// a part where we read values from our configuration file
PlayerSpeed.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.Speed;
PlayerJumpHeight.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.JumpHeight;
PlayerStartHealth.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.StartHealth;
PlayerMaxHealth.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.MaxHealth;

}
}

function SetupButtonBar()
{
ButtonBar.AppendButton( "<Strings:UTGameUI.ButtonCallouts.Back>", OnButtonBar_Back);
}

function bool OnButtonBar_Back(UIScreenObject InButton, int InPlayerIndex)
{
class'PlayerTweak. PlayerTweakMutator'.default.Speed = PlayerSpeed.GetValue();
... like in Ambershee code
}

DefaultProperties
{
}

(Ignore all spaces which I did after some dots after "PlayerTweak." word. Don't do them in your code.)

Basically we just have to load saved values from the configuration file - they are not loaded by the engine itself (I think I am right here but who knows). Also it would be better if after compilation of your code you set the starting default values in your configuration file yourself so they would appear when you first run the game (Configuration file == UTPlayerTweak.ini if somebody has already forgot).
It should work, hopefully :)
Great tutorials Ambershee

Reply Good karma Bad karma+2 votes
InfectedShroom
InfectedShroom

First off, thanks so much for the tutorials. I really want to get into modding but I couldn't find any thing really all that helpful. Then i stumbled across these tutorials which are just perfect.

Anyway, i got it the mutator working with one little problem. The sliders resize fine at differen't resolutions but my background image does not. I put it into pnlSafeRegion like the tutorial says, and then when that didnt work i tried putting it in pnlSafeRegionLong, that also failed to do anything. So what im left with is my background filling up about half of the screen with the swirling background taking up the rest. It looks especially bad seeing as my labels are integrated to the background.

Any ideas as to how i can fix this?

Reply Good karma Bad karma+1 vote
UTCollector88
UTCollector88

Hi

This is the third time I am doing this mutator. I am a beginner with UT3 programming/scripting. Anyway I have a problem, I can't get my imported background into the 'image ref' section in the 'Image' options of the UIScene Editor. I have the background imported on the generic browser but when I click on the green arrow nothing happens.

Reply Good karma Bad karma+1 vote
Springare
Springare

Okey I have finally got everything to work as intended took a lot of trial and error but got there after awhile
hehe I'll post my scripts since there are a few typo/bugs that had to be fixed ^^ Don't get me wrong I am extremely grateful for this tutorial but sometimes even the master needs help from it's students. *wink*

I will post everything in 4 different posts including this one since everything ended up becoming about 6-7k characters and 2k is the limit/post. ‘^^

Okey well here the .uc files

PlayerTweakMutator.uc

//-----------------------
class PlayerTweakMutator extends UTMutator config(PlayerTweak);

var config float Speed;
var config float JumpHeight;
var config int StartHealth;
var config int MaxHealth;

function ModifyPlayer(Pawn Other)
{
Other.GroundSpeed *= (Speed/100);
Other.JumpZ *= (JumpHeight/100);
Other.Health = StartHealth;
Other.HealthMax = MaxHealth;

Super.ModifyPlayer(Other);
}

DefaultProperties
{
}
//-----------------------

Note that I removed the * in front of the = for both Start and Max Health since it made the HP go crazy since it took the original HP and multiplied it whit the value from the slider.

Oh well of to the next file:

UTUIFrontEnd_PlayerTweakMenu.uc

//-----------------------
class UTUIFrontEnd_PlayerTweakMenu extends UTUIFrontEnd;

var transient UTUISlider PlayerSpeed;
var transient UTUISlider PlayerJumpHeight;
var transient UTUISlider PlayerStartHealth;
var transient UTUISlider PlayerMaxHealth;

event SceneActivated(bool bInitialActivation)
{
Super.SceneActivated(bInitialActivation);

Reply Good karma Bad karma+1 vote
Springare
Springare

if (bInitialActivation)
{
PlayerSpeed = UTUISlider(FindChild('sliSpeed', true));
PlayerJumpHeight = UTUISlider(FindChild('sliJumpHeight', true));
PlayerStartHealth = UTUISlider(FindChild('sliStartHealth', true));
PlayerMaxHealth = UTUISlider(FindChild('sliMaxHealth', true));

//PlayerSpeed.SliderValue.CurrentValue = 100.f;
PlayerSpeed.SliderValue.MinValue = 25.f;
PlayerSpeed.SliderValue.MaxValue = 200.f;
PlayerSpeed.SliderValue.NudgeValue = 25.f;
PlayerSpeed.SliderValue.bIntRange = true;

//PlayerJumpHeight.SliderValue.CurrentValue = 100.f;
PlayerJumpHeight.SliderValue.MinValue = 0.f;
PlayerJumpHeight.SliderValue.MaxValue = 400.f;
PlayerJumpHeight.SliderValue.NudgeValue = 25.f;
PlayerJumpHeight.SliderValue.bIntRange = true;

//PlayerStartHealth.SliderValue.CurrentValue = 100;
PlayerStartHealth.SliderValue.MinValue = 25f;
PlayerStartHealth.SliderValue.MaxValue = 250f;
PlayerStartHealth.SliderValue.NudgeValue = 25;
PlayerStartHealth.SliderValue.bIntRange = true;

//PlayerMaxHealth.SliderValue.CurrentValue = 199;
PlayerMaxHealth.SliderValue.MinValue = 25;
PlayerMaxHealth.SliderValue.MaxValue = 500;
PlayerMaxHealth.SliderValue.NudgeValue = 25;
PlayerMaxHealth.SliderValue.bIntRange = true;

// a part where we read values from our configuration file
PlayerSpeed.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.Speed;
PlayerJumpHeight.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.JumpHeight;
PlayerStartHealth.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.StartHealth;
PlayerMaxHealth.SliderValue.CurrentValue = class'PlayerTweak. PlayerTweakMutator'.default.MaxHealth;

//Update Slider
PlayerSpeed.UpdateCaption();
PlayerJumpHeight.UpdateCaption();
PlayerStartHealth.UpdateCaption();
PlayerMaxHealth.UpdateCaption();
}
}

Reply Good karma Bad karma+1 vote
Springare
Springare

function SetupButtonBar()
{
ButtonBar.AppendButton(" <Strings:UTGameUI.ButtonCallouts.Back> ", OnButtonBar_Back);
}

function bool OnButtonBar_Back(UIScreenObject InButton, int InPlayerIndex)
{
class' PlayerTweak.PlayerTweakMutator '.default.Speed = PlayerSpeed.GetValue();
class' PlayerTweak.PlayerTweakMutator '.default.JumpHeight = PlayerJumpHeight.GetValue();
class' PlayerTweak.PlayerTweakMutator '.default.StartHealth = PlayerStartHealth.GetValue();
class' PlayerTweak.PlayerTweakMutator '.default.MaxHealth = PlayerMaxHealth.GetValue();

class' PlayerTweak.PlayerTweakMutator '.static.StaticSaveConfig();

CloseScene(self);

return true;
}

DefaultProperties
{
}
//-----------------------

I'd like to thank "xmai" who come up whit the fix for it to save the values into the config file and then thanks to "warlord57" @ utforums.epicgames.com for the fix to make the sliders to update correctly.

Okey so that both of the .uc files, next up is the .ini files in the config map:

UTPlayerTweak.ini

//-----------------------
[PlayerTweakMutator UTUIDataProvider_Mutator]
ClassName= PlayerTweak.PlayerTweakMutator
FriendlyName=Player Tweak
Description=Allows you to custom set player stats
GroupNames=
UIConfigScene= UI_Scenes_PlayerTweak.PlayerTweakConfigMenu
bStandaloneOnly=False
bRemoveOn360=False
bRemoveOnPC=False
bRemoveOnPS3=False

[PlayerTweak.PlayerTweakMutator]
Speed=137.000000
JumpHeight=247.000000
StartHealth=110
MaxHealth=270
//-----------------------

Reply Good karma Bad karma+2 votes
Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: