UE2 - UT2kX Problem changing game rules with mutator

  • Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

ShadowsWar

New Member
Nov 30, 2008
76
0
0
The mod that I'm using(the UT2004RPG mod) and the mutator file has this:
Code:
function PostBeginPlay()
{
	local RPGRules G;
	local int x;
	local Pickup P;
	local RPGPlayerDataObject DataObject;
	local array<string> PlayerNames;

	G = spawn(class'RPGRules');
	G.RPGMut = self;
	G.PointsPerLevel = PointsPerLevel;
	G.LevelDiffExpGainDiv = LevelDiffExpGainDiv;
	if ( Level.Game.GameRulesModifiers == None )
		Level.Game.GameRulesModifiers = G;
	else
		Level.Game.GameRulesModifiers.AddGameRules(G);

	if (bReset)
	{
		//load em all up, and delete them one by one
		PlayerNames = class'RPGPlayerDataObject'.static.GetPerObjectNames("UT2004RPG",, 1000000);
		for (x = 0; x < PlayerNames.length; x++)
		{
			DataObject = new(None, PlayerNames[x]) class'RPGPlayerDataObject';
			DataObject.ClearConfig();
		}

		bReset = false;
		SaveConfig();
	}

	for (x = 0; x < WeaponModifiers.length; x++)
		TotalModifierChance += WeaponModifiers[x].Chance;

	spawn(class'RPGArtifactManager');

	if (SaveDuringGameInterval > 0.0)
		SetTimer(SaveDuringGameInterval, true);

	if (StartingLevel < 1)
	{
		StartingLevel = 1;
		SaveConfig();
	}

	BotSpendAmount = PointsPerLevel * 3;

	//HACK - if another mutator played with the weapon pickups in *BeginPlay() (like Random Weapon Swap does)
	//we won't get CheckRelevance() calls on those pickups, so find any such pickups here and force it
	foreach DynamicActors(class'Pickup', P)
		if (P.bScriptInitialized && !P.bGameRelevant && !CheckRelevance(P))
			P.Destroy();

	Super.PostBeginPlay();
}

Ok everything is fine there, but when I play using the new gametype that I created, the game rules won't aply, and in the log I receive this error msg:
Code:
Warning: RPGRules SWMS-1on1-Desolation.RPGRules (Function Engine.Actor.PreBeginPlay:0043) Accessed None 'BaseMutator'
Warning: MutUT2004RPG SWMS-1on1-Desolation.MutUT2004RPG (Function ut2004rpg.MutUT2004RPG.PostBeginPlay:0015) Accessed None 'G'
Warning: MutUT2004RPG SWMS-1on1-Desolation.MutUT2004RPG (Function ut2004rpg.MutUT2004RPG.PostBeginPlay:001D) Attempt to assign variable through None
Warning: MutUT2004RPG SWMS-1on1-Desolation.MutUT2004RPG (Function ut2004rpg.MutUT2004RPG.PostBeginPlay:0025) Accessed None 'G'
Warning: MutUT2004RPG SWMS-1on1-Desolation.MutUT2004RPG (Function ut2004rpg.MutUT2004RPG.PostBeginPlay:002D) Attempt to assign variable through None
Warning: MutUT2004RPG SWMS-1on1-Desolation.MutUT2004RPG (Function ut2004rpg.MutUT2004RPG.PostBeginPlay:0039) Accessed None 'G'
Warning: MutUT2004RPG SWMS-1on1-Desolation.MutUT2004RPG (Function ut2004rpg.MutUT2004RPG.PostBeginPlay:0041) Attempt to assign variable through None
Warning: RPGArtifactManager SWMS-1on1-Desolation.RPGArtifactManager (Function Engine.Actor.PreBeginPlay:0043) Accessed None 'BaseMutator'

Maybe I've done something wrong in the gametype XD since in other gametypes it's working just fine =/

here is my new gametype code:
Code:
class MSGame extends xTeamGame;


defaultproperties
{
     HUDType="UT2004RPG.HudSWTeamDeathMatch"
     DMHints(10)="If you are a vampire avoid the sun. If not you can enjoy it."
     DMHints(11)="Distroy as many enemies as you can."
     DMHints(12)="Try working out with your race as a team, use advanced tatics."
     bWeaponStay=False
     bAllowVehicles=True
     bLiberalVehiclePaths=True
     MapListType="UT2004RPG.MapList_Massacre"
     MapPrefix="SWMS"
     BeaconName="SWMS"
     GoalScore=0
     TimeLimit=0
     MutatorClass="UT2004RPG.MutUT2004RPG"
     GameName="Shadows War Massacre"
     ScreenShotName="UT2004Thumbnails.TDMShots"
     DecoTextName="UT2004RPG.MSGame"
     Acronym="SWMS"
}
 

Wormbo

Administrator
Staff member
Jun 4, 2001
5,913
36
48
Germany
www.koehler-homepage.de
So, your PostBeginPlay() function is part of a Mutator class that is spawned as the BaseMutator of your gametype.

Let's have a look at your first log warning:
"Warning: RPGRules SWMS-1on1-Desolation.RPGRules (Function Engine.Actor.PreBeginPlay:0043) Accessed None 'BaseMutator'"
An access to an empty object reference (an "Accessed None") inside the Actor.PreBeginPlay() function in the context of the RPGRules actor you spawned in the PostBeginPlay() function of your mutator. According to the warning, the access to the BaseMutator variable failed.
With that knowledge, let's have a look at Actor.PreBeginPlay():
Code:
event PreBeginPlay()
{
    // Handle autodestruction if desired.
    if( !bGameRelevant && (Level.NetMode != NM_Client) && !Level.Game.BaseMutator.CheckRelevance(Self) )
        Destroy();
    else if ( (Level.DetailMode == DM_Low) && (CullDistance == Default.CullDistance) )
        CullDistance *= 0.8;
}
"If not bGameRelevant" - like most classes this also applies to GameRules and, unless you changed it, also to your RPGRules class - "...and no on client" - mutators are serverside-only, so its PostBeginPlay() and also this code is not executed clientsidely - "...and not Level.Game.BaseMutator..." - AHA!
This code is executed during your PostBeginPlay(), which is executed during the Spawn() that creates your mutator. Your mutator instance will eventually be assigned to the Level.Game.BaseMutator variable, but this happens after Spawn() returned. Now, an Accessed None is a graceful failure - it simply results in the null value of the expected return type - in this case "False", the null value of the "bool" type. "!False" is True, and since the previous two parts of thecondition were also met, execution goes into the if block, which here reads "Destroy()".
In other words, since there's no BaseMutator yet, your RPGRules self-destructs before the Spawn() call that should create it returns. Destroyed actors result in a reference to None, which is what Spawn(class'RPGRules') returns in that case.

Why does it work for other gametypes? Simple. In other gametypes another mutator takes the role of the BaseMutator and your mutator is spawned some time later, so the BaseMutator reference is already valid and the RPGRules won't self-destruct on spawn.

So, how do you get around that problem? You could go the hard-core route and override PreBeginPlay() in your RPGRules class without calling Super. The other, possibly more elegant way is to just make use of the other conditions tested in Actor.PreBeginPlay(). You can't affect the client test, but you can affect the value of bGameRelevant in the defaultproperties block of the RPGRules class. Set it to True and your problem should be gone.

Same goes for the RPGArtifactManager, which is also spawned in your mutator'S PostBeginPlay(), i.e. before the BaseMutator variable has a valid reference.