Legacy:ConfigMaster
This is a custom class, which is part of the ConfigManager for UT2003.
<uscript line> //----------------------------------------------------------- // ConfigManager.ConfigMaster version 1.8 // Allows for ServerActors & Mutators to add to PlayInfo // // The latest version of ConfigManager is always available at // http://www.organized-evolution.com/ConfigManager/ //-----------------------------------------------------------
class ConfigMaster extends Mutator DependsOn(AutoLoader) config(ConfigMaster);
// If 2184 or earlier, crash the server var int GameVersion;
// Contains previous values of modified IniEntries, unless there is already // a previous value for an IniEntry. When a managed loader is de-activated, // the original value of the IniEntry is restored. var config array<AutoLoader.IniEntry> OriginalValues;
// Holder for properties which aren't needed - used by loaders that get activated at the end of the match var array<Property> IrrelevantProperties;
struct SA { var class<Info> SAClass; var string SAName; var string SADescription; };
struct AL { var class<AutoLoader> AutoLoaderClass; var string AutoLoaderDesc; };
var array<SA> ManagedActors; // Info about Loaders' ActorClasses var array<AL> LoaderClasses; // All Loader Classes found var array<AutoLoader> Loaders; // Active Loaders var array<string> ActiveMutators; // Currently active mutator classes var bool bInitialized; // Initialization var bool bHangRestart; // Don't let server travel yet
var GameEngine GE;
const VERSION = 1.71; const LOGNAME = 'Config Manager'; var const bool DEBUG; var const bool DEBUGPROPS;
// Localization var localized string LoadSuccess; var localized string RequiredVersion; var localized string UpgradeOrDie; var localized string RemovalCancelled;
// Errors var localized string InvalidLoaderClass; var localized string InvalidPI;
event PreBeginPlay() { GameVersion = int(Level.EngineVersion);
log(" -"@LOGNAME@VERSION@LoadSuccess,LOGNAME); if (GameVersion < 2199) { log(RequiredVersion@LOGNAME$".",LOGNAME); log(UpgradeOrDie,LOGNAME); log("",'ConfigManager'); Assert(False); }
GetGameEngine(); }
event PostBeginPlay() { local int i;
if (DEBUG) { log(class@"Beginning initialization",'PostBeginPlay'); log("START OF GAME SERVERACTORS",'PostBeginPlay'); for (i = 0; i < GE.ServerActors.Length; i++) log("ServerActor["$i$"]:"$GE.ServerActors[i],'PostBeginPlay');
log("START OF GAME SERVERPACKAGES",'PostBeginPlay'); for (i = 0; i < GE.ServerPackages.Length; i++) log("ServerPackages["$i$"]:"$GE.ServerPackages[i],'PostBeginPlay');
log("",'PostBeginPlay'); } // Level.Game.AddMutator("ConfigManagerGUI.ConfigManagerGUIMaster");
InitLoaders(); if (DEBUG) log(class@"finished loading all actors and loaders",'PostBeginPlay');
Super.PostBeginPlay(); }
// Sends a list of currently active mutators to all loader classes // Loader classes may want to check if its mutator was loaded without using the loader // (added at command line, etc.) function GetGameEngine() { foreach AllObjects(class'Engine.GameEngine', GE) break; }
function AddMutator(Mutator M) { local int i;
for (i = 0; i < ActiveMutators.Length; i++) if (ActiveMutators[i] ~= string(M.Class)) break;
if (i == ActiveMutators.Length) ActiveMutators[ActiveMutators.Length] = string(M.Class);
if (DEBUG) for (i = 0; i < ActiveMutators.Length; i++) log("ActiveMutators["$i$"]:"@ActiveMutators[i],'AddMutator');
Super.AddMutator(M); }
// Do not show ConfigMaster in server browser as active mutator function GetServerDetails( out GameInfo.ServerResponseLine ServerState ) { }
function InitLoaders() { FindAllLoaders(); CreateLoaders(); }
function FindAllLoaders() { local int i, j; local AL TempAL; local SA TempSA;
local class<AutoLoader> LoaderClass; local class<Info> ServerActorClass; local string LoaderClassName, LoaderClassDescription, ActorClass, ServerActorName, ServerActorDesc;
GetNextIntDesc("ConfigManager.AutoLoader",0,LoaderClassName,LoaderClassDescription); while (LoaderClassName != "") { // Hack to prevent Config Loader from being loaded if (LoaderClassName ~= "ConfigManagerLoader.SampleLoader") { GetNextIntDesc("ConfigManager.AutoLoader",++i,LoaderClassName,LoaderClassDescription); continue; } if (DEBUG) log("Found a new AutoLoader:"@LoaderClassName@LoaderClassDescription,'FindAllLoaders');
LoaderClass = class<AutoLoader>(DynamicLoadObject(LoaderClassName,Class'Class')); if (LoaderClass != None) { if (ShouldAddLoaderClass(LoaderClass)) { TempAL.AutoLoaderClass = LoaderClass; TempAL.AutoLoaderDesc = LoaderClassDescription; LoaderClasses[LoaderClasses.Length] = TempAL; j = -1; while (LoaderClass.static.AddManagedActor(j++, ActorClass, ServerActorName, ServerActorDesc)) { if (ActorClass != "" && ServerActorName != "" && ServerActorDesc != "") { ServerActorClass = class<Info>(DynamicLoadObject(ActorClass,class'Class')); if (ServerActorClass != None) { TempSA.SAClass = ServerActorClass; TempSA.SAName = ServerActorName; TempSA.SADescription = ServerActorDesc;
ManagedActors[ManagedActors.Length] = TempSA; } } } } } else Warn(InvalidLoaderClass@LoaderClassName);
GetNextIntDesc("ConfigManager.AutoLoader",++i, LoaderClassName, LoaderClassDescription); }
return; }
function bool ShouldAddLoaderClass(class<AutoLoader> NewClass) { local int i;
if (DEBUG) log("Loader Class"@NewClass,'ShouldAddLoaderClass');
// Don't add if it's already in the list for (i = 0;i < LoaderClasses.Length; i++) if (LoaderClasses[i].AutoLoaderClass == NewClass) return false;
return true; }
function CreateLoaders() { local int i; local AutoLoader Loader;
if (DEBUG) log("LoaderClasses"@LoaderClasses.Length,'CreateLoaders');
for (i = 0;i<LoaderClasses.Length;i++) { if (ShouldAddLoader(LoaderClasses[i].AutoLoaderClass)) { Loader = AddLoader(LoaderClasses[i].AutoLoaderClass); if (Loader != None) Loaders[Loaders.Length] = Loader; } } }
function bool LoaderNotActive(class<AutoLoader> NewClass) { local int i;
for (i = 0; i < Loaders.Length; i++) if (Loaders[i].Class == NewClass) return false;
return true; }
function bool ShouldAddLoader(class<AutoLoader> NewClass) { local bool bShouldAdd;
bShouldAdd = LoaderNotActive(NewClass) && GE != None;
if (bShouldAdd) bShouldAdd = NewClass.static.CheckStrayActors(GE.GetPropertyText("ServerActors")) || NewClass.static.IsActive();
bShouldAdd = bShouldAdd && NewClass.static.ValidateLoader();
if (DEBUG) log(NewClass@"will be added:"$bShouldAdd,'ShouldAddLoader');
return bShouldAdd; }
function AutoLoader AddLoader(class<AutoLoader> NewClass) { local AutoLoader Loader; if (NewClass == None) return None;
Loader = Spawn(NewClass,Self); if (Loader != None && GE != None) Loader.GE = GE;
if (DEBUG) log("Returning"@Loader,'AddLoader');
return Loader; }
// Make sure to remain as Game.BaseMutator.NextMutator so we will know about every mutator that is added. event Tick(float DeltaTime) { local int i;
if (bInitialized && Level != None && Level.NextURL != "") { if (bHangRestart) Level.NextSwitchCountdown = 4.0;
else if (Loaders.Length > 0) { bHangRestart = True; SetTimer(0.2,False); } }
// Do not replace BaseMutator, or DMMutator will show up in server browser as an active mutator if (Level != None && Level.Game != None && Level.Game.BaseMutator != None) { if (Level.Game.BaseMutator.NextMutator != None) { if (Level.Game.BaseMutator.NextMutator != Self) { // Some other ConfigManager as BaseMutator.NextMutator, but it isn't me???? // Maybe added ConfigManager as a serveractor? // Disable or server will crash if (!bInitialized && Level.Game.BaseMutator.NextMutator.Class == Class) { Destroy(); return; }
// We have been replaced by another mutator wanting // to be the first mutator. if (Level.Game.BaseMutator.NextMutator.NextMutator == Self) { if (NextMutator != None) Level.Game.BaseMutator.NextMutator.NextMutator = NextMutator; else Level.Game.BaseMutator.NextMutator.NextMutator = None; }
NextMutator = Level.Game.BaseMutator.NextMutator; Level.Game.BaseMutator.NextMutator = Self; } }
else Level.Game.BaseMutator.NextMutator = Self; }
if (!bInitialized) { for (i = 0; i < LoaderClasses.Length; i++) { if (LoaderNotActive(LoaderClasses[i].AutoLoaderClass) && LoaderClasses[i].AutoLoaderClass.static.CheckCurrentMutators(GetURLOption("Mutator"))) { if (DEBUG) log("Adding previously non-active loader"@LoaderClasses[i].AutoLoaderClass,'Tick'); Loaders[Loaders.Length] = AddLoader(LoaderClasses[i].AutoLoaderClass); } }
bInitialized = True; } }
event Timer() { Super.Timer(); ApplyLoaderSettings(); }
function array<Property> LoadProperties() { local array<Property> AllProperties; local array<class> RelevantActors; local array<string> RelevantPropNames; local class RelevantClass; local Property P; local int i, j, k;
// Build a array of properties which are relevant to the currently loaded loaders // so that the amount of time it will take each loader to update their settings will // be dramatically reduced - // Typical number of Property objects in the game: 200,000 // Typical number of properties relevant to current loaders: 50
// Start by first getting a list of actors/objects which will be relevant
// All ManagedActors are relevant (Loader's ActorClass) for (i = 0; i < ManagedActors.Length; i++) { for (j = 0; j < RelevantActors.Length; j++) if (RelevantActors[j] == ManagedActors[i].SAClass) break;
if (j < RelevantActors.Length) continue;
RelevantActors[RelevantActors.Length] = ManagedActors[i].SAClass; }
if (DEBUG) log("Loaders"@LoaderClasses.Length,'LoadProperties');
for (i = 0; i < LoaderClasses.Length; i++) { // If ActorClass was already added to list, skip it for (j = 0; j < RelevantActors.Length; j++) if (string(RelevantActors[j]) ~= LoaderClasses[i].AutoLoaderClass.default.ActorClass) break;
if (j == RelevantActors.Length) { if (LoaderClasses[i].AutoLoaderClass.default.ActorClass != "") RelevantClass = class(DynamicLoadObject(LoaderClasses[i].AutoLoaderClass.default.ActorClass,class'Class'));
if (RelevantClass != None) RelevantActors[RelevantActors.Length] = RelevantClass; }
// Begin building a list of property names to mark as relevant // We'll match these names to the Property.Name variable later when we iterate AllObjects for class'Property' for (j = 0; j < LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries.Length; j++) {
for (k = 0; k < RelevantPropNames.Length; k++) { if (RelevantPropNames[k] == LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].PropName) break; }
if ( k == RelevantPropNames.Length ) { RelevantPropNames[RelevantPropNames.Length] = LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].PropName; if (DEBUGPROPS) log("Added new Relevant Property Name:"$RelevantPropNames[k],'LoadProperties'); }
RelevantClass = class(DynamicLoadObject(LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].ClassFrom,Class'class',True)); if (RelevantClass == None) continue;
// Find out if this entry's associated class is already in the relevant actors list // If not, add it for (k = 0; k < RelevantActors.Length; k++) { if (DEBUGPROPS) log("Compare"@LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].ClassFrom@"to Relevant Actor"@k$":"@RelevantActors[k],'LoadProperties');
if (RelevantActors[k] == RelevantClass) break; } if (DEBUGPROPS) log("Breaking on"@k$", Total Relevant Actors:"@RelevantActors.Length,'LoadProperties');
if (k < RelevantActors.Length) continue;
RelevantActors[RelevantActors.Length] = RelevantClass; if (DEBUGPROPS) log("Added new relevant actor:"$LoaderClasses[i].AutoLoaderClass.default.RequiredIniEntries[j].ClassFrom,'LoadProperties'); } }
// Finished building relevant actors and relevant names // Iterate AllObjects, looking for Property objects foreach AllObjects(class'Property', P) { RelevantClass = None; // Some property types should be skipped if ( ValidProp(P) ) { if (Class(P.Outer) != None) RelevantClass = Class(P.Outer); if (RelevantClass != None) { for (i = 0; i < RelevantActors.Length; i++) { // The Outer variable for properties is the class that the property is contained in // If this property's Outer is an object that is relevant, add it to the list if (RelevantClass == RelevantActors[i]) { for (j = 0; j < RelevantPropNames.Length; j++) if (RelevantPropNames[j] == string(P.Name)) { if (DEBUGPROPS) log("Adding Initial Relevant Property:"$P.Outer$"."$P.Name,'LoadProperties'); AllProperties[AllProperties.Length] = P; break; }
if (j < RelevantPropNames.Length) break; } } }
// OK, this property's Outer wasn't relevant // Check the property against the relevant name list if (i == RelevantActors.Length) { for (i = 0; i < RelevantPropNames.Length; i++) { // If we find a match, then we should check the relevant objects list again, // in case the relevant object is a superclass of the property's Outer if (RelevantPropNames[i] == string(P.Name)) { if (DEBUGPROPS) log("Compare Property:"@i@RelevantPropNames[i]@"to"@string(P.Name),'LoadProperties');
for (j = 0; j < RelevantActors.Length; j ++) { if (RelevantClass == None) continue;
if (DEBUGPROPS) log("Relevant Actor Check:"@j@RelevantActors[j]@"is child of"@class(P.Outer)@":"$ClassIsChildOf(RelevantActors[j],Class(P.Outer)),'LoadProperties');
if (ClassIsChildOf(RelevantActors[j], RelevantClass)) { if (DEBUGPROPS) log("Adding Additional Relevant Property:"$P.Outer$"."$P.Name,'LoadProperties');
AllProperties[AllProperties.Length] = P; break; } }
if (j < RelevantActors.Length) break; } } } } }
return AllProperties; }
// Update Properties array with newly loaded loaders // No longer used function CheckRelevantProperties(AutoLoader L, out array<Property> Props) { local int i, j; local array<class> Classes, Outers;
local class TempClass; local Property P;
if (DEBUGPROPS) log("Checking relevant properties for new loader"@L,'CheckRelevantProperties');
for (i = 0; i < Props.Length; i++) { TempClass = Class(Props[i].Outer); if (TempClass == None) continue;
for (j = 0; j < Outers.Length; j++) if (TempClass == Outers[j]) break;
if (j < Outers.Length) continue;
Outers[Outers.Length] = TempClass; }
if (L.bIncludeServerActor && L.ActorClass != "") { if (DEBUGPROPS) log("Checking for existence of"@L.ActorClass@"properties",'CheckRelevantProperties');
TempClass = class(DynamicLoadObject(L.ActorClass,class'Class',True)); if (TempClass != None) { for (i = 0; i < Outers.Length; i++) if (TempClass == Outers[i]) break;
if (i == Outers.Length) Classes[Classes.Length] = TempClass;
else if (DEBUGPROPS) log(TempClass@"has already been added to the properties array.",'CheckRelevantProperties'); } }
for (i = 0; i < L.RequiredIniEntries.Length; i++) { if (DEBUGPROPS) log("Checking for existence of relevant class"@L.RequiredIniEntries[i].ClassFrom,'CheckRelevantProperties');
TempClass = class(DynamicLoadObject(L.RequiredIniEntries[i].ClassFrom,class'Class',True)); if (TempClass != None) { for (j = 0; j < Classes.Length; j++) if (Classes[j] == TempClass) break;
if (j < Classes.Length) continue;
for (j = 0; j < Outers.Length; j++) if (Outers[j] == TempClass) break;
if (j < Outers.Length) continue;
Classes[Classes.Length] = TempClass; } else if (DEBUGPROPS) log("Could not load RequiredIniEntry["$i$"].ClassFrom:"@L.RequiredIniEntries[i].ClassFrom,'CheckRelevantProperties'); }
if (DEBUGPROPS && Classes.Length == 0) log("All relevant classes from this loader already existed in properties array",'CheckRelevantProperties');
for (i = 0; i < Classes.Length; i++) { if (DEBUGPROPS) { log(""); log("Adding properties from class"@Classes[i]@"to properties array.",'CheckRelevantProperties'); }
for (j = 0; j < IrrelevantProperties.Length; j++) { P = IrrelevantProperties[j]; TempClass = Class(P.Outer);
if (TempClass == None || TempClass != Classes[i]) continue;
if (DEBUGPROPS) log(" Adding property"@P.Name,'CheckRelevantProperties');
Props[Props.Length] = P; IrrelevantProperties.Remove(j--, 1); } } }
// TODO: Add support for structs final function bool ValidProp(Property P) { return P.Class != class'ObjectProperty' && P.Class != class'DelegateProperty' && P.Class != class'PointerProperty' && P.Class != class'MapProperty' && P.Class != class'StructProperty'; }
// Fills PlayInfo for ServerActors final function CallManagedActorPlayInfo(PlayInfo PI) { local int i, j;
for (i = 0; i < LoaderClasses.Length; i++) { if (DEBUG) log("Checking for LoaderClass"@i@"in playinfo:"$loaderclasses[i].autoloaderclass,'ManagedActorFillPlayInfo');
if (NotInPlayInfo(PI,LoaderClasses[i].AutoLoaderClass)) { if (DEBUG) log("Calling FillPlayInfo() for LoaderClass"@i$":"$loaderclasses[i].autoloaderclass,'ManagedActorFillPlayInfo');
LoaderClasses[i].AutoLoaderClass.static.FillPlayInfo(PI); PI.PopClass(); }
for (j = 0; j < ManagedActors.Length; j++) { if (LoaderClasses[i].AutoLoaderClass.default.ActorClass != string(ManagedActors[j].SAClass)) continue;
if (DEBUG) log("Checking for ManagedActor"@j@"in playinfo:"$ManagedActors[j].SAClass,'ManagedActorFillPlayInfo');
if (LoaderClasses[i].AutoLoaderClass.static.IsActive()) { ManagedActors[j].SAClass.static.FillPlayInfo(PI); PI.PopClass(); } } } }
// Only webadmin calls Mutator.MutatorFillPlayInfo()? function MutatorFillPlayInfo(PlayInfo PI) { if (DEBUG) log("");
if (DEBUG) log("Checking URL Option:"$GetURLOption("Mutator"),'MutatorFillPlayInfo');
if (NextMutator != None) NextMutator.MutatorFillPlayInfo(PI);
CallManagedActorPlayInfo(PI); }
// Allows Loaders to adjust game configuration parameters // Loaders provide info about which ini changes need to be made for the mod to work // This allows other programs (such as Ladder) to only include the ini modifications // which are applicable for the loaded packages // // (Ex: ServerActors, ServerPackages, QueryHandlerClasses, Applications) final function ApplyLoaderSettings() { local int i, Index; local array<Property> CurrentProperties; local class Temp;
// Checking for any loaders that have been enabled since last check // Otherwise, must wait 2 server restarts to apply new loader settings // (One to load loader and apply changes, another for changes to take effect) FindAllLoaders(); CurrentProperties = LoadProperties(); for ( i = 0; i < LoaderClasses.Length; i++) { if (DEBUG) log("LoaderClass"@i$":"@LoaderClasses[i].AutoLoaderClass,'ApplyLoaderSettings');
if (ShouldAddLoader(LoaderClasses[i].AutoLoaderClass) || (LoaderClasses[i].AutoLoaderClass.static.CheckCurrentMutators(Level.NextURL) && LoaderClasses[i].AutoLoaderClass.static.ValidateLoader())) Loaders[Loaders.Length] = AddLoader(LoaderClasses[i].AutoLoaderClass);
else if (LoaderNotActive(LoaderClasses[i].AutoLoaderClass)) AddLoader(LoaderClasses[i].AutoLoaderClass).AcceptRemoval(CurrentProperties); }
if (DEBUGPROPS) { log("*** Relevant Property Listing ***",'ApplyLoaderSettings'); for (i = 0; i < CurrentProperties.Length;i++) { if (Class(CurrentProperties[i].Outer) != None && Temp != Class(CurrentProperties[i].Outer)) { Temp = Class(CurrentProperties[i].Outer); log("",'ApplyLoaderSettings'); log("Relevant properties from class"@Temp@"-",'ApplyLoaderSettings'); } log(" "$currentproperties[i].name,'ApplyLoaderSettings'); } }
while (Index < Loaders.Length) { if (DEBUG) log("Loader"@Index$":"@Loaders[Index],'ApplyLoaderSettings');
if (Loaders[Index].ApplyUpdate()) Loaders[Index].UpdateConfiguration(CurrentProperties);
else if (!Loaders[Index].AcceptRemoval(CurrentProperties)) log(RemovalCancelled@Loaders[Index],'ConfigManager');
Index++; }
Disable('Tick'); if (DEBUG) { log("",'ApplyLoaderSettings'); log("END OF GAME SERVERACTORS",'ApplyLoaderSettings'); for (i = 0; i < GE.ServerActors.Length; i++) log("ServerActor["$i$"]:"$GE.ServerActors[i],'ApplyLoaderSettings');
log("END OF GAME SERVERPACKAGES",'ApplyLoaderSettings'); for (i = 0; i < GE.ServerPackages.Length; i++) log("ServerPackages["$i$"]:"$GE.ServerPackages[i],'ApplyLoaderSettings');
log("",'ApplyLoaderSettings'); } }
function bool NotInPlayInfo(PlayInfo PI, class<Info> NewInfo) { local int i; if (PI == None) { Warn(InvalidPI); return false; }
for (i=0;i<PI.InfoClasses.Length;i++) { if (PI.InfoClasses[i] == NewInfo) return false; }
return true; }
function array<string> GetAllManagedActors() { local int i; local array<string> Arr;
for (i = 0; i < LoaderClasses.Length; i++) Arr = AddS(Arr,LoaderClasses[i].AutoLoaderClass.static.GetManagedActors());
return Arr; }
static final function float GetConfigMasterVersion() { return VERSION; }
// following function copied from wUtils (El_Muerte[TDS]) static final function array<string> AddS(array<string> A, array<string> B) {
local int i; for (i = 0; i < B.length; i++) { A.length = A.length+1; A[A.length-1] = B[i]; } return A;
} </uscript>