Legacy:ProfileConfigSet

From Unreal Wiki, The Unreal Engine Documentation Site
UT2003 :: Object >> ProfileConfigSet (Ladder1.46)
//-----------------------------------------------------------
// Ladder.ProfileConfigSet
// Loosely (very loosely) based on GameConfigSet
//
// ProfileConfigSet is, in essence, a primitive database program which
// stores and retrieves not only numerous different "GameConfigSet"
// profiles, but map, mutator, serveractor and accesscontrol information as well.
//-----------------------------------------------------------
class ProfileConfigSet extends Object
	Config(System)
	PerObjectConfig;

const LOGNAME = 'ProfileConfigSet';

// Variables that are used globally
var LevelInfo							Level;			// Need access to Level object
var protected string					AllMapsPrefix;	// Which map prefix is currently loaded
var protected array< class<GameInfo> >	AllGameTypes;	// All valid gametypes
var protected config string 			DefaultGameType;// The gametype for this profile
var protected class<AccessControl> 		ACClass;		// The access control class
var protected GameConfigSet 			RealConfigSet;	// Actual gameconfigset used by the game

var protected class<GameInfo>			GameClass;		// Which game class is used by this profile
var protected PlayInfo					PInfo;			// PlayInfo for currently active GameType, AccessControl Class, and Active Mutators
var protected MapList					Maps;			// Maps currently in rotation

// Regarding ServerActors
struct ProfileSA {
						var string		ActorClass;
						var bool		bRequired; };
var config array<ProfileSA>				AllServerActors;
var config array<string>				ProfileServerActors;
var protected array<string>				GameServerActors;
var protected StringArray				ActiveServerActors;

// Regarding Maps
struct ProfileMap {
						var string 		MapName;
						var int			MapListOrder;
						var bool 		bRequired; };
var config int 							MaxMaps;				// Maximum maps allowed in maplist
var protected array<string> 			GameMaps;				// List of all maps for this gametype that exist on server
var protected config array<ProfileMap>	AllMaps;				// List of all maps that could be used by this profile
var protected config array<string>		ProfileMaps;			// List of all maps that are included in the maplist for this profile
var protected StringArray				ActiveMaps;				// StringArray of ProfileMaps

// Regarding Mutators
struct ProfileMutator {
						var string 			MutatorName;
						var bool 			bRequired; };
var string 									NextMutators;			// What mutators were set during this session
var protected array<xUtil.MutatorRecord>	GameMutators;			// List of all mutators that exist on server
var protected config array<ProfileMutator>	AllMutators;			// List of all mutators that could be used this profile
var protected config array<string> 			ProfileMutators;		// Mutators that will be loaded by this profile
var protected StringArray					ActiveMutators;			// StringArray of ProfileMutators

// Regarding PlayInfo
var protected config string					AccessClass;
struct ProfileSetting {	var string 			SettingName;
						var string 			SettingValue; };
var protected config array<ProfileSetting> 	ProfileSettings;	// Stored Profile Settings which include non-active mutators PlayInfo
var protected array<ProfileSetting> 		ActiveSettings;		// Representation of stored profile settings including only active mutators

// Whether we are currently editing something
var protected bool 							bEdit;

// Localized strings
var localized string	ErrorNoGameType;
var localized string	SavingToFile;
var localized string	DidNotStartEdit;

function Init(LevelInfo Lv, optional string GameType, optional string AC)
{
	if (Lv==None)
		return;

	Level = Lv;
	if (GameType!="") DefaultGameType = GameType;
	if (AC != "") AccessClass = AC;
	else AccessClass = Level.Game.AccessControlClass;
	AllMapsPrefix = FindGameType(DefaultGameType).default.MapPrefix;

	// Make sure that none of the configured mutators have been removed from this server
	ValidateProfile();
}

function Cleanup()
{
	// Destroy any references to actors
	if (Level != None)
		Level=None;

	if (ActiveMaps != None)
		ActiveMaps = None;

	if (Maps != None)
		Maps = None;
}

function ValidateProfile()
{
	ValidateAllMutators();
	ValidateAllMaps();
	ValidateAllServerActors();
}

function ValidateAllMutators()
{
	local class<Mutator> 	TempMutClass;
	local int i;

	for (i = 0;i < AllMutators.Length; i++)
	{
		TempMutClass = class<Mutator>(DynamicLoadObject(AllMutators[i].MutatorName, Class'class'));
		if (TempMutClass == None)
		{
			log("Mutator class '"$AllMutators[i].MutatorName$"' has been removed from this server.  Removing mutator from current profile.",LOGNAME);
			AllMutators.Remove(i--,1);
			SaveConfig();
		}
	}
}

function ValidateAllMaps()
{
	local int i, j;

	LoadAllMaps();
	for (i = 0;i < AllMaps.Length;i++)
	{
		for (j = 0;j < GameMaps.Length;j++)
			if (GameMaps[j] ~= AllMaps[i].MapName)
				break;

		if (j == GameMaps.Length)
		{
			log("Map '"$AllMaps[i].MapName$"' has been removed from this server. Removing map from profile.",LOGNAME);
			AllMaps.Remove(i--,1);
			SaveConfig();
		}
	}
}

function ValidateAllServerActors()
{
	local int i;
	local class<Info> TempSA;

	for (i=0;i<AllServerActors.Length;i++)
	{
		TempSA = class<Info>(DynamicLoadObject(AllServerActors[i].ActorClass,Class'Class'));
		if (TempSA == None)
		{
			log("ServerActor '"$AllServerActors[i].ActorClass$"' does not exist on this server.  Removing ServerActor from profile.",LOGNAME);
			AllServerActors.Remove(i--,1);
			SaveConfig();
		}
	}
}

function bool StartEdit()
{
	if (Level == None || bEdit)
		return false;

	bEdit = true;

	if (PInfo == None)
		PInfo = New(None) class'PlayInfo';

	if (AllGameTypes.Length == 0)
		LoadGameTypes();
	GameClass = FindGameType(DefaultGameType);
	if (GameClass == None)
	{
		log(ErrorNoGameType$DefaultGameType);
		return false;
	}

	if (AccessClass != "")
		ACClass = class<AccessControl>(DynamicLoadObject(AccessClass, class'class'));

	if (Level != None && Level.Game != None && Level.Game.AccessControl != None && AccessControlIni(Level.Game.AccessControl) != None && AccessControlIni(Level.Game.AccessControl).ConfigSet != None)
		RealConfigSet = AccessControlIni(Level.Game.AccessControl).ConfigSet;

	if (ActiveMutators == None)
		ActiveMutators = new(None) class'SortedStringArray';
	if (ActiveMaps == None)
		ActiveMaps = new(None) class'StringArray';
	if (ActiveServerActors == None)
		ActiveServerActors = new(None) class'SortedStringArray';

	NextMutators = "";
	LoadAllMaps();

	if (GameMutators.Length == 0)
		LoadAllMutators();
	LoadAllServerActors();

	SetUsedMaps();
	SetUsedMutators();
	SetUsedServerActors();

	// Load Game Setting
	LoadSettings(GameClass);
	AllMapsPrefix = GameClass.default.MapPrefix;
	return true;
}

function bool EndEdit(bool bSave, optional bool bQuiet)
{
	if (Level == None || !bEdit)
		return false;

	// Save all data where it belongs
	if (bSave)
	{
		if (!bQuiet) Log(Name@SavingToFile);

		SaveUsedMaps();
		SaveUsedMutators();
		SaveUsedServerActors();
		SaveConfig();
	}

	bEdit = false;
	return true;
}

function ReplaceWith(ProfileConfigSet SourcePCS)
{
	local int i;

	if (!bEdit)
	{
		log("ReplaceWith()"@DidNotStartEdit);
		return;
	}

	if (SourcePCS.GetGameClass() != None)
	{
		Wipe();
		DefaultGameType = string(SourcePCS.GetGameClass());
		GameClass = FindGameType(DefaultGameType);
		AccessClass = SourcePCS.GetAccessControl();
		ACClass = SourcePCS.GetAccessClass();
		AllMapsPrefix = GameClass.default.MapPrefix;
		MaxMaps = SourcePCS.MaxMaps;

		AllMaps = SourcePCS.GetProfileMaps();
		AllMutators = SourcePCS.GetProfileMutators();
		AllServerActors = SourcePCS.GetProfileServerActors();
		ProfileMaps = SourcePCS.GetUsedMaps();
		ProfileMutators = SourcePCS.GetUsedMutators();
		ProfileServerActors = SourcePCS.GetUsedServerActors();
		ProfileSettings.Length = SourcePCS.Count();
		for (i = 0; i < SourcePCS.Count(); i++)
			SetProfileParam(i, SourcePCS.GetProfileParamName(i), SourcePCS.GetProfileParam(i));

		LoadSettings(GameClass);
	}
}

function bool CanEdit()
{
	return !bEdit;
}

// This profile was deleted, but PerObjectConfig config values cannot be completely removed from .ini (that I know of)
// We can, however, make the ini entry for this object as small as possible until it is reused.
final function Wipe()
{
//log("Wiping Profile"@Name);
	ActiveMaps.Reset();
	ActiveMutators.Reset();

	MaxMaps = 0;

	ProfileMaps.Length = 0;
	AllMaps.Length = 0;
	ProfileMutators.Length = 0;
	AllMutators.Length = 0;
	ProfileServerActors.Length = 0;
	AllServerActors.Length = 0;
	ProfileSettings.Length = 0;
	ActiveSettings.Length = 0;

	DefaultGameType = "";
	AccessClass = "";
	AllMapsPrefix = "";
	NextMutators = "";

	GameClass = None;
	ACClass = None;
	Maps = None;

}

///////////////////////////////////////////////////////////////////
// Public GameType Information
///////////////////////////////////////////////////////////////////

function bool SetGameType(optional string NewGameType)
{
	local string OldGameType;

	if (!bEdit)
	{
		log("SetGameType()"@DidNotStartEdit);
		return false;
	}

	OldGameType = DefaultGameType;
	if (NewGameType=="")
		NewGameType=DefaultGameType;
	else DefaultGameType = NewGameType;

	if (AllGameTypes.Length==0)
		LoadGameTypes();

	GameClass = FindGameType(NewGameType);

	if (GameClass != None && (NewGameType != OldGameType))
	{
		AllMapsPrefix = GameClass.default.MapPrefix;
		ClearUsedMaps();
		ClearAllMaps();
		ClearProfile(ProfileSettings);
		LoadSettings(GameClass);
		return true;
	}
	return false;
}

function class<GameInfo> GetGameClass()
{
	if (GameClass != None)
		return GameClass;

	return None;
}

function string GetGameAcronym()
{
	if (GameClass != None)
		return GameClass.default.Acronym;

	return "";
}

function string GetAccessControl()
{
	return AccessClass;
}

function class<AccessControl> GetAccessClass()
{
	if (ACClass != None)
		return ACClass;
	return None;
}

/////////////////////////////////////////////////////////////
// Public MapList Functions
/////////////////////////////////////////////////////////////
function bool AddProfileMap(string MapMask, bool bRequired)
{
	local int i;
	local ProfileMap tmp;

	if (!bEdit)
	{
		log("AddProfileMap()"@DidNotStartEdit);
		return false;
	}

	for (i=0;i<AllMaps.Length;i++)
	{
		if (AllMaps[i].MapName ~= MapMask)
		{
			AllMaps[i].bRequired = bRequired;
			return true;
		}
	}

	for (i=0;i<GameMaps.Length;i++)
	{
		if (MapMask ~= GameMaps[i])
		{
			tmp.MapName = GameMaps[i];
			tmp.bRequired = bRequired;
			AllMaps[AllMaps.Length] = tmp;
			return true;
		}
	}

	return false;
}

function bool DelProfileMap(string MapName)
{
	local int i;
	local string Str;

	if (!bEdit)
	{
		log("DelProfileMap()"@DidNotStartEdit);
		return false;
	}

	for (i=0;i<AllMaps.Length;i++)
	{
		Str = AllMaps[i].MapName;
		if (Str ~= MapName)
		{
			AllMaps.Remove(i, 1);
			SetUsedMaps();
			return true;
		}
	}

	return false;
}

function string AddMap(string MapMask, int Order)
{
	local int i, j, k;
	local bool bFound;

	if (!bEdit)
	{
		log("AddMaps()"@DidNotStartEdit);
		return "";
	}

	k = ActiveMaps.Count();
	for (i = 0; i<AllMaps.Length; i++)
	{
		if (AllMaps[i].MapName ~= MapMask)
		{
			// Found a matching map, see if its already in the Used Maps list
			bFound = false;
			for (j = 0; j < k; j++)
			{
				if (ActiveMaps.GetTag(j) ~= AllMaps[i].MapName)
				{
					bFound = true;
					AllMaps[i].MapListOrder = Order;
					break;
				}
			}

			if (!bFound && ((MaxMaps == 0) || (k < MaxMaps)))
			{
				AllMaps[i].MapListOrder = ActiveMaps.Count();
				ActiveMaps.Add(string(i), AllMaps[i].MapName);
				return AllMaps[i].MapName;
			}
		}
	}
	return "";
}

function string RemoveMap(string MapName)
{
	local int i;
	local string TempStr;
	if (!bEdit)
	{
		log("RemoveMaps()"@DidNotStartEdit);
		return "";
	}

	for (i=0; i<ActiveMaps.Count(); i++)
	{
		TempStr = ActiveMaps.GetTag(i);
		if (TempStr ~= MapName)
		{
			ActiveMaps.Remove(i);
			return TempStr;
		}
	}
	return "";
}

function array<string> FindMaps(string MapMask)
{
	local array<string> FoundMasks, FoundMaps;
	local int i, j, k;
	local bool bFound;

	class'wUtils103.wString'.static.Split2(MapMask, " ", FoundMasks);
	if (FoundMasks.Length > 0)
	{
		for (i = 0; i<AllMaps.Length; i++)
		{
			for (j = 0; j<FoundMasks.Length; j++)
			{
				if (class'wUtils103.wString'.static.MaskedCompare(AllMaps[i].MapName, FoundMasks[j]))
				{
					// Found a matching map, see if its already in the Used Maps list
					bFound = false;
					for (k = 0; k<ActiveMaps.Count(); k++)
					{
						if (ActiveMaps.GetTag(k) ~= AllMaps[i].MapName)
						{
							bFound = true;
							break;
						}
					}

					if (bFound)
						FoundMaps[FoundMaps.Length] = "+"$AllMaps[i].MapName;
					else
						FoundMaps[FoundMaps.Length] = AllMaps[i].MapName;

					break;
				}
			}
		}
	}
	return FoundMaps;
}

function MapList GetMaps()
{
	if (Maps==None)
	{
		if (GameClass==None)
			GameClass=class<GameInfo>(DynamicLoadObject(DefaultGameType, class'Class'));

		Maps = Level.Game.GetMapList(AllMapsPrefix);
	}

	return Maps;
}

function array<string> GetUsedMaps()
{
	local array<string>	Strings;
	local int i;

	if (ActiveMaps == None)
		ActiveMaps = new(None) class'StringArray';

	for (i = 0; i<ActiveMaps.Count(); i++)
		Strings[Strings.Length] = ActiveMaps.GetTag(i);

	return Strings;
}

function array<string> GetUnusedMaps()
{
	local array<string> Strings;
	local int i;

	if (ActiveMaps == None)
		ActiveMaps = new(None) class'StringArray';

	Strings.Length = AllMaps.Length;
	for (i = 0; i<AllMaps.Length; i++)
		Strings[i] = AllMaps[i].MapName;

	// Tag all used mutators
	for (i = 0; i<ActiveMaps.Count(); i++)
		Strings[int(ActiveMaps.GetItem(i))] = "";

	for (i = 0; i<Strings.Length; i++)
	{
		if (Strings[i] == "")
		{
			Strings.Remove(i, 1);
			i--;
		}
	}
	return Strings;
}

function bool MapIsRequired(string MapName)
{
	local int i;
	for (i=0;i<AllMaps.Length;i++)
		if (MapName ~= AllMaps[i].MapName && AllMaps[i].bRequired)
			return true;
	return false;
}

function array<ProfileMap> GetProfileMaps()
{
	return AllMaps;
}

function int GetMaxMaps()
{
	return MaxMaps;
}

/////////////////////////////////////////////////////////////////////
// Public Mutator list functions
/////////////////////////////////////////////////////////////////////

function array<ProfileMutator> GetProfileMutators()
{
	return AllMutators;
}

function array<string> GetUsedMutators()
{
	local array<string>	Strings;
	local int i;

	if (ActiveMutators == None)
		ActiveMutators = new(None) class'SortedStringArray';

	for (i = 0; i<ActiveMutators.Count(); i++)
		Strings[Strings.Length] = ActiveMutators.GetTag(i);

	return Strings;
}

function array<string> GetUnusedMutators()
{
	local array<string> Strings;
	local int i;

	if (ActiveMutators == None)
		ActiveMutators = new(None) class'SortedStringArray';

	Strings.Length = AllMutators.Length;
	for (i = 0; i<AllMutators.Length; i++)
		Strings[i] = AllMutators[i].MutatorName;

	// Tag all used mutators
	for (i = 0; i<ActiveMutators.Count(); i++)
		Strings[int(ActiveMutators.GetItem(i))] = "";

	for (i = 0; i<Strings.Length; i++)
	{
		if (Strings[i] == "")
		{
			Strings.Remove(i, 1);
			i--;
		}
	}
	return Strings;
}

function bool AddMutator(string MutatorName)
{
	local int i;
	local string Str;

	if (!bEdit)
	{
		log("AddMutator()"@DidNotStartEdit);
		return false;
	}

	if (ActiveMutators.Count() == 0)
		SetUsedMutators();

	// First make sure it isnt in the list
	for (i = 0; i<ActiveMutators.Count(); i++)
	{
		Str = ActiveMutators.GetTag(i);
		if (Str ~= MutatorName || Right(Str, Len(MutatorName) + 1) ~= ("."$MutatorName))
			return false;
	}

	for (i=0;i<AllMutators.Length;i++)
	{
		Str = AllMutators[i].MutatorName;
		if (Str ~= MutatorName || Right(Str, Len(MutatorName) + 1) ~= ("."$MutatorName))
		{
			ActiveMutators.Add(string(i), Str);
			return true;
		}
	}
	return false;
}

function bool DelMutator(string MutatorName)
{
	local int i;
	local string Str;

	if (!bEdit)
	{
		log("DelMutator()"@DidNotStartEdit);
		return false;
	}

	if (MutIsRequired(MutatorName))
		return false;

	// First make sure it is in the list
	for (i = 0; i<ActiveMutators.Count(); i++)
	{
		Str = ActiveMutators.GetTag(i);
		if (Str ~= MutatorName || Right(Str, Len(MutatorName) + 1) ~= ("."$MutatorName))
		{
			ActiveMutators.Remove(i);
			return true;
		}
	}
	return false;
}

// Add mutator to list of possible mutators
function bool AddProfileMutator(string MutatorName, bool bRequired)
{
	local int i,j;
	local string Str;
	local ProfileMutator tmp;

	if (!bEdit)
	{
		log("AddProfileMutator()"@DidNotStartEdit);
		return false;
	}

	for (i=0;i<AllMutators.Length;i++)
	{
		Str = AllMutators[i].MutatorName;
		if (Str ~= MutatorName || Right(Str, Len(MutatorName) + 1) ~= ("."$MutatorName))
		{
			AllMutators[i].bRequired = bRequired;
			return false;
		}
	}

	for (j=0;j<GameMutators.Length;j++)
	{
		Str = GameMutators[j].ClassName;
		if (Str ~= MutatorName || Right(Str, Len(MutatorName) + 1) ~= ("."$MutatorName))
		{
			tmp.MutatorName = Str;
			tmp.bRequired = bRequired;
			AllMutators[AllMutators.Length] = tmp;
			return true;
		}
	}

	return false;
}

function bool DelProfileMutator(string MutatorName)
{
	local int i;
	local string Str;

	if (!bEdit)
	{
		log("DelProfileMutator()"@DidNotStartEdit);
		return false;
	}

	for (i=0;i<AllMutators.Length;i++)
	{
		Str = AllMutators[i].MutatorName;
		if (Str ~= MutatorName || Right(Str, Len(MutatorName)+1) ~= ("."$MutatorName))
		{
			AllMutators.Remove(i, 1);
			SetUsedMutators();
			return true;
		}
	}

	return false;
}

function bool MutIsRequired(string MutatorName)
{
	local int i;
	for (i=0;i<AllMutators.Length;i++)
		if (MutatorName ~= AllMutators[i].MutatorName && AllMutators[i].bRequired)
			return true;
	return false;
}

//////////////////////////////////
// Public ServerActor Functions
//////////////////////////////////

function array<ProfileSA> GetProfileServerActors()
{
	return AllServerActors;
}

function array<string> GetUsedServerActors()
{
	local array<string>	Strings;
	local int i;

	if (ActiveServerActors == None)
		ActiveServerActors = new(None) class'SortedStringArray';

	for (i = 0; i<ActiveServerActors.Count(); i++)
		Strings[Strings.Length] = ActiveServerActors.GetTag(i);

	return Strings;
}

function bool AddProfileServerActor(string ActorName, bool bRequired)
{
	local int i;
	local ProfileSA tmp;

	if (!bEdit)
	{
		log("AddProfileServerActor()"@DidNotStartEdit);
		return false;
	}

	for (i=0;i<AllServerActors.Length;i++)
	{
		if (AllServerActors[i].ActorClass ~= ActorName)
		{
			AllServerActors[i].bRequired = bRequired;
			return false;
		}
	}

	tmp.ActorClass = ActorName;
	tmp.bRequired = bRequired;
	AllServerActors[AllServerActors.Length] = tmp;
	SetUsedServerActors();
	return true;
}

function bool AddServerActor(string ActorName)
{
	local int i;

	if (!bEdit)
	{
		log("AddServerActor()"@DidNotStartEdit);
		return false;
	}

	// Check for already exists
	for (i=0;i<ProfileServerActors.Length;i++)
	{
		if (ProfileServerActors[i] ~= ActorName)
			return false;
	}

	for (i=0;i<AllServerActors.Length;i++)
	{
		if (AllServerActors[i].ActorClass ~= ActorName)
		{
			ProfileServerActors[ProfileServerActors.Length] = ActorName;
			SetUsedServerActors();
			return true;
		}
	}
	return false;
}

function bool DelProfileServerActor(string ActorName)
{
	local int i;

	if (!bEdit)
	{
		log("DelProfileServerActor()"@DidNotStartEdit);
		return false;
	}

	for (i=0;i<AllServerActors.Length;i++)
	{
		if (AllServerActors[i].ActorClass ~= ActorName)
		{
			AllServerActors.Remove(i,1);
			SetUsedServerActors();
			return true;
		}
	}

	return false;
}

function bool DelServerActor(string ActorName)
{
	local int i;

	if (!bEdit)
	{
		log("DelServerActor()"@DidNotStartEdit);
		return false;
	}

	i = ActiveServerActors.FindTagId(ActorName);
	if (i >= 0)
	{
		ActiveServerActors.Remove(i);
		return true;
	}

	return false;
}

function bool ServerActorIsRequired(string ActorName)
{
	local int i;
	for (i=0;i<AllServerActors.Length;i++)
		if (ActorName ~= AllServerActors[i].ActorClass)
			return AllServerActors[i].bRequired;

	return false;
}


////////////////////////////////
// Protected Helping functions
////////////////////////////////

// Always reload settings at StartEdit()
protected function string LoadSettings(class<GameInfo> GameClass)
{
	local class<Mutator> MutClass;
	local class<Info>	SAClass;
	local int i,j;

	if (!bEdit)
	{
		log("LoadSettings()"@DidNotStartEdit);
		return "";
	}

	if (PInfo == None)
		PInfo = new(None) class'PlayInfo';

	PInfo.Clear();

	// Unhook GameInfo.FillPlayInfo()'s hook to BaseMutator.FillPlayInfo()
	// Otherwise, we end up with mutator playinfo that we may not want
	GameClass.static.FillPlayInfo(PInfo);
	PInfo.PopClass();

	if (ACClass == None && AccessClass != "")
		ACClass = class<AccessControl>(DynamicLoadObject(AccessClass,class'Class'));

	if (ACClass!=None)
	{
		ACClass.static.FillPlayInfo(PInfo);
		PInfo.PopClass();
	}

	if (GameClass.default.MutatorClass != "")
	{
		MutClass = class<Mutator>(DynamicLoadObject(GameClass.default.MutatorClass,class'Class'));
		if (MutClass != None)
		{
			MutClass.static.FillPlayInfo(PInfo);
			PInfo.PopClass();
		}
	}

	if (ActiveMutators.Count() == 0)
		SetUsedMutators();

	if (ActiveServerActors.Count() == 0)
		SetUsedServerActors();

	for (i=0;i<ActiveMutators.Count();i++)
	{
		MutClass=class<Mutator>(DynamicLoadObject(AllMutators[int(ActiveMutators.GetItem(i))].MutatorName,class'class'));
		if (MutClass!=None)
		{
			MutClass.static.FillPlayInfo(PInfo);
			PInfo.PopClass();
		}
	}

	for (i=0;i<ActiveServerActors.Count();i++)
	{
		j = int(ActiveServerActors.GetItem(i));
		SAClass = class<Info>(DynamicLoadObject(AllServerActors[j].ActorClass,class'Class'));
		if (SAClass != None)
		{
			SAClass.static.FillPlayInfo(PInfo);
			PInfo.PopClass();
		}
	}

	// Create active profile array
	InitializeProfile(ActiveSettings);
	if (ProfileSettings.Length > 0)
	{
		ActiveSettings.Length = ProfileSettings.Length;
		// Then retrieve all stored values from saved profile
		for (i=0;i<ProfileSettings.Length;i++)
			ActiveSettings[i] = ProfileSettings[i];
	}
	else // Copy active profile to saved profile.
	{
		ProfileSettings.Length = ActiveSettings.Length;
		for (i=0;i<ActiveSettings.Length;i++)
			SetProfileParam(i,ActiveSettings[i].SettingName,ActiveSettings[i].SettingValue);
	}

	return string(GameClass);
}

protected function LoadGameTypes()
{
	local class<GameInfo>	TempClass;
	local String 			NextGame;
	local int				i;

	// Compile a list of all gametypes.
	i = 0;
	NextGame = Level.GetNextInt("Engine.GameInfo", 0);
	AllGameTypes.Length = 0;
	while (NextGame != "")
	{
		TempClass = class<GameInfo>(DynamicLoadObject(NextGame, class'Class'));
		if (TempClass != None)
			AllGameTypes[AllGameTypes.Length] = TempClass;

		NextGame = Level.GetNextInt("Engine.GameInfo", ++i);
	}
}

protected function class<GameInfo> FindGameType(string GameType)
{
	local class<GameInfo> TempClass;
	local int i;

	if (AllGameTypes.Length == 0)
		LoadGameTypes();
	TempClass = None;
	for (i=0; i<AllGameTypes.Length; i++)
	{
		TempClass = AllGameTypes[i];
		if (GameType ~= string(TempClass))				break;
		if (GameType ~= TempClass.default.Acronym)		break;
		if (GameType ~= TempClass.default.DecoTextName)	break;
		if (Right(string(TempClass), Len(GameType)+1) ~= ("."$GameType))			break;
		if (Right(TempClass.default.DecoTextName, Len(GameType)+1) ~= ("."$GameType))	break;
	}
	return TempClass;
}

protected function LoadAllMaps()
{
	if (GameClass==None)
		GameClass = FindGameType(DefaultGameType);

	if (GameClass == None)
		return;

	GameMaps.Length = 0;
	GameClass.static.LoadMapList(GameClass.default.MapPrefix, GameMaps);
}

protected function LoadAllMutators()
{
	class'xUtil'.static.GetMutatorList(GameMutators);
}

protected function LoadAllServerActors()
{
	local int i;
	local ConfigMaster ConfigM;

	if (Level != None && Level.Game != None && Level.Game.BaseMutator != None && ConfigMaster(Level.Game.BaseMutator.NextMutator) != None)
		ConfigM = ConfigMaster(Level.Game.BaseMutator.NextMutator);
	else return;

	for (i=0;i<ConfigM.ManagedActors.Length;i++)
		GameServerActors[GameServerActors.Length] = string(ConfigM.ManagedActors[i].SAClass);
}

protected function bool MapIsValid(string MapName)
{
	local string Prefix, ShortName;

	Divide(MapName,"-",Prefix,ShortName);
	if (Prefix ~= AllMapsPrefix)
		return true;
	return false;
}

protected function string GetMutatorGroup(string MutName)
{
	local int i;

	if (GameMutators.Length == 0)
		LoadAllMutators();

	for (i=0;i<GameMutators.Length;i++)
		if (GameMutators[i].ClassName ~= MutName)
			return GameMutators[i].GroupName;

	return "";
}

protected function SetUsedMaps()
{
	local int i,j;

	if (!bEdit)
	{
		log("SetUsedMaps()"@DidNotStartEdit);
		return;
	}

	if (AllMaps.Length == 0)
		return;

	ActiveMaps.Reset();

	// Add required maps first, up to MaxMaps count
	for (i=0;i<AllMaps.Length;i++)
	{
		if (MaxMaps > 0 && ActiveMaps.Count() >= MaxMaps)
			break;
		if (AllMaps[i].bRequired)
			ActiveMaps.Add(string(i),AllMaps[i].MapName);
	}

	if ((((MaxMaps > 0) && (ActiveMaps.Count() < MaxMaps)) || (MaxMaps == 0))&&(ProfileMaps.Length>0))
	{
		for (i=0;i<ProfileMaps.Length;i++)
		{
			if (!MapIsValid(ProfileMaps[i]))
			{
				ProfileMaps.Remove(i,1);
				i--;
				continue;
			}

			if (MaxMaps > 0 && ActiveMaps.Count() >= MaxMaps)
				break;
			for (j=0;j<AllMaps.Length;j++)
				if ((ProfileMaps[i]~=AllMaps[j].MapName) && (ActiveMaps.FindTagId(AllMaps[j].MapName)<0))
					ActiveMaps.Add(string(j), AllMaps[j].MapName);
		}
	}
}

// Loads used mutators from ini into ActiveMutators StringArray
protected function SetUsedMutators()
{
	local int i,j;
	local string MutatorGroups, tmp;
	if (!bEdit)
	{
		log("SetUsedMutators()"@DidNotStartEdit);
		return;
	}

	if (AllMutators.Length == 0)
		return;

	ActiveMutators.Reset();
	// Add required mutators first
	for (i=0;i<AllMutators.Length;i++)
	{
		if (AllMutators[i].bRequired)
		{
			tmp = GetMutatorGroup(AllMutators[i].MutatorName);
			if (InStr(MutatorGroups, tmp) == -1)
			{
				if (MutatorGroups != "") MutatorGroups = MutatorGroups $ ",";
				MutatorGroups = MutatorGroups $ tmp;
				ActiveMutators.Add(string(i), AllMutators[i].MutatorName);
			}
		}
	}

	for (i=0;i<ProfileMutators.Length;i++)
	{
		for (j=0;j<AllMutators.Length;j++)
		{
			if ((AllMutators[j].MutatorName ~= ProfileMutators[i])&&(ActiveMutators.FindTagId(AllMutators[j].MutatorName)<0))
			{
				tmp = GetMutatorGroup(AllMutators[j].MutatorName);
				if (InStr(MutatorGroups, tmp) == -1)
				{
					if (MutatorGroups != "") MutatorGroups = MutatorGroups $ ",";
					MutatorGroups = MutatorGroups $ tmp;
					ActiveMutators.Add(string(j), AllMutators[j].MutatorName);
				}
			}
		}
	}
}

protected function SetUsedServerActors()
{
	local int i,j;
	if (!bEdit)
	{
		log("SetUsedServerActors()"@DidNotStartEdit);
		return;
	}

	if (AllServerActors.Length == 0)
		return;

	ActiveServerActors.Reset();
	// Add required server actors first
	for (i=0;i<AllServerActors.Length;i++)
		if (AllServerActors[i].bRequired)
			ActiveServerActors.Add(string(i), AllServerActors[i].ActorClass,True);

	for (i=0;i<ProfileServerActors.Length;i++)
		for (j=0;j<AllServerActors.Length;j++)
			if (AllServerActors[j].ActorClass ~= ProfileServerActors[i])
				ActiveServerActors.Add(string(j),AllServerActors[j].ActorClass,True);
}

protected function ClearUsedMaps()
{
	ProfileMaps.Length = 0;
	SaveConfig();
}

protected function ClearUsedMutators()
{
	ProfileMutators.Length = 0;
	SaveConfig();
}

protected function ClearUsedServerActors()
{
	ProfileServerActors.Length = 0;
	SaveConfig();
}

protected function ClearAllMaps()
{
	AllMaps.Length=0;
	SaveConfig();
}

protected function ClearAllMutators()
{
	AllMutators.Length = 0;
	SaveConfig();
}

protected function ClearAllServerActors()
{
	AllServerActors.Length = 0;
	SaveConfig();
}

// Saves active maps for this profile to ini
protected function SaveUsedMaps()
{
	local int i;
	if (!bEdit)
	{
		log("SaveUsedMaps()"@DidNotStartEdit);
		return;
	}

	ClearUsedMaps();
	for (i=0;i<ActiveMaps.Count();i++)
		ProfileMaps[ProfileMaps.Length] = ActiveMaps.GetTag(i);
}

// Saves ActiveMutators to ini
protected function SaveUsedMutators()
{
	local int i;

	if (!bEdit)
	{
		log("SaveUsedMutators()"@DidNotStartEdit);
		return;
	}

	ClearUsedMutators();
	for (i=0;i<ActiveMutators.Count();i++)
		ProfileMutators[ProfileMutators.Length] = ActiveMutators.GetTag(i);
}

protected function SaveUsedServerActors()
{
	local int i;

	if (!bEdit)
	{
		log("SaveUsedServerActors()"@DidNotStartEdit);
		return;
	}
	ClearUsedServerActors();
	for (i=0;i<ActiveServerActors.Count();i++)
		ProfileServerActors[ProfileServerActors.Length] = ActiveServerActors.GetTag(i);
}

// Applies the active maps to the actual Game maplist
protected function ApplyMapList(array<string> NewMapList)
{
	local int i;

	if (GameClass == None)
		GameClass = class<GameInfo>(DynamicLoadObject(DefaultGameType,class'Class'));

	if (Maps == None)
		GetMaps();

	if (Maps == None)
		return;

	Maps.Maps.Length = 0;
	for (i=0;i<NewMapList.Length;i++)
		Maps.Maps[i] = NewMapList[i];

	Maps.SaveConfig();
}

// Applies ActiveMutators to actual Game mutator list
protected function ApplyMutators()
{
	local int i;
	local array<string> TempMut;

	if (!bEdit)
	{
		log("ApplyMutators()"@DidNotStartEdit);
		return;
	}

	for (i=0;i<ActiveMutators.Count();i++)
		TempMut[TempMut.Length] = ActiveMutators.GetTag(i);

	if (TempMut.Length == 0)
		NextMutators = "";

	else NextMutators = class'wUtils103.wArray'.static.Join(TempMut,",");
}

protected function ClearProfile(out array<ProfileSetting> OldProfile)
{
	if (!bEdit)
	{
		log("ClearProfile()"@DidNotStartEdit);
		return;
	}

	OldProfile.Length = 0;
}

protected function bool InitializeProfile(out array<ProfileSetting> NewProfile)
{
	local int i;
	local ProfileSetting NewSetting;

	if (!bEdit)
	{
		log("InitializeProfile()"@DidNotStartEdit);
		return false;
	}

	if (PInfo==None)
		return false;

	if (NewProfile.Length>0)
		ClearProfile(NewProfile);

	for (i = 0; i < PInfo.Settings.Length; i++)
	{
		if (InStr(PInfo.Settings[i].SettingName,"AdminName") != -1 || InStr(PInfo.Settings[i].SettingName,"AdminEmail") != -1)
			continue;

		NewSetting.SettingName = PInfo.Settings[i].SettingName;
		NewSetting.SettingValue = PInfo.Settings[i].Value;

		NewProfile[NewProfile.Length] = NewSetting;
	}

	return true;
}

////////////////////////////////////////////////////////////////////////////
// PlayInfo Query Functions
////////////////////////////////////////////////////////////////////////////

function string GetParamName(int idx)
{
	if (idx < 0 || idx >= PInfo.Settings.Length)
		return "";

	return PInfo.Settings[idx].SettingName;
}

function int GetParamIndex(string SettingName)
{
	local int i;

	for (i = 0; i < PInfo.Settings.Length; i++)
		if (PInfo.Settings[i].SettingName ~= SettingName)
			break;

	if (i==PInfo.Settings.Length)
		return -1;

	return i;
}

function string GetParam(int idx)
{
	if (idx < 0 || idx >= PInfo.Settings.Length)
		return "";

	return PInfo.Settings[idx].Value;
}

function string GetNamedParam(string Parameter)
{
	local int i;
	local string SettingName;

	for (i = 0; i < PInfo.Settings.Length; i++)
	{
		SettingName = PInfo.Settings[i].SettingName;
		if (SettingName ~= Parameter || Right(SettingName, Len(Parameter) + 1) ~= ("."$Parameter))
			return PInfo.Settings[i].Value;
	}
	return "";
}

function array<string> GetMaskedParams(string ParamMask)
{
	local array<string> FoundParams;
	local array<string> FoundMasks;
	local string SettingName, ShortName;
	local int i, j, p;

	class'wUtils103.wString'.static.Split2(ParamMask, " ", FoundMasks);
	if (FoundMasks.Length > 0)
	{
		for (i = 0; i<PInfo.Settings.Length; i++)
		{
			SettingName = PInfo.Settings[i].SettingName;

			ShortName = SettingName;
			j = Instr(ShortName, ".");
			while (j != -1)
			{
				ShortName = Mid(ShortName, p+1);
				j = Instr(ShortName, ".");
			}

			for (j = 0; j<FoundMasks.Length; j++)
			{
				if (class'wUtils103.wString'.static.MaskedCompare(ShortName, FoundMasks[j]) || class'wUtils103.wString'.static.MaskedCompare(SettingName, FoundMasks[j]))
				{
					FoundParams[FoundParams.Length] = SettingName;
					FoundParams[FoundParams.Length] = PInfo.Settings[i].Value;
					break;
				}
			}
		}
	}
	return FoundParams;
}

/////////////////////////////////////////////////////////////////////
// Profile Query Functions
////////////////////////////////////////////////////////////////////

function int GetProfileParamIndex(string SettingName)
{
	local int i;

	for (i=0;i<ProfileSettings.Length;i++)
		if (ProfileSettings[i].SettingName ~= SettingName)
			break;

	if (i==ProfileSettings.Length)
		return -1;

	return i;
}

function string GetProfileParamName(int idx)
{
	if (idx < 0 || idx >= ProfileSettings.Length)
		return "";

	return ProfileSettings[idx].SettingName;
}

function string GetProfileParam(int idx)
{
	if (idx < 0 || idx >= ProfileSettings.Length)
		return "";

	return ProfileSettings[idx].SettingValue;
}

function string GetProfileNamedParam(string Parameter)
{
	local int i;
	local string SettingName;

	for (i = 0; i < ProfileSettings.Length; i++)
	{
		SettingName = ProfileSettings[i].SettingName;
		if (SettingName ~= Parameter || Right(SettingName, Len(Parameter)+1) ~= ("."$Parameter))
			return ProfileSettings[i].SettingValue;
	}

	return "";
}

/////////////////////////////////////////////////////////////////////
// PlayInfo Manipulation Functions
/////////////////////////////////////////////////////////////////////

function SavePI()
{
	if (!bEdit)
	{
		log("SavePI()"@DidNotStartEdit);
		return;
	}

	if (PInfo == None)
		return;

	PInfo.SaveSettings();
}

function bool SetParam(int idx, string Value)
{
	if (PInfo == None || idx < 0 || idx >= PInfo.Settings.Length)
		return false;

	if (InStr(PInfo.Settings[idx].SettingName,"AdminName") != -1 || InStr(PInfo.Settings[idx].SettingName,"AdminEmail") != -1)
		return false;

	return PInfo.StoreSetting(idx, Value);
}

function bool SetNamedParam(string Parameter, string Value)
{
	local int i;
	local string SettingName;

	if (PInfo == None) return false;

	for (i = 0; i < PInfo.Settings.Length; i++)
	{
		SettingName = PInfo.Settings[i].SettingName;
		if (SettingName ~= Parameter || Right(SettingName, Len(Parameter) + 1) ~= ("."$Parameter))
		{
			if (InStr(PInfo.Settings[i].SettingName,"AdminName") != -1 || InStr(PInfo.Settings[i].SettingName,"AdminEmail") != -1)
				return false;

			return PInfo.StoreSetting(i, Value);
		}
	}
	// Parameter not found
	return false;
}

///////////////////////////////////////////////////////////////////////////
// Profile Manipulation Functions
///////////////////////////////////////////////////////////////////////////

function int Count()
{
	return ProfileSettings.Length;
}

function bool SetProfileParam(int idx, string SettingName, coerce string SettingValue)
{
	if (idx < 0 || idx > ProfileSettings.Length)
		return false;

    if (ProfileSettings.Length == idx)
    	ProfileSettings.Length = ProfileSettings.Length+1;

	ProfileSettings[idx].SettingName = SettingName;
	ProfileSettings[idx].SettingValue = SettingValue;

	return true;
}

function bool SetProfileNamedParam(string Parameter, string Value)
{
	local int i;
	local string SettingName;

	for (i = 0;i < ProfileSettings.Length; i++)
	{
		SettingName = ProfileSettings[i].SettingName;
		if (SettingName ~= Parameter || Right(SettingName, Len(Parameter) + 1) ~= ("."$Parameter))
		{
			ProfileSettings[i].SettingValue = Value;
			return true;
		}
	}

	return false;
}